| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | /// Web Serial API Implementation
 | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  | /// https://developer.mozilla.org/en-US/docs/Web/API/SerialPort
 | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | class SerialPort { | 
					
						
							|  |  |  |   constructor(port) { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     this._port = port; | 
					
						
							|  |  |  |     this._readLoopPromise = null; | 
					
						
							|  |  |  |     this._reader = null; | 
					
						
							|  |  |  |     this._writer = null; | 
					
						
							|  |  |  |     this._initialized = false; | 
					
						
							|  |  |  |     this._keepReading = true; | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |     this.isConnected = false; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   /// Connect and start reading loop
 | 
					
						
							|  |  |  |   async connect(options = { baudRate: 9600 }) { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     if (this._initialized) { | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         await this.disconnect(); | 
					
						
							|  |  |  |       } catch (error) { | 
					
						
							|  |  |  |         console.error('Error disconnecting previous port:', error); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-07-26 10:11:20 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (this._readLoopPromise) { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           await this._readLoopPromise; | 
					
						
							|  |  |  |         } catch (error) { | 
					
						
							|  |  |  |           console.error('Error in read loop:', error); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |       this._readLoopPromise = null; | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     this._initialized = true; | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     this.isConnected = true; | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     this._keepReading = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       await this._port.open(options); | 
					
						
							|  |  |  |     } catch (error) { | 
					
						
							|  |  |  |       this.isConnected = false; | 
					
						
							|  |  |  |       throw error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this._readLoopPromise = this._readLoop(); | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Internal continuous read loop
 | 
					
						
							|  |  |  |   async _readLoop() { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     try { | 
					
						
							|  |  |  |       while (this._port.readable && this._keepReading) { | 
					
						
							|  |  |  |         this._reader = this._port.readable.getReader(); | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           while (true) { | 
					
						
							|  |  |  |             const { value, done } = await this._reader.read(); | 
					
						
							|  |  |  |             if (done) { | 
					
						
							|  |  |  |               // |reader| has been canceled.
 | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (this.onReceive) { | 
					
						
							|  |  |  |               this.onReceive(value); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } catch (error) { | 
					
						
							|  |  |  |           if (this.onReceiveError) this.onReceiveError(error); | 
					
						
							|  |  |  |         } finally { | 
					
						
							|  |  |  |           this._reader.releaseLock(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     } finally { | 
					
						
							|  |  |  |       this.isConnected = false; | 
					
						
							|  |  |  |       await this._port.close(); | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   /// Stop reading and release port
 | 
					
						
							|  |  |  |   async disconnect() { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     this._keepReading = false; | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     if (this._reader) { | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |       try { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |         await this._reader.cancel(); | 
					
						
							|  |  |  |       } catch (error) { | 
					
						
							|  |  |  |         console.error('Error cancelling reader:', error); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this._reader.releaseLock(); | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     if (this._writer) { | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |       try { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |         await this._writer.abort(); | 
					
						
							|  |  |  |       } catch (error) { | 
					
						
							|  |  |  |         console.error('Error closing writer:', error); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this._writer.releaseLock(); | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     try { | 
					
						
							|  |  |  |       await this._port.close(); | 
					
						
							|  |  |  |     } catch (error) { | 
					
						
							|  |  |  |       console.error('Error closing port:', error); | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-26 10:11:20 +02:00
										 |  |  |     if (this._readLoopPromise) { | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         await this._readLoopPromise; | 
					
						
							|  |  |  |       } catch (error) { | 
					
						
							|  |  |  |         console.error('Error in read loop:', error); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Send data to port
 | 
					
						
							|  |  |  |   send(data) { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     if (!this._port.writable) { | 
					
						
							|  |  |  |       throw new Error('Port is not writable'); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-07-29 15:51:54 +02:00
										 |  |  |     this._writer = this._port.writable.getWriter(); | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     if (!this._writer) { | 
					
						
							|  |  |  |       throw new Error('Failed to get writer from port'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       return this._writer.write(data); | 
					
						
							|  |  |  |     } finally { | 
					
						
							|  |  |  |       this._writer.releaseLock(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async forgetDevice() {} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /// WebUSB Implementation
 | 
					
						
							|  |  |  | class WebUsbSerialPort { | 
					
						
							|  |  |  |   constructor(device) { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     this._device = device; | 
					
						
							|  |  |  |     this._interfaceNumber = 0; | 
					
						
							|  |  |  |     this._endpointIn = 0; | 
					
						
							|  |  |  |     this._endpointOut = 0; | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |     this.isConnected = false; | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     this._readLoopPromise = null; | 
					
						
							|  |  |  |     this._initialized = false; | 
					
						
							|  |  |  |     this._keepReading = true; | 
					
						
							| 
									
										
										
										
											2025-07-29 15:51:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     this._vendorId = device.vendorId; | 
					
						
							|  |  |  |     this._productId = device.productId; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _isSameWebUsbSerialPort(webUsbSerialPort) { | 
					
						
							|  |  |  |     return this._vendorId === webUsbSerialPort._vendorId && this._productId === webUsbSerialPort._productId; | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   /// Connect and start reading loop
 | 
					
						
							|  |  |  |   async connect() { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     if (this._initialized) { | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         await this.disconnect(); | 
					
						
							|  |  |  |       } catch (error) { | 
					
						
							|  |  |  |         console.error('Error disconnecting previous device:', error); | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-07-26 10:11:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-29 15:51:54 +02:00
										 |  |  |       const webUsbSerialPorts = await serial.getWebUsbSerialPorts(); | 
					
						
							|  |  |  |       const webUsbSerialPort = webUsbSerialPorts.find(serialPort => this._isSameWebUsbSerialPort(serialPort)); | 
					
						
							|  |  |  |       this._device = webUsbSerialPort ? webUsbSerialPort._device : this._device; | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     this._initialized = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this.isConnected = true; | 
					
						
							|  |  |  |     this._keepReading = true; | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |       await this._device.open(); | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |       if (!this._device.configuration) { | 
					
						
							|  |  |  |         await this._device.selectConfiguration(1); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |       // Find interface with vendor-specific class (0xFF) and endpoints
 | 
					
						
							|  |  |  |       for (const iface of this._device.configuration.interfaces) { | 
					
						
							|  |  |  |         for (const alternate of iface.alternates) { | 
					
						
							|  |  |  |           if (alternate.interfaceClass === 0xff) { | 
					
						
							|  |  |  |             this._interfaceNumber = iface.interfaceNumber; | 
					
						
							|  |  |  |             for (const endpoint of alternate.endpoints) { | 
					
						
							|  |  |  |               if (endpoint.direction === 'out') this._endpointOut = endpoint.endpointNumber; | 
					
						
							|  |  |  |               else if (endpoint.direction === 'in') this._endpointIn = endpoint.endpointNumber; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |       if (this._interfaceNumber === undefined) { | 
					
						
							|  |  |  |         throw new Error('No suitable interface found.'); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |       await this._device.claimInterface(this._interfaceNumber); | 
					
						
							|  |  |  |       await this._device.selectAlternateInterface(this._interfaceNumber, 0); | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |       // Set device to ENABLE (0x22 = SET_CONTROL_LINE_STATE, value 0x01 = activate)
 | 
					
						
							|  |  |  |       await this._device.controlTransferOut({ | 
					
						
							|  |  |  |         requestType: 'class', | 
					
						
							|  |  |  |         recipient: 'interface', | 
					
						
							|  |  |  |         request: 0x22, | 
					
						
							|  |  |  |         value: 0x01, | 
					
						
							|  |  |  |         index: this._interfaceNumber, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } catch (error) { | 
					
						
							|  |  |  |       this.isConnected = false; | 
					
						
							|  |  |  |       throw error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     this._readLoopPromise = this._readLoop(); | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Internal continuous read loop
 | 
					
						
							|  |  |  |   async _readLoop() { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     try { | 
					
						
							|  |  |  |       while (this._keepReading && this.isConnected) { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           const result = await this._device.transferIn(this._endpointIn, 16384); | 
					
						
							|  |  |  |           if (result.data && this.onReceive) { | 
					
						
							|  |  |  |             this.onReceive(result.data); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } catch (error) { | 
					
						
							|  |  |  |           this.isConnected = false; | 
					
						
							|  |  |  |           if (this.onReceiveError) { | 
					
						
							|  |  |  |             this.onReceiveError(error); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     } finally { | 
					
						
							|  |  |  |       this.isConnected = false; | 
					
						
							|  |  |  |       await this._device.close(); | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   /// Stop reading and release device
 | 
					
						
							|  |  |  |   async disconnect() { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     this._keepReading = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |       await this._device.controlTransferOut({ | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |         requestType: 'class', | 
					
						
							|  |  |  |         recipient: 'interface', | 
					
						
							|  |  |  |         request: 0x22, | 
					
						
							|  |  |  |         value: 0x00, | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |         index: this._interfaceNumber, | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     } catch (error) { | 
					
						
							|  |  |  |       console.error('Error sending control transfer:', error); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     await this._device.releaseInterface(this._interfaceNumber); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-26 10:11:20 +02:00
										 |  |  |     if (this._readLoopPromise) { | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         await this._readLoopPromise; | 
					
						
							|  |  |  |       } catch (error) { | 
					
						
							|  |  |  |         console.error('Error in read loop:', error); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   /// Send data to device
 | 
					
						
							|  |  |  |   send(data) { | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     return this._device.transferOut(this._endpointOut, data); | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   async forgetDevice() { | 
					
						
							|  |  |  |     await this.disconnect(); | 
					
						
							| 
									
										
										
										
											2025-07-24 23:58:54 +02:00
										 |  |  |     await this._device.forget(); | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Utility Functions
 | 
					
						
							|  |  |  | const serial = { | 
					
						
							|  |  |  |   isWebSerialSupported: () => 'serial' in navigator, | 
					
						
							|  |  |  |   isWebUsbSupported: () => 'usb' in navigator, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async getSerialPorts() { | 
					
						
							|  |  |  |     if (!this.isWebSerialSupported()) return []; | 
					
						
							|  |  |  |     const ports = await navigator.serial.getPorts(); | 
					
						
							|  |  |  |     return ports.map(port => new SerialPort(port)); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async getWebUsbSerialPorts() { | 
					
						
							|  |  |  |     if (!this.isWebUsbSupported()) return []; | 
					
						
							|  |  |  |     const devices = await navigator.usb.getDevices(); | 
					
						
							|  |  |  |     return devices.map(device => new WebUsbSerialPort(device)); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async requestSerialPort() { | 
					
						
							|  |  |  |     const port = await navigator.serial.requestPort(); | 
					
						
							|  |  |  |     return new SerialPort(port); | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async requestWebUsbSerialPort() { | 
					
						
							|  |  |  |     const filters = [ | 
					
						
							|  |  |  |       { vendorId: 0xcafe }, // TinyUSB
 | 
					
						
							|  |  |  |       { vendorId: 0x239a }, // Adafruit
 | 
					
						
							|  |  |  |       { vendorId: 0x2e8a }, // Raspberry Pi
 | 
					
						
							|  |  |  |       { vendorId: 0x303a }, // Espressif
 | 
					
						
							|  |  |  |       { vendorId: 0x2341 }, // Arduino
 | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  |     const device = await navigator.usb.requestDevice({ filters }); | 
					
						
							|  |  |  |     return new WebUsbSerialPort(device); | 
					
						
							| 
									
										
										
										
											2025-07-05 19:42:44 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | }; |