import React, { useState } from 'react'; import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Typography, LinearProgress, Box, Alert } from '@mui/material'; import FileUploadIcon from '@mui/icons-material/FileUpload'; import FileServer from './FileServer'; const FirmwareUpdateModal = ({ open, onClose, targetNodeId }) => { const [firmwareFile, setFirmwareFile] = useState(null); const [fileContent, setFileContent] = useState(null); const [updateProgress, setUpdateProgress] = useState(0); const [updateStatus, setUpdateStatus] = useState(null); // 'idle', 'updating', 'success', 'error' const [statusMessage, setStatusMessage] = useState(''); const handleFileChange = (event) => { const file = event.target.files[0]; if (!file) return; // Validate file extension is .bin const fileExtension = file.name.split('.').pop().toLowerCase(); if (fileExtension !== 'bin') { setUpdateStatus('error'); setStatusMessage('Invalid file type. Please select a .bin firmware file.'); return; } setFirmwareFile(file); setUpdateStatus('idle'); setStatusMessage(''); // Generate a unique path for this firmware file const firmwarePath = FileServer.pathKey(file.name); console.log(`Generated firmware path key: ${firmwarePath}`); // Load the file into the FileServer using the generated path FileServer.loadFile(file, firmwarePath) .then(fileInfo => { console.log(`Firmware loaded: ${fileInfo.name}, size: ${fileInfo.size} bytes, path: ${fileInfo.path}`); setFileContent(fileInfo); }) .catch(error => { console.error('Error loading firmware:', error); setUpdateStatus('error'); setStatusMessage('Failed to load firmware file'); }); }; // Function to read data at a specific offset const readDataAtOffset = (offset, length) => { if (!fileContent || !fileContent.data) return null; try { const dataView = new DataView(fileContent.data); if (offset + length > fileContent.size) { console.error('Requested offset+length exceeds file size'); return null; } // Read bytes and return as hex string let hexString = ''; for (let i = 0; i < length; i++) { const byte = dataView.getUint8(offset + i); hexString += byte.toString(16).padStart(2, '0'); } return hexString; } catch (error) { console.error('Error reading data at offset:', error); return null; } }; const handleUpdate = () => { if (!firmwareFile || !fileContent) return; try { // Get the local node reference const localNode = window.localNode; if (!localNode) { setUpdateStatus('error'); setStatusMessage('Local node not available'); return; } // Update UI state setUpdateStatus('updating'); setStatusMessage('Starting firmware update...'); setUpdateProgress(0); // Register a progress callback with the FileServer const firmwarePath = fileContent.path; FileServer.registerProgressCallback(firmwarePath, (progress, offset, total, eof) => { // Update progress in state (0-100%) setUpdateProgress(progress * 100); // Update status message setStatusMessage(`Updating firmware: ${Math.round(progress * 100)}% (${offset}/${total} bytes)`); // When complete if (eof) { setUpdateStatus('success'); setStatusMessage('Firmware update completed successfully!'); // Clean up progress tracking setTimeout(() => { FileServer.unregisterProgressCallback(firmwarePath); }, 2000); } }); // Begin the firmware update process console.log(`Starting firmware update for node ${targetNodeId} with file ${firmwareFile.name}`); // Call the beginFirmwareUpdate method on the local node localNode.beginFirmwareUpdate( targetNodeId, firmwarePath, (transfer) => { console.log("Firmware update result:", transfer); const msg = transfer.payload; if (!msg || msg.fields.error.value > 0) { // Handle update failure setUpdateStatus('error'); setStatusMessage(`Update failed: code: ${msg.fields.error.value} ${msg.fields.optional_error_message.toString() || 'Unknown error'}`); FileServer.unregisterProgressCallback(firmwarePath); } else { setUpdateStatus('updating'); } } ); } catch (error) { console.error('Error initiating firmware update:', error); setUpdateStatus('error'); setStatusMessage(`Failed to start update: ${error.message || 'Unknown error'}`); } }; return ( Firmware Update Please select the firmware file (.bin) to upload to node {targetNodeId}. {firmwareFile && ( Selected File: {firmwareFile.name} {fileContent && ` (${fileContent.size} bytes)`} )} {updateStatus === 'updating' && ( {statusMessage || 'Updating firmware...'} )} {updateStatus === 'error' && ( {statusMessage || 'An error occurred during the update.'} )} {updateStatus === 'success' && ( {statusMessage || 'Firmware update completed successfully!'} )} {updateStatus !== 'updating' ? ( <> ) : ( )} ); }; export default FirmwareUpdateModal;