【Dcm】車両診断通信 その77【シミュレーション⑮】

【Dcm】車両診断通信 その77【シミュレーション⑮】 車両診断通信

バックナンバーはこちら。
https://www.simulationroom999.com/blog/diagnostic-communication-backnumber/

はじめに

AUTOSAR-Dcmのシミュレーションの話。
SecurityAccessのシミュレーションのPythonコードについて。

登場人物

博識フクロウのフクさん

イラストACにて公開の「kino_k」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=iKciwKA9&area=1

エンジニア歴8年の太郎くん

イラストACにて公開の「しのみ」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=uCKphAW2&area=1

SecurityAccessのシミュレーション用のPythonコード

フクさん
フクさん

次はSecurityAccess。
Pythonコードはちょっと拡張した。

import isotp
import logging
import time
import threading

from can.interfaces.vector import VectorBus

class ThreadedApp:
   def __init__(self):
      isotp_params = {
         'stmin' : 0, 
         'blocksize' : 4,
         'wftmax' : 0,
         'll_data_length' : 8,
         'tx_padding' : 0xCC,
         'rx_flowcontrol_timeout' : 1000,
         'rx_consecutive_frame_timeout' : 1000,
         'squash_stmin_requirement' : False,
         'can_fd' : False,
         'tx_data_min_length' : 8
      }
      self.exit_requested = False
      #self.bus = VectorBus(channel='0', bitrate=500000)
      self.bus = VectorBus(channel='0', bitrate=500000, fd=True)
      addr = isotp.Address(isotp.AddressingMode.NormalFixed_29bits, source_address=0xF1, target_address=0x10) 
      self.stack = isotp.CanStack(self.bus, address=addr, params=isotp_params, error_handler=self.my_error_handler)

   def start(self):
      self.exit_requested = False
      self.thread = threading.Thread(target = self.thread_task)
      self.thread.start()

   def stop(self):
      self.exit_requested = True
      if self.thread.isAlive():
         self.thread.join()
   
   def send(self, msg):
      self.stack.send(msg)
   
   def my_error_handler(self, error):
      logging.warning('IsoTp error happened : %s - %s' % (error.__class__.__name__, str(error)))

   def thread_task(self):
      while self.exit_requested == False:
         self.stack.process()                # Non-blocking
         #time.sleep(self.stack.sleep_time()) # Variable sleep time based on state machine state
         time.sleep(0.001) # Variable sleep time based on state machine state

   def shutdown(self):
      self.stop()
      self.bus.shutdown()

def sendrecv( app, msg ):
   
   if msg[0] == 0x00:
      tsleep = msg[1]*0x100+msg[2]
      tsleep = tsleep / 1000
      print("sleep : %f [ms]" % tsleep)
      time.sleep(tsleep)
   else:
      print("Send msg : %s" % (msg.hex()))
      app.send(msg)
      t1 = time.time()
      while time.time() - t1 < 5:
         if app.stack.available():
            payload = app.stack.recv()
            print("Recv msg : %s" % (payload.hex()))
            break
         time.sleep(0.001)


if __name__ == '__main__':
   app = ThreadedApp()
   app.start()
   
   datas=[
      bytes([0x27, 0x13]),
      bytes([0x10, 0x03]),
      bytes([0x27, 0x13, 0xDE, 0xAD, 0xBE, 0xEF]),
      bytes([0x27, 0x14, 0xDE, 0xAD, 0xBE, 0xEF]),
      bytes([0x27, 0x11]),
      bytes([0x27, 0x14, 0xDE, 0xAD, 0xBE, 0xEE]),
      bytes([0x27, 0x13]),
      bytes([0x27, 0x14, 0xDE, 0xAD, 0xBE, 0xEF]),
      bytes([0x27, 0x13]),
      bytes([0x27, 0x14, 0xDE, 0xAD, 0xBE, 0xEF]),
      bytes([0x10, 0x03]),
      bytes([0x27, 0x13]),
      bytes([0x27, 0x14, 0xDE, 0xAD, 0xBE, 0xEF]),
      bytes([0x27, 0x13]),
      bytes([0x00, 0x08, 0x00]),
      bytes([0x27, 0x13]),
      bytes([0x00, 0x13, 0x24]),
      bytes([0x27, 0x13]),
      bytes([0x00, 0x13, 0xEC]),
      bytes([0x27, 0x13]),
      bytes([0x10, 0x03]),
      bytes([0x27, 0x13]),
      bytes([0x27, 0x14, 0xDE, 0xAD, 0xBE, 0xEF]),
   ]
   
   #while True:
   for i in range(len(datas)):
      sendrecv(app, datas[i])

   print("Exiting")
   app.shutdown()

