Advertisement
ShinxisS

web serial api

Dec 11th, 2024 (edited)
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // serialHandler.ts
  2. let reader: ReadableStreamDefaultReader;
  3. let writer: WritableStreamDefaultWriter;
  4. const decoder = new TextDecoder();
  5.  
  6. async function serialHandler() {
  7.   const outputElem =
  8.     document.querySelector<HTMLInputElement>(`#Connect-messages`);
  9.   if (!outputElem) {
  10.     throw new Error("Output element not found");
  11.   }
  12.   if ("serial" in navigator) {
  13.     try {
  14.       const port = await (navigator as any).serial.requestPort();
  15.  
  16.       outputElem.innerHTML = outputElem.innerHTML + "\r\n Opening port";
  17.       console.log("Opening port");
  18.       let wasAlreadyOpen = await retry(openPort, [port], 5);
  19.  
  20.       if (!wasAlreadyOpen) {
  21.         if (writer) writer.releaseLock(); // Release existing writer lock if necessary
  22.         if (reader) reader.releaseLock(); // Release existing reader lock if necessary
  23.  
  24.         //only assign writable & readable streams when port wasn't previously opened
  25.         writer = port.writable.getWriter();
  26.         reader = port.readable.getReader();
  27.       }
  28.       outputElem.innerHTML =
  29.         outputElem.innerHTML + "\r\n Port successfully opened";
  30.     } catch (err) {
  31.       alert("There was an error opening the serial port: " + err);
  32.     }
  33.   } else {
  34.     console.error(
  35.       "Web serial doesn't seem to be enabled in your browser. Check https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API#browser_compatibility for more info."
  36.     );
  37.   }
  38. }
  39.  
  40. /**
  41.  * Takes a string of data, encodes it and then writes it using the `writer` attached to the serial port.
  42.  * @param data - A string of data that will be sent to the Serial port.
  43.  * @returns An empty promise after the message has been written.
  44.  */
  45. async function write(data: string): Promise<void> {
  46.   try {
  47.     console.log("sending data: ", data);
  48.     const dataArrayBuffer = await toAscii(data);
  49.     await writer.write(dataArrayBuffer);
  50.     await writer.ready;
  51.   } catch (err) {
  52.     console.error("Error writing to serial port:", err);
  53.   }
  54. }
  55.  
  56. /**
  57.  * Reads data from the serial port using the `reader` attached to the serial port.
  58.  * @returns A promise that resolves to the decoded string of data read from the serial port.
  59.  */
  60. async function read(): Promise<string> {
  61.   try {
  62.     const readerData = await reader.read();
  63.     var msg = decoder.decode(readerData.value);
  64.     console.log("response received: ", msg);
  65.     return msg;
  66.   } catch (err) {
  67.     const errorMessage = `error reading data: ${err}`;
  68.     console.error(errorMessage);
  69.     return errorMessage;
  70.   }
  71. }
  72.  
  73. function toAscii(text: String): Uint8Array {
  74.   let convertedChar;
  75.   var array = new Uint8Array(text.length);
  76.  
  77.   for (let i = 0; i < text.length; i++) {
  78.     convertedChar = text.charCodeAt(i);
  79.     array[i] = convertedChar;
  80.   }
  81.  
  82.   return array;
  83. }
  84.  
  85. // sendMessage.ts
  86. import serialHandler from "./serialHandler";
  87.  
  88. export default async function sendMessage(
  89.   message: string,
  90.   label: string
  91. ): Promise<string[]> {
  92.   try {
  93.     const outputElem = document.querySelector<HTMLInputElement>(
  94.       `#${label}-messages`
  95.     );
  96.     if (!outputElem) {
  97.       throw new Error("Output element not found");
  98.     }
  99.  
  100.     await serialHandler.write(message);
  101.     outputElem.innerHTML = outputElem.innerHTML + "\r\nMessage sent:" + message;
  102.     const result = await serialHandler.read();
  103.     outputElem.innerHTML =
  104.       outputElem.innerHTML + "\r\nResponse received:" + result;
  105.  
  106.     let results = result.substring(0, result.indexOf("\r\n")).split(",");
  107.     return results;
  108.   } catch (e) {
  109.     console.error(e);
  110.     return [];
  111.   }
  112. }
  113.  
  114.  
  115. // startDevice.ts
  116.  
  117. import sendMessage from "./sendMessage";
  118. /**
  119.  * Sends a command to start the device.
  120.  * @returns A promise resolving to a boolean indicating success or failure.
  121.  */
  122. export default async function startDevice(): Promise<boolean> {
  123.   try {
  124.     console.log("Sending start command to the device...");
  125.  
  126.     // HELO handshake
  127.     const heloResponse = await sendMessage(":HELO? [''] 1\r\n", "startDevice");
  128.     if (heloResponse[0] !== "ACK") {
  129.       throw new Error("Device did not acknowledge the HELO command.");
  130.     }
  131.  
  132.     // Send the start command
  133.     const startResponse = await sendMessage(":START\r\n", "startDevice");
  134.     await sendMessage(":END?\r\n", "sendMessages");
  135.     if (startResponse[0] === "OK") {
  136.       console.log("Device started successfully.");
  137.       return true;
  138.     } else {
  139.       console.error("Failed to start the device:", startResponse);
  140.  
  141.       return false;
  142.     }
  143.   } catch (error) {
  144.     console.error("Error in startDevice:", error);
  145.     return false;
  146.   }
  147. }
  148.  
  149.  
  150. // stopDevice.ts
  151. import sendMessage from "./sendMessage";
  152. /**
  153.  * Sends a command to stop the device.
  154.  * @returns A promise resolving to a boolean indicating success or failure.
  155.  */
  156. export default async function stopDevice(): Promise<boolean> {
  157.   try {
  158.     console.log("Sending stop command to the device...");
  159.  
  160.     // HELO handshake
  161.     const heloResponse = await sendMessage(":HELO? [''] 1\r\n", "stopDevice");
  162.     if (heloResponse[0] !== "ACK") {
  163.       throw new Error("Device did not acknowledge the HELO command.");
  164.     }
  165.  
  166.     // Send the stop command
  167.     const stopResponse = await sendMessage(":STOP\r\n", "stopDevice");
  168.     await sendMessage(":END?\r\n", "sendMessages");
  169.     if (stopResponse[0] === "OK") {
  170.       console.log("Device stopped successfully.");
  171.       return true;
  172.     } else {
  173.       console.error("Failed to stop the device:", stopResponse);
  174.       return false;
  175.     }
  176.   } catch (error) {
  177.     console.error("Error in stopDevice:", error);
  178.     return false;
  179.   }
  180. }
  181.  
  182. import { useState } from "react";
  183. import serialHandler from "./utils/serialHandler";
  184. import ActionButton from "./component/ActionButton";
  185. import StatusDisplay from "./component/StatusDisplay";
  186. import startDevice from "./utils/startDevice";
  187. import stopDevice from "./utils/stopDevice";
  188.  
  189. function App() {
  190.   const [status, setStatus] = useState<boolean>(false);
  191.   const [data, setData] = useState<any>(null);
  192.   const [device, setDevice] = useState<string>("");
  193.  
  194.   const handleConnect = async () => {
  195.     await serialHandler.init();
  196.     await serialHandler.write("*IDN?\r\n");
  197.     let device = await serialHandler.read();
  198.     setDevice(device);
  199.     setStatus(true);
  200.   };
  201.  
  202.   const handleGetMeasurementData = async () => {
  203.     const [success, receivedData] = await GetMeasurementData();
  204.     if (success) {
  205.       setData(receivedData);
  206.       console.log("Received Data:", data);
  207.     } else {
  208.       console.error("Failed to get measurement data.");
  209.     }
  210.   };
  211.   const actions = [
  212.     { name: "startDevice", handler: () => startDevice() },
  213.     { name: "stopDevice", handler: () => stopDevice() },
  214.   ];
  215.   return (
  216.     <div className="container mx-auto p-4">
  217.       <StatusDisplay status={status} deviceName={device} />
  218.       <div className="grid grid-cols-2 lg:grid-cols-3 gap-4 mt-4">
  219.         <ActionButton
  220.           label={"Connect"}
  221.           onClick={handleConnect}
  222.           disabled={status}
  223.         />
  224.         {actions.map((action) => (
  225.           <ActionButton
  226.             key={action.name}
  227.             label={action.name}
  228.             onClick={action.handler}
  229.             disabled={!status}
  230.           />
  231.         ))}
  232.       </div>
  233.     </div>
  234.   );
  235. }
  236.  
  237. export default App;
  238.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement