Lydia - Printhead
All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
Modbus Buffer Management

Functions

void Modbus::buildException (uint8_t u8exception)
 This method builds an exception message. More...
 
uint16_t Modbus::calcCRC (uint8_t u8length)
 This method calculates CRC. More...
 
uint16_t Modbus::getErrCnt ()
 error counter More...
 
uint16_t Modbus::getInCnt ()
 number of incoming messages More...
 
uint8_t Modbus::getLastError ()
 get last error message More...
 
uint16_t Modbus::getOutCnt ()
 number of outcoming messages More...
 
int8_t Modbus::getRxBuffer ()
 This method moves Serial buffer data to the Modbus au8Buffer. More...
 
uint8_t Modbus::getState ()
 
void Modbus::sendTxBuffer ()
 This method transmits au8Buffer to Serial line. Only if u8txenpin != 0, there is a flow handling in order to keep the RS485 transceiver in output state as long as the message is being sent. This is done with UCSRxA register. The CRC is appended to the buffer before starting to send it. More...
 
uint8_t Modbus::validateAnswer ()
 This method validates master incoming messages. More...
 
uint8_t Modbus::validateRequest ()
 This method validates slave incoming messages. More...
 

Detailed Description

Function Documentation

◆ buildException()

void Modbus::buildException ( uint8_t  u8exception)
private

This method builds an exception message.

Definition at line 1244 of file ModbusRtu.h.

1245 {
1246  uint8_t u8func = au8Buffer[FUNC]; // get the original FUNC code
1247 
1248  au8Buffer[ID] = u8id;
1249  au8Buffer[FUNC] = u8func + 0x80;
1250  au8Buffer[2] = u8exception;
1252 }

◆ calcCRC()

uint16_t Modbus::calcCRC ( uint8_t  u8length)
private

This method calculates CRC.

Returns
uint16_t calculated CRC value for the message

Definition at line 1096 of file ModbusRtu.h.

1097 {
1098  unsigned int temp, temp2, flag;
1099  temp = 0xFFFF;
1100  for (unsigned char i = 0; i < u8length; i++)
1101  {
1102  temp = temp ^ au8Buffer[i];
1103  // Serial.println(au8Buffer[i], DEC);
1104  for (unsigned char j = 1; j <= 8; j++)
1105  {
1106  flag = temp & 0x0001;
1107  temp >>= 1;
1108  if (flag)
1109  temp ^= 0xA001;
1110  }
1111  }
1112  // Reverse byte order.
1113  temp2 = temp >> 8;
1114  temp = (temp << 8) | temp2;
1115  temp &= 0xFFFF;
1116  // the returned value is already swapped
1117  // crcLo byte is first & crcHi byte is last
1118  return temp;
1119 }

◆ getErrCnt()

uint16_t Modbus::getErrCnt ( )

error counter

Get errors counter value This can be useful to diagnose communication.

Returns
errors counter

Definition at line 545 of file ModbusRtu.h.

546 {
547  return u16errCnt;
548 }

◆ getInCnt()

uint16_t Modbus::getInCnt ( )

number of incoming messages

Get input messages counter value This can be useful to diagnose communication.

Returns
input messages counter

Definition at line 519 of file ModbusRtu.h.

520 {
521  return u16InCnt;
522 }

◆ getLastError()

uint8_t Modbus::getLastError ( )

get last error message

Get the last error in the protocol processor

@returnreturn NO_REPLY = 255 Time-out

Returns
EXC_FUNC_CODE = 1 Function code not available
EXC_ADDR_RANGE = 2 Address beyond available space for Modbus registers
EXC_REGS_QUANT = 3 Coils or registers number beyond the available space

Definition at line 575 of file ModbusRtu.h.

576 {
577  return u8lastError;
578 }

◆ getOutCnt()

uint16_t Modbus::getOutCnt ( )

number of outcoming messages

Get transmitted messages counter value This can be useful to diagnose communication.

Returns
transmitted messages counter

Definition at line 532 of file ModbusRtu.h.

533 {
534  return u16OutCnt;
535 }

◆ getRxBuffer()

int8_t Modbus::getRxBuffer ( )
private

This method moves Serial buffer data to the Modbus au8Buffer.

Returns
buffer size if OK, ERR_BUFF_OVERFLOW if u8BufferSize >= MAX_BUFFER

Definition at line 905 of file ModbusRtu.h.

