低レベルなKotlin

 低レベルなKotlin

F46a37b9f855c245f72a07b04045216a?s=128

Tomoya Miwa

July 03, 2018
Tweet

Transcript

  1. 低レベルな Kotlin tomoya0x00 集まれKotlin好き︕Kotlin愛好会 vol2

  2. About me tomoya0x00 Twitter, GitHub, Qiita Android, Embedded system, BLE/BT,

    iOS DeNA Co., Ltd. Automotive Business Unit.
  3. 低レベル 低レイヤー

  4. BT/BLE通信をKotlinで書いてて ちょっとハマった事 ※BT/BLEの技術的な話しはゼロなのでご安⼼を ※⼀応、Androidアプリのお話しです

  5. KotlinのByte型は 符号有り Javaも同じだけど

  6. 何が困るのか︖

  7. 何が困るのか︖ BT/BLE通信に限らず、デバイス間通信では 符号無し 前提で通信する ことがまぁまぁある なので、サイズ1byteで 符号無し な型が欲しくなるときがある

  8. 困る例 // 通信して受信したデータだとする val received = 0x80.toByte() // 10進数で 128

    と出⼒されるのが期待値 println(received) result -128
  9. NG

  10. なぜこうなるのか︖

  11. 負の数のコンピューター内部表現

  12. 負の数のコンピューター内部表現 基本的には 2の補数 で表現されている 詳細は ぐぐる or 直接聞いてみてね︕ そして、最上位bitが⽴っていれば負の数と判定できる

  13. KotlinのByte型における0x80とは 最上位bitが⽴っているので、負の数 10進数表現では -128 となってしまう

  14. どうするのか︖

  15. toInt()して下位1byteだけ取り出す 1. 符号無しとして扱ったときの最⼤値が⼗分に表現できる型へ変換 2. 不要な部分はマスクして捨てる // 通信して受信したデータだとする val received =

    0x80.toByte() // 10進数で 128 と出⼒されるのが期待値 println(received.toInt() and 0xff) result 128
  16. OK

  17. チェックサム

  18. チェックサム is 何︖

  19. データ転送時のエラー検出⽅法の⼀つ シリアル通信とかで独⾃プロトコル実装時に良く使われている TCP/IPでも使われているよ チェックサム⾃体、何パターンかある 全部⾜してゼロ 全部⾜した下位1byte ★今回取り上げるパターン CRC etc...

  20. Example

  21. Aデバイス Bデバイス

  22. 0x80, 0x01, 0x02, 0x84 を送信したい

  23. 送信フォーマット 以降、送信フォーマットに合わせたデータを パケット と呼びます データ部サイズ (1byte) データ部(0〜 255byte) チェックサム(1byte) 0x01

    0x02 0xfe ※チェックサムの計算にデータ部サイズは含めないものとする
  24. 送信︓Aデバイス 1. 0x80, 0x01, 0x02, 0x84 を全部⾜す -> 0x0107 2.

    0x0107 の下位1byteを取り出す -> 0x07 3. 計算結果をチェックサム値とし、送信フォーマットに合わせて送信 送信したパケット データ部サイズ (1byte) データ部(0〜 255byte) チェックサム(1byte) 0x04 0x80,0x01,0x02,0x84 0x07
  25. 受信︓Bデバイス 1. 1byte読み出し、データ部サイズが4byteであることを知る 2. 4byte読み出して全部⾜し、下位1byteを取り出す -> 0x07 3. 1byte読み出し(チェックサム)、計算結果と合致を確認 受信したパケット

    データ部サイズ (1byte) データ部(0〜 255byte) チェックサム(1byte) 0x04 0x80,0x01,0x02,0x84 0x07
  26. チェックサムの部分をKotlinで

  27. in Kotlin 2の補数表現の事を考慮して・・・ // 通信して受信したByteArrayだとする val received = read() val

    size = received[0] val body = received.slice(1 until size + 1) val checkSum = received[size + 1] val sum = body.map { it.toLong() and 0xff }.sum() val isValid = (sum and 0xff) == (checkSum.toLong() and 0xff) println(isValid)
  28. OK

  29. But...

  30. これでも良さそう ということに資料作っている内に気付きました・・・ // 通信して受信したByteArrayだとする val received = read() val size

    = received[0] val body = received.slice(1 until size + 1) val checkSum = received[size + 1] //val sum = body.map { it.toLong() and 0xff }.sum() val sum = body.sum() //val isValid = (sum and 0xff) == (checkSum.toLong() and 0xff) val isValid = sum and 0xff == checkSum.toInt() println(isValid)
  31. なんででしょうね︖ 2の補数とかで説明できそうな気がしています

  32. ありがとうございました