termora 0.80.0__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 (104) hide show
  1. termora-0.80.0/LICENSE +21 -0
  2. termora-0.80.0/MANIFEST.in +3 -0
  3. termora-0.80.0/PKG-INFO +201 -0
  4. termora-0.80.0/README.md +170 -0
  5. termora-0.80.0/pyproject.toml +72 -0
  6. termora-0.80.0/requirements.txt +5 -0
  7. termora-0.80.0/setup.cfg +4 -0
  8. termora-0.80.0/src/__init__.py +11 -0
  9. termora-0.80.0/src/__main__.py +6 -0
  10. termora-0.80.0/src/app.py +151 -0
  11. termora-0.80.0/src/can/__init__.py +24 -0
  12. termora-0.80.0/src/can/backend.py +542 -0
  13. termora-0.80.0/src/can/dbc_support.py +132 -0
  14. termora-0.80.0/src/core/__init__.py +1 -0
  15. termora-0.80.0/src/core/filter_rules.py +55 -0
  16. termora-0.80.0/src/core/i18n.py +61 -0
  17. termora-0.80.0/src/core/modbus.py +374 -0
  18. termora-0.80.0/src/core/paths.py +123 -0
  19. termora-0.80.0/src/core/platformutil.py +116 -0
  20. termora-0.80.0/src/core/settings.py +518 -0
  21. termora-0.80.0/src/core/theme.py +778 -0
  22. termora-0.80.0/src/plugins/__init__.py +1 -0
  23. termora-0.80.0/src/plugins/autoreply.py +143 -0
  24. termora-0.80.0/src/plugins/counter.py +125 -0
  25. termora-0.80.0/src/plugins/host.py +414 -0
  26. termora-0.80.0/src/plugins/macros.py +1234 -0
  27. termora-0.80.0/src/plugins/manager.py +121 -0
  28. termora-0.80.0/src/plugins/modbus_assistant.py +327 -0
  29. termora-0.80.0/src/plugins/netproxy.py +299 -0
  30. termora-0.80.0/src/plugins/send_queue.py +122 -0
  31. termora-0.80.0/src/plugins/serial_bridge.py +225 -0
  32. termora-0.80.0/src/resources/i18n/en.json +655 -0
  33. termora-0.80.0/src/resources/i18n/zh_CN.json +655 -0
  34. termora-0.80.0/src/resources/icons/app.ico +0 -0
  35. termora-0.80.0/src/resources/icons/app.png +0 -0
  36. termora-0.80.0/src/resources/icons/app.svg +26 -0
  37. termora-0.80.0/src/resources/icons/break.svg +5 -0
  38. termora-0.80.0/src/resources/icons/check_off.svg +3 -0
  39. termora-0.80.0/src/resources/icons/check_off_light.svg +3 -0
  40. termora-0.80.0/src/resources/icons/check_on.svg +4 -0
  41. termora-0.80.0/src/resources/icons/chevron_down.svg +3 -0
  42. termora-0.80.0/src/resources/icons/chevron_up.svg +3 -0
  43. termora-0.80.0/src/resources/icons/clear.svg +5 -0
  44. termora-0.80.0/src/resources/icons/close.svg +4 -0
  45. termora-0.80.0/src/resources/icons/crc.svg +6 -0
  46. termora-0.80.0/src/resources/icons/export.svg +5 -0
  47. termora-0.80.0/src/resources/icons/find.svg +4 -0
  48. termora-0.80.0/src/resources/icons/freeze.svg +5 -0
  49. termora-0.80.0/src/resources/icons/hex.svg +4 -0
  50. termora-0.80.0/src/resources/icons/log.svg +5 -0
  51. termora-0.80.0/src/resources/icons/open.svg +4 -0
  52. termora-0.80.0/src/resources/icons/scope.svg +4 -0
  53. termora-0.80.0/src/resources/icons/send_file.svg +5 -0
  54. termora-0.80.0/src/resources/icons/session.svg +4 -0
  55. termora-0.80.0/src/resources/icons/settings.svg +4 -0
  56. termora-0.80.0/src/resources/icons/tab_close.svg +3 -0
  57. termora-0.80.0/src/resources/icons/tab_close_light.svg +3 -0
  58. termora-0.80.0/src/resources/macros/arduino_cli.json +162 -0
  59. termora-0.80.0/src/resources/macros/bluetooth_hc05.json +162 -0
  60. termora-0.80.0/src/resources/macros/common_debug.json +162 -0
  61. termora-0.80.0/src/resources/macros/esp32_at.json +162 -0
  62. termora-0.80.0/src/resources/macros/gnss.json +162 -0
  63. termora-0.80.0/src/resources/macros/gps_ublox.json +162 -0
  64. termora-0.80.0/src/resources/macros/grbl.json +162 -0
  65. termora-0.80.0/src/resources/macros/lora_at.json +162 -0
  66. termora-0.80.0/src/resources/macros/marlin_gcode.json +162 -0
  67. termora-0.80.0/src/resources/macros/modbus.json +162 -0
  68. termora-0.80.0/src/resources/macros/modem_4g.json +162 -0
  69. termora-0.80.0/src/resources/macros/serial_hmi.json +162 -0
  70. termora-0.80.0/src/resources/terminal.svg +500 -0
  71. termora-0.80.0/src/resources/themes/dark.qss +219 -0
  72. termora-0.80.0/src/resources/themes/light.qss +178 -0
  73. termora-0.80.0/src/resources/themes/nord.qss +179 -0
  74. termora-0.80.0/src/resources/themes/terminal.qss +179 -0
  75. termora-0.80.0/src/ui/__init__.py +1 -0
  76. termora-0.80.0/src/ui/can_analyzer.py +1368 -0
  77. termora-0.80.0/src/ui/can_config_dialog.py +279 -0
  78. termora-0.80.0/src/ui/can_scope.py +619 -0
  79. termora-0.80.0/src/ui/collapsible.py +95 -0
  80. termora-0.80.0/src/ui/control_panel.py +589 -0
  81. termora-0.80.0/src/ui/ctrl_popup.py +77 -0
  82. termora-0.80.0/src/ui/data_display.py +626 -0
  83. termora-0.80.0/src/ui/disk_log_dialog.py +75 -0
  84. termora-0.80.0/src/ui/display_perf_dialog.py +80 -0
  85. termora-0.80.0/src/ui/filter_rules_dialog.py +218 -0
  86. termora-0.80.0/src/ui/flow_layout.py +128 -0
  87. termora-0.80.0/src/ui/font_dialog.py +193 -0
  88. termora-0.80.0/src/ui/highlighter.py +124 -0
  89. termora-0.80.0/src/ui/icons.py +62 -0
  90. termora-0.80.0/src/ui/log_viewer_dialog.py +133 -0
  91. termora-0.80.0/src/ui/main_window.py +2173 -0
  92. termora-0.80.0/src/ui/protocol_panel.py +164 -0
  93. termora-0.80.0/src/ui/search_bar.py +87 -0
  94. termora-0.80.0/src/ui/session_dialog.py +173 -0
  95. termora-0.80.0/src/ui/signal_scope.py +328 -0
  96. termora-0.80.0/src/ui/status_widget.py +87 -0
  97. termora-0.80.0/src/ui/tools_dialog.py +118 -0
  98. termora-0.80.0/src/ui/windowing.py +193 -0
  99. termora-0.80.0/termora.egg-info/PKG-INFO +201 -0
  100. termora-0.80.0/termora.egg-info/SOURCES.txt +102 -0
  101. termora-0.80.0/termora.egg-info/dependency_links.txt +1 -0
  102. termora-0.80.0/termora.egg-info/entry_points.txt +3 -0
  103. termora-0.80.0/termora.egg-info/requires.txt +4 -0
  104. termora-0.80.0/termora.egg-info/top_level.txt +1 -0
