mirror of
				https://github.com/Pablo2048/modbus-rtu-master.git
				synced 2025-10-31 00:12:42 +01:00 
			
		
		
		
	Refactoring, correctly handling disconnect & reconnect, use of trace.js
This commit is contained in:
		| @@ -9,11 +9,36 @@ class ModbusRTUMaster { | ||||
|         this.parity = config.parity || 'none'; | ||||
|         this.flowControl = config.flowControl || 'none'; | ||||
|         this.timeout = config.timeout || 2000; // Default timeout is 2 seconds | ||||
|  | ||||
|         navigator.serial.addEventListener('disconnect', (event) => { | ||||
|             TRACE_WARNING("mbrtu", 'Port disconnected, attempting to reconnect...'); | ||||
|             this.handleDeviceLost(); | ||||
|         }); | ||||
|  | ||||
|         navigator.serial.addEventListener('connect', (event) => { | ||||
|             TRACE_INFO("mbrtu", 'Device connected:', event); | ||||
|             this.reconnect(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     async connect() { | ||||
|         try { | ||||
|             this.port = await navigator.serial.requestPort(); | ||||
|             await this.openPort(); | ||||
|             TRACE_VERBOSE("mbrtu", 'Connected to serial port with configuration:', { | ||||
|                 baudRate: this.baudRate, | ||||
|                 dataBits: this.dataBits, | ||||
|                 stopBits: this.stopBits, | ||||
|                 parity: this.parity, | ||||
|                 flowControl: this.flowControl, | ||||
|                 timeout: this.timeout | ||||
|             }); | ||||
|         } catch (error) { | ||||
|             TRACE_ERROR("mbrtu", 'Failed to open serial port:', error); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async openPort() { | ||||
|         await this.port.open({ | ||||
|             baudRate: this.baudRate, | ||||
|             dataBits: this.dataBits, | ||||
| @@ -23,21 +48,10 @@ class ModbusRTUMaster { | ||||
|         }); | ||||
|         this.reader = this.port.readable.getReader(); | ||||
|         this.writer = this.port.writable.getWriter(); | ||||
|             console.log('Connected to serial port with configuration:', { | ||||
|                 baudRate: this.baudRate, | ||||
|                 dataBits: this.dataBits, | ||||
|                 stopBits: this.stopBits, | ||||
|                 parity: this.parity, | ||||
|                 flowControl: this.flowControl, | ||||
|                 timeout: this.timeout | ||||
|             }); | ||||
|         } catch (error) { | ||||
|             console.error('Failed to open serial port:', error); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async disconnect() { | ||||
|         console.log('Disconnect requested'); | ||||
|         TRACE_ERROR("mbrtu", "Disconnect."); | ||||
|         try { | ||||
|             if (this.reader) { | ||||
|                 await this.reader.cancel(); | ||||
| @@ -51,13 +65,42 @@ class ModbusRTUMaster { | ||||
|             if (this.port) { | ||||
|                 await this.port.close(); | ||||
|                 this.port = null; | ||||
|                 console.log('Serial port closed'); | ||||
|                 TRACE_INFO("mbrtu", 'Serial port closed'); | ||||
|             } | ||||
|         } catch (error) { | ||||
|             console.error('Error during disconnect:', error); | ||||
|             TRACE_ERROR("mbrtu", 'Error during disconnect:', error); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async handleDeviceLost() { | ||||
|         TRACE_WARNING("mbrtu", 'Attempting to reconnect...'); | ||||
|         await this.disconnect(); | ||||
|         this.reconnect(); | ||||
|     } | ||||
|  | ||||
|     reconnect() { | ||||
|         setTimeout(async () => { | ||||
|             try { | ||||
|                 const ports = await navigator.serial.getPorts(); | ||||
|                 if (ports.length > 0) { | ||||
|                     this.port = ports[0]; | ||||
|                     if (!this.port.readable && !this.port.writable) { | ||||
|                         await this.openPort(); | ||||
|                         TRACE_INFO("mbrtu", 'Reconnected to serial port.'); | ||||
|                     } else { | ||||
|                         TRACE_WARNING("mbrtu", 'Port is already open. Skipping open operation.'); | ||||
|                     } | ||||
|                 } else { | ||||
|                     TRACE_WARNING("mbrtu", 'Port not found, retrying...'); | ||||
|                     this.reconnect(); | ||||
|                 } | ||||
|             } catch (error) { | ||||
|                 TRACE_ERROR("mbrtu", 'Reconnect failed:', error); | ||||
|                 this.reconnect(); | ||||
|             } | ||||
|         }, 1000); // Retry every 1 second | ||||
|     } | ||||
|  | ||||
|     async readHoldingRegisters(slaveId, startAddress, quantity) { | ||||
|         const response = await this.readRegisters(slaveId, 0x03, startAddress, quantity); | ||||
|         return this.parseRegisterValues(response, quantity); | ||||
| @@ -85,6 +128,7 @@ class ModbusRTUMaster { | ||||
|         } | ||||
|  | ||||
|         const request = this.buildRequest(slaveId, functionCode, startAddress, quantity); | ||||
|         TRACE_VERBOSE("mbrtu", "Send request"); | ||||
|         await this.sendRequest(request); | ||||
|         return await this.receiveResponse(slaveId, functionCode, quantity); | ||||
|     } | ||||
| @@ -121,12 +165,10 @@ class ModbusRTUMaster { | ||||
|  | ||||
|     async sendRequest(request) { | ||||
|         await this.writer.write(request); | ||||
|         //console.log('Request sent:', request); | ||||
|         TRACE_VERBOSE("mbrtu", 'Request sent:', request); | ||||
|     } | ||||
|  | ||||
|     // Receiving and validating response with timeout detection and Modbus Exception Codes processing | ||||
|     async receiveResponse(slaveId, functionCode, quantity) { | ||||
|         // Set the expected length of the response (slaveId, functionCode, byte count, data, CRC) | ||||
|         let expectedLength = 5 + quantity * 2; | ||||
|         let response = new Uint8Array(expectedLength); | ||||
|         let index = 0; | ||||
| @@ -140,9 +182,8 @@ class ModbusRTUMaster { | ||||
|                         response.set(value, index); | ||||
|                         index += value.length; | ||||
|  | ||||
|                         // If an exception is detected (highest bit of the function code), set the length to 5 bytes (slaveId, functionCode, exceptionCode, CRC) | ||||
|                         if (index >= 2 && (response[1] & 0x80)) { | ||||
|                             expectedLength = 5; // Override expected length in case of an exception | ||||
|                             expectedLength = 5; | ||||
|                         } | ||||
|                     } | ||||
|                 })(), | ||||
| @@ -151,25 +192,23 @@ class ModbusRTUMaster { | ||||
|                 ) | ||||
|             ]); | ||||
|  | ||||
|             // Modbus Exception Codes processing | ||||
|             if (response[1] & 0x80) { // Check if the highest bit of the function code is set | ||||
|             if (response[1] & 0x80) { | ||||
|                 const exceptionCode = response[2]; | ||||
|                 throw new Error(`Modbus Exception Code: ${this.getExceptionMessage(exceptionCode)} (Code: ${exceptionCode})`); | ||||
|             } | ||||
|  | ||||
|             // Check CRC after receiving the full response | ||||
|             const dataWithoutCRC = response.slice(0, index - 2); | ||||
|             const receivedCRC = (response[index - 1] << 8) | response[index - 2]; | ||||
|             const calculatedCRC = this.calculateCRC(dataWithoutCRC); | ||||
|  | ||||
|             if (calculatedCRC === receivedCRC) { | ||||
|                 //console.log('Received response with valid CRC:', response.slice(0, index)); | ||||
|                 TRACE_VERBOSE("mbrtu", 'Received response with valid CRC:', response.slice(0, index)); | ||||
|                 return response.slice(0, index); | ||||
|             } else { | ||||
|                 throw new Error(`CRC Error: Calculated CRC ${calculatedCRC} does not match received CRC ${receivedCRC}.`); | ||||
|             } | ||||
|         } catch (error) { | ||||
|             console.error('Error receiving response:', error.message); | ||||
|             TRACE_ERROR("mbrtu", 'Error receiving response:', error.message); | ||||
|             if (this.reader) { | ||||
|                 await this.reader.cancel(); | ||||
|                 await this.reader.releaseLock(); | ||||
| @@ -179,16 +218,10 @@ class ModbusRTUMaster { | ||||
|             if (error.message.includes('Device has been lost')) { | ||||
|                 await this.handleDeviceLost(); | ||||
|             } | ||||
|             return { error: error.message }; // TODO: or throw error; ? | ||||
|             throw error; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async handleDeviceLost() { | ||||
|         console.warn('Attempting to reconnect...'); | ||||
|         await this.disconnect(); | ||||
|         await this.connect(); | ||||
|     } | ||||
|  | ||||
|     getExceptionMessage(code) { | ||||
|         const exceptionMessages = { | ||||
|             1: 'Illegal Function', | ||||
|   | ||||
		Reference in New Issue
	
	Block a user