/var/log/messages

Mar 8, 2018 - 3 minute read - Comments - misc

PyEcom における複数フレーム送信処理について

メータ関連のテストにて

10,0B,30,0B,00,02,00,00
21,00,00,00,00,00,00,00

みたいな ISO-TP の複数フレームなメッセージが送出されているのを確認しています。

上記、レングスが長いパケットを送付する場合のプロトコルなのですが、PyECOM にて実装されていることを確認しましたので内容について精査してみました。

確認するのは PyEcom.py にて定義されている send_iso_tp_data 手続きです。細かい部分は飛ばすとして以下がパケット長で分岐するあたりの記述です。

        #multi-packet send
        if len(data) > 7:
            #print "Multi packet"

これはメッセージ長が 7 以下の場合は単一フレームで処理可能なのですが、そうでない場合には multi-packet の対象になる、ということになります。ちなみに ISO-TP 云々については Adventures in Automotive Networks and Control Units というドキュメントにざっくりな記載がありますのでそちらを確認してみてください。

この ISO-TP という規格は CAN バス経由でデータパケットを送信するためのものであり、データ送信しないケースではこの形式に沿っている必要はありません。データパケットである場合、先頭にメタデータが付与されるのですが

  • 0 は単一フレームで次の nibble はパケット内のデータ量
  • 1 は複数フレームの先頭で続く 3 nibble はペイロードのサイズ
  • 2 は残りのマルチパケットペイロードで次の nibble はインデクスになります(条件ありますが折り返し可能)

みたいな形になります。上で紹介した例であれば

  • 10 0B 30 0B 00 02 00 00 が最初のフレームでペイロードのサイズは 0x00B (データは 30 0B 00 02 00 00)
  • 21 00 00 00 00 00 00 00 が二番目のフレーム (データは 00 00 00 00 00)

みたいな形に解釈されます。

send_iso_tp_data に渡されたデータの長さが 7 より大きい場合複数フレームにする必要がある、ということで上記の条件分岐が記述されていることになります。そして以降で最初のパケットを組み立てています。

            # first packet
            datalen = len(data)

            # Fix due to Charlie bricking my ECM Booo charlie
            datalen = datalen & 0x0FFF
            data_bytes = (0x01000 | datalen) & 0x0FFFF
            byteone = (data_bytes >> 8)
            bytetwo = data_bytes & 0xFF

ここは先頭 2byte のメタデータの作成の部分になります。そして最初のフレームにデータを入れて送信しています。

            firstdata = [byteone, bytetwo] + data[0:6]
            line = "IDH: %02X, IDL: %02X, Len: 08, Data: " % (idh, idl)
            line += self.data_to_line(firstdata, 8)
            self.mydll.DbgLineToSFF(line, sff_msg)
            self.mydll.PrintSFF(sff_msg,0)
            self.mydll.write_message(self.handle, sff_msg)

レスポンス云々はスルーするとして以降のフレームのデータを組み立てている部分が以下になります。

            #send the remaining data
            while sent < datalen:
                    firstbyte = 0x20 + ((counter+1) & 0xf)
                    firstdata = [firstbyte] + data[6 + counter*7 : 13 + counter*7]
                    line = "IDH: %02X, IDL: %02X, Len: 08, Data: " % (idh, idl)
                    line += self.data_to_line(firstdata, 8)
                    self.mydll.DbgLineToSFF(line, sff_msg)
                    self.mydll.PrintSFF(sff_msg,0)
                    self.mydll.write_message(self.handle, sff_msg)
                    sent += 7
                    counter += 1                

二番目のフレーム以降ではカウンタを使っていることがわかります。桁あふれにも対応されていることがわかります。

おわりに

ELM327 では送付が不可能な複数フレームのメッセージですが、ECOM ケーブルを使うことでこうしたメッセージにも対応できている、ということは非常に興味深いです。

slack で RSS 読めるのか 香味油

comments powered by Disqus