termora-0.80.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 sunyd168
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ graft src/resources
2
+ include LICENSE README.md pyproject.toml requirements.txt
3
+ global-exclude __pycache__ *.py[cod] .DS_Store
@@ -0,0 +1,201 @@
1
+ Metadata-Version: 2.4
2
+ Name: termora
3
+ Version: 0.80.0
4
+ Summary: Desktop workbench for serial, CAN, and protocol debugging
5
+ Author-email: sunyd168 <sunyd168@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/syd168/Termora
8
+ Project-URL: Repository, https://github.com/syd168/Termora
9
+ Project-URL: Issues, https://github.com/syd168/Termora/issues
10
+ Keywords: serial,uart,can,modbus,terminal,pyside6,protocol
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: X11 Applications :: Qt
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: System :: Hardware
22
+ Classifier: Topic :: Terminals :: Serial
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: PySide6>=6.6
27
+ Requires-Dist: PySide6-Addons>=6.6
28
+ Requires-Dist: python-can>=4.3
29
+ Requires-Dist: cantools>=39.0
30
+ Dynamic: license-file
31
+
32
+ # Termora
33
+
34
+ [![PyPI](https://img.shields.io/pypi/v/termora.svg)](https://pypi.org/project/termora/)
35
+ [![Python](https://img.shields.io/pypi/pyversions/termora.svg)](https://pypi.org/project/termora/)
36
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
37
+
38
+ Desktop workbench for **serial**, **CAN**, and **protocol** debugging. Built with PySide6, laid out for wide / 2K / 4K screens, with skins and English / 简体中文. Inspired by classic [CuteCom](https://gitlab.com/cutecom/cutecom).
39
+
40
+ The product name is **Termora**. The Python import package stays `cutecom` so existing macros and scripts keep working.
41
+
42
+ 面向串口、CAN 与协议调试的桌面工作台。基于 PySide6,界面按大屏设计,支持皮肤与多语言。
43
+
44
+ ---
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ pip install termora
50
+ termora
51
+ ```
52
+
53
+ Or from this repository:
54
+
55
+ ```bash
56
+ git clone https://github.com/syd168/Termora.git
57
+ cd Termora
58
+ python3 -m venv .venv
59
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
60
+ pip install -e .
61
+ termora
62
+ ```
63
+
64
+ Use a **dedicated venv**. Mixing conda `pyside6` with pip `PySide6-Addons` leads to
65
+ `libshiboken6.abi3.so` import errors.
66
+
67
+ ### Platform notes
68
+
69
+ | Capability | Linux | macOS | Windows |
70
+ |------------|:-----:|:-----:|:-------:|
71
+ | Serial I/O, sessions, macros, plugins | ✓ | ✓ | ✓ |
72
+ | CAN (virtual / PCAN / Kvaser / Vector / SLCAN, …) | ✓ | ✓* | ✓* |
73
+ | Native SocketCAN | ✓ | — | — |
74
+ | X/Y/Zmodem (`sz` / lrzsz) | ✓ | ✓* | — |
75
+
76
+ \* Needs the matching driver or Homebrew tool. Use the `virtual` CAN backend without hardware.
77
+
78
+ - **Linux**: `sudo usermod -aG dialout $USER` then log in again.
79
+ - **macOS**: ports look like `/dev/cu.*`. Zmodem: `brew install lrzsz`.
80
+ - **Windows**: `COMx` in Device Manager. No X/Y/Zmodem (`sz` + POSIX redirection).
81
+
82
+ ---
83
+
84
+ ## Usage
85
+
86
+ ```bash
87
+ termora # GUI
88
+ termora -s Default # named session
89
+ python -m cutecom # same entry point
90
+ python run.py # from a source checkout
91
+ ```
92
+
93
+ Headless serial (no window; RX on stdout):
94
+
95
+ ```bash
96
+ termora --headless --port /dev/ttyUSB0 --baud 115200 --send "AT" --timeout 2
97
+ ```
98
+
99
+ | Flag | Meaning |
100
+ |------|---------|
101
+ | `-s`, `--session` | Open a named session |
102
+ | `--port` | Serial device |
103
+ | `--baud` | Baud rate (default `115200`) |
104
+ | `--send` | String to write after open |
105
+ | `--send-file` | File bytes to write after open |
106
+ | `--line-end` | `none` / `lf` / `cr` / `crlf` (headless `--send`) |
107
+ | `--timeout` | Headless read duration in seconds |
108
+ | `--headless` | No GUI; requires `--port` |
109
+
110
+ Logs: repo runs write `logs/` in the project; a pip-installed run uses the OS app-data directory.
111
+
112
+ ---
113
+
114
+ ## Interface
115
+
116
+ Connection settings on the left, a large output pane in the middle, command history above, input bar at the bottom.
117
+
118
+ - **View → Skin**: Light / Dark / Nord / Terminal green
119
+ - **View → Language**: English / 简体中文
120
+ - **View → Connection settings** (`Alt+S`): reopen the sidebar
121
+
122
+ ---
123
+
124
+ ## Features
125
+
126
+ Aligned with classic CuteCom:
127
+
128
+ - Open/close, baud, data bits, parity, stop bits, flow control, RTS/DTR
129
+ - Read-write / read-only / write-only, auto-reconnect
130
+ - Line endings LF / CR / CRLF / none / Hex, character delay
131
+ - Command history, completion, Ctrl control characters
132
+ - Text / HEX display, control characters, timestamps, find (`F3`)
133
+ - Session manager; disk logs (per session and window)
134
+ - Send file as text or script; X/Y/Zmodem on Linux/macOS (`sz`)
135
+ - Plugins: macro packs (JSON, hand-editable; legacy `.tmf` supported), UDP/TCP proxy, byte counter, Modbus assistant
136
+
137
+ Termora extras:
138
+
139
+ - Skins and language switch
140
+ - Local echo (TX in green)
141
+ - Leave port settings unchanged on open
142
+ - Break, repeat send
143
+ - Freeze scroll / export output (`Ctrl+E`)
144
+ - Live RX/TX B/s, recent devices
145
+ - CRC / checksum tools, protocol pane (NMEA / AT / Modbus)
146
+ - CAN analyzer (multiple backends, DBC, sequenced send)
147
+ - Widescreen sidebar layout
148
+ - Multiple windows (each with its own port and log file)
149
+
150
+ ### Macro packs
151
+
152
+ JSON files. Built-in examples live in the package (`cutecom/resources/macros/`). When you run from the repo, user copies go under `config/macros/`.
153
+
154
+ ```json
155
+ {
156
+ "format": "cutecom-macros",
157
+ "version": 2,
158
+ "name": { "en": "ESP32 / ESP-AT", "zh_CN": "ESP32 / ESP-AT" },
159
+ "macros": [
160
+ { "name": { "en": "Reset", "zh_CN": "复位" }, "command": "AT+RST" }
161
+ ]
162
+ }
163
+ ```
164
+
165
+ Escapes in commands: `\n` `\r` `\t` `\0` `\xFF`. In JSON write `\\`.
166
+
167
+ ---
168
+
169
+ ## 中文
170
+
171
+ ```bash
172
+ pip install termora
173
+ termora
174
+ ```
175
+
176
+ 从源码:
177
+
178
+ ```bash
179
+ git clone https://github.com/syd168/Termora.git
180
+ cd Termora
181
+ python3 -m venv .venv
182
+ source .venv/bin/activate
183
+ pip install -e .
184
+ termora
185
+ ```
186
+
187
+ 请使用项目自己的虚拟环境。不要用混装了 conda `pyside6` 与 pip `PySide6-Addons` 的解释器,否则会报找不到 `libshiboken6.abi3.so`。
188
+
189
+ 无界面发串口:
190
+
191
+ ```bash
192
+ termora --headless --port /dev/ttyUSB0 --baud 115200 --send "AT" --timeout 2
193
+ ```
194
+
195
+ Linux 串口权限:`sudo usermod -aG dialout $USER`,重新登录后生效。开发态日志在项目 `logs/`;`pip install` 后使用系统 AppData / Application Support。
196
+
197
+ ---
198
+
199
+ ## License
200
+
201
+ [MIT](LICENSE). Inspired by [CuteCom](https://gitlab.com/cutecom/cutecom); this is an independent Python implementation.
@@ -0,0 +1,170 @@
1
+ # Termora
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/termora.svg)](https://pypi.org/project/termora/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/termora.svg)](https://pypi.org/project/termora/)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+
7
+ Desktop workbench for **serial**, **CAN**, and **protocol** debugging. Built with PySide6, laid out for wide / 2K / 4K screens, with skins and English / 简体中文. Inspired by classic [CuteCom](https://gitlab.com/cutecom/cutecom).
8
+
9
+ The product name is **Termora**. The Python import package stays `cutecom` so existing macros and scripts keep working.
10
+
11
+ 面向串口、CAN 与协议调试的桌面工作台。基于 PySide6,界面按大屏设计,支持皮肤与多语言。
12
+
13
+ ---
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ pip install termora
19
+ termora
20
+ ```
21
+
22
+ Or from this repository:
23
+
24
+ ```bash
25
+ git clone https://github.com/syd168/Termora.git
26
+ cd Termora
27
+ python3 -m venv .venv
28
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
29
+ pip install -e .
30
+ termora
31
+ ```
32
+
33
+ Use a **dedicated venv**. Mixing conda `pyside6` with pip `PySide6-Addons` leads to
34
+ `libshiboken6.abi3.so` import errors.
35
+
36
+ ### Platform notes
37
+
38
+ | Capability | Linux | macOS | Windows |
39
+ |------------|:-----:|:-----:|:-------:|
40
+ | Serial I/O, sessions, macros, plugins | ✓ | ✓ | ✓ |
41
+ | CAN (virtual / PCAN / Kvaser / Vector / SLCAN, …) | ✓ | ✓* | ✓* |
42
+ | Native SocketCAN | ✓ | — | — |
43
+ | X/Y/Zmodem (`sz` / lrzsz) | ✓ | ✓* | — |
44
+
45
+ \* Needs the matching driver or Homebrew tool. Use the `virtual` CAN backend without hardware.
46
+
47
+ - **Linux**: `sudo usermod -aG dialout $USER` then log in again.
48
+ - **macOS**: ports look like `/dev/cu.*`. Zmodem: `brew install lrzsz`.
49
+ - **Windows**: `COMx` in Device Manager. No X/Y/Zmodem (`sz` + POSIX redirection).
50
+
51
+ ---
52
+
53
+ ## Usage
54
+
55
+ ```bash
56
+ termora # GUI
57
+ termora -s Default # named session
58
+ python -m cutecom # same entry point
59
+ python run.py # from a source checkout
60
+ ```
61
+
62
+ Headless serial (no window; RX on stdout):
63
+
64
+ ```bash
65
+ termora --headless --port /dev/ttyUSB0 --baud 115200 --send "AT" --timeout 2
66
+ ```
67
+
68
+ | Flag | Meaning |
69
+ |------|---------|
70
+ | `-s`, `--session` | Open a named session |
71
+ | `--port` | Serial device |
72
+ | `--baud` | Baud rate (default `115200`) |
73
+ | `--send` | String to write after open |
74
+ | `--send-file` | File bytes to write after open |
75
+ | `--line-end` | `none` / `lf` / `cr` / `crlf` (headless `--send`) |
76
+ | `--timeout` | Headless read duration in seconds |
77
+ | `--headless` | No GUI; requires `--port` |
78
+
79
+ Logs: repo runs write `logs/` in the project; a pip-installed run uses the OS app-data directory.
80
+
81
+ ---
82
+
83
+ ## Interface
84
+
85
+ Connection settings on the left, a large output pane in the middle, command history above, input bar at the bottom.
86
+
87
+ - **View → Skin**: Light / Dark / Nord / Terminal green
88
+ - **View → Language**: English / 简体中文
89
+ - **View → Connection settings** (`Alt+S`): reopen the sidebar
90
+
91
+ ---
92
+
93
+ ## Features
94
+
95
+ Aligned with classic CuteCom:
96
+
97
+ - Open/close, baud, data bits, parity, stop bits, flow control, RTS/DTR
98
+ - Read-write / read-only / write-only, auto-reconnect
99
+ - Line endings LF / CR / CRLF / none / Hex, character delay
100
+ - Command history, completion, Ctrl control characters
101
+ - Text / HEX display, control characters, timestamps, find (`F3`)
102
+ - Session manager; disk logs (per session and window)
103
+ - Send file as text or script; X/Y/Zmodem on Linux/macOS (`sz`)
104
+ - Plugins: macro packs (JSON, hand-editable; legacy `.tmf` supported), UDP/TCP proxy, byte counter, Modbus assistant
105
+
106
+ Termora extras:
107
+
108
+ - Skins and language switch
109
+ - Local echo (TX in green)
110
+ - Leave port settings unchanged on open
111
+ - Break, repeat send
112
+ - Freeze scroll / export output (`Ctrl+E`)
113
+ - Live RX/TX B/s, recent devices
114
+ - CRC / checksum tools, protocol pane (NMEA / AT / Modbus)
115
+ - CAN analyzer (multiple backends, DBC, sequenced send)
116
+ - Widescreen sidebar layout
117
+ - Multiple windows (each with its own port and log file)
118
+
119
+ ### Macro packs
120
+
121
+ JSON files. Built-in examples live in the package (`cutecom/resources/macros/`). When you run from the repo, user copies go under `config/macros/`.
122
+
123
+ ```json
124
+ {
125
+ "format": "cutecom-macros",
126
+ "version": 2,
127
+ "name": { "en": "ESP32 / ESP-AT", "zh_CN": "ESP32 / ESP-AT" },
128
+ "macros": [
129
+ { "name": { "en": "Reset", "zh_CN": "复位" }, "command": "AT+RST" }
130
+ ]
131
+ }
132
+ ```
133
+
134
+ Escapes in commands: `\n` `\r` `\t` `\0` `\xFF`. In JSON write `\\`.
135
+
136
+ ---
137
+
138
+ ## 中文
139
+
140
+ ```bash
141
+ pip install termora
142
+ termora
143
+ ```
144
+
145
+ 从源码:
146
+
147
+ ```bash
148
+ git clone https://github.com/syd168/Termora.git
149
+ cd Termora
150
+ python3 -m venv .venv
151
+ source .venv/bin/activate
152
+ pip install -e .
153
+ termora
154
+ ```
155
+
156
+ 请使用项目自己的虚拟环境。不要用混装了 conda `pyside6` 与 pip `PySide6-Addons` 的解释器,否则会报找不到 `libshiboken6.abi3.so`。
157
+
158
+ 无界面发串口:
159
+
160
+ ```bash
161
+ termora --headless --port /dev/ttyUSB0 --baud 115200 --send "AT" --timeout 2
162
+ ```
163
+
164
+ Linux 串口权限:`sudo usermod -aG dialout $USER`,重新登录后生效。开发态日志在项目 `logs/`;`pip install` 后使用系统 AppData / Application Support。
165
+
166
+ ---
167
+
168
+ ## License
169
+
170
+ [MIT](LICENSE). Inspired by [CuteCom](https://gitlab.com/cutecom/cutecom); this is an independent Python implementation.
@@ -0,0 +1,72 @@
1
+ [build-system]
2
+ requires = ["setuptools>=69", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "termora"
7
+ version = "0.80.0"
8
+ description = "Desktop workbench for serial, CAN, and protocol debugging"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ authors = [{ name = "sunyd168", email = "sunyd168@gmail.com" }]
13
+ keywords = [
14
+ "serial",
15
+ "uart",
16
+ "can",
17
+ "modbus",
18
+ "terminal",
19
+ "pyside6",
20
+ "protocol",
21
+ ]
22
+ classifiers = [
23
+ "Development Status :: 4 - Beta",
24
+ "Environment :: X11 Applications :: Qt",
25
+ "Intended Audience :: Developers",
26
+ "Intended Audience :: End Users/Desktop",
27
+ "Operating System :: OS Independent",
28
+ "Programming Language :: Python :: 3",
29
+ "Programming Language :: Python :: 3.10",
30
+ "Programming Language :: Python :: 3.11",
31
+ "Programming Language :: Python :: 3.12",
32
+ "Programming Language :: Python :: 3.13",
33
+ "Topic :: System :: Hardware",
34
+ "Topic :: Terminals :: Serial",
35
+ ]
36
+ dependencies = [
37
+ "PySide6>=6.6",
38
+ "PySide6-Addons>=6.6",
39
+ "python-can>=4.3",
40
+ "cantools>=39.0",
41
+ ]
42
+
43
+ [project.urls]
44
+ Homepage = "https://github.com/syd168/Termora"
45
+ Repository = "https://github.com/syd168/Termora"
46
+ Issues = "https://github.com/syd168/Termora/issues"
47
+
48
+ [project.scripts]
49
+ termora = "cutecom.app:main"
50
+ cutecom = "cutecom.app:main"
51
+
52
+ [tool.setuptools]
53
+ package-dir = { cutecom = "src" }
54
+ packages = [
55
+ "cutecom",
56
+ "cutecom.core",
57
+ "cutecom.ui",
58
+ "cutecom.plugins",
59
+ "cutecom.can",
60
+ "cutecom.resources",
61
+ "cutecom.resources.i18n",
62
+ "cutecom.resources.icons",
63
+ "cutecom.resources.macros",
64
+ "cutecom.resources.themes",
65
+ ]
66
+
67
+ [tool.setuptools.package-data]
68
+ cutecom = [
69
+ "resources/**/*.json",
70
+ "resources/**/*.qss",
71
+ "resources/**/*.svg",
72
+ ]
@@ -0,0 +1,5 @@
1
+ # Install from pyproject.toml when possible: pip install -e .
2
+ PySide6>=6.6
3
+ PySide6-Addons>=6.6
4
+ python-can>=4.3
5
+ cantools>=39.0
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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"
@@ -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())
@@ -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
+ ]