1. Introdução
O Xmodem é um protocolo de transferência de arquivo assíncrono amplamente utilizado na comunicação serial, dividido em dois protocolos: Xmodem (usando blocos de dados de 128 bytes) e 1K-xmodem (usando blocos de dados de 1024 bytes, ou seja, blocos de dados de 1k bytes).
Este artigo implementa o protocolo XModem de blocos de dados de 128 bytes, que adotam a verificação do CRC16. Quando aplicado no projeto, a extremidade de envio e recebimento pode modificar o contrato entre ambas as partes de acordo com as circunstâncias específicas.
Se você não sabe muito sobre comunicação em série, pode ler o blog que escrevi para usar o Java para implementar a comunicação serial.
2. Implementação
Durante o processo de depuração com alunos incorporados, verificou -se que o lado enviado enviou dados muito rápido, o que fez com que o lado receptor não fosse capaz de processá -los. Portanto, um encadeamento infantil foi aberto no método de envio para processar a lógica de envio de dados, o que facilita a adição do processamento de atraso.
No método de recebimento, enviar C significa verificação no CRC.
classe pública xmodem {// iniciar o byte final privado Soh = 0x01; // final do byte final privado eot = 0x04; // Responda o byte final privado ACK = 0x06; // retransmissão de byte final privado nak = 0x15; // final de final privado incondicional CAN = 0x18; // transferir dados em 128 bytes Blocks Private final Int Sector_size = 128; // Erro máximo (sem resposta) Número de pacotes privados final int max_errors = 10; // fluxo de entrada, usado para ler dados de porta serial private inputStream inputStream; // fluxo de saída, usado para enviar dados de porta serial private OutputStream OutputStream; public xmodem (inputStream inputStream, outputStream OutputStream) {this.inputStream = inputStream; this.OutputStream = outputStream; } / *** Enviar dados** @param filepath* caminho do arquivo* / public void send (final string filepath) {new Thread () {public void run () {try {// número de pacotes de erros int errorCount; // Número do pacote bytes blockNumber = 0x01; // soma de verificação de verificação; // número de bytes lido para o buffer int nbytes; // Inicialize a seção byte de buffer de dados [] seção = novo byte [setor_size]; // Leia a inicialização do arquivo DatainputStream inputStream = new DatainputStream (new FileInputStream (FilePath)); while ((nbytes = inputStream.read (setor))> 0) {// Se o último pacote de dados for menor que 128 bytes, preencha -o com 0xff if (nbytes <setor_size) {for (int i = nbytes; i <setor_size; i ++) {para (i] (i 0 [por nbytes); }} // O mesmo pacote de dados é enviado até 10 vezes ErrorCount = 0; while (ErrorCount <max_errors) {// pacote de grupo // caracteres de controle + número do pacote + código inverso do número do pacote + dados + soma de verificação putdata (SOH); putdata (BlockNumber); putdata (~ blockNumber); soma de verificação = crc16.calc (setor) e 0x00ffff; putchar (setor, (curto) soma de verificação); outputStream.flush (); // Obtenha dados de dados de dados de dados = getData (); // Se a resposta for recebida, o próximo pacote de dados irá pular e enviar o próximo pacote de dados // nenhuma resposta é recebida, o número de pacotes incorretamente +1, continue a reenviar se (data == ack) {break; } else {++ errorCount; }} // O número do pacote é aumentado por blockNumber = (byte) ((++ blockNumber) % 256); } // Depois que todos os dados forem enviados, o sinalizador final da bandeira final boolean isack = false; while (! isack) {putdata (eot); isack = getData () == ACK; }} catch (Exceção e) {e.printStackTrace (); }}; }.começar(); } / *** Receba dados** @param filepath* caminho do arquivo* @return se a recepção é concluída* @throws ioexception* exceção* / public boolean receba (string filepath) lança exceção {// pacote de erro int errorCount = 0; // Número do pacote bytes blockNumber = 0x01; // dados de bytes de dados; // soma de verificação de verificação; // Inicialize a seção byte de buffer de dados [] seção = novo byte [setor_size]; // grava no arquivo para inicializar dataOutputStream outputStream = new DataOutputStream (new FileOutputStream (filepath)); // Envie a verificação do caractere C e CRC putdata ((byte) 0x43); while (true) {if (errorCount> max_errors) {outputStream.close (); retornar falso; } // Obtenha dados de resposta dados = getData (); if (dados! continuar; } // Obtenha os dados do número de série do pacote = getData (); // Determine se o número de série do pacote está correto se (dados! = Blocknumber) {errorCount ++; continuar; } // Obtenha o código inverso do número de série do pacote byte _blockNumber = (byte) ~ getData (); // Determine se o código inverso do número de série do pacote está correto se (dados! = _BlockNumber) {ErrorCount ++; continuar; } // Obtenha os dados para (int i = 0; i <setor_size; i ++) {setor [i] = getData (); } // Obtenha a soma de verificação de verificação = (getData () & 0xff) << 8; soma de verificação | = (getData () e 0xff); // determinar se a soma de verificação está correta int crc = Crc16.Calc (setor); if (CRC! = checksum) {ErrorCount ++; continuar; } // Envie a resposta putdata (ACK); // O número do pacote é incrementado pelo BlockNumber ++; // grava dados no outputStream.write (setor) local; // ErrorCount é redefinido para zero = 0; } catch (Exceção e) {e.printStackTrace (); } finalmente {// Se ocorrer um erro, envie o identificador de retransmissão se (errorCount! = 0) {putdata (nak); }}} else {break; }} // Fechar o fluxo de saída outputStream.close (); // Envie a resposta putdata (ACK); retornar true; } / *** Get Data** @return Data* @THOWSows IOException* Exception* / Private Byte getData () lança IoException {return (byte) inputStream.read (); } / *** Enviar dados** @Param Data* Dados* @Throws IoException* Exception* / private void putdata (int dados) lança IoException {outputStream.Write ((byte) dados); } / *** Enviar dados** @param dados* dados* @param checksum* soma de verificação* @throws ioexception* exceção* / private void putchar (byte [] dados, soma de verificação curta) lança ioexception {bytebuffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.bffher.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.buffer.Bert.BIGIG. bb.put (dados); bb.putShort (soma de verificação); outputStream.Write (bb.array ()); }}O algoritmo de verificação do CRC16 usa o método de pesquisa da tabela.
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, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xE7fe, 0x979d, 0x8738, 0xf7df, 0xE7fe, 0x979d, 0x8738, 0xf7df, 0xe7fe, 0x719, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0XE98E, 0xf9af, 0x8948, 0x9969, 0xxa94, 0xf9af, 0x8948, 0x9969, 0xxax4, 0xf9af, 0x8948, 0x9969, 0xxax4, 0xf9af, 0x8948, 0x9969, 0xxax4, 0xf9af, 0x8948, 0x9969, 0xxax4, 0xf9AF, 0x8948, 0x9969, 0xXax4, 0xf9af, 0x8948, 0x9969, 0xxax4. 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, 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, 0xe7db, 0xb7fa, 0x8799, 0x97b8, 0xE75f, 0xf77, 0x8799, 0x97b8, 0xE75f, 0xB7F7, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xE92f, 0x99c8, 0xc99e, 0xf90e, 0xE92f, 0x99c8, 0xc99e, 0xf90e, 0xE92F, 0x99c8, 0xc99e, 0xf90e, 0xE92F, 0x99c8, 0xc99e, 0xf90e, 0xE92f, 0x99c8, 0xc99e, 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; para (byte B: bytes) {Crc = (char) ((Crc << 8) ^ Crctable [((CRC >> 8) ^ B) & 0x00FF]); } retornar (char) (CRC); }}3. Use
// serialport é o objeto de porta serial xmodem xmodem = new xmodem (serialport.getInputStream (), serialport.getoutputStream ()); // filepath é o caminho do arquivo // ./bin/xxx.binxmodem.send.sEnd(FilePath);
4. Escreva no final
Download completo de código
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.