From 77f1c3c99ff854569cdaf75feb8da8537fe2938a Mon Sep 17 00:00:00 2001 From: travis-farmer Date: Wed, 11 Dec 2024 14:21:04 -0500 Subject: [PATCH] first prototype EX-MB-ioexpander, CS side --- IO_Modbus.cpp | 25 ++--- IO_Modbus.h | 249 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 235 insertions(+), 39 deletions(-) diff --git a/IO_Modbus.cpp b/IO_Modbus.cpp index f7b0b22..b637e55 100644 --- a/IO_Modbus.cpp +++ b/IO_Modbus.cpp @@ -550,13 +550,13 @@ void Modbus::_loop(unsigned long currentMicros) { if (error != MODBUS_RTU_MASTER_SUCCESS && (error != MODBUS_RTU_MASTER_WAITING || _waitCounter > 2)) flagOK = false; break; case 2: - error = readDiscreteInputs(_currentNode->getNodeID(), 0, (int*) _currentNode->discreteInputs, _currentNode->getNumDiscreteInputs()); - if (error != MODBUS_RTU_MASTER_SUCCESS && error != MODBUS_RTU_MASTER_WAITING) DIAG(F("ModbusDI: T%d F%d N%d %s"), _currentNode->getNodeID(), 0, _currentNode->getNumDiscreteInputs(), errorStrings[error]); + error = readInputRegisters(_currentNode->getNodeID(), 0, (uint16_t*) _currentNode->inputRegisters, _currentNode->getNumInputRegisters()); + if (error != MODBUS_RTU_MASTER_SUCCESS && error != MODBUS_RTU_MASTER_WAITING) DIAG(F("ModbusIR: T%d F%d N%d %s"), _currentNode->getNodeID(), 0, _currentNode->getNumInputRegisters(), errorStrings[error]); if (error != MODBUS_RTU_MASTER_SUCCESS && (error != MODBUS_RTU_MASTER_WAITING || _waitCounter > 2)) flagOK = false; break; case 3: - error = readInputRegisters(_currentNode->getNodeID(), 0, (uint16_t*) _currentNode->inputRegisters, _currentNode->getNumInputRegisters()); - if (error != MODBUS_RTU_MASTER_SUCCESS && error != MODBUS_RTU_MASTER_WAITING) DIAG(F("ModbusIR: T%d F%d N%d %s"), _currentNode->getNodeID(), 0, _currentNode->getNumInputRegisters(), errorStrings[error]); + error = readDiscreteInputs(_currentNode->getNodeID(), 0, (int*) _currentNode->discreteInputs, _currentNode->getNumDiscreteInputs()); + if (error != MODBUS_RTU_MASTER_SUCCESS && error != MODBUS_RTU_MASTER_WAITING) DIAG(F("ModbusDI: T%d F%d N%d %s"), _currentNode->getNodeID(), 0, _currentNode->getNumDiscreteInputs(), errorStrings[error]); if (error != MODBUS_RTU_MASTER_SUCCESS && (error != MODBUS_RTU_MASTER_WAITING || _waitCounter > 2)) flagOK = false; break; } @@ -572,6 +572,7 @@ void Modbus::_loop(unsigned long currentMicros) { _waitCounter = 0; _waitCounterB = 0; _operationCount = 0; + _currentNode = _currentNode->getNext(); } } else { @@ -584,6 +585,7 @@ void Modbus::_loop(unsigned long currentMicros) { _operationCount++; // improve error recovery... } else { _operationCount = 0; + _currentNode->procData(); _currentNode = _currentNode->getNext(); } } @@ -616,25 +618,12 @@ Modbus *Modbus::_busList = NULL; ************************************************************/ // Constructor for Modbusnode object -Modbusnode::Modbusnode(VPIN firstVpin, int nPins, uint8_t busNo, uint8_t nodeID, uint8_t numCoils, uint8_t numDiscreteInputs, uint8_t numHoldingRegisters, uint8_t numInputRegisters) { +Modbusnode::Modbusnode(VPIN firstVpin, int nPins, uint8_t busNo, uint8_t nodeID) { _firstVpin = firstVpin; _nPins = nPins; _busNo = busNo; _nodeID = nodeID; - _numCoils = numCoils; - _numDiscreteInputs = numDiscreteInputs; - _numHoldingRegisters = numHoldingRegisters; - _numInputRegisters = numInputRegisters; - - if ((unsigned int)_nPins < numDiscreteInputs + numCoils) - DIAG(F("Modbusnode: bus:%d nodeID:%d WARNING number of Vpins does not cover all inputs and outputs"), _busNo, _nodeID); - - if (!discreteInputs || !coils) { - DIAG(F("Modbusnode: ERROR insufficient memory")); - return; - } - // Add this device to HAL device list IODevice::addDevice(this); _display(); diff --git a/IO_Modbus.h b/IO_Modbus.h index d0f4779..6eb2fbb 100644 --- a/IO_Modbus.h +++ b/IO_Modbus.h @@ -163,20 +163,76 @@ private: char _type; Modbusnode *_next = NULL; bool _initialised = false; - uint8_t _numCoils; - uint8_t _numDiscreteInputs; - uint8_t _numHoldingRegisters; - uint8_t _numInputRegisters; - -public: - static void create(VPIN firstVpin, int nPins, uint8_t busNo, uint8_t nodeID, uint8_t numCoils=0, uint8_t numDiscreteInputs=0, uint8_t numHoldingRegisters=0, uint8_t numInputRegisters=0) { - if (checkNoOverlap(firstVpin, nPins)) new Modbusnode(firstVpin, nPins, busNo, nodeID, numCoils, numDiscreteInputs, numHoldingRegisters, numInputRegisters); + static const uint8_t _numCoils=100; + static const uint8_t _numDiscreteInputs=100; + static const uint8_t _numHoldingRegisters=100; + static const uint8_t _numInputRegisters=100; + uint8_t _numBO=0; + uint8_t _numBI=0; + uint8_t _numAO=0; + uint8_t _numAI=0; + int dataBO[16]; + int dataBI[16]; + int dataAO[84]; + int dataAI[84]; + int capePinsBI[16]; + int capePinsBO[16]; + int capePinsPU[16]; + int capePinsAO[16]; + int capePinsAI[16]; + int configBPinsO[16]; + int configBPinsI[16]; + int configBPinsPU[16]; + int configAPinsO[16]; + int configAPinsI[16]; + + void resetInit() { + for (int i = 0; i < 16; i++) { + capePinsBI[i] = 0; + capePinsBO[i] = 0; + capePinsPU[i] = 0; + capePinsAO[i] = 0; + capePinsAI[i] = 0; + configBPinsO[i] = 0; + configBPinsI[i] = 0; + configBPinsPU[i] = 0; + configAPinsO[i] = 0; + configAPinsI[i] = 0; + } } - Modbusnode(VPIN firstVpin, int nPins, uint8_t busNo, uint8_t nodeID, uint8_t numCoils, uint8_t numDiscreteInputs, uint8_t numHoldingRegisters, uint8_t numInputRegisters); - int *coils[100]; - int *discreteInputs[100]; - uint16_t *holdingRegisters[100]; - uint16_t *inputRegisters[100]; + + + + void spitError(int pin) { + bool isBI = false; + bool isBO = false; + bool isPU = false; + bool isAI = false; + bool isAO = false; + int configPinNum = pin / 16; + int configPinBit = pin % 16; + if (bitRead(configBPinsI[configPinNum],configPinBit) == true) isBI = true; + if (bitRead(configBPinsO[configPinNum],configPinBit) == true) isBO = true; + if (bitRead(configBPinsPU[configPinNum],configPinBit) == true) isPU = true; + if (bitRead(configAPinsI[configPinNum],configPinBit) == true) isAI = true; + if (bitRead(configAPinsO[configPinNum],configPinBit) == true) isAO = true; + if (isBI && isPU) DIAG(F("IO_Modbus config eror: Bool Input with pull-up, pin: %d"),pin); + if (isBI && !isPU) DIAG(F("IO_Modbus config eror: Bool Input without pull-up, pin: %d"),pin); + if (isBO) DIAG(F("IO_Modbus config eror: Bool Output, pin: %d"),pin); + if (isAI) DIAG(F("IO_Modbus config eror: Analog Input, pin: %d"),pin); + if (isAO) DIAG(F("IO_Modbus config eror: Analog Output, pin: %d"),pin); + + } + +public: + static void create(VPIN firstVpin, int nPins, uint8_t busNo, uint8_t nodeID) { + if (checkNoOverlap(firstVpin, nPins)) new Modbusnode(firstVpin, nPins, busNo, nodeID); + } + Modbusnode(VPIN firstVpin, int nPins, uint8_t busNo, uint8_t nodeID); + int *coils[_numCoils]; + int *discreteInputs[_numDiscreteInputs]; + uint16_t *holdingRegisters[_numHoldingRegisters]; + uint16_t *inputRegisters[_numInputRegisters]; uint8_t getNodeID() { return _nodeID; @@ -193,6 +249,8 @@ public: uint8_t getNumInputRegisters() { return _numInputRegisters; } + + Modbusnode *getNext() { return _next; } @@ -206,33 +264,181 @@ public: _initialised = true; } + bool addPinBI(VPIN vpin, bool inputPullup) { + int configPinNum = vpin / 16; + int configPinBit = vpin % 16; + bitSet(configBPinsI[configPinNum],configPinBit); // input + bitWrite(configBPinsPU[configPinNum],configPinBit,inputPullup); + if (_numBI + _numBO + _numAI + _numAO > _nPins) { + DIAG(F("IO_Modbus config error: Too many I/O pins vs VPINs: %d"),_numBI + _numBO + _numAI + _numAO); + return true; + } + _numBI++; + return false; + } + + bool addPinBO(VPIN vpin) { + int configPinNum = vpin / 16; + int configPinBit = vpin % 16; + bitSet(configBPinsO[configPinNum],configPinBit); // input + if (_numBI + _numBO + _numAI + _numAO > _nPins) { + DIAG(F("IO_Modbus config error: Too many I/O pins vs VPINs: %d"),_numBI + _numBO + _numAI + _numAO); + return true; + } + _numBO++; + return false; + } + + bool addPinAI(VPIN vpin) { + int configPinNum = vpin / 6; + int configPinBit = vpin % 16; + bitSet(configAPinsI[configPinNum],configPinBit); // input + if (_numBI + _numBO + _numAI + _numAO > _nPins) { + DIAG(F("IO_Modbus config error: Too many I/O pins vs VPINs: %d"),_numBI + _numBO + _numAI + _numAO); + return true; + } + _numAI++; + return false; + } + + bool addPinAO(VPIN vpin) { + int configPinNum = vpin / 6; + int configPinBit = vpin % 16; + bitSet(configAPinsO[configPinNum],configPinBit); // input + if (_numBI + _numBO + _numAI + _numAO > _nPins) { + DIAG(F("IO_Modbus config error: Too many I/O pins vs VPINs: %d"),_numBI + _numBO + _numAI + _numAO); + return true; + } + _numBI++; + return false; + } + + bool _configure(VPIN vpin, ConfigTypeEnum configType, int paramCount, int params[]) override { + byte arduinoPin = params[1]; + if (paramCount != 1) return false; + int pin = vpin - _firstVpin; + if (configType == CONFIGURE_INPUT) { + bool inputPullup = false; + if (params[2] == 1) inputPullup = true; + bool status = addPinBI(vpin,inputPullup); + if (status == false) { + return true; + } else + DIAG(F("IO_Modbus Vpin %u, Arduino Pin %d, cannot be used as a digital input pin"), (int)vpin, arduinoPin); + } else if (configType == CONFIGURE_OUTPUT) { + bool status = addPinBO(vpin); + if (status == false) { + return true; + } else + DIAG(F("IO_Modbus Vpin %u, Arduino Pin %d, cannot be used as a digital Output pin"), (int)vpin, arduinoPin); + } else if (configType == CONFIGURE_SERVO) { + //blah + } else if (configType == CONFIGURE_ANALOGOUTPUT) { + bool status = addPinAO(vpin); + if (status == false) { + return true; + } else + DIAG(F("IO_Modbus Vpin %u, Arduino Pin %d, cannot be used as a analog Output pin"), (int)vpin, arduinoPin); + } else if (configType == CONFIGURE_ANALOGINPUT) { + bool status = addPinAI(vpin); + if (status == false) { + return true; + } else + DIAG(F("IO_Modbus Vpin %u, Arduino Pin %d, cannot be used as a analog Input pin"), (int)vpin, arduinoPin); + } + return false; + } + void _begin() override { + resetInit(); + coils[0] = (int*) 1; // set config mode + coils[1] = (int*) 1; // set pull capabilities + _initialised = false; } + + + void procData() { + if (isInitialised()) { // read/write data + for (int i = 0; i < 16; i++) { + holdingRegisters[i] = (uint16_t*) dataBO[i]; + dataBI[i] = (int) inputRegisters[i]; + } + for (int i = 16; i < 84; i++) { + holdingRegisters[i] = (uint16_t*) dataAO[i]; + dataAI[i] = (int) inputRegisters[i]; + } + } else { // read/write config + if (discreteInputs[0] == (int*) 1 && discreteInputs[1] == (int*) 1){ // get capabilities + for (int i = 0; i < 16; i++) { // read capabilities params + capePinsBI[i] = (int) inputRegisters[i]; + capePinsBO[i] = (int) inputRegisters[i+16]; + capePinsPU[i] = (int) inputRegisters[i+32]; + capePinsAI[i] = (int) inputRegisters[i+48]; + capePinsAO[i] = (int) inputRegisters[i+64]; + } + coils[0] = (int*) 1; // config mode + coils[1] = (int*) 0; // exit cape mode + for (int i = 0; i < 16; i++) { // load config params + holdingRegisters[i] = (uint16_t*) configBPinsI[i]; + holdingRegisters[i+16] = (uint16_t*) configBPinsO[i]; + holdingRegisters[i+32] = (uint16_t*) configBPinsPU[i]; + holdingRegisters[i+48] = (uint16_t*) configAPinsI[i]; + holdingRegisters[i+64] = (uint16_t*) configAPinsO[i]; + } + } else if (discreteInputs[0] == (int*) 1 && discreteInputs[1] == (int*) 0) { + for (int i = 0; i < 16; i++) { + if (configBPinsI[i] != (int) inputRegisters[i]) spitError(i); + if (configBPinsO[i] != (int) inputRegisters[i+16]) spitError(i+16); + if (configBPinsPU[i] != (int) inputRegisters[i+32]) spitError(i+32); + if (configAPinsI[i] != (int) inputRegisters[i+48]) spitError(i+48); + if (configAPinsO[i] != (int) inputRegisters[i+64]) spitError(i+64); + } + // todo error checking and set failure mode + // for now, assume everything is fine, sort this out later if needed + coils[0] = (int*) 0; // exit config mode + coils[1] = (int*) 0; // not in cape mode + setInitialised(); + } + } + } + int _read(VPIN vpin) override { // Return current state from this device uint16_t pin = vpin - _firstVpin; - return (int) discreteInputs[pin]; + int PinNum = pin / 16; + int PinBit = pin % 16; + if (bitRead(configAPinsI[PinNum],PinBit) == true) return bitRead(dataBI[PinNum],PinBit)? 1:0; + else return 0; } void _write(VPIN vpin, int value) override { // Update current state for this device, in preparation the bus transmission - uint16_t pin = vpin - _firstVpin - _numDiscreteInputs; - if (value == 1) coils[pin] = (int*) 0x1; - if (value == 0) coils[pin] = (int*) 0x0; + uint16_t pin = vpin - _firstVpin; + int PinNum = pin / 16; + int PinBit = pin % 16; + if (bitRead(configAPinsO[PinNum], PinBit) == true) { + if (value == 1) bitSet(dataBO[PinNum], PinBit); + else bitClear(dataBO[PinNum], PinBit); + } } int _readAnalogue(VPIN vpin) { // Return acquired data value, e.g. - int pin = vpin - _firstVpin - _numDiscreteInputs - _numCoils; - return (int) inputRegisters[pin]; + uint16_t pin = vpin - _firstVpin; + int PinNum = pin / 16; + int PinBit = pin % 16; + if (bitRead(configAPinsI[PinNum],PinBit) == true) return dataAI[pin]; + else return 0; } void _writeAnalogue(VPIN vpin, int value) { - uint16_t pin = vpin - _firstVpin - _numDiscreteInputs - _numCoils - _numInputRegisters; - holdingRegisters[pin] = (uint16_t*) value; + uint16_t pin = vpin - _firstVpin; + int PinNum = pin / 16; + int PinBit = pin % 16; + if (bitRead(configAPinsI[PinNum],PinBit) == true) dataAO[pin] = value; } uint8_t getBusNumber() { @@ -380,6 +586,7 @@ public: return NULL; } + // Add new Modbusnode to the list of nodes for this bus. void addNode(Modbusnode *newNode) { if (!_nodeListStart)