Upgrade to Pro — share decks privately, control downloads, hide ads and more …

低レベルなKotlin

 低レベルなKotlin

Tomoya Miwa

July 03, 2018
Tweet

More Decks by Tomoya Miwa

Other Decks in Programming

Transcript

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

    View Slide

  2. About me
    tomoya0x00
    Twitter, GitHub, Qiita
    Android, Embedded system, BLE/BT, iOS
    DeNA Co., Ltd.
    Automotive Business Unit.

    View Slide

  3. 低レベル 低レイヤー

    View Slide

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

    View Slide

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

    View Slide

  6. 何が困るのか︖

    View Slide

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

    View Slide

  8. 困る例
    // 通信して受信したデータだとする
    val received = 0x80.toByte()
    // 10進数で 128 と出⼒されるのが期待値
    println(received)
    result
    -128

    View Slide

  9. NG

    View Slide

  10. なぜこうなるのか︖

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  14. どうするのか︖

    View Slide

  15. toInt()して下位1byteだけ取り出す
    1. 符号無しとして扱ったときの最⼤値が⼗分に表現できる型へ変換
    2. 不要な部分はマスクして捨てる
    // 通信して受信したデータだとする
    val received = 0x80.toByte()
    // 10進数で 128 と出⼒されるのが期待値
    println(received.toInt() and 0xff)
    result
    128

    View Slide

  16. OK

    View Slide


  17. View Slide

  18. チェックサム

    View Slide

  19. チェックサム is 何︖

    View Slide

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

    View Slide

  21. Example

    View Slide

  22. Aデバイス Bデバイス

    View Slide

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

    View Slide

  24. 送信フォーマット
    以降、送信フォーマットに合わせたデータを パケット と呼びます
    データ部サイズ
    (1byte)
    データ部(0〜
    255byte)
    チェックサム(1byte)
    0x01 0x02 0xfe
    ※チェックサムの計算にデータ部サイズは含めないものとする

    View Slide

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

    View Slide

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

    View Slide

  27. チェックサムの部分をKotlinで

    View Slide

  28. 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)

    View Slide

  29. OK

    View Slide

  30. But...

    View Slide

  31. これでも良さそう
    ということに資料作っている内に気付きました・・・
    // 通信して受信した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)

    View Slide

  32. なんででしょうね︖
    2の補数とかで説明できそうな気がしています

    View Slide

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

    View Slide