// Utility functions for serial communication and UWB data processing export interface SerialPortInfo { path: string manufacturer?: string serialNumber?: string pnpId?: string locationId?: string productId?: string vendorId?: string } export class UWBDataProcessor { private static instance: UWBDataProcessor private dataBuffer: string = '' static getInstance(): UWBDataProcessor { if (!UWBDataProcessor.instance) { UWBDataProcessor.instance = new UWBDataProcessor() } return UWBDataProcessor.instance } // Process incoming serial data stream processDataStream(chunk: string): string[] { this.dataBuffer += chunk const lines: string[] = [] // Split on line endings const parts = this.dataBuffer.split(/\r?\n/) // Keep last incomplete line in buffer this.dataBuffer = parts.pop() || '' // Return complete lines return parts.filter(line => line.trim().length > 0) } // Check if ESP32 device based on port info static isESP32Device(port: SerialPortInfo): boolean { const esp32Vendors = ['10C4', '1A86', '0403'] // Silicon Labs, QinHeng, FTDI const esp32Manufacturers = ['Silicon Labs', 'FTDI', 'QinHeng Electronics'] return ( (port.vendorId && esp32Vendors.includes(port.vendorId)) || (port.manufacturer && esp32Manufacturers.some(m => port.manufacturer?.includes(m) )) ) } // Validate UWB command format static validateUWBCommand(command: string): boolean { const validCommands = [ 'AT?', 'AT+GETVER?', 'AT+RESTART', 'AT+RESTORE', 'AT+SAVE', 'AT+SETCFG=', 'AT+GETCFG?', 'AT+SETANT=', 'AT+GETANT?', 'AT+SETCAP=', 'AT+GETCAP?', 'AT+SETRPT=', 'AT+GETRPT?', 'AT+SLEEP=', 'AT+SETPOW=', 'AT+GETPOW?', 'AT+DATA=', 'AT+RDATA', 'AT+SETPAN=', 'AT+GETPAN?' ] return validCommands.some(cmd => command.startsWith(cmd) || command === cmd ) } // Clear data buffer clearBuffer(): void { this.dataBuffer = '' } }