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.
- {lecore-0.2.6/src/lecore.egg-info → lecore-0.2.7}/PKG-INFO +1 -1
- {lecore-0.2.6 → lecore-0.2.7}/pyproject.toml +1 -1
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/FwBuild.py +99 -6
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/__main__.py +89 -89
- {lecore-0.2.6 → lecore-0.2.7/src/lecore.egg-info}/PKG-INFO +1 -1
- {lecore-0.2.6 → lecore-0.2.7}/LICENSE +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/MANIFEST.in +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/README.md +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/setup.cfg +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/DeviceTests/Base.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/DeviceTests/LeBinTests.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/DeviceTests/ModbusTests.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/DeviceTests/Plugin.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/DeviceTests/__init__.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/DeviceBase.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/LeBinDev.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/ModbusDev.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/ComSettings.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/PhaseDet.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/PhaseDetRegs.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/PhaseDet_Modbus.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/UpgradeSettings.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/VisualSettings.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/PhaseDet/__init__.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/ComSettings.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/Rftb.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/RftbLeBin.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/UpgradeSettings.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/VisualSettings.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/__init__.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/rftbRegs.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/rftb_Modbus.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Rftb/rftb_registers.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/ComSettings.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/RtdEmul.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/RtdEmulRegs.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/RtdEmul_Modbus.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/UpgradeSettings.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/VisualSettings.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/RtdEmul/__init__.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/Validation.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/ComSettings.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/UpgradeSettings.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/VMS_RTDRegs.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/VMS_RTD_Modbus.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/VisualSettings.json +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/VmsRtd.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/VmsRtd/__init__.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Devices/__init__.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Doc/ModbusTable.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Doc/__init__.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Fg320/Fg320.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Fg320/__init__.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/LeBin/RegisterMap.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/LeBin/SerialCom.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/LeBin/UpgradeFirmware.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/LeBin/VisualLeBin.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/LeBin/__init__.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Looger.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/QUICKSTART.md +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/Scaffold.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/TestFrame/CoreTest.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/TestFrame/ModbusUnitTest.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/TestFrame/RtuClient.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/TestFrame/Runner.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/TestFrame/TestUtils.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/TestFrame/__init__.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/AppLogging.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/Crc32.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/HelpAbout.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/MbClient.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/MbUpgrade.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/ReadWrite.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/RegMap.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/TextMbApp.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/TextMbAppCss.tcss +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/VisualMbApp.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/VmSettings.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/VisualModbus/__init__.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/__init__.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/_version.py +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore/py.typed +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore.egg-info/SOURCES.txt +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore.egg-info/dependency_links.txt +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore.egg-info/entry_points.txt +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore.egg-info/requires.txt +0 -0
- {lecore-0.2.6 → lecore-0.2.7}/src/lecore.egg-info/top_level.txt +0 -0
|
@@ -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
|
|
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
|
-
|
|
151
|
-
|
|
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(
|
|
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())
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|