lecore 0.2.6__tar.gz → 0.2.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. {lecore-0.2.6/src/lecore.egg-info → lecore-0.2.7}/PKG-INFO +1 -1
  2. {lecore-0.2.6 → lecore-0.2.7}/pyproject.toml +1 -1
  3. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/FwBuild.py +99 -6
  4. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/__main__.py +89 -89
  5. {lecore-0.2.6 → lecore-0.2.7/src/lecore.egg-info}/PKG-INFO +1 -1
  6. {lecore-0.2.6 → lecore-0.2.7}/LICENSE +0 -0
  7. {lecore-0.2.6 → lecore-0.2.7}/MANIFEST.in +0 -0
  8. {lecore-0.2.6 → lecore-0.2.7}/README.md +0 -0
  9. {lecore-0.2.6 → lecore-0.2.7}/setup.cfg +0 -0
  10. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/DeviceTests/Base.py +0 -0
  11. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/DeviceTests/LeBinTests.py +0 -0
  12. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/DeviceTests/ModbusTests.py +0 -0
  13. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/DeviceTests/Plugin.py +0 -0
  14. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/DeviceTests/__init__.py +0 -0
  15. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/DeviceBase.py +0 -0
  16. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/LeBinDev.py +0 -0
  17. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/ModbusDev.py +0 -0
  18. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/ComSettings.json +0 -0
  19. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/PhaseDet.py +0 -0
  20. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/PhaseDetRegs.py +0 -0
  21. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/PhaseDet_Modbus.json +0 -0
  22. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/UpgradeSettings.json +0 -0
  23. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/VisualSettings.json +0 -0
  24. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/__init__.py +0 -0
  25. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/ComSettings.json +0 -0
  26. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/Rftb.py +0 -0
  27. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/RftbLeBin.py +0 -0
  28. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/UpgradeSettings.json +0 -0
  29. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/VisualSettings.json +0 -0
  30. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/__init__.py +0 -0
  31. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/rftbRegs.py +0 -0
  32. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/rftb_Modbus.json +0 -0
  33. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/rftb_registers.json +0 -0
  34. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/ComSettings.json +0 -0
  35. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/RtdEmul.py +0 -0
  36. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/RtdEmulRegs.py +0 -0
  37. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/RtdEmul_Modbus.json +0 -0
  38. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/UpgradeSettings.json +0 -0
  39. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/VisualSettings.json +0 -0
  40. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/__init__.py +0 -0
  41. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Validation.py +0 -0
  42. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/ComSettings.json +0 -0
  43. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/UpgradeSettings.json +0 -0
  44. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/VMS_RTDRegs.py +0 -0
  45. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/VMS_RTD_Modbus.json +0 -0
  46. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/VisualSettings.json +0 -0
  47. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/VmsRtd.py +0 -0
  48. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/__init__.py +0 -0
  49. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/__init__.py +0 -0
  50. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Doc/ModbusTable.py +0 -0
  51. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Doc/__init__.py +0 -0
  52. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Fg320/Fg320.py +0 -0
  53. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Fg320/__init__.py +0 -0
  54. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/LeBin/RegisterMap.py +0 -0
  55. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/LeBin/SerialCom.py +0 -0
  56. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/LeBin/UpgradeFirmware.py +0 -0
  57. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/LeBin/VisualLeBin.py +0 -0
  58. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/LeBin/__init__.py +0 -0
  59. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Looger.py +0 -0
  60. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/QUICKSTART.md +0 -0
  61. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Scaffold.py +0 -0
  62. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/TestFrame/CoreTest.py +0 -0
  63. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/TestFrame/ModbusUnitTest.py +0 -0
  64. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/TestFrame/RtuClient.py +0 -0
  65. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/TestFrame/Runner.py +0 -0
  66. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/TestFrame/TestUtils.py +0 -0
  67. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/TestFrame/__init__.py +0 -0
  68. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/AppLogging.py +0 -0
  69. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/Crc32.py +0 -0
  70. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/HelpAbout.py +0 -0
  71. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/MbClient.py +0 -0
  72. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/MbUpgrade.py +0 -0
  73. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/ReadWrite.py +0 -0
  74. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/RegMap.py +0 -0
  75. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/TextMbApp.py +0 -0
  76. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/TextMbAppCss.tcss +0 -0
  77. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/VisualMbApp.py +0 -0
  78. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/VmSettings.py +0 -0
  79. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/__init__.py +0 -0
  80. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/__init__.py +0 -0
  81. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/_version.py +0 -0
  82. {lecore-0.2.6 → lecore-0.2.7}/src/lecore/py.typed +0 -0
  83. {lecore-0.2.6 → lecore-0.2.7}/src/lecore.egg-info/SOURCES.txt +0 -0
  84. {lecore-0.2.6 → lecore-0.2.7}/src/lecore.egg-info/dependency_links.txt +0 -0
  85. {lecore-0.2.6 → lecore-0.2.7}/src/lecore.egg-info/entry_points.txt +0 -0
  86. {lecore-0.2.6 → lecore-0.2.7}/src/lecore.egg-info/requires.txt +0 -0
  87. {lecore-0.2.6 → lecore-0.2.7}/src/lecore.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lecore
3
- Version: 0.2.6
3
+ Version: 0.2.7
4
4
  Summary: Logic Elements core utilities
5
5
  Author-email: Jan Bartovský <jan.bartovsky@logicelements.cz>
6
6
  License-Expression: MIT
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "lecore"
7
7
  description = "Logic Elements core utilities"
8
- version = "0.2.6"
8
+ version = "0.2.7"
9
9
  authors = [
10
10
  { name="Jan Bartovský", email="jan.bartovsky@logicelements.cz" },
11
11
  ]
@@ -6,6 +6,8 @@ The CRC is the one of the STM32 hardware CRC unit: polynom 0x04C11DB7, init 0xFF
6
6
  words, no reflection and no final XOR. The same CRC is produced for all targets.
7
7
 
8
8
  Targets 1-7 are verified byte by byte against BinBuild.exe (build of 2024-09). Target 8 is not implemented.
9
+ Intel HEX files are supported too (except target 1): the image from the lowest address is processed like a binary,
10
+ gaps are filled with 0x00 (like ``objcopy -O binary``) and the result is written as a contiguous HEX.
9
11
  """
10
12
  import datetime
11
13
  import struct
@@ -74,6 +76,9 @@ TARGETS = {
74
76
  7: Target(512, True, 16, "512 B offset in the FW, decimal information (Fixture)"),
75
77
  }
76
78
 
79
+ _HEX_MAX_SIZE = 16 * 1024 * 1024 # protection against huge gaps (e.g. option bytes far away from the FW)
80
+ _HEX_RECORD = 16
81
+
77
82
  _LEGACY_OFFSET = 512 # target 1 checks the same free space as the targets with a 512 B offset
78
83
 
79
84
 
@@ -132,13 +137,92 @@ def build(data: bytes, target: int, version: str, dev_id: str = "", date: Option
132
137
  return stamped[:offset] + info + stamped[offset + len(info):], crc
133
138
 
134
139
 
140
+ def read_hex(text: str) -> tuple:
141
+ """
142
+ Parse an Intel HEX file into a contiguous image, gaps are filled with 0x00
143
+ :param text: HEX file content
144
+ :return: Tuple (base address, image, start address record line or None)
145
+ """
146
+ chunks = {}
147
+ upper = 0
148
+ start = None
149
+ for number, line in enumerate(text.splitlines(), 1):
150
+ line = line.strip()
151
+ if not line:
152
+ continue
153
+ try:
154
+ if line[0] != ":":
155
+ raise ValueError
156
+ record = bytes.fromhex(line[1:])
157
+ except ValueError:
158
+ raise ValueError(f"line {number}: not an Intel HEX record") from None
159
+ if len(record) < 5 or len(record) != record[0] + 5:
160
+ raise ValueError(f"line {number}: wrong record length")
161
+ if sum(record) & 0xFF:
162
+ raise ValueError(f"line {number}: wrong checksum")
163
+ rtype, payload = record[3], record[4:-1]
164
+ if rtype == 0x00:
165
+ address = upper + int.from_bytes(record[1:3], "big")
166
+ chunks[address] = chunks.get(address, b"") + payload
167
+ elif rtype == 0x01:
168
+ break
169
+ elif rtype == 0x02:
170
+ upper = int.from_bytes(payload, "big") << 4
171
+ elif rtype == 0x04:
172
+ upper = int.from_bytes(payload, "big") << 16
173
+ elif rtype in (0x03, 0x05):
174
+ start = line
175
+ else:
176
+ raise ValueError(f"line {number}: unknown record type {rtype:02X}")
177
+ if not chunks:
178
+ raise ValueError("no data in the HEX file")
179
+ base = min(chunks)
180
+ size = max(address + len(payload) for address, payload in chunks.items()) - base
181
+ if size > _HEX_MAX_SIZE:
182
+ raise ValueError(f"HEX image is too large ({size} B from 0x{base:08X}), check for data at distant addresses")
183
+ image = bytearray(size)
184
+ for address, payload in chunks.items():
185
+ image[address - base:address - base + len(payload)] = payload
186
+ return base, bytes(image), start
187
+
188
+
189
+ def _hex_record(rtype: int, address: int, payload: bytes) -> str:
190
+ record = bytes([len(payload)]) + address.to_bytes(2, "big") + bytes([rtype]) + payload
191
+ return ":" + (record + bytes([-sum(record) & 0xFF])).hex().upper()
192
+
193
+
194
+ def write_hex(base: int, image: bytes, start: Optional[str] = None) -> str:
195
+ """
196
+ Write a contiguous image as an Intel HEX file
197
+ :param base: Address of the image
198
+ :param image: Image content
199
+ :param start: Start address record line (from ``read_hex``)
200
+ :return: HEX file content
201
+ """
202
+ lines = []
203
+ upper = None
204
+ address = base
205
+ end = base + len(image)
206
+ while address < end:
207
+ if address >> 16 != upper:
208
+ upper = address >> 16
209
+ lines.append(_hex_record(0x04, 0, upper.to_bytes(2, "big")))
210
+ length = min(_HEX_RECORD, end - address, 0x10000 - (address & 0xFFFF))
211
+ lines.append(_hex_record(0x00, address & 0xFFFF, image[address - base:address - base + length]))
212
+ address += length
213
+ if start:
214
+ lines.append(start)
215
+ lines.append(_hex_record(0x01, 0, b""))
216
+ return "\n".join(lines) + "\n"
217
+
218
+
135
219
  def build_file(target: int, path, version: str, suffix: str = "", out_dir=None,
136
220
  date: Optional[datetime.date] = None) -> tuple:
137
221
  """
