text: # SPDX-License-Identifier: MIT
  
  import struct
  
  from enum import IntEnum
  
  from m1n1.proxyutils import RegMonitor
  from m1n1.utils import *
  from m1n1.trace.dart import DARTTracer
  from m1n1.trace.asc import ASCTracer, EP, EPState, msg, msg_log, DIR
  from m1n1.fw.smc import *
  
  ASCTracer = ASCTracer._reloadcls()
  
  class SMCEpTracer(EP):
      BASE_MESSAGE = SMCMessage
  
      def __init__(self, tracer, epid):
          super().__init__(tracer, epid)
          self.state.sram_addr = None
          self.state.verbose = 1
          self.state.rb = {}
  
      Initialize = msg_log(SMC_INITIALIZE, DIR.TX, SMCInitialize)
      Notification = msg_log(SMC_NOTIFICATION, DIR.RX)
  
      @msg(SMC_WRITE_KEY, DIR.TX, SMCWriteKey)
      def WriteKey(self, msg):
          key = msg.KEY.to_bytes(4, byteorder="big").decode("ascii")
          data = self.hv.iface.readmem(self.state.sram_addr, msg.SIZE)
          self.log(f"[{msg.ID:x}] >W: <{key}> = {data.hex()}")
          return True
  
      @msg(SMC_READ_KEY, DIR.TX, SMCReadKey)
      def ReadKey(self, msg):
          key = msg.KEY.to_bytes(4, byteorder="big").decode("ascii")
          self.state.rb[msg.ID] = msg.TYPE, key, msg.SIZE
          self.log(f"[{msg.ID:x}] >R: <{key}> = ...")
          return True
  
      @msg(SMC_GET_KEY_INFO, DIR.TX, SMCGetKeyInfo)
      def GetInfo(self, msg):
          key = msg.KEY.to_bytes(4, byteorder="big").decode("ascii")
          self.state.rb[msg.ID] = msg.TYPE, key, None
          self.log(f"[{msg.ID:x}] >Get Info: <{key}>")
          return True
  
      @msg(None, DIR.RX, Register64)
      def RXMsg(self, msg):
          if self.state.sram_addr is None:
              self.log(f"SRAM address: {msg.value:#x}")
              self.state.sram_addr = msg.value
              return True
  
          msg = SMCResult(msg.value)
          if msg.RESULT != 0:
              self.log(f"[{msg.ID:x}] <Err: 0x{msg.RESULT:02x}")
              return True
  
          if msg.ID in self.state.rb:
              msgtype, key, size = self.state.rb.pop(msg.ID)
              if msgtype == SMC_READ_KEY:
                  if size <= 4:
                      data = hex(msg.VALUE)
                  else:
                      data = self.hv.iface.readmem(self.state.sram_addr, msg.SIZE).hex()
                  self.log(f"[{msg.ID:x}] <R: <{key}> = {data}")
                  return True
  
              elif msgtype == SMC_GET_KEY_INFO:
                  data = self.hv.iface.readmem(self.state.sram_addr, 6)
                  size, type, flags = struct.unpack("B4sB", data)
                  self.log(f"[{msg.ID:x}] <Info: <{key}>: size={size} type={type.decode('ascii')} flags={flags:#x}")
                  return True
  
          self.log(f"[{msg.ID:x}] <OK {msg!r}")
          return True
  
  class SMCTracer(ASCTracer):
      ENDPOINTS = {
          0x20: SMCEpTracer
      }
  
      def handle_msg(self, direction, r0, r1):
          super().handle_msg(direction, r0, r1)
  
  smc_tracer = SMCTracer(hv, "/arm-io/smc", verbose=1)
  smc_tracer.start()
  