Modbus-RTUスクリプト

注釈



ここでは、シェルスクリプトを使用してModbus-RTUプロトコルを実装し、jsコードの形式でバインドする方法について説明します。 ここで説明する方法は、限られた環境(ルーター)でバイト配列を操作する必要がある他のストリーミングプロトコルの実装に使用できます。







3行のアイデア



せっかちな人のために、主なアイデアを示します。



printf "\x00\x03\x00\x00\x00\x01\x85\xDB" > $tty ( dd if=$tty of=$ans count=256 2> /dev/null ) & /usr/bin/sleep $timeout; kill $! echo "[`hexdump -ve '1/1 "%d,"' $ans | sed 's/\(.*\),/\1/'`]"
      
      





挑戦する



まず、目標を決定します。 TL-MR3020などのOpenWrtファームウェアを備えたルーターがあり、modbus-rtuプロトコルを使用してサードパーティのデバイスを制御するために使用する必要があるとします。 このようなデバイスをルーターに接続するためのオプション(それらのいくつかがあります)は考慮しませんが、そのようなバンドル用の制御ソフトウェアを作成する可能な方法を考慮します。



最初に思い浮かぶのはlibmodbusの使用ですが、そのためにはCプログラムを作成してコンパイルする必要があります。 コンパイルを伴うソリューションには、高度な作業スキル、適切なソフトウェアの可用性、さらにはOSが必要です。 一般に、これは広範に使用するための方法としてのオプションではありません。



2番目に試すことができるのは、OpenWrtで使用可能なスクリプトエンジンです。 たとえば、lua。 他にもありますが、やはり問題があります。 あなたが知らない場合、あなたはそれらを勉強する必要がありますが、これはそれほど悪くはありません。 TL-MR3020ルーターには、文字通り最大1 MBの空きスペースがほとんどありません。 依存関係のあるスクリプトパッケージをインストールすると、何か他のもののための十分なスペースがない可能性があります。



経験的に、さまざまなオプションを並べ替えて、ここで気付きました: いくつかの黒魔術:bash、cgi、およびファイルのアップロード 。 この短い記事では、私のものと同じ制限を持つシェルスクリプトを使用してファイルをダウンロードする例を示します。 手短に言えば、 ddコマンドを使用して、一時ファイルを使用せずに、要求からのバイナリストリームを直接ファイルにダンプすることがわかります。 このコードは、問題を解決するのに最適な候補です。



解決策



ここで、上記で引用した3行を分析します。



ステップ1 modbus-rtuプロトコルを実装するには、リクエストを作成してレスポンスを受信する必要があります。 この要求は、バイトの配列として発行する必要があります。 この目的のために、printfと出力リダイレクトを使用します。



 printf "\x00\x03\x00\x00\x00\x01\x85\xDB" > $tty
      
      





ステップ2 OK、リクエストを送信しましたが、どのようにレスポンスを取得しますか? これらの目的でreadを使用することはできません。 ゼロバイトでは、このコマンドは使いにくいです。 上記のddコマンドでトリックを使用し、受信したデータをファイルに保存します。 しかし、一つだけありますが、 受信した正確なバイト数を指定する必要があります。 スクリプト内のパッケージをループ内のバイト単位で解析することはできません(サイズは受信したデータから確認できます)。 おそらく時間がない。 パッケージの最大サイズ(256バイト)を指定することでこの状況から抜け出すことができますが、 ddがフリーズし、到着が少ない場合は受信を待機します。 そして、ここで最後のトリックを作ります: 不要な遅延なしにbashでコマンドをタイムアウトする



 ( dd if=$tty of=$ans count=256 2> /dev/null ) & /usr/bin/sleep $timeout; kill $!
      
      





または:



 timeout $timeout dd if=$tty of=$ans count=256 2> /dev/null
      
      





2番目のオプションでは、タイムアウトを使用するために約60 Kbが必要であり、「無料」のソリューションがある場合は使用しません。 このようなコマンドの動作の結果、受信したデータを含むファイルを取得します。



ステップ3 受信したバイト配列を便利な形式で出力します。



 echo "[`hexdump -ve '1/1 "%d,"' $ans | sed 's/\(.*\),/\1/'`]"
      
      





このコードは各バイトを10進数で表し、それらの間にコンマを挿入し、最後のコンマを削除して、角括弧で囲みます。 これはjsonの配列であり、js配列に簡単に変換できます(JSON.parse()、または 'json'パラメーターを指定した$ .post()に対して通常は自動的に変換されます)。



指定したルーターがあり、端末にアクセスできる場合は、usb-comアダプターとヌルモデムを介してルーターをPCに接続することにより、これらの手順を確認できます。 Modbusデバイスとして、エミュレータを使用できます。たとえば、 Modbus Slaveです。



JavaScriptはどこから来たのですか?



観察者は「シェルスクリプトで送信されるデータのcrcをどのように読み取るか」と尋ねるかもしれません(文字列とbashについてのみ計算が見つかりましたが、インタープリターの切り捨てバージョンがあります)。 このタスクは、「上位」レベル、つまりpostリクエストを使用してスクリプトを呼び出すhtmlページによって処理されます。 これは難しいことではありません。ここでは、クエリの実行(jQueryを使用)を担当する以下の例のコードを示します。



 Post: function( slaveid, func, bytes ) { var self = this; //  CRC  . var crc = this.crc16( bytes ); bytes.push( crc & 0xFF ); bytes.push( crc >> 8 ); //    . var adu = ''; for ( var b in bytes ) adu += '\\x' + dec2hex( bytes[b] ); //  application data unit (ADU). $('#console').val( adu ); return $.post( this.Url, { action: 'query', serial: this.Serial, data: adu }, function( data ) { self.OnReceive( slaveid, func, data ); }, 'json' ); }, Function: function( slaveid, func, address, value ) { var bytes = []; try { bytes.push( slaveid ); bytes.push( func ); bytes.push( address >> 8 ); bytes.push( address & 0xFF ); bytes.push( value >> 8 ); bytes.push( value & 0xFF ); return this.Post( slaveid, func, bytes ); } catch ( ex ) { console.error( ex ); } },
      
      





チェックサム自体は表形式のメソッドと見なされます。 私はテーブルを与えません、それらはネットワーク上と例の両方にあり、コード自体は標準です:



 crc16: function( data ) { var hi = 0xFF; var lo = 0xFF; var i; for (var j = 0, l = data.length; j < l; ++j) { i = lo ^ data[j]; lo = hi ^ CRC_HI[i]; hi = CRC_LO[i]; } return hi << 8 | lo; }
      
      







具体例を示すためだけに残っています。 これは明らかに簡単ではないので、Cyber​​Wrtファームウェアの代替モジュールであるCyber​​Wrt Modbusモジュールを参照します 。 ここで、モジュールのソースコードとその他の関連ドキュメントを含む最新のアーカイブをダウンロードできます。



例は次のようになります。



1.受信中のエラー。







2. 10個のレジスタを読み取ります。







おわりに



たとえば、アーカイブには、プロトコルのすべての機能を実装するソースmodbus.jsが含まれます。 受信したデータはまだModbus.Register []プロパティにあります。 MBAXP Modbus RTU / ASCII ActiveX ControlのActiveXコンポーネントとの類推により、このオプションを実行しました。 ヘルプを読むと、コードの構成を理解できます。



この例はまだ確定中であるため、現在の説明は古い可能性があります。



補足[2014年6月11日]



タスクとその定期的な実行のサポートが追加されました。 オーバーレイに問題がありました。



画像



参照資料



1. Modbus Application Protocol V1.1b3(pdf)

2. ロシア語でのModbusプロトコルの説明(doc)

3. Cyber​​Wrtモジュール「Modbus」(例)



All Articles