Skip to content

Commit 477b638

Browse files
committed
add ts example
1 parent 1a4c0a2 commit 477b638

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

examples/serial_echo.ts

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// @ts-nocheck
2+
// deno run --allow-ffi --allow-read examples/serial_echo.ts
3+
4+
interface CliOptions {
5+
lib: string;
6+
port?: string;
7+
}
8+
9+
function parseArgs(): CliOptions {
10+
const opts: CliOptions = { lib: "./build/libCPP-Unix-Bindings.so" };
11+
12+
for (let i = 0; i < Deno.args.length; ++i) {
13+
const arg = Deno.args[i];
14+
if (arg === "--lib" && i + 1 < Deno.args.length) {
15+
opts.lib = Deno.args[++i];
16+
} else if (arg === "--port" && i + 1 < Deno.args.length) {
17+
opts.port = Deno.args[++i];
18+
} else {
19+
console.warn(`Unknown argument '${arg}' ignored.`);
20+
}
21+
}
22+
return opts;
23+
}
24+
25+
// -----------------------------------------------------------------------------
26+
// Helper utilities for C interop
27+
// -----------------------------------------------------------------------------
28+
const encoder = new TextEncoder();
29+
const decoder = new TextDecoder();
30+
31+
function cString(str: string): Uint8Array {
32+
// Encodes JavaScript string as null-terminated UTF-8 byte array.
33+
const bytes = encoder.encode(str);
34+
const buf = new Uint8Array(bytes.length + 1);
35+
buf.set(bytes, 0);
36+
buf[bytes.length] = 0;
37+
return buf;
38+
}
39+
40+
function pointer(view: Uint8Array): Deno.UnsafePointer {
41+
return Deno.UnsafePointer.of(view) as Deno.UnsafePointer;
42+
}
43+
44+
// -----------------------------------------------------------------------------
45+
// Load dynamic library
46+
// -----------------------------------------------------------------------------
47+
const { lib, port: cliPort } = parseArgs();
48+
49+
const dylib = Deno.dlopen(
50+
lib,
51+
{
52+
serialOpen: { parameters: ["pointer", "i32", "i32", "i32", "i32"], result: "pointer" },
53+
serialClose: { parameters: ["pointer"], result: "void" },
54+
serialWrite: { parameters: ["pointer", "pointer", "i32", "i32", "i32"], result: "i32" },
55+
serialReadUntil: {
56+
parameters: ["pointer", "pointer", "i32", "i32", "i32", "pointer"],
57+
result: "i32",
58+
},
59+
serialGetPortsInfo: { parameters: ["pointer", "i32", "pointer"], result: "i32" },
60+
} as const,
61+
);
62+
63+
// -----------------------------------------------------------------------------
64+
// 1. List available ports
65+
// -----------------------------------------------------------------------------
66+
const sepBuf = cString(";");
67+
const portsBuf = new Uint8Array(4096);
68+
dylib.symbols.serialGetPortsInfo(
69+
pointer(portsBuf),
70+
portsBuf.length,
71+
pointer(sepBuf),
72+
);
73+
74+
const cPortsStr = decoder.decode(portsBuf.subarray(0, portsBuf.indexOf(0)));
75+
const ports = cPortsStr ? cPortsStr.split(";") : [];
76+
console.log("Available ports:");
77+
for (const p of ports) {
78+
console.log(" •", p);
79+
}
80+
if (ports.length === 0) {
81+
console.error("No serial ports found (ttyUSB). Exiting.");
82+
dylib.close();
83+
Deno.exit(1);
84+
}
85+
86+
// -----------------------------------------------------------------------------
87+
// 2. Echo test on selected port
88+
// -----------------------------------------------------------------------------
89+
const portPath = cliPort ?? ports[0];
90+
console.log(`\nUsing port: ${portPath}`);
91+
92+
const portBuf = cString(portPath);
93+
const handle = dylib.symbols.serialOpen(pointer(portBuf), 115200, 8, 0, 0);
94+
if (handle === null) {
95+
console.error("Failed to open port!");
96+
dylib.close();
97+
Deno.exit(1);
98+
}
99+
100+
// Give MCU a moment to reboot (similar to C++ tests)
101+
await new Promise((r) => setTimeout(r, 2000));
102+
103+
const msg = "HELLO\n";
104+
const msgBuf = encoder.encode(msg);
105+
const written = dylib.symbols.serialWrite(handle, pointer(msgBuf), msgBuf.length, 100, 1);
106+
if (written !== msgBuf.length) {
107+
console.error(`Write failed (wrote ${written}/${msgBuf.length})`);
108+
dylib.symbols.serialClose(handle);
109+
dylib.close();
110+
Deno.exit(1);
111+
}
112+
113+
const readBuf = new Uint8Array(64);
114+
const untilBuf = new Uint8Array(["\n".charCodeAt(0)]);
115+
116+
const read = dylib.symbols.serialReadUntil(handle, pointer(readBuf), readBuf.length, 500, 1, pointer(untilBuf));
117+
if (read <= 0) {
118+
console.error("Read failed or timed out.");
119+
dylib.symbols.serialClose(handle);
120+
dylib.close();
121+
Deno.exit(1);
122+
}
123+
124+
const echo = decoder.decode(readBuf.subarray(0, read));
125+
console.log(`Echo response (${read} bytes): '${echo}'`);
126+
127+
if (echo === msg) {
128+
console.log("Echo test: ✅ success");
129+
} else {
130+
console.error("Echo test: ❌ mismatch");
131+
}
132+
133+
dylib.symbols.serialClose(handle);
134+
dylib.close();

0 commit comments

Comments
 (0)