Using Java to implement the XMODEM protocol _java

Source: Internet
Author: User
Tags ack file transfer protocol

1. Introduce

Xmodem is a widely used asynchronous file transfer Protocol in serial communication, divided into Xmodem (using 128 bytes of data blocks) and 1k-xmodem (using 1024 bytes or 1k bytes of data block) protocol two.
This article realizes the 128 byte data Block Xmodem protocol, uses the CRC16 verification, when uses in the project, the sending end and the receiving end may modify the mutual agreement according to the concrete situation.
If you do not know the serial communication, you can see the blog I wrote the use of Java to implement serial communication.

2. To achieve

In the process of debugging with the embedded students, it is found that the sender sends the data too fast, which leads to the receiving end processing, so a child thread is opened in the Send method to handle the data sending logic, which is convenient to add the delay processing.
In the Receive method, send C is the CRC checksum.

public class Xmodem {//start private final byte SOH = 0x01;
 End of private final byte EOT = 0x04;
 Answer private final byte ACK = 0x06;
 Retransmission private Final byte NAK = 0x15;

 Unconditional end of private final byte CAN = 0x18;
 Transmits data in 128-byte block private final int sector_size = 128;

 Maximum error (no answer) package private final int max_errors = 10;
 Input stream, used to read serial data private InputStream InputStream;

 Output stream, used to send serial port data private OutputStream outputstream;
 Public Xmodem (InputStream InputStream, OutputStream outputstream) {this.inputstream = InputStream;
 This.outputstream = OutputStream; /** * Send Data * * @param filePath * file path/public void Send (final String filePath) {new Thread () {public VO
   ID run () {try {///error packet int errorcount;
   Packet ordinal byte blocknumber = 0x01;
   checksum int checkSum;
   The number of bytes read to the buffer int nbytes;
   Initialize data buffer byte[] sector = new Byte[sector_size]; Read file initialization datainputstream InputStream = new DataInputStream (New FileInputStream (Filepath));
    while (nbytes = inputstream.read (sector)) > 0 {//If the last packet of data is less than 128 bytes, 0xFF is padded if (Nbytes < sector_size) {
    for (int i = Nbytes i < sector_size; i++) {Sector[i] = (byte) 0xFF;
   }///the same packet data sent up to 10 times Errorcount = 0;
    while (Errorcount < max_errors) {///group//control character + package serial number + packet serial number of counter code + data + checksum putdata (SOH);
    PutData (Blocknumber);
    PutData (~blocknumber);
    CheckSum = Crc16.calc (sector) & 0x00ffff;
    Putchar (Sector, (short) checkSum);

    Outputstream.flush ();
    Gets the answer data byte data = GetData ();
    If you receive the answer data, then jump out of the loop, send the next packet of data//no response, the number of +1 error packets, continue to resend if (data = ACK) {break;
    else {++errorcount;
   }//Package serial number self-blocknumber = (byte) ((++blocknumber)% 256);
   ///Send end identifier Boolean isack = False after all data is sent;
   while (!isack) {putdata (EOT);
   Isack = getData () = = ACK;
  } catch (Exception e) {e.printstacktrace ();
 }
  };
 }.start (); /** * Receive Data * * @param FILEPATH * File path * @return whether to receive completion * @throws IOException * Exception/public boolean receive (String FilePath) throws Exception
 {///error packet int errorcount = 0;
 Packet ordinal byte blocknumber = 0x01;
 Data byte;
 checksum int checkSum;
 Initialize data buffer byte[] sector = new Byte[sector_size];

 Write file initialization DataOutputStream OutputStream = new DataOutputStream (new FileOutputStream (FilePath));

 Send character C,CRC way to verify PutData ((byte) 0x43);
  while (true) {if (Errorcount > Max_errors) {outputstream.close ();
  return false;
  //Get Answer data = GetData ();
   if (data!= EOT) {try {///Determine whether the received is a start identification if (data!= SOH) {errorcount++;
   Continue
   //Get package ordinal data = GetData ();
   Determine if the package serial number is correct if (data!= blocknumber) {errorcount++;
   Continue
   //Get the reverse code byte _blocknumber = (byte) ~getdata () of the package ordinal;
   Determine if the inverse code of the package sequence number is correct if (data!= _blocknumber) {errorcount++;
   Continue //Get data for (int i = 0; i < sector_size i++) {Sector[i] = GetdatA ();
   //Get checksum CheckSum = (GetData () & 0xff) << 8;
   CheckSum |= (GetData () & 0xff);
   To determine whether the checksum is correct int CRC = CRC16.CALC (Sector);
   if (CRC!= CheckSum) {errorcount++;
   Continue
   //Send answer PutData (ACK);
   The package serial number is blocknumber++ by itself;
   Writes the data to the local outputstream.write (sector);

  Error packet number to zero errorcount = 0;

  catch (Exception e) {e.printstacktrace ();
   finally {//If error sends retransmission ID if (errorcount!= 0) {putdata (NAK);
  }} else {break;
 }//Turn off output stream outputstream.close ();

 Send answer PutData (ACK);
 return true; /** * Get Data * * @return Data * @throws IOException * Exception/private byte GetData () throws IOException {return (
 byte) Inputstream.read (); /** * Send Data * * @param the data * * @throws IOException * Exception/private void PutData (int data) throws Ioexcep
 tion {outputstream.write ((byte) data); /** * Send Data * * @param data * @param checkSum * checksum * @throws IOException *  Exception */private void Putchar (byte[] data, short checkSum) throws IOException {Bytebuffer BB = bytebuffer.allocate (data
 . length + 2). order (Byteorder.big_endian);
 Bb.put (data);
 Bb.putshort (CheckSum);
 Outputstream.write (Bb.array ());

 }
}

The

CRC16 verification algorithm, using the Look-up table method.

public class CRC16 {private static final char crctable[] = {0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0X60C6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0XD1AD, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0X52B5, 0x429 4, 0x72f7, 0X62D6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0XD3BD, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x6 4e6, 0x74c7, 0X44A4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0XF5CF, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0 630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0XF7DF, 0xe7fe, 0xd79d, 0XC7BC, 0X48C4, 0x58e5, 0  x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0XDBFD, 0XCBDC, 0XFBBF, 0xeb9e, 0x9b79, 0x8b58, 0XBB3B, 0XAB1 A, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0X3C03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0XDDCD, 0xad2a, 0xbd0b, 0x8 D68, 0x9d49, 0x7e97, 0x6Eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0XDFDD, 0XCFFC, 0XBF1B, 0xaf3a, 0x9f59, 0x8f78, 0  x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0X30C2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0X83B9, 0x9398, 0XA3FB, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0X32D2, 0x4235, 0x521 4, 0x6277, 0x7256, 0xb5ea, 0XA5CB, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0X24C3, 0x14a0, 0x0481, 0x7 466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x1 6b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0  x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0XABBB, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0X0AF1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0XCD4D, 0xbdaa, 0xad8b, 0x9de8, 0X8DC 9, 0x7c26, 0X6C07, 0x5c64, 0X4C45, 0X3CA2, 0x2c83, 0x1ce0, 0X0CC1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0XBFBA, 0x8fd9, 0x9ff8, 0x6e17, 0x7

 E36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0X1EF0};
 public static char calc (byte[] bytes) {char CRC = 0x0000;
 for (Byte b:bytes) {CRC = (char) (CRC << 8) ^ crctable[(CRC >> 8) ^ b) & 0x00ff]);
 Return (char) (CRC);

 }
}

3. Use

SerialPort is a serial object
Xmodem Xmodem = new Xmodem (Serialport.getinputstream (), Serialport.getoutputstream ());
FilePath is the file path
//./bin/xxx.bin
Xmodem.send (FilePath);

4. Written in the final

Complete code Download

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.