##概要
SORACOMのバイナリパーサーを有効にして、SORACOMコンソールで送信したデータを確認すると、どうやら変換がうまくいっていませんでした。
その原因を突き止めるのに悪戦苦闘したので、判明した原因を共有します。
##結論
まず、結論から。
見た目では16進数に変換できていたのですが、内部ではASCII文字として保存されていたからです。
##目標と結果
-
やったこと
経度: 139.752101, 緯度: 35.682501を、SORACOM Unified Endpointにバイナリで送る。 -
目標
コンソール上で**{"lat":139.752101,"lng":35.682501,"binaryParserEnabled":true}**と確認できる。 -
結果
コンソールでは、**{"lat":943.010871,"lng":845.23141,"binaryParserEnabled":true}**と表示されてしまう。
##実装していたソースコード
スケッチの loop()内の処理のみ、共有します。
// 実際のデータは、grove-gpsセンサから読み取った値が格納。
double lat = 139.752101;
double lng = 35.682501;
unsigned long int const lat_decimal = (unsigned long int)(lat * 1000000);
unsigned long int const lng_decimal = (unsigned long int)(lng * 1000000);
char post_data[64];
sprintf(post_data, "%x%x", lat_decimal, lng_decimal);
SerialUSB.print("post data: ");
SerialUSB.println(post_data);
// UDPプロトコルでデータを送信
Nectis.PostDataViaUdp(post_data);
##間違いポイント
- sprintf() で変換指定子を16進数の %x にすれば良い
と勘違いしていたところです。
この方法で変換した送信データをArduinoIDEのシリアルモニタで確認すると、
Send:85472a522078c5
となっており、10進数に戻すと、見た目上は確かにlat,lngになります。
さらに、SORACOM Binary Parser Playgroundで試してみても、うまく変換できてしまいます。
どうして思い通りに変換できなかったのかというと、16進数に変換したデータを16進数のASCII文字として送信していたからです。
##失敗した送信データを解読してみる
ArduinoIDEのシリアルモニタで確認した送信データ**"85472a522078c5"**が、バイナリパーサーで変換すると、
{"lat":943.010871,"lng":845.23141,"binaryParserEnabled":true}
となることを確認していきます。
送信データを先頭から16進数のASCII文字に変換していくと、
85472a522078c5 => 38 35 34 37 32 61 35 32 32 30 37 38 63 35
となります。
先頭の4Bytes、即ち38 35 34 37を16進数とみなし、10進数に変換してみます。
(38353437)16 = (943010871)10
SORACOMコンソールで確認できたデータの"lat"と一致しました。
同様に、次の4Bytesを変換すると、
(32613532)16 = (845231410)10
となり、これもコンソールで確認できたデータの"lng"と一致します。
##まとめ
扱っているデータが、16進数のASCII文字なのか、16進数の数値なのか、しっかりと確認しましょう。