termora 0.80.0__py3-none-any.whl
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.
- cutecom/__init__.py +11 -0
- cutecom/__main__.py +6 -0
- cutecom/app.py +151 -0
- cutecom/can/__init__.py +24 -0
- cutecom/can/backend.py +542 -0
- cutecom/can/dbc_support.py +132 -0
- cutecom/core/__init__.py +1 -0
- cutecom/core/filter_rules.py +55 -0
- cutecom/core/i18n.py +61 -0
- cutecom/core/modbus.py +374 -0
- cutecom/core/paths.py +123 -0
- cutecom/core/platformutil.py +116 -0
- cutecom/core/settings.py +518 -0
- cutecom/core/theme.py +778 -0
- cutecom/plugins/__init__.py +1 -0
- cutecom/plugins/autoreply.py +143 -0
- cutecom/plugins/counter.py +125 -0
- cutecom/plugins/host.py +414 -0
- cutecom/plugins/macros.py +1234 -0
- cutecom/plugins/manager.py +121 -0
- cutecom/plugins/modbus_assistant.py +327 -0
- cutecom/plugins/netproxy.py +299 -0
- cutecom/plugins/send_queue.py +122 -0
- cutecom/plugins/serial_bridge.py +225 -0
- cutecom/resources/i18n/en.json +655 -0
- cutecom/resources/i18n/zh_CN.json +655 -0
- cutecom/resources/icons/app.ico +0 -0
- cutecom/resources/icons/app.png +0 -0
- cutecom/resources/icons/app.svg +26 -0
- cutecom/resources/icons/break.svg +5 -0
- cutecom/resources/icons/check_off.svg +3 -0
- cutecom/resources/icons/check_off_light.svg +3 -0
- cutecom/resources/icons/check_on.svg +4 -0
- cutecom/resources/icons/chevron_down.svg +3 -0
- cutecom/resources/icons/chevron_up.svg +3 -0
- cutecom/resources/icons/clear.svg +5 -0
- cutecom/resources/icons/close.svg +4 -0
- cutecom/resources/icons/crc.svg +6 -0
- cutecom/resources/icons/export.svg +5 -0
- cutecom/resources/icons/find.svg +4 -0
- cutecom/resources/icons/freeze.svg +5 -0
- cutecom/resources/icons/hex.svg +4 -0
- cutecom/resources/icons/log.svg +5 -0
- cutecom/resources/icons/open.svg +4 -0
- cutecom/resources/icons/scope.svg +4 -0
- cutecom/resources/icons/send_file.svg +5 -0
- cutecom/resources/icons/session.svg +4 -0
- cutecom/resources/icons/settings.svg +4 -0
- cutecom/resources/icons/tab_close.svg +3 -0
- cutecom/resources/icons/tab_close_light.svg +3 -0
- cutecom/resources/macros/arduino_cli.json +162 -0
- cutecom/resources/macros/bluetooth_hc05.json +162 -0
- cutecom/resources/macros/common_debug.json +162 -0
- cutecom/resources/macros/esp32_at.json +162 -0
- cutecom/resources/macros/gnss.json +162 -0
- cutecom/resources/macros/gps_ublox.json +162 -0
- cutecom/resources/macros/grbl.json +162 -0
- cutecom/resources/macros/lora_at.json +162 -0
- cutecom/resources/macros/marlin_gcode.json +162 -0
- cutecom/resources/macros/modbus.json +162 -0
- cutecom/resources/macros/modem_4g.json +162 -0
- cutecom/resources/macros/serial_hmi.json +162 -0
- cutecom/resources/terminal.svg +500 -0
- cutecom/resources/themes/dark.qss +219 -0
- cutecom/resources/themes/light.qss +178 -0
- cutecom/resources/themes/nord.qss +179 -0
- cutecom/resources/themes/terminal.qss +179 -0
- cutecom/ui/__init__.py +1 -0
- cutecom/ui/can_analyzer.py +1368 -0
- cutecom/ui/can_config_dialog.py +279 -0
- cutecom/ui/can_scope.py +619 -0
- cutecom/ui/collapsible.py +95 -0
- cutecom/ui/control_panel.py +589 -0
- cutecom/ui/ctrl_popup.py +77 -0
- cutecom/ui/data_display.py +626 -0
- cutecom/ui/disk_log_dialog.py +75 -0
- cutecom/ui/display_perf_dialog.py +80 -0
- cutecom/ui/filter_rules_dialog.py +218 -0
- cutecom/ui/flow_layout.py +128 -0
- cutecom/ui/font_dialog.py +193 -0
- cutecom/ui/highlighter.py +124 -0
- cutecom/ui/icons.py +62 -0
- cutecom/ui/log_viewer_dialog.py +133 -0
- cutecom/ui/main_window.py +2173 -0
- cutecom/ui/protocol_panel.py +164 -0
- cutecom/ui/search_bar.py +87 -0
- cutecom/ui/session_dialog.py +173 -0
- cutecom/ui/signal_scope.py +328 -0
- cutecom/ui/status_widget.py +87 -0
- cutecom/ui/tools_dialog.py +118 -0
- cutecom/ui/windowing.py +193 -0
- termora-0.80.0.dist-info/METADATA +201 -0
- termora-0.80.0.dist-info/RECORD +97 -0
- termora-0.80.0.dist-info/WHEEL +5 -0
- termora-0.80.0.dist-info/entry_points.txt +3 -0
- termora-0.80.0.dist-info/licenses/LICENSE +21 -0
- termora-0.80.0.dist-info/top_level.txt +1 -0
cutecom/__init__.py
ADDED
cutecom/__main__.py
ADDED
cutecom/app.py
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""Termora 主入口:解析命令行,在 GUI 与无界面串口模式之间分发。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
import time
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from PySide6.QtCore import QCoreApplication, QIODevice, QTimer
|
|
11
|
+
from PySide6.QtSerialPort import QSerialPort
|
|
12
|
+
from PySide6.QtWidgets import QApplication
|
|
13
|
+
|
|
14
|
+
from cutecom import APP_ID, APP_NAME, APP_ORG, VERSION
|
|
15
|
+
from cutecom.core.settings import AppSettings
|
|
16
|
+
from cutecom.core.theme import ui_font
|
|
17
|
+
from cutecom.ui.icons import app_icon
|
|
18
|
+
from cutecom.ui.main_window import MainWindow
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _run_headless(args: argparse.Namespace) -> int:
|
|
22
|
+
"""无界面模式:打开串口,可选发送字符串或文件,将 RX 写入 stdout 后按超时退出。"""
|
|
23
|
+
app = QCoreApplication([APP_NAME])
|
|
24
|
+
app.setOrganizationName(APP_ORG)
|
|
25
|
+
app.setApplicationName(APP_ID)
|
|
26
|
+
app.setApplicationVersion(VERSION)
|
|
27
|
+
|
|
28
|
+
port = QSerialPort()
|
|
29
|
+
port.setPortName(args.port)
|
|
30
|
+
port.setBaudRate(args.baud)
|
|
31
|
+
port.setDataBits(QSerialPort.DataBits.Data8)
|
|
32
|
+
port.setParity(QSerialPort.Parity.NoParity)
|
|
33
|
+
port.setStopBits(QSerialPort.StopBits.OneStop)
|
|
34
|
+
if not port.open(QIODevice.OpenModeFlag.ReadWrite):
|
|
35
|
+
print(f"termora: cannot open {args.port}: {port.errorString()}", file=sys.stderr)
|
|
36
|
+
return 1
|
|
37
|
+
|
|
38
|
+
def on_ready() -> None:
|
|
39
|
+
data = bytes(port.readAll())
|
|
40
|
+
if data:
|
|
41
|
+
sys.stdout.buffer.write(data)
|
|
42
|
+
sys.stdout.buffer.flush()
|
|
43
|
+
|
|
44
|
+
port.readyRead.connect(on_ready)
|
|
45
|
+
|
|
46
|
+
if args.send:
|
|
47
|
+
payload = args.send.encode("utf-8", errors="replace")
|
|
48
|
+
if args.line_end == "crlf":
|
|
49
|
+
payload += b"\r\n"
|
|
50
|
+
elif args.line_end == "cr":
|
|
51
|
+
payload += b"\r"
|
|
52
|
+
elif args.line_end == "lf":
|
|
53
|
+
payload += b"\n"
|
|
54
|
+
port.write(payload)
|
|
55
|
+
port.flush()
|
|
56
|
+
|
|
57
|
+
if args.send_file:
|
|
58
|
+
path = Path(args.send_file)
|
|
59
|
+
if not path.is_file():
|
|
60
|
+
print(f"termora: file not found: {path}", file=sys.stderr)
|
|
61
|
+
port.close()
|
|
62
|
+
return 1
|
|
63
|
+
port.write(path.read_bytes())
|
|
64
|
+
port.flush()
|
|
65
|
+
|
|
66
|
+
deadline = time.monotonic() + max(0.0, args.timeout)
|
|
67
|
+
timer = QTimer()
|
|
68
|
+
timer.setInterval(50)
|
|
69
|
+
|
|
70
|
+
def tick() -> None:
|
|
71
|
+
if time.monotonic() >= deadline:
|
|
72
|
+
port.close()
|
|
73
|
+
app.quit()
|
|
74
|
+
|
|
75
|
+
timer.timeout.connect(tick)
|
|
76
|
+
timer.start()
|
|
77
|
+
return app.exec()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def main(argv: list[str] | None = None) -> int:
|
|
81
|
+
parser = argparse.ArgumentParser(description=f"{APP_NAME} {VERSION}")
|
|
82
|
+
parser.add_argument("-s", "--session", default="", help="Open a named session")
|
|
83
|
+
parser.add_argument("--port", default="", help="Serial device (CLI)")
|
|
84
|
+
parser.add_argument("--baud", type=int, default=115200, help="Baud rate for --port")
|
|
85
|
+
parser.add_argument("--send", default="", help="Send a string after open")
|
|
86
|
+
parser.add_argument("--send-file", default="", help="Send a file after open")
|
|
87
|
+
parser.add_argument(
|
|
88
|
+
"--line-end",
|
|
89
|
+
choices=("none", "lf", "cr", "crlf"),
|
|
90
|
+
default="lf",
|
|
91
|
+
help="Line ending appended to --send (headless)",
|
|
92
|
+
)
|
|
93
|
+
parser.add_argument(
|
|
94
|
+
"--timeout",
|
|
95
|
+
type=float,
|
|
96
|
+
default=2.0,
|
|
97
|
+
help="Seconds to keep reading in headless mode before exit",
|
|
98
|
+
)
|
|
99
|
+
parser.add_argument(
|
|
100
|
+
"--headless",
|
|
101
|
+
action="store_true",
|
|
102
|
+
help="No GUI: open --port, send, print RX to stdout",
|
|
103
|
+
)
|
|
104
|
+
args = parser.parse_args(argv)
|
|
105
|
+
|
|
106
|
+
if args.headless:
|
|
107
|
+
if not args.port:
|
|
108
|
+
parser.error("--headless requires --port")
|
|
109
|
+
# 使用 QCoreApplication,不实例化 QWidget,适合脚本与管道场景。
|
|
110
|
+
return _run_headless(args)
|
|
111
|
+
|
|
112
|
+
app = QApplication(sys.argv if argv is None else [APP_NAME, *argv])
|
|
113
|
+
app.setOrganizationName(APP_ORG)
|
|
114
|
+
app.setApplicationName(APP_ID)
|
|
115
|
+
app.setApplicationDisplayName(APP_NAME)
|
|
116
|
+
app.setApplicationVersion(VERSION)
|
|
117
|
+
# 资源图标缺失时 isNull(),跳过 setWindowIcon 以免占位空图标。
|
|
118
|
+
icon = app_icon()
|
|
119
|
+
if not icon.isNull():
|
|
120
|
+
app.setWindowIcon(icon)
|
|
121
|
+
|
|
122
|
+
settings = AppSettings()
|
|
123
|
+
settings.read(args.session)
|
|
124
|
+
if args.port:
|
|
125
|
+
settings.update_session(device=args.port, baud_rate=args.baud)
|
|
126
|
+
app.setFont(ui_font(settings.language))
|
|
127
|
+
window = MainWindow(settings, args.session)
|
|
128
|
+
if args.port:
|
|
129
|
+
window.control.apply_session(settings.current_session())
|
|
130
|
+
window.show()
|
|
131
|
+
if args.port:
|
|
132
|
+
QTimer.singleShot(0, window.open_device)
|
|
133
|
+
# 延迟发送,等待 open_device 完成后再写串口。
|
|
134
|
+
if args.send_file:
|
|
135
|
+
def _send_file_later() -> None:
|
|
136
|
+
path = Path(args.send_file)
|
|
137
|
+
if path.is_file() and window.device.isOpen():
|
|
138
|
+
window._write_bytes(path.read_bytes())
|
|
139
|
+
|
|
140
|
+
QTimer.singleShot(400, _send_file_later)
|
|
141
|
+
if args.send:
|
|
142
|
+
def _send_later() -> None:
|
|
143
|
+
if window.device.isOpen():
|
|
144
|
+
window.input.setText(args.send)
|
|
145
|
+
window.exec_cmd(clear_input=False)
|
|
146
|
+
|
|
147
|
+
QTimer.singleShot(400, _send_later)
|
|
148
|
+
return app.exec()
|
|
149
|
+
|
|
150
|
+
if __name__ == "__main__":
|
|
151
|
+
raise SystemExit(main())
|
cutecom/can/__init__.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""CAN 分析器公共导出:帧/过滤器类型与可选 python-can 后端封装。"""
|
|
2
|
+
|
|
3
|
+
from cutecom.can.backend import (
|
|
4
|
+
BusStats,
|
|
5
|
+
CanBackendKind,
|
|
6
|
+
CanBusBackend,
|
|
7
|
+
CanConnectionConfig,
|
|
8
|
+
CanFilter,
|
|
9
|
+
CanFrame,
|
|
10
|
+
list_interfaces,
|
|
11
|
+
)
|
|
12
|
+
from cutecom.can.dbc_support import DbcDatabase, DecodedSignal
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"BusStats",
|
|
16
|
+
"CanBackendKind",
|
|
17
|
+
"CanBusBackend",
|
|
18
|
+
"CanConnectionConfig",
|
|
19
|
+
"CanFilter",
|
|
20
|
+
"CanFrame",
|
|
21
|
+
"DbcDatabase",
|
|
22
|
+
"DecodedSignal",
|
|
23
|
+
"list_interfaces",
|
|
24
|
+
]
|