Исправления

This commit is contained in:
Tutukov Beslan
2021-11-12 07:10:36 +03:00
parent a10d3d7420
commit 461e8fdbdb
4 changed files with 499 additions and 437 deletions

View File

@@ -11,12 +11,12 @@ std::vector<TRegister> _regs;
std::vector<TCallback> _callbacks; std::vector<TCallback> _callbacks;
#endif #endif
uint16_t Modbus::mbCallback(TRegister* reg, uint16_t val, TCallback::CallbackType t) uint16_t Modbus::mbCallback(TRegister *reg, uint16_t val, TCallback::CallbackType t) {
{
uint16_t newVal = val; uint16_t newVal = val;
std::vector<TCallback>::iterator it = _callbacks.begin(); auto it = _callbacks.begin();
do { do {
it = std::find_if(it, _callbacks.end(), [reg, t](TCallback& cb) { return cb.address == reg->address && cb.type == t; }); it = std::find_if(it, _callbacks.end(),
[reg, t](TCallback &cb) { return cb.address == reg->address && cb.type == t; });
if (it != _callbacks.end()) { if (it != _callbacks.end()) {
newVal = it->cb(reg, newVal); newVal = it->cb(reg, newVal);
it++; it++;
@@ -25,31 +25,28 @@ uint16_t Modbus::mbCallback(TRegister* reg, uint16_t val, TCallback::CallbackTyp
return newVal; return newVal;
} }
TRegister* Modbus::searchRegister(TAddress address) TRegister *Modbus::searchRegister(TAddress address) {
{ auto it = std::find_if(_regs.begin(), _regs.end(), [address](TRegister &addr) { return addr.address == address; });
std::vector<TRegister>::iterator it = std::find_if(_regs.begin(), _regs.end(), [address](TRegister& addr) { return addr.address == address; });
if (it != _regs.end()) if (it != _regs.end())
return &*it; return &*it;
return nullptr; return nullptr;
} }
bool Modbus::addReg(TAddress address, uint16_t value, uint16_t numregs) bool Modbus::addReg(TAddress address, uint16_t value, uint16_t numregs) {
{
#ifdef MB_MAX_REGS #ifdef MB_MAX_REGS
if (_regs.size() + numregs > MB_MAX_REGS) if (_regs.size() + numregs > MB_MAX_REGS)
return false; return false;
#endif #endif
for (uint16_t i = 0; i < numregs; i++) { for (uint16_t i = 0; i < numregs; i++) {
if (!searchRegister(address + i)) if (!searchRegister(address + i))
_regs.push_back({ address + i, value }); _regs.push_back({address + i, value});
} }
//std::sort(_regs.begin(), _regs.end()); //std::sort(_regs.begin(), _regs.end());
return true; return true;
} }
bool Modbus::Reg(TAddress address, uint16_t value) bool Modbus::Reg(TAddress address, uint16_t value) {
{ TRegister *reg;
TRegister* reg;
reg = searchRegister(address); //search for the register address reg = searchRegister(address); //search for the register address
if (reg) { //if found then assign the register value to the new value. if (reg) { //if found then assign the register value to the new value.
if (cbEnabled) { if (cbEnabled) {
@@ -62,9 +59,8 @@ bool Modbus::Reg(TAddress address, uint16_t value)
return false; return false;
} }
uint16_t Modbus::Reg(TAddress address) uint16_t Modbus::Reg(TAddress address) {
{ TRegister *reg;
TRegister* reg;
reg = searchRegister(address); reg = searchRegister(address);
if (reg) if (reg)
if (cbEnabled) { if (cbEnabled) {
@@ -76,9 +72,8 @@ uint16_t Modbus::Reg(TAddress address)
return 0; return 0;
} }
bool Modbus::removeReg(TAddress address, uint16_t numregs) bool Modbus::removeReg(TAddress address, uint16_t numregs) {
{ TRegister *reg;
TRegister* reg;
bool atLeastOne = false; bool atLeastOne = false;
for (uint16_t i = 0; i < numregs; i++) { for (uint16_t i = 0; i < numregs; i++) {
reg = searchRegister(address + i); reg = searchRegister(address + i);
@@ -92,115 +87,114 @@ bool Modbus::removeReg(TAddress address, uint16_t numregs)
return atLeastOne; return atLeastOne;
} }
void Modbus::slavePDU(uint8_t* frame) void Modbus::slavePDU(uint8_t *frame) {
{ auto fcode = (FunctionCode) frame[0];
FunctionCode fcode = (FunctionCode)frame[0]; uint16_t field1 = (uint16_t) frame[1] << 8 | (uint16_t) frame[2];
uint16_t field1 = (uint16_t)frame[1] << 8 | (uint16_t)frame[2]; uint16_t field2 = (uint16_t) frame[3] << 8 | (uint16_t) frame[4];
uint16_t field2 = (uint16_t)frame[3] << 8 | (uint16_t)frame[4];
uint16_t bytecount_calc; uint16_t bytecount_calc;
uint16_t k; uint16_t k;
switch (fcode) { switch (fcode) {
case FC_WRITE_REG: case FC_WRITE_REG:
//field1 = reg, field2 = value //field1 = reg, field2 = value
if (!Hreg(field1, field2)) { //Check Address and execute (reg exists?) if (!Hreg(field1, field2)) { //Check Address and execute (reg exists?)
exceptionResponse(fcode, EX_ILLEGAL_ADDRESS);
break;
}
if (Hreg(field1) != field2) { //Check for failure
exceptionResponse(fcode, EX_SLAVE_FAILURE);
break;
}
_reply = REPLY_ECHO;
break;
case FC_READ_REGS:
//field1 = startreg, field2 = numregs, header len = 3
readWords(HREG(field1), field2, fcode);
break;
case FC_WRITE_REGS:
//field1 = startreg, field2 = numregs, frame[5] = data lenght, header len = 6
if (field2 < 0x0001 || field2 > 0x007B || frame[5] != 2 * field2) { //Check value
exceptionResponse(fcode, EX_ILLEGAL_VALUE);
break;
}
for (k = 0; k < field2; k++) { //Check Address (startreg...startreg + numregs)
if (!searchRegister(HREG(field1) + k)) {
exceptionResponse(fcode, EX_ILLEGAL_ADDRESS); exceptionResponse(fcode, EX_ILLEGAL_ADDRESS);
break; break;
} }
} if (Hreg(field1) != field2) { //Check for failure
if (k >= field2) { exceptionResponse(fcode, EX_SLAVE_FAILURE);
setMultipleWords((uint16_t*)(frame + 6), HREG(field1), field2); break;
successResponce(HREG(field1), field2, fcode); }
_reply = REPLY_NORMAL; _reply = REPLY_ECHO;
}
break;
case FC_READ_COILS:
//field1 = startreg, field2 = numregs
readBits(COIL(field1), field2, fcode);
break;
case FC_READ_INPUT_STAT:
//field1 = startreg, field2 = numregs
readBits(ISTS(field1), field2, fcode);
break;
case FC_READ_INPUT_REGS:
//field1 = startreg, field2 = numregs
readWords(IREG(field1), field2, fcode);
break;
case FC_WRITE_COIL:
//field1 = reg, field2 = status, header len = 3
if (field2 != 0xFF00 && field2 != 0x0000) { //Check value (status)
exceptionResponse(fcode, EX_ILLEGAL_VALUE);
break; break;
}
if (!Coil(field1, COIL_BOOL(field2))) { //Check Address and execute (reg exists?)
exceptionResponse(fcode, EX_ILLEGAL_ADDRESS);
break;
}
if (Coil(field1) != COIL_BOOL(field2)) { //Check for failure
exceptionResponse(fcode, EX_SLAVE_FAILURE);
break;
}
_reply = REPLY_ECHO;
break;
case FC_WRITE_COILS: case FC_READ_REGS:
//field1 = startreg, field2 = numregs, frame[5] = bytecount, header len = 6 //field1 = startreg, field2 = numregs, header len = 3
bytecount_calc = field2 / 8; readWords(HREG(field1), field2, fcode);
if (field2 % 8)
bytecount_calc++;
if (field2 < 0x0001 || field2 > 0x07B0 || frame[5] != bytecount_calc) { //Check registers range and data size maches
exceptionResponse(fcode, EX_ILLEGAL_VALUE);
break; break;
}
for (k = 0; k < field2; k++) { //Check Address (startreg...startreg + numregs) case FC_WRITE_REGS:
if (!searchRegister(COIL(field1) + k)) { //field1 = startreg, field2 = numregs, frame[5] = data lenght, header len = 6
if (field2 < 0x0001 || field2 > 0x007B || frame[5] != 2 * field2) { //Check value
exceptionResponse(fcode, EX_ILLEGAL_VALUE);
break;
}
for (k = 0; k < field2; k++) { //Check Address (startreg...startreg + numregs)
if (!searchRegister(HREG(field1) + k)) {
exceptionResponse(fcode, EX_ILLEGAL_ADDRESS);
break;
}
}
if (k >= field2) {
setMultipleWords((uint16_t *) (frame + 6), HREG(field1), field2);
successResponce(HREG(field1), field2, fcode);
_reply = REPLY_NORMAL;
}
break;
case FC_READ_COILS:
//field1 = startreg, field2 = numregs
readBits(COIL(field1), field2, fcode);
break;
case FC_READ_INPUT_STAT:
//field1 = startreg, field2 = numregs
readBits(ISTS(field1), field2, fcode);
break;
case FC_READ_INPUT_REGS:
//field1 = startreg, field2 = numregs
readWords(IREG(field1), field2, fcode);
break;
case FC_WRITE_COIL:
//field1 = reg, field2 = status, header len = 3
if (field2 != 0xFF00 && field2 != 0x0000) { //Check value (status)
exceptionResponse(fcode, EX_ILLEGAL_VALUE);
break;
}
if (!Coil(field1, COIL_BOOL(field2))) { //Check Address and execute (reg exists?)
exceptionResponse(fcode, EX_ILLEGAL_ADDRESS); exceptionResponse(fcode, EX_ILLEGAL_ADDRESS);
break; break;
} }
} if (Coil(field1) != COIL_BOOL(field2)) { //Check for failure
if (k >= field2) { exceptionResponse(fcode, EX_SLAVE_FAILURE);
setMultipleBits(frame + 6, COIL(field1), field2); break;
successResponce(COIL(field1), field2, fcode); }
_reply = REPLY_NORMAL; _reply = REPLY_ECHO;
} break;
break;
default: case FC_WRITE_COILS:
exceptionResponse(fcode, EX_ILLEGAL_FUNCTION); //field1 = startreg, field2 = numregs, frame[5] = bytecount, header len = 6
bytecount_calc = field2 / 8;
if (field2 % 8)
bytecount_calc++;
if (field2 < 0x0001 || field2 > 0x07B0 ||
frame[5] != bytecount_calc) { //Check registers range and data size maches
exceptionResponse(fcode, EX_ILLEGAL_VALUE);
break;
}
for (k = 0; k < field2; k++) { //Check Address (startreg...startreg + numregs)
if (!searchRegister(COIL(field1) + k)) {
exceptionResponse(fcode, EX_ILLEGAL_ADDRESS);
break;
}
}
if (k >= field2) {
setMultipleBits(frame + 6, COIL(field1), field2);
successResponce(COIL(field1), field2, fcode);
_reply = REPLY_NORMAL;
}
break;
default:
exceptionResponse(fcode, EX_ILLEGAL_FUNCTION);
} }
} }
void Modbus::successResponce(TAddress startreg, uint16_t numoutputs, FunctionCode fn) void Modbus::successResponce(TAddress startreg, uint16_t numoutputs, FunctionCode fn) {
{
free(_frame); free(_frame);
_len = 5; _len = 5;
_frame = (uint8_t*)malloc(_len); _frame = (uint8_t *) malloc(_len);
_frame[0] = fn; _frame[0] = fn;
_frame[1] = startreg.address >> 8; _frame[1] = startreg.address >> 8;
_frame[2] = startreg.address & 0x00FF; _frame[2] = startreg.address & 0x00FF;
@@ -208,18 +202,16 @@ void Modbus::successResponce(TAddress startreg, uint16_t numoutputs, FunctionCod
_frame[4] = numoutputs & 0x00FF; _frame[4] = numoutputs & 0x00FF;
} }
void Modbus::exceptionResponse(FunctionCode fn, ResultCode excode) void Modbus::exceptionResponse(FunctionCode fn, ResultCode excode) {
{
free(_frame); free(_frame);
_len = 2; _len = 2;
_frame = (uint8_t*)malloc(_len); _frame = (uint8_t *) malloc(_len);
_frame[0] = fn + 0x80; _frame[0] = fn + 0x80;
_frame[1] = excode; _frame[1] = excode;
_reply = REPLY_NORMAL; _reply = REPLY_NORMAL;
} }
void Modbus::getMultipleBits(uint8_t* frame, TAddress startreg, uint16_t numregs) void Modbus::getMultipleBits(uint8_t *frame, TAddress startreg, uint16_t numregs) {
{
uint8_t bitn = 0; uint8_t bitn = 0;
uint16_t i = 0; uint16_t i = 0;
while (numregs--) { while (numregs--) {
@@ -236,15 +228,13 @@ void Modbus::getMultipleBits(uint8_t* frame, TAddress startreg, uint16_t numregs
} }
} }
void Modbus::getMultipleWords(uint16_t* frame, TAddress startreg, uint16_t numregs) void Modbus::getMultipleWords(uint16_t *frame, TAddress startreg, uint16_t numregs) {
{ for (uint16_t i = 0; i < numregs; i++) {
for (uint8_t i = 0; i < numregs; i++) {
frame[i] = __bswap_16(Reg(startreg + i)); frame[i] = __bswap_16(Reg(startreg + i));
} }
} }
void Modbus::readBits(TAddress startreg, uint16_t numregs, FunctionCode fn) void Modbus::readBits(TAddress startreg, uint16_t numregs, FunctionCode fn) {
{
if (numregs < 0x0001 || numregs > 0x07D0) { //Check value (numregs) if (numregs < 0x0001 || numregs > 0x07D0) { //Check value (numregs)
exceptionResponse(fn, EX_ILLEGAL_VALUE); exceptionResponse(fn, EX_ILLEGAL_VALUE);
return; return;
@@ -264,7 +254,7 @@ void Modbus::readBits(TAddress startreg, uint16_t numregs, FunctionCode fn)
_len = 2 + numregs / 8; _len = 2 + numregs / 8;
if (numregs % 8) if (numregs % 8)
_len++; //Add 1 to the message length for the partial byte. _len++; //Add 1 to the message length for the partial byte.
_frame = (uint8_t*)malloc(_len); _frame = (uint8_t *) malloc(_len);
if (!_frame) { if (!_frame) {
exceptionResponse(fn, EX_SLAVE_FAILURE); exceptionResponse(fn, EX_SLAVE_FAILURE);
return; return;
@@ -276,8 +266,7 @@ void Modbus::readBits(TAddress startreg, uint16_t numregs, FunctionCode fn)
_reply = REPLY_NORMAL; _reply = REPLY_NORMAL;
} }
void Modbus::readWords(TAddress startreg, uint16_t numregs, FunctionCode fn) void Modbus::readWords(TAddress startreg, uint16_t numregs, FunctionCode fn) {
{
//Check value (numregs) //Check value (numregs)
if (numregs < 0x0001 || numregs > 0x007D) { if (numregs < 0x0001 || numregs > 0x007D) {
exceptionResponse(fn, EX_ILLEGAL_VALUE); exceptionResponse(fn, EX_ILLEGAL_VALUE);
@@ -289,19 +278,18 @@ void Modbus::readWords(TAddress startreg, uint16_t numregs, FunctionCode fn)
} }
free(_frame); free(_frame);
_len = 2 + numregs * 2; //calculate the query reply message length. 2 bytes per register + 2 bytes for header _len = 2 + numregs * 2; //calculate the query reply message length. 2 bytes per register + 2 bytes for header
_frame = (uint8_t*)malloc(_len); _frame = (uint8_t *) malloc(_len);
if (!_frame) { if (!_frame) {
exceptionResponse(fn, EX_SLAVE_FAILURE); exceptionResponse(fn, EX_SLAVE_FAILURE);
return; return;
} }
_frame[0] = fn; _frame[0] = fn;
_frame[1] = _len - 2; //byte count _frame[1] = _len - 2; //byte count
getMultipleWords((uint16_t*)(_frame + 2), startreg, numregs); getMultipleWords((uint16_t *) (_frame + 2), startreg, numregs);
_reply = REPLY_NORMAL; _reply = REPLY_NORMAL;
} }
void Modbus::setMultipleBits(uint8_t* frame, TAddress startreg, uint16_t numoutputs) void Modbus::setMultipleBits(const uint8_t *frame, TAddress startreg, uint16_t numoutputs) {
{
uint8_t bitn = 0; uint8_t bitn = 0;
uint16_t i = 0; uint16_t i = 0;
while (numoutputs--) { while (numoutputs--) {
@@ -315,16 +303,14 @@ void Modbus::setMultipleBits(uint8_t* frame, TAddress startreg, uint16_t numoutp
} }
} }
void Modbus::setMultipleWords(uint16_t* frame, TAddress startreg, uint16_t numregs) void Modbus::setMultipleWords(const uint16_t *frame, TAddress startreg, uint16_t numregs) {
{ for (uint16_t i = 0; i < numregs; i++) {
for (uint8_t i = 0; i < numregs; i++) {
Reg(startreg + i, __bswap_16(frame[i])); Reg(startreg + i, __bswap_16(frame[i]));
} }
} }
bool Modbus::onGet(TAddress address, cbModbus cb, uint16_t numregs) bool Modbus::onGet(TAddress address, cbModbus cb, uint16_t numregs) {
{ TRegister *reg;
TRegister* reg;
bool atLeastOne = false; bool atLeastOne = false;
if (!cb) { if (!cb) {
return removeOnGet(address); return removeOnGet(address);
@@ -332,25 +318,7 @@ bool Modbus::onGet(TAddress address, cbModbus cb, uint16_t numregs)
while (numregs > 0) { while (numregs > 0) {
reg = searchRegister(address); reg = searchRegister(address);
if (reg) { if (reg) {
_callbacks.push_back({ TCallback::ON_GET, address, cb }); _callbacks.push_back({TCallback::ON_GET, address, cb});
atLeastOne = true;
}
address++;
numregs--;
}
return atLeastOne;
}
bool Modbus::onSet(TAddress address, cbModbus cb, uint16_t numregs)
{
TRegister* reg;
bool atLeastOne = false;
if (!cb) {
return removeOnGet(address);
}
while (numregs > 0) {
reg = searchRegister(address);
if (reg) {
_callbacks.push_back({ TCallback::ON_SET, address, cb });
atLeastOne = true; atLeastOne = true;
} }
address++; address++;
@@ -359,28 +327,48 @@ bool Modbus::onSet(TAddress address, cbModbus cb, uint16_t numregs)
return atLeastOne; return atLeastOne;
} }
bool Modbus::removeOnSet(TAddress address, cbModbus cb, uint16_t numregs) bool Modbus::onSet(TAddress address, cbModbus cb, uint16_t numregs) {
{ TRegister *reg;
while (numregs--) { bool atLeastOne = false;
_callbacks.erase(remove_if(_callbacks.begin(), _callbacks.end(), [address, cb](TCallback entry) { return entry.type == TCallback::ON_SET && entry.address == address && (!cb || entry.cb == cb); }), _callbacks.end()); if (!cb) {
address++; return removeOnGet(address);
} }
return false; while (numregs > 0) {
reg = searchRegister(address);
if (reg) {
_callbacks.push_back({TCallback::ON_SET, address, cb});
atLeastOne = true;
}
address++;
numregs--;
}
return atLeastOne;
} }
bool Modbus::removeOnGet(TAddress address, cbModbus cb, uint16_t numregs)
{ bool Modbus::removeOnSet(TAddress address, cbModbus cb, uint16_t numregs) {
while (numregs--) { while (numregs--) {
_callbacks.erase(remove_if(_callbacks.begin(), _callbacks.end(), [address, cb](TCallback entry) { return entry.type == TCallback::ON_GET && entry.address == address && (!cb || entry.cb == cb); }), _callbacks.end()); _callbacks.erase(remove_if(_callbacks.begin(), _callbacks.end(), [address, cb](TCallback entry) {
return entry.type == TCallback::ON_SET && entry.address == address && (!cb || entry.cb == cb);
}), _callbacks.end());
address++; address++;
} }
return false; return false;
} }
bool Modbus::readSlave(uint16_t address, uint16_t numregs, FunctionCode fn) bool Modbus::removeOnGet(TAddress address, cbModbus cb, uint16_t numregs) {
{ while (numregs--) {
_callbacks.erase(remove_if(_callbacks.begin(), _callbacks.end(), [address, cb](TCallback entry) {
return entry.type == TCallback::ON_GET && entry.address == address && (!cb || entry.cb == cb);
}), _callbacks.end());
address++;
}
return false;
}
bool Modbus::readSlave(uint16_t address, uint16_t numregs, FunctionCode fn) {
free(_frame); free(_frame);
_len = 5; _len = 5;
_frame = (uint8_t*)malloc(_len); _frame = (uint8_t *) malloc(_len);
_frame[0] = fn; _frame[0] = fn;
_frame[1] = address >> 8; _frame[1] = address >> 8;
_frame[2] = address & 0x00FF; _frame[2] = address & 0x00FF;
@@ -389,13 +377,12 @@ bool Modbus::readSlave(uint16_t address, uint16_t numregs, FunctionCode fn)
return true; return true;
} }
bool Modbus::writeSlaveBits(TAddress startreg, uint16_t to, uint16_t numregs, FunctionCode fn, bool* data) bool Modbus::writeSlaveBits(TAddress startreg, uint16_t to, uint16_t numregs, FunctionCode fn, bool *data) {
{
free(_frame); free(_frame);
_len = 6 + numregs / 8; _len = 6 + numregs / 8;
if (numregs % 8) if (numregs % 8)
_len++; //Add 1 to the message length for the partial byte. _len++; //Add 1 to the message length for the partial byte.
_frame = (uint8_t*)malloc(_len); _frame = (uint8_t *) malloc(_len);
if (_frame) { if (_frame) {
_frame[0] = fn; _frame[0] = fn;
_frame[1] = to >> 8; _frame[1] = to >> 8;
@@ -416,11 +403,10 @@ bool Modbus::writeSlaveBits(TAddress startreg, uint16_t to, uint16_t numregs, Fu
return false; return false;
} }
bool Modbus::writeSlaveWords(TAddress startreg, uint16_t to, uint16_t numregs, FunctionCode fn, uint16_t* data) bool Modbus::writeSlaveWords(TAddress startreg, uint16_t to, uint16_t numregs, FunctionCode fn, const uint16_t *data) {
{
free(_frame); free(_frame);
_len = 6 + 2 * numregs; _len = 6 + 2 * numregs;
_frame = (uint8_t*)malloc(_len); _frame = (uint8_t *) malloc(_len);
if (_frame) { if (_frame) {
_frame[0] = fn; _frame[0] = fn;
_frame[1] = to >> 8; _frame[1] = to >> 8;
@@ -429,12 +415,12 @@ bool Modbus::writeSlaveWords(TAddress startreg, uint16_t to, uint16_t numregs, F
_frame[4] = numregs & 0x00FF; _frame[4] = numregs & 0x00FF;
_frame[5] = _len - 6; _frame[5] = _len - 6;
if (data) { if (data) {
uint16_t* frame = (uint16_t*)(_frame + 6); auto *frame = (uint16_t *) (_frame + 6);
for (uint8_t i = 0; i < numregs; i++) { for (uint16_t i = 0; i < numregs; i++) {
frame[i] = __bswap_16(data[i]); frame[i] = __bswap_16(data[i]);
} }
} else { } else {
getMultipleWords((uint16_t*)(_frame + 6), startreg, numregs); getMultipleWords((uint16_t *) (_frame + 6), startreg, numregs);
} }
return true; return true;
} }
@@ -442,8 +428,7 @@ bool Modbus::writeSlaveWords(TAddress startreg, uint16_t to, uint16_t numregs, F
return false; return false;
} }
void Modbus::boolToBits(uint8_t* dst, bool* src, uint16_t numregs) void Modbus::boolToBits(uint8_t *dst, const bool *src, uint16_t numregs) {
{
uint8_t bitn = 0; uint8_t bitn = 0;
uint16_t i = 0; uint16_t i = 0;
uint16_t j = 0; uint16_t j = 0;
@@ -461,8 +446,7 @@ void Modbus::boolToBits(uint8_t* dst, bool* src, uint16_t numregs)
} }
} }
void Modbus::bitsToBool(bool* dst, uint8_t* src, uint16_t numregs) void Modbus::bitsToBool(bool *dst, const uint8_t *src, uint16_t numregs) {
{
uint8_t bitn = 0; uint8_t bitn = 0;
uint16_t i = 0; uint16_t i = 0;
uint16_t j = 0; uint16_t j = 0;
@@ -477,202 +461,197 @@ void Modbus::bitsToBool(bool* dst, uint8_t* src, uint16_t numregs)
} }
} }
void Modbus::masterPDU(uint8_t* frame, uint8_t* sourceFrame, TAddress startreg, uint16_t* output) void Modbus::masterPDU(uint8_t *frame, const uint8_t *sourceFrame, TAddress startreg, uint16_t *output) {
{
uint8_t fcode = frame[0]; uint8_t fcode = frame[0];
_reply = EX_SUCCESS; _reply = EX_SUCCESS;
if ((fcode & 0x80) != 0) { if ((fcode & 0x80) != 0) {
_reply = frame[1]; _reply = frame[1];
return; return;
} }
uint16_t field2 = (uint16_t)sourceFrame[3] << 8 | (uint16_t)sourceFrame[4]; uint16_t field2 = (uint16_t) sourceFrame[3] << 8 | (uint16_t) sourceFrame[4];
uint8_t bytecount_calc; uint8_t bytecount_calc;
switch (fcode) { switch (fcode) {
case FC_READ_REGS: case FC_READ_REGS:
case FC_READ_INPUT_REGS: case FC_READ_INPUT_REGS:
//field2 = numregs, frame[1] = data lenght, header len = 2 //field2 = numregs, frame[1] = data lenght, header len = 2
if (frame[1] != 2 * field2) { //Check if data size matches if (frame[1] != 2 * field2) { //Check if data size matches
_reply = EX_DATA_MISMACH; _reply = EX_DATA_MISMACH;
break; break;
} }
if (output) { if (output) {
frame += 2; frame += 2;
while (field2) { while (field2) {
*((uint16_t*)output) = __bswap_16(*((uint16_t*)frame)); *((uint16_t *) output) = __bswap_16(*((uint16_t *) frame));
frame += 2; frame += 2;
output += 2; output += 2;
field2--; field2--;
}
} else {
setMultipleWords((uint16_t *) (frame + 2), startreg, field2);
} }
} else {
setMultipleWords((uint16_t*)(frame + 2), startreg, field2);
}
break;
case FC_READ_COILS:
case FC_READ_INPUT_STAT:
//field2 = numregs, frame[1] = data length, header len = 2
bytecount_calc = field2 / 8;
if (field2 % 8)
bytecount_calc++;
if (frame[1] != bytecount_calc) { // check if data size matches
_reply = EX_DATA_MISMACH;
break; break;
} case FC_READ_COILS:
if (output) { case FC_READ_INPUT_STAT:
bitsToBool((bool*)output, frame + 2, field2); //field2 = numregs, frame[1] = data length, header len = 2
} else { bytecount_calc = field2 / 8;
setMultipleBits(frame + 2, startreg, field2); if (field2 % 8)
} bytecount_calc++;
break; if (frame[1] != bytecount_calc) { // check if data size matches
case FC_WRITE_REG: _reply = EX_DATA_MISMACH;
case FC_WRITE_REGS: break;
case FC_WRITE_COIL: }
case FC_WRITE_COILS: if (output) {
break; bitsToBool((bool *) output, frame + 2, field2);
default: } else {
_reply = EX_GENERAL_FAILURE; setMultipleBits(frame + 2, startreg, field2);
}
break;
case FC_WRITE_REG:
case FC_WRITE_REGS:
case FC_WRITE_COIL:
case FC_WRITE_COILS:
break;
default:
_reply = EX_GENERAL_FAILURE;
} }
} }
void Modbus::cbEnable(bool state) void Modbus::cbEnable(bool state) {
{
cbEnabled = state; cbEnabled = state;
} }
void Modbus::cbDisable()
{ void Modbus::cbDisable() {
cbEnable(false); cbEnable(false);
} }
bool Modbus::addHreg(uint16_t offset, uint16_t value, uint16_t numregs) bool Modbus::addHreg(uint16_t offset, uint16_t value, uint16_t numregs) {
{
return addReg(HREG(offset), value, numregs); return addReg(HREG(offset), value, numregs);
} }
bool Modbus::Hreg(uint16_t offset, uint16_t value)
{ bool Modbus::Hreg(uint16_t offset, uint16_t value) {
return Reg(HREG(offset), value); return Reg(HREG(offset), value);
} }
uint16_t Modbus::Hreg(uint16_t offset)
{ uint16_t Modbus::Hreg(uint16_t offset) {
return Reg(HREG(offset)); return Reg(HREG(offset));
} }
uint16_t Modbus::removeHreg(uint16_t offset, uint16_t numregs)
{ uint16_t Modbus::removeHreg(uint16_t offset, uint16_t numregs) {
return removeReg(HREG(offset), numregs); return removeReg(HREG(offset), numregs);
} }
bool Modbus::addCoil(uint16_t offset, bool value, uint16_t numregs)
{ bool Modbus::addCoil(uint16_t offset, bool value, uint16_t numregs) {
return addReg(COIL(offset), COIL_VAL(value), numregs); return addReg(COIL(offset), COIL_VAL(value), numregs);
} }
bool Modbus::addIsts(uint16_t offset, bool value, uint16_t numregs)
{ bool Modbus::addIsts(uint16_t offset, bool value, uint16_t numregs) {
return addReg(ISTS(offset), ISTS_VAL(value), numregs); return addReg(ISTS(offset), ISTS_VAL(value), numregs);
} }
bool Modbus::addIreg(uint16_t offset, uint16_t value, uint16_t numregs)
{ bool Modbus::addIreg(uint16_t offset, uint16_t value, uint16_t numregs) {
return addReg(IREG(offset), value, numregs); return addReg(IREG(offset), value, numregs);
} }
bool Modbus::Coil(uint16_t offset, bool value)
{ bool Modbus::Coil(uint16_t offset, bool value) {
return Reg(COIL(offset), COIL_VAL(value)); return Reg(COIL(offset), COIL_VAL(value));
} }
bool Modbus::Ists(uint16_t offset, bool value)
{ bool Modbus::Ists(uint16_t offset, bool value) {
return Reg(ISTS(offset), ISTS_VAL(value)); return Reg(ISTS(offset), ISTS_VAL(value));
} }
bool Modbus::Ireg(uint16_t offset, uint16_t value)
{ bool Modbus::Ireg(uint16_t offset, uint16_t value) {
return Reg(IREG(offset), value); return Reg(IREG(offset), value);
} }
bool Modbus::Coil(uint16_t offset)
{ bool Modbus::Coil(uint16_t offset) {
return COIL_BOOL(Reg(COIL(offset))); return COIL_BOOL(Reg(COIL(offset)));
} }
bool Modbus::Ists(uint16_t offset)
{ bool Modbus::Ists(uint16_t offset) {
return ISTS_BOOL(Reg(ISTS(offset))); return ISTS_BOOL(Reg(ISTS(offset)));
} }
uint16_t Modbus::Ireg(uint16_t offset)
{ uint16_t Modbus::Ireg(uint16_t offset) {
return Reg(IREG(offset)); return Reg(IREG(offset));
} }
bool Modbus::removeCoil(uint16_t offset, uint16_t numregs)
{ bool Modbus::removeCoil(uint16_t offset, uint16_t numregs) {
return removeReg(COIL(offset), numregs); return removeReg(COIL(offset), numregs);
} }
bool Modbus::removeIsts(uint16_t offset, uint16_t numregs)
{ bool Modbus::removeIsts(uint16_t offset, uint16_t numregs) {
return removeReg(ISTS(offset), numregs); return removeReg(ISTS(offset), numregs);
} }
bool Modbus::removeIreg(uint16_t offset, uint16_t numregs)
{ bool Modbus::removeIreg(uint16_t offset, uint16_t numregs) {
return removeReg(IREG(offset), numregs); return removeReg(IREG(offset), numregs);
} }
bool Modbus::onGetCoil(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::onGetCoil(uint16_t offset, cbModbus cb, uint16_t numregs) {
return onGet(COIL(offset), cb, numregs); return onGet(COIL(offset), cb, numregs);
} }
bool Modbus::onSetCoil(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::onSetCoil(uint16_t offset, cbModbus cb, uint16_t numregs) {
return onSet(COIL(offset), cb, numregs); return onSet(COIL(offset), cb, numregs);
} }
bool Modbus::onGetHreg(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::onGetHreg(uint16_t offset, cbModbus cb, uint16_t numregs) {
return onGet(HREG(offset), cb, numregs); return onGet(HREG(offset), cb, numregs);
} }
bool Modbus::onSetHreg(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::onSetHreg(uint16_t offset, cbModbus cb, uint16_t numregs) {
return onSet(HREG(offset), cb, numregs); return onSet(HREG(offset), cb, numregs);
} }
bool Modbus::onGetIsts(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::onGetIsts(uint16_t offset, cbModbus cb, uint16_t numregs) {
return onGet(ISTS(offset), cb, numregs); return onGet(ISTS(offset), cb, numregs);
} }
bool Modbus::onSetIsts(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::onSetIsts(uint16_t offset, cbModbus cb, uint16_t numregs) {
return onSet(ISTS(offset), cb, numregs); return onSet(ISTS(offset), cb, numregs);
} }
bool Modbus::onGetIreg(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::onGetIreg(uint16_t offset, cbModbus cb, uint16_t numregs) {
return onGet(IREG(offset), cb, numregs); return onGet(IREG(offset), cb, numregs);
} }
bool Modbus::onSetIreg(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::onSetIreg(uint16_t offset, cbModbus cb, uint16_t numregs) {
return onSet(IREG(offset), cb, numregs); return onSet(IREG(offset), cb, numregs);
} }
bool Modbus::removeOnGetCoil(uint16_t offset, cbModbus cb, uint16_t numregs) bool Modbus::removeOnGetCoil(uint16_t offset, cbModbus cb, uint16_t numregs) {
{
return removeOnGet(COIL(offset), cb, numregs); return removeOnGet(COIL(offset), cb, numregs);
} }
bool Modbus::removeOnSetCoil(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::removeOnSetCoil(uint16_t offset, cbModbus cb, uint16_t numregs) {
return removeOnSet(COIL(offset), cb, numregs); return removeOnSet(COIL(offset), cb, numregs);
} }
bool Modbus::removeOnGetHreg(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::removeOnGetHreg(uint16_t offset, cbModbus cb, uint16_t numregs) {
return removeOnGet(HREG(offset), cb, numregs); return removeOnGet(HREG(offset), cb, numregs);
} }
bool Modbus::removeOnSetHreg(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::removeOnSetHreg(uint16_t offset, cbModbus cb, uint16_t numregs) {
return removeOnSet(HREG(offset), cb, numregs); return removeOnSet(HREG(offset), cb, numregs);
} }
bool Modbus::removeOnGetIsts(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::removeOnGetIsts(uint16_t offset, cbModbus cb, uint16_t numregs) {
return removeOnGet(ISTS(offset), cb, numregs); return removeOnGet(ISTS(offset), cb, numregs);
} }
bool Modbus::removeOnSetIsts(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::removeOnSetIsts(uint16_t offset, cbModbus cb, uint16_t numregs) {
return removeOnSet(ISTS(offset), cb, numregs); return removeOnSet(ISTS(offset), cb, numregs);
} }
bool Modbus::removeOnGetIreg(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::removeOnGetIreg(uint16_t offset, cbModbus cb, uint16_t numregs) {
return removeOnGet(IREG(offset), cb, numregs); return removeOnGet(IREG(offset), cb, numregs);
} }
bool Modbus::removeOnSetIreg(uint16_t offset, cbModbus cb, uint16_t numregs)
{ bool Modbus::removeOnSetIreg(uint16_t offset, cbModbus cb, uint16_t numregs) {
return removeOnSet(IREG(offset), cb, numregs); return removeOnSet(IREG(offset), cb, numregs);
} }
Modbus::~Modbus() Modbus::~Modbus() {
{
free(_frame); free(_frame);
} }

138
Modbus.h
View File

@@ -8,6 +8,7 @@
#include "mbed.h" #include "mbed.h"
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#include <byteswap.h> #include <byteswap.h>
#endif #endif
@@ -39,66 +40,70 @@
struct TRegister; struct TRegister;
typedef uint16_t (*cbModbus)(TRegister* reg, uint16_t val); // Callback function Type typedef uint16_t (*cbModbus)(TRegister *reg, uint16_t val); // Callback function Type
struct TAddress { struct TAddress {
enum RegType { COIL, enum RegType {
COIL,
ISTS, ISTS,
IREG, IREG,
HREG }; HREG
};
RegType type; RegType type;
uint16_t address; uint16_t address;
bool operator==(const TAddress& obj) const
{ // TAddress == TAddress bool operator==(const TAddress &obj) const { // TAddress == TAddress
return type == obj.type && address == obj.address; return type == obj.type && address == obj.address;
} }
bool operator!=(const TAddress& obj) const
{ // TAddress != TAddress bool operator!=(const TAddress &obj) const { // TAddress != TAddress
return type != obj.type || address != obj.address; return type != obj.type || address != obj.address;
} }
TAddress& operator++()
{ // ++TAddress TAddress &operator++() { // ++TAddress
address++; address++;
return *this; return *this;
} }
TAddress operator++(int)
{ // TAddress++ const TAddress operator++(int) { // TAddress++
TAddress result(*this); TAddress result(*this);
++(*this); ++(*this);
return result; return result;
} }
TAddress& operator+=(const int& inc)
{ // TAddress += integer TAddress &operator+=(const int &inc) { // TAddress += integer
address += inc; address += inc;
return *this; return *this;
} }
const TAddress operator+(const int& inc) const
{ // TAddress + integer TAddress operator+(const int &inc) const { // TAddress + integer
TAddress result(*this); TAddress result(*this);
result.address += inc; result.address += inc;
return result; return result;
} }
bool isCoil()
{ bool isCoil() const {
return type == COIL; return type == COIL;
} }
bool isIsts()
{ bool isIsts() const {
return type == ISTS; return type == ISTS;
} }
bool isIreg()
{ bool isIreg() const {
return type == IREG; return type == IREG;
} }
bool isHreg()
{ bool isHreg() const {
return type == HREG; return type == HREG;
} }
}; };
struct TCallback { struct TCallback {
enum CallbackType { ON_SET, enum CallbackType {
ON_GET }; ON_SET,
ON_GET
};
CallbackType type; CallbackType type;
TAddress address; TAddress address;
cbModbus cb; cbModbus cb;
@@ -107,8 +112,8 @@ struct TCallback {
struct TRegister { struct TRegister {
TAddress address; TAddress address;
uint16_t value; uint16_t value;
bool operator==(const TRegister& obj) const
{ bool operator==(const TRegister &obj) const {
return address == obj.address; return address == obj.address;
} }
}; };
@@ -151,23 +156,41 @@ public:
EX_CONNECTION_LOST = 0xE5, // Custom. Connection with device lost EX_CONNECTION_LOST = 0xE5, // Custom. Connection with device lost
EX_CANCEL = 0xE6 // Custom. Transaction/request canceled EX_CANCEL = 0xE6 // Custom. Transaction/request canceled
}; };
~Modbus(); ~Modbus();
bool addHreg(uint16_t offset, uint16_t value = 0, uint16_t numregs = 1); bool addHreg(uint16_t offset, uint16_t value = 0, uint16_t numregs = 1);
bool Hreg(uint16_t offset, uint16_t value); bool Hreg(uint16_t offset, uint16_t value);
uint16_t Hreg(uint16_t offset); uint16_t Hreg(uint16_t offset);
uint16_t removeHreg(uint16_t offset, uint16_t numregs = 1); uint16_t removeHreg(uint16_t offset, uint16_t numregs = 1);
bool addCoil(uint16_t offset, bool value = false, uint16_t numregs = 1); bool addCoil(uint16_t offset, bool value = false, uint16_t numregs = 1);
bool addIsts(uint16_t offset, bool value = false, uint16_t numregs = 1); bool addIsts(uint16_t offset, bool value = false, uint16_t numregs = 1);
bool addIreg(uint16_t offset, uint16_t value = 0, uint16_t numregs = 1); bool addIreg(uint16_t offset, uint16_t value = 0, uint16_t numregs = 1);
bool Coil(uint16_t offset, bool value); bool Coil(uint16_t offset, bool value);
bool Ists(uint16_t offset, bool value); bool Ists(uint16_t offset, bool value);
bool Ireg(uint16_t offset, uint16_t value); bool Ireg(uint16_t offset, uint16_t value);
bool Coil(uint16_t offset); bool Coil(uint16_t offset);
bool Ists(uint16_t offset); bool Ists(uint16_t offset);
uint16_t Ireg(uint16_t offset); uint16_t Ireg(uint16_t offset);
bool removeCoil(uint16_t offset, uint16_t numregs = 1); bool removeCoil(uint16_t offset, uint16_t numregs = 1);
bool removeIsts(uint16_t offset, uint16_t numregs = 1); bool removeIsts(uint16_t offset, uint16_t numregs = 1);
bool removeIreg(uint16_t offset, uint16_t numregs = 1); bool removeIreg(uint16_t offset, uint16_t numregs = 1);
/* /*
bool Hreg(uint16_t offset, uint16_t* value); bool Hreg(uint16_t offset, uint16_t* value);
bool Coil(uint16_t offset, bool* value); bool Coil(uint16_t offset, bool* value);
@@ -175,38 +198,57 @@ public:
bool Ireg(uint16_t offset, uint16_t* value); bool Ireg(uint16_t offset, uint16_t* value);
*/ */
void cbEnable(bool state = true); void cbEnable(bool state = true);
void cbDisable(); void cbDisable();
bool onGetCoil(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool onGetCoil(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool onSetCoil(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool onSetCoil(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool onGetHreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool onGetHreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool onSetHreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool onSetHreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool onGetIsts(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool onGetIsts(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool onSetIsts(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool onSetIsts(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool onGetIreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool onGetIreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool onSetIreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool onSetIreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool removeOnGetCoil(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool removeOnGetCoil(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool removeOnSetCoil(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool removeOnSetCoil(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool removeOnGetHreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool removeOnGetHreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool removeOnSetHreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool removeOnSetHreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool removeOnGetIsts(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool removeOnGetIsts(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool removeOnSetIsts(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool removeOnSetIsts(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool removeOnGetIreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool removeOnGetIreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
bool removeOnSetIreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1); bool removeOnSetIreg(uint16_t offset, cbModbus cb = nullptr, uint16_t numregs = 1);
private: private:
void readBits(TAddress startreg, uint16_t numregs, FunctionCode fn); void readBits(TAddress startreg, uint16_t numregs, FunctionCode fn);
void readWords(TAddress startreg, uint16_t numregs, FunctionCode fn); void readWords(TAddress startreg, uint16_t numregs, FunctionCode fn);
void setMultipleBits(uint8_t* frame, TAddress startreg, uint16_t numoutputs); void setMultipleBits(const uint8_t *frame, TAddress startreg, uint16_t numoutputs);
void setMultipleWords(uint16_t* frame, TAddress startreg, uint16_t numoutputs);
void getMultipleBits(uint8_t* frame, TAddress startreg, uint16_t numregs); void setMultipleWords(const uint16_t *frame, TAddress startreg, uint16_t numoutputs);
void getMultipleWords(uint16_t* frame, TAddress startreg, uint16_t numregs);
void bitsToBool(bool* dst, uint8_t* src, uint16_t numregs); void getMultipleBits(uint8_t *frame, TAddress startreg, uint16_t numregs);
void boolToBits(uint8_t* dst, bool* src, uint16_t numregs);
void getMultipleWords(uint16_t *frame, TAddress startreg, uint16_t numregs);
static void bitsToBool(bool *dst, const uint8_t *src, uint16_t numregs);
static void boolToBits(uint8_t *dst, const bool *src, uint16_t numregs);
protected: protected:
//Reply Types //Reply Types
@@ -221,24 +263,31 @@ protected:
std::vector<TRegister> _regs; std::vector<TRegister> _regs;
std::vector<TCallback> _callbacks; std::vector<TCallback> _callbacks;
#endif #endif
uint8_t* _frame = nullptr; uint8_t *_frame = nullptr;
uint16_t _len = 0; uint16_t _len = 0;
uint8_t _reply = 0; uint8_t _reply = 0;
bool cbEnabled = true; bool cbEnabled = true;
uint16_t mbCallback(TRegister* reg, uint16_t val, TCallback::CallbackType t);
TRegister* searchRegister(TAddress addr); uint16_t mbCallback(TRegister *reg, uint16_t val, TCallback::CallbackType t);
TRegister *searchRegister(TAddress addr);
void exceptionResponse(FunctionCode fn, ResultCode excode); // Fills _frame with response void exceptionResponse(FunctionCode fn, ResultCode excode); // Fills _frame with response
void successResponce(TAddress startreg, uint16_t numoutputs, FunctionCode fn); // Fills frame with response void successResponce(TAddress startreg, uint16_t numoutputs, FunctionCode fn); // Fills frame with response
void slavePDU(uint8_t* frame); //For Slave void slavePDU(uint8_t *frame); //For Slave
void masterPDU(uint8_t* frame, uint8_t* sourceFrame, TAddress startreg, uint16_t* output = nullptr); //For Master void
masterPDU(uint8_t *frame, const uint8_t *sourceFrame, TAddress startreg, uint16_t *output = nullptr); //For Master
// frame - data received form slave // frame - data received form slave
// sourceFrame - data have sent fo slave // sourceFrame - data have sent fo slave
// startreg - local register to start put data to // startreg - local register to start put data to
// output - if not null put data to the buffer insted local registers. output assumed to by array of uint16_t or boolean // output - if not null put data to the buffer insted local registers. output assumed to by array of uint16_t or boolean
bool readSlave(uint16_t address, uint16_t numregs, FunctionCode fn); bool readSlave(uint16_t address, uint16_t numregs, FunctionCode fn);
bool writeSlaveBits(TAddress startreg, uint16_t to, uint16_t numregs, FunctionCode fn, bool* data = nullptr);
bool writeSlaveWords(TAddress startreg, uint16_t to, uint16_t numregs, FunctionCode fn, uint16_t* data = nullptr); bool writeSlaveBits(TAddress startreg, uint16_t to, uint16_t numregs, FunctionCode fn, bool *data = nullptr);
bool
writeSlaveWords(TAddress startreg, uint16_t to, uint16_t numregs, FunctionCode fn, const uint16_t *data = nullptr);
// startreg - local register to get data from // startreg - local register to get data from
// to - slave register to write data to // to - slave register to write data to
// numregs - number of registers // numregs - number of registers
@@ -246,16 +295,23 @@ protected:
// data - if null use local registers. Otherwise use data from array to erite to slave // data - if null use local registers. Otherwise use data from array to erite to slave
bool addReg(TAddress address, uint16_t value = 0, uint16_t numregs = 1); bool addReg(TAddress address, uint16_t value = 0, uint16_t numregs = 1);
bool Reg(TAddress address, uint16_t value); bool Reg(TAddress address, uint16_t value);
uint16_t Reg(TAddress address); uint16_t Reg(TAddress address);
bool removeReg(TAddress address, uint16_t numregs = 1); bool removeReg(TAddress address, uint16_t numregs = 1);
bool onGet(TAddress address, cbModbus cb = nullptr, uint16_t numregs = 1); bool onGet(TAddress address, cbModbus cb = nullptr, uint16_t numregs = 1);
bool onSet(TAddress address, cbModbus cb = nullptr, uint16_t numregs = 1); bool onSet(TAddress address, cbModbus cb = nullptr, uint16_t numregs = 1);
bool removeOnSet(TAddress address, cbModbus cb = nullptr, uint16_t numregs = 1); bool removeOnSet(TAddress address, cbModbus cb = nullptr, uint16_t numregs = 1);
bool removeOnGet(TAddress address, cbModbus cb = nullptr, uint16_t numregs = 1); bool removeOnGet(TAddress address, cbModbus cb = nullptr, uint16_t numregs = 1);
virtual uint32_t eventSource() { return 0; } virtual uint32_t eventSource() { return 0; }
}; };
typedef bool (*cbTransaction)(Modbus::ResultCode event, uint16_t transactionId, void* data); // Callback skeleton for requests typedef bool (*cbTransaction)(Modbus::ResultCode event, uint16_t transactionId,
void *data); // Callback skeleton for requests

View File

@@ -11,28 +11,44 @@
// Table of CRC values // Table of CRC values
static const uint16_t _auchCRC[] = { static const uint16_t _auchCRC[] = {
0x0000, 0xC1C0, 0x81C1, 0x4001, 0x01C3, 0xC003, 0x8002, 0x41C2, 0x01C6, 0xC006, 0x8007, 0x41C7, 0x0005, 0xC1C5, 0x81C4, 0x0000, 0xC1C0, 0x81C1, 0x4001, 0x01C3, 0xC003, 0x8002, 0x41C2, 0x01C6, 0xC006, 0x8007, 0x41C7, 0x0005, 0xC1C5,
0x4004, 0x01CC, 0xC00C, 0x800D, 0x41CD, 0x000F, 0xC1CF, 0x81CE, 0x400E, 0x000A, 0xC1CA, 0x81CB, 0x400B, 0x01C9, 0xC009, 0x81C4,
0x8008, 0x41C8, 0x01D8, 0xC018, 0x8019, 0x41D9, 0x001B, 0xC1DB, 0x81DA, 0x401A, 0x001E, 0xC1DE, 0x81DF, 0x401F, 0x01DD, 0x4004, 0x01CC, 0xC00C, 0x800D, 0x41CD, 0x000F, 0xC1CF, 0x81CE, 0x400E, 0x000A, 0xC1CA, 0x81CB, 0x400B, 0x01C9,
0xC01D, 0x801C, 0x41DC, 0x0014, 0xC1D4, 0x81D5, 0x4015, 0x01D7, 0xC017, 0x8016, 0x41D6, 0x01D2, 0xC012, 0x8013, 0x41D3, 0xC009,
0x0011, 0xC1D1, 0x81D0, 0x4010, 0x01F0, 0xC030, 0x8031, 0x41F1, 0x0033, 0xC1F3, 0x81F2, 0x4032, 0x0036, 0xC1F6, 0x81F7, 0x8008, 0x41C8, 0x01D8, 0xC018, 0x8019, 0x41D9, 0x001B, 0xC1DB, 0x81DA, 0x401A, 0x001E, 0xC1DE, 0x81DF, 0x401F,
0x4037, 0x01F5, 0xC035, 0x8034, 0x41F4, 0x003C, 0xC1FC, 0x81FD, 0x403D, 0x01FF, 0xC03F, 0x803E, 0x41FE, 0x01FA, 0xC03A, 0x01DD,
0x803B, 0x41FB, 0x0039, 0xC1F9, 0x81F8, 0x4038, 0x0028, 0xC1E8, 0x81E9, 0x4029, 0x01EB, 0xC02B, 0x802A, 0x41EA, 0x01EE, 0xC01D, 0x801C, 0x41DC, 0x0014, 0xC1D4, 0x81D5, 0x4015, 0x01D7, 0xC017, 0x8016, 0x41D6, 0x01D2, 0xC012, 0x8013,
0xC02E, 0x802F, 0x41EF, 0x002D, 0xC1ED, 0x81EC, 0x402C, 0x01E4, 0xC024, 0x8025, 0x41E5, 0x0027, 0xC1E7, 0x81E6, 0x4026, 0x41D3,
0x0022, 0xC1E2, 0x81E3, 0x4023, 0x01E1, 0xC021, 0x8020, 0x41E0, 0x01A0, 0xC060, 0x8061, 0x41A1, 0x0063, 0xC1A3, 0x81A2, 0x0011, 0xC1D1, 0x81D0, 0x4010, 0x01F0, 0xC030, 0x8031, 0x41F1, 0x0033, 0xC1F3, 0x81F2, 0x4032, 0x0036, 0xC1F6,
0x4062, 0x0066, 0xC1A6, 0x81A7, 0x4067, 0x01A5, 0xC065, 0x8064, 0x41A4, 0x006C, 0xC1AC, 0x81AD, 0x406D, 0x01AF, 0xC06F, 0x81F7,
0x806E, 0x41AE, 0x01AA, 0xC06A, 0x806B, 0x41AB, 0x0069, 0xC1A9, 0x81A8, 0x4068, 0x0078, 0xC1B8, 0x81B9, 0x4079, 0x01BB, 0x4037, 0x01F5, 0xC035, 0x8034, 0x41F4, 0x003C, 0xC1FC, 0x81FD, 0x403D, 0x01FF, 0xC03F, 0x803E, 0x41FE, 0x01FA,
0xC07B, 0x807A, 0x41BA, 0x01BE, 0xC07E, 0x807F, 0x41BF, 0x007D, 0xC1BD, 0x81BC, 0x407C, 0x01B4, 0xC074, 0x8075, 0x41B5, 0xC03A,
0x0077, 0xC1B7, 0x81B6, 0x4076, 0x0072, 0xC1B2, 0x81B3, 0x4073, 0x01B1, 0xC071, 0x8070, 0x41B0, 0x0050, 0xC190, 0x8191, 0x803B, 0x41FB, 0x0039, 0xC1F9, 0x81F8, 0x4038, 0x0028, 0xC1E8, 0x81E9, 0x4029, 0x01EB, 0xC02B, 0x802A, 0x41EA,
0x4051, 0x0193, 0xC053, 0x8052, 0x4192, 0x0196, 0xC056, 0x8057, 0x4197, 0x0055, 0xC195, 0x8194, 0x4054, 0x019C, 0xC05C, 0x01EE,
0x805D, 0x419D, 0x005F, 0xC19F, 0x819E, 0x405E, 0x005A, 0xC19A, 0x819B, 0x405B, 0x0199, 0xC059, 0x8058, 0x4198, 0x0188, 0xC02E, 0x802F, 0x41EF, 0x002D, 0xC1ED, 0x81EC, 0x402C, 0x01E4, 0xC024, 0x8025, 0x41E5, 0x0027, 0xC1E7, 0x81E6,
0xC048, 0x8049, 0x4189, 0x004B, 0xC18B, 0x818A, 0x404A, 0x004E, 0xC18E, 0x818F, 0x404F, 0x018D, 0xC04D, 0x804C, 0x418C, 0x4026,
0x0044, 0xC184, 0x8185, 0x4045, 0x0187, 0xC047, 0x8046, 0x4186, 0x0182, 0xC042, 0x8043, 0x4183, 0x0041, 0xC181, 0x8180, 0x0022, 0xC1E2, 0x81E3, 0x4023, 0x01E1, 0xC021, 0x8020, 0x41E0, 0x01A0, 0xC060, 0x8061, 0x41A1, 0x0063, 0xC1A3,
0x4040, 0x0000 0x81A2,
0x4062, 0x0066, 0xC1A6, 0x81A7, 0x4067, 0x01A5, 0xC065, 0x8064, 0x41A4, 0x006C, 0xC1AC, 0x81AD, 0x406D, 0x01AF,
0xC06F,
0x806E, 0x41AE, 0x01AA, 0xC06A, 0x806B, 0x41AB, 0x0069, 0xC1A9, 0x81A8, 0x4068, 0x0078, 0xC1B8, 0x81B9, 0x4079,
0x01BB,
0xC07B, 0x807A, 0x41BA, 0x01BE, 0xC07E, 0x807F, 0x41BF, 0x007D, 0xC1BD, 0x81BC, 0x407C, 0x01B4, 0xC074, 0x8075,
0x41B5,
0x0077, 0xC1B7, 0x81B6, 0x4076, 0x0072, 0xC1B2, 0x81B3, 0x4073, 0x01B1, 0xC071, 0x8070, 0x41B0, 0x0050, 0xC190,
0x8191,
0x4051, 0x0193, 0xC053, 0x8052, 0x4192, 0x0196, 0xC056, 0x8057, 0x4197, 0x0055, 0xC195, 0x8194, 0x4054, 0x019C,
0xC05C,
0x805D, 0x419D, 0x005F, 0xC19F, 0x819E, 0x405E, 0x005A, 0xC19A, 0x819B, 0x405B, 0x0199, 0xC059, 0x8058, 0x4198,
0x0188,
0xC048, 0x8049, 0x4189, 0x004B, 0xC18B, 0x818A, 0x404A, 0x004E, 0xC18E, 0x818F, 0x404F, 0x018D, 0xC04D, 0x804C,
0x418C,
0x0044, 0xC184, 0x8185, 0x4045, 0x0187, 0xC047, 0x8046, 0x4186, 0x0182, 0xC042, 0x8043, 0x4183, 0x0041, 0xC181,
0x8180,
0x4040, 0x0000
}; };
uint16_t ModbusRTU::crc16(uint8_t address, uint8_t* frame, uint8_t pduLen) uint16_t ModbusRTU::crc16(uint8_t address, uint8_t *frame, uint8_t pduLen) {
{
uint8_t i = 0xFF ^ address; uint8_t i = 0xFF ^ address;
uint16_t val = pgm_read_word(_auchCRC + i); uint16_t val = pgm_read_word(_auchCRC + i);
uint8_t CRCHi = 0xFF ^ highByte(val); // Hi uint8_t CRCHi = 0xFF ^ highByte(val); // Hi
@@ -46,8 +62,7 @@ uint16_t ModbusRTU::crc16(uint8_t address, uint8_t* frame, uint8_t pduLen)
return (CRCHi << 8) | CRCLo; return (CRCHi << 8) | CRCLo;
} }
void ModbusRTU::setBaudrate(uint32_t baud) void ModbusRTU::setBaudrate(uint32_t baud) {
{
if (baud > 19200) { if (baud > 19200) {
_t = 50ms; _t = 50ms;
} else { } else {
@@ -56,16 +71,14 @@ void ModbusRTU::setBaudrate(uint32_t baud)
} }
} }
bool ModbusRTU::begin(UnbufferedSerial* port) bool ModbusRTU::begin(UnbufferedSerial *port) {
{
_port = port; _port = port;
_t = 50ms; _t = 50ms;
_port->attach(callback(this, &ModbusRTU::SerialRXHandler), SerialBase::RxIrq); _port->attach(callback(this, &ModbusRTU::SerialRXHandler), SerialBase::RxIrq);
return true; return true;
} }
bool ModbusRTU::begin(UnbufferedSerial* port, PinName txPin) bool ModbusRTU::begin(UnbufferedSerial *port, PinName txPin) {
{
uint32_t baud = 0; uint32_t baud = 0;
#if defined(ESP32) || defined(ESP8266) #if defined(ESP32) || defined(ESP8266)
// baudRate() only available with ESP32+ESP8266 // baudRate() only available with ESP32+ESP8266
@@ -85,17 +98,15 @@ bool ModbusRTU::begin(UnbufferedSerial* port, PinName txPin)
return true; return true;
} }
void ModbusRTU::SerialRXHandler() void ModbusRTU::SerialRXHandler() {
{
char c; char c;
if (_port->readable()) { if (_port->readable()) {
_port->read(&c, 1); _port->read(&c, 1);
RX_RingBuff.push((uint8_t)(c & (uint8_t)0xFFU)); RX_RingBuff.push((uint8_t) (c & (uint8_t) 0xFFU));
} }
} }
void ModbusRTU::SerialTXHandler() void ModbusRTU::SerialTXHandler() {
{
//Здесь проверка на TC а не на RX!!!! //Здесь проверка на TC а не на RX!!!!
//Изменено в serial_api.c //Изменено в serial_api.c
if (_port->writeable()) { if (_port->writeable()) {
@@ -104,17 +115,15 @@ void ModbusRTU::SerialTXHandler()
} }
} }
uint8_t ModbusRTU::Read(void) uint8_t ModbusRTU::Read() {
{
uint8_t cur = 0xff; uint8_t cur = 0xff;
if (!RX_RingBuff.empty()) { if (!RX_RingBuff.empty()) {
RX_RingBuff.pop((char&)cur); RX_RingBuff.pop((char &) cur);
} }
return cur; return cur;
} }
uint8_t ModbusRTU::isDataAvailable(void) uint8_t ModbusRTU::isDataAvailable() {
{
if (RX_RingBuff.full()) { if (RX_RingBuff.full()) {
RX_RingBuff.reset(); RX_RingBuff.reset();
} }
@@ -133,8 +142,7 @@ bool ModbusRTU::begin(SoftwareSerial* port, int16_t txPin)
} }
#endif #endif
bool ModbusRTU::rawSend(uint8_t slaveId, uint8_t* frame, uint8_t len) bool ModbusRTU::rawSend(uint8_t slaveId, uint8_t *frame, uint8_t len) {
{
uint16_t newCrc = crc16(slaveId, frame, len); uint16_t newCrc = crc16(slaveId, frame, len);
char crc[2]; char crc[2];
crc[0] = newCrc >> 8; crc[0] = newCrc >> 8;
@@ -153,8 +161,7 @@ bool ModbusRTU::rawSend(uint8_t slaveId, uint8_t* frame, uint8_t len)
return true; return true;
} }
bool ModbusRTU::send(uint8_t slaveId, TAddress startreg, cbTransaction cb, void* data, bool waitResponse) bool ModbusRTU::send(uint8_t slaveId, TAddress startreg, cbTransaction cb, void *data, bool waitResponse) {
{
if (_slaveId) if (_slaveId)
return false; // Break if waiting for previous request result return false; // Break if waiting for previous request result
rawSend(slaveId, _frame, _len); rawSend(slaveId, _frame, _len);
@@ -171,8 +178,7 @@ bool ModbusRTU::send(uint8_t slaveId, TAddress startreg, cbTransaction cb, void*
return true; return true;
} }
void ModbusRTU::task() void ModbusRTU::task() {
{
if (RX_RingBuff.size() > _len) { if (RX_RingBuff.size() > _len) {
_len = RX_RingBuff.size(); _len = RX_RingBuff.size();
@@ -201,13 +207,13 @@ void ModbusRTU::task()
} }
free(_frame); //Just in case free(_frame); //Just in case
_frame = (uint8_t*)malloc(_len); _frame = (uint8_t *) malloc(_len);
if (!_frame) { // Fail to allocate buffer if (!_frame) { // Fail to allocate buffer
RX_RingBuff.reset(); // Skip packet if can't allocate buffer RX_RingBuff.reset(); // Skip packet if can't allocate buffer
_len = 0; _len = 0;
return; return;
} }
for (uint8_t i = 0; i < _len; i++) { for (uint16_t i = 0; i < _len; i++) {
_frame[i] = Read(); // read data + crc _frame[i] = Read(); // read data + crc
#if defined(MODBUSRTU_DEBUG) #if defined(MODBUSRTU_DEBUG)
Serial.printf("%02X ", _frame[i]); Serial.printf("%02X ", _frame[i]);
@@ -229,9 +235,9 @@ void ModbusRTU::task()
_reply = EX_SUCCESS; _reply = EX_SUCCESS;
if ((_frame[0] & 0x7F) == _sentFrame[0]) { // Check if function code the same as requested if ((_frame[0] & 0x7F) == _sentFrame[0]) { // Check if function code the same as requested
// Procass incoming frame as master // Procass incoming frame as master
masterPDU(_frame, _sentFrame, _sentReg, (uint16_t*)_data); masterPDU(_frame, _sentFrame, _sentReg, (uint16_t *) _data);
if (_cb) { if (_cb) {
_cb((ResultCode)_reply, 0, nullptr); _cb((ResultCode) _reply, 0, nullptr);
} }
free(_sentFrame); free(_sentFrame);
_sentFrame = nullptr; _sentFrame = nullptr;
@@ -253,8 +259,7 @@ void ModbusRTU::task()
_len = 0; _len = 0;
} }
bool ModbusRTU::cleanup() bool ModbusRTU::cleanup() {
{
// Remove timeouted request and forced event // Remove timeouted request and forced event
if (_slaveId && (Kernel::Clock::now() - _timestamp > MODBUSRTU_TIMEOUT)) { if (_slaveId && (Kernel::Clock::now() - _timestamp > MODBUSRTU_TIMEOUT)) {
if (_cb) if (_cb)
@@ -269,68 +274,59 @@ bool ModbusRTU::cleanup()
return false; return false;
} }
uint16_t ModbusRTU::writeHreg(uint8_t slaveId, uint16_t offset, uint16_t value, cbTransaction cb) uint16_t ModbusRTU::writeHreg(uint8_t slaveId, uint16_t offset, uint16_t value, cbTransaction cb) {
{
readSlave(offset, value, FC_WRITE_REG); readSlave(offset, value, FC_WRITE_REG);
return send(slaveId, HREG(offset), cb, nullptr, cb); return send(slaveId, HREG(offset), cb, nullptr, cb);
} }
uint16_t ModbusRTU::writeCoil(uint8_t slaveId, uint16_t offset, bool value, cbTransaction cb) uint16_t ModbusRTU::writeCoil(uint8_t slaveId, uint16_t offset, bool value, cbTransaction cb) {
{
readSlave(offset, COIL_VAL(value), FC_WRITE_COIL); readSlave(offset, COIL_VAL(value), FC_WRITE_COIL);
return send(slaveId, COIL(offset), cb, nullptr, cb); return send(slaveId, COIL(offset), cb, nullptr, cb);
} }
uint16_t ModbusRTU::readCoil(uint8_t slaveId, uint16_t offset, bool* value, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::readCoil(uint8_t slaveId, uint16_t offset, bool *value, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > maxRegs << 4) if (numregs < 0x0001 || numregs > maxRegs << 4)
return false; return false;
readSlave(offset, numregs, FC_READ_COILS); readSlave(offset, numregs, FC_READ_COILS);
return send(slaveId, COIL(offset), cb, value); return send(slaveId, COIL(offset), cb, value);
} }
uint16_t ModbusRTU::writeCoil(uint8_t slaveId, uint16_t offset, bool* value, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::writeCoil(uint8_t slaveId, uint16_t offset, bool *value, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > 0x07D0) if (numregs < 0x0001 || numregs > 0x07D0)
return false; return false;
writeSlaveBits(COIL(offset), offset, numregs, FC_WRITE_COILS, value); writeSlaveBits(COIL(offset), offset, numregs, FC_WRITE_COILS, value);
return send(slaveId, COIL(offset), cb, nullptr, cb); return send(slaveId, COIL(offset), cb, nullptr, cb);
} }
uint16_t ModbusRTU::writeHreg(uint8_t slaveId, uint16_t offset, uint16_t* value, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::writeHreg(uint8_t slaveId, uint16_t offset, uint16_t *value, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > 0x007D) if (numregs < 0x0001 || numregs > 0x007D)
return false; return false;
writeSlaveWords(HREG(offset), offset, numregs, FC_WRITE_REGS, value); writeSlaveWords(HREG(offset), offset, numregs, FC_WRITE_REGS, value);
return send(slaveId, HREG(offset), cb, nullptr, cb); return send(slaveId, HREG(offset), cb, nullptr, cb);
} }
uint16_t ModbusRTU::readHreg(uint8_t slaveId, uint16_t offset, uint16_t* value, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::readHreg(uint8_t slaveId, uint16_t offset, uint16_t *value, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > maxRegs) if (numregs < 0x0001 || numregs > maxRegs)
return false; return false;
readSlave(offset, numregs, FC_READ_REGS); readSlave(offset, numregs, FC_READ_REGS);
return send(slaveId, HREG(offset), cb, value); return send(slaveId, HREG(offset), cb, value);
} }
uint16_t ModbusRTU::readIsts(uint8_t slaveId, uint16_t offset, bool* value, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::readIsts(uint8_t slaveId, uint16_t offset, bool *value, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > maxRegs << 4) if (numregs < 0x0001 || numregs > maxRegs << 4)
return false; return false;
readSlave(offset, numregs, FC_READ_INPUT_STAT); readSlave(offset, numregs, FC_READ_INPUT_STAT);
return send(slaveId, ISTS(offset), cb, value); return send(slaveId, ISTS(offset), cb, value);
} }
uint16_t ModbusRTU::readIreg(uint8_t slaveId, uint16_t offset, uint16_t* value, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::readIreg(uint8_t slaveId, uint16_t offset, uint16_t *value, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > maxRegs) if (numregs < 0x0001 || numregs > maxRegs)
return false; return false;
readSlave(offset, numregs, FC_READ_INPUT_REGS); readSlave(offset, numregs, FC_READ_INPUT_REGS);
return send(slaveId, IREG(offset), cb, value); return send(slaveId, IREG(offset), cb, value);
} }
uint16_t ModbusRTU::pushCoil(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::pushCoil(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > 0x07D0) if (numregs < 0x0001 || numregs > 0x07D0)
return false; return false;
if (!searchRegister(COIL(from))) if (!searchRegister(COIL(from)))
@@ -343,8 +339,7 @@ uint16_t ModbusRTU::pushCoil(uint8_t slaveId, uint16_t to, uint16_t from, uint16
return send(slaveId, COIL(from), cb); return send(slaveId, COIL(from), cb);
} }
uint16_t ModbusRTU::pullCoil(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::pullCoil(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > maxRegs << 4) if (numregs < 0x0001 || numregs > maxRegs << 4)
return false; return false;
#ifdef MODBUSRTU_ADD_REG #ifdef MODBUSRTU_ADD_REG
@@ -354,8 +349,7 @@ uint16_t ModbusRTU::pullCoil(uint8_t slaveId, uint16_t from, uint16_t to, uint16
return send(slaveId, COIL(to), cb); return send(slaveId, COIL(to), cb);
} }
uint16_t ModbusRTU::pullIsts(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::pullIsts(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > maxRegs << 4) if (numregs < 0x0001 || numregs > maxRegs << 4)
return false; return false;
#ifdef MODBUSRTU_ADD_REG #ifdef MODBUSRTU_ADD_REG
@@ -365,8 +359,7 @@ uint16_t ModbusRTU::pullIsts(uint8_t slaveId, uint16_t from, uint16_t to, uint16
return send(slaveId, ISTS(to), cb); return send(slaveId, ISTS(to), cb);
} }
uint16_t ModbusRTU::pushHreg(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::pushHreg(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > 0x007D) if (numregs < 0x0001 || numregs > 0x007D)
return false; return false;
if (!searchRegister(HREG(from))) if (!searchRegister(HREG(from)))
@@ -379,8 +372,7 @@ uint16_t ModbusRTU::pushHreg(uint8_t slaveId, uint16_t to, uint16_t from, uint16
return send(slaveId, HREG(from), cb); return send(slaveId, HREG(from), cb);
} }
uint16_t ModbusRTU::pullHreg(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::pullHreg(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > maxRegs) if (numregs < 0x0001 || numregs > maxRegs)
return false; return false;
#ifdef MODBUSRTU_ADD_REG #ifdef MODBUSRTU_ADD_REG
@@ -390,8 +382,7 @@ uint16_t ModbusRTU::pullHreg(uint8_t slaveId, uint16_t from, uint16_t to, uint16
return send(slaveId, HREG(to), cb); return send(slaveId, HREG(to), cb);
} }
uint16_t ModbusRTU::pullIreg(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::pullIreg(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > maxRegs) if (numregs < 0x0001 || numregs > maxRegs)
return false; return false;
#ifdef MODBUSRTU_ADD_REG #ifdef MODBUSRTU_ADD_REG
@@ -401,8 +392,7 @@ uint16_t ModbusRTU::pullIreg(uint8_t slaveId, uint16_t from, uint16_t to, uint16
return send(slaveId, IREG(to), cb); return send(slaveId, IREG(to), cb);
} }
uint16_t ModbusRTU::pushIregToHreg(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::pushIregToHreg(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > 0x007D) if (numregs < 0x0001 || numregs > 0x007D)
return false; return false;
if (!searchRegister(IREG(from))) if (!searchRegister(IREG(from)))
@@ -415,8 +405,7 @@ uint16_t ModbusRTU::pushIregToHreg(uint8_t slaveId, uint16_t to, uint16_t from,
return send(slaveId, IREG(from), cb); return send(slaveId, IREG(from), cb);
} }
uint16_t ModbusRTU::pushIstsToCoil(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::pushIstsToCoil(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > maxRegs << 4) if (numregs < 0x0001 || numregs > maxRegs << 4)
return false; return false;
if (!searchRegister(ISTS(from))) if (!searchRegister(ISTS(from)))
@@ -429,8 +418,7 @@ uint16_t ModbusRTU::pushIstsToCoil(uint8_t slaveId, uint16_t to, uint16_t from,
return send(slaveId, ISTS(from), cb); return send(slaveId, ISTS(from), cb);
} }
uint16_t ModbusRTU::pullHregToIreg(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::pullHregToIreg(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > maxRegs) if (numregs < 0x0001 || numregs > maxRegs)
return false; return false;
#ifdef MODBUSRTU_ADD_REG #ifdef MODBUSRTU_ADD_REG
@@ -440,8 +428,7 @@ uint16_t ModbusRTU::pullHregToIreg(uint8_t slaveId, uint16_t from, uint16_t to,
return send(slaveId, IREG(to), cb); return send(slaveId, IREG(to), cb);
} }
uint16_t ModbusRTU::pullCoilToIsts(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs, cbTransaction cb) uint16_t ModbusRTU::pullCoilToIsts(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs, cbTransaction cb) {
{
if (numregs < 0x0001 || numregs > maxRegs << 4) if (numregs < 0x0001 || numregs > maxRegs << 4)
return false; return false;
#ifdef MODBUSRTU_ADD_REG #ifdef MODBUSRTU_ADD_REG

View File

@@ -5,6 +5,7 @@
This code is licensed under the BSD New License. See LICENSE.txt for more info. This code is licensed under the BSD New License. See LICENSE.txt for more info.
*/ */
#pragma once #pragma once
#include "mbed.h" #include "mbed.h"
#include <Modbus.h> #include <Modbus.h>
@@ -24,12 +25,17 @@
class ModbusRTU : public Modbus { class ModbusRTU : public Modbus {
protected: protected:
CircularBuffer<char, 200> RX_RingBuff; CircularBuffer<char, 200> RX_RingBuff;
UnbufferedSerial* _port; UnbufferedSerial *_port;
DigitalOut* _txPin; DigitalOut *_txPin;
void SerialRXHandler(); void SerialRXHandler();
void SerialTXHandler(); void SerialTXHandler();
uint8_t isDataAvailable(void);
uint8_t Read(void); uint8_t isDataAvailable();
uint8_t Read();
// unsigned int // unsigned int
Kernel::Clock::duration MODBUSRTU_TIMEOUT = 1s; Kernel::Clock::duration MODBUSRTU_TIMEOUT = 1s;
Kernel::Clock::duration _t; // inter-frame delay in mS Kernel::Clock::duration _t; // inter-frame delay in mS
@@ -38,53 +44,87 @@ protected:
uint8_t _slaveId; uint8_t _slaveId;
Kernel::Clock::time_point _timestamp; Kernel::Clock::time_point _timestamp;
cbTransaction _cb = nullptr; cbTransaction _cb = nullptr;
void* _data = nullptr; void *_data = nullptr;
uint8_t* _sentFrame = nullptr; uint8_t *_sentFrame = nullptr;
TAddress _sentReg = COIL(0); TAddress _sentReg = COIL(0);
uint16_t maxRegs = 0x007D; uint16_t maxRegs = 0x007D;
#ifdef ESP32 #ifdef ESP32
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
#endif #endif
bool send(uint8_t slaveId, TAddress startreg, cbTransaction cb, void* data = nullptr, bool waitResponse = true);
bool send(uint8_t slaveId, TAddress startreg, cbTransaction cb, void *data = nullptr, bool waitResponse = true);
// Prepare and send ModbusRTU frame. _frame buffer and _len should be filled with Modbus data // Prepare and send ModbusRTU frame. _frame buffer and _len should be filled with Modbus data
// slaveId - slave id // slaveId - slave id
// startreg - first local register to save returned data to (miningless for write to slave operations) // startreg - first local register to save returned data to (miningless for write to slave operations)
// cb - transaction callback function // cb - transaction callback function
// data - if not null use buffer to save returned data instead of local registers // data - if not null use buffer to save returned data instead of local registers
bool rawSend(uint8_t slaveId, uint8_t* frame, uint8_t len); bool rawSend(uint8_t slaveId, uint8_t *frame, uint8_t len);
bool cleanup(); // Free clients if not connected and remove timedout transactions and transaction with forced events bool cleanup(); // Free clients if not connected and remove timedout transactions and transaction with forced events
uint16_t crc16(uint8_t address, uint8_t* frame, uint8_t pdulen); static uint16_t crc16(uint8_t address, uint8_t *frame, uint8_t pdulen);
public: public:
void setBaudrate(uint32_t baud = -1); void setBaudrate(uint32_t baud = -1);
#if defined(ESP8266) #if defined(ESP8266)
bool begin(BufferedSerial* port, int16_t txPin = -1); bool begin(BufferedSerial* port, int16_t txPin = -1);
#endif #endif
bool begin(UnbufferedSerial* port, PinName txPin = NC);
bool begin(UnbufferedSerial* port); bool begin(UnbufferedSerial *port, PinName txPin = NC);
bool begin(UnbufferedSerial *port);
void task(); void task();
void master() { isMaster = true; }; void master() { isMaster = true; };
void slave(uint8_t slaveId) { _slaveId = slaveId; }; void slave(uint8_t slaveId) { _slaveId = slaveId; };
uint8_t slave() { return _slaveId; }
uint8_t slave() const { return _slaveId; }
uint32_t eventSource() override { return _slaveId; } uint32_t eventSource() override { return _slaveId; }
uint16_t writeHreg(uint8_t slaveId, uint16_t offset, uint16_t value, cbTransaction cb = nullptr); uint16_t writeHreg(uint8_t slaveId, uint16_t offset, uint16_t value, cbTransaction cb = nullptr);
uint16_t writeCoil(uint8_t slaveId, uint16_t offset, bool value, cbTransaction cb = nullptr); uint16_t writeCoil(uint8_t slaveId, uint16_t offset, bool value, cbTransaction cb = nullptr);
uint16_t readCoil(uint8_t slaveId, uint16_t offset, bool* value, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t writeCoil(uint8_t slaveId, uint16_t offset, bool* value, uint16_t numregs = 1, cbTransaction cb = nullptr); uint16_t readCoil(uint8_t slaveId, uint16_t offset, bool *value, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t writeHreg(uint8_t slaveId, uint16_t offset, uint16_t* value, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t readIsts(uint8_t slaveId, uint16_t offset, bool* value, uint16_t numregs = 1, cbTransaction cb = nullptr); uint16_t writeCoil(uint8_t slaveId, uint16_t offset, bool *value, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t readHreg(uint8_t slaveId, uint16_t offset, uint16_t* value, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t readIreg(uint8_t slaveId, uint16_t offset, uint16_t* value, uint16_t numregs = 1, cbTransaction cb = nullptr); uint16_t
writeHreg(uint8_t slaveId, uint16_t offset, uint16_t *value, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t readIsts(uint8_t slaveId, uint16_t offset, bool *value, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t
readHreg(uint8_t slaveId, uint16_t offset, uint16_t *value, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t
readIreg(uint8_t slaveId, uint16_t offset, uint16_t *value, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t pushCoil(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs = 1, cbTransaction cb = nullptr); uint16_t pushCoil(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t pullCoil(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs = 1, cbTransaction cb = nullptr); uint16_t pullCoil(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t pullIsts(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs = 1, cbTransaction cb = nullptr); uint16_t pullIsts(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t pushHreg(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs = 1, cbTransaction cb = nullptr); uint16_t pushHreg(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t pullHreg(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs = 1, cbTransaction cb = nullptr); uint16_t pullHreg(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t pullIreg(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs = 1, cbTransaction cb = nullptr); uint16_t pullIreg(uint8_t slaveId, uint16_t from, uint16_t to, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t pullHregToIreg(uint8_t slaveId, uint16_t offset, uint16_t startreg, uint16_t numregs = 1, cbTransaction cb = nullptr); uint16_t pullHregToIreg(uint8_t slaveId, uint16_t offset, uint16_t startreg, uint16_t numregs = 1,
uint16_t pullCoilToIsts(uint8_t slaveId, uint16_t offset, uint16_t startreg, uint16_t numregs = 1, cbTransaction cb = nullptr); cbTransaction cb = nullptr);
uint16_t pushIstsToCoil(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t pushIregToHreg(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs = 1, cbTransaction cb = nullptr); uint16_t pullCoilToIsts(uint8_t slaveId, uint16_t offset, uint16_t startreg, uint16_t numregs = 1,
cbTransaction cb = nullptr);
uint16_t
pushIstsToCoil(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs = 1, cbTransaction cb = nullptr);
uint16_t
pushIregToHreg(uint8_t slaveId, uint16_t to, uint16_t from, uint16_t numregs = 1, cbTransaction cb = nullptr);
}; };