Jason Engelman
/
Adaptronictmp
First Working Master with Adaptronic simulator
Embed:
(wiki syntax)
Show/hide line numbers
modbus.c
00001 00002 00003 #include <stdio.h> 00004 #include <string.h> 00005 #include <stdlib.h> 00006 #include <stdint.h> 00007 00008 #include <errno.h> 00009 #include <limits.h> 00010 00011 00012 #include "modbus.h" 00013 00014 #include "mbed.h" 00015 extern Serial serial; 00016 00017 #define UNKNOWN_ERROR_MSG "Not defined in modbus specification" 00018 00019 /* This structure reduces the number of params in functions and so 00020 * optimizes the speed of execution (~ 37%). */ 00021 typedef struct { 00022 int slave; 00023 int function; 00024 int t_id; 00025 } sft_t; 00026 00027 static const uint8_t NB_TAB_ERROR_MSG = 12; 00028 static const char *TAB_ERROR_MSG[] = { 00029 /* 0x00 */ UNKNOWN_ERROR_MSG, 00030 /* 0x01 */ "Illegal function code", 00031 /* 0x02 */ "Illegal data address", 00032 /* 0x03 */ "Illegal data value", 00033 /* 0x04 */ "Slave device or server failure", 00034 /* 0x05 */ "Acknowledge", 00035 /* 0x06 */ "Slave device or server busy", 00036 /* 0x07 */ "Negative acknowledge", 00037 /* 0x08 */ "Memory parity error", 00038 /* 0x09 */ UNKNOWN_ERROR_MSG, 00039 /* 0x0A */ "Gateway path unavailable", 00040 /* 0x0B */ "Target device failed to respond" 00041 }; 00042 00043 /* Table of CRC values for high-order byte */ 00044 static uint8_t table_crc_hi[] = { 00045 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 00046 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 00047 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 00048 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 00049 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 00050 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 00051 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 00052 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 00053 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 00054 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 00055 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 00056 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 00057 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 00058 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 00059 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 00060 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 00061 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 00062 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 00063 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 00064 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 00065 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 00066 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 00067 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 00068 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 00069 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 00070 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 00071 }; 00072 00073 /* Table of CRC values for low-order byte */ 00074 static uint8_t table_crc_lo[] = { 00075 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 00076 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 00077 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 00078 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 00079 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 00080 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 00081 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 00082 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 00083 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 00084 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 00085 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 00086 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 00087 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 00088 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 00089 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 00090 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 00091 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 00092 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 00093 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 00094 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 00095 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 00096 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 00097 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 00098 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 00099 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 00100 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 00101 }; 00102 00103 /* Treats errors and flush or close connection if necessary */ 00104 static void error_treat(modbus_param_t *mb_param, int code, const char *string) 00105 { 00106 printf("\nERROR %s (%d)\n", string, code); 00107 00108 if (mb_param->error_handling == FLUSH_OR_RECONNECT_ON_ERROR) { 00109 switch (code) { 00110 case ILLEGAL_DATA_VALUE: 00111 case ILLEGAL_DATA_ADDRESS: 00112 case ILLEGAL_FUNCTION: 00113 break; 00114 default: 00115 // tcflush(mb_param->fd, TCIOFLUSH); 00116 00117 } 00118 } 00119 } 00120 00121 /* Computes the length of the expected response */ 00122 static unsigned int compute_response_length(modbus_param_t *mb_param, 00123 uint8_t *query) 00124 { 00125 int length; 00126 int offset; 00127 00128 offset = mb_param->header_length; 00129 00130 switch (query[offset + 1]) { 00131 case FC_READ_COIL_STATUS: 00132 case FC_READ_INPUT_STATUS: { 00133 /* Header + nb values (code from force_multiple_coils) */ 00134 int nb = (query[offset + 4] << 8) | query[offset + 5]; 00135 length = 3 + (nb / 8) + ((nb % 8) ? 1 : 0); 00136 } 00137 break; 00138 case FC_READ_HOLDING_REGISTERS: 00139 case FC_READ_INPUT_REGISTERS: 00140 /* Header + 2 * nb values */ 00141 length = 3 + 2 * (query[offset + 4] << 8 | 00142 query[offset + 5]); 00143 break; 00144 case FC_READ_EXCEPTION_STATUS: 00145 length = 4; 00146 break; 00147 default: 00148 length = 6; 00149 } 00150 00151 return length + offset + mb_param->checksum_length; 00152 } 00153 00154 /* Builds a RTU query header */ 00155 int build_query_basis_rtu(int slave, int function, 00156 int start_addr, int nb, 00157 uint8_t *query) 00158 { 00159 query[0] = slave; 00160 query[1] = function; 00161 query[2] = start_addr >> 8; 00162 query[3] = start_addr & 0x00ff; 00163 query[4] = nb >> 8; 00164 query[5] = nb & 0x00ff; 00165 00166 return PRESET_QUERY_LENGTH_RTU; 00167 } 00168 00169 00170 static int build_query_basis(modbus_param_t *mb_param, int slave, 00171 int function, int start_addr, 00172 int nb, uint8_t *query) 00173 { 00174 00175 return build_query_basis_rtu(slave, function, start_addr, 00176 nb, query); 00177 00178 } 00179 00180 /* Builds a RTU response header */ 00181 static int build_response_basis_rtu(sft_t *sft, uint8_t *response) 00182 { 00183 response[0] = sft->slave; 00184 response[1] = sft->function; 00185 00186 return PRESET_RESPONSE_LENGTH_RTU; 00187 } 00188 00189 static int build_response_basis(modbus_param_t *mb_param, sft_t *sft, 00190 uint8_t *response) 00191 { 00192 00193 return build_response_basis_rtu(sft, response); 00194 00195 } 00196 00197 00198 /* Fast CRC */ 00199 static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length) 00200 { 00201 uint8_t crc_hi = 0xFF; /* high CRC byte initialized */ 00202 uint8_t crc_lo = 0xFF; /* low CRC byte initialized */ 00203 unsigned int i; /* will index into CRC lookup */ 00204 00205 /* pass through message buffer */ 00206 while (buffer_length--) { 00207 i = crc_hi ^ *buffer++; /* calculate the CRC */ 00208 crc_hi = crc_lo ^ table_crc_hi[i]; 00209 crc_lo = table_crc_lo[i]; 00210 } 00211 00212 return (crc_hi << 8 | crc_lo); 00213 } 00214 00215 /* If CRC is correct returns 0 else returns INVALID_CRC */ 00216 static int check_crc16(modbus_param_t *mb_param, 00217 uint8_t *msg, 00218 const int msg_length) 00219 { 00220 int ret; 00221 uint16_t crc_calc; 00222 uint16_t crc_received; 00223 00224 crc_calc = crc16(msg, msg_length - 2); 00225 crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1]; 00226 00227 /* Check CRC of msg */ 00228 if (crc_calc == crc_received) { 00229 ret = 0; 00230 } else { 00231 char s_error[64]; 00232 sprintf(s_error, 00233 "invalid crc received %0X - crc_calc %0X", 00234 crc_received, crc_calc); 00235 ret = INVALID_CRC; 00236 error_treat(mb_param, ret, s_error); 00237 } 00238 00239 return ret; 00240 } 00241 00242 int modbus_send(modbus_param_t *mb_param, uint8_t *query, 00243 int query_length) 00244 { 00245 int ret; 00246 uint16_t s_crc; 00247 int i; 00248 00249 s_crc = crc16(query, query_length); 00250 query[query_length++] = s_crc >> 8; 00251 query[query_length++] = s_crc & 0x00FF; 00252 00253 if (mb_param->debug) { 00254 for (i = 0; i < query_length; i++) 00255 printf("[%.2X]", query[i]); 00256 printf("\n"); 00257 } 00258 00259 //mbed 00260 for (i = 0; i < query_length; i++) serial.putc(query[i]); 00261 00262 // ret = write(mb_param->fd, query, query_length); 00263 00264 /* Return the number of bytes written (0 to n) 00265 or PORT_SOCKET_FAILURE on error */ 00266 /* 00267 if ((ret == -1) || (ret != query_length)) { 00268 ret = PORT_SOCKET_FAILURE; 00269 error_treat(mb_param, ret, "Write port/socket failure"); 00270 } 00271 */ 00272 return ret; 00273 } 00274 00275 /* Computes the length of the header following the function code */ 00276 static uint8_t compute_query_length_header(int function) 00277 { 00278 int length; 00279 00280 if (function <= FC_FORCE_SINGLE_COIL || 00281 function == FC_PRESET_SINGLE_REGISTER) 00282 /* Read and single write */ 00283 length = 4; 00284 else if (function == FC_FORCE_MULTIPLE_COILS || 00285 function == FC_PRESET_MULTIPLE_REGISTERS) 00286 /* Multiple write */ 00287 length = 5; 00288 else 00289 length = 0; 00290 00291 return length; 00292 } 00293 00294 /* Computes the length of the data to write in the query */ 00295 static int compute_query_length_data(modbus_param_t *mb_param, uint8_t *msg) 00296 { 00297 int function = msg[mb_param->header_length + 1]; 00298 int length; 00299 00300 if (function == FC_FORCE_MULTIPLE_COILS || 00301 function == FC_PRESET_MULTIPLE_REGISTERS) 00302 length = msg[mb_param->header_length + 6]; 00303 else 00304 length = 0; 00305 00306 length += mb_param->checksum_length; 00307 00308 return length; 00309 } 00310 00311 00312 00313 /* Waits a reply from a modbus slave or a query from a modbus master. 00314 This function blocks for timeout seconds if there is no reply. 00315 00316 In 00317 - msg_length_computed must be set to MSG_LENGTH_UNDEFINED if undefined 00318 00319 Out 00320 - msg is an array of uint8_t to receive the message 00321 - p_msg_length, the variable is assigned to the number of 00322 characters received. This value won't be greater than 00323 msg_length_computed. 00324 00325 Returns 0 in success or a negative value if an error occured. 00326 */ 00327 int receive_msg(modbus_param_t *mb_param, 00328 int msg_length_computed, 00329 uint8_t *msg, int *p_msg_length) 00330 { 00331 int select_ret; 00332 int read_ret; 00333 // fd_set rfds; 00334 // struct timeval tv; 00335 int length_to_read; 00336 00337 uint8_t *p_msg; 00338 00339 enum { FUNCTION, BYTE, COMPLETE }; 00340 int state; 00341 00342 if (mb_param->debug) { 00343 if (msg_length_computed == MSG_LENGTH_UNDEFINED) 00344 printf("Waiting for a message...\n"); 00345 else 00346 printf("Waiting for a message (%d bytes)...\n", 00347 msg_length_computed); 00348 } 00349 printf("0"); 00350 /* Add a file descriptor to the set */ 00351 //FD_ZERO(&rfds); 00352 //FD_SET(mb_param->fd, &rfds); 00353 00354 if (msg_length_computed == MSG_LENGTH_UNDEFINED) { 00355 /* Wait for a message */ 00356 //tv.tv_sec = 60; 00357 //tv.tv_usec = 0; 00358 00359 /* The message length is undefined (query receiving) so 00360 * we need to analyse the message step by step. 00361 * At the first step, we want to reach the function 00362 * code because all packets have that information. */ 00363 msg_length_computed = mb_param->header_length + 2; 00364 state = FUNCTION; 00365 } else { 00366 // tv.tv_sec = 0; 00367 // tv.tv_usec = TIME_OUT_BEGIN_OF_TRAME; 00368 state = COMPLETE; 00369 } 00370 00371 length_to_read = msg_length_computed; 00372 00373 select_ret = 1; 00374 // WAIT_DATA(); 00375 00376 /* Initialize the readin the message */ 00377 (*p_msg_length) = 0; 00378 p_msg = msg; 00379 00380 while (select_ret) { 00381 00382 read_ret=0; 00383 //read_ret = read(mb_param->fd, p_msg, length_to_read); 00384 printf("1"); 00385 while(serial.readable()) { 00386 p_msg[read_ret] = serial.getc(); 00387 printf("x"); 00388 read_ret++; 00389 } 00390 printf("2"); 00391 /* Sums bytes received */ 00392 (*p_msg_length) += read_ret; 00393 00394 /* Display the hex code of each character received */ 00395 if (mb_param->debug) { 00396 int i; 00397 for (i=0; i < read_ret; i++) 00398 printf("<%.2X>", p_msg[i]); 00399 } 00400 00401 if ((*p_msg_length) < msg_length_computed) { 00402 /* Message incomplete */ 00403 length_to_read = msg_length_computed - (*p_msg_length); 00404 } else { 00405 switch (state) { 00406 case FUNCTION: 00407 /* Function code position */ 00408 length_to_read = compute_query_length_header(msg[mb_param->header_length + 1]); 00409 msg_length_computed += length_to_read; 00410 /* It's useless to check 00411 p_msg_length_computed value in this 00412 case (only defined values are used). */ 00413 state = BYTE; 00414 break; 00415 case BYTE: 00416 length_to_read = compute_query_length_data(mb_param, msg); 00417 msg_length_computed += length_to_read; 00418 if (msg_length_computed > MAX_MESSAGE_LENGTH) { 00419 error_treat(mb_param, TOO_MANY_DATA, "Too many data"); 00420 return TOO_MANY_DATA; 00421 } 00422 state = COMPLETE; 00423 break; 00424 case COMPLETE: 00425 length_to_read = 0; 00426 break; 00427 } 00428 } 00429 00430 /* Moves the pointer to receive other data */ 00431 p_msg = &(p_msg[read_ret]); 00432 00433 if (length_to_read > 0) { 00434 /* If no character at the buffer wait 00435 TIME_OUT_END_OF_TRAME before to generate an error. */ 00436 //tv.tv_sec = 0; 00437 //tv.tv_usec = TIME_OUT_END_OF_TRAME; 00438 00439 //WAIT_DATA(); 00440 } else { 00441 /* All chars are received */ 00442 select_ret = FALSE; 00443 } 00444 } 00445 00446 printf("8"); 00447 if (mb_param->debug) 00448 printf("\n"); 00449 00450 if (mb_param->type_com == RTU) { 00451 printf("CRC"); 00452 check_crc16(mb_param, msg, (*p_msg_length)); 00453 } 00454 00455 /* OK */ 00456 return 0; 00457 } 00458 00459 00460 /* Receives the response and checks values (and checksum in RTU). 00461 00462 Returns: 00463 - the number of values (bits or word) if success or the response 00464 length if no value is returned 00465 - less than 0 for exception errors 00466 00467 Note: all functions used to send or receive data with modbus return 00468 these values. */ 00469 int modbus_receive(modbus_param_t *mb_param, 00470 uint8_t *query, 00471 uint8_t *response) 00472 { 00473 int ret; 00474 int response_length; 00475 int response_length_computed; 00476 int offset = mb_param->header_length; 00477 00478 response_length_computed = compute_response_length(mb_param, query); 00479 ret = receive_msg(mb_param, response_length_computed, 00480 response, &response_length); 00481 if (ret == 0) { 00482 /* GOOD RESPONSE */ 00483 int query_nb_value; 00484 int response_nb_value; 00485 00486 /* The number of values is returned if it's corresponding 00487 * to the query */ 00488 switch (response[offset + 1]) { 00489 case FC_READ_COIL_STATUS: 00490 case FC_READ_INPUT_STATUS: 00491 /* Read functions, 8 values in a byte (nb 00492 * of values in the query and byte count in 00493 * the response. */ 00494 query_nb_value = (query[offset+4] << 8) + query[offset+5]; 00495 query_nb_value = (query_nb_value / 8) + ((query_nb_value % 8) ? 1 : 0); 00496 response_nb_value = response[offset + 2]; 00497 break; 00498 case FC_READ_HOLDING_REGISTERS: 00499 case FC_READ_INPUT_REGISTERS: 00500 /* Read functions 1 value = 2 bytes */ 00501 query_nb_value = (query[offset+4] << 8) + query[offset+5]; 00502 response_nb_value = (response[offset + 2] / 2); 00503 break; 00504 case FC_FORCE_MULTIPLE_COILS: 00505 case FC_PRESET_MULTIPLE_REGISTERS: 00506 /* N Write functions */ 00507 query_nb_value = (query[offset+4] << 8) + query[offset+5]; 00508 response_nb_value = (response[offset + 4] << 8) | response[offset + 5]; 00509 break; 00510 case FC_REPORT_SLAVE_ID: 00511 /* Report slave ID (bytes received) */ 00512 query_nb_value = response_nb_value = response_length; 00513 break; 00514 default: 00515 /* 1 Write functions & others */ 00516 query_nb_value = response_nb_value = 1; 00517 } 00518 00519 if (query_nb_value == response_nb_value) { 00520 ret = response_nb_value; 00521 } else { 00522 char *s_error = (char *)malloc(64 * sizeof(char)); 00523 sprintf(s_error, "Quantity (%d) not corresponding to the query (%d)", 00524 response_nb_value, query_nb_value); 00525 ret = ILLEGAL_DATA_VALUE; 00526 error_treat(mb_param, ILLEGAL_DATA_VALUE, s_error); 00527 free(s_error); 00528 } 00529 } else if (ret == COMM_TIME_OUT) { 00530 00531 if (response_length == (offset + 3 + mb_param->checksum_length)) { 00532 /* EXCEPTION CODE RECEIVED */ 00533 00534 /* Optimization allowed because exception response is 00535 the smallest trame in modbus protocol (3) so always 00536 raise a timeout error */ 00537 00538 /* CRC must be checked here (not done in receive_msg) */ 00539 if (mb_param->type_com == RTU) { 00540 ret = check_crc16(mb_param, response, response_length); 00541 if (ret != 0) 00542 return ret; 00543 } 00544 00545 /* Check for exception response. 00546 0x80 + function is stored in the exception 00547 response. */ 00548 if (0x80 + query[offset + 1] == response[offset + 1]) { 00549 00550 int exception_code = response[offset + 2]; 00551 // FIXME check test 00552 if (exception_code < NB_TAB_ERROR_MSG) { 00553 error_treat(mb_param, -exception_code, 00554 TAB_ERROR_MSG[response[offset + 2]]); 00555 /* RETURN THE EXCEPTION CODE */ 00556 /* Modbus error code is negative */ 00557 return -exception_code; 00558 } else { 00559 /* The chances are low to hit this 00560 case but it can avoid a vicious 00561 segfault */ 00562 char *s_error = (char *)malloc(64 * sizeof(char)); 00563 sprintf(s_error, 00564 "Invalid exception code %d", 00565 response[offset + 2]); 00566 error_treat(mb_param, INVALID_EXCEPTION_CODE, 00567 s_error); 00568 free(s_error); 00569 return INVALID_EXCEPTION_CODE; 00570 } 00571 } 00572 /* If doesn't return previously, return as 00573 TIME OUT here */ 00574 } 00575 00576 /* COMMUNICATION TIME OUT */ 00577 error_treat(mb_param, ret, "Communication time out"); 00578 return ret; 00579 } 00580 00581 return ret; 00582 } 00583 00584 static int response_io_status(int address, int nb, 00585 uint8_t *tab_io_status, 00586 uint8_t *response, int offset) 00587 { 00588 int shift = 0; 00589 int byte = 0; 00590 int i; 00591 00592 for (i = address; i < address+nb; i++) { 00593 byte |= tab_io_status[i] << shift; 00594 if (shift == 7) { 00595 /* Byte is full */ 00596 response[offset++] = byte; 00597 byte = shift = 0; 00598 } else { 00599 shift++; 00600 } 00601 } 00602 00603 if (shift != 0) 00604 response[offset++] = byte; 00605 00606 return offset; 00607 } 00608 00609 /* Build the exception response */ 00610 static int response_exception(modbus_param_t *mb_param, sft_t *sft, 00611 int exception_code, uint8_t *response) 00612 { 00613 int response_length; 00614 00615 sft->function = sft->function + 0x80; 00616 response_length = build_response_basis(mb_param, sft, response); 00617 00618 /* Positive exception code */ 00619 response[response_length++] = -exception_code; 00620 00621 return response_length; 00622 } 00623 00624 /* Manages the received query. 00625 Analyses the query and constructs a response. 00626 If an error occurs, this function construct the response 00627 accordingly. 00628 */ 00629 void modbus_manage_query(modbus_param_t *mb_param, const uint8_t *query, 00630 int query_length, modbus_mapping_t *mb_mapping) 00631 { 00632 int offset = mb_param->header_length; 00633 int slave = query[offset]; 00634 int function = query[offset+1]; 00635 uint16_t address = (query[offset+2] << 8) + query[offset+3]; 00636 uint8_t response[MAX_MESSAGE_LENGTH]; 00637 int resp_length = 0; 00638 sft_t sft; 00639 00640 sft.slave = slave; 00641 sft.function = function; 00642 // if (mb_param->type_com == TCP) { 00643 // sft.t_id = (query[0] << 8) + query[1]; 00644 // } else { 00645 sft.t_id = 0; 00646 query_length -= CHECKSUM_LENGTH_RTU; 00647 // } 00648 00649 switch (function) { 00650 case FC_READ_COIL_STATUS: { 00651 int nb = (query[offset+4] << 8) + query[offset+5]; 00652 00653 if ((address + nb) > mb_mapping->nb_coil_status) { 00654 printf("Illegal data address %0X in read_coil_status\n", 00655 address + nb); 00656 resp_length = response_exception(mb_param, &sft, 00657 ILLEGAL_DATA_ADDRESS, response); 00658 } else { 00659 resp_length = build_response_basis(mb_param, &sft, response); 00660 response[resp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); 00661 resp_length = response_io_status(address, nb, 00662 mb_mapping->tab_coil_status, 00663 response, resp_length); 00664 } 00665 } 00666 break; 00667 case FC_READ_INPUT_STATUS: { 00668 /* Similar to coil status (but too much arguments to use a 00669 * function) */ 00670 int nb = (query[offset+4] << 8) + query[offset+5]; 00671 00672 if ((address + nb) > mb_mapping->nb_input_status) { 00673 printf("Illegal data address %0X in read_input_status\n", 00674 address + nb); 00675 resp_length = response_exception(mb_param, &sft, 00676 ILLEGAL_DATA_ADDRESS, response); 00677 } else { 00678 resp_length = build_response_basis(mb_param, &sft, response); 00679 response[resp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); 00680 resp_length = response_io_status(address, nb, 00681 mb_mapping->tab_input_status, 00682 response, resp_length); 00683 } 00684 } 00685 break; 00686 case FC_READ_HOLDING_REGISTERS: { 00687 int nb = (query[offset+4] << 8) + query[offset+5]; 00688 00689 if ((address + nb) > mb_mapping->nb_holding_registers) { 00690 printf("Illegal data address %0X in read_holding_registers\n", 00691 address + nb); 00692 resp_length = response_exception(mb_param, &sft, 00693 ILLEGAL_DATA_ADDRESS, response); 00694 } else { 00695 int i; 00696 00697 resp_length = build_response_basis(mb_param, &sft, response); 00698 response[resp_length++] = nb << 1; 00699 for (i = address; i < address + nb; i++) { 00700 response[resp_length++] = mb_mapping->tab_holding_registers[i] >> 8; 00701 response[resp_length++] = mb_mapping->tab_holding_registers[i] & 0xFF; 00702 } 00703 } 00704 } 00705 break; 00706 case FC_READ_INPUT_REGISTERS: { 00707 /* Similar to holding registers (but too much arguments to use a 00708 * function) */ 00709 int nb = (query[offset+4] << 8) + query[offset+5]; 00710 00711 if ((address + nb) > mb_mapping->nb_input_registers) { 00712 printf("Illegal data address %0X in read_input_registers\n", 00713 address + nb); 00714 resp_length = response_exception(mb_param, &sft, 00715 ILLEGAL_DATA_ADDRESS, response); 00716 } else { 00717 int i; 00718 00719 resp_length = build_response_basis(mb_param, &sft, response); 00720 response[resp_length++] = nb << 1; 00721 for (i = address; i < address + nb; i++) { 00722 response[resp_length++] = mb_mapping->tab_input_registers[i] >> 8; 00723 response[resp_length++] = mb_mapping->tab_input_registers[i] & 0xFF; 00724 } 00725 } 00726 } 00727 break; 00728 case FC_FORCE_SINGLE_COIL: 00729 if (address >= mb_mapping->nb_coil_status) { 00730 printf("Illegal data address %0X in force_singe_coil\n", address); 00731 resp_length = response_exception(mb_param, &sft, 00732 ILLEGAL_DATA_ADDRESS, response); 00733 } else { 00734 int data = (query[offset+4] << 8) + query[offset+5]; 00735 00736 if (data == 0xFF00 || data == 0x0) { 00737 mb_mapping->tab_coil_status[address] = (data) ? ON : OFF; 00738 00739 /* In RTU mode, the CRC is computed and added 00740 to the query by modbus_send, the computed 00741 CRC will be same and optimisation is 00742 possible here (FIXME). */ 00743 memcpy(response, query, query_length); 00744 resp_length = query_length; 00745 } else { 00746 printf("Illegal data value %0X in force_single_coil request at address %0X\n", 00747 data, address); 00748 resp_length = response_exception(mb_param, &sft, 00749 ILLEGAL_DATA_VALUE, response); 00750 } 00751 } 00752 break; 00753 case FC_PRESET_SINGLE_REGISTER: 00754 if (address >= mb_mapping->nb_holding_registers) { 00755 printf("Illegal data address %0X in preset_holding_register\n", address); 00756 resp_length = response_exception(mb_param, &sft, 00757 ILLEGAL_DATA_ADDRESS, response); 00758 } else { 00759 int data = (query[offset+4] << 8) + query[offset+5]; 00760 00761 mb_mapping->tab_holding_registers[address] = data; 00762 memcpy(response, query, query_length); 00763 resp_length = query_length; 00764 } 00765 break; 00766 case FC_FORCE_MULTIPLE_COILS: { 00767 int nb = (query[offset+4] << 8) + query[offset+5]; 00768 00769 if ((address + nb) > mb_mapping->nb_coil_status) { 00770 printf("Illegal data address %0X in force_multiple_coils\n", 00771 address + nb); 00772 resp_length = response_exception(mb_param, &sft, 00773 ILLEGAL_DATA_ADDRESS, response); 00774 } else { 00775 /* 6 = byte count, 7 = first byte of data */ 00776 set_bits_from_bytes(mb_mapping->tab_coil_status, address, nb, &query[offset + 7]); 00777 00778 resp_length = build_response_basis(mb_param, &sft, response); 00779 /* 4 to copy the coil address (2) and the quantity of coils */ 00780 memcpy(response + resp_length, query + resp_length, 4); 00781 resp_length += 4; 00782 } 00783 } 00784 break; 00785 case FC_PRESET_MULTIPLE_REGISTERS: { 00786 int nb = (query[offset+4] << 8) + query[offset+5]; 00787 00788 if ((address + nb) > mb_mapping->nb_holding_registers) { 00789 printf("Illegal data address %0X in preset_multiple_registers\n", 00790 address + nb); 00791 resp_length = response_exception(mb_param, &sft, 00792 ILLEGAL_DATA_ADDRESS, response); 00793 } else { 00794 int i, j; 00795 for (i = address, j = 0; i < address + nb; i++, j += 2) { 00796 /* 6 = byte count, 7 and 8 = first value */ 00797 mb_mapping->tab_holding_registers[i] = 00798 (query[offset + 7 + j] << 8) + query[offset + 8 + j]; 00799 } 00800 00801 resp_length = build_response_basis(mb_param, &sft, response); 00802 /* 4 to copy the address (2) and the no. of registers */ 00803 memcpy(response + resp_length, query + resp_length, 4); 00804 resp_length += 4; 00805 } 00806 } 00807 break; 00808 case FC_READ_EXCEPTION_STATUS: 00809 case FC_REPORT_SLAVE_ID: 00810 printf("Not implemented\n"); 00811 break; 00812 } 00813 00814 modbus_send(mb_param, response, resp_length); 00815 } 00816 00817 /* Listens any message on a socket or file descriptor. 00818 Returns: 00819 - 0 if OK, or a negative error number if the request fails 00820 - query, message received 00821 - query_length, length in bytes of the message */ 00822 int modbus_listen(modbus_param_t *mb_param, uint8_t *query, int *query_length) 00823 { 00824 int ret; 00825 00826 /* The length of the query to receive isn't known. */ 00827 ret = receive_msg(mb_param, MSG_LENGTH_UNDEFINED, query, query_length); 00828 00829 return ret; 00830 } 00831 00832 /* Reads IO status */ 00833 static int read_io_status(modbus_param_t *mb_param, int slave, int function, 00834 int start_addr, int nb, uint8_t *data_dest) 00835 { 00836 int ret; 00837 int query_length; 00838 00839 uint8_t query[MIN_QUERY_LENGTH]; 00840 uint8_t response[MAX_MESSAGE_LENGTH]; 00841 00842 query_length = build_query_basis(mb_param, slave, function, 00843 start_addr, nb, query); 00844 00845 ret = modbus_send(mb_param, query, query_length); 00846 if (ret > 0) { 00847 int i, temp, bit; 00848 int pos = 0; 00849 int offset; 00850 int offset_length; 00851 00852 ret = modbus_receive(mb_param, query, response); 00853 if (ret < 0) 00854 return ret; 00855 00856 offset = mb_param->header_length; 00857 00858 offset_length = offset + ret; 00859 for (i = offset; i < offset_length; i++) { 00860 /* Shift reg hi_byte to temp */ 00861 temp = response[3 + i]; 00862 00863 for (bit = 0x01; (bit & 0xff) && (pos < nb);) { 00864 data_dest[pos++] = (temp & bit) ? TRUE : FALSE; 00865 bit = bit << 1; 00866 } 00867 00868 } 00869 } 00870 00871 return ret; 00872 } 00873 00874 /* Reads the boolean status of coils and sets the array elements 00875 in the destination to TRUE or FALSE. */ 00876 int read_coil_status(modbus_param_t *mb_param, int slave, int start_addr, 00877 int nb, uint8_t *data_dest) 00878 { 00879 int status; 00880 00881 if (nb > MAX_STATUS) { 00882 printf("ERROR Too many coils status requested (%d > %d)\n", 00883 nb, MAX_STATUS); 00884 return TOO_MANY_DATA; 00885 } 00886 00887 status = read_io_status(mb_param, slave, FC_READ_COIL_STATUS, 00888 start_addr, nb, data_dest); 00889 00890 if (status > 0) 00891 status = nb; 00892 00893 return status; 00894 } 00895 00896 00897 /* Same as read_coil_status but reads the slaves input table */ 00898 int read_input_status(modbus_param_t *mb_param, int slave, int start_addr, 00899 int nb, uint8_t *data_dest) 00900 { 00901 int status; 00902 00903 if (nb > MAX_STATUS) { 00904 printf("ERROR Too many input status requested (%d > %d)\n", 00905 nb, MAX_STATUS); 00906 return TOO_MANY_DATA; 00907 } 00908 00909 status = read_io_status(mb_param, slave, FC_READ_INPUT_STATUS, 00910 start_addr, nb, data_dest); 00911 00912 if (status > 0) 00913 status = nb; 00914 00915 return status; 00916 } 00917 00918 /* Reads the data from a modbus slave and put that data into an array */ 00919 static int read_registers(modbus_param_t *mb_param, int slave, int function, 00920 int start_addr, int nb, uint16_t *data_dest) 00921 { 00922 int ret; 00923 int query_length; 00924 uint8_t query[MIN_QUERY_LENGTH]; 00925 uint8_t response[MAX_MESSAGE_LENGTH]; 00926 00927 if (nb > MAX_REGISTERS) { 00928 printf("EROOR Too many holding registers requested (%d > %d)\n", 00929 nb, MAX_REGISTERS); 00930 return TOO_MANY_DATA; 00931 } 00932 00933 query_length = build_query_basis(mb_param, slave, function, 00934 start_addr, nb, query); 00935 00936 ret = modbus_send(mb_param, query, query_length); 00937 00938 /* 00939 if (ret > 0) { 00940 int offset; 00941 int i; 00942 00943 ret = modbus_receive(mb_param, query, response); 00944 00945 offset = mb_param->header_length; 00946 00947 // If ret is negative, the loop is jumped ! 00948 for (i = 0; i < ret; i++) { 00949 // shift reg hi_byte to temp OR with lo_byte 00950 data_dest[i] = (response[offset + 3 + (i << 1)] << 8) | 00951 response[offset + 4 + (i << 1)]; 00952 } 00953 } 00954 */ 00955 return ret; 00956 } 00957 00958 /* Reads the holding registers in a slave and put the data into an 00959 array */ 00960 int read_holding_registers(modbus_param_t *mb_param, int slave, 00961 int start_addr, int nb, uint16_t *data_dest) 00962 { 00963 int status; 00964 00965 if (nb > MAX_REGISTERS) { 00966 printf("ERROR Too many holding registers requested (%d > %d)\n", 00967 nb, MAX_REGISTERS); 00968 return TOO_MANY_DATA; 00969 } 00970 00971 status = read_registers(mb_param, slave, FC_READ_HOLDING_REGISTERS, 00972 start_addr, nb, data_dest); 00973 return status; 00974 } 00975 00976 /* Reads the input registers in a slave and put the data into 00977 an array */ 00978 int read_input_registers(modbus_param_t *mb_param, int slave, 00979 int start_addr, int nb, uint16_t *data_dest) 00980 { 00981 int status; 00982 00983 if (nb > MAX_REGISTERS) { 00984 printf("ERROR Too many input registers requested (%d > %d)\n", 00985 nb, MAX_REGISTERS); 00986 return TOO_MANY_DATA; 00987 } 00988 00989 status = read_registers(mb_param, slave, FC_READ_INPUT_REGISTERS, 00990 start_addr, nb, data_dest); 00991 00992 return status; 00993 } 00994 00995 /* Sends a value to a register in a slave. 00996 Used by force_single_coil and preset_single_register */ 00997 static int set_single(modbus_param_t *mb_param, int slave, int function, 00998 int addr, int value) 00999 { 01000 int ret; 01001 int query_length; 01002 uint8_t query[MIN_QUERY_LENGTH]; 01003 01004 query_length = build_query_basis(mb_param, slave, function, 01005 addr, value, query); 01006 01007 ret = modbus_send(mb_param, query, query_length); 01008 if (ret > 0) { 01009 /* Used by force_single_coil and 01010 * preset_single_register */ 01011 uint8_t response[MIN_QUERY_LENGTH]; 01012 ret = modbus_receive(mb_param, query, response); 01013 } 01014 01015 return ret; 01016 } 01017 01018 /* Turns ON or OFF a single coil in the slave device */ 01019 int force_single_coil(modbus_param_t *mb_param, int slave, 01020 int coil_addr, int state) 01021 { 01022 int status; 01023 01024 if (state) 01025 state = 0xFF00; 01026 01027 status = set_single(mb_param, slave, FC_FORCE_SINGLE_COIL, 01028 coil_addr, state); 01029 01030 return status; 01031 } 01032 01033 /* Sets a value in one holding register in the slave device */ 01034 int preset_single_register(modbus_param_t *mb_param, int slave, 01035 int reg_addr, int value) 01036 { 01037 int status; 01038 01039 status = set_single(mb_param, slave, FC_PRESET_SINGLE_REGISTER, 01040 reg_addr, value); 01041 01042 return status; 01043 } 01044 01045 /* Sets/resets the coils in the slave from an array in argument */ 01046 int force_multiple_coils(modbus_param_t *mb_param, int slave, 01047 int start_addr, int nb, 01048 const uint8_t *data_src) 01049 { 01050 int ret; 01051 int i; 01052 int byte_count; 01053 int query_length; 01054 int coil_check = 0; 01055 int pos = 0; 01056 01057 uint8_t query[MAX_MESSAGE_LENGTH]; 01058 01059 if (nb > MAX_STATUS) { 01060 printf("ERROR Writing to too many coils (%d > %d)\n", 01061 nb, MAX_STATUS); 01062 return TOO_MANY_DATA; 01063 } 01064 01065 query_length = build_query_basis(mb_param, slave, 01066 FC_FORCE_MULTIPLE_COILS, 01067 start_addr, nb, query); 01068 byte_count = (nb / 8) + ((nb % 8) ? 1 : 0); 01069 query[query_length++] = byte_count; 01070 01071 for (i = 0; i < byte_count; i++) { 01072 int bit; 01073 01074 bit = 0x01; 01075 query[query_length] = 0; 01076 01077 while ((bit & 0xFF) && (coil_check++ < nb)) { 01078 if (data_src[pos++]) 01079 query[query_length] |= bit; 01080 else 01081 query[query_length] &=~ bit; 01082 01083 bit = bit << 1; 01084 } 01085 query_length++; 01086 } 01087 01088 ret = modbus_send(mb_param, query, query_length); 01089 if (ret > 0) { 01090 uint8_t response[MAX_MESSAGE_LENGTH]; 01091 ret = modbus_receive(mb_param, query, response); 01092 } 01093 01094 01095 return ret; 01096 } 01097 01098 /* Copies the values in the slave from the array given in argument */ 01099 int preset_multiple_registers(modbus_param_t *mb_param, int slave, 01100 int start_addr, int nb, 01101 const uint16_t *data_src) 01102 { 01103 int ret; 01104 int i; 01105 int query_length; 01106 int byte_count; 01107 01108 uint8_t query[MAX_MESSAGE_LENGTH]; 01109 01110 if (nb > MAX_REGISTERS) { 01111 printf("ERROR Trying to write to too many registers (%d > %d)\n", 01112 nb, MAX_REGISTERS); 01113 return TOO_MANY_DATA; 01114 } 01115 01116 query_length = build_query_basis(mb_param, slave, 01117 FC_PRESET_MULTIPLE_REGISTERS, 01118 start_addr, nb, query); 01119 byte_count = nb * 2; 01120 query[query_length++] = byte_count; 01121 01122 for (i = 0; i < nb; i++) { 01123 query[query_length++] = data_src[i] >> 8; 01124 query[query_length++] = data_src[i] & 0x00FF; 01125 } 01126 01127 ret = modbus_send(mb_param, query, query_length); 01128 if (ret > 0) { 01129 uint8_t response[MAX_MESSAGE_LENGTH]; 01130 ret = modbus_receive(mb_param, query, response); 01131 } 01132 01133 return ret; 01134 } 01135 01136 /* Returns the slave id! */ 01137 int report_slave_id(modbus_param_t *mb_param, int slave, 01138 uint8_t *data_dest) 01139 { 01140 int ret; 01141 int query_length; 01142 uint8_t query[MIN_QUERY_LENGTH]; 01143 01144 query_length = build_query_basis(mb_param, slave, FC_REPORT_SLAVE_ID, 01145 0, 0, query); 01146 01147 /* HACKISH, start_addr and count are not used */ 01148 query_length -= 4; 01149 01150 ret = modbus_send(mb_param, query, query_length); 01151 if (ret > 0) { 01152 int i; 01153 int offset; 01154 int offset_length; 01155 uint8_t response[MAX_MESSAGE_LENGTH]; 01156 01157 /* Byte count, slave id, run indicator status, 01158 additional data */ 01159 ret = modbus_receive(mb_param, query, response); 01160 if (ret < 0) 01161 return ret; 01162 01163 offset = mb_param->header_length; 01164 offset_length = offset + ret; 01165 01166 for (i = offset; i < offset_length; i++) 01167 data_dest[i] = response[i]; 01168 } 01169 01170 return ret; 01171 } 01172 01173 /* Initializes the modbus_param_t structure for RTU 01174 - device: "/dev/ttyS0" 01175 - baud: 9600, 19200, 57600, 115200, etc 01176 - parity: "even", "odd" or "none" 01177 - data_bits: 5, 6, 7, 8 01178 - stop_bits: 1, 2 01179 */ 01180 void modbus_init_rtu(modbus_param_t *mb_param, const char *device, 01181 int baud, const char *parity, int data_bit, 01182 int stop_bit) 01183 { 01184 memset(mb_param, 0, sizeof(modbus_param_t)); 01185 strcpy(mb_param->device, device); 01186 mb_param->baud = baud; 01187 strcpy(mb_param->parity, parity); 01188 mb_param->debug = FALSE; 01189 mb_param->data_bit = data_bit; 01190 mb_param->stop_bit = stop_bit; 01191 mb_param->type_com = RTU; 01192 mb_param->header_length = HEADER_LENGTH_RTU; 01193 mb_param->checksum_length = CHECKSUM_LENGTH_RTU; 01194 } 01195 01196 01197 /* By default, the error handling mode used is FLUSH_OR_RECONNECT_ON_ERROR. 01198 01199 With FLUSH_OR_RECONNECT_ON_ERROR, the library will flush to I/O 01200 port in RTU mode or attempt an immediate reconnection which may 01201 hang for several seconds if the network to the remote target unit 01202 is down in TCP mode. 01203 01204 With NOP_ON_ERROR, it is expected that the application will 01205 check for error returns and deal with them as necessary. 01206 */ 01207 void modbus_set_error_handling(modbus_param_t *mb_param, 01208 error_handling_t error_handling) 01209 { 01210 if (error_handling == FLUSH_OR_RECONNECT_ON_ERROR || 01211 error_handling == NOP_ON_ERROR) { 01212 mb_param->error_handling = error_handling; 01213 } else { 01214 printf("Invalid setting for error handling (not changed)\n"); 01215 } 01216 } 01217 01218 01219 /* Sets up a serial port for RTU communications */ 01220 static int modbus_connect_rtu(modbus_param_t *mb_param) 01221 { 01222 01223 return 0; 01224 } 01225 01226 01227 /* Establishes a modbus connexion. 01228 Returns -1 if an error occured. */ 01229 int modbus_connect(modbus_param_t *mb_param) 01230 { 01231 int ret; 01232 ret = modbus_connect_rtu(mb_param); 01233 01234 return ret; 01235 } 01236 01237 /* Closes the file descriptor in RTU mode */ 01238 static void modbus_close_rtu(modbus_param_t *mb_param) 01239 { 01240 01241 } 01242 01243 /* Closes a modbus connection */ 01244 void modbus_close(modbus_param_t *mb_param) 01245 { 01246 modbus_close_rtu(mb_param); 01247 01248 } 01249 01250 /* Activates the debug messages */ 01251 void modbus_set_debug(modbus_param_t *mb_param, int boolean) 01252 { 01253 mb_param->debug = boolean; 01254 } 01255 01256 /* Allocates 4 arrays to store coils, input status, input registers and 01257 holding registers. The pointers are stored in modbus_mapping structure. 01258 01259 Returns: TRUE if ok, FALSE on failure 01260 */ 01261 int modbus_mapping_new(modbus_mapping_t *mb_mapping, 01262 int nb_coil_status, int nb_input_status, 01263 int nb_holding_registers, int nb_input_registers) 01264 { 01265 /* 0X */ 01266 mb_mapping->nb_coil_status = nb_coil_status; 01267 mb_mapping->tab_coil_status = 01268 (uint8_t *) malloc(nb_coil_status * sizeof(uint8_t)); 01269 memset(mb_mapping->tab_coil_status, 0, 01270 nb_coil_status * sizeof(uint8_t)); 01271 if (mb_mapping->tab_coil_status == NULL) 01272 return FALSE; 01273 01274 /* 1X */ 01275 mb_mapping->nb_input_status = nb_input_status; 01276 mb_mapping->tab_input_status = 01277 (uint8_t *) malloc(nb_input_status * sizeof(uint8_t)); 01278 memset(mb_mapping->tab_input_status, 0, 01279 nb_input_status * sizeof(uint8_t)); 01280 if (mb_mapping->tab_input_status == NULL) { 01281 free(mb_mapping->tab_coil_status); 01282 return FALSE; 01283 } 01284 01285 /* 4X */ 01286 mb_mapping->nb_holding_registers = nb_holding_registers; 01287 mb_mapping->tab_holding_registers = 01288 (uint16_t *) malloc(nb_holding_registers * sizeof(uint16_t)); 01289 memset(mb_mapping->tab_holding_registers, 0, 01290 nb_holding_registers * sizeof(uint16_t)); 01291 if (mb_mapping->tab_holding_registers == NULL) { 01292 free(mb_mapping->tab_coil_status); 01293 free(mb_mapping->tab_input_status); 01294 return FALSE; 01295 } 01296 01297 /* 3X */ 01298 mb_mapping->nb_input_registers = nb_input_registers; 01299 mb_mapping->tab_input_registers = 01300 (uint16_t *) malloc(nb_input_registers * sizeof(uint16_t)); 01301 memset(mb_mapping->tab_input_registers, 0, 01302 nb_input_registers * sizeof(uint16_t)); 01303 if (mb_mapping->tab_input_registers == NULL) { 01304 free(mb_mapping->tab_coil_status); 01305 free(mb_mapping->tab_input_status); 01306 free(mb_mapping->tab_holding_registers); 01307 return FALSE; 01308 } 01309 01310 return TRUE; 01311 } 01312 01313 /* Frees the 4 arrays */ 01314 void modbus_mapping_free(modbus_mapping_t *mb_mapping) 01315 { 01316 free(mb_mapping->tab_coil_status); 01317 free(mb_mapping->tab_input_status); 01318 free(mb_mapping->tab_holding_registers); 01319 free(mb_mapping->tab_input_registers); 01320 } 01321 /** Utils **/ 01322 01323 /* Sets many input/coil status from a single byte value (all 8 bits of 01324 the byte value are setted) */ 01325 void set_bits_from_byte(uint8_t *dest, int address, const uint8_t value) 01326 { 01327 int i; 01328 01329 for (i=0; i<8; i++) { 01330 dest[address+i] = (value & (1 << i)) ? ON : OFF; 01331 } 01332 } 01333 01334 /* Sets many input/coil status from a table of bytes (only the bits 01335 between address and address + nb_bits are setted) */ 01336 void set_bits_from_bytes(uint8_t *dest, int address, int nb_bits, 01337 const uint8_t tab_byte[]) 01338 { 01339 int i; 01340 int shift = 0; 01341 01342 for (i = address; i < address + nb_bits; i++) { 01343 dest[i] = tab_byte[(i - address) / 8] & (1 << shift) ? ON : OFF; 01344 /* gcc doesn't like: shift = (++shift) % 8; */ 01345 shift++; 01346 shift %= 8; 01347 } 01348 } 01349 01350 /* Gets the byte value from many input/coil status. 01351 To obtain a full byte, set nb_bits to 8. */ 01352 uint8_t get_byte_from_bits(const uint8_t *src, int address, int nb_bits) 01353 { 01354 int i; 01355 uint8_t value = 0; 01356 01357 if (nb_bits > 8) { 01358 printf("Error: nb_bits is too big\n"); 01359 nb_bits = 8; 01360 } 01361 01362 for (i=0; i < nb_bits; i++) { 01363 value |= (src[address+i] << i); 01364 } 01365 01366 return value; 01367 }
Generated on Wed Jul 20 2022 21:56:37 by 1.7.2