@@ -488,11 +488,17 @@ def __init__(
488
488
shortaddr : Optional [address .DeviceShort ] = None ,
489
489
groups : Optional [Iterable [address .DeviceGroup ]] = None ,
490
490
memory_banks : Optional [Iterable [Type [FakeMemoryBank ]]] = (FakeDeviceBank0 ,),
491
+ random_preload : list [int ] = [],
491
492
):
492
493
# Store parameters
493
494
self .shortaddr = shortaddr
494
495
self .groups = set (groups ) if groups else set ()
495
496
# 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
496
502
self .dtr0 : int = 0
497
503
self .dtr1 : int = 0
498
504
self .dtr2 : int = 0
@@ -504,6 +510,12 @@ def __init__(
504
510
raise ValueError (f"Duplicate memory bank { bank_number } " )
505
511
self .memory_banks [bank_number ] = fake_bank ()
506
512
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
+
507
519
def valid_address (self , cmd : Command ) -> bool :
508
520
"""Should we respond to this command?"""
509
521
if len (cmd .frame ) != 24 :
@@ -521,6 +533,13 @@ def valid_address(self, cmd: Command) -> bool:
521
533
if isinstance (cmd .destination , address .DeviceGroup ):
522
534
return cmd .destination in self .groups
523
535
536
+ @property
537
+ def shortaddr_int (self ):
538
+ if self .shortaddr is None :
539
+ return 0xff
540
+ else :
541
+ return self .shortaddr .address
542
+
524
543
def send (self , cmd : Command ) -> Optional [int ]:
525
544
# Reset enable_write_memory if command is not one of the memory
526
545
# writing commands, even if the command is not addressed to us
@@ -627,6 +646,58 @@ def send(self, cmd: Command) -> Optional[int]:
627
646
finally :
628
647
if not bank .nobble_dtr0_update :
629
648
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
630
701
631
702
return None
632
703
0 commit comments