mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2025-04-21 12:31:19 +02:00
first prototype EX-MB-ioexpander, CS side
This commit is contained in:
parent
3cb6a35dde
commit
77f1c3c99f
@ -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;
|
if (error != MODBUS_RTU_MASTER_SUCCESS && (error != MODBUS_RTU_MASTER_WAITING || _waitCounter > 2)) flagOK = false;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
error = readDiscreteInputs(_currentNode->getNodeID(), 0, (int*) _currentNode->discreteInputs, _currentNode->getNumDiscreteInputs());
|
error = readInputRegisters(_currentNode->getNodeID(), 0, (uint16_t*) _currentNode->inputRegisters, _currentNode->getNumInputRegisters());
|
||||||
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) 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;
|
if (error != MODBUS_RTU_MASTER_SUCCESS && (error != MODBUS_RTU_MASTER_WAITING || _waitCounter > 2)) flagOK = false;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
error = readInputRegisters(_currentNode->getNodeID(), 0, (uint16_t*) _currentNode->inputRegisters, _currentNode->getNumInputRegisters());
|
error = readDiscreteInputs(_currentNode->getNodeID(), 0, (int*) _currentNode->discreteInputs, _currentNode->getNumDiscreteInputs());
|
||||||
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) 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;
|
if (error != MODBUS_RTU_MASTER_SUCCESS && (error != MODBUS_RTU_MASTER_WAITING || _waitCounter > 2)) flagOK = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -572,6 +572,7 @@ void Modbus::_loop(unsigned long currentMicros) {
|
|||||||
_waitCounter = 0;
|
_waitCounter = 0;
|
||||||
_waitCounterB = 0;
|
_waitCounterB = 0;
|
||||||
_operationCount = 0;
|
_operationCount = 0;
|
||||||
|
|
||||||
_currentNode = _currentNode->getNext();
|
_currentNode = _currentNode->getNext();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -584,6 +585,7 @@ void Modbus::_loop(unsigned long currentMicros) {
|
|||||||
_operationCount++; // improve error recovery...
|
_operationCount++; // improve error recovery...
|
||||||
} else {
|
} else {
|
||||||
_operationCount = 0;
|
_operationCount = 0;
|
||||||
|
_currentNode->procData();
|
||||||
_currentNode = _currentNode->getNext();
|
_currentNode = _currentNode->getNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -616,24 +618,11 @@ Modbus *Modbus::_busList = NULL;
|
|||||||
************************************************************/
|
************************************************************/
|
||||||
|
|
||||||
// Constructor for Modbusnode object
|
// 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;
|
_firstVpin = firstVpin;
|
||||||
_nPins = nPins;
|
_nPins = nPins;
|
||||||
_busNo = busNo;
|
_busNo = busNo;
|
||||||
_nodeID = nodeID;
|
_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
|
// Add this device to HAL device list
|
||||||
IODevice::addDevice(this);
|
IODevice::addDevice(this);
|
||||||
|
245
IO_Modbus.h
245
IO_Modbus.h
@ -163,20 +163,76 @@ private:
|
|||||||
char _type;
|
char _type;
|
||||||
Modbusnode *_next = NULL;
|
Modbusnode *_next = NULL;
|
||||||
bool _initialised = false;
|
bool _initialised = false;
|
||||||
uint8_t _numCoils;
|
static const uint8_t _numCoils=100;
|
||||||
uint8_t _numDiscreteInputs;
|
static const uint8_t _numDiscreteInputs=100;
|
||||||
uint8_t _numHoldingRegisters;
|
static const uint8_t _numHoldingRegisters=100;
|
||||||
uint8_t _numInputRegisters;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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:
|
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) {
|
static void create(VPIN firstVpin, int nPins, uint8_t busNo, uint8_t nodeID) {
|
||||||
if (checkNoOverlap(firstVpin, nPins)) new Modbusnode(firstVpin, nPins, busNo, nodeID, numCoils, numDiscreteInputs, numHoldingRegisters, numInputRegisters);
|
if (checkNoOverlap(firstVpin, nPins)) new Modbusnode(firstVpin, nPins, busNo, nodeID);
|
||||||
}
|
}
|
||||||
Modbusnode(VPIN firstVpin, int nPins, uint8_t busNo, uint8_t nodeID, uint8_t numCoils, uint8_t numDiscreteInputs, uint8_t numHoldingRegisters, uint8_t numInputRegisters);
|
Modbusnode(VPIN firstVpin, int nPins, uint8_t busNo, uint8_t nodeID);
|
||||||
int *coils[100];
|
int *coils[_numCoils];
|
||||||
int *discreteInputs[100];
|
int *discreteInputs[_numDiscreteInputs];
|
||||||
uint16_t *holdingRegisters[100];
|
uint16_t *holdingRegisters[_numHoldingRegisters];
|
||||||
uint16_t *inputRegisters[100];
|
uint16_t *inputRegisters[_numInputRegisters];
|
||||||
|
|
||||||
uint8_t getNodeID() {
|
uint8_t getNodeID() {
|
||||||
return _nodeID;
|
return _nodeID;
|
||||||
@ -193,6 +249,8 @@ public:
|
|||||||
uint8_t getNumInputRegisters() {
|
uint8_t getNumInputRegisters() {
|
||||||
return _numInputRegisters;
|
return _numInputRegisters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Modbusnode *getNext() {
|
Modbusnode *getNext() {
|
||||||
return _next;
|
return _next;
|
||||||
}
|
}
|
||||||
@ -206,33 +264,181 @@ public:
|
|||||||
_initialised = true;
|
_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 {
|
void _begin() override {
|
||||||
|
resetInit();
|
||||||
|
coils[0] = (int*) 1; // set config mode
|
||||||
|
coils[1] = (int*) 1; // set pull capabilities
|
||||||
|
|
||||||
_initialised = false;
|
_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 {
|
int _read(VPIN vpin) override {
|
||||||
// Return current state from this device
|
// Return current state from this device
|
||||||
uint16_t pin = vpin - _firstVpin;
|
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 {
|
void _write(VPIN vpin, int value) override {
|
||||||
// Update current state for this device, in preparation the bus transmission
|
// Update current state for this device, in preparation the bus transmission
|
||||||
uint16_t pin = vpin - _firstVpin - _numDiscreteInputs;
|
uint16_t pin = vpin - _firstVpin;
|
||||||
if (value == 1) coils[pin] = (int*) 0x1;
|
int PinNum = pin / 16;
|
||||||
if (value == 0) coils[pin] = (int*) 0x0;
|
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) {
|
int _readAnalogue(VPIN vpin) {
|
||||||
// Return acquired data value, e.g.
|
// Return acquired data value, e.g.
|
||||||
int pin = vpin - _firstVpin - _numDiscreteInputs - _numCoils;
|
uint16_t pin = vpin - _firstVpin;
|
||||||
return (int) inputRegisters[pin];
|
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) {
|
void _writeAnalogue(VPIN vpin, int value) {
|
||||||
uint16_t pin = vpin - _firstVpin - _numDiscreteInputs - _numCoils - _numInputRegisters;
|
uint16_t pin = vpin - _firstVpin;
|
||||||
holdingRegisters[pin] = (uint16_t*) value;
|
int PinNum = pin / 16;
|
||||||
|
int PinBit = pin % 16;
|
||||||
|
if (bitRead(configAPinsI[PinNum],PinBit) == true) dataAO[pin] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getBusNumber() {
|
uint8_t getBusNumber() {
|
||||||
@ -380,6 +586,7 @@ public:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Add new Modbusnode to the list of nodes for this bus.
|
// Add new Modbusnode to the list of nodes for this bus.
|
||||||
void addNode(Modbusnode *newNode) {
|
void addNode(Modbusnode *newNode) {
|
||||||
if (!_nodeListStart)
|
if (!_nodeListStart)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user