SecurityAccessのシミュレーション用のPythonコード解説

太郎くん
太郎くん

ん?
投げてるメッセージ以外でどこが変わったの?

フクさん
フクさん

ちょっと今回は送信メッセージの間で待ち時間を作りたかったんで、
先頭byteが0x00の時は2byte目、3byte目を16bit長時間変数と見たてて、
その時間[ms]分waitするようになってる。

太郎くん
太郎くん

あー、ホントだ。
何か所か先頭byteが0x00になってるね。

太郎くん
太郎くん

で、今回はどんな感じの流れになるの?

フクさん
フクさん

こんな感じ
①defaultSession(SecurityAccessサービス未サポートセッション)でSecurityAccessサービス要求
②extendDiagnosticSessionへ遷移
③Seed要求としては間違ったメッセージ長
④Seed要求が成功していないのにKey送信
⑤存在しないSecurityLevelでSeed要求
⑥再度Seed要求が成功していないのにKey送信
⑦Seed要求
⑧Key送信(Key=deadbeef)
⑨再度Seed要求
⑩セキュリティアンロック済みの状態でKey送信
⑪extendDiagnosticSessionへ再遷移(これでセキュリティロックが掛かる)
⑫Seed要求
⑬Key送信(Key=deadbeef)
⑭Seed要求
⑮2秒ほどWait
⑯Seed要求
⑰4.9秒Wait
⑱Seed要求
⑲5.1秒Wait
⑳Seed要求
㉑extendDiagnosticSessionへ遷移
㉒Seed要求
㉓Key送信(Key=deadbeef)

太郎くん
太郎くん

え?ちょっと、なんかいろいろ多くない?!

フクさん
フクさん

まぁセキュリティ関連の挙動を確認しようとするとこうなるんだよねー。

フクさん
フクさん

確認したいことをまとめると、以下なんだよねー。

  • SecurityAccessサービスはextendDiagnosticSessionでサポート
    • つまり、defaultSessionではNRCが返るはず
  • 間違ったメッセージ長ははじく
  • 存在しないSecurityLevelははじく
  • Seed要求していないのにKey送信するとシーケンスエラーになる。
  • セキュリティアンロック状態でSeed要求すると0x00000000のSeedが返ってくる。
  • セキュリティアンロック状態でKey送信するとシーケンスエラーになる。
  • extendDiagnosticSessionに再遷移するとセキュリティロックが掛かるはず
  • セキュリティアンロック状態でS3タイムアウトになるとdefaultSessionに戻る&セキュリティロック&未サポート
太郎くん
太郎くん

うーん、なんとなくやりたいことはわかるようなわからんようなー。

フクさん
フクさん

まぁ次回のシミュレーション結果を見て再度頭を捻ってもいいんじゃん?

太郎くん
太郎くん

そうだねー。

まとめ

フクさん
フクさん

まとめだよ。

  • SecurityAccessのシミュレーション用のPythonコード書いた。
  • SecurityAccessの動作確認はいろいろありすぎる。
    • サポートセッション。
    • シーケンス。
    • セキュリティアンロック状態のSeed。
    • セッション遷移に伴うロック状態への遷移。
    • S3タイムアウトに伴うセッション遷移。

バックナンバーはこちら。

コメント

タイトルとURLをコピーしました