diff --git a/src/objdictgen/maps.py b/src/objdictgen/maps.py index c3e1570..810ea42 100644 --- a/src/objdictgen/maps.py +++ b/src/objdictgen/maps.py @@ -505,7 +505,7 @@ def FindMapVariableList(self, node: Node, compute=True) -> Generator[tuple[int, It yields tuple of (index, subindex, size, name) """ for index, entry in self.items(): - if entry.get("need") is False: + if not node.IsEntry(index): continue values = entry["values"] for subindex, subvalue in enumerate(values): diff --git a/src/objdictgen/node.py b/src/objdictgen/node.py index d503f37..50c4fd9 100644 --- a/src/objdictgen/node.py +++ b/src/objdictgen/node.py @@ -541,6 +541,8 @@ def _get_buffer_size(index: int, subindex: int, size: int, name: str) -> int: try: params: TParamEntry = self.ParamsDictionary[index][subindex] # type: ignore[literal-required] bs = params["buffer_size"] + if isinstance(bs, str): + bs = int(bs) if bs <= 8: return (index << 16) + (subindex << 8) + size * bs raise ValueError(f"String size of '{name}' too big to fit in a PDO") @@ -552,13 +554,9 @@ def _get_buffer_size(index: int, subindex: int, size: int, name: str) -> int: varlist = self.GetMapVariableList() for index, subindex, size, name in varlist: if mapname == self.GenerateMapName(name, index, subindex): - # array type, only look at subindex 1 in UserMapping - if self.UserMapping[index]["struct"] == OD.ARRAY: - if self.IsStringType(self.UserMapping[index]["values"][1]["type"]): - return _get_buffer_size(index, subindex, size, mapname) - else: - if self.IsStringType(self.UserMapping[index]["values"][subindex]["type"]): - return _get_buffer_size(index, subindex, size, mapname) + subentry_infos = self.GetSubentryInfos(index, subindex) + if self.IsStringType(subentry_infos["type"]): + return _get_buffer_size(index, subindex, size, mapname) return (index << 16) + (subindex << 8) + size raise ValueError(f"Mapping '{mapname}' not found") diff --git a/src/objdictgen/ui/commondialogs.py b/src/objdictgen/ui/commondialogs.py index bf9a80d..c42333e 100644 --- a/src/objdictgen/ui/commondialogs.py +++ b/src/objdictgen/ui/commondialogs.py @@ -1452,6 +1452,8 @@ def ResetView(self, grid): (wx.grid.Grid) -> Reset the grid view. Call this to update the grid if rows and columns have been added or deleted """ + if grid.IsCellEditControlEnabled(): + grid.DisableCellEditControl() grid.BeginBatch() for current, new, delmsg, addmsg in [ ( diff --git a/src/objdictgen/ui/subindextable.py b/src/objdictgen/ui/subindextable.py index e01ec25..f92d639 100644 --- a/src/objdictgen/ui/subindextable.py +++ b/src/objdictgen/ui/subindextable.py @@ -189,6 +189,8 @@ def ResetView(self, grid): (wx.grid.Grid) -> Reset the grid view. Call this to update the grid if rows and columns have been added or deleted """ + if grid.IsCellEditControlEnabled(): + grid.DisableCellEditControl() grid.BeginBatch() for current, new, delmsg, addmsg in [ ( diff --git a/tests/test_node.py b/tests/test_node.py index b863d4c..90da206 100644 --- a/tests/test_node.py +++ b/tests/test_node.py @@ -1,8 +1,81 @@ """Tests for node.py""" import pytest +from objdictgen.maps import OD from objdictgen.node import Node, NodeProtocol, executeCustomGenerator +@pytest.mark.parametrize("index, name, size", [ + (0x1001, "Error Register", 8), + (0x1002, "Manufacturer Status Register", 32), +]) +def test_node_builtin_pdo_mapping_choices(index, name, size): + node = Node() + node.AddEntry(index, value=0) + mapname = node.GenerateMapName(name, index, 0) + + assert mapname in node.GetMapList() + assert (index, 0, size, name) in node.GetMapVariableList() + assert node.GetMapValue(mapname) == (index << 16) + size + assert node.GetMapName((index << 16) + size) == mapname + + +def test_node_pdo_mapping_choices(): + node = Node() + assert node.GetMapList() == ["None"] + + node.AddEntry(0x1000, value=0) + assert node.GetMapList() == ["None"] + + +def test_node_pdo_mapping_string_buffer_size_as_text(): + node = Node() + node.UserMapping[0x2000] = { + "name": "Mapped object", + "struct": OD.RECORD, + "need": False, + "values": [ + {"name": "Count", "type": 0x05, "access": "ro", "pdo": False}, + {"name": "Payload", "type": 0x09, "access": "rw", "pdo": True}, + ], + } + node.AddEntry(0x2000, value=["abc"]) + node.SetParamsEntry(0x2000, 1, params={"buffer_size": "3"}) + + mapname = node.GenerateMapName("Payload", 0x2000, 1) + assert node.GetMapValue(mapname) == (0x2000 << 16) + (1 << 8) + 24 + + +@pytest.mark.parametrize("source", ["UserMapping", "Profile", "DS302"]) +@pytest.mark.parametrize("struct", [OD.ARRAY, OD.RECORD]) +@pytest.mark.parametrize("objtype, value, size", [(0x05, 0, 8), (0x09, "abc", 24)]) +def test_node_pdo_mapping_subentry_choices(source, struct, objtype, value, size): + node = Node() + subentries = [{"name": "Count", "type": 0x05, "access": "ro", "pdo": False}] + if struct == OD.ARRAY: + subentries.append({ + "name": "Value %d[(sub)]", "type": objtype, "access": "rw", "pdo": True, "nbmax": 2, + }) + else: + subentries.extend([ + {"name": "First", "type": objtype, "access": "rw", "pdo": True}, + {"name": "Second", "type": objtype, "access": "rw", "pdo": True}, + ]) + getattr(node, source)[0x2000] = { + "name": "Mapped object", "struct": struct, "need": False, "values": subentries, + } + node.AddEntry(0x2000, value=[value, value]) + for subindex in (1, 2): + if objtype == 0x09: + node.SetParamsEntry(0x2000, subindex, params={"buffer_size": 3}) + name = node.GetSubentryInfos(0x2000, subindex)["name"] + mapname = node.GenerateMapName(name, 0x2000, subindex) + mapvalue = (0x2000 << 16) + (subindex << 8) + size + + assert mapname in node.GetMapList() + assert (0x2000, subindex, 8, name) in node.GetMapVariableList() + assert node.GetMapValue(mapname) == mapvalue + assert node.GetMapName(mapvalue) == mapname + @pytest.mark.parametrize("file", ['master', 'slave']) def test_node_LoadFile(odpath, file):