Bluetooth通信の
仕組みと活用法紹介
   2012.Aug.5th Takehiko YOSHIDA
                        twitter: @chihayafuru
              URL: http://www.chihayafuru.jp
アジェンダ
通信ハードウェア構成
フロー制御
電文フォーマット
NXTブロック ハードウェア仕様
メインプロセッサ: Atmel 32bit ARM processor
  256KB FLASH / 64KB RAM / 48MHz
サブプロセッサ: Atmel 8bit AVR processor
  4KB FLASH / 512KB RAM / 8MHz
Bluetoothチップ:
   CSR BlueCore 4 v2.0 + EDR System
  シリアルポートプロファイル(SPP)サポート
  内部RAM 47KBytes
  外部FLASH 8MBit
  26MHz
NXT通信 ブロック図
                  PC                                  NXT
          User Program                          User Program
      (Communication Protocol)                   (nxtOSEK)
仮想                                                                     SIO
COM                                                                  (UART)
      Bluetooth
         OS             USB                   USB
      Interface        Driver                Driver
                                                        Bluetooth
      Bluetooth                                          Hardware
        Driver                                            Driver
                                   USB                  (BlueCore)
      Bluetooth
       Dongle                    Bluetooth
オシロスコープによる信号波形観測
最小のシリアル通信配線



データ送信        データ送信


データ受信        データ受信




グラウンド        グラウンド
『フロー制御』
 って何?
無手順(フロー制御なし)

              くそ、自分のペースで
                話しやがって!
 ちゃんと          メモし損ねたけど
メモしろよ!            諦めよ…




    送信ノード   受信ノード
フロー制御あり

              話していいぞ!




送信ノード                   受信ノード
        実は…
ハードウェアフロー制御配線

データ送信      データ送信


データ受信      データ受信


送信要求       送信要求


送信可能       送信可能


グラウンド      グラウンド
NxtLoggerキャプチャ画面

    “DSR”って何?
DCEを中継した通信
データ端末装置                          データ端末装置
  (DTE)                            (DTE)



                CTS / RTS



  DSR / DTR   公衆通信回線網            DSR / DTR




  データ回線終端装置                 データ回線終端装置
      (DCE)                     (DCE)
シリアル通信 I/O名称
短縮名   方向           英語名                   意味


TxD   OUT   Transmit Exchange Data     送信データ

RxD   IN    Receive Exchange Data      受信データ

RTS   OUT      Request To Send         送信要求

CTS   IN        Clear To Send           送信可

DTR   OUT    Data Terminal Ready     データ端末レディ

DSR   IN        Data Set Ready       データ・セット・レディ
NXTハードウェア インターフェース




       引用: LEGO Mindstorms NXT Bluetooth Developer Kit
【PC】H/Wフロー制御コード nxtLogger
                                              LogPort.cs
88.   // シリアルポート番号設定
89.   this.PortName = portName;
90.
91.   // ポートのオープン制御
92.   this.Open();
                                        初期状態は
93.                               false(送信禁止)のため、
94.   // 受信バッファの破棄                    このコードは必須
95.   this.DiscardInBuffer();
96.
97.   // ハードウェアフロー制御
98.   this.DtrEnable = true;
99.   this.RtsEnable = true;
【NXT】H/Wフロー制御コード nxtOSEK
                                                    bt.c
