|
43 | 43 | from openlcb.convert import Convert |
44 | 44 | # from openlcb.localnode import LocalNode # circular import |
45 | 45 | from openlcb.memoryconfigurationheader import MemoryConfigurationHeader |
| 46 | +from openlcb.memoryspace import MemorySpace |
46 | 47 | from openlcb.memoryspaceindex import MemorySpaceIndex |
47 | 48 | from openlcb.memorymanager import MemoryManager |
48 | 49 | from openlcb.nodeid import NodeID |
@@ -328,13 +329,17 @@ def parseReplyDatagram(memo: Union[MemoryReadMemo, MemoryWriteMemo], |
328 | 329 | ) |
329 | 330 | offset = 6 |
330 | 331 | error = None |
331 | | - assert mcHeader.spaceIndex is not MemorySpaceIndex.Uninitialized |
332 | | - if mcHeader.spaceIndex is MemorySpaceIndex.Custom: |
| 332 | + if mcHeader.spaceIndex in (MemorySpaceIndex.Custom, |
| 333 | + MemorySpaceIndex.Uninitialized): |
333 | 334 | # mcHeader.customSpace = memo.space |
334 | 335 | mcHeader.customSpace = dmemo.data[6] |
335 | 336 | offset = 7 |
| 337 | + else: |
| 338 | + assert mcHeader.customSpace is None, \ |
| 339 | + "fromMC2ndByte should not set customSpace in this case" |
336 | 340 | memo.error = None |
337 | 341 | memo.errorCode = None |
| 342 | + print(f"reply datagram: {mcHeader.spaceIndex} customSpace={mcHeader.customSpace}") |
338 | 343 | if (dmemo.data[1] & 0x08 == 0): |
339 | 344 | # ok reply |
340 | 345 | return |
@@ -625,42 +630,55 @@ def datagramReceivedListener(self, dmemo: DatagramReadMemo) -> bool: |
625 | 630 | self.spaceLengthCallback(address) |
626 | 631 | self.spaceLengthCallback = None |
627 | 632 | elif mcOp is MCOp.Read_Command: |
628 | | - # assert dmemo.data[1] in TWO_BIT_PARAMS[MCOp.Read_Command.value], \ |
| 633 | + # assert dmemo.data[1] in TWO_BIT_PARAMS[MCOp.Read_Command.value],\ |
629 | 634 | # "self-test failed (bad constant(s))" |
630 | 635 | mcHeader = MemoryConfigurationHeader.fromMC2ndByte(dmemo.data[1]) |
631 | 636 | addressBytes = dmemo.data[2:6] |
632 | 637 | address = struct.unpack(">I", addressBytes)[0] |
633 | 638 | # ^ [0] since always returns list even when reading 1 value. |
634 | 639 | # ^ capital assumes unsigned, "I" assumes 32-bit (4 bytes) |
635 | | - space = dmemo.data[1] & 0b00000011 |
| 640 | + spaceIndex = dmemo.data[1] & 0b00000011 |
636 | 641 | offset = 0 |
| 642 | + space = None |
637 | 643 | if mcHeader.spaceIsCustom(): |
638 | | - assert space == 0 |
| 644 | + assert spaceIndex == 0 |
639 | 645 | space = dmemo.data[6] |
640 | 646 | offset = 1 |
641 | 647 | size = dmemo.data[6+offset] # requested read count |
642 | 648 | datagramBytes = bytearray([0x20, MCOp.Read_Reply.value]) |
643 | 649 | # ^ byte1 (2nd) changed to error below if applicable |
644 | | - assert isinstance(space, int), \ |
645 | | - (f"Logic missing, space should be number here," |
646 | | - f" got {emit_cast(space)}") |
| 650 | + assert isinstance(spaceIndex, int), \ |
| 651 | + (f"Logic missing, spaceIndex should be number here," |
| 652 | + f" got {emit_cast(spaceIndex)}") |
647 | 653 | assert isinstance(address, int) |
648 | 654 | datagramBytes += addressBytes |
649 | | - assert space is not None, \ |
650 | | - f"space not computed from datagram: {dmemo.data}" |
651 | 655 | if mcHeader.spaceIsCustom(): |
| 656 | + assert space is not None |
652 | 657 | datagramBytes.append(space) |
653 | 658 | assert len(datagramBytes) == 7, "space goes in index [6]" |
654 | 659 | else: |
| 660 | + space = MemorySpace.fromIndex(MemorySpaceIndex(spaceIndex)) |
| 661 | + assert space is not None |
| 662 | + space = space.value |
655 | 663 | spaceIndex = (space & 0b00000011) |
656 | | - assert spaceIndex == space |
657 | 664 | assert space is not None |
658 | 665 | datagramBytes[1] = \ |
659 | 666 | datagramBytes[1] | spaceIndex |
660 | 667 | assert len(datagramBytes) == 6, "should not have space in [6]" |
| 668 | + assert space is not None, \ |
| 669 | + f"space not computed from datagram: {dmemo.data}" |
661 | 670 | payload = None |
662 | 671 | try: |
663 | | - payload = self.memory.getSlice(space, address, size) |
| 672 | + segment = self.memory.getStorage(space) |
| 673 | + if segment is None: |
| 674 | + raise KeyError(f"space {space} is not valid") |
| 675 | + if address >= segment.size(): |
| 676 | + raise IndexError( |
| 677 | + f"address {address} past end of {hex(space)}") |
| 678 | + payload = self.memory.getSlice(space, address, size, |
| 679 | + force=True) |
| 680 | + # ^ force=True because reading past end is normal |
| 681 | + # (pad with zeroes to indicate end) |
664 | 682 | except (IndexError, KeyError) as ex: |
665 | 683 | # address out of range (See Segment's getSlice) |
666 | 684 | datagramBytes[1] = MCOp.Read_Reply_Failure.value |
@@ -698,6 +716,10 @@ def datagramReceivedListener(self, dmemo: DatagramReadMemo) -> bool: |
698 | 716 | dmemo.srcID, |
699 | 717 | datagramBytes |
700 | 718 | ) |
| 719 | + # hexStrings = [] |
| 720 | + # for b in datagramBytes: |
| 721 | + # hexStrings.append(hex(b)) |
| 722 | + # print(f"Sending read reply: {hexStrings}") |
701 | 723 | self.service.sendDatagram(requestedMemoryMemo) |
702 | 724 | else: |
703 | 725 | logger.error("Did not expect reply of type 0x{:02X}" |
|
0 commit comments