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.
Files changed (97) hide show
  1. cutecom/__init__.py +11 -0
  2. cutecom/__main__.py +6 -0
  3. cutecom/app.py +151 -0
  4. cutecom/can/__init__.py +24 -0
  5. cutecom/can/backend.py +542 -0
  6. cutecom/can/dbc_support.py +132 -0
  7. cutecom/core/__init__.py +1 -0
  8. cutecom/core/filter_rules.py +55 -0
  9. cutecom/core/i18n.py +61 -0
  10. cutecom/core/modbus.py +374 -0
  11. cutecom/core/paths.py +123 -0
  12. cutecom/core/platformutil.py +116 -0
  13. cutecom/core/settings.py +518 -0
  14. cutecom/core/theme.py +778 -0
  15. cutecom/plugins/__init__.py +1 -0
  16. cutecom/plugins/autoreply.py +143 -0
  17. cutecom/plugins/counter.py +125 -0
  18. cutecom/plugins/host.py +414 -0
  19. cutecom/plugins/macros.py +1234 -0
  20. cutecom/plugins/manager.py +121 -0
  21. cutecom/plugins/modbus_assistant.py +327 -0
  22. cutecom/plugins/netproxy.py +299 -0
  23. cutecom/plugins/send_queue.py +122 -0
  24. cutecom/plugins/serial_bridge.py +225 -0
  25. cutecom/resources/i18n/en.json +655 -0
  26. cutecom/resources/i18n/zh_CN.json +655 -0
  27. cutecom/resources/icons/app.ico +0 -0
  28. cutecom/resources/icons/app.png +0 -0
  29. cutecom/resources/icons/app.svg +26 -0
  30. cutecom/resources/icons/break.svg +5 -0
  31. cutecom/resources/icons/check_off.svg +3 -0
  32. cutecom/resources/icons/check_off_light.svg +3 -0
  33. cutecom/resources/icons/check_on.svg +4 -0
  34. cutecom/resources/icons/chevron_down.svg +3 -0
  35. cutecom/resources/icons/chevron_up.svg +3 -0
  36. cutecom/resources/icons/clear.svg +5 -0
  37. cutecom/resources/icons/close.svg +4 -0
  38. cutecom/resources/icons/crc.svg +6 -0
  39. cutecom/resources/icons/export.svg +5 -0
  40. cutecom/resources/icons/find.svg +4 -0
  41. cutecom/resources/icons/freeze.svg +5 -0
  42. cutecom/resources/icons/hex.svg +4 -0
  43. cutecom/resources/icons/log.svg +5 -0
  44. cutecom/resources/icons/open.svg +4 -0
  45. cutecom/resources/icons/scope.svg +4 -0
  46. cutecom/resources/icons/send_file.svg +5 -0
  47. cutecom/resources/icons/session.svg +4 -0
  48. cutecom/resources/icons/settings.svg +4 -0
  49. cutecom/resources/icons/tab_close.svg +3 -0
  50. cutecom/resources/icons/tab_close_light.svg +3 -0
  51. cutecom/resources/macros/arduino_cli.json +162 -0
  52. cutecom/resources/macros/bluetooth_hc05.json +162 -0
  53. cutecom/resources/macros/common_debug.json +162 -0
  54. cutecom/resources/macros/esp32_at.json +162 -0
  55. cutecom/resources/macros/gnss.json +162 -0
  56. cutecom/resources/macros/gps_ublox.json +162 -0
  57. cutecom/resources/macros/grbl.json +162 -0
  58. cutecom/resources/macros/lora_at.json +162 -0
  59. cutecom/resources/macros/marlin_gcode.json +162 -0
  60. cutecom/resources/macros/modbus.json +162 -0
  61. cutecom/resources/macros/modem_4g.json +162 -0
  62. cutecom/resources/macros/serial_hmi.json +162 -0
  63. cutecom/resources/terminal.svg +500 -0
  64. cutecom/resources/themes/dark.qss +219 -0
  65. cutecom/resources/themes/light.qss +178 -0
  66. cutecom/resources/themes/nord.qss +179 -0
  67. cutecom/resources/themes/terminal.qss +179 -0
  68. cutecom/ui/__init__.py +1 -0
  69. cutecom/ui/can_analyzer.py +1368 -0
  70. cutecom/ui/can_config_dialog.py +279 -0
  71. cutecom/ui/can_scope.py +619 -0
  72. cutecom/ui/collapsible.py +95 -0
  73. cutecom/ui/control_panel.py +589 -0
  74. cutecom/ui/ctrl_popup.py +77 -0
  75. cutecom/ui/data_display.py +626 -0
  76. cutecom/ui/disk_log_dialog.py +75 -0
  77. cutecom/ui/display_perf_dialog.py +80 -0
  78. cutecom/ui/filter_rules_dialog.py +218 -0
  79. cutecom/ui/flow_layout.py +128 -0
  80. cutecom/ui/font_dialog.py +193 -0
  81. cutecom/ui/highlighter.py +124 -0
  82. cutecom/ui/icons.py +62 -0
  83. cutecom/ui/log_viewer_dialog.py +133 -0
  84. cutecom/ui/main_window.py +2173 -0
  85. cutecom/ui/protocol_panel.py +164 -0
  86. cutecom/ui/search_bar.py +87 -0
  87. cutecom/ui/session_dialog.py +173 -0
  88. cutecom/ui/signal_scope.py +328 -0
  89. cutecom/ui/status_widget.py +87 -0
  90. cutecom/ui/tools_dialog.py +118 -0
  91. cutecom/ui/windowing.py +193 -0
  92. termora-0.80.0.dist-info/METADATA +201 -0
  93. termora-0.80.0.dist-info/RECORD +97 -0
  94. termora-0.80.0.dist-info/WHEEL +5 -0
  95. termora-0.80.0.dist-info/entry_points.txt +3 -0
  96. termora-0.80.0.dist-info/licenses/LICENSE +21 -0
  97. termora-0.80.0.dist-info/top_level.txt +1 -0
cutecom/__init__.py ADDED
@@ -0,0 +1,11 @@
1
+ """Termora(``cutecom`` 包)— 串口、CAN 与协议调试工具。
2
+
3
+ 提供桌面 GUI 与可选的无界面 CLI;本模块导出应用名称、组织与版本等标识,
4
+ 供设置持久化、窗口标题与命令行描述共用。
5
+ """
6
+
7
+ APP_NAME = "Termora"
8
+ APP_ORG = "Termora"
9
+ APP_ID = "Termora"
10
+ APP_TAGLINE = "Serial · CAN · Protocols"
11
+ VERSION = "0.80.0"
cutecom/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ """``python -m cutecom`` 入口:委托 ``cutecom.app.main`` 启动应用。"""
2
+
3
+ from cutecom.app import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())
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())
@@ -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
+ ]