const serialResultsDiv = document.getElementById("serialResults"); // Buffer for accumulating received data before logging let receivedDataBuffer = ''; // Function to log communication to API async function logCommunication(data, direction) { // Only log if debug mode is enabled if (typeof DEBUG === 'undefined' || !DEBUG) { return; } // Log all communication including connection/disconnection events try { // Get service token for API authentication const serviceToken = document.getElementById("servicetoken")?.innerHTML || ''; // Get serial number if available let serialNumber = ''; if (typeof serial !== 'undefined' && serial) { serialNumber = serial; } const logData = { data: data, direction: direction, // 'sent', 'received', 'connected', 'disconnected', 'handshake' timestamp: new Date().toISOString(), serial_number: serialNumber, maintenance_run: 0 // Not used in scripts.js, set to 0 }; // Get base URL for API calls (assuming 'link' variable is defined globally) const url = link + '/v2/com_log/log'; const bearer = 'Bearer ' + serviceToken; const response = await fetch(url, { method: 'POST', withCredentials: true, credentials: 'include', headers: { 'Authorization': bearer, 'Content-Type': 'application/json' }, body: JSON.stringify(logData) }); if (!response.ok) { console.warn('Failed to log communication:', response.status); } } catch (error) { console.warn('Error logging communication:', error); } } function progressBar(percentage, message, color){ var readbar = document.getElementById("readBar"); readBar.style.background = color; readBar.style.width = percentage +"%"; readBar.innerHTML = message; } async function connectDevice() { //clear input readBar.innerHTML = ''; serialResultsDiv.innerHTML = ''; // Reset received data buffer for new connection receivedDataBuffer = ''; //set prgress bar progressBar("1", "", ""); try { // Prompt user to select any serial port. const filters = [{ usbVendorId: 1027, usbProductId: 24597 }]; port = await navigator.serial.requestPort({ filters }); // Log selected port details const portInfo = port.getInfo(); const portDetails = { processStep: 'Firmware', usbVendorId: portInfo.usbVendorId, usbProductId: portInfo.usbProductId, readable: !!port.readable, writable: !!port.writable, opened: port.readable !== null && port.writable !== null }; await logCommunication(`Selected USB device - ${JSON.stringify(portDetails)}`, 'connected'); await port.open({ baudRate: 56700, dataBits: 8, stopBits: 1, parity: 'none', flowControl: 'none' }); progressBar("10", "Connecting", "#04AA6D"); // Log successful connection with details const portInfoSuccess = port.getInfo(); const portDetailsSuccess = { processStep: 'Firmware', usbVendorId: portInfoSuccess.usbVendorId, usbProductId: portInfoSuccess.usbProductId, readable: !!port.readable, writable: !!port.writable, opened: port.readable !== null && port.writable !== null }; await logCommunication(`Serial port opened successfully (baudRate: 56700) - ${JSON.stringify(portDetailsSuccess)}`, 'connected'); listenToPort(); textEncoder = new TextEncoderStream(); writableStreamClosed = textEncoder.readable.pipeTo(port.writable); writer = textEncoder.writable.getWriter(); } catch (error) { // Log connection failure details await logCommunication(`Serial connection failed: ${error.message || 'Unknown error'}`, 'disconnected'); // Check for specific "No port selected" error and show user-friendly message if (error.message && error.message.includes('No port selected by the user')) { progressBar("100", "No device selected, please try again", "#ff6666"); } else if (openPort = 1){ closePort(); console.log("Closing port"); alert("System is still trying to close the serial port. If this message continues to come up please refresh this page."); } else{ alert("Your browser does not support this functionality. Please use latest Chrome or Edge browser."); } } } async function listenToPort() { const textDecoder = new TextDecoderStream(); readableStreamClosed = port.readable.pipeTo(textDecoder.writable); reader = textDecoder.readable.getReader(); openPort = 1; // Log starting to listen to port await logCommunication('Starting to listen to serial port', 'connected'); while (true) { const { value, done } = await reader.read(); if (done) { reader.releaseLock(); break; } progressBar("40", "Reading", "#04AA6D"); appendToTerminal(value); var item = serialResultsDiv.innerHTML; x = Array.from(new Set(item.split(";"))).toString(); if (x.indexOf("SN=") > 0 && x.indexOf("HW=") > 0 && x.indexOf("FW=") >0 && x.indexOf("STATE=") > 0) { progressBar("60", "Reading device completed", "#04AA6D"); // Log combined received data when device identification is complete await logCommunication(`Device identification data received: ${receivedDataBuffer.trim()}`, 'handshake'); // Reset buffer for next connection receivedDataBuffer = ''; setTimeout(getDeviceData, 4000); return; } } } async function appendToTerminal(newStuff) { serialResultsDiv.innerHTML += newStuff; // Log received data await logCommunication(newStuff.trim(), 'received'); } async function getServiceID(){ var data = document.getElementById("servicetoken").innerHTML; return data } async function getDeviceData(){ var item = serialResultsDiv.innerHTML; x = Array.from(new Set(item.split(";"))).toString(); //Check if Serialnumber is retrieved from device if (x.indexOf("SN=") > 0){ var a = x.indexOf("SN="); var b = a + 3; var c = b + 8; serial = x.substring(b,c); progressBar("65", "Retrieving device data", "#04AA6D"); console.log(serial); // Log serial number retrieval await logCommunication(`Serial number retrieved: ${serial}`, 'handshake'); if (x.indexOf("FW=") > 0){ var a = x.indexOf("FW="); var b = a + 3; var c = b + 8; fw = x.substring(b,c); fw = fw.replace(/^0+/, ''); // Log firmware version await logCommunication(`Firmware version retrieved: ${fw}`, 'handshake'); } //Check if HW is retrieved from device if (x.indexOf("HW=") > 0 && x.indexOf("FW=") >0){ var a = x.indexOf("HW="); var b = a + 3; var c = b + 8; var d = x.substring(b,c); var e = d.slice(-1); if (e.toLowerCase() !== e.toUpperCase()){ var f = d.slice(d.length - 3) hw = 'R'+f; sw = 'R'+f; } else { var f = d.slice(d.length - 2) hw = 'R'+f; sw = 'R'+f; } //GET THE COMMITCODE commitCode = compareCommitCodes("",fw); // Log hardware version and commit code await logCommunication(`Hardware version retrieved: ${hw}, Commit code: ${commitCode}`, 'handshake'); getServiceID().then(firmwareUpdate); progressBar("80", "checking for available firmware", "#04AA6D"); setTimeout(checkAvailableFirmware, 5000); } else { progressBar("80", "Reading of device not successful, please try again", "#ff6666"); console.log('Reading of device not successful'); // Log failure to read device data await logCommunication('Failed to retrieve complete device data (HW and FW)', 'disconnected'); } } } function firmwareUpdate(data){ var serialnumber = serial; var action = '/v2/products_software/sn='+serialnumber+'&version='+commitCode+'&hw_version='+hw; var url = link+action; var bearer = 'Bearer ' + data; // Log firmware update request logCommunication(`Requesting firmware update for SN: ${serialnumber}, Version: ${commitCode}, HW: ${hw}`, 'sent'); fetch(url, { method: 'GET', withCredentials: true, credentials: 'include', headers: { 'Authorization': bearer, 'Content-Type': 'application/json' } }) .then(response => response.json()) .then(firmware=> { firmwarelocation = './firmware/'+firmware['software']; upgraded_version = firmware['version']; // Log firmware response logCommunication(`Firmware update response: ${firmware['software']}, Version: ${firmware['version']}`, 'received'); return firmwarelocation; }) .catch(error => { console.log(error) // Log firmware fetch error logCommunication(`Firmware update fetch error: ${error.message}`, 'disconnected'); }) } function findShortGitCommitHash(string) { // Step 1: Find all hexadecimal sequences const hexSequencePattern = /[0-9a-f]+/gi; const allHexMatches = string.match(hexSequencePattern) || []; // Step 2: Filter to only include those with exactly 6 or 7 characters const commitHashes = allHexMatches.filter(match => match.length === 6 || match.length === 7); return commitHashes; } function compareCommitCodes(stringA, stringB) { // Get commit codes from both strings const commitCodesA = findShortGitCommitHash(stringA); const commitCodesB = findShortGitCommitHash(stringB); // Case 1: Check if there are matching commit codes between A and B for (const codeA of commitCodesA) { if (commitCodesB.includes(codeA)) { return codeA; // Return the first matching commit code } } // Case 2: If A has commit code but B doesn't if (commitCodesA.length > 0 && commitCodesB.length === 0) { return commitCodesA[0]; // Return the first commit code from A } // Case 3: If A has no commit code but B does if (commitCodesA.length === 0 && commitCodesB.length > 0) { return commitCodesB[0]; // Return the first commit code from B } // Case 4: Neither has commit code return ""; } function checkAvailableFirmware(){ if (typeof firmwarelocation !== 'undefined') { progressBar("90", "Validating firmware retrieved", "#04AA6D"); hex_fw = firmwarelocation.split("/firmware/").pop(); console.log(hex_fw) if (hex_fw == 'null' || hex_fw == ''){ //document.getElementById("updateAvailabe").style.display = "none"; progressBar("100", "No firmware found for this device", "#ff6666"); // Log no firmware found logCommunication('No firmware found for this device', 'disconnected'); } else { var element = document.getElementById("Device_output"); //COMPARE commitCODE from DEVICE with RETURNED CODE FROM API if (commitCode.toUpperCase() == upgraded_version.toUpperCase()){ readBar.innerHTML = 'Latest Firmware already on device'; // Log firmware up to date logCommunication(`Firmware is up to date: ${commitCode}`, 'received'); if (typeof(element) != 'undefined' && element != null) { document.getElementById("Device_output").style.display = "none"; } } else { readBar.innerHTML = 'Firmware available'; // Log firmware available logCommunication(`Firmware update available: Current ${commitCode}, Available ${upgraded_version}`, 'received'); if (typeof(element) != 'undefined' && element != null){ document.getElementById("Device_output").style.display = "block"; } } } } else{ document.getElementById("updateAvailabe").style.display = "none"; readBar.innerHTML = 'No firmware found for this device'; // Log no firmware location logCommunication('No firmware location available', 'disconnected'); } closePort(); } async function closePort(){ try { // Log port closure start const portInfo = port.getInfo(); const portDetails = { processStep: 'Firmware', usbVendorId: portInfo.usbVendorId, usbProductId: portInfo.usbProductId, readable: !!port.readable, writable: !!port.writable, opened: port.readable !== null && port.writable !== null }; await logCommunication(`Starting port closure - ${JSON.stringify(portDetails)}`, 'disconnected'); reader.cancel(); await readableStreamClosed.catch(() => { /* Ignore the error */ }); writer.close(); await writableStreamClosed; console.log('Device connection closed'); await port.close(); // Log successful port closure await logCommunication(`Serial port closed successfully - VendorID: ${portInfo.usbVendorId}, ProductID: ${portInfo.usbProductId}`, 'disconnected'); } catch (error) { // Log port closure failure await logCommunication(`Serial port closure failed: ${error.message || 'Unknown error'}`, 'disconnected'); } openPort = 0; readBar.style.width = "100%"; } function checkFormUpdateFirmware() { let buttonfirmware = document.getElementById("updateFirmware") if (document.getElementById("action_firmware").checked) {updateFirmware.disabled = false; buttonfirmware.style.display = "block"; } else { buttonfirmware.disabled = "disabled"; buttonfirmware.style.display = "none"; } }