This repository has no description
1import "./global.css";
2
3let port: SerialPort;
4
5// Check if Serial API is supported
6if (!("serial" in navigator)) {
7 alert(
8 "Web Serial API is not supported in this browser. Please use Chrome or Edge.",
9 );
10}
11
12const createTemplate = () => `
13 <div style="display: flex; flex-direction: row; height: 100vh;">
14 <div style="display: flex; flex-direction: column; align-items: center; justify-content: center; flex: 1; gap: 20px;">
15 <button id="connect">Connect Serial Port</button>
16
17 <div>
18 <label>Left Motor (1) Rotations:</label>
19 <input type="range" id="motor1" min="-10" max="10" step="0.1" value="0">
20 <span id="motor1Value">0</span>
21 <button id="send1">Send</button>
22 </div>
23
24 <div>
25 <label>Right Motor (2) Rotations:</label>
26 <input type="range" id="motor2" min="-10" max="10" step="0.1" value="0">
27 <span id="motor2Value">0</span>
28 <button id="send2">Send</button>
29 </div>
30 </div>
31 <div style="width: 300px; padding: 20px; border-left: 1px solid #ccc; overflow-y: auto;">
32 <h3>Serial Log</h3>
33 <pre id="serialLog" style="white-space: pre-wrap; margin: 0;"></pre>
34 </div>
35 </div>
36`;
37
38async function connectSerial() {
39 try {
40 port = await navigator.serial.requestPort();
41 await port.open({ baudRate: 115200 });
42
43 // Verify port is open before continuing
44 if (port.writable == null) {
45 throw new Error("Failed to open serial port - port is not writable");
46 }
47
48 console.log("Connected to serial port");
49 appendToLog("Connected to serial port");
50
51 // Start reading from the serial port
52 while (port.readable) {
53 const reader = port.readable.getReader();
54 try {
55 while (true) {
56 const { value, done } = await reader.read();
57 if (done) break;
58 const decoded = new TextDecoder().decode(value);
59 appendToLog(decoded);
60 }
61 } catch (error) {
62 console.error(error);
63 } finally {
64 reader.releaseLock();
65 }
66 }
67 } catch (err) {
68 console.error("Serial port error:", err);
69 alert(
70 "Failed to open serial port. Please check your connection and permissions.",
71 );
72 }
73}
74
75function appendToLog(message: string) {
76 const log = document.getElementById("serialLog");
77 if (log) {
78 log.textContent += message + "\n";
79 log.scrollTop = log.scrollHeight;
80 }
81}
82
83async function sendMotorCommand(motorNum: number) {
84 if (!port) {
85 alert("Please connect serial port first");
86 return;
87 }
88
89 if (!port.writable) {
90 alert("Serial port is not writable");
91 return;
92 }
93
94 const rotations = (
95 document.getElementById(`motor${motorNum}`) as HTMLInputElement
96 ).value;
97 const writer = port.writable.getWriter();
98 const encoder = new TextEncoder();
99 const data = `${motorNum} ${rotations}\r`;
100
101 try {
102 await writer.write(encoder.encode(data));
103 appendToLog(`Sent to motor ${motorNum}: ${rotations} rotations`);
104 } catch (err) {
105 console.error("Write error:", err);
106 appendToLog(`Error sending to motor ${motorNum}: ${err}`);
107 } finally {
108 writer.releaseLock();
109 }
110}
111
112function defaultPageRender() {
113 const app = document.querySelector<HTMLDivElement>("#app");
114 if (!app) throw new Error("App element not found");
115 app.innerHTML = createTemplate();
116
117 // Add slider value display updates
118 document.getElementById("motor1")?.addEventListener("input", (e) => {
119 const value = (e.target as HTMLInputElement).value;
120 const display = document.getElementById("motor1Value");
121 if (display) display.textContent = value;
122 });
123
124 document.getElementById("motor2")?.addEventListener("input", (e) => {
125 const value = (e.target as HTMLInputElement).value;
126 const display = document.getElementById("motor2Value");
127 if (display) display.textContent = value;
128 });
129
130 document.getElementById("connect")?.addEventListener("click", connectSerial);
131 document
132 .getElementById("send1")
133 ?.addEventListener("click", () => sendMotorCommand(1));
134 document
135 .getElementById("send2")
136 ?.addEventListener("click", () => sendMotorCommand(2));
137}
138
139function handleRoute() {
140 defaultPageRender();
141}
142
143handleRoute();