1. Einführung
Xmodem ist ein asynchrones Dateiübertragungsprotokoll, das in der seriellen Kommunikation weit verbreitet ist und in zwei Protokolle unterteilt ist: XMODEM (unter Verwendung von 128-Byte-Datenblöcken) und 1K-Xmodem (unter Verwendung von 1024-Byte-Datenblöcken, d. H. 1K-Byte-Datenblöcke) Protozolen.
Dieser Artikel implementiert das Xmodem-Protokoll von 128-Byte-Datenblöcken, wodurch die CRC16-Überprüfung verwendet wird. Wenn Sie im Projekt angewendet werden, kann das Senden- und Empfangsende die Vereinbarung zwischen beiden Parteien gemäß den spezifischen Umständen ändern.
Wenn Sie nicht viel über serielle Kommunikation wissen, können Sie das Blog lesen, den ich mit Java geschrieben habe, um die serielle Kommunikation zu implementieren.
2. Implementierung
Während des Debugging -Prozesses mit eingebetteten Schülern wurde festgestellt, dass die sendende Seite Daten zu schnell sandte, was dazu führte, dass die Empfangsseite sie nicht verarbeiten konnte. Daher wurde in der Send -Methode ein untergeordneter Thread geöffnet, um die Daten zu verarbeiten, die Logik Send -Logik verarbeitet, was die Zugabe der Verzögerungsverarbeitung erleichtert.
In der Empfangsmethode bedeutet das Senden von C -Überprüfung in CRC.
public class xmodem {// private endgültige byte soh = 0x01 starten; // Private Final Byte EOT = 0x04 beenden; // Antwort private endgültige Byte ACK = 0x06; // private endgültige Byte Nak = 0x15 abzusetzen; // bedingungsloses Ende Private Final Byte CAN = 0x18; // Daten in 128 Byte -Blöcken private endgültige int sector_size = 128; // Maximaler Fehler (keine Antwort) Anzahl der Pakete private endgültige int max_errors = 10; // Eingabestream, verwendet, um serielle Portdaten privateingabestream zu lesen; // Ausgabestream, verwendet, um serielle Portdaten private OutputStream -Ausgabestream zu senden; public xmodem (InputStream InputStream, OutputStream OutputStream) {this.inputStream = InputStream; this.outputStream = outputStream; } / *** Daten senden** @param filepath* Dateipfad* / public void send (endgültige Zeichenfolge filepath) {neuer Thread () {public void run () {try {// Anzahl der Fehlerpakete intalCount; // Packungsnummer Byte BlockNumber = 0x01; // Prüfsumme in Int -Prüfsumme; // Anzahl der Bytes, die den Puffer int nBytes vorgelesen haben; // Initialisieren Sie das Datenpuffer -Byte [] Abschnitt = new Byte [sector_size]; // Dateiinitialisierung DataNputStream inputStream lesen while ((nBytes = inputStream.read (Sektor))> 0) {// Wenn das letzte Datenpaket weniger als 128 Bytes ist, füllen Sie es mit 0xff if (nBytes <sector_size) {für (int i = nBytes; i <sector_size; i ++) {Sektor [i] = (byte) 0x; }} // Das gleiche Datenpaket wird bis zu 10 -mal errungen. ErrorCount = 0; while (errorCount <max_errors) {// Gruppenpaket // Steuerzeichen + Paketnummer + inverser Code der Paketnummer + Daten + Prüfsumme PutData (SOH); putdata (blocknummer); putdata (~ blockNumber); Prüfsumme = crc16.calc (Sektor) & 0x00ffff; PutChar (Sektor, (kurze) Prüfsumme); outputStream.flush (); // Antwort Daten Byte Data = getData (); // Wenn die Antwort empfangen wird, springt das nächste Datenpaket heraus und sendet das nächste Datenpaket // Es wird keine Antwort empfangen. } else {++ ERRORCOUNT; }} // Die Paketnummer wird durch BlockNumber = (Byte) ((++ BlockNumber) % 256) erhöht; } // Nachdem alle Daten gesendet wurden, sendete das Ende Flagge boolean isack = false; while (! isack) {putdata (eot); isack = getData () == ACK; }} catch (Ausnahme e) {e.printstacktrace (); }}; }.Start(); } / *** Daten empfangen** @param filepath* Dateipfad* @return, ob der Empfang abgeschlossen ist // Packungsnummer Byte BlockNumber = 0x01; // Daten Byte -Daten; // Prüfsumme in Int -Prüfsumme; // Initialisieren Sie das Datenpuffer -Byte [] Abschnitt = new Byte [sector_size]; // in Datei schreiben, um DataOutputStream OutputStream = New DataOutputStream (neuer FileOutputStream (Filepath)) zu initialisieren; // Zeichen C und CRC -Überprüfung putdata ((byte) 0x43); while (true) {if (errorCount> max_errors) {outputStream.close (); false zurückgeben; } // Antwortdaten abrufen Daten = getData (); if (data! weitermachen; } // Die Paket -Seriennummer Data = getData () abrufen; // Bestimmen Sie, ob die Seriennummer der Paket korrekt ist, wenn (Daten! = BlockNumber) {ERRORCOUNT ++; weitermachen; } // den inversen Code des Paket -Seriennummer Byte _BlockNumber = (byte) ~ getData () erhalten; // Bestimmen Sie, ob der inverse Code der Seriennummer der Paket korrekt ist, wenn (Daten! = _BlockNumber) {ERRORCOUNT ++; weitermachen; } // Die Daten für (int i = 0; i <sector_size; i ++) {sector [i] = getData (); } // Die Prüfsummen -Prüfsumme = (getData () & 0xff) << 8; Prüfsumme | = (getData () & 0xff); // Bestimmen Sie, ob die Prüfsumme korrekt ist. if (crc! = prüfsum) {errorCount ++; weitermachen; } // die Antwort putdata (ACK) senden; // Die Paketnummer wird durch BlockNumber ++ erhöht; // Daten in den lokalen outputStream.write (Sektor) schreiben; // Fehlercount wird auf Null = 0 zurückgesetzt; } catch (Ausnahme e) {e.printstacktrace (); } endlich {// Wenn ein Fehler auftritt, senden Sie den Retransmission -Kennung if (errorCount! = 0) {putData (nak); }}} else {break; }} // Schließen Sie den Ausgabestream outputStream.close (); // die Antwort putdata (ACK) senden; zurückkehren; } / *** Daten abrufen** @return data* @throws ioException* Ausnahme* / private byte getData () löscht IoException {return (byte) inputStream.read (); } / *** Daten senden** @param data* data* @throws ioException* Ausnahme* / private void putData (int data) löscht IOException {outputStream.write ((byte) data) aus; } / *** Daten senden** @param data* data* @param checksum* prüfsum* @throws ioException* Exception* / private void putchar (byte [] data, Short Checksum) löscht ioException {bytebuffer bb = bytebuffer.alloclocation (Data.Length + 2) .Order (byteorder.buffer.buffer.buffer.buffer.buffer.buffer.bufr. BB.Put (Daten); BB.PUTSHORT (Prüfsumme); outputStream.write (BB.Array ()); }}Der CRC16 -Verifizierungsalgorithmus verwendet die Tabellen -Lookup -Methode.
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, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf. 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 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, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 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, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf777e, 0xc71d, 0xe75f, 0xf77e, 0xc71d, 0xd73c 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 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, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0}; public static char calc (byte [] bytes) {char crc = 0x0000; für (Byte b: bytes) {crc = (char) ((crc << 8) ^ crctable [(crc >> 8) ^ b) & 0x00ff]); } return (char) (crc); }}3. Verwendung
// Serialport ist das serielle Portobjekt xmodem xmodem = new Xmodem (serialport.getInputStream (), serialport.getOutputStream (); // filepath ist der Dateipfad //bin/xxx.binxModem.send(filepath);
4. Schreiben Sie am Ende
CODE CODE -Download
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.