1。はじめに
Xmodemは、シリアル通信で広く使用されている非同期ファイル転送プロトコルであり、2つのプロトコルに分割されています:Xmodem(128バイトデータブロックを使用)と1K-Xmodem(1024バイトデータブロック、つまり1Kバイトデータブロックを使用)プロトコル。
この記事では、CRC16検証を採用する128バイトのデータブロックのXmodemプロトコルを実装しています。プロジェクトに適用されると、送信および受信側は、特定の状況に応じて両当事者間の契約を変更できます。
シリアルコミュニケーションについてあまり知らない場合は、Javaを使用してシリアル通信を実装するために書いたブログを読むことができます。
2。実装
埋め込まれた学生を使用したデバッグプロセス中に、送信側がデータを速すぎて送信したため、受信側が処理できなくなったことがわかりました。したがって、sendメソッドで子スレッドが開かれ、データ送信ロジックを処理し、遅延処理の追加が容易になりました。
受信方法では、Cを送信することはCRCの検証を意味します。
public class xmodem {//プライベートファイナルバイトSOH = 0x01を開始します。 //プライベートファイナルバイトEOT = 0x04を終了します。 //プライベートファイナルバイトACK = 0x06に回答します。 //プライベートファイナルバイトnak = 0x15を再送信します。 //無条件のエンドプライベート最終バイトcan = 0x18; // 128バイトブロックのデータ転送プライベート最終int sector_size = 128; //最大エラー(応答なし)パケット数プライベート最終int max_errors = 10; //シリアルポートデータの読み取りに使用される入力ストリームPrivate inputStream inputStream; //シリアルポートデータの送信に使用される出力ストリームプライベート出力ストリーム出力ストリーム。 public xmodem(inputstream inputstream、outputstream outputstream){this.inputStream = inputstream; this.outputStream = outputStream; } / ***データの送信** @param filepath*ファイルパス* / public void send(final string filepath){new shood(){public void run(){try {//エラーパケットの数int errorcount; //パッケージ番号BYTE BLOCKNUMBER = 0x01; // Checksum int checkum; //バッファーインターンバイツに読み取られるバイト数。 // data buffer byte [] 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倍まで送信されますerrorcount = 0; while(errorcount <max_errors){//グループパケット//コントロール文字 +パケット番号 +パケット番号 +データ +チェックサムPutdata(soh)の逆コード; putdata(blocknumber); putdata(〜blockNumber); Checksum = crc16.calc(sector)&0x00ffff; PutCher(セクター、(短い)チェックサム); outputStream.flush(); //回答データバイトデータ= getData(); //回答が受信された場合、次のデータパケットがジャンプして次のデータのパケットを送信します} else {++ errorcount; }} //パケット番号はblocknumber =(byte)((++ blocknumber)%256)によって増加します。 } //すべてのデータが送信された後、送信エンドフラグブールisack = false; while(!isack){putdata(eot); isack = getData()== ack; }} catch(例外e){e.printstacktrace(); }}; }。始める(); } / ***データの受信** @param filepath*ファイルパス* @returnレセプションが完了したかどうか* @throws ioexception* exception* / public boolean receive(string filepath)スロー例外{// error packet int errorcount = 0; //パッケージ番号BYTE BLOCKNUMBER = 0x01; //データバイトデータ。 // Checksum int checkum; // data buffer byte [] section = new byte [sector_size];を初期化します。 // dataoutputStream outputStream = new DataOutputStream(new FileOutputStream(filePath))を初期化するためにファイルに書き込みます。 //文字CおよびCRC検証putdata((byte)0x43)を送信します。 while(true){if(errorcount> max_errors){outputstream.close(); falseを返します。 } //返信データデータ= getData(); if(data!= eot){try {//受信開始識別子if(data!= soh){errorcount ++;続く; } //パケットシリアル番号データを取得= getData(); //パケットシリアル番号が正しいかどうかを判断します(data!= blockNumber){errorcount ++;続く; } //パケットシリアル番号byte _blocknumber =(byte)〜getData()の逆コードを取得します。 //パケットシリアル番号の逆コードが正しいかどうかを判断します(data!= _blocknumber){errorcount ++;続く; } //(int i = 0; i <sector_size; i ++){sector [i] = getData();のデータを取得します。 } //チェックサムチェックサムを取得=(getData()&0xff)<< 8; CheckSum | =(getData()&0xff); //チェックサムが正しいかどうかを判断しますint crc = crc16.calc(sector); if(crc!= checksum){errorcount ++;続く; } //返信putdata(ack)を送信します。 //パケット番号はBlockNumber ++によって増加します。 // local outputstream.write(sector)にデータを書き込む; // errorcountがzero = 0にリセットされます。 } catch(Exception e){e.printstacktrace(); }最後に{//エラーが発生した場合、再送信識別子を送信します(errorcount!= 0){putdata(nak); }}} else {break; }} //出力ストリームoutputStream.close()を閉じる; //返信を送信しますputdata(ack); trueを返します。 } / *** data** @return data* @throws ioexception*例外* / private byte getdata()throws 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 checksum* checkum* @throws ioexception* exception* / private void putchar(byte [] data、short checkum)throws {bytebuffer bb = bytebuffer.allocate(data.length + 2)。 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、0xc18c、0xc18c、 0xf1ef、0x1231、0x0210、0x3273、0x2252、0x52b5、0x4294、0x72f7、0x62d6、0x9339、0x8318、0xb37b、0xa35a、0xd3bd、0xc39ff、0xc39ff、0xc39ff、0xc39ff 0x2462、0x3443、0x0420、0x1401、0x64e6、0x74c7、0x44a4、0x5485、0xa56a、0xb54b、0x8528、0x9509、0xe5ee、0xf5cf、0xc5ac、0xc5ac、0xc5ac、0xc5ac、0xc5ac、0xc5ac、0xc5ac、0xc5ac 0x2672、0x1611、0x0630、0x76d7、0x66f6、0x5695、0x46b4、0xb75b、0xa77a、0x9719、0x8738、0xf7df、0xe7fe、0xd79d、0xc7bc48e58e58e 0x6886、0x78a7、0x0840、0x1861、0x2802、0x3823、0xc9cc、0xd9ed、0xe98e、0xf9af、0x8948、0x9969、0xa90a、0xb92b、0x5af5、0x7ab7、 0x6a96、0x1a71、0x0a50、0x3a33、0x2a12、0xdbfd、0xcbdc、0xfbbf、0xeb9e、0x9b79、0x8b58、0xbb3b、0xab1a、0x6ca6、0x7c87、0x7c87、0x7c87、0x7c87、0x7c87、0x7c87 0x2c22、0x3c03、0x0c60、0x1c41、0xedae、0xfd8f、0xcdec、0xddcd、0xad2a、0xbd0b、0x8d68、0x9d49、0x7e97、0x6eb6、0x5ed5、0x43e、0x5ed5、0x43edef4、 0x2e32、0x1e51、0x0e70、0xff9f、0xefbe、0xdfdd、0xcffc、0xbf1b、0xaf3a、0x9f59、0x8f78、0x9188、0x81a9、0xb1ca、0xa1eb、0xcd10c、 0xf14e、0xe16f、0x1080、0x00a1、0x30c2、0x20e3、0x5004、0x4025、0x7046、0x6067、0x83b9、0x9398、0xa3fb、0xb3da、0xc33d、0xcdd37 0xf35e、0x02b1、0x1290、0x22f3、0x32d2、0x4235、0x5214、0x6277、0x7256、0xb5ea、0xa5cb、0x95a8、0x8589、0xf56e、0xf56e、0xe54f、0xe54f、0xe54f、 0x34e2、0x24c3、0x14a0、0x0481、0x7466、0x6447、0x5424、0x4405、0xa7db、0xb7fa、0x8799、0x97b8、0xe75f、0xf77e、0xc71d、0xc71d、 0x26d3、0x36f2、0x0691、0x16b0、0x6657、0x7676、0x4615、0x5634、0xd94c、0xc96d、0xf90e、0xe92f、0x99c8、0x89e9、0xb98a、0xb98a、0xb98a、0xb98a 0x4865、0x7806、0x6827、0x18c0、0x08e1、0x3882、0x28a3、0xcb7d、0xdb5c、0xeb3f、0xfb1e、0x8bf9、0x9bd8、0xfbbbbbbbbbbbbbbbb、0xbb9a、0xb9a5、 0x6a37、0x7a16、0x0af1、0x1ad0、0x2ab3、0x3a92、0xfd2e、0xed0f、0xdd6c、0xcd4d、0xbdaa、0xad8b、0x9de8、0x8dc9、0x7c26、0x64、0xx64、0xc26、0x45c64 0x4c45、0x3ca2、0x2c83、0x1ce0、0x0cc1、0xef1f、0xff3e、0xcf5d、0xdf7c、0xaf9b、0xbfba、0x8fd9、0x9ff8、0x6e17、0x7e36、0x4e55e74、 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。使用します
//シリアルポートはシリアルポートオブジェクトxmodem xmodem = new xmodem(serialport.getinputstream()、serialport.getOutputStream());
4。最後に書きます
完全なコードダウンロード
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。