906 {
907  boolean bBuffOverflow = false;
908 
909  if (u8txenpin > 1)
910  {
913  // digitalWrite( u8txenpin, LOW );
914  }
915 
916  u8BufferSize = 0;
917  if (u8serno < 4)
918  while (port->available())
919  {
920  au8Buffer[u8BufferSize] = port->read();
922  u8BufferSize++;
923 
924  if (u8BufferSize >= MAX_BUFFER)
925  bBuffOverflow = true;
926  }
927  else
928  while (softPort->available())
929  {
930  au8Buffer[u8BufferSize] = softPort->read();
931  u8BufferSize++;
932 
933  if (u8BufferSize >= MAX_BUFFER)
934  bBuffOverflow = true;
935  }
936  u16InCnt++;
937 
938  if (bBuffOverflow)
939  {
940  Log.verboseln("buffer overflow: %d", u8BufferSize);
941  u16errCnt++;
942  return ERR_BUFF_OVERFLOW;
943  }
944  //Log.verboseln("getRX-Buffer : %d",u8BufferSize);
945  //printHex(rxBuffer, u8BufferSize);
947  return u8BufferSize;
948 }

◆ getState()

uint8_t Modbus::getState ( )

Get modbus master state

Returns
= 0 IDLE, = 1 WAITING FOR ANSWER

Definition at line 561 of file ModbusRtu.h.

562 {
563  return u8state;
564 }

◆ sendTxBuffer()

void Modbus::sendTxBuffer ( )
private

This method transmits au8Buffer to Serial line. Only if u8txenpin != 0, there is a flow handling in order to keep the RS485 transceiver in output state as long as the message is being sent. This is done with UCSRxA register. The CRC is appended to the buffer before starting to send it.

Parameters
nothing
Returns
nothing

Definition at line 962 of file ModbusRtu.h.

963 {
964  uint8_t i = 0;
965 
966  // append CRC to message
967  uint16_t u16crc = calcCRC(u8BufferSize);
968 /*
969  Serial.print("---- calc CRC : HEX : ");
970  Serial.print(u16crc, DEC);
971  Serial.print(" - HEX : ");
972  Serial.print(u16crc, HEX);
973  Serial.print(" - ");
974  Serial.print(u8BufferSize);
975  Serial.print("\n");
976  */
977 
978  au8Buffer[u8BufferSize] = u16crc >> 8;
979  u8BufferSize++;
980  au8Buffer[u8BufferSize] = u16crc & 0x00ff;
981  u8BufferSize++;
982 
983  if (debugSend)
984  {
985  Serial.print("Send Hex : \t");
986  for (int i = 0; i < 8; i++)
987  {
988  Serial.print(au8Buffer[i], HEX);
989  Serial.print(" : ");
990  }
991  Serial.println("--------------- \n");
992  }
993 
994  // set RS485 transceiver to transmit mode
995  if (u8txenpin > 1)
996  {
997  switch (u8serno)
998  {
999 #if defined(UBRR1H)
1000  case 1:
1001  UCSR1A = UCSR1A | (1 << TXC1);
1002  break;
1003 #endif
1004 
1005 #if defined(UBRR2H)
1006  case 2:
1007  UCSR2A = UCSR2A | (1 << TXC2);
1008  break;
1009 #endif
1010 
1011 #if defined(UBRR3H)
1012  case 3:
1013  UCSR3A = UCSR3A | (1 << TXC3);
1014  break;
1015 #endif
1016  case 0:
1017  default:
1018  UCSR0A = UCSR0A | (1 << TXC0);
1019  break;
1020  }
1021  RS485_SET_DE;
1022  RS485_SET_RE;
1023  // digitalWrite( u8txenpin, HIGH );
1024  }
1025 
1026  // transfer buffer to serial line
1027  if (u8serno < 4)
1028  {
1029  port->write(au8Buffer, u8BufferSize);
1030  }
1031  else
1032  {
1033  softPort->write(au8Buffer, u8BufferSize);
1034  }
1035  // keep RS485 transceiver in transmit mode as long as sending
1036  if (u8txenpin > 1)
1037  {
1038  switch (u8serno)
1039  {
1040 #if defined(UBRR1H)
1041  case 1:
1042  while (!(UCSR1A & (1 << TXC1)))
1043  ;
1044  break;
1045 #endif
1046 
1047 #if defined(UBRR2H)
1048  case 2:
1049  while (!(UCSR2A & (1 << TXC2)))
1050  ;
1051  break;
1052 #endif
1053 
1054 #if defined(UBRR3H)
1055  case 3:
1056  while (!(UCSR3A & (1 << TXC3)))
1057  ;
1058  break;
1059 #endif
1060  case 0:
1061  default:
1062  while (!(UCSR0A & (1 << TXC0)))
1063  ;
1064  break;
1065  }
1066  // return RS485 transceiver to receive mode
1069  // digitalWrite( u8txenpin, LOW );
1070  }
1071  if (u8serno < 4)
1072  while (port->read() >= 0)
1073  ;
1074  else
1075  while (softPort->read() >= 0)
1076  ;
1077 
1078  u8BufferSize = 0;
1079 
1080  // set time-out for master
1081  u32timeOut = millis() + (unsigned long)u16timeOut;
1082 
1083  // increase message counter
1084  u16OutCnt++;
1085 
1087 }

