Modbus Master and Slave for Arduino  1.2
Arduino library for implementing a Modbus Master or Slave through Serial port
ModbusRtu.h
Go to the documentation of this file.
1 
48 typedef struct {
49  uint8_t u8id;
50  uint8_t u8fct;
51  uint16_t u16RegAdd;
52  uint16_t u16CoilsNo;
53  uint16_t *au16reg;
54 }
55 modbus_t;
56 
57 enum {
61 };
62 
68 enum MESSAGE {
69  ID = 0,
70  FUNC,
76 };
77 
87 enum MB_FC {
88  MB_FC_NONE = 0,
97 };
98 
99 enum COM_STATES {
100  COM_IDLE = 0,
102 
103 };
104 
105 enum ERR_LIST {
111 };
112 
113 enum {
114  NO_REPLY = 255,
119 };
120 
121 const unsigned char fctsupported[] = {
130 };
131 
132 #define T35 5
133 #define MAX_BUFFER 64
134 
135 
141 class Modbus {
142 private:
143  HardwareSerial *port;
144  uint8_t u8id;
145  uint8_t u8serno;
146  uint8_t u8txenpin;
147  uint8_t u8state;
148  uint8_t u8lastError;
149  uint8_t au8Buffer[MAX_BUFFER];
150  uint8_t u8BufferSize;
151  uint8_t u8lastRec;
152  uint16_t *au16regs;
153  uint16_t u16InCnt, u16OutCnt, u16errCnt;
154  uint16_t u16timeOut;
155  uint32_t u32time, u32timeOut;
156  uint8_t u8regsize;
157 
158  void init(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin);
159  void sendTxBuffer();
160  int8_t getRxBuffer();
161  uint16_t calcCRC(uint8_t u8length);
162  uint8_t validateAnswer();
163  uint8_t validateRequest();
164  void get_FC1();
165  void get_FC3();
166  int8_t process_FC1( uint16_t *regs, uint8_t u8size );
167  int8_t process_FC3( uint16_t *regs, uint8_t u8size );
168  int8_t process_FC5( uint16_t *regs, uint8_t u8size );
169  int8_t process_FC6( uint16_t *regs, uint8_t u8size );
170  int8_t process_FC15( uint16_t *regs, uint8_t u8size );
171  int8_t process_FC16( uint16_t *regs, uint8_t u8size );
172  void buildException( uint8_t u8exception ); // build exception message
173 
174 public:
175  Modbus();
176  Modbus(uint8_t u8id, uint8_t u8serno);
177  Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin);
178  void begin(long u32speed);
179  void begin();
180  void setTimeOut( uint16_t u16timeout);
181  uint16_t getTimeOut();
182  boolean getTimeOutState();
183  int8_t query( modbus_t telegram );
184  int8_t poll();
185  int8_t poll( uint16_t *regs, uint8_t u8size );
186  uint16_t getInCnt();
187  uint16_t getOutCnt();
188  uint16_t getErrCnt();
189  uint8_t getID();
190  uint8_t getState();
191  uint8_t getLastError();
192  void setID( uint8_t u8id );
193  void end();
194 };
195 
196 /* _____PUBLIC FUNCTIONS_____________________________________________________ */
197 
205  init(0, 0, 0);
206 }
207 
218 Modbus::Modbus(uint8_t u8id, uint8_t u8serno) {
219  init(u8id, u8serno, 0);
220 }
221 
234 Modbus::Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin) {
235  init(u8id, u8serno, u8txenpin);
236 }
237 
250 void Modbus::begin(long u32speed) {
251 
252  switch( u8serno ) {
253 #if defined(UBRR1H)
254  case 1:
255  port = &Serial1;
256  break;
257 #endif
258 
259 #if defined(UBRR2H)
260  case 2:
261  port = &Serial2;
262  break;
263 #endif
264 
265 #if defined(UBRR3H)
266  case 3:
267  port = &Serial3;
268  break;
269 #endif
270  case 0:
271  default:
272  port = &Serial;
273  break;
274  }
275 
276  // port->begin(u32speed, u8config);
277  port->begin(u32speed);
278  if (u8txenpin > 1) { // pin 0 & pin 1 are reserved for RX/TX
279  // return RS485 transceiver to transmit mode
280  pinMode(u8txenpin, OUTPUT);
281  digitalWrite(u8txenpin, LOW);
282  }
283 
284  port->flush();
285  u8lastRec = u8BufferSize = 0;
286  u16InCnt = u16OutCnt = u16errCnt = 0;
287 }
288 
300  begin(19200);
301 }
302 
310 void Modbus::setID( uint8_t u8id) {
311  if (( u8id != 0) && (u8id <= 247)) {
312  this->u8id = u8id;
313  }
314 }
315 
323 uint8_t Modbus::getID() {
324  return this->u8id;
325 }
326 
338 void Modbus::setTimeOut( uint16_t u16timeOut) {
339  this->u16timeOut = u16timeOut;
340 }
341 
351  return (millis() > u32timeOut);
352 }
353 
362 uint16_t Modbus::getInCnt() {
363  return u16InCnt;
364 }
365 
374 uint16_t Modbus::getOutCnt() {
375  return u16OutCnt;
376 }
377 
386 uint16_t Modbus::getErrCnt() {
387  return u16errCnt;
388 }
389 
396 uint8_t Modbus::getState() {
397  return u8state;
398 }
399 
410  return u8lastError;
411 }
412 
425 int8_t Modbus::query( modbus_t telegram ) {
426  uint8_t u8regsno, u8bytesno;
427  if (u8id!=0) return -2;
428  if (u8state != COM_IDLE) return -1;
429 
430  if ((telegram.u8id==0) || (telegram.u8id>247)) return -3;
431 
432  au16regs = telegram.au16reg;
433 
434  // telegram header
435  au8Buffer[ ID ] = telegram.u8id;
436  au8Buffer[ FUNC ] = telegram.u8fct;
437  au8Buffer[ ADD_HI ] = highByte(telegram.u16RegAdd );
438  au8Buffer[ ADD_LO ] = lowByte( telegram.u16RegAdd );
439 
440  switch( telegram.u8fct ) {
441  case MB_FC_READ_COILS:
445  au8Buffer[ NB_HI ] = highByte(telegram.u16CoilsNo );
446  au8Buffer[ NB_LO ] = lowByte( telegram.u16CoilsNo );
447  u8BufferSize = 6;
448  break;
449  case MB_FC_WRITE_COIL:
450  au8Buffer[ NB_HI ] = ((au16regs[0] > 0) ? 0xff : 0);
451  au8Buffer[ NB_LO ] = 0;
452  u8BufferSize = 6;
453  break;
455  au8Buffer[ NB_HI ] = highByte(au16regs[0]);
456  au8Buffer[ NB_LO ] = lowByte(au16regs[0]);
457  u8BufferSize = 6;
458  break;
459  case MB_FC_WRITE_MULTIPLE_COILS: // TODO: implement "sending coils"
460  u8regsno = telegram.u16CoilsNo / 16;
461  u8bytesno = u8regsno * 2;
462  if ((telegram.u16CoilsNo % 16) != 0) {
463  u8bytesno++;
464  u8regsno++;
465  }
466 
467  au8Buffer[ NB_HI ] = highByte(telegram.u16CoilsNo );
468  au8Buffer[ NB_LO ] = lowByte( telegram.u16CoilsNo );
469  au8Buffer[ NB_LO+1 ] = u8bytesno;
470  u8BufferSize = 7;
471 
472  u8regsno = u8bytesno = 0; // now auxiliary registers
473  for (uint16_t i = 0; i < telegram.u16CoilsNo; i++) {
474 
475 
476  }
477  break;
478 
480  au8Buffer[ NB_HI ] = highByte(telegram.u16CoilsNo );
481  au8Buffer[ NB_LO ] = lowByte( telegram.u16CoilsNo );
482  au8Buffer[ NB_LO+1 ] = (uint8_t) ( telegram.u16CoilsNo * 2 );
483  u8BufferSize = 7;
484 
485  for (uint16_t i=0; i< telegram.u16CoilsNo; i++) {
486  au8Buffer[ u8BufferSize ] = highByte( au16regs[ i ] );
487  u8BufferSize++;
488  au8Buffer[ u8BufferSize ] = lowByte( au16regs[ i ] );
489  u8BufferSize++;
490  }
491  break;
492  }
493 
494  sendTxBuffer();
495  u8state = COM_WAITING;
496  return 0;
497 }
498 
513 int8_t Modbus::poll() {
514  // check if there is any incoming frame
515  uint8_t u8current = port->available();
516 
517  if (millis() > u32timeOut) {
518  u8state = COM_IDLE;
519  u8lastError = NO_REPLY;
520  u16errCnt++;
521  return 0;
522  }
523 
524  if (u8current == 0) return 0;
525 
526  // check T35 after frame end or still no frame end
527  if (u8current != u8lastRec) {
528  u8lastRec = u8current;
529  u32time = millis() + T35;
530  return 0;
531  }
532  if (millis() < u32time) return 0;
533 
534  // transfer Serial buffer frame to auBuffer
535  u8lastRec = 0;
536  int8_t i8state = getRxBuffer();
537  if (i8state < 7) {
538  u8state = COM_IDLE;
539  u16errCnt++;
540  return i8state;
541  }
542 
543  // validate message: id, CRC, FCT, exception
544  uint8_t u8exception = validateAnswer();
545  if (u8exception != 0) {
546  u8state = COM_IDLE;
547  return u8exception;
548  }
549 
550  // process answer
551  switch( au8Buffer[ FUNC ] ) {
552  case MB_FC_READ_COILS:
554  // call get_FC1 to transfer the incoming message to au16regs buffer
555  get_FC1( );
556  break;
558  case MB_FC_READ_REGISTERS :
559  // call get_FC3 to transfer the incoming message to au16regs buffer
560  get_FC3( );
561  break;
562  case MB_FC_WRITE_COIL:
563  case MB_FC_WRITE_REGISTER :
566  // nothing to do
567  break;
568  default:
569  break;
570  }
571  u8state = COM_IDLE;
572  return u8BufferSize;
573 }
574 
588 int8_t Modbus::poll( uint16_t *regs, uint8_t u8size ) {
589 
590  au16regs = regs;
591  u8regsize = u8size;
592 
593  // check if there is any incoming frame
594  uint8_t u8current = port->available();
595  if (u8current == 0) return 0;
596 
597  // check T35 after frame end or still no frame end
598  if (u8current != u8lastRec) {
599  u8lastRec = u8current;
600  u32time = millis() + T35;
601  return 0;
602  }
603  if (millis() < u32time) return 0;
604 
605  u8lastRec = 0;
606  int8_t i8state = getRxBuffer();
607  u8lastError = i8state;
608  if (i8state < 7) return i8state;
609 
610  // check slave id
611  if (au8Buffer[ ID ] != u8id) return 0;
612 
613  // validate message: CRC, FCT, address and size
614  uint8_t u8exception = validateRequest();
615  if (u8exception > 0) {
616  if (u8exception != NO_REPLY) {
617  buildException( u8exception );
618  sendTxBuffer();
619  }
620  u8lastError = u8exception;
621  return u8exception;
622  }
623 
624  u32timeOut = millis() + long(u16timeOut);
625  u8lastError = 0;
626 
627  // process message
628  switch( au8Buffer[ FUNC ] ) {
629  case MB_FC_READ_COILS:
631  return process_FC1( regs, u8size );
632  break;
634  case MB_FC_READ_REGISTERS :
635  return process_FC3( regs, u8size );
636  break;
637  case MB_FC_WRITE_COIL:
638  return process_FC5( regs, u8size );
639  break;
640  case MB_FC_WRITE_REGISTER :
641  return process_FC6( regs, u8size );
642  break;
644  return process_FC15( regs, u8size );
645  break;
647  return process_FC16( regs, u8size );
648  break;
649  default:
650  break;
651  }
652  return i8state;
653 }
654 
655 /* _____PRIVATE FUNCTIONS_____________________________________________________ */
656 
657 void Modbus::init(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin) {
658  this->u8id = u8id;
659  this->u8serno = (u8serno > 3) ? 0 : u8serno;
660  this->u8txenpin = u8txenpin;
661  this->u16timeOut = 1000;
662 }
663 
671 int8_t Modbus::getRxBuffer() {
672  boolean bBuffOverflow = false;
673 
674  if (u8txenpin > 1) digitalWrite( u8txenpin, LOW );
675 
676  u8BufferSize = 0;
677  while ( port->available() ) {
678  au8Buffer[ u8BufferSize ] = port->read();
679  u8BufferSize ++;
680 
681  if (u8BufferSize >= MAX_BUFFER) bBuffOverflow = true;
682  }
683  u16InCnt++;
684 
685  if (bBuffOverflow) {
686  u16errCnt++;
687  return ERR_BUFF_OVERFLOW;
688  }
689  return u8BufferSize;
690 }
691 
704 void Modbus::sendTxBuffer() {
705  uint8_t i = 0;
706 
707  // append CRC to message
708  uint16_t u16crc = calcCRC( u8BufferSize );
709  au8Buffer[ u8BufferSize ] = u16crc >> 8;
710  u8BufferSize++;
711  au8Buffer[ u8BufferSize ] = u16crc & 0x00ff;
712  u8BufferSize++;
713 
714  // set RS485 transceiver to transmit mode
715  if (u8txenpin > 1) {
716  switch( u8serno ) {
717 #if defined(UBRR1H)
718  case 1:
719  UCSR1A=UCSR1A |(1 << TXC1);
720  break;
721 #endif
722 
723 #if defined(UBRR2H)
724  case 2:
725  UCSR2A=UCSR2A |(1 << TXC2);
726  break;
727 #endif
728 
729 #if defined(UBRR3H)
730  case 3:
731  UCSR3A=UCSR3A |(1 << TXC3);
732  break;
733 #endif
734  case 0:
735  default:
736  UCSR0A=UCSR0A |(1 << TXC0);
737  break;
738  }
739  digitalWrite( u8txenpin, HIGH );
740  }
741 
742  // transfer buffer to serial line
743  port->write( au8Buffer, u8BufferSize );
744 
745  // keep RS485 transceiver in transmit mode as long as sending
746  if (u8txenpin > 1) {
747  switch( u8serno ) {
748 #if defined(UBRR1H)
749  case 1:
750  while (!(UCSR1A & (1 << TXC1)));
751  break;
752 #endif
753 
754 #if defined(UBRR2H)
755  case 2:
756  while (!(UCSR2A & (1 << TXC2)));
757  break;
758 #endif
759 
760 #if defined(UBRR3H)
761  case 3:
762  while (!(UCSR3A & (1 << TXC3)));
763  break;
764 #endif
765  case 0:
766  default:
767  while (!(UCSR0A & (1 << TXC0)));
768  break;
769  }
770 
771  // return RS485 transceiver to receive mode
772  digitalWrite( u8txenpin, LOW );
773  }
774  port->flush();
775  u8BufferSize = 0;
776 
777  // set time-out for master
778  u32timeOut = millis() + (unsigned long) u16timeOut;
779 
780  // increase message counter
781  u16OutCnt++;
782 }
783 
791 uint16_t Modbus::calcCRC(uint8_t u8length) {
792  unsigned int temp, temp2, flag;
793  temp = 0xFFFF;
794  for (unsigned char i = 0; i < u8length; i++) {
795  temp = temp ^ au8Buffer[i];
796  for (unsigned char j = 1; j <= 8; j++) {
797  flag = temp & 0x0001;
798  temp >>=1;
799  if (flag)
800  temp ^= 0xA001;
801  }
802  }
803  // Reverse byte order.
804  temp2 = temp >> 8;
805  temp = (temp << 8) | temp2;
806  temp &= 0xFFFF;
807  // the returned value is already swapped
808  // crcLo byte is first & crcHi byte is last
809  return temp;
810 }
811 
819 uint8_t Modbus::validateRequest() {
820  // check message crc vs calculated crc
821  uint16_t u16MsgCRC =
822  ((au8Buffer[u8BufferSize - 2] << 8)
823  | au8Buffer[u8BufferSize - 1]); // combine the crc Low & High bytes
824  if ( calcCRC( u8BufferSize-2 ) != u16MsgCRC ) {
825  u16errCnt ++;
826  return NO_REPLY;
827  }
828 
829  // check fct code
830  boolean isSupported = false;
831  for (uint8_t i = 0; i< sizeof( fctsupported ); i++) {
832  if (fctsupported[i] == au8Buffer[FUNC]) {
833  isSupported = 1;
834  break;
835  }
836  }
837  if (!isSupported) {
838  u16errCnt ++;
839  return EXC_FUNC_CODE;
840  }
841 
842  // check start address & nb range
843  uint16_t u16regs = 0;
844  uint8_t u8regs;
845  switch ( au8Buffer[ FUNC ] ) {
846  case MB_FC_READ_COILS:
849  u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]) / 16;
850  u16regs += word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ]) /16;
851  u8regs = (uint8_t) u16regs;
852  if (u8regs > u8regsize) return EXC_ADDR_RANGE;
853  break;
854  case MB_FC_WRITE_COIL:
855  u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]) / 16;
856  u8regs = (uint8_t) u16regs;
857  if (u8regs > u8regsize) return EXC_ADDR_RANGE;
858  break;
859  case MB_FC_WRITE_REGISTER :
860  u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]);
861  u8regs = (uint8_t) u16regs;
862  if (u8regs > u8regsize) return EXC_ADDR_RANGE;
863  break;
864  case MB_FC_READ_REGISTERS :
867  u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]);
868  u16regs += word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ]);
869  u8regs = (uint8_t) u16regs;
870  if (u8regs > u8regsize) return EXC_ADDR_RANGE;
871  break;
872  }
873  return 0; // OK, no exception code thrown
874 }
875 
883 uint8_t Modbus::validateAnswer() {
884  // check message crc vs calculated crc
885  uint16_t u16MsgCRC =
886  ((au8Buffer[u8BufferSize - 2] << 8)
887  | au8Buffer[u8BufferSize - 1]); // combine the crc Low & High bytes
888  if ( calcCRC( u8BufferSize-2 ) != u16MsgCRC ) {
889  u16errCnt ++;
890  return NO_REPLY;
891  }
892 
893  // check exception
894  if ((au8Buffer[ FUNC ] & 0x80) != 0) {
895  u16errCnt ++;
896  return ERR_EXCEPTION;
897  }
898 
899  // check fct code
900  boolean isSupported = false;
901  for (uint8_t i = 0; i< sizeof( fctsupported ); i++) {
902  if (fctsupported[i] == au8Buffer[FUNC]) {
903  isSupported = 1;
904  break;
905  }
906  }
907  if (!isSupported) {
908  u16errCnt ++;
909  return EXC_FUNC_CODE;
910  }
911 
912  return 0; // OK, no exception code thrown
913 }
914 
921 void Modbus::buildException( uint8_t u8exception ) {
922  uint8_t u8func = au8Buffer[ FUNC ]; // get the original FUNC code
923 
924  au8Buffer[ ID ] = u8id;
925  au8Buffer[ FUNC ] = u8func + 0x80;
926  au8Buffer[ 2 ] = u8exception;
927  u8BufferSize = EXCEPTION_SIZE;
928 }
929 
936 void Modbus::get_FC1() {
937  uint8_t u8byte, i;
938  u8byte = 0;
939 
940  // for (i=0; i< au8Buffer[ 2 ] /2; i++) {
941  // au16regs[ i ] = word(
942  // au8Buffer[ u8byte ],
943  // au8Buffer[ u8byte +1 ]);
944  // u8byte += 2;
945  // }
946 }
947 
954 void Modbus::get_FC3() {
955  uint8_t u8byte, i;
956  u8byte = 3;
957 
958  for (i=0; i< au8Buffer[ 2 ] /2; i++) {
959  au16regs[ i ] = word(
960  au8Buffer[ u8byte ],
961  au8Buffer[ u8byte +1 ]);
962  u8byte += 2;
963  }
964 }
965 
974 int8_t Modbus::process_FC1( uint16_t *regs, uint8_t u8size ) {
975  uint8_t u8currentRegister, u8currentBit, u8bytesno, u8bitsno;
976  uint8_t u8CopyBufferSize;
977  uint16_t u16currentCoil, u16coil;
978 
979  // get the first and last coil from the message
980  uint16_t u16StartCoil = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
981  uint16_t u16Coilno = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ] );
982 
983  // put the number of bytes in the outcoming message
984  u8bytesno = (uint8_t) (u16Coilno / 8);
985  if (u16Coilno % 8 != 0) u8bytesno ++;
986  au8Buffer[ ADD_HI ] = u8bytesno;
987  u8BufferSize = ADD_LO;
988 
989  // read each coil from the register map and put its value inside the outcoming message
990  u8bitsno = 0;
991 
992  for (u16currentCoil = 0; u16currentCoil < u16Coilno; u16currentCoil++) {
993  u16coil = u16StartCoil + u16currentCoil;
994  u8currentRegister = (uint8_t) (u16coil / 16);
995  u8currentBit = (uint8_t) (u16coil % 16);
996 
997  bitWrite(
998  au8Buffer[ u8BufferSize ],
999  u8bitsno,
1000  bitRead( regs[ u8currentRegister ], u8currentBit ) );
1001  u8bitsno ++;
1002 
1003  if (u8bitsno > 7) {
1004  u8bitsno = 0;
1005  u8BufferSize++;
1006  }
1007  }
1008 
1009  // send outcoming message
1010  if (u16Coilno % 8 != 0) u8BufferSize ++;
1011  u8CopyBufferSize = u8BufferSize +2;
1012  sendTxBuffer();
1013  return u8CopyBufferSize;
1014 }
1015 
1024 int8_t Modbus::process_FC3( uint16_t *regs, uint8_t u8size ) {
1025 
1026  uint8_t u8StartAdd = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
1027  uint8_t u8regsno = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ] );
1028  uint8_t u8CopyBufferSize;
1029  uint8_t i;
1030 
1031  au8Buffer[ 2 ] = u8regsno * 2;
1032  u8BufferSize = 3;
1033 
1034  for (i = u8StartAdd; i < u8StartAdd + u8regsno; i++) {
1035  au8Buffer[ u8BufferSize ] = highByte(regs[i]);
1036  u8BufferSize++;
1037  au8Buffer[ u8BufferSize ] = lowByte(regs[i]);
1038  u8BufferSize++;
1039  }
1040  u8CopyBufferSize = u8BufferSize +2;
1041  sendTxBuffer();
1042 
1043  return u8CopyBufferSize;
1044 }
1045 
1054 int8_t Modbus::process_FC5( uint16_t *regs, uint8_t u8size ) {
1055  uint8_t u8currentRegister, u8currentBit;
1056  uint8_t u8CopyBufferSize;
1057  uint16_t u16coil = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
1058 
1059  // point to the register and its bit
1060  u8currentRegister = (uint8_t) (u16coil / 16);
1061  u8currentBit = (uint8_t) (u16coil % 16);
1062 
1063  // write to coil
1064  bitWrite(
1065  regs[ u8currentRegister ],
1066  u8currentBit,
1067  au8Buffer[ NB_HI ] == 0xff );
1068 
1069 
1070  // send answer to master
1071  u8BufferSize = 6;
1072  u8CopyBufferSize = u8BufferSize +2;
1073  sendTxBuffer();
1074 
1075  return u8CopyBufferSize;
1076 }
1077 
1086 int8_t Modbus::process_FC6( uint16_t *regs, uint8_t u8size ) {
1087 
1088  uint8_t u8add = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
1089  uint8_t u8CopyBufferSize;
1090  uint16_t u16val = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ] );
1091 
1092  regs[ u8add ] = u16val;
1093 
1094  // keep the same header
1095  u8BufferSize = RESPONSE_SIZE;
1096 
1097  u8CopyBufferSize = u8BufferSize +2;
1098  sendTxBuffer();
1099 
1100  return u8CopyBufferSize;
1101 }
1102 
1111 int8_t Modbus::process_FC15( uint16_t *regs, uint8_t u8size ) {
1112  uint8_t u8currentRegister, u8currentBit, u8frameByte, u8bitsno;
1113  uint8_t u8CopyBufferSize;
1114  uint16_t u16currentCoil, u16coil;
1115  boolean bTemp;
1116 
1117  // get the first and last coil from the message
1118  uint16_t u16StartCoil = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ] );
1119  uint16_t u16Coilno = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ] );
1120 
1121 
1122  // read each coil from the register map and put its value inside the outcoming message
1123  u8bitsno = 0;
1124  u8frameByte = 7;
1125  for (u16currentCoil = 0; u16currentCoil < u16Coilno; u16currentCoil++) {
1126 
1127  u16coil = u16StartCoil + u16currentCoil;
1128  u8currentRegister = (uint8_t) (u16coil / 16);
1129  u8currentBit = (uint8_t) (u16coil % 16);
1130 
1131  bTemp = bitRead(
1132  au8Buffer[ u8frameByte ],
1133  u8bitsno );
1134 
1135  bitWrite(
1136  regs[ u8currentRegister ],
1137  u8currentBit,
1138  bTemp );
1139 
1140  u8bitsno ++;
1141 
1142  if (u8bitsno > 7) {
1143  u8bitsno = 0;
1144  u8frameByte++;
1145  }
1146  }
1147 
1148  // send outcoming message
1149  // it's just a copy of the incomping frame until 6th byte
1150  u8BufferSize = 6;
1151  u8CopyBufferSize = u8BufferSize +2;
1152  sendTxBuffer();
1153  return u8CopyBufferSize;
1154 }
1155 
1164 int8_t Modbus::process_FC16( uint16_t *regs, uint8_t u8size ) {
1165  uint8_t u8func = au8Buffer[ FUNC ]; // get the original FUNC code
1166  uint8_t u8StartAdd = au8Buffer[ ADD_HI ] << 8 | au8Buffer[ ADD_LO ];
1167  uint8_t u8regsno = au8Buffer[ NB_HI ] << 8 | au8Buffer[ NB_LO ];
1168  uint8_t u8CopyBufferSize;
1169  uint8_t i;
1170  uint16_t temp;
1171 
1172  // build header
1173  au8Buffer[ NB_HI ] = 0;
1174  au8Buffer[ NB_LO ] = u8regsno;
1175  u8BufferSize = RESPONSE_SIZE;
1176 
1177  // write registers
1178  for (i = 0; i < u8regsno; i++) {
1179  temp = word(
1180  au8Buffer[ (BYTE_CNT + 1) + i * 2 ],
1181  au8Buffer[ (BYTE_CNT + 2) + i * 2 ]);
1182 
1183  regs[ u8StartAdd + i ] = temp;
1184  }
1185  u8CopyBufferSize = u8BufferSize +2;
1186  sendTxBuffer();
1187 
1188  return u8CopyBufferSize;
1189 }