138
- Stamp the FW information block into a binary file, the result is written next to it (or to ``out_dir``) as
139
- ``<name>[-<suffix>]-<yyyymmdd>-<version>.bin``
222
+ Stamp the FW information block into a binary or Intel HEX (``.hex``) file, the result is written next to it
223
+ (or to ``out_dir``) as ``<name>[-<suffix>]-<yyyymmdd>-<version>.bin`` (``.hex``)
140
224
  :param target: Target number, see ``TARGETS``
141
- :param path: Binary file
225
+ :param path: Binary or Intel HEX file
142
226
  :param version: FW version, hexadecimal (BCD)
143
227
  :param suffix: Suffix of the output name, also used as the device ID of target 4
144
228
  :param out_dir: Output directory (default directory of the input file)
@@ -147,8 +231,17 @@ def build_file(target: int, path, version: str, suffix: str = "", out_dir=None,
147
231
  """
148
232
  path = Path(path)
149
233
  date = date or datetime.date.today()
150
- result, crc = build(path.read_bytes(), target, version, suffix, date)
151
- name = f"{path.stem}{'-' + suffix if suffix else ''}-{date:%Y%m%d}-{int(version, 16):X}.bin"
234
+ is_hex = path.suffix.lower() == ".hex"
235
+ if is_hex:
236
+ if TARGETS.get(target) is not None and TARGETS[target].offset is None:
237
+ raise ValueError(f"target {target} prepends the block to the file, it is not supported for HEX files")
238
+ base, image, start = read_hex(path.read_text(encoding="ascii"))
239
+ result, crc = build(image, target, version, suffix, date)
240
+ content = write_hex(base, result, start).encode("ascii")
241
+ else:
242
+ content, crc = build(path.read_bytes(), target, version, suffix, date)
243
+ name = f"{path.stem}{'-' + suffix if suffix else ''}-{date:%Y%m%d}-{int(version, 16):X}"
244
+ name += ".hex" if is_hex else ".bin"
152
245
  out = Path(out_dir) / name if out_dir else path.with_name(name)
153
- out.write_bytes(result)
246
+ out.write_bytes(content)
154
247
  return out, crc
@@ -1,89 +1,89 @@
1
- """
2
- Command line jump-start for lecore, see ``python -m lecore --help``
3
- """
4
- import argparse
5
- import sys
6
- import warnings
7
-
8
- from .Scaffold import guide, new_device, generate_regs, generate_tests
9
- from .FwBuild import TARGETS, build_file
10
-
11
-
12
- def _show_warning(message, category, filename, lineno, file=None, line=None):
13
- print(f"warning: {message}", file=sys.stderr)
14
-
15
-
16
- def main(argv=None) -> int:
17
- warnings.showwarning = _show_warning
18
- parser = argparse.ArgumentParser(prog="lecore", description="Logic Elements core utilities")
19
- sub = parser.add_subparsers(dest="cmd", required=True)
20
-
21
- sub.add_parser("guide", help="print quick guide for creating devices with lecore")
22
-
23
- p = sub.add_parser("new-device", help="create device class and missing configuration files next to the "
24
- "register map")
25
- p.add_argument("name", help="device class name, e.g., MyDevice")
26
- proto = p.add_mutually_exclusive_group()
27
- proto.add_argument("--modbus", dest="protocol", action="store_const", const="modbus",
28
- help="Modbus device (default: detected from register map)")
29
- proto.add_argument("--lebin", dest="protocol", action="store_const", const="lebin", help="LeBin device")
30
- p.add_argument("--dir", default=".", help="directory with register map (default: current)")
31
- p.add_argument("--reg-map", help="register map JSON in the directory (default: the single one found)")
32
- p.add_argument("--template", action="store_true",
33
- help="create minimal register map template and *Regs.py when no register map is present")
34
- p.add_argument("--gen-regs", action="store_true", help="generate missing *Regs.py from the register map")
35
- p.add_argument("--slave", type=int, default=1, help="default Modbus slave address")
36
- p.add_argument("--comport", default="COM1", help="default COM port")
37
- p.add_argument("--baud-rate", type=int, default=19200, help="default baud rate")
38
- p.add_argument("--parity", default="E", choices=("N", "E", "O"), help="default parity")
39
- p.add_argument("--usb", nargs=3, metavar=("VID", "PID", "SN"), help="LeBin USB identification for search_com()")
40
- p.add_argument("--force", action="store_true", help="overwrite existing device module and configuration files")
41
-
42
- p = sub.add_parser("new-tests", help="create missing communication test files (test_modbus.py, test_lebin.py) "
43
- "for device classes in a directory")
44
- p.add_argument("--dir", default=".", help="directory with device modules (default: current)")
45
- p.add_argument("--force", action="store_true", help="overwrite existing test files")
46
-
47
- p = sub.add_parser("regs", help="generate class with register name constants from a register map")
48
- p.add_argument("reg_map", help="register map JSON (Modbus or LeBin)")
49
- p.add_argument("--class", dest="class_name", default="Regs", help="generated class name")
50
- p.add_argument("-o", "--output", help="output Python file (default: print)")
51
-
52
- p = sub.add_parser("binbuild", help="stamp the FW information block (CRC, version, size) into a binary "
53
- "(replaces BinBuild.exe)",
54
- formatter_class=argparse.RawDescriptionHelpFormatter,
55
- epilog="targets:\n" + "\n".join(f" {n} - {t.description}" for n, t in TARGETS.items()))
56
- p.add_argument("target", type=int, choices=sorted(TARGETS), help="FW information block layout")
57
- p.add_argument("file", help="binary file")
58
- p.add_argument("version", help="FW version, hexadecimal (BCD)")
59
- p.add_argument("--suffix", default="", help="suffix of the output name, device ID for target 4")
60
- p.add_argument("--out-dir", help="output directory (default: directory of the binary)")
61
-
62
- args = parser.parse_args(argv)
63
- try:
64
- if args.cmd == "guide":
65
- print(guide())
66
- elif args.cmd == "new-device":
67
- usb = (int(args.usb[0], 0), int(args.usb[1], 0), args.usb[2]) if args.usb else None
68
- result = new_device(args.name, args.protocol, args.dir, args.reg_map, args.template, args.gen_regs,
69
- args.slave, args.comport, args.baud_rate, args.parity, usb, args.force)
70
- for path, status in result.items():
71
- print(f"{status:12}{path}")
72
- elif args.cmd == "new-tests":
73
- for path, status in generate_tests(args.dir, args.force).items():
74
- print(f"{status:12}{path}")
75
- elif args.cmd == "regs":
76
- src = generate_regs(args.reg_map, args.class_name, args.output)
77
- if args.output is None:
78
- print(src, end="")
79
- elif args.cmd == "binbuild":
80
- out, crc = build_file(args.target, args.file, args.version, args.suffix, args.out_dir)
81
- print(f"{out}\nNew File created with CRC value {crc:08X}")
82
- except (ValueError, OSError) as e:
83
- print(f"error: {e}", file=sys.stderr)
84
- return 1
85
- return 0
86
-
87
-
88
- if __name__ == "__main__":
89
- sys.exit(main())
1
+ """
2
+ Command line jump-start for lecore, see ``python -m lecore --help``
3
+ """
4
+ import argparse
5
+ import sys
6
+ import warnings
7
+
8
+ from .Scaffold import guide, new_device, generate_regs, generate_tests
9
+ from .FwBuild import TARGETS, build_file
10
+
11
+
12
+ def _show_warning(message, category, filename, lineno, file=None, line=None):
13
+ print(f"warning: {message}", file=sys.stderr)
14
+
15
+
16
+ def main(argv=None) -> int:
17
+ warnings.showwarning = _show_warning
18
+ parser = argparse.ArgumentParser(prog="lecore", description="Logic Elements core utilities")
19
+ sub = parser.add_subparsers(dest="cmd", required=True)
20
+
21
+ sub.add_parser("guide", help="print quick guide for creating devices with lecore")
22
+
23
+ p = sub.add_parser("new-device", help="create device class and missing configuration files next to the "
24
+ "register map")
25
+ p.add_argument("name", help="device class name, e.g., MyDevice")
26
+ proto = p.add_mutually_exclusive_group()
27
+ proto.add_argument("--modbus", dest="protocol", action="store_const", const="modbus",
28
+ help="Modbus device (default: detected from register map)")
29
+ proto.add_argument("--lebin", dest="protocol", action="store_const", const="lebin", help="LeBin device")
30
+ p.add_argument("--dir", default=".", help="directory with register map (default: current)")
31
+ p.add_argument("--reg-map", help="register map JSON in the directory (default: the single one found)")
32
+ p.add_argument("--template", action="store_true",
33
+ help="create minimal register map template and *Regs.py when no register map is present")
34
+ p.add_argument("--gen-regs", action="store_true", help="generate missing *Regs.py from the register map")
35
+ p.add_argument("--slave", type=int, default=1, help="default Modbus slave address")
36
+ p.add_argument("--comport", default="COM1", help="default COM port")
37
+ p.add_argument("--baud-rate", type=int, default=19200, help="default baud rate")
38
+ p.add_argument("--parity", default="E", choices=("N", "E", "O"), help="default parity")
39
+ p.add_argument("--usb", nargs=3, metavar=("VID", "PID", "SN"), help="LeBin USB identification for search_com()")
40
+ p.add_argument("--force", action="store_true", help="overwrite existing device module and configuration files")
41
+
42
+ p = sub.add_parser("new-tests", help="create missing communication test files (test_modbus.py, test_lebin.py) "
43
+ "for device classes in a directory")
44
+ p.add_argument("--dir", default=".", help="directory with device modules (default: current)")
45
+ p.add_argument("--force", action="store_true", help="overwrite existing test files")
46
+
47
+ p = sub.add_parser("regs", help="generate class with register name constants from a register map")
48
+ p.add_argument("reg_map", help="register map JSON (Modbus or LeBin)")
49
+ p.add_argument("--class", dest="class_name", default="Regs", help="generated class name")
50
+ p.add_argument("-o", "--output", help="output Python file (default: print)")
51
+
52
+ p = sub.add_parser("binbuild", help="stamp the FW information block (CRC, version, size) into a binary or HEX "
53
+ "(replaces BinBuild.exe)",
54
+ formatter_class=argparse.RawDescriptionHelpFormatter,
55
+ epilog="targets:\n" + "\n".join(f" {n} - {t.description}" for n, t in TARGETS.items()))
56
+ p.add_argument("target", type=int, choices=sorted(TARGETS), help="FW information block layout")
57
+ p.add_argument("file", help="binary or Intel HEX (.hex) file")
58
+ p.add_argument("version", help="FW version, hexadecimal (BCD)")
59
+ p.add_argument("--suffix", default="", help="suffix of the output name, device ID for target 4")
60
+ p.add_argument("--out-dir", help="output directory (default: directory of the binary)")
61
+
62
+ args = parser.parse_args(argv)
63
+ try:
64
+ if args.cmd == "guide":
65
+ print(guide())
66
+ elif args.cmd == "new-device":
67
+ usb = (int(args.usb[0], 0), int(args.usb[1], 0), args.usb[2]) if args.usb else None
68
+ result = new_device(args.name, args.protocol, args.dir, args.reg_map, args.template, args.gen_regs,
69
+ args.slave, args.comport, args.baud_rate, args.parity, usb, args.force)
70
+ for path, status in result.items():
71
+ print(f"{status:12}{path}")
72
+ elif args.cmd == "new-tests":
73
+ for path, status in generate_tests(args.dir, args.force).items():
74
+ print(f"{status:12}{path}")
75
+ elif args.cmd == "regs":
76
+ src = generate_regs(args.reg_map, args.class_name, args.output)
77
+ if args.output is None:
78
+ print(src, end="")
79
+ elif args.cmd == "binbuild":
80
+ out, crc = build_file(args.target, args.file, args.version, args.suffix, args.out_dir)
81
+ print(f"{out}\nNew File created with CRC value {crc:08X}")
82
+ except (ValueError, OSError) as e:
83
+ print(f"error: {e}", file=sys.stderr)
84
+ return 1
85
+ return 0
86
+
87
+
88
+ if __name__ == "__main__":
89
+ sys.exit(main())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lecore
3
- Version: 0.2.6
3
+ Version: 0.2.7
4
4
  Summary: Logic Elements core utilities
5
5
  Author-email: Jan Bartovský <jan.bartovsky@logicelements.cz>
6
6
  License-Expression: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes