Khiem Tran / Mbed 2 deprecated STM32_Modbus

Dependencies:   mbed

Committer:
KhiemTran
Date:
Mon Mar 25 14:42:49 2019 +0000
Revision:
3:355a72e1d7d2
Parent:
0:54bd111a5369
Keyword C to C++

Who changed what in which revision?

UserRevisionLine numberNew contents of line
KhiemTran 0:54bd111a5369 1 /*
KhiemTran 0:54bd111a5369 2 Modbus.cpp - Source for Modbus Base Library
KhiemTran 3:355a72e1d7d2 3 Copyright (C) 2019 Khiem Tran
KhiemTran 0:54bd111a5369 4 */
KhiemTran 0:54bd111a5369 5 #include "Modbus.h"
KhiemTran 0:54bd111a5369 6
KhiemTran 0:54bd111a5369 7 Modbus::Modbus() {
KhiemTran 3:355a72e1d7d2 8 _regs_head = NULL;
KhiemTran 3:355a72e1d7d2 9 _regs_last = NULL;
KhiemTran 0:54bd111a5369 10 }
KhiemTran 0:54bd111a5369 11
KhiemTran 0:54bd111a5369 12 TRegister* Modbus::searchRegister(uint16_t address) {
KhiemTran 0:54bd111a5369 13 TRegister *reg = _regs_head;
KhiemTran 0:54bd111a5369 14 //if there is no register configured, bail
KhiemTran 0:54bd111a5369 15 if(reg == 0) return(0);
KhiemTran 0:54bd111a5369 16 //scan through the linked list until the end of the list or the register is found.
KhiemTran 0:54bd111a5369 17 //return the pointer.
KhiemTran 0:54bd111a5369 18 do {
KhiemTran 0:54bd111a5369 19 if (reg->address == address) return(reg);
KhiemTran 0:54bd111a5369 20 reg = reg->next;
KhiemTran 0:54bd111a5369 21 } while(reg);
KhiemTran 0:54bd111a5369 22 return(0);
KhiemTran 0:54bd111a5369 23 }
KhiemTran 0:54bd111a5369 24
KhiemTran 0:54bd111a5369 25 void Modbus::addReg(uint16_t address, uint16_t value) {
KhiemTran 0:54bd111a5369 26 TRegister *newreg;
KhiemTran 0:54bd111a5369 27
KhiemTran 3:355a72e1d7d2 28 newreg = new TRegister();
KhiemTran 3:355a72e1d7d2 29 //newreg = (TRegister *) malloc(sizeof(TRegister));
KhiemTran 0:54bd111a5369 30 newreg->address = address;
KhiemTran 0:54bd111a5369 31 newreg->value = value;
KhiemTran 0:54bd111a5369 32 newreg->next = 0;
KhiemTran 0:54bd111a5369 33
KhiemTran 0:54bd111a5369 34 if(_regs_head == 0) {
KhiemTran 0:54bd111a5369 35 _regs_head = newreg;
KhiemTran 0:54bd111a5369 36 _regs_last = _regs_head;
KhiemTran 0:54bd111a5369 37 } else {
KhiemTran 0:54bd111a5369 38 //Assign the last register's next pointer to newreg.
KhiemTran 0:54bd111a5369 39 _regs_last->next = newreg;
KhiemTran 0:54bd111a5369 40 //then make temp the last register in the list.
KhiemTran 0:54bd111a5369 41 _regs_last = newreg;
KhiemTran 0:54bd111a5369 42 }
KhiemTran 0:54bd111a5369 43 }
KhiemTran 0:54bd111a5369 44
KhiemTran 0:54bd111a5369 45 bool Modbus::Reg(uint16_t address, uint16_t value) {
KhiemTran 0:54bd111a5369 46 TRegister *reg;
KhiemTran 0:54bd111a5369 47 //search for the register address
KhiemTran 0:54bd111a5369 48 reg = this->searchRegister(address);
KhiemTran 0:54bd111a5369 49 //if found then assign the register value to the new value.
KhiemTran 0:54bd111a5369 50 if (reg) {
KhiemTran 0:54bd111a5369 51 reg->value = value;
KhiemTran 0:54bd111a5369 52 return true;
KhiemTran 0:54bd111a5369 53 } else
KhiemTran 0:54bd111a5369 54 return false;
KhiemTran 0:54bd111a5369 55 }
KhiemTran 0:54bd111a5369 56
KhiemTran 0:54bd111a5369 57 uint16_t Modbus::Reg(uint16_t address) {
KhiemTran 0:54bd111a5369 58 TRegister *reg;
KhiemTran 0:54bd111a5369 59 reg = this->searchRegister(address);
KhiemTran 0:54bd111a5369 60 if(reg)
KhiemTran 0:54bd111a5369 61 return(reg->value);
KhiemTran 0:54bd111a5369 62 else
KhiemTran 0:54bd111a5369 63 return(0);
KhiemTran 0:54bd111a5369 64 }
KhiemTran 0:54bd111a5369 65
KhiemTran 0:54bd111a5369 66 void Modbus::addHreg(uint16_t offset, uint16_t value) {
KhiemTran 0:54bd111a5369 67 this->addReg(offset + 40001, value);
KhiemTran 0:54bd111a5369 68 }
KhiemTran 0:54bd111a5369 69
KhiemTran 0:54bd111a5369 70 bool Modbus::Hreg(uint16_t offset, uint16_t value) {
KhiemTran 0:54bd111a5369 71 return Reg(offset + 40001, value);
KhiemTran 0:54bd111a5369 72 }
KhiemTran 0:54bd111a5369 73
KhiemTran 0:54bd111a5369 74 uint16_t Modbus::Hreg(uint16_t offset) {
KhiemTran 0:54bd111a5369 75 return Reg(offset + 40001);
KhiemTran 0:54bd111a5369 76 }
KhiemTran 0:54bd111a5369 77
KhiemTran 0:54bd111a5369 78 #ifndef USE_HOLDING_REGISTERS_ONLY
KhiemTran 0:54bd111a5369 79 void Modbus::addCoil(uint16_t offset, bool value) {
KhiemTran 0:54bd111a5369 80 this->addReg(offset + 1, value?0xFF00:0x0000);
KhiemTran 0:54bd111a5369 81 }
KhiemTran 0:54bd111a5369 82
KhiemTran 0:54bd111a5369 83 void Modbus::addIsts(uint16_t offset, bool value) {
KhiemTran 0:54bd111a5369 84 this->addReg(offset + 10001, value?0xFF00:0x0000);
KhiemTran 0:54bd111a5369 85 }
KhiemTran 0:54bd111a5369 86
KhiemTran 0:54bd111a5369 87 void Modbus::addIreg(uint16_t offset, uint16_t value) {
KhiemTran 0:54bd111a5369 88 this->addReg(offset + 30001, value);
KhiemTran 0:54bd111a5369 89 }
KhiemTran 0:54bd111a5369 90
KhiemTran 0:54bd111a5369 91 bool Modbus::Coil(uint16_t offset, bool value) {
KhiemTran 0:54bd111a5369 92 return Reg(offset + 1, value?0xFF00:0x0000);
KhiemTran 0:54bd111a5369 93 }
KhiemTran 0:54bd111a5369 94
KhiemTran 0:54bd111a5369 95 bool Modbus::Ists(uint16_t offset, bool value) {
KhiemTran 0:54bd111a5369 96 return Reg(offset + 10001, value?0xFF00:0x0000);
KhiemTran 0:54bd111a5369 97 }
KhiemTran 0:54bd111a5369 98
KhiemTran 0:54bd111a5369 99 bool Modbus::Ireg(uint16_t offset, uint16_t value) {
KhiemTran 0:54bd111a5369 100 return Reg(offset + 30001, value);
KhiemTran 0:54bd111a5369 101 }
KhiemTran 0:54bd111a5369 102
KhiemTran 0:54bd111a5369 103 bool Modbus::Coil(uint16_t offset) {
KhiemTran 0:54bd111a5369 104 if (Reg(offset + 1) == 0xFF00) {
KhiemTran 0:54bd111a5369 105 return true;
KhiemTran 0:54bd111a5369 106 } else return false;
KhiemTran 0:54bd111a5369 107 }
KhiemTran 0:54bd111a5369 108
KhiemTran 0:54bd111a5369 109 bool Modbus::Ists(uint16_t offset) {
KhiemTran 0:54bd111a5369 110 if (Reg(offset + 10001) == 0xFF00) {
KhiemTran 0:54bd111a5369 111 return true;
KhiemTran 0:54bd111a5369 112 } else return false;
KhiemTran 0:54bd111a5369 113 }
KhiemTran 0:54bd111a5369 114
KhiemTran 0:54bd111a5369 115 uint16_t Modbus::Ireg(uint16_t offset) {
KhiemTran 0:54bd111a5369 116 return Reg(offset + 30001);
KhiemTran 0:54bd111a5369 117 }
KhiemTran 0:54bd111a5369 118 #endif
KhiemTran 0:54bd111a5369 119
KhiemTran 0:54bd111a5369 120
KhiemTran 0:54bd111a5369 121 void Modbus::receivePDU(uint8_t* frame) {
KhiemTran 0:54bd111a5369 122 uint8_t fcode = frame[0];
KhiemTran 0:54bd111a5369 123 uint16_t field1 = (uint16_t)frame[1] << 8 | (uint16_t)frame[2];
KhiemTran 0:54bd111a5369 124 uint16_t field2 = (uint16_t)frame[3] << 8 | (uint16_t)frame[4];
KhiemTran 0:54bd111a5369 125
KhiemTran 0:54bd111a5369 126 switch (fcode) {
KhiemTran 0:54bd111a5369 127
KhiemTran 0:54bd111a5369 128 case MB_FC_WRITE_REG:
KhiemTran 0:54bd111a5369 129 //field1 = reg, field2 = value
KhiemTran 0:54bd111a5369 130 this->writeSingleRegister(field1, field2);
KhiemTran 0:54bd111a5369 131 break;
KhiemTran 0:54bd111a5369 132
KhiemTran 0:54bd111a5369 133 case MB_FC_READ_REGS:
KhiemTran 0:54bd111a5369 134 //field1 = startreg, field2 = numregs
KhiemTran 0:54bd111a5369 135 this->readRegisters(field1, field2);
KhiemTran 0:54bd111a5369 136 break;
KhiemTran 0:54bd111a5369 137
KhiemTran 0:54bd111a5369 138 case MB_FC_WRITE_REGS:
KhiemTran 0:54bd111a5369 139 //field1 = startreg, field2 = status
KhiemTran 0:54bd111a5369 140 this->writeMultipleRegisters(frame,field1, field2, frame[5]);
KhiemTran 0:54bd111a5369 141 break;
KhiemTran 0:54bd111a5369 142
KhiemTran 0:54bd111a5369 143 #ifndef USE_HOLDING_REGISTERS_ONLY
KhiemTran 0:54bd111a5369 144 case MB_FC_READ_COILS:
KhiemTran 0:54bd111a5369 145 //field1 = startreg, field2 = numregs
KhiemTran 0:54bd111a5369 146 this->readCoils(field1, field2);
KhiemTran 0:54bd111a5369 147 break;
KhiemTran 0:54bd111a5369 148
KhiemTran 0:54bd111a5369 149 case MB_FC_READ_INPUT_STAT:
KhiemTran 0:54bd111a5369 150 //field1 = startreg, field2 = numregs
KhiemTran 0:54bd111a5369 151 this->readInputStatus(field1, field2);
KhiemTran 0:54bd111a5369 152 break;
KhiemTran 0:54bd111a5369 153
KhiemTran 0:54bd111a5369 154 case MB_FC_READ_INPUT_REGS:
KhiemTran 0:54bd111a5369 155 //field1 = startreg, field2 = numregs
KhiemTran 0:54bd111a5369 156 this->readInputRegisters(field1, field2);
KhiemTran 0:54bd111a5369 157 break;
KhiemTran 0:54bd111a5369 158
KhiemTran 0:54bd111a5369 159 case MB_FC_WRITE_COIL:
KhiemTran 0:54bd111a5369 160 //field1 = reg, field2 = status
KhiemTran 0:54bd111a5369 161 this->writeSingleCoil(field1, field2);
KhiemTran 0:54bd111a5369 162 break;
KhiemTran 0:54bd111a5369 163
KhiemTran 0:54bd111a5369 164 case MB_FC_WRITE_COILS:
KhiemTran 0:54bd111a5369 165 //field1 = startreg, field2 = numoutputs
KhiemTran 0:54bd111a5369 166 this->writeMultipleCoils(frame,field1, field2, frame[5]);
KhiemTran 0:54bd111a5369 167 break;
KhiemTran 0:54bd111a5369 168
KhiemTran 0:54bd111a5369 169 #endif
KhiemTran 0:54bd111a5369 170 default:
KhiemTran 0:54bd111a5369 171 this->exceptionResponse(fcode, MB_EX_ILLEGAL_FUNCTION);
KhiemTran 0:54bd111a5369 172 }
KhiemTran 0:54bd111a5369 173 }
KhiemTran 0:54bd111a5369 174
KhiemTran 0:54bd111a5369 175 void Modbus::exceptionResponse(uint8_t fcode, uint8_t excode) {
KhiemTran 0:54bd111a5369 176 //Clean frame buffer
KhiemTran 3:355a72e1d7d2 177 delete[] _frame;
KhiemTran 3:355a72e1d7d2 178 //free(_frame);
KhiemTran 0:54bd111a5369 179 _len = 2;
KhiemTran 3:355a72e1d7d2 180 _frame = new uint8_t[_len];
KhiemTran 3:355a72e1d7d2 181 //_frame = (uint8_t *) malloc(_len);
KhiemTran 0:54bd111a5369 182 _frame[0] = fcode + 0x80;
KhiemTran 0:54bd111a5369 183 _frame[1] = excode;
KhiemTran 0:54bd111a5369 184
KhiemTran 0:54bd111a5369 185 _reply = MB_REPLY_NORMAL;
KhiemTran 0:54bd111a5369 186 }
KhiemTran 0:54bd111a5369 187
KhiemTran 0:54bd111a5369 188 void Modbus::readRegisters(uint16_t startreg, uint16_t numregs) {
KhiemTran 0:54bd111a5369 189 //Check value (numregs)
KhiemTran 0:54bd111a5369 190 if (numregs < 0x0001 || numregs > 0x007D) {
KhiemTran 0:54bd111a5369 191 this->exceptionResponse(MB_FC_READ_REGS, MB_EX_ILLEGAL_VALUE);
KhiemTran 0:54bd111a5369 192 return;
KhiemTran 0:54bd111a5369 193 }
KhiemTran 0:54bd111a5369 194
KhiemTran 0:54bd111a5369 195 //Check Address
KhiemTran 0:54bd111a5369 196 //*** See comments on readCoils method.
KhiemTran 0:54bd111a5369 197 if (!this->searchRegister(startreg + 40001)) {
KhiemTran 0:54bd111a5369 198 this->exceptionResponse(MB_FC_READ_REGS, MB_EX_ILLEGAL_ADDRESS);
KhiemTran 0:54bd111a5369 199 return;
KhiemTran 0:54bd111a5369 200 }
KhiemTran 0:54bd111a5369 201
KhiemTran 0:54bd111a5369 202
KhiemTran 0:54bd111a5369 203 //Clean frame buffer
KhiemTran 3:355a72e1d7d2 204 delete[] _frame;
KhiemTran 3:355a72e1d7d2 205 //free(_frame);
KhiemTran 0:54bd111a5369 206 _len = 0;
KhiemTran 0:54bd111a5369 207
KhiemTran 0:54bd111a5369 208 //calculate the query reply message length
KhiemTran 0:54bd111a5369 209 //for each register queried add 2 bytes
KhiemTran 0:54bd111a5369 210 _len = 2 + numregs * 2;
KhiemTran 0:54bd111a5369 211
KhiemTran 3:355a72e1d7d2 212 _frame = new uint8_t[_len];
KhiemTran 3:355a72e1d7d2 213 //_frame = (uint8_t *) malloc(_len);
KhiemTran 0:54bd111a5369 214 if (!_frame) {
KhiemTran 0:54bd111a5369 215 this->exceptionResponse(MB_FC_READ_REGS, MB_EX_SLAVE_FAILURE);
KhiemTran 0:54bd111a5369 216 return;
KhiemTran 0:54bd111a5369 217 }
KhiemTran 0:54bd111a5369 218
KhiemTran 0:54bd111a5369 219 _frame[0] = MB_FC_READ_REGS;
KhiemTran 0:54bd111a5369 220 _frame[1] = _len - 2; //byte count
KhiemTran 0:54bd111a5369 221
KhiemTran 0:54bd111a5369 222 uint16_t val;
KhiemTran 0:54bd111a5369 223 uint16_t i = 0;
KhiemTran 0:54bd111a5369 224 while(numregs--) {
KhiemTran 0:54bd111a5369 225 //retrieve the value from the register bank for the current register
KhiemTran 0:54bd111a5369 226 val = this->Hreg(startreg + i);
KhiemTran 0:54bd111a5369 227 //write the high byte of the register value
KhiemTran 0:54bd111a5369 228 _frame[2 + i * 2] = val >> 8;
KhiemTran 0:54bd111a5369 229 //write the low byte of the register value
KhiemTran 0:54bd111a5369 230 _frame[3 + i * 2] = val & 0xFF;
KhiemTran 0:54bd111a5369 231 i++;
KhiemTran 0:54bd111a5369 232 }
KhiemTran 0:54bd111a5369 233
KhiemTran 0:54bd111a5369 234 _reply = MB_REPLY_NORMAL;
KhiemTran 0:54bd111a5369 235 }
KhiemTran 0:54bd111a5369 236
KhiemTran 0:54bd111a5369 237 void Modbus::writeSingleRegister(uint16_t reg, uint16_t value) {
KhiemTran 0:54bd111a5369 238 //No necessary verify illegal value (EX_ILLEGAL_VALUE) - because using word (0x0000 - 0x0FFFF)
KhiemTran 0:54bd111a5369 239 //Check Address and execute (reg exists?)
KhiemTran 0:54bd111a5369 240 if (!this->Hreg(reg, value)) {
KhiemTran 0:54bd111a5369 241 this->exceptionResponse(MB_FC_WRITE_REG, MB_EX_ILLEGAL_ADDRESS);
KhiemTran 0:54bd111a5369 242 return;
KhiemTran 0:54bd111a5369 243 }
KhiemTran 0:54bd111a5369 244
KhiemTran 0:54bd111a5369 245 //Check for failure
KhiemTran 0:54bd111a5369 246 if (this->Hreg(reg) != value) {
KhiemTran 0:54bd111a5369 247 this->exceptionResponse(MB_FC_WRITE_REG, MB_EX_SLAVE_FAILURE);
KhiemTran 0:54bd111a5369 248 return;
KhiemTran 0:54bd111a5369 249 }
KhiemTran 0:54bd111a5369 250
KhiemTran 0:54bd111a5369 251 _reply = MB_REPLY_ECHO;
KhiemTran 0:54bd111a5369 252 }
KhiemTran 0:54bd111a5369 253
KhiemTran 0:54bd111a5369 254 void Modbus::writeMultipleRegisters(uint8_t* frame,uint16_t startreg, uint16_t numoutputs, uint8_t bytecount) {
KhiemTran 0:54bd111a5369 255 //Check value
KhiemTran 0:54bd111a5369 256 if (numoutputs < 0x0001 || numoutputs > 0x007B || bytecount != 2 * numoutputs) {
KhiemTran 0:54bd111a5369 257 this->exceptionResponse(MB_FC_WRITE_REGS, MB_EX_ILLEGAL_VALUE);
KhiemTran 0:54bd111a5369 258 return;
KhiemTran 0:54bd111a5369 259 }
KhiemTran 0:54bd111a5369 260
KhiemTran 0:54bd111a5369 261 //Check Address (startreg...startreg + numregs)
KhiemTran 0:54bd111a5369 262 for (int k = 0; k < numoutputs; k++) {
KhiemTran 0:54bd111a5369 263 if (!this->searchRegister(startreg + 40001 + k)) {
KhiemTran 0:54bd111a5369 264 this->exceptionResponse(MB_FC_WRITE_REGS, MB_EX_ILLEGAL_ADDRESS);
KhiemTran 0:54bd111a5369 265 return;
KhiemTran 0:54bd111a5369 266 }
KhiemTran 0:54bd111a5369 267 }
KhiemTran 0:54bd111a5369 268
KhiemTran 0:54bd111a5369 269 //Clean frame buffer
KhiemTran 3:355a72e1d7d2 270 delete[] _frame;
KhiemTran 3:355a72e1d7d2 271 //free(_frame);
KhiemTran 0:54bd111a5369 272 _len = 5;
KhiemTran 3:355a72e1d7d2 273
KhiemTran 3:355a72e1d7d2 274 _frame = new uint8_t[_len];
KhiemTran 3:355a72e1d7d2 275 //_frame = (uint8_t *) malloc(_len);
KhiemTran 0:54bd111a5369 276 if (!_frame) {
KhiemTran 0:54bd111a5369 277 this->exceptionResponse(MB_FC_WRITE_REGS, MB_EX_SLAVE_FAILURE);
KhiemTran 0:54bd111a5369 278 return;
KhiemTran 0:54bd111a5369 279 }
KhiemTran 0:54bd111a5369 280
KhiemTran 0:54bd111a5369 281 _frame[0] = MB_FC_WRITE_REGS;
KhiemTran 0:54bd111a5369 282 _frame[1] = startreg >> 8;
KhiemTran 0:54bd111a5369 283 _frame[2] = startreg & 0x00FF;
KhiemTran 0:54bd111a5369 284 _frame[3] = numoutputs >> 8;
KhiemTran 0:54bd111a5369 285 _frame[4] = numoutputs & 0x00FF;
KhiemTran 0:54bd111a5369 286
KhiemTran 0:54bd111a5369 287 uint16_t val;
KhiemTran 0:54bd111a5369 288 uint16_t i = 0;
KhiemTran 0:54bd111a5369 289 while(numoutputs--) {
KhiemTran 0:54bd111a5369 290 val = (uint16_t)frame[6+i*2] << 8 | (uint16_t)frame[7+i*2];
KhiemTran 0:54bd111a5369 291 this->Hreg(startreg + i, val);
KhiemTran 0:54bd111a5369 292 i++;
KhiemTran 0:54bd111a5369 293 }
KhiemTran 0:54bd111a5369 294
KhiemTran 0:54bd111a5369 295 _reply = MB_REPLY_NORMAL;
KhiemTran 0:54bd111a5369 296 }
KhiemTran 0:54bd111a5369 297
KhiemTran 0:54bd111a5369 298 #ifndef USE_HOLDING_REGISTERS_ONLY
KhiemTran 0:54bd111a5369 299 void Modbus::readCoils(uint16_t startreg, uint16_t numregs) {
KhiemTran 0:54bd111a5369 300 //Check value (numregs)
KhiemTran 0:54bd111a5369 301 if (numregs < 0x0001 || numregs > 0x07D0) {
KhiemTran 0:54bd111a5369 302 this->exceptionResponse(MB_FC_READ_COILS, MB_EX_ILLEGAL_VALUE);
KhiemTran 0:54bd111a5369 303 return;
KhiemTran 0:54bd111a5369 304 }
KhiemTran 0:54bd111a5369 305
KhiemTran 0:54bd111a5369 306 //Check Address
KhiemTran 0:54bd111a5369 307 //Check only startreg. Is this correct?
KhiemTran 0:54bd111a5369 308 //When I check all registers in range I got errors in ScadaBR
KhiemTran 0:54bd111a5369 309 //I think that ScadaBR request more than one in the single request
KhiemTran 0:54bd111a5369 310 //when you have more then one datapoint configured from same type.
KhiemTran 0:54bd111a5369 311 if (!this->searchRegister(startreg + 1)) {
KhiemTran 0:54bd111a5369 312 this->exceptionResponse(MB_FC_READ_COILS, MB_EX_ILLEGAL_ADDRESS);
KhiemTran 0:54bd111a5369 313 return;
KhiemTran 0:54bd111a5369 314 }
KhiemTran 0:54bd111a5369 315
KhiemTran 0:54bd111a5369 316 //Clean frame buffer
KhiemTran 3:355a72e1d7d2 317 delete[] _frame;
KhiemTran 3:355a72e1d7d2 318 //free(_frame);
KhiemTran 0:54bd111a5369 319 _len = 0;
KhiemTran 0:54bd111a5369 320
KhiemTran 0:54bd111a5369 321 //Determine the message length = function type, byte count and
KhiemTran 0:54bd111a5369 322 //for each group of 8 registers the message length increases by 1
KhiemTran 0:54bd111a5369 323 _len = 2 + numregs/8;
KhiemTran 0:54bd111a5369 324 if (numregs%8) _len++; //Add 1 to the message length for the partial byte.
KhiemTran 0:54bd111a5369 325
KhiemTran 3:355a72e1d7d2 326 _frame = new uint8_t[_len];
KhiemTran 3:355a72e1d7d2 327 //_frame = (uint8_t *) malloc(_len);
KhiemTran 0:54bd111a5369 328 if (!_frame) {
KhiemTran 0:54bd111a5369 329 this->exceptionResponse(MB_FC_READ_COILS, MB_EX_SLAVE_FAILURE);
KhiemTran 0:54bd111a5369 330 return;
KhiemTran 0:54bd111a5369 331 }
KhiemTran 0:54bd111a5369 332
KhiemTran 0:54bd111a5369 333 _frame[0] = MB_FC_READ_COILS;
KhiemTran 0:54bd111a5369 334 _frame[1] = _len - 2; //byte count (_len - function code and byte count)
KhiemTran 0:54bd111a5369 335
KhiemTran 0:54bd111a5369 336 uint8_t bitn = 0;
KhiemTran 0:54bd111a5369 337 uint16_t totregs = numregs;
KhiemTran 0:54bd111a5369 338 uint16_t i;
KhiemTran 0:54bd111a5369 339 while (numregs--) {
KhiemTran 0:54bd111a5369 340 i = (totregs - numregs) / 8;
KhiemTran 0:54bd111a5369 341 if (this->Coil(startreg))
KhiemTran 0:54bd111a5369 342 bitSet(_frame[2+i], bitn);
KhiemTran 0:54bd111a5369 343 else
KhiemTran 0:54bd111a5369 344 bitClear(_frame[2+i], bitn);
KhiemTran 0:54bd111a5369 345 //increment the bit index
KhiemTran 0:54bd111a5369 346 bitn++;
KhiemTran 0:54bd111a5369 347 if (bitn == 8) bitn = 0;
KhiemTran 0:54bd111a5369 348 //increment the register
KhiemTran 0:54bd111a5369 349 startreg++;
KhiemTran 0:54bd111a5369 350 }
KhiemTran 0:54bd111a5369 351
KhiemTran 0:54bd111a5369 352 _reply = MB_REPLY_NORMAL;
KhiemTran 0:54bd111a5369 353 }
KhiemTran 0:54bd111a5369 354
KhiemTran 0:54bd111a5369 355 void Modbus::readInputStatus(uint16_t startreg, uint16_t numregs) {
KhiemTran 0:54bd111a5369 356 //Check value (numregs)
KhiemTran 0:54bd111a5369 357 if (numregs < 0x0001 || numregs > 0x07D0) {
KhiemTran 0:54bd111a5369 358 this->exceptionResponse(MB_FC_READ_INPUT_STAT, MB_EX_ILLEGAL_VALUE);
KhiemTran 0:54bd111a5369 359 return;
KhiemTran 0:54bd111a5369 360 }
KhiemTran 0:54bd111a5369 361
KhiemTran 0:54bd111a5369 362 //Check Address
KhiemTran 0:54bd111a5369 363 //*** See comments on readCoils method.
KhiemTran 0:54bd111a5369 364 if (!this->searchRegister(startreg + 10001)) {
KhiemTran 0:54bd111a5369 365 this->exceptionResponse(MB_FC_READ_COILS, MB_EX_ILLEGAL_ADDRESS);
KhiemTran 0:54bd111a5369 366 return;
KhiemTran 0:54bd111a5369 367 }
KhiemTran 0:54bd111a5369 368
KhiemTran 0:54bd111a5369 369 //Clean frame buffer
KhiemTran 3:355a72e1d7d2 370 delete[] _frame;
KhiemTran 3:355a72e1d7d2 371 //free(_frame);
KhiemTran 0:54bd111a5369 372 _len = 0;
KhiemTran 0:54bd111a5369 373
KhiemTran 0:54bd111a5369 374 //Determine the message length = function type, byte count and
KhiemTran 0:54bd111a5369 375 //for each group of 8 registers the message length increases by 1
KhiemTran 0:54bd111a5369 376 _len = 2 + numregs/8;
KhiemTran 0:54bd111a5369 377 if (numregs%8) _len++; //Add 1 to the message length for the partial byte.
KhiemTran 0:54bd111a5369 378
KhiemTran 3:355a72e1d7d2 379 _frame = new uint8_t[_len];
KhiemTran 3:355a72e1d7d2 380 //_frame = (uint8_t *) malloc(_len);
KhiemTran 0:54bd111a5369 381 if (!_frame) {
KhiemTran 0:54bd111a5369 382 this->exceptionResponse(MB_FC_READ_INPUT_STAT, MB_EX_SLAVE_FAILURE);
KhiemTran 0:54bd111a5369 383 return;
KhiemTran 0:54bd111a5369 384 }
KhiemTran 0:54bd111a5369 385
KhiemTran 0:54bd111a5369 386 _frame[0] = MB_FC_READ_INPUT_STAT;
KhiemTran 0:54bd111a5369 387 _frame[1] = _len - 2;
KhiemTran 0:54bd111a5369 388
KhiemTran 0:54bd111a5369 389 uint8_t bitn = 0;
KhiemTran 0:54bd111a5369 390 uint16_t totregs = numregs;
KhiemTran 0:54bd111a5369 391 uint16_t i;
KhiemTran 0:54bd111a5369 392 while (numregs--) {
KhiemTran 0:54bd111a5369 393 i = (totregs - numregs) / 8;
KhiemTran 0:54bd111a5369 394 if (this->Ists(startreg))
KhiemTran 0:54bd111a5369 395 bitSet(_frame[2+i], bitn);
KhiemTran 0:54bd111a5369 396 else
KhiemTran 0:54bd111a5369 397 bitClear(_frame[2+i], bitn);
KhiemTran 0:54bd111a5369 398 //increment the bit index
KhiemTran 0:54bd111a5369 399 bitn++;
KhiemTran 0:54bd111a5369 400 if (bitn == 8) bitn = 0;
KhiemTran 0:54bd111a5369 401 //increment the register
KhiemTran 0:54bd111a5369 402 startreg++;
KhiemTran 0:54bd111a5369 403 }
KhiemTran 0:54bd111a5369 404
KhiemTran 0:54bd111a5369 405 _reply = MB_REPLY_NORMAL;
KhiemTran 0:54bd111a5369 406 }
KhiemTran 0:54bd111a5369 407
KhiemTran 0:54bd111a5369 408 void Modbus::readInputRegisters(uint16_t startreg, uint16_t numregs) {
KhiemTran 0:54bd111a5369 409 //Check value (numregs)
KhiemTran 0:54bd111a5369 410 if (numregs < 0x0001 || numregs > 0x007D) {
KhiemTran 0:54bd111a5369 411 this->exceptionResponse(MB_FC_READ_INPUT_REGS, MB_EX_ILLEGAL_VALUE);
KhiemTran 0:54bd111a5369 412 return;
KhiemTran 0:54bd111a5369 413 }
KhiemTran 0:54bd111a5369 414
KhiemTran 0:54bd111a5369 415 //Check Address
KhiemTran 0:54bd111a5369 416 //*** See comments on readCoils method.
KhiemTran 0:54bd111a5369 417 if (!this->searchRegister(startreg + 30001)) {
KhiemTran 0:54bd111a5369 418 this->exceptionResponse(MB_FC_READ_COILS, MB_EX_ILLEGAL_ADDRESS);
KhiemTran 0:54bd111a5369 419 return;
KhiemTran 0:54bd111a5369 420 }
KhiemTran 0:54bd111a5369 421
KhiemTran 0:54bd111a5369 422 //Clean frame buffer
KhiemTran 3:355a72e1d7d2 423 delete[] _frame;
KhiemTran 3:355a72e1d7d2 424 //free(_frame);
KhiemTran 0:54bd111a5369 425 _len = 0;
KhiemTran 0:54bd111a5369 426
KhiemTran 0:54bd111a5369 427 //calculate the query reply message length
KhiemTran 0:54bd111a5369 428 //for each register queried add 2 bytes
KhiemTran 0:54bd111a5369 429 _len = 2 + numregs * 2;
KhiemTran 0:54bd111a5369 430
KhiemTran 3:355a72e1d7d2 431 _frame = new uint8_t[_len];
KhiemTran 3:355a72e1d7d2 432 //_frame = (uint8_t *) malloc(_len);
KhiemTran 0:54bd111a5369 433 if (!_frame) {
KhiemTran 0:54bd111a5369 434 this->exceptionResponse(MB_FC_READ_INPUT_REGS, MB_EX_SLAVE_FAILURE);
KhiemTran 0:54bd111a5369 435 return;
KhiemTran 0:54bd111a5369 436 }
KhiemTran 0:54bd111a5369 437
KhiemTran 0:54bd111a5369 438 _frame[0] = MB_FC_READ_INPUT_REGS;
KhiemTran 0:54bd111a5369 439 _frame[1] = _len - 2;
KhiemTran 0:54bd111a5369 440
KhiemTran 0:54bd111a5369 441 uint16_t val;
KhiemTran 0:54bd111a5369 442 uint16_t i = 0;
KhiemTran 0:54bd111a5369 443 while(numregs--) {
KhiemTran 0:54bd111a5369 444 //retrieve the value from the register bank for the current register
KhiemTran 0:54bd111a5369 445 val = this->Ireg(startreg + i);
KhiemTran 0:54bd111a5369 446 //write the high byte of the register value
KhiemTran 0:54bd111a5369 447 _frame[2 + i * 2] = val >> 8;
KhiemTran 0:54bd111a5369 448 //write the low byte of the register value
KhiemTran 0:54bd111a5369 449 _frame[3 + i * 2] = val & 0xFF;
KhiemTran 0:54bd111a5369 450 i++;
KhiemTran 0:54bd111a5369 451 }
KhiemTran 0:54bd111a5369 452
KhiemTran 0:54bd111a5369 453 _reply = MB_REPLY_NORMAL;
KhiemTran 0:54bd111a5369 454 }
KhiemTran 0:54bd111a5369 455
KhiemTran 0:54bd111a5369 456 void Modbus::writeSingleCoil(uint16_t reg, uint16_t status) {
KhiemTran 0:54bd111a5369 457 //Check value (status)
KhiemTran 0:54bd111a5369 458 if (status != 0xFF00 && status != 0x0000) {
KhiemTran 0:54bd111a5369 459 this->exceptionResponse(MB_FC_WRITE_COIL, MB_EX_ILLEGAL_VALUE);
KhiemTran 0:54bd111a5369 460 return;
KhiemTran 0:54bd111a5369 461 }
KhiemTran 0:54bd111a5369 462
KhiemTran 0:54bd111a5369 463 //Check Address and execute (reg exists?)
KhiemTran 0:54bd111a5369 464 if (!this->Coil(reg, (bool)status)) {
KhiemTran 0:54bd111a5369 465 this->exceptionResponse(MB_FC_WRITE_COIL, MB_EX_ILLEGAL_ADDRESS);
KhiemTran 0:54bd111a5369 466 return;
KhiemTran 0:54bd111a5369 467 }
KhiemTran 0:54bd111a5369 468
KhiemTran 0:54bd111a5369 469 //Check for failure
KhiemTran 0:54bd111a5369 470 if (this->Coil(reg) != (bool)status) {
KhiemTran 0:54bd111a5369 471 this->exceptionResponse(MB_FC_WRITE_COIL, MB_EX_SLAVE_FAILURE);
KhiemTran 0:54bd111a5369 472 return;
KhiemTran 0:54bd111a5369 473 }
KhiemTran 0:54bd111a5369 474
KhiemTran 0:54bd111a5369 475 _reply = MB_REPLY_ECHO;
KhiemTran 0:54bd111a5369 476 }
KhiemTran 0:54bd111a5369 477
KhiemTran 0:54bd111a5369 478 void Modbus::writeMultipleCoils(uint8_t* frame,uint16_t startreg, uint16_t numoutputs, uint8_t bytecount) {
KhiemTran 0:54bd111a5369 479 //Check value
KhiemTran 0:54bd111a5369 480 uint16_t bytecount_calc = numoutputs / 8;
KhiemTran 0:54bd111a5369 481 if (numoutputs%8) bytecount_calc++;
KhiemTran 0:54bd111a5369 482 if (numoutputs < 0x0001 || numoutputs > 0x07B0 || bytecount != bytecount_calc) {
KhiemTran 0:54bd111a5369 483 this->exceptionResponse(MB_FC_WRITE_COILS, MB_EX_ILLEGAL_VALUE);
KhiemTran 0:54bd111a5369 484 return;
KhiemTran 0:54bd111a5369 485 }
KhiemTran 0:54bd111a5369 486
KhiemTran 0:54bd111a5369 487 //Check Address (startreg...startreg + numregs)
KhiemTran 0:54bd111a5369 488 for (int k = 0; k < numoutputs; k++) {
KhiemTran 0:54bd111a5369 489 if (!this->searchRegister(startreg + 1 + k)) {
KhiemTran 0:54bd111a5369 490 this->exceptionResponse(MB_FC_WRITE_COILS, MB_EX_ILLEGAL_ADDRESS);
KhiemTran 0:54bd111a5369 491 return;
KhiemTran 0:54bd111a5369 492 }
KhiemTran 0:54bd111a5369 493 }
KhiemTran 0:54bd111a5369 494
KhiemTran 0:54bd111a5369 495 //Clean frame buffer
KhiemTran 3:355a72e1d7d2 496 delete[] _frame;
KhiemTran 3:355a72e1d7d2 497 //free(_frame);
KhiemTran 0:54bd111a5369 498 _len = 5;
KhiemTran 3:355a72e1d7d2 499 _frame = new uint8_t[_len];
KhiemTran 3:355a72e1d7d2 500 //_frame = (uint8_t *) malloc(_len);
KhiemTran 0:54bd111a5369 501 if (!_frame) {
KhiemTran 0:54bd111a5369 502 this->exceptionResponse(MB_FC_WRITE_COILS, MB_EX_SLAVE_FAILURE);
KhiemTran 0:54bd111a5369 503 return;
KhiemTran 0:54bd111a5369 504 }
KhiemTran 0:54bd111a5369 505
KhiemTran 0:54bd111a5369 506 _frame[0] = MB_FC_WRITE_COILS;
KhiemTran 0:54bd111a5369 507 _frame[1] = startreg >> 8;
KhiemTran 0:54bd111a5369 508 _frame[2] = startreg & 0x00FF;
KhiemTran 0:54bd111a5369 509 _frame[3] = numoutputs >> 8;
KhiemTran 0:54bd111a5369 510 _frame[4] = numoutputs & 0x00FF;
KhiemTran 0:54bd111a5369 511
KhiemTran 0:54bd111a5369 512 uint8_t bitn = 0;
KhiemTran 0:54bd111a5369 513 uint16_t totoutputs = numoutputs;
KhiemTran 0:54bd111a5369 514 uint16_t i;
KhiemTran 0:54bd111a5369 515 while (numoutputs--) {
KhiemTran 0:54bd111a5369 516 i = (totoutputs - numoutputs) / 8;
KhiemTran 0:54bd111a5369 517 this->Coil(startreg, bitRead(frame[6+i], bitn));
KhiemTran 0:54bd111a5369 518 //increment the bit index
KhiemTran 0:54bd111a5369 519 bitn++;
KhiemTran 0:54bd111a5369 520 if (bitn == 8) bitn = 0;
KhiemTran 0:54bd111a5369 521 //increment the register
KhiemTran 0:54bd111a5369 522 startreg++;
KhiemTran 0:54bd111a5369 523 }
KhiemTran 0:54bd111a5369 524
KhiemTran 0:54bd111a5369 525 _reply = MB_REPLY_NORMAL;
KhiemTran 0:54bd111a5369 526 }
KhiemTran 0:54bd111a5369 527 #endif
KhiemTran 0:54bd111a5369 528
KhiemTran 0:54bd111a5369 529
KhiemTran 0:54bd111a5369 530