88. void bt_init(void)
89. {
90. U8 trash;
91. U32 trash2;
92. in_buf_in_ptr = out_buf_ptr = 0;
93. in_buf_idx = 0;
94.
95. *AT91C_PMC_PCER = (1 << AT91C_PERIPHERAL_ID_US1);
96.
97. *AT91C_PIOA_PDR = BT_RX_PIN | BT_TX_PIN |
    BT_SCK_PIN | BT_RTS_PIN | BT_CTS_PIN;
98. *AT91C_PIOA_ASR = BT_RX_PIN | BT_TX_PIN |
    BT_SCK_PIN | BT_RTS_PIN | BT_CTS_PIN;
電文
フォーマット
バイナリダンプ
サンプルコード 電文フォーマット
オフセット

 +0000   0x20   ヘッダー部
 +0001   0x00   (ペイロード長)
 +0002   0x3F
 +0003   0x10   ペイロード部
 途中省略           (データー本体)
 +0033   0x72
電文の生成

送信処理
【NXT】電文生成部コード nxtOSEK
                                                       ecrobot_interface.c
318. U32 ecrobot_send_bt_packet(U8 *buf, U32 bufLen)
319. {
320.     SINT i;

321.     if (bt_status == BT_STREAM && bufLen <= BT_MAX_TX_BUF_SIZE-2)
322.             {
323.             sendBuf[0] = (U8) (bufLen & 0xFF);
324.             sendBuf[1] = (U8) ((bufLen >> 8) & 0xFF);
325.             for(i = 0; i < bufLen; i++)
326.             {
327.                     sendBuf[i+2] = buf[i];
328.             }
329.             bt_write(&sendBuf[0], 0, bufLen+2);
330.             return bufLen;
331.             }
332.             return 0;                       ※ソースコードの一部を省略
333. }
リトル
エンディアン
 って何?
エンディアネスの説明
           10進数: 32

    Int型(2byte)16進数: 0x0020
                    バイト単位に分割
            0x00   0x20
オフセット

 +0000   0x20      +0000   0x00
 +0001   0x00      +0001   0x20
下位バイトマスク処理
  sendBuf[0] = (U8) (bufLen & 0xFF);

             16進数表記         2進数表記

 bufLen       0x1234   0001 0010 0011 0100

   0xFF       0x00FF   0000 0000 1111 1111

sendBuf[0]    0x0034   0000 0000 0011 0100
上位バイトマスク処理
sendBuf[1] = (U8) ((bufLen >> 8) & 0xFF);

             16進数表記         2進数表記

 bufLen       0x1234   0001 0010 0011 0100

bufLen>>8     0x0012   0000 0000 0001 0010

   0xFF       0x00FF   0000 0000 1111 1111

sendBuf[0]    0x0034   0000 0000 0011 0100
上位バイトマスク処理
sendBuf[1] = (U8) ((bufLen >> 8) & 0xFF);

             16進数表記         2進数表記

 bufLen       0x1234   0001 0010 0011 0100

bufLen>>8     0x0012   0000 0000 0001 0010

   0xFF       0x00FF   0000 0000 1111 1111

sendBuf[0]    0x0034   0000 0000 0011 0100
論理シフト(unsigned int)の場合

10進表記           16進数表記         2進数表記

43776            0xAB00   1010 1011 0000 0000

        1/256                        8ビット右シフト


 171             0x00AB   0000 0000 1010 1011
算術シフト(signed int)の場合

10進表記          16進数表記         2進数表記

-21760          0xAB00   1010 1011 0000 0000

       1/256                        8ビット右シフト


 -85            0xFFAB   1111 1111 1010 1011
コンテナ部データ構成
オフセット     データ    オフセット    データ   オフセット   データ    オフセット   データ



  0                8             16             24
                                                       ADC2
  1                9             17             25
        システム時刻           モータ0           モータ2
         (ミリ秒)           カウンタ           カウンタ
  2               10             18             26
                                                       ADC3
  3               11             19             27

  4      データ1     12             20             28
                                        ADC0
  5      データ2     13             21             29
                         モータ1
                                                       I2C
                         カウンタ
  6               14             22             30
        バッテリーレ
                                        ADC1
          ベル
  7               15             23             31
【NXT】コンテナ部生成部コード (nxtOSEK)
                                                                 ecrobot_interface.c
735. void ecrobot_bt_data_logger(S8 data1, S8 data2)
736. {
737.     U8 data_log_buffer[32];

738.     *((U32   *)(&data_log_buffer[0]))    =   (U32)systick_get_ms();
739.     *(( S8   *)(&data_log_buffer[4]))    =    (S8)data1;
740.     *(( S8   *)(&data_log_buffer[5]))    =    (S8)data2;
741.     *((U16   *)(&data_log_buffer[6]))    =   (U16)ecrobot_inputs.battery_state;
742.     *((S32   *)(&data_log_buffer[8]))    =   (S32)nxt_motor_get_count(0);
743.     *((S32   *)(&data_log_buffer[12]))   =   (S32)nxt_motor_get_count(1);
744.     *((S32   *)(&data_log_buffer[16]))   =   (S32)nxt_motor_get_count(2);
745.     *((S16   *)(&data_log_buffer[20]))   =   (S16)sensor_adc(0);
746.     *((S16   *)(&data_log_buffer[22]))   =   (S16)sensor_adc(1);
747.     *((S16   *)(&data_log_buffer[24]))   =   (S16)sensor_adc(2);
748.     *((S16   *)(&data_log_buffer[26]))   =   (S16)sensor_adc(3);
749.     *((S32   *)(&data_log_buffer[28]))   =   (S32)getDistance();
750.
751.     ecrobot_send_bt_packet(data_log_buffer, 32);
752. }
                                  『リトル・エンディアン』前提の移植性の低いコード
電文の解析

受信処理
【PC】コンテナ部解析部コード (nxtLogger)
                                                  LogMessage.cs
248.// パケットをフィールドに変換
249.this.sysTick = BitConverter.ToUInt32(packetPayload, 0);
250.this.dataLeft = (SByte)packetPayload[4];
251.this.dataRight = (SByte)packetPayload[5];
252.this.batt = BitConverter.ToUInt16(packetPayload, 6);
253.this.motorCnt0 = BitConverter.ToInt32(packetPayload, 8);
254.this.motorCnt1 = BitConverter.ToInt32(packetPayload, 12);
255.this.motorCnt2 = BitConverter.ToInt32(packetPayload, 16);
256.this.sensorAdc0 = BitConverter.ToInt16(packetPayload, 20);
257.this.sensorAdc1 = BitConverter.ToInt16(packetPayload, 22);
258.this.sensorAdc2 = BitConverter.ToInt16(packetPayload, 24);
259.this.sensorAdc3 = BitConverter.ToInt16(packetPayload, 26);
260.this.i2c = BitConverter.ToInt32(packetPayload, 28);
BitConverterクラス
• 基本データ型をバイト配列に、バイト配列を基本
  データ型に変換します。
• BitConverter.ToUInt16() unsigned型
• BitConverter.ToUInt16() signed型
• Intel系CPUはリトル・エンディアンのため
  BitConverterクラスもリトル・エンディアンで
  動作します。
• 非Intel系CPU(ビッグ・エンディアン)への移植の
  可能性があるのであれば、
  BitConverter.IsLittleEndianフィールドのTrue/False
  で判定してバイト列を反転しましょう!
Bluetooth通信の留意事項
        • 受信モードから送信モードに切り替わるとき約30ミリ秒の遅れが生じる
        • 大きなデータパケットを受信する場合、ARMプロセッサとの間に短時間の
H/W制約     遅延(small timing difference)が発生する。



        • 電文の途中にで送受信の一時停止が発生する。
        • 電文と電文の間のタイムラグ(休止時間)が短くなる。
 影響


        • 1つの電文を2回以上のデータ受信処理(APIコール)に分割して受信する。
        • 1回のデータ受信処理(API)で2つ以上の電文を受け取ってしまう。
 結果
電文受信 ステートマシン図
        [受信バイト == 開始コード(0x20, 0x00)]




       電文待ち                   電文受信
初期状態


            [受信バイト数 == 電文長]
電文受信 状態遷移表

     イベント              受信バイト
                                      受信バイト数
状態           開始コード                     == 電文長
                               その他
            (0x20, 0x00)


電文待ち         電文受信              電文待ち    電文待ち




電文受信         電文受信              電文受信    電文待ち
【PC】受信バイト列を1バイトに分割するコード
                                        Form1.cs
99. /// <summary>
100. /// (メインスレッドの)ログデータ受信
101. /// </summary>
102. /// <param name="mes">データ</param>
103. private void messegeReceive(Byte[] mes)
104. {
105.     for (int i = 0; i < mes.Length; i++)
106.     {
107.         log.Append(mes[i]);
108.     }     電文の先頭を見つけるために一旦、1バイトずつに分割
109. }            Byte[0]が電文の先頭とは限らない!!!
【PC】状態遷移(分岐)処理
                                                   LogMessage.cs
216.   public void Append(Byte dat)
217.   {
218.       // パケットヘッダー部
219.       if (byteNo < PacketHeaderLen)
220.       {
221.            // 順送りでパケットヘッダー配列へ保存              状態遷移の『電文待ち』
222.            packetHeader[byteNo++] = dat;
223.            // 中略
224.       }
225.       // パケットペイロード(ヘッダーを除いた本体部)
226.       else if (byteNo < PacketLen)
227.       {                                       状態遷移の『電文受信』
228.            // 中略
229.       }
230.       else     // byteNo >= PacketLenは設計の想定外
231.       {                                       状態遷移の設計外
232.            byteNo = 0;
233.       }
234.   }
                                                  ※ソースコードの一部を省略
【PC】電文ヘッダー判定処理
                                                      LogMessage.cs
211.   // 順送りでパケットヘッダー配列へ保存
212.   packetHeader[byteNo++] = dat;
213.
214.   if (byteNo == PacketHeaderLen)
215.   {
216.     // パケットヘッダー(パケットサイズ)のチェック
217.     // NXTから送信されるパケットサイズにはヘッダの2バイト分は含まれない
218.     UInt16 len = BitConverter.ToUInt16(packetHeader, 0);
219.
220.       if (len != PacketPayloadLen)
221.       {
222.         // パケット仕様: ヘッダー = ペイロードサイズ
223.         // 想定したヘッダー値でなければ1バイト分を読み捨てる
224.         packetHeader[0] = packetHeader[1];
225.         byteNo = 1;
226.       }
227.   }
ご静聴ありがとうございます

Bluetooth通信の 仕組みと活用法紹介

  • 1.
    Bluetooth通信の 仕組みと活用法紹介 2012.Aug.5th Takehiko YOSHIDA twitter: @chihayafuru URL: http://www.chihayafuru.jp
  • 2.
  • 3.
    NXTブロック ハードウェア仕様 メインプロセッサ: Atmel32bit ARM processor 256KB FLASH / 64KB RAM / 48MHz サブプロセッサ: Atmel 8bit AVR processor 4KB FLASH / 512KB RAM / 8MHz Bluetoothチップ: CSR BlueCore 4 v2.0 + EDR System シリアルポートプロファイル(SPP)サポート 内部RAM 47KBytes 外部FLASH 8MBit 26MHz
  • 4.
    NXT通信 ブロック図 PC NXT User Program User Program (Communication Protocol) (nxtOSEK) 仮想 SIO COM (UART) Bluetooth OS USB USB Interface Driver Driver Bluetooth Bluetooth Hardware Driver Driver USB (BlueCore) Bluetooth Dongle Bluetooth
  • 5.
  • 6.
    最小のシリアル通信配線 データ送信 データ送信 データ受信 データ受信 グラウンド グラウンド
  • 7.
  • 8.
    無手順(フロー制御なし) くそ、自分のペースで 話しやがって! ちゃんと メモし損ねたけど メモしろよ! 諦めよ… 送信ノード 受信ノード
  • 9.
    フロー制御あり 話していいぞ! 送信ノード 受信ノード 実は…
  • 10.
    ハードウェアフロー制御配線 データ送信 データ送信 データ受信 データ受信 送信要求 送信要求 送信可能 送信可能 グラウンド グラウンド
  • 11.
    NxtLoggerキャプチャ画面 “DSR”って何?
  • 12.
    DCEを中継した通信 データ端末装置 データ端末装置 (DTE) (DTE) CTS / RTS DSR / DTR 公衆通信回線網 DSR / DTR データ回線終端装置 データ回線終端装置 (DCE) (DCE)
  • 13.
    シリアル通信 I/O名称 短縮名 方向 英語名 意味 TxD OUT Transmit Exchange Data 送信データ RxD IN Receive Exchange Data 受信データ RTS OUT Request To Send 送信要求 CTS IN Clear To Send 送信可 DTR OUT Data Terminal Ready データ端末レディ DSR IN Data Set Ready データ・セット・レディ
  • 14.
    NXTハードウェア インターフェース 引用: LEGO Mindstorms NXT Bluetooth Developer Kit
  • 15.
    【PC】H/Wフロー制御コード nxtLogger LogPort.cs 88. // シリアルポート番号設定 89. this.PortName = portName; 90. 91. // ポートのオープン制御 92. this.Open(); 初期状態は 93. false(送信禁止)のため、 94. // 受信バッファの破棄 このコードは必須 95. this.DiscardInBuffer(); 96. 97. // ハードウェアフロー制御 98. this.DtrEnable = true; 99. this.RtsEnable = true;
  • 16.
    【NXT】H/Wフロー制御コード nxtOSEK bt.c 88. void bt_init(void) 89. { 90. U8 trash; 91. U32 trash2; 92. in_buf_in_ptr = out_buf_ptr = 0; 93. in_buf_idx = 0; 94. 95. *AT91C_PMC_PCER = (1 << AT91C_PERIPHERAL_ID_US1); 96. 97. *AT91C_PIOA_PDR = BT_RX_PIN | BT_TX_PIN | BT_SCK_PIN | BT_RTS_PIN | BT_CTS_PIN; 98. *AT91C_PIOA_ASR = BT_RX_PIN | BT_TX_PIN | BT_SCK_PIN | BT_RTS_PIN | BT_CTS_PIN;
  • 17.
  • 18.
  • 19.
    サンプルコード 電文フォーマット オフセット +0000 0x20 ヘッダー部 +0001 0x00 (ペイロード長) +0002 0x3F +0003 0x10 ペイロード部 途中省略 (データー本体) +0033 0x72
  • 20.
  • 21.
    【NXT】電文生成部コード nxtOSEK ecrobot_interface.c 318. U32 ecrobot_send_bt_packet(U8 *buf, U32 bufLen) 319. { 320. SINT i; 321. if (bt_status == BT_STREAM && bufLen <= BT_MAX_TX_BUF_SIZE-2) 322. { 323. sendBuf[0] = (U8) (bufLen & 0xFF); 324. sendBuf[1] = (U8) ((bufLen >> 8) & 0xFF); 325. for(i = 0; i < bufLen; i++) 326. { 327. sendBuf[i+2] = buf[i]; 328. } 329. bt_write(&sendBuf[0], 0, bufLen+2); 330. return bufLen; 331. } 332. return 0; ※ソースコードの一部を省略 333. }
  • 22.
  • 23.
    エンディアネスの説明 10進数: 32 Int型(2byte)16進数: 0x0020 バイト単位に分割 0x00 0x20 オフセット +0000 0x20 +0000 0x00 +0001 0x00 +0001 0x20
  • 24.
    下位バイトマスク処理 sendBuf[0]= (U8) (bufLen & 0xFF); 16進数表記 2進数表記 bufLen 0x1234 0001 0010 0011 0100 0xFF 0x00FF 0000 0000 1111 1111 sendBuf[0] 0x0034 0000 0000 0011 0100
  • 25.
    上位バイトマスク処理 sendBuf[1] = (U8)((bufLen >> 8) & 0xFF); 16進数表記 2進数表記 bufLen 0x1234 0001 0010 0011 0100 bufLen>>8 0x0012 0000 0000 0001 0010 0xFF 0x00FF 0000 0000 1111 1111 sendBuf[0] 0x0034 0000 0000 0011 0100
  • 26.
    上位バイトマスク処理 sendBuf[1] = (U8)((bufLen >> 8) & 0xFF); 16進数表記 2進数表記 bufLen 0x1234 0001 0010 0011 0100 bufLen>>8 0x0012 0000 0000 0001 0010 0xFF 0x00FF 0000 0000 1111 1111 sendBuf[0] 0x0034 0000 0000 0011 0100
  • 27.
    論理シフト(unsigned int)の場合 10進表記 16進数表記 2進数表記 43776 0xAB00 1010 1011 0000 0000 1/256 8ビット右シフト 171 0x00AB 0000 0000 1010 1011
  • 28.
    算術シフト(signed int)の場合 10進表記 16進数表記 2進数表記 -21760 0xAB00 1010 1011 0000 0000 1/256 8ビット右シフト -85 0xFFAB 1111 1111 1010 1011
  • 30.
    コンテナ部データ構成 オフセット データ オフセット データ オフセット データ オフセット データ 0 8 16 24 ADC2 1 9 17 25 システム時刻 モータ0 モータ2 (ミリ秒) カウンタ カウンタ 2 10 18 26 ADC3 3 11 19 27 4 データ1 12 20 28 ADC0 5 データ2 13 21 29 モータ1 I2C カウンタ 6 14 22 30 バッテリーレ ADC1 ベル 7 15 23 31
  • 31.
    【NXT】コンテナ部生成部コード (nxtOSEK) ecrobot_interface.c 735. void ecrobot_bt_data_logger(S8 data1, S8 data2) 736. { 737. U8 data_log_buffer[32]; 738. *((U32 *)(&data_log_buffer[0])) = (U32)systick_get_ms(); 739. *(( S8 *)(&data_log_buffer[4])) = (S8)data1; 740. *(( S8 *)(&data_log_buffer[5])) = (S8)data2; 741. *((U16 *)(&data_log_buffer[6])) = (U16)ecrobot_inputs.battery_state; 742. *((S32 *)(&data_log_buffer[8])) = (S32)nxt_motor_get_count(0); 743. *((S32 *)(&data_log_buffer[12])) = (S32)nxt_motor_get_count(1); 744. *((S32 *)(&data_log_buffer[16])) = (S32)nxt_motor_get_count(2); 745. *((S16 *)(&data_log_buffer[20])) = (S16)sensor_adc(0); 746. *((S16 *)(&data_log_buffer[22])) = (S16)sensor_adc(1); 747. *((S16 *)(&data_log_buffer[24])) = (S16)sensor_adc(2); 748. *((S16 *)(&data_log_buffer[26])) = (S16)sensor_adc(3); 749. *((S32 *)(&data_log_buffer[28])) = (S32)getDistance(); 750. 751. ecrobot_send_bt_packet(data_log_buffer, 32); 752. } 『リトル・エンディアン』前提の移植性の低いコード
  • 32.
  • 33.
    【PC】コンテナ部解析部コード (nxtLogger) LogMessage.cs 248.// パケットをフィールドに変換 249.this.sysTick = BitConverter.ToUInt32(packetPayload, 0); 250.this.dataLeft = (SByte)packetPayload[4]; 251.this.dataRight = (SByte)packetPayload[5]; 252.this.batt = BitConverter.ToUInt16(packetPayload, 6); 253.this.motorCnt0 = BitConverter.ToInt32(packetPayload, 8); 254.this.motorCnt1 = BitConverter.ToInt32(packetPayload, 12); 255.this.motorCnt2 = BitConverter.ToInt32(packetPayload, 16); 256.this.sensorAdc0 = BitConverter.ToInt16(packetPayload, 20); 257.this.sensorAdc1 = BitConverter.ToInt16(packetPayload, 22); 258.this.sensorAdc2 = BitConverter.ToInt16(packetPayload, 24); 259.this.sensorAdc3 = BitConverter.ToInt16(packetPayload, 26); 260.this.i2c = BitConverter.ToInt32(packetPayload, 28);
  • 34.
    BitConverterクラス • 基本データ型をバイト配列に、バイト配列を基本 データ型に変換します。 • BitConverter.ToUInt16() unsigned型 • BitConverter.ToUInt16() signed型 • Intel系CPUはリトル・エンディアンのため BitConverterクラスもリトル・エンディアンで 動作します。 • 非Intel系CPU(ビッグ・エンディアン)への移植の 可能性があるのであれば、 BitConverter.IsLittleEndianフィールドのTrue/False で判定してバイト列を反転しましょう!
  • 35.
    Bluetooth通信の留意事項 • 受信モードから送信モードに切り替わるとき約30ミリ秒の遅れが生じる • 大きなデータパケットを受信する場合、ARMプロセッサとの間に短時間の H/W制約 遅延(small timing difference)が発生する。 • 電文の途中にで送受信の一時停止が発生する。 • 電文と電文の間のタイムラグ(休止時間)が短くなる。 影響 • 1つの電文を2回以上のデータ受信処理(APIコール)に分割して受信する。 • 1回のデータ受信処理(API)で2つ以上の電文を受け取ってしまう。 結果
  • 36.
    電文受信 ステートマシン図 [受信バイト == 開始コード(0x20, 0x00)] 電文待ち 電文受信 初期状態 [受信バイト数 == 電文長]
  • 37.
    電文受信 状態遷移表 イベント 受信バイト 受信バイト数 状態 開始コード == 電文長 その他 (0x20, 0x00) 電文待ち 電文受信 電文待ち 電文待ち 電文受信 電文受信 電文受信 電文待ち
  • 38.
    【PC】受信バイト列を1バイトに分割するコード Form1.cs 99. /// <summary> 100. /// (メインスレッドの)ログデータ受信 101. /// </summary> 102. /// <param name="mes">データ</param> 103. private void messegeReceive(Byte[] mes) 104. { 105. for (int i = 0; i < mes.Length; i++) 106. { 107. log.Append(mes[i]); 108. } 電文の先頭を見つけるために一旦、1バイトずつに分割 109. } Byte[0]が電文の先頭とは限らない!!!
  • 39.
    【PC】状態遷移(分岐)処理 LogMessage.cs 216. public void Append(Byte dat) 217. { 218. // パケットヘッダー部 219. if (byteNo < PacketHeaderLen) 220. { 221. // 順送りでパケットヘッダー配列へ保存 状態遷移の『電文待ち』 222. packetHeader[byteNo++] = dat; 223. // 中略 224. } 225. // パケットペイロード(ヘッダーを除いた本体部) 226. else if (byteNo < PacketLen) 227. { 状態遷移の『電文受信』 228. // 中略 229. } 230. else // byteNo >= PacketLenは設計の想定外 231. { 状態遷移の設計外 232. byteNo = 0; 233. } 234. } ※ソースコードの一部を省略
  • 40.
    【PC】電文ヘッダー判定処理 LogMessage.cs 211. // 順送りでパケットヘッダー配列へ保存 212. packetHeader[byteNo++] = dat; 213. 214. if (byteNo == PacketHeaderLen) 215. { 216. // パケットヘッダー(パケットサイズ)のチェック 217. // NXTから送信されるパケットサイズにはヘッダの2バイト分は含まれない 218. UInt16 len = BitConverter.ToUInt16(packetHeader, 0); 219. 220. if (len != PacketPayloadLen) 221. { 222. // パケット仕様: ヘッダー = ペイロードサイズ 223. // 想定したヘッダー値でなければ1バイト分を読み捨てる 224. packetHeader[0] = packetHeader[1]; 225. byteNo = 1; 226. } 227. }
  • 41.