@@ -488,11 +488,17 @@ def __init__(
488488 shortaddr : Optional [address .DeviceShort ] = None ,
489489 groups : Optional [Iterable [address .DeviceGroup ]] = None ,
490490 memory_banks : Optional [Iterable [Type [FakeMemoryBank ]]] = (FakeDeviceBank0 ,),
491+ random_preload : list [int ] = [],
491492 ):
492493 # Store parameters
493494 self .shortaddr = shortaddr
494495 self .groups = set (groups ) if groups else set ()
495496 # Configure internal variables
497+ self .randomaddr = frame .Frame (24 )
498+ self .searchaddr = frame .Frame (24 )
499+ self .random_preload = random_preload
500+ self .initialising = False
501+ self .withdrawn = False
496502 self .dtr0 : int = 0
497503 self .dtr1 : int = 0
498504 self .dtr2 : int = 0
@@ -504,6 +510,12 @@ def __init__(
504510 raise ValueError (f"Duplicate memory bank { bank_number } " )
505511 self .memory_banks [bank_number ] = fake_bank ()
506512
513+ def _next_random_address (self ):
514+ if self .random_preload :
515+ return self .random_preload .pop (0 )
516+ else :
517+ return random .randrange (0 , 0x1000000 )
518+
507519 def valid_address (self , cmd : Command ) -> bool :
508520 """Should we respond to this command?"""
509521 if len (cmd .frame ) != 24 :
@@ -521,6 +533,13 @@ def valid_address(self, cmd: Command) -> bool:
521533 if isinstance (cmd .destination , address .DeviceGroup ):
522534 return cmd .destination in self .groups
523535
536+ @property
537+ def shortaddr_int (self ):
538+ if self .shortaddr is None :
539+ return 0xff
540+ else :
541+ return self .shortaddr .address
542+
524543 def send (self , cmd : Command ) -> Optional [int ]:
525544 # Reset enable_write_memory if command is not one of the memory
526545 # writing commands, even if the command is not addressed to us
@@ -627,6 +646,58 @@ def send(self, cmd: Command) -> Optional[int]:
627646 finally :
628647 if not bank .nobble_dtr0_update :
629648 self .dtr0 = min (self .dtr0 + 1 , 255 )
649+ elif isinstance (cmd , device .general .SetShortAddress ):
650+ if self .dtr0 == 0xff :
651+ self .shortaddr = None
652+ elif (self .dtr0 & 1 ) == 1 :
653+ self .shortaddr = address .DeviceShort ((self .dtr0 & 0x7e ) >> 1 )
654+ elif isinstance (cmd , device .general .QueryMissingShortAddress ):
655+ if self .shortaddr is None :
656+ return _yes
657+ elif isinstance (cmd , device .general .QueryRandomAddressH ):
658+ return self .randomaddr [23 :16 ]
659+ elif isinstance (cmd , device .general .QueryRandomAddressM ):
660+ return self .randomaddr [15 :8 ]
661+ elif isinstance (cmd , device .general .QueryRandomAddressL ):
662+ return self .randomaddr [7 :0 ]
663+ elif isinstance (cmd , device .general .Terminate ):
664+ self .initialising = False
665+ self .withdrawn = False
666+ elif isinstance (cmd , device .general .Initialise ):
667+ if cmd .param == 0xff \
668+ or (cmd .param == 0x7f and self .shortaddr is None ) \
669+ or (cmd .param == self .shortaddr ):
670+ self .initialising = True
671+ self .withdrawn = False
672+ # We don't implement the 15 minute timer
673+ elif isinstance (cmd , device .general .Randomise ):
674+ self .randomaddr = frame .Frame (24 , self ._next_random_address ())
675+ elif isinstance (cmd , device .general .Compare ):
676+ if self .initialising \
677+ and not self .withdrawn \
678+ and self .randomaddr .as_integer <= self .searchaddr .as_integer :
679+ return _yes
680+ elif isinstance (cmd , device .general .Withdraw ):
681+ if self .initialising \
682+ and self .randomaddr == self .searchaddr :
683+ self .withdrawn = True
684+ elif isinstance (cmd , device .general .SearchAddrH ):
685+ self .searchaddr [23 :16 ] = cmd .param
686+ elif isinstance (cmd , device .general .SearchAddrM ):
687+ self .searchaddr [15 :8 ] = cmd .param
688+ elif isinstance (cmd , device .general .SearchAddrL ):
689+ self .searchaddr [7 :0 ] = cmd .param
690+ elif isinstance (cmd , device .general .ProgramShortAddress ):
691+ if self .initialising \
692+ and self .randomaddr == self .searchaddr :
693+ if cmd .param == 255 :
694+ self .shortaddr = None
695+ else :
696+ self .shortaddr = address .DeviceShort (cmd .param )
697+ elif isinstance (cmd , device .general .VerifyShortAddress ):
698+ if self .initialising \
699+ and self .shortaddr_int == cmd .param :
700+ return _yes
630701
631702 return None
632703
0 commit comments