cj-tauri 2.0.0 → 2.1.1
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.
- package/README.md +206 -139
- package/bin/cj-tauri.js +287 -287
- package/cjpm.toml +63 -52
- package/cli/cjpm.toml +22 -22
- package/cli/src/doctor.cj +308 -306
- package/cli/src/main.cj +129 -129
- package/cli/src/manifest.cj +643 -558
- package/cli/src/manifest_test.cj +87 -0
- package/cli/src/project.cj +770 -770
- package/cli/src/resolve.cj +348 -348
- package/cli/src/scaffold.cj +369 -369
- package/cli/src/sync.cj +638 -526
- package/cli/src/util.cj +168 -168
- package/cli/templates/app/README.md +51 -48
- package/cli/templates/app/assets/capabilities/default.json +7 -7
- package/cli/templates/app/assets/ui/index.html +120 -118
- package/cli/templates/app/cj-tauri.toml +32 -22
- package/cli/templates/app/cjpm.toml +34 -34
- package/cli/templates/app/src/main.cj +101 -90
- package/cli/templates/app-react/README.md +56 -56
- package/cli/templates/app-react/assets/capabilities/default.json +7 -7
- package/cli/templates/app-react/assets/ui/index.html +25 -25
- package/cli/templates/app-react/assets/ui/package.json +19 -19
- package/cli/templates/app-react/assets/ui/src/App.css +67 -67
- package/cli/templates/app-react/assets/ui/src/App.jsx +124 -124
- package/cli/templates/app-react/assets/ui/src/main.jsx +6 -6
- package/cli/templates/app-react/assets/ui/vite.config.js +24 -24
- package/cli/templates/app-react/cj-tauri.toml +33 -23
- package/cli/templates/app-react/cjpm.toml +34 -34
- package/cli/templates/app-react/src/main.cj +91 -91
- package/cli/templates/app-vue/README.md +56 -56
- package/cli/templates/app-vue/assets/capabilities/default.json +7 -7
- package/cli/templates/app-vue/assets/ui/index.html +25 -25
- package/cli/templates/app-vue/assets/ui/package.json +18 -18
- package/cli/templates/app-vue/assets/ui/src/App.vue +176 -176
- package/cli/templates/app-vue/assets/ui/src/main.js +4 -4
- package/cli/templates/app-vue/assets/ui/vite.config.js +24 -24
- package/cli/templates/app-vue/cj-tauri.toml +33 -23
- package/cli/templates/app-vue/cjpm.toml +34 -34
- package/cli/templates/app-vue/src/main.cj +91 -91
- package/cli/templates/ohos-skeleton/AppScope/app.json5 +13 -13
- package/cli/templates/ohos-skeleton/AppScope/resources/base/element/string.json +8 -8
- package/cli/templates/ohos-skeleton/AppScope/resources/base/media/layered_image.json +6 -6
- package/cli/templates/ohos-skeleton/README.md +84 -79
- package/cli/templates/ohos-skeleton/build-hap.sh +15 -0
- package/cli/templates/ohos-skeleton/build-profile.json5 +46 -46
- package/cli/templates/ohos-skeleton/entry/build-profile.json5 +26 -26
- package/cli/templates/ohos-skeleton/entry/cjpm.toml +51 -43
- package/cli/templates/ohos-skeleton/entry/hvigorfile.ts +6 -6
- package/cli/templates/ohos-skeleton/entry/oh-package.json5 +9 -9
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/ability_stage.cj +17 -17
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/app_host.cj +94 -94
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/dialog_host.cj +217 -0
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/index.cj +527 -167
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/main_ability.cj +139 -139
- package/cli/templates/ohos-skeleton/entry/src/main/module.json5 +57 -49
- package/cli/templates/ohos-skeleton/entry/src/main/resources/base/element/color.json +8 -8
- package/cli/templates/ohos-skeleton/entry/src/main/resources/base/element/string.json +16 -16
- package/cli/templates/ohos-skeleton/entry/src/main/resources/base/media/layered_image.json +6 -6
- package/cli/templates/ohos-skeleton/entry/src/main/resources/base/profile/main_pages.json +2 -2
- package/cli/templates/ohos-skeleton/entry/src/main/resources/rawfile/capabilities.json +6 -6
- package/cli/templates/ohos-skeleton/entry/src/main/resources/rawfile/index.html +92 -92
- package/cli/templates/ohos-skeleton/hvigor/hvigor-config.json5 +5 -5
- package/cli/templates/ohos-skeleton/hvigorfile.ts +6 -6
- package/cli/templates/ohos-skeleton/oh-package.json5 +10 -10
- package/native/build_win.bat +62 -62
- package/native/core/bridge_core.c +1681 -1626
- package/native/core/bridge_core.h +675 -618
- package/native/core/bridge_js.h +108 -108
- package/native/platforms/harmonyos/README.md +115 -6
- package/native/platforms/linux/bridge_linux.c +2787 -2485
- package/native/platforms/windows/bridge_win.c +3745 -3248
- package/native/tests/gtk_threading_probe.c +143 -143
- package/native/tests/test_bridge_core.c +1339 -1228
- package/package.json +53 -53
- package/src/api_system.cj +67 -67
- package/src/app.cj +335 -969
- package/src/app_events.cj +166 -0
- package/src/app_host_ops.cj +287 -0
- package/src/app_run.cj +283 -0
- package/src/app_spec.cj +76 -76
- package/src/arkweb_menu.cj +216 -0
- package/src/arkweb_script.cj +142 -142
- package/src/capability.cj +409 -409
- package/src/clipboard_bridge.cj +178 -0
- package/src/dialog_spec.cj +79 -0
- package/src/dragdrop.cj +26 -26
- package/src/embedded_assets.cj +98 -98
- package/src/host.cj +752 -607
- package/src/host_arkweb.cj +924 -778
- package/src/host_webkit.cj +663 -570
- package/src/host_webview2.cj +663 -570
- package/src/hotkey.cj +66 -66
- package/src/ipc_hub.cj +401 -337
- package/src/ipc_message.cj +286 -286
- package/src/launch.cj +62 -62
- package/src/logging.cj +127 -127
- package/src/menu.cj +197 -197
- package/src/platform/platform_app_context.cj +77 -77
- package/src/platform/platform_assets.cj +33 -33
- package/src/platform/platform_discover.cj +176 -176
- package/src/platform/platform_env.cj +29 -29
- package/src/platform/platform_feature.cj +31 -31
- package/src/platform/platform_page_source.cj +87 -87
- package/src/platform/platform_target_info.cj +32 -32
- package/src/platform_host_provider.cj +87 -87
- package/src/plugin.cj +333 -333
- package/src/plugins/clipboard/plugin_clipboard.cj +152 -152
- package/src/plugins/dialog/plugin_dialog.cj +209 -209
- package/src/plugins/fs/plugin_fs.cj +105 -1
- package/src/plugins/http/http_backend.cj +131 -0
- package/src/plugins/http/http_desktop.cj +195 -0
- package/src/plugins/http/http_ohos.cj +204 -0
- package/src/plugins/http/plugin_http.cj +310 -459
- package/src/plugins/log/plugin_log.cj +105 -105
- package/src/plugins/menu/plugin_menu.cj +158 -158
- package/src/plugins/notification/plugin_notification.cj +154 -154
- package/src/plugins/serial/plugin_serial.cj +458 -454
- package/src/plugins/serial/serial_bridge.cj +194 -194
- package/src/plugins/serial/serial_manager_ohos.cj +92 -0
- package/src/plugins/serial/serial_ohos.cj +529 -0
- package/src/plugins/shell/plugin_shell.cj +258 -258
- package/src/plugins/sqlite/plugin_sqlite.cj +705 -710
- package/src/plugins/sqlite/sqlite_ffi.cj +206 -211
- package/src/plugins/ws/plugin_ws.cj +488 -470
- package/src/process_hidden.cj +174 -174
- package/src/scope.cj +391 -391
- package/src/shell_event.cj +69 -69
- package/src/tests/app_spec_test.cj +130 -127
- package/src/tests/capability_test.cj +243 -243
- package/src/tests/dialog_spec_test.cj +73 -0
- package/src/tests/fake_host.cj +201 -201
- package/src/tests/ipc_hub_test.cj +563 -487
- package/src/tests/logging_test.cj +62 -62
- package/src/tests/platform_contract_test.cj +264 -251
- package/src/tests/plugin_clipboard_test.cj +222 -222
- package/src/tests/plugin_dialog_test.cj +237 -237
- package/src/tests/plugin_fs_test.cj +207 -0
- package/src/tests/plugin_http_test.cj +124 -124
- package/src/tests/plugin_notification_test.cj +205 -205
- package/src/tests/plugin_serial_test.cj +48 -0
- package/src/tests/plugin_test.cj +605 -585
- package/src/tests/plugin_ws_test.cj +40 -40
- package/src/tests/process_hidden_test.cj +129 -129
- package/src/tests/scope_test.cj +350 -350
- package/src/tests/system_host_test.cj +99 -81
- package/src/tests/urlutil_test.cj +53 -53
- package/src/tests/version_test.cj +75 -75
- package/src/tests/window_registry_test.cj +123 -123
- package/src/tray.cj +90 -90
- package/src/urlutil.cj +159 -159
- package/src/version.cj +44 -44
- package/src/window.cj +51 -51
- package/src/window_registry.cj +116 -116
- package/prebuilt/win32-x64/cj-tauri.exe +0 -0
- package/src/plugins/serial/serial_ohos_stub.cj +0 -61
- package/src/plugins/sqlite/sqlite_ohos_stub.cj +0 -91
|
@@ -1,194 +1,194 @@
|
|
|
1
|
-
package cjTauri.plugins.serial
|
|
2
|
-
|
|
3
|
-
// 桌面两端包装函数用(ohos
|
|
4
|
-
// foreign 声明不带门禁:ohos 侧无引用即不要求符号,不产生链接错误
|
|
5
|
-
@When[env != "ohos"]
|
|
6
|
-
import std.collection.*
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* 串口桥(plugin_serial 的 FFI 面):C 桥 `cj_bridge_serial_*` 的声明与薄包装。
|
|
10
|
-
*
|
|
11
|
-
* 为什么这里**不带 @When**:两平台的导出同名同签名(AGENTS §2 的硬约束),平台差异全在
|
|
12
|
-
* `native/bridge_*.c` 里——Linux 是 termios,Windows 侧接口已留、实现待补(返回可读的
|
|
13
|
-
* 「暂不支持」,不是静默失败)。所以仓颉侧一份声明就能同时编两个平台,上层不需要平台分支。
|
|
14
|
-
*
|
|
15
|
-
* 参数约定(与 native/bridge_core.h 逐字一致):parity 0=无 1=奇 2=偶,stopBits 1|2,
|
|
16
|
-
* dataBits 5..8。**路径白名单与参数校验都在 C 侧 core**——页面可控的字符串绝不能只在仓颉侧挡。
|
|
17
|
-
*
|
|
18
|
-
* 这组导出**不收宿主句柄**:串口不是宿主能力,不必先建窗口才能用(无头进程里照样能开)。
|
|
19
|
-
*/
|
|
20
|
-
@C
|
|
21
|
-
foreign func cj_bridge_serial_open(path: CString, baud: Int32, dataBits: Int32, parity: Int32,
|
|
22
|
-
stopBits: Int32): Int64
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* 读:最多 len 字节、最多等 timeoutMs 毫秒(0 = 立即返回)。返回实际字节数(0 = 超时无数据)
|
|
26
|
-
*/
|
|
27
|
-
@C
|
|
28
|
-
foreign func cj_bridge_serial_read(h: Int64, buf: CPointer<UInt8>, len: Int32, timeoutMs: Int32): Int32
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* 写:在 timeoutMs 预算内尽量写完;返回实际写入字节数(可能小于 len)
|
|
32
|
-
*/
|
|
33
|
-
@C
|
|
34
|
-
foreign func cj_bridge_serial_write(h: Int64, buf: CPointer<UInt8>, len: Int32,
|
|
35
|
-
timeoutMs: Int32): Int32
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 关闭并释放句柄(幂等:重复关同一句柄返回 -4)
|
|
39
|
-
*/
|
|
40
|
-
@C
|
|
41
|
-
foreign func cj_bridge_serial_close(h: Int64): Int32
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* 最近一次失败的明细(UTF-8,C 侧**线程局部**:命令各自跑在 worker 线程上,
|
|
45
|
-
* 静态单槽会被并发调用互相覆盖)
|
|
46
|
-
*/
|
|
47
|
-
@C
|
|
48
|
-
foreign func cj_bridge_serial_last_error(): CString
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 枚举本机串口(serial:list 的平台层):一行一个名字写进 buf('\n' 分隔),
|
|
52
|
-
* 返回条数(0 = 没有串口,不是错误);-1 参数非法,-4 本平台未实现。
|
|
53
|
-
* 两平台导出同名同签名:Windows 走 QueryDosDeviceW,Linux 返回 -4(list 在 Linux 走 /dev 扫描)。
|
|
54
|
-
*/
|
|
55
|
-
@C
|
|
56
|
-
foreign func cj_bridge_serial_list(buf: CPointer<UInt8>, bufLen: Int32): Int32
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* 打开串口:成功返回 >0 句柄,失败返回负码(-1 参数/白名单、-2 句柄表满、-3 平台打不开)。
|
|
60
|
-
* 失败明细用 serialLastError() 取(C 侧线程局部,同一线程内取才有意义)。
|
|
61
|
-
*/
|
|
62
|
-
@When[env != "ohos"]
|
|
63
|
-
public func serialOpen(path: String, baud: Int32, dataBits: Int32, parity: Int32,
|
|
64
|
-
stopBits: Int32): Int64 {
|
|
65
|
-
var h: Int64 = -1
|
|
66
|
-
unsafe {
|
|
67
|
-
let cpath = LibC.mallocCString(path)
|
|
68
|
-
h = cj_bridge_serial_open(cpath, baud, dataBits, parity, stopBits)
|
|
69
|
-
// C 侧(core)当场把路径拷进自己的句柄槽,不持有我们的指针——这里立刻归还,
|
|
70
|
-
// 免得每次打开漏一小块(跨 FFI 的内存一律「谁分配谁释放」)
|
|
71
|
-
LibC.free(cpath)
|
|
72
|
-
}
|
|
73
|
-
return h
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* C 侧最近一次失败的明细;取不到时返回空串(调用方自行降级成数字码)
|
|
78
|
-
*/
|
|
79
|
-
@When[env != "ohos"]
|
|
80
|
-
public func serialLastError(): String {
|
|
81
|
-
unsafe {
|
|
82
|
-
return cj_bridge_serial_last_error().toString()
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* C 桥枚举本机串口:Windows 下走 QueryDosDeviceW(返回 COM 名字列表);
|
|
88
|
-
* Linux 返回 None(-4 未实现,serial:list 在 Linux 走 /dev 扫描)。C 侧异常时也回 None。
|
|
89
|
-
*/
|
|
90
|
-
@When[env != "ohos"]
|
|
91
|
-
public func serialListC(): Option<ArrayList<String>> {
|
|
92
|
-
let cap: Int32 = 8192
|
|
93
|
-
let buf = LibC.malloc<UInt8>(count: Int64(cap))
|
|
94
|
-
var n: Int32 = 0
|
|
95
|
-
unsafe {
|
|
96
|
-
n = cj_bridge_serial_list(buf, cap)
|
|
97
|
-
}
|
|
98
|
-
if (n < 0) {
|
|
99
|
-
unsafe {
|
|
100
|
-
LibC.free(buf)
|
|
101
|
-
}
|
|
102
|
-
return None
|
|
103
|
-
}
|
|
104
|
-
// 返回值是「条数」不是字节数;真正的文本以 '\0' 结尾,按终止符取整段再按 '\n' 切开
|
|
105
|
-
var len: Int64 = 0
|
|
106
|
-
unsafe {
|
|
107
|
-
while (len < Int64(cap) && buf.read(len) != 0) {
|
|
108
|
-
len++
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
let bytes = Array<UInt8>(len, repeat: 0)
|
|
112
|
-
unsafe {
|
|
113
|
-
for (i in 0..len) {
|
|
114
|
-
bytes[i] = buf.read(i)
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
unsafe {
|
|
118
|
-
LibC.free(buf)
|
|
119
|
-
}
|
|
120
|
-
let out = ArrayList<String>()
|
|
121
|
-
let text = String.fromUtf8(bytes)
|
|
122
|
-
if (text != "") {
|
|
123
|
-
for (line in text.split('\n')) {
|
|
124
|
-
if (line != "") {
|
|
125
|
-
out.add(line)
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return Some(out)
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* 读:最多 maxBytes 字节。返回实际读到的字节(空数组 = 超时无数据)。
|
|
134
|
-
* 缓冲在这里现分配现释放——每次读的用量都很小,不值得为它引一层对象池。
|
|
135
|
-
*/
|
|
136
|
-
@When[env != "ohos"]
|
|
137
|
-
public func serialRead(h: Int64, maxBytes: Int32, timeoutMs: Int32): Array<UInt8> {
|
|
138
|
-
let cap = Int64(maxBytes)
|
|
139
|
-
let buf = LibC.malloc<UInt8>(count: cap)
|
|
140
|
-
var n: Int32 = 0
|
|
141
|
-
unsafe {
|
|
142
|
-
n = cj_bridge_serial_read(h, buf, maxBytes, timeoutMs)
|
|
143
|
-
}
|
|
144
|
-
var out = Array<UInt8>(0, repeat: 0)
|
|
145
|
-
if (n > 0) {
|
|
146
|
-
out = Array<UInt8>(Int64(n), repeat: 0)
|
|
147
|
-
unsafe {
|
|
148
|
-
for (i in 0..Int64(n)) {
|
|
149
|
-
out[i] = buf.read(i)
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
unsafe {
|
|
154
|
-
LibC.free(buf)
|
|
155
|
-
}
|
|
156
|
-
return out
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* 写:在 timeoutMs 预算内尽量写完,返回实际写入字节数(可能 < data.size;0 = 一个字节都没出去)
|
|
161
|
-
*/
|
|
162
|
-
@When[env != "ohos"]
|
|
163
|
-
public func serialWrite(h: Int64, data: Array<UInt8>, timeoutMs: Int32): Int32 {
|
|
164
|
-
if (data.size == 0) {
|
|
165
|
-
return 0
|
|
166
|
-
}
|
|
167
|
-
let n = data.size
|
|
168
|
-
let buf = LibC.malloc<UInt8>(count: n)
|
|
169
|
-
unsafe {
|
|
170
|
-
for (i in 0..n) {
|
|
171
|
-
buf.write(i, data[i])
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
var w: Int32 = 0
|
|
175
|
-
unsafe {
|
|
176
|
-
w = cj_bridge_serial_write(h, buf, Int32(n), timeoutMs)
|
|
177
|
-
}
|
|
178
|
-
unsafe {
|
|
179
|
-
LibC.free(buf)
|
|
180
|
-
}
|
|
181
|
-
return w
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* 关句柄:0 = 成功,负码 = 失败(重复关返回 -4)
|
|
186
|
-
*/
|
|
187
|
-
@When[env != "ohos"]
|
|
188
|
-
public func serialClose(h: Int64): Int32 {
|
|
189
|
-
var rc: Int32 = 0
|
|
190
|
-
unsafe {
|
|
191
|
-
rc = cj_bridge_serial_close(h)
|
|
192
|
-
}
|
|
193
|
-
return rc
|
|
194
|
-
}
|
|
1
|
+
package cjTauri.plugins.serial
|
|
2
|
+
|
|
3
|
+
// 桌面两端包装函数用(ohos 走 NDK FFI 直连,实现在 serial_ohos.cj,批次 4);
|
|
4
|
+
// foreign 声明不带门禁:ohos 侧无引用即不要求符号,不产生链接错误
|
|
5
|
+
@When[env != "ohos"]
|
|
6
|
+
import std.collection.*
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 串口桥(plugin_serial 的 FFI 面):C 桥 `cj_bridge_serial_*` 的声明与薄包装。
|
|
10
|
+
*
|
|
11
|
+
* 为什么这里**不带 @When**:两平台的导出同名同签名(AGENTS §2 的硬约束),平台差异全在
|
|
12
|
+
* `native/bridge_*.c` 里——Linux 是 termios,Windows 侧接口已留、实现待补(返回可读的
|
|
13
|
+
* 「暂不支持」,不是静默失败)。所以仓颉侧一份声明就能同时编两个平台,上层不需要平台分支。
|
|
14
|
+
*
|
|
15
|
+
* 参数约定(与 native/bridge_core.h 逐字一致):parity 0=无 1=奇 2=偶,stopBits 1|2,
|
|
16
|
+
* dataBits 5..8。**路径白名单与参数校验都在 C 侧 core**——页面可控的字符串绝不能只在仓颉侧挡。
|
|
17
|
+
*
|
|
18
|
+
* 这组导出**不收宿主句柄**:串口不是宿主能力,不必先建窗口才能用(无头进程里照样能开)。
|
|
19
|
+
*/
|
|
20
|
+
@C
|
|
21
|
+
foreign func cj_bridge_serial_open(path: CString, baud: Int32, dataBits: Int32, parity: Int32,
|
|
22
|
+
stopBits: Int32): Int64
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 读:最多 len 字节、最多等 timeoutMs 毫秒(0 = 立即返回)。返回实际字节数(0 = 超时无数据)
|
|
26
|
+
*/
|
|
27
|
+
@C
|
|
28
|
+
foreign func cj_bridge_serial_read(h: Int64, buf: CPointer<UInt8>, len: Int32, timeoutMs: Int32): Int32
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 写:在 timeoutMs 预算内尽量写完;返回实际写入字节数(可能小于 len)
|
|
32
|
+
*/
|
|
33
|
+
@C
|
|
34
|
+
foreign func cj_bridge_serial_write(h: Int64, buf: CPointer<UInt8>, len: Int32,
|
|
35
|
+
timeoutMs: Int32): Int32
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 关闭并释放句柄(幂等:重复关同一句柄返回 -4)
|
|
39
|
+
*/
|
|
40
|
+
@C
|
|
41
|
+
foreign func cj_bridge_serial_close(h: Int64): Int32
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 最近一次失败的明细(UTF-8,C 侧**线程局部**:命令各自跑在 worker 线程上,
|
|
45
|
+
* 静态单槽会被并发调用互相覆盖)
|
|
46
|
+
*/
|
|
47
|
+
@C
|
|
48
|
+
foreign func cj_bridge_serial_last_error(): CString
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 枚举本机串口(serial:list 的平台层):一行一个名字写进 buf('\n' 分隔),
|
|
52
|
+
* 返回条数(0 = 没有串口,不是错误);-1 参数非法,-4 本平台未实现。
|
|
53
|
+
* 两平台导出同名同签名:Windows 走 QueryDosDeviceW,Linux 返回 -4(list 在 Linux 走 /dev 扫描)。
|
|
54
|
+
*/
|
|
55
|
+
@C
|
|
56
|
+
foreign func cj_bridge_serial_list(buf: CPointer<UInt8>, bufLen: Int32): Int32
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 打开串口:成功返回 >0 句柄,失败返回负码(-1 参数/白名单、-2 句柄表满、-3 平台打不开)。
|
|
60
|
+
* 失败明细用 serialLastError() 取(C 侧线程局部,同一线程内取才有意义)。
|
|
61
|
+
*/
|
|
62
|
+
@When[env != "ohos"]
|
|
63
|
+
public func serialOpen(path: String, baud: Int32, dataBits: Int32, parity: Int32,
|
|
64
|
+
stopBits: Int32): Int64 {
|
|
65
|
+
var h: Int64 = -1
|
|
66
|
+
unsafe {
|
|
67
|
+
let cpath = LibC.mallocCString(path)
|
|
68
|
+
h = cj_bridge_serial_open(cpath, baud, dataBits, parity, stopBits)
|
|
69
|
+
// C 侧(core)当场把路径拷进自己的句柄槽,不持有我们的指针——这里立刻归还,
|
|
70
|
+
// 免得每次打开漏一小块(跨 FFI 的内存一律「谁分配谁释放」)
|
|
71
|
+
LibC.free(cpath)
|
|
72
|
+
}
|
|
73
|
+
return h
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* C 侧最近一次失败的明细;取不到时返回空串(调用方自行降级成数字码)
|
|
78
|
+
*/
|
|
79
|
+
@When[env != "ohos"]
|
|
80
|
+
public func serialLastError(): String {
|
|
81
|
+
unsafe {
|
|
82
|
+
return cj_bridge_serial_last_error().toString()
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* C 桥枚举本机串口:Windows 下走 QueryDosDeviceW(返回 COM 名字列表);
|
|
88
|
+
* Linux 返回 None(-4 未实现,serial:list 在 Linux 走 /dev 扫描)。C 侧异常时也回 None。
|
|
89
|
+
*/
|
|
90
|
+
@When[env != "ohos"]
|
|
91
|
+
public func serialListC(): Option<ArrayList<String>> {
|
|
92
|
+
let cap: Int32 = 8192
|
|
93
|
+
let buf = LibC.malloc<UInt8>(count: Int64(cap))
|
|
94
|
+
var n: Int32 = 0
|
|
95
|
+
unsafe {
|
|
96
|
+
n = cj_bridge_serial_list(buf, cap)
|
|
97
|
+
}
|
|
98
|
+
if (n < 0) {
|
|
99
|
+
unsafe {
|
|
100
|
+
LibC.free(buf)
|
|
101
|
+
}
|
|
102
|
+
return None
|
|
103
|
+
}
|
|
104
|
+
// 返回值是「条数」不是字节数;真正的文本以 '\0' 结尾,按终止符取整段再按 '\n' 切开
|
|
105
|
+
var len: Int64 = 0
|
|
106
|
+
unsafe {
|
|
107
|
+
while (len < Int64(cap) && buf.read(len) != 0) {
|
|
108
|
+
len++
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
let bytes = Array<UInt8>(len, repeat: 0)
|
|
112
|
+
unsafe {
|
|
113
|
+
for (i in 0..len) {
|
|
114
|
+
bytes[i] = buf.read(i)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
unsafe {
|
|
118
|
+
LibC.free(buf)
|
|
119
|
+
}
|
|
120
|
+
let out = ArrayList<String>()
|
|
121
|
+
let text = String.fromUtf8(bytes)
|
|
122
|
+
if (text != "") {
|
|
123
|
+
for (line in text.split('\n')) {
|
|
124
|
+
if (line != "") {
|
|
125
|
+
out.add(line)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return Some(out)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* 读:最多 maxBytes 字节。返回实际读到的字节(空数组 = 超时无数据)。
|
|
134
|
+
* 缓冲在这里现分配现释放——每次读的用量都很小,不值得为它引一层对象池。
|
|
135
|
+
*/
|
|
136
|
+
@When[env != "ohos"]
|
|
137
|
+
public func serialRead(h: Int64, maxBytes: Int32, timeoutMs: Int32): Array<UInt8> {
|
|
138
|
+
let cap = Int64(maxBytes)
|
|
139
|
+
let buf = LibC.malloc<UInt8>(count: cap)
|
|
140
|
+
var n: Int32 = 0
|
|
141
|
+
unsafe {
|
|
142
|
+
n = cj_bridge_serial_read(h, buf, maxBytes, timeoutMs)
|
|
143
|
+
}
|
|
144
|
+
var out = Array<UInt8>(0, repeat: 0)
|
|
145
|
+
if (n > 0) {
|
|
146
|
+
out = Array<UInt8>(Int64(n), repeat: 0)
|
|
147
|
+
unsafe {
|
|
148
|
+
for (i in 0..Int64(n)) {
|
|
149
|
+
out[i] = buf.read(i)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
unsafe {
|
|
154
|
+
LibC.free(buf)
|
|
155
|
+
}
|
|
156
|
+
return out
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 写:在 timeoutMs 预算内尽量写完,返回实际写入字节数(可能 < data.size;0 = 一个字节都没出去)
|
|
161
|
+
*/
|
|
162
|
+
@When[env != "ohos"]
|
|
163
|
+
public func serialWrite(h: Int64, data: Array<UInt8>, timeoutMs: Int32): Int32 {
|
|
164
|
+
if (data.size == 0) {
|
|
165
|
+
return 0
|
|
166
|
+
}
|
|
167
|
+
let n = data.size
|
|
168
|
+
let buf = LibC.malloc<UInt8>(count: n)
|
|
169
|
+
unsafe {
|
|
170
|
+
for (i in 0..n) {
|
|
171
|
+
buf.write(i, data[i])
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
var w: Int32 = 0
|
|
175
|
+
unsafe {
|
|
176
|
+
w = cj_bridge_serial_write(h, buf, Int32(n), timeoutMs)
|
|
177
|
+
}
|
|
178
|
+
unsafe {
|
|
179
|
+
LibC.free(buf)
|
|
180
|
+
}
|
|
181
|
+
return w
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 关句柄:0 = 成功,负码 = 失败(重复关返回 -4)
|
|
186
|
+
*/
|
|
187
|
+
@When[env != "ohos"]
|
|
188
|
+
public func serialClose(h: Int64): Int32 {
|
|
189
|
+
var rc: Int32 = 0
|
|
190
|
+
unsafe {
|
|
191
|
+
rc = cj_bridge_serial_close(h)
|
|
192
|
+
}
|
|
193
|
+
return rc
|
|
194
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
package cjTauri.plugins.serial
|
|
2
|
+
|
|
3
|
+
// 桌面侧看不到这个文件里的 `@When[env == "ohos"]` 函数体,`ArrayList` 就成「未使用」——
|
|
4
|
+
// 按 AGENTS §4「跨平台文件别按单平台警告去清 import」,给 import 加同款门禁,而不是删掉它。
|
|
5
|
+
@When[env == "ohos"]
|
|
6
|
+
import std.collection.*
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 鸿蒙侧 USB 串口后端:**如实降级,不做互操作**
|
|
10
|
+
*
|
|
11
|
+
* ## 为什么这里是空的(2026-10-24 真机 A/B 实测,别再徒手重试)
|
|
12
|
+
*
|
|
13
|
+
* 原本的落法是「仓颉侧经 `ohos.ark_interop` 调 `@ohos.usbManager.serial`」,三组对照把它否掉了:
|
|
14
|
+
*
|
|
15
|
+
* | 产物 | 内容 | 真机结果 |
|
|
16
|
+
* | --- | --- | --- |
|
|
17
|
+
* | 有互操作、真去用 | `spawn` 出 owner 线程建 `JSRuntime()` | 启动即 `signal:6`(SIGABRT),日志停在 `startApp begin`,`initScripts` 都没打印 |
|
|
18
|
+
* | 只有互操作、从不执行 | 同名符号全留,owner 线程刻意不起 | **应用正常启动**,页面跑完自检(`pidof` 有、`page end label=main`) |
|
|
19
|
+
* | 互操作整段摘掉 | 本文件上一版的空桩 | 同样正常启动 |
|
|
20
|
+
*
|
|
21
|
+
* 第三组证明「链接 `libohos.ark_interop.so` 本身无害」(`NEEDED` 里两个库、4 个 JSRuntime 符号都在,
|
|
22
|
+
* 应用照跑);**真正 abort 的是执行 `JSRuntime()`**。再补一个探针把创建点挪到 UI 线程
|
|
23
|
+
* (`onWindowStageCreate`,与 ArkTS 同一条线程)——只打出 `runtime probe begin [ui-thread]`,
|
|
24
|
+
* 结论行永远没出现、进程当场消失。所以不是「Cangjie 轻量线程没有 VM」,
|
|
25
|
+
* 而是**纯仓颉进程里根本没有 ArkTS VM**;线程换哪儿都一样。
|
|
26
|
+
*
|
|
27
|
+
* 结论:`serialManager` 只能由**真正的 ArkTS 侧**调用(混合工程,或应用自己宿主 ArkTS 模块),
|
|
28
|
+
* 不能关在框架插件的叶子内。ADR 见 `docs/设计决策记录.md` D-022 的 2026-10-24 结论段。
|
|
29
|
+
*
|
|
30
|
+
* ## 所以这里的选择
|
|
31
|
+
*
|
|
32
|
+
* 保持插件导出面(`serialOpen` 等已按句柄空间分流到这里),但一律**如实报不可用**——
|
|
33
|
+
* 既不假装成功,也不让「没后台」变成「应用起不来」。POSIX 的 `/dev/ttyS*` 通路不受影响
|
|
34
|
+
* (`serialOpen` 先试 POSIX,失败才落到这儿)。
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/** 降级原因(命令层原样回给前端,便于页面说清楚为什么不能开 USB 串口) */
|
|
38
|
+
@When[env == "ohos"]
|
|
39
|
+
const OHOS_USB_UNAVAILABLE: String =
|
|
40
|
+
"USB 串口在鸿蒙上需要 ArkTS 侧调用 serialManager:纯仓颉进程里没有 ArkTS VM," +
|
|
41
|
+
"建 JSRuntime 会让进程 SIGABRT(真机 A/B 已证);请改用 /dev/ttyS* 或走 ArkTS 宿主"
|
|
42
|
+
|
|
43
|
+
/** 句柄是否属于 USB 串口空间——降级后永远 false,`serialRead/Write/Close` 全部留在 POSIX 侧 */
|
|
44
|
+
@When[env == "ohos"]
|
|
45
|
+
public func usbSerialIsHandle(h: Int64): Bool {
|
|
46
|
+
let _ = h
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** 枚举 USB 串口:降级后恒空(「没有 USB 串口」与「后端不可用」在命令层同形,原因进错误槽) */
|
|
51
|
+
@When[env == "ohos"]
|
|
52
|
+
public func usbSerialListNames(): ArrayList<String> {
|
|
53
|
+
return ArrayList<String>()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** 打开 USB 串口:恒回 -3(打不开/未授权)并写明原因 */
|
|
57
|
+
@When[env == "ohos"]
|
|
58
|
+
public func usbSerialOpenByPath(path: String, baud: Int32, dataBits: Int32, parity: Int32,
|
|
59
|
+
stopBits: Int32): Int64 {
|
|
60
|
+
let _ = path
|
|
61
|
+
let _ = baud
|
|
62
|
+
let _ = dataBits
|
|
63
|
+
let _ = parity
|
|
64
|
+
let _ = stopBits
|
|
65
|
+
serialOhosSetError(OHOS_USB_UNAVAILABLE)
|
|
66
|
+
return -3
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** 读:不会有句柄走到这里(`usbSerialIsHandle` 恒 false),保留签名为了上层不分叉 */
|
|
70
|
+
@When[env == "ohos"]
|
|
71
|
+
public func usbSerialReadHandle(h: Int64, maxBytes: Int32, timeoutMs: Int32): Array<UInt8> {
|
|
72
|
+
let _ = h
|
|
73
|
+
let _ = maxBytes
|
|
74
|
+
let _ = timeoutMs
|
|
75
|
+
return Array<UInt8>(0, repeat: 0)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** 写:同上,恒 0 字节 */
|
|
79
|
+
@When[env == "ohos"]
|
|
80
|
+
public func usbSerialWriteHandle(h: Int64, data: Array<UInt8>, timeoutMs: Int32): Int32 {
|
|
81
|
+
let _ = h
|
|
82
|
+
let _ = data
|
|
83
|
+
let _ = timeoutMs
|
|
84
|
+
return 0
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** 关句柄:同上,恒 -4 */
|
|
88
|
+
@When[env == "ohos"]
|
|
89
|
+
public func usbSerialCloseHandle(h: Int64): Int32 {
|
|
90
|
+
let _ = h
|
|
91
|
+
return -4
|
|
92
|
+
}
|