1. Введение
Xmodem-это асинхронный протокол переноса файла, широко используемый в последовательной связи, деленные на два протокола: Xmodem (с использованием блоков данных 128-байтовых данных) и 1K-Xmodem (с использованием блоков данных 1024-байта, то есть протоколов 1K-байтовых блоков).
Эта статья реализует протокол Xmodem 128-байтовых блоков данных, который принимает проверку CRC16. При применении в проекте отправка и получение конца могут изменить соглашение между обеими сторонами в соответствии с конкретными обстоятельствами.
Если вы не знаете много о последовательной коммуникации, вы можете прочитать блог, который я написал, чтобы использовать Java для реализации последовательного общения.
2. Реализация
Во время процесса отладки со встроенными студентами было обнаружено, что отправляющая сторона отправляет данные слишком быстро, что привело к тому, что приемная сторона не смогла их обрабатывать. Поэтому в методе отправки была открыта детская поток для обработки логики отправки данных, которая облегчает добавление обработки задержки.
В методе получения отправка C означает проверку в CRC.
public Class Xmodem {// Начать частное окончательное байт SOH = 0x01; // end private final byte eot = 0x04; // Ответьте на частный окончательный байт ack = 0x06; // ретрансляция частного окончательного байта NAK = 0x15; // безоговорочный конечный частный финальный байт -байт = 0x18; // Передача данных в 128 байтовых блоках Private Final int sector_size = 128; // максимальная ошибка (без ответа) Количество пакетов Private Final int max_errors = 10; // Входной поток, используемый для чтения данных последовательного порта Private InputStream InputStream; // выходной поток, используемый для отправки данных последовательного порта private outputStream outputStream; public xmodem (inputstream inputstream, outputstream outputstream) {this.inputStream = inputStream; this.outputStream = outputStream; } / *** Отправить данные** @param filepath* pail path* / public void send (final String filePath) {new Thread () {public void run () {try {// количество пакетов ошибок in errorCount; // номер пакета byte blocknumber = 0x01; // контрольная сумма Checksum int; // количество байтов, прочитанных в буфер int nbytes; // инициализировать байт буфера данных [] section = new Byte [sector_size]; // Читать инициализацию файла dataInputStream inputStream = new DataInputStream (new FileInputStream (filePath)); while ((nbytes = inputstream.read (sector))> 0) {// Если последний пакет данных составляет менее 128 байтов, заполните его 0xff if (nbytes <sector_size) {for (int i = nbytes; i <sector_size; i ++) {sector [i] = (byte) 0xff; }} // Тот же пакет данных отправляется в 10 раз Eirmorcount = 0; while (errorcount <max_errors) {// группы пакетов // управления + номер пакета + обратный код номера пакета + data + cecksum putdata (SOH); putdata (blocknumber); putdata (~ blocknumber); Checksum = crc16.calc (сектор) & 0x00ffff; Putchar (сектор, (короткая) контрольная сумма); outputStream.flush (); // Получить данные данных byte data = getData (); // Если ответ получен, следующий пакет данных выпрыгнет и отправит следующий пакет данных // Ответ не будет } else {++ errorCount; }} // Номер пакета увеличивается blocknumber = (byte) ((++ blocknumber) % 256); } // После того, как все данные отправляются, отправляется флаг -флаг Boolean isack = false; while (! isack) {putdata (eot); isack = getData () == ack; }} catch (Exception e) {e.printstackTrace (); }}; }.начинать(); } / *** Получить данные** @param filepath* pail path* @return. Будь ли прием заполнен* @throhs ioexception* exception* / public boolean cheach (String filePath) Throws Exception {// ошибка packet int errorcount = 0; // номер пакета byte blocknumber = 0x01; // данные байтов данных; // контрольная сумма Checksum int; // инициализировать байт буфера данных [] section = new Byte [sector_size]; // Записать в файл для инициализации DataOutputStream outputStream = new DecaTputStream (new FileOutputStream (filePath)); // отправлять символ C и CRC Verification Putdata ((Byte) 0x43); while (true) {if (errorcount> max_errors) {outputstream.close (); вернуть ложь; } // Получить данные ответа данных = getData (); if (data! = eot) {try {// определить, получен ли принятый идентификатор начала if (data! = soh) {errorcount ++; продолжать; } // Получить пакет серийный номер data = getData (); // определить, является ли серийный номер пакета правильным, если (data! = Blocknumber) {errorcount ++; продолжать; } // Получить обратный код серийного номера пакета byte _blocknumber = (byte) ~ getData (); // определить, является ли обратный код последовательного номера пакета правильным, если (data! = _Blocknumber) {errorcount ++; продолжать; } // Получить данные для (int i = 0; i <sector_size; i ++) {sector [i] = getData (); } // Получить контрольную сумму = (getData () & 0xff) << 8; контрольная сумма | = (getData () и 0xff); // определить, является ли контрольная сумма правильной int crc = crc16.calc (сектор); if (crc! = checksum) {errorcount ++; продолжать; } // Отправить ответ putdata (ack); // номер пакета увеличивается BlockNumber ++; // записать данные в локальный outputstream.write (сектор); // errorcount сброшен на ноль = 0; } catch (Exception e) {e.printstackTrace (); } наконец {// Если возникает ошибка, отправьте идентификатор ретрансмиссии if (errorCount! = 0) {putdata (nak); }}} else {break; }} // Закройте выходной поток outputstream.close (); // Отправить ответ putdata (ack); вернуть истину; } / *** Получить данные** @return Data* @Throws ioException* Exception* / private byte getData () бросает ioException {return (byte) inputstream.read (); } / *** Отправить данные** @param data* data* @throws ioexception* exception* / private void putdata (int data) throws ioexception {outputStream.write ((byte) data); } / *** Отправить данные** @param data* data* @param chectsum* checksum* @throws ioexception* exception* / private void putchar (byte [] data, короткая контрольная сумма) бросает ioexception {bytebuffer bb = bytebuffer.allocate (data.length + 2). Order (bytebuffer bb = bytebuff. bb.put (data); bb.putshort (контрольная сумма); outputStream.write (bb.array ()); }}Алгоритм проверки CRC16 использует метод поиска таблицы.
открытый класс CRC16 {Private Static Final CHAR CRCTABLE [] = {0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0x.ce. 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3b3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3. 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc585, 0x363, 0x363, 0x., 0x363, 0x., 0x363, 0xe5 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe 0x6886, 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, 0xab1a, 0x6ca6, 0x7c87, 0xab1a, 0x6ca6, 0x7c87, 0xab1a, 0x5ca6 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e.e.e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3eab4, 0x3e.e. 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12, 0xc12, 0xc12, 0xc12, 0xc12, 0xc12 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xD31 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc711d7c8, 0xe75f, 0xf77e, 0xc711d7, 0x, 0xf77. 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98aab, 0x.58ab, 0x. 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbbbb. 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x64, 0x54, 0x64, 0x54, 0x54, 0x9, 0x9, 0x8dc9, 0x76, 0x64, 0x9, 0x8, 0x8dc9, 0x76, 0x64, 0x9de8, 0x8dc9, 0x76, 0x64, 0x9de8, 0x8dc9, 0x76, 0xaD8b, 0x9de8, 0x8dc9, 0x76, 0xad8b, 0x9de8, 0x8dc9, 0x76, 0xad8b, 0x9de8, 0x8dc9, 0x76. 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x76, 0x455, 0x5. 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0}; public static char calc (byte [] bytes) {char crc = 0x0000; for (byte b: байты) {crc = (char) ((crc << 8) ^ crctable [((crc >> 8) ^ b) & 0x00ff]); } return (char) (crc); }}3. Используйте
// serialport - это объект последовательного порта xmodem xmodem = new xmodem (serialport.getinputstream (), serialport.getOutputStream ()); // filePath - это путь файла // ./bin/xxx.binxmodem.send(filepath);
4. Напишите в конце
Полный код скачать
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.