From b8000fa788e3f1c0a2d864a0a42ef7a144072424 Mon Sep 17 00:00:00 2001 From: JeroenSt Date: Wed, 17 Aug 2022 19:55:42 +0200 Subject: [PATCH] Update for functioncode 5 and 6 and 15 --- .../TasmotaModbus-3.4.0/src/TasmotaModbus.cpp | 8 ++-- .../xdrv_63_modbus_bridge.ino | 48 +++++++++++++++---- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/lib/lib_basic/TasmotaModbus-3.4.0/src/TasmotaModbus.cpp b/lib/lib_basic/TasmotaModbus-3.4.0/src/TasmotaModbus.cpp index 483a20ad2..f543725a5 100644 --- a/lib/lib_basic/TasmotaModbus-3.4.0/src/TasmotaModbus.cpp +++ b/lib/lib_basic/TasmotaModbus-3.4.0/src/TasmotaModbus.cpp @@ -1,4 +1,4 @@ -/* + /* TasmotaModbus.cpp - Basic modbus wrapper for TasmotaSerial for Tasmota Copyright (C) 2021 Theo Arends @@ -60,13 +60,13 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1 uint8_t *frame; uint8_t framepointer = 0; - if (function_code < 5) + if (function_code < 7) { - frame = (uint8_t *)malloc(8); // Addres(1), Function(1), Start Address(2), Registercount (2) or Data(2), CRC(2) + frame = (uint8_t *)malloc(8); // Addres(1), Function(1), Start/Coil Address(2), Registercount or Data (2), CRC(2) } else { - frame = (uint8_t *)malloc(9 + (register_count * 2)); // Addres(1), Function(1), Start Address(2), Quantity of registers (2), Bytecount(1), Data(2..n), CRC(2) + frame = (uint8_t *)malloc(9 + (register_count * 2)); // Addres(1), Function(1), Start/Coil Address(2),Quantity of registers (2), Bytecount(1), Data(1..n), CRC(2) } mb_address = device_address; // Save address for receipt check diff --git a/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino b/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino index c63942e63..989b44f35 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino @@ -633,7 +633,7 @@ void CmndModbusBridgeSend(void) if (strcmp(stype, "int8") == 0) { modbusBridge.type = ModbusBridgeType::mb_int8; - modbusBridge.dataCount = modbusBridge.count; + modbusBridge.dataCount = ((modbusBridge.count - 1)/ 2) + 1; } else if (strcmp(stype, "int16") == 0) { @@ -648,7 +648,7 @@ void CmndModbusBridgeSend(void) else if ((strcmp(stype, "uint8") == 0)) { modbusBridge.type = ModbusBridgeType::mb_uint8; - modbusBridge.dataCount = modbusBridge.count; + modbusBridge.dataCount = ((modbusBridge.count - 1)/ 2) + 1; } else if ((strcmp(stype, "uint16") == 0) || (strcmp(stype, "") == 0)) // Default is uint16 { @@ -678,7 +678,7 @@ void CmndModbusBridgeSend(void) else if (strcmp(stype, "bit") == 0) { modbusBridge.type = ModbusBridgeType::mb_bit; - modbusBridge.dataCount = modbusBridge.count; + modbusBridge.dataCount = ((modbusBridge.count - 1) / 16) + 1; } else errorcode = ModbusBridgeError::wrongtype; @@ -704,23 +704,42 @@ void CmndModbusBridgeSend(void) } else { - // ToDo: Convert uint, int float etc. to writedata writeData = (uint16_t *)malloc(writeDataSize * 2); for (uint8_t jsonDataArrayPointer = 0; jsonDataArrayPointer < writeDataSize; jsonDataArrayPointer++) { switch (modbusBridge.type) { + case ModbusBridgeType::mb_bit: + { + AddLog(LOG_LEVEL_DEBUG, PSTR("jsonDataArrayPointer[%u]=%u"), (uint8_t)jsonDataArrayPointer, (uint8_t)jsonDataArray[jsonDataArrayPointer].getUInt(0)); + // Set 2 following bytes to 0 + if (jsonDataArrayPointer % 16 == 0) + { + writeData[jsonDataArrayPointer/15] = 0; + } + // Swap low and high bytes according to modbus specification + uint16_t bitValue = (jsonDataArray[jsonDataArrayPointer].getUInt(0) == 1) ? 1 : 0; + uint8_t bitPointer = (jsonDataArrayPointer % 15) + 8; + if (bitPointer > 15) bitPointer -= 16; + + writeData[jsonDataArrayPointer/15] += bitValue << bitPointer; + + AddLog(LOG_LEVEL_DEBUG, PSTR("writeDataPointer[%u]=%u bitPointer=[%u]=[%u]"), jsonDataArrayPointer/15, writeData[jsonDataArrayPointer/15], bitPointer, bitValue); + } + break; case ModbusBridgeType::mb_int8: - writeData[jsonDataArrayPointer] = (uint16_t)jsonDataArray[jsonDataArrayPointer].getInt(0); + if (jsonDataArrayPointer % 2) writeData[jsonDataArrayPointer / 2] += (int8_t)jsonDataArray[jsonDataArrayPointer].getInt(0); + else writeData[jsonDataArrayPointer] = (int8_t)jsonDataArray[jsonDataArrayPointer / 2].getInt(0) << 8; break; case ModbusBridgeType::mb_uint8: - writeData[jsonDataArrayPointer] = (uint16_t)jsonDataArray[jsonDataArrayPointer].getUInt(0); + if (jsonDataArrayPointer % 2) writeData[jsonDataArrayPointer / 2] += (uint8_t)jsonDataArray[jsonDataArrayPointer].getInt(0); + else writeData[jsonDataArrayPointer / 2] = (uint8_t)jsonDataArray[jsonDataArrayPointer].getInt(0) << 8; break; case ModbusBridgeType::mb_int16: - writeData[jsonDataArrayPointer] = (uint16_t)jsonDataArray[jsonDataArrayPointer].getInt(0); + writeData[jsonDataArrayPointer] = (int16_t)jsonDataArray[jsonDataArrayPointer].getInt(0); break; case ModbusBridgeType::mb_uint16: - writeData[jsonDataArrayPointer] = (int16_t)jsonDataArray[jsonDataArrayPointer].getUInt(0); + writeData[jsonDataArrayPointer] = (uint16_t)jsonDataArray[jsonDataArrayPointer].getUInt(0); break; case ModbusBridgeType::mb_float: // TODO @@ -740,6 +759,9 @@ void CmndModbusBridgeSend(void) case ModbusBridgeType::mb_hex: writeData[jsonDataArrayPointer] = (uint8_t)jsonDataArray[jsonDataArrayPointer*2].getUInt(0) << 8 + (uint8_t)jsonDataArray[(jsonDataArrayPointer*2)+1].getUInt(0); break; + default: + errorcode = ModbusBridgeError::wrongtype; + break; } } } @@ -754,6 +776,16 @@ void CmndModbusBridgeSend(void) return; } + // Adapt data according to modbus protocol + for (uint8_t writeDataPointer = 0; writeDataPointer < modbusBridge.dataCount; writeDataPointer++) + { + // For function code 5, on and off are 0xFF00 and 0x0000, not 1 and 0 + if (modbusBridge.functionCode == ModbusBridgeFunctionCode::mb_writeSingleCoil) + { + writeData[writeDataPointer] = writeData[writeDataPointer] ? 0xFF00 : 0x0000; + } + } + // If writing a single coil or single register, the register count is always 1. We also prevent writing data out of range if ((modbusBridge.functionCode == ModbusBridgeFunctionCode::mb_writeSingleCoil) || (modbusBridge.functionCode == ModbusBridgeFunctionCode::mb_writeSingleRegister)) modbusBridge.dataCount = 1;