SMSによるGPSトラック転送

ウォームアップされた分散型のフォールトトレラントバックエンド、すべての可能なプラットフォーム用に作成されたクールなモバイルアプリケーションがありますが、突然、ユーザーは文明から遠く離れており、コミュニケーションをとる唯一の方法はSMSですか? 次に、例としてGPSトラックを使用して、データ転送のためにこの古風なチャネルを使用して最大の情報を送信する方法についての物語を読むことは興味深いでしょう。



GPSトラックについて少し



特定のケースでは、トラックは、 時間と、場合によってはいくつかのフラグ (たとえば、トラックの先頭のSOS)を参照して、ユーザーが位置する座標によって定義された一連のポイントでした。



時間は次の方法で決定できます。



long time= System.currentTimeMillis();
      
      





座標は経度と緯度です。 AndroidのLocationオブジェクトは、経度と緯度にdoubleを使用します。



したがって、トラックの各ポイントには、64 + 2 * 64 + 2 = 194ビットの情報が含まれている必要があります。



SMSについて少し



SMSバイク
学生時代のゼロ年に、さまざまなウィンターアウトリーチスクールと青少年会議が市外のレクリエーションセンターで開催されました。 当時、街の外でのセルラー通信の信頼できる報道はまれであり、どういうわけか私の両親は彼らが生きていて元気で、凍り付かず、彼らの帽子を忘れないことを知らされなければなりませんでした。 SMSが必要かつ有用なものであるという理解が生まれました。 地上からSMSを送信することはできませんでしたが、特定の高さで-2回目または3回目は可能でした。 最も信頼できるのは、電話機を長いスティックにつなぎ、ダイヤルしてメッセージを送信し、スティックを上げ、しばらく垂直に保持してから、メッセージが送信されたかどうかを確認し、必要に応じて手順を繰り返すことでした。 一部の特に必死な人々は、この方法でSMSを送信することを期待して電話を捨てました-メッセージは送信されましたが、その後は雪の吹きだまりでノキアを探す必要がありました。 私の記憶では、単一の電話が失われたのではなく、壊れたわけではありません-Nokiaはそうです。



SMSの使用者(使用者)は、1つのSMSでキリル文字1文字に70文字、音訳に160文字を入力できることを覚えています! そこで不正があります。あなたは制裁を言います。



SMSの配置方法は、 RFC 5724で読むことができます。

GSM SMSメッセージは、送信可能な英数字のページングメッセージです

SMSクライアントから。 SMSメッセージの最大長は160です

文字(GSM文字セット[SMS-CHAR]の7ビット文字)、

または140オクテット。 その他の文字セット(UCS-2 16ビットなど)

文字、結果として70文字のメッセージ)もサポートされる場合があります

[SMS-CHAR]、ただしSMSによりオプションとして定義されている

仕様。 その結果、SMSメッセージを次のように処理するアプリケーション

文字処理アプリケーションのチェーンの一部は、

文字セットが文字との間で正しくマップされている

SMSメッセージに使用されるセット。


したがって、ペイロードとして、140バイトを使用できます。これは、7ビットエンコーディングで同じ160文字(ラテン文字、数字、 その他の文字 )になります。



大量のテキストを送信できますが、元のメッセージは部分に分割されます。 セグメント情報は各ピースの先頭にある特別なUDHヘッダーに格納されるため、各部分は6バイト少なくなります。 7ビット文字では、153が残ります。



理論的には、最大255セグメントの分割がサポートされていますが、実際には、6セグメントのみのサポートが保証されています。



バイナリ形式:タイトル



トラックのバイナリデータをSMSに配置するには、ソースデータの3バイトごとに4つの7ビット文字を出力する、Base64 7ビットエンコーディングとの単純で互換性のある変換を使用する必要があります。 合計すると、それほど多くの有用なデータは残っていません-ちょうど160 * 3/4 = 120バイトです。



アプリケーションには大きな未来があったので、開発中のフォーマットは1つのタイプのメッセージまたは1つのバージョンのプロトコルに限定されるべきではないため、タイプshortはmessageTypeに割り当てられました。



データはSMSを介して受信する必要があったため、従来のWebに馴染みのある証明書、パスワード、認証がないため、受信したメッセージをシステムユーザーにバインドする方法を学ぶ必要がありました:ランダムに生成されたlong型のauthenticationTokenが導入されました。



整合性制御のために、タイプshortのチェックサムフィールドが追加されました。



ヘッダーの合計サイズは2 + 8 + 2 = 12バイトです。



有用なデータの合計量からヘッダーサイズを除外します:120-12 = 108バイトまたは

864ビット。



素朴な実装



1つのトラックポイントは194ビットを占有します。 1つのSMSには864ビットのトラックデータが含まれます。 Ahem、864/194 = 4ポイントのみが適合します。



しかし、メッセージを6つのセグメントに分割するとどうなりますか? 1セグメント= 153 7ビット文字; 6セグメント= 153 * 6 = 818 7ビット文字。 有用なデータは818 * 3/4 = 613バイトになります。 したがって、613-12 = 601バイトまたは4808ビットがトラックデータの下に残ります。 合計で、4808/194 = 24ポイントを太いSMS'kuに入れることができ、さらに19バイトが残ります。



明らかなマイナスに加えて、メッセージに非常に少数のポイントを入れることができますが、長さが複数バイトを占めるポイントを操作するという不快なロジックはクロールアウトします。



最適化



時間



  1. 実際、ミリ秒の精度は必要ありません
  2. アプリケーションは過去数十年間データを送信しません
  3. アプリケーションが50年間変わらない可能性は低い


精度を4秒のままにします。



私たちの時代を紹介します:



 long ERA = 1388534400000L;
      
      





標準Unix(1970年1月1日UTC)に関連します。 上記の日付は、2014年1月1日UTCに対応しています。



最後の仮定を考えると、4バイトを保存するのに十分です。



(60/4)* 60 * 24 * 365.25 * 50 = 394,470,000 <2 ^ 29。 予備の3ビット(フラグ用)。



 long time= System.currentTimeMillis(); long newTime = (time - ERA) / (1000 * 4);
      
      





地理学



地球は球体に非常に近く、極から平らになっているため、赤道の長さ(40 075 696メートル)は2重子午線の長さ(40 008 552メートル)よりわずかに長くなっています。



ロケーションの座標は度で指定されます(±S / WおよびS / Sに依存)。



合計で、360度、つまり21,600分、または1,296,000秒の円があります。 したがって、赤道または子午線の1メートルでは、少なくとも0.032秒(1,296,000 / 40,075,696 = 0.0323388 ...)です。 たとえば、1メートルで60度の緯度では、平行度は約2倍の秒(約0.064秒)になります。 これはどういう意味ですか? 赤道および60番目の緯線での1メートルの位置決め誤差は、Location.getLongitude()の角度の誤差が半分異なります。 さらに、赤道から遠くなるほど、上のメートルで固定した場合の度数の誤差。 逆もまた同様です。度単位の固定誤差で赤道から離れる場合、メートル単位で誤差が減少します。つまり、赤道を赤道付近で32/1000秒に丸めると、1メートルを超えない最大の位置決め誤差が得られます。



5メートルの測位精度に満足していると仮定します(実際、GPSモジュールから受信した値の精度ははるかに悪いことが判明しています)。 境界線を低くしてみましょう。測位の精度を緯度と経度で少なくとも3メートルにします(5> 3 * sqrt(2))。



これで、座標をdoubleで破棄し、96/1000秒の精度で非負の整数値にすることができます。



 long newLatitude = (latitude + 90) * 60 * 60 * 1000 / 96; long newLongitude = (longitude + 180) * 60 * 60 * 1000 / 96;
      
      





明らかに、新しい値は360 * 60 * 60 * 1000/96 = 13,500,000 <2 ^ 24を超えず、3バイトに収まります。また、可能な最大値は値を保存するには、2倍少ない23ビットで十分です。



結果



トラックポイントサイズは4 + 3 + 3 = 10バイトに縮小され、さらにいくつかのビットが未使用のままになりました。 通常のSMSには864/80 = 10ポイントが含まれるようになりました。 6セグメントの太字:4808/80 = 60ポイント。



さらなる最適化



これまでは、ポイントが1つのトラックに属しているという事実を使用していなかったため、ポイント間の距離と時間間隔について推測することができます。



したがって、絶対座標と時間は最初のポイントに対してのみ固定され、後続のすべてのポイントは、座標と時間の両方で前のポイントに対するオフセットをそれ自体に保存しました。 このような最適化により、後続のポイントのサイズをさらに2バイトから8バイトに減らすことができ、その結果、1 SMS'keのポイントの合計数が13、太字で84に増えました。



フォーマットの説明



HEADER(96)+ BODY(変数):

|| メッセージタイプ(16)| 認証トークン(64)| チェックサム(16)|| データ(変数)||



最初のトラックポイント情報(80):

|| 開始(1)| SOS(1)| 予約済み(1)| 日時(29)| 予約済み(1)| 緯度(23)| 経度(24)||



NTHトラックポイント情報(64):

|| オフセット(16)| 開始(1)| SOS(1)| 北(1)| 緯度(21)| 予約済み(1)| 予約済み(1)| 東(1)| 経度(21)||



括弧内はビット単位のフィールド長です。





ヘッダー(12バイト)と2つのポイント(それぞれ10および8バイト)で構成されるバイナリメッセージ(30バイト)のHEXレコード:



00 01 00 11 AA BB CC DD EE FF 00 90 80 00 24 09 54 04 9D 89 87 A0 09 B1 40 00 00 20 92 7C







デコード:



 short messageType = 1; // 00 01 long authenticationToken = 4972798176784127L; // 00 11 AA BB CC DD EE FF short checksum = 144; // 00 90 boolean start = true; // [1]000 0000 00 24 09 boolean sos = false; // 1[0]000 0000 00 24 09 int dateTime = 9225; // 100[0 0000 00 24 09] // 1  2014 10:15:00 UTC int latitude = 5506205; // 0[101 0100 04 9D] // 56.83213333° . . ( : 56.832139° . .) int longitude = 9013152; // 89 87 A0 // 60.35072° . . ( : 60.350722° . .) int offset = 2481 // 09 B1 // 1  2014 12:45:24 UTC boolean start2 = false; // [0]100 0000 00 00 boolean sos2 = true; // 0[1]00 0000 00 00 boolean north2 = false; // 01[0]0 0000 00 00 int latitude2 = 0; // 010[0 0000 00 00] // 56.83213333° . . boolean east2 = true; // 00[1]0 0000 92 7C int longitude2 = 37500; // 001[0 0000 92 7C] // 61.35072° . .
      
      





PS近日公開予定! 誰かがこの投稿が役に立つ/面白いと思うことを願っています。



All Articles