◆ validateAnswer()

uint8_t Modbus::validateAnswer ( )
private

This method validates master incoming messages.

Returns
0 if OK, EXCEPTION if anything fails

Definition at line 1201 of file ModbusRtu.h.

1202 {
1203  // check message crc vs calculated crc
1204  uint16_t u16MsgCRC =
1205  ((au8Buffer[u8BufferSize - 2] << 8) | au8Buffer[u8BufferSize - 1]); // combine the crc Low & High bytes
1206  if (calcCRC(u8BufferSize - 2) != u16MsgCRC)
1207  {
1208  u16errCnt++;
1209  return NO_REPLY;
1210  }
1211 
1212  // check exception
1213  if ((au8Buffer[FUNC] & 0x80) != 0)
1214  {
1215  u16errCnt++;
1216  return ERR_EXCEPTION;
1217  }
1218 
1219  // check fct code
1220  boolean isSupported = false;
1221  for (uint8_t i = 0; i < sizeof(fctsupported); i++)
1222  {
1223  if (fctsupported[i] == au8Buffer[FUNC])
1224  {
1225  isSupported = 1;
1226  break;
1227  }
1228  }
1229  if (!isSupported)
1230  {
1231  u16errCnt++;
1232  return EXC_FUNC_CODE;
1233  }
1234 
1235  return 0; // OK, no exception code thrown
1236 }

◆ validateRequest()

uint8_t Modbus::validateRequest ( )
private

This method validates slave incoming messages.

Returns
0 if OK, EXCEPTION if anything fails

Definition at line 1128 of file ModbusRtu.h.

1129 {
1130  // check message crc vs calculated crc
1131  uint16_t u16MsgCRC =
1132  ((au8Buffer[u8BufferSize - 2] << 8) | au8Buffer[u8BufferSize - 1]); // combine the crc Low & High bytes
1133  if (calcCRC(u8BufferSize - 2) != u16MsgCRC)
1134  {
1135  u16errCnt++;
1136  return NO_REPLY;
1137  }
1138 
1139  // check fct code
1140  boolean isSupported = false;
1141  for (uint8_t i = 0; i < sizeof(fctsupported); i++)
1142  {
1143  if (fctsupported[i] == au8Buffer[FUNC])
1144  {
1145  isSupported = 1;
1146  break;
1147  }
1148  }
1149  if (!isSupported)
1150  {
1151  u16errCnt++;
1152  return EXC_FUNC_CODE;
1153  }
1154 
1155  // check start address & nb range
1156  uint16_t u16regs = 0;
1157  uint8_t u8regs;
1158  switch (au8Buffer[FUNC])
1159  {
1160  case MB_FC_READ_COILS:
1161  case MB_FC_READ_DISCRETE_INPUT:
1162  case MB_FC_WRITE_MULTIPLE_COILS:
1163  u16regs = word(au8Buffer[ADD_HI], au8Buffer[ADD_LO]) / 16;
1164  u16regs += word(au8Buffer[NB_HI], au8Buffer[NB_LO]) / 16;
1165  u8regs = (uint8_t)u16regs;
1166  if (u8regs > u8regsize)
1167  return EXC_ADDR_RANGE;
1168  break;
1169  case MB_FC_WRITE_COIL:
1170  u16regs = word(au8Buffer[ADD_HI], au8Buffer[ADD_LO]) / 16;
1171  u8regs = (uint8_t)u16regs;
1172  if (u8regs > u8regsize)
1173  return EXC_ADDR_RANGE;
1174  break;
1175  case MB_FC_WRITE_REGISTER:
1176  u16regs = word(au8Buffer[ADD_HI], au8Buffer[ADD_LO]);
1177  u8regs = (uint8_t)u16regs;
1178  if (u8regs > u8regsize)
1179  return EXC_ADDR_RANGE;
1180  break;
1181  case MB_FC_READ_REGISTERS:
1182  case MB_FC_READ_INPUT_REGISTER:
1183  case MB_FC_WRITE_MULTIPLE_REGISTERS:
1184  u16regs = word(au8Buffer[ADD_HI], au8Buffer[ADD_LO]);
1185  u16regs += word(au8Buffer[NB_HI], au8Buffer[NB_LO]);
1186  u8regs = (uint8_t)u16regs;
1187  if (u8regs > u8regsize)
1188  return EXC_ADDR_RANGE;
1189  break;
1190  }
1191  return 0; // OK, no exception code thrown
1192 }
EXC_ADDR_RANGE
@ EXC_ADDR_RANGE
Definition: ModbusRtu.h:130
MAX_BUFFER
#define MAX_BUFFER
maximum size for the communication buffer in bytes
Definition: ModbusRtu.h:57
RS485_CLEAR_DE
#define RS485_CLEAR_DE
Definition: ModbusRtu.h:51
Modbus::u32timeOut
uint32_t u32timeOut
Definition: ModbusRtu.h:168
Modbus::u8BufferSize
uint8_t u8BufferSize
Definition: ModbusRtu.h:163
Modbus::debugSend
bool debugSend
Definition: ModbusRtu.h:214
modbus_t::flags
uint8_t flags
Definition: ModbusRtu.h:74
Modbus::u8state
uint8_t u8state
Definition: ModbusRtu.h:160
fctsupported
const unsigned char fctsupported[]
Definition: ModbusRtu.h:135
RS485_SET_DE
#define RS485_SET_DE
Definition: ModbusRtu.h:53
Modbus::currentQuery
modbus_t * currentQuery
Definition: ModbusRtu.h:178
EXC_FUNC_CODE
@ EXC_FUNC_CODE
Definition: ModbusRtu.h:129
NB_HI
@ NB_HI
Number of coils or registers high byte.
Definition: ModbusRtu.h:97
Modbus::u8regsize
uint8_t u8regsize
Definition: ModbusRtu.h:169
Modbus::u16errCnt
uint16_t u16errCnt
Definition: ModbusRtu.h:166
Modbus::u8serno
uint8_t u8serno
serial port: 0-Serial, 1..3-Serial1..Serial3; 4: use software serial
Definition: ModbusRtu.h:158
Modbus::u16OutCnt
uint16_t u16OutCnt
Definition: ModbusRtu.h:166
Modbus::calcCRC
uint16_t calcCRC(uint8_t u8length)
This method calculates CRC.
Definition: ModbusRtu.h:1096
Modbus::rxSize
uint8_t rxSize
Definition: ModbusRtu.h:216
ERR_BUFF_OVERFLOW
@ ERR_BUFF_OVERFLOW
Definition: ModbusRtu.h:121
Modbus::u16InCnt
uint16_t u16InCnt
Definition: ModbusRtu.h:166
Modbus::rxBuffer
uint8_t rxBuffer[MAX_BUFFER]
Definition: ModbusRtu.h:217
RS485_CLEAR_RE
#define RS485_CLEAR_RE
Definition: ModbusRtu.h:52
EXCEPTION_SIZE
@ EXCEPTION_SIZE
Definition: ModbusRtu.h:82
Modbus::u16timeOut
uint16_t u16timeOut
Definition: ModbusRtu.h:167
ERR_EXCEPTION
@ ERR_EXCEPTION
Definition: ModbusRtu.h:123
Modbus::u8txenpin
uint8_t u8txenpin
flow control pin: 0=USB or RS-232 mode, >0=RS-485 mode
Definition: ModbusRtu.h:159
Modbus::au8Buffer
uint8_t au8Buffer[MAX_BUFFER]
Definition: ModbusRtu.h:162
FUNC
@ FUNC
Function code position.
Definition: ModbusRtu.h:94
NO_REPLY
@ NO_REPLY
Definition: ModbusRtu.h:128
ADD_HI
@ ADD_HI
Address high byte.
Definition: ModbusRtu.h:95
SENT
@ SENT
Definition: enums.h:92
Modbus::u8lastError
uint8_t u8lastError
Definition: ModbusRtu.h:161
RS485_SET_RE
#define RS485_SET_RE
Definition: ModbusRtu.h:54
Modbus::softPort
SoftwareSerial * softPort
Pointer to SoftwareSerial class object.
Definition: ModbusRtu.h:156
Modbus::port
HardwareSerial * port
Pointer to Serial class object.
Definition: ModbusRtu.h:155
ID
@ ID
ID field.
Definition: ModbusRtu.h:93
Modbus::u8id
uint8_t u8id
0=master, 1..247=slave number
Definition: ModbusRtu.h:157
ADD_LO
@ ADD_LO
Address low byte.
Definition: ModbusRtu.h:96
NB_LO
@ NB_LO
Number of coils or registers low byte.
Definition: ModbusRtu.h:98