Universal NMEA 0183 Parser / Formatter in C#(+ port on JAVA)

プレフィックス



どんなに些細なことに聞こえるかもしれませんが、 NMEAメッセージの操作を(私の意見では)完全にサポートできる既成のソリューションを探していましたが、私はそれを見つけませんでした。



公式文書を研究した後、私はこれを確実に実現するというアイデアに完全に夢中になりました。



プロット



人々を許してくれますが、わかりやすくするために、それでも現象の物理学について簡単に説明します。

そのため、NMEA規格のメッセージは、規格自体では「センテンス」と呼ばれ、これらの「センテンス」が「話す」-「トーカー」です。 したがって、たとえば、NMEA内のGPSアプリケーションの識別子は「GP」であり、 Cheberleinに対する答えは「GL」です。



既存のソリューションは、これら2種類のデバイスのみで機能し、最良の場合、特定のメーカー(Germin、UBLOxなど)のチームレシーバーに固有のさまざまなものを理解していました。

そして、誰が知っているか、突然、原子時計からのデータを解釈する必要が緊急に必要になります(話者:ZA)、またはロランCシステム(話者:LC)を使用して自分自身を配置しますが、オートパイロット(話者:AG)とチャットする可能性を排除することはできません!







実際、この規格には、トーカーとして機能する34種類のデバイス、約74種類のメッセージ(文章)、独自のコード(トーカー:P)を使用する可能性-デバイスメーカーの裁量で独自のコマンドセットが記載されています。 そして、このキッチン全体を単一の名前空間の下でカバーせずに、恥ずかしがるでしょう!



一般に、私は望ましい結果から始めました。 その結果、次のコードが機能するようにタスクが設定されました。



NMEASentence parsedSentence = NMEAParser.Parse(sourceString);
      
      







その他:



 string NMEASentenceString = NMEAParser.Build(parsedSentence);
      
      







NMEASentenceの内部は次のようになります。



 public sealed class NMEASentence { public TalkerIdentifiers TalkerID; public SentenceIdentifiers SentenceID; public object[] parameters; }
      
      







ちなみに、NMEA文の一般的な形式は次のとおりです。



$ <talker ID> <entent ID、> [parameter 1]、[parameter 2]、... [<*チェックサム>] <CR> <LF>



これは、先頭と末尾に「$」が付いた82文字以下のASCII文字列です。 そのような文字列を部分に分類することは困難ではありません-すべては単純なstring.Split()で行われます;問題は特定の式をチェックして解析する方法です。

この規格では、いくつかの基本的なタイプのデータについて説明していますが、規格のドキュメントでは次のように示されています。



「X」は全体です

「Xx」-本物

「C-c」は文字列です

Hh-16進数

「Llll.ll」-緯度

「Yyyyy.yy」-経度

「Hhmmss.ss」-時間

「Ddmmyy」-日付

「A」は記号です



マジックストリング「...」がまだあります。これは、後続のすべてのメッセージパラメータが前のパラメータと同じタイプであることを意味します。



解析を実装するために、基本的なものから各コマンドを継承し、各コマンドのロジックを個別に実装することから、各パラメーターをヒューリスティックに解析するまで、さまざまなオプションが考えられました。



解決策は表面にあることが判明しました:アンチパターンマジックストリングを適用してください!



すべてのドキュメントがこの形式のメッセージの形式を説明しているため、



$ GPRMA、A、llll.ll、a、yyyyy.yy、a、xx、xx、xx、xx、xx、a <CR> <LF>



それらをコードに保存します-同時に新しいメッセージのサポートを追加するのは非常に簡単です:

1)マニュアルから説明をコピーします

2)コードへの挿入

3)???

4)利益



3つの質問の下で、次のアイデア。

すべてのメッセージの説明はディクショナリに保存されます。キーはメッセージ識別子です。列挙型:



 public enum SentencesIdentifiers { AAM, ALM, APA, ... }
      
      







意味、マニュアルからの望ましい「魔法の行」。 次のようになります。



 public static Dictionary<SentenceIdentifiers, string> SentencesFormats = new Dictionary<SentenceIdentifiers, string>() { { SentenceIdentifiers.AAM, "A,A,xx,N,c--c" }, { SentenceIdentifiers.ALM, "xx,xx,xx,xx,hh,hhhh,hh,hhhh,hhhhhh,hhhhhh,hhhhhh,hhhhhh,hhh,hhh" }, { SentenceIdentifiers.APB, "A,A,xx,a,N,A,A,xx,a,c--c,xx,a,xx,a" }, ...
      
      







今それをどうしますか?

出力は次のとおりです。メッセージパラメータとその識別子を選択し、 SentencesFormatsディクショナリからフォーマットの説明を決定します。SentencesFormatsディクショナリはコンポーネントに分割され、メソッドの入力に送られます。



 private static object ParseToken(string token, string formatter) { ??? }
      
      







システム全体の最も厄介な部分は、すべての法律とアルファベットによって、これらの3つの質問の下で、何らかの長い切り替えの形で解決します。



 switch (formatter) { case "xx": { return double.Parse(token, CultureInfo.Invariant); } ... default: return token; //    ,  ,     }
      
      







このボトルネックでは、システムのすべての柔軟性が失われますが、これは良くないので、これを行うのが最善です。



 return parsers[format](token);
      
      







パーサーという名前の下には、砂糖自体が隠れています。



 private static Dictionary<string, Func<string,object>> parsers = new Dictionary<string, Func<string,object>>() { { "x", x => int.Parse(x) }, ... { "hh", x => Convert.ToByte(x, 16) }, ... { "xx", x => double.Parse(x, CultureInfo.InvariantCulture) }, { "c--c", x => x }, { "llll.ll", x => ParseLatitude(x) }, { "yyyyy.yy", x => ParseLongitude(x) }, { "hhmmss.ss", x => ParseCommonTime(x) }, { "ddmmyy", x => ParseCommonDate(x) }, ... };
      
      







ご覧のとおり、これは辞書であり、キーはフォーマット文字列であり、値はパラメーター文字列をオブジェクトに変換する関数です。



このようなディクショナリはシリアル化でき、新しいエントリやサポートされているメッセージのリストで簡単に拡張できます。



状況は、上記のシナリオからわずかに逸脱した独自のメッセージでも同様です。



後置



上記のアイデアは、NMEAParserライブラリに完全に実装されました。

製造元コードの完全なリスト、222のアンカーポイント(データム、DOP)のリストもあります。



ライブラリのソースコードを含むアーカイブをトピックに添付したいと思いますが、そのような機会はないので、私自身のPRではなく、CodeProjectの自分の記事へのリンクを許してください。



批判、希望、提案を聞いてうれしいです。



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~

更新:指定されたCodeProjectリンクにJavaポートが表示されます



All Articles