msousa@1909: /* File generated by Beremiz (PlugGenerate_C method of Modbus plugin) */ msousa@1909: msousa@1909: /* msousa@1909: * Copyright (c) 2016 Mario de Sousa (msousa@fe.up.pt) msousa@1909: * msousa@1909: * This file is part of the Modbus library for Beremiz and matiec. msousa@1909: * msousa@1909: * This Modbus library is free software: you can redistribute it and/or modify msousa@1909: * it under the terms of the GNU Lesser General Public License as published by msousa@1909: * the Free Software Foundation, either version 3 of the License, or msousa@1909: * (at your option) any later version. msousa@1909: * msousa@1909: * This program is distributed in the hope that it will be useful, but msousa@1909: * WITHOUT ANY WARRANTY; without even the implied warranty of msousa@1909: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser msousa@1909: * General Public License for more details. msousa@1909: * msousa@1909: * You should have received a copy of the GNU Lesser General Public License msousa@1909: * along with this Modbus library. If not, see . msousa@1909: * msousa@1909: * This code is made available on the understanding that it will not be msousa@1909: * used in safety-critical situations without a full and competent review. msousa@1909: */ msousa@1909: msousa@1909: msousa@1909: #include msousa@1909: #include /* required for memcpy() */ msousa@1909: #include "mb_slave_and_master.h" msousa@1909: #include "MB_%(locstr)s.h" msousa@1909: msousa@1909: msousa@1909: #define MAX_MODBUS_ERROR_CODE 11 msousa@1909: static const char *modbus_error_messages[MAX_MODBUS_ERROR_CODE+1] = { msousa@1909: /* 0 */ "", /* un-used -> no error! */ msousa@1909: /* 1 */ "illegal/unsuported function", msousa@1909: /* 2 */ "illegal data address", msousa@1909: /* 3 */ "illegal data value", msousa@1909: /* 4 */ "slave device failure", msousa@1909: /* 5 */ "acknowledge -> slave intends to reply later", msousa@1909: /* 6 */ "slave device busy", msousa@1909: /* 7 */ "negative acknowledge", msousa@1909: /* 8 */ "memory parity error", msousa@1909: /* 9 */ "", /* undefined by Modbus */ msousa@1909: /* 10*/ "gateway path unavalilable", msousa@1909: /* 11*/ "gateway target device failed to respond" msousa@1909: }; msousa@1909: msousa@1909: msousa@1909: /* Execute a modbus client transaction/request */ msousa@1909: static int __execute_mb_request(int request_id){ msousa@1909: switch (client_requests[request_id].mb_function){ msousa@1909: msousa@1909: case 1: /* read coils */ msousa@1909: return read_output_bits(client_requests[request_id].slave_id, msousa@1909: client_requests[request_id].address, msousa@1909: client_requests[request_id].count, msousa@1909: client_requests[request_id].coms_buffer, msousa@1909: (int) client_requests[request_id].count, msousa@1909: client_nodes[client_requests[request_id].client_node_id].mb_nd, msousa@1909: client_requests[request_id].retries, msousa@1909: &(client_requests[request_id].error_code), msousa@1909: &(client_requests[request_id].resp_timeout), msousa@1909: &(client_requests[request_id].coms_buf_mutex)); msousa@1909: msousa@1909: case 2: /* read discrete inputs */ msousa@1909: return read_input_bits( client_requests[request_id].slave_id, msousa@1909: client_requests[request_id].address, msousa@1909: client_requests[request_id].count, msousa@1909: client_requests[request_id].coms_buffer, msousa@1909: (int) client_requests[request_id].count, msousa@1909: client_nodes[client_requests[request_id].client_node_id].mb_nd, msousa@1909: client_requests[request_id].retries, msousa@1909: &(client_requests[request_id].error_code), msousa@1909: &(client_requests[request_id].resp_timeout), msousa@1909: &(client_requests[request_id].coms_buf_mutex)); msousa@1909: msousa@1909: case 3: /* read holding registers */ msousa@1909: return read_output_words(client_requests[request_id].slave_id, msousa@1909: client_requests[request_id].address, msousa@1909: client_requests[request_id].count, msousa@1909: client_requests[request_id].coms_buffer, msousa@1909: (int) client_requests[request_id].count, msousa@1909: client_nodes[client_requests[request_id].client_node_id].mb_nd, msousa@1909: client_requests[request_id].retries, msousa@1909: &(client_requests[request_id].error_code), msousa@1909: &(client_requests[request_id].resp_timeout), msousa@1909: &(client_requests[request_id].coms_buf_mutex)); msousa@1909: msousa@1909: case 4: /* read input registers */ msousa@1909: return read_input_words(client_requests[request_id].slave_id, msousa@1909: client_requests[request_id].address, msousa@1909: client_requests[request_id].count, msousa@1909: client_requests[request_id].coms_buffer, msousa@1909: (int) client_requests[request_id].count, msousa@1909: client_nodes[client_requests[request_id].client_node_id].mb_nd, msousa@1909: client_requests[request_id].retries, msousa@1909: &(client_requests[request_id].error_code), msousa@1909: &(client_requests[request_id].resp_timeout), msousa@1909: &(client_requests[request_id].coms_buf_mutex)); msousa@1909: msousa@1909: case 5: /* write single coil */ msousa@1909: return write_output_bit(client_requests[request_id].slave_id, msousa@1909: client_requests[request_id].address, msousa@1909: client_requests[request_id].coms_buffer[0], msousa@1909: client_nodes[client_requests[request_id].client_node_id].mb_nd, msousa@1909: client_requests[request_id].retries, msousa@1909: &(client_requests[request_id].error_code), msousa@1909: &(client_requests[request_id].resp_timeout), msousa@1909: &(client_requests[request_id].coms_buf_mutex)); msousa@1909: msousa@1909: case 6: /* write single register */ msousa@1909: return write_output_word(client_requests[request_id].slave_id, msousa@1909: client_requests[request_id].address, msousa@1909: client_requests[request_id].coms_buffer[0], msousa@1909: client_nodes[client_requests[request_id].client_node_id].mb_nd, msousa@1909: client_requests[request_id].retries, msousa@1909: &(client_requests[request_id].error_code), msousa@1909: &(client_requests[request_id].resp_timeout), msousa@1909: &(client_requests[request_id].coms_buf_mutex)); msousa@1909: msousa@1909: case 7: break; /* function not yet supported */ msousa@1909: case 8: break; /* function not yet supported */ msousa@1909: case 9: break; /* function not yet supported */ msousa@1909: case 10: break; /* function not yet supported */ msousa@1909: case 11: break; /* function not yet supported */ msousa@1909: case 12: break; /* function not yet supported */ msousa@1909: case 13: break; /* function not yet supported */ msousa@1909: case 14: break; /* function not yet supported */ msousa@1909: msousa@1909: case 15: /* write multiple coils */ msousa@1909: return write_output_bits(client_requests[request_id].slave_id, msousa@1909: client_requests[request_id].address, msousa@1909: client_requests[request_id].count, msousa@1909: client_requests[request_id].coms_buffer, msousa@1909: client_nodes[client_requests[request_id].client_node_id].mb_nd, msousa@1909: client_requests[request_id].retries, msousa@1909: &(client_requests[request_id].error_code), msousa@1909: &(client_requests[request_id].resp_timeout), msousa@1909: &(client_requests[request_id].coms_buf_mutex)); msousa@1909: msousa@1909: case 16: /* write multiple registers */ msousa@1909: return write_output_words(client_requests[request_id].slave_id, msousa@1909: client_requests[request_id].address, msousa@1909: client_requests[request_id].count, msousa@1909: client_requests[request_id].coms_buffer, msousa@1909: client_nodes[client_requests[request_id].client_node_id].mb_nd, msousa@1909: client_requests[request_id].retries, msousa@1909: &(client_requests[request_id].error_code), msousa@1909: &(client_requests[request_id].resp_timeout), msousa@1909: &(client_requests[request_id].coms_buf_mutex)); msousa@1909: msousa@1909: default: break; /* should never occur, if file generation is correct */ msousa@1909: } msousa@1909: msousa@1909: fprintf(stderr, "Modbus plugin: Modbus function %%d not supported\n", request_id); /* should never occur, if file generation is correct */ msousa@1909: return -1; msousa@1909: } msousa@1909: msousa@1909: msousa@1909: msousa@1909: /* pack bits from unpacked_data to packed_data */ msousa@1909: static inline int __pack_bits(u16 *unpacked_data, u16 start_addr, u16 bit_count, u8 *packed_data) { msousa@1909: u8 bit; msousa@1909: u16 byte, coils_processed; msousa@1909: msousa@1909: if ((0 == bit_count) || (65535-start_addr < bit_count-1)) msousa@1909: return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */ msousa@1909: msousa@1909: for( byte = 0, coils_processed = 0; coils_processed < bit_count; byte++) { msousa@1909: packed_data[byte] = 0; msousa@1909: for( bit = 0x01; (bit & 0xFF) && (coils_processed < bit_count); bit <<= 1, coils_processed++ ) { msousa@1909: if(unpacked_data[start_addr + coils_processed]) msousa@1909: packed_data[byte] |= bit; /* set bit */ msousa@1909: else packed_data[byte] &= ~bit; /* reset bit */ msousa@1909: } msousa@1909: } msousa@1909: return 0; msousa@1909: } msousa@1909: msousa@1909: msousa@1909: /* unpack bits from packed_data to unpacked_data */ msousa@1909: static inline int __unpack_bits(u16 *unpacked_data, u16 start_addr, u16 bit_count, u8 *packed_data) { msousa@1909: u8 temp, bit; msousa@1909: u16 byte, coils_processed; msousa@1909: msousa@1909: if ((0 == bit_count) || (65535-start_addr < bit_count-1)) msousa@1909: return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */ msousa@1909: msousa@1909: for(byte = 0, coils_processed = 0; coils_processed < bit_count; byte++) { msousa@1909: temp = packed_data[byte] ; msousa@1909: for(bit = 0x01; (bit & 0xff) && (coils_processed < bit_count); bit <<= 1, coils_processed++) { msousa@1909: unpacked_data[start_addr + coils_processed] = (temp & bit)?1:0; msousa@1909: } msousa@1909: } msousa@1909: return 0; msousa@1909: } msousa@1909: msousa@1909: msousa@1909: static int __read_inbits (void *mem_map, u16 start_addr, u16 bit_count, u8 *data_bytes) msousa@1909: {return __pack_bits(((server_mem_t *)mem_map)->ro_bits, start_addr, bit_count, data_bytes);} msousa@1909: static int __read_outbits (void *mem_map, u16 start_addr, u16 bit_count, u8 *data_bytes) msousa@1909: {return __pack_bits(((server_mem_t *)mem_map)->rw_bits, start_addr, bit_count, data_bytes);} msousa@1909: static int __write_outbits (void *mem_map, u16 start_addr, u16 bit_count, u8 *data_bytes) msousa@1909: {return __unpack_bits(((server_mem_t *)mem_map)->rw_bits, start_addr, bit_count, data_bytes); } msousa@1909: msousa@1909: msousa@1909: msousa@1909: static int __read_inwords (void *mem_map, u16 start_addr, u16 word_count, u16 *data_words) { msousa@1909: u16 count; msousa@1909: // return -ERR_ILLEGAL_FUNCTION; /* function not yet supported *//* ERR_ILLEGAL_FUNCTION defined in mb_util.h */ msousa@1909: msousa@1909: if ((start_addr + word_count) > MEM_AREA_SIZE) msousa@1909: return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */ msousa@1909: msousa@1909: /* use memcpy() as it is more efficient... msousa@1909: for (count = 0; count < word_count ; count++) msousa@1909: data_words[count] = ((server_mem_t *)mem_map)->ro_words[count + start_addr]; msousa@1909: */ msousa@1909: memcpy(/* dest */ (void *)data_words, msousa@1909: /* src */ (void *)&(((server_mem_t *)mem_map)->ro_words[start_addr]), msousa@1909: /* size */ word_count * 2); msousa@1909: return 0; msousa@1909: } msousa@1909: msousa@1909: msousa@1909: msousa@1909: static int __read_outwords (void *mem_map, u16 start_addr, u16 word_count, u16 *data_words) { msousa@1909: u16 count; msousa@1909: // return -ERR_ILLEGAL_FUNCTION; /* function not yet supported *//* ERR_ILLEGAL_FUNCTION defined in mb_util.h */ msousa@1909: msousa@1909: if ((start_addr + word_count) > MEM_AREA_SIZE) msousa@1909: return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */ msousa@1909: msousa@1909: /* use memcpy() as it is more efficient... msousa@1909: for (count = 0; count < word_count ; count++) msousa@1909: data_words[count] = ((server_mem_t *)mem_map)->rw_words[count + start_addr]; msousa@1909: */ msousa@1909: memcpy(/* dest */ (void *)data_words, msousa@1909: /* src */ (void *)&(((server_mem_t *)mem_map)->rw_words[start_addr]), msousa@1909: /* size */ word_count * 2); msousa@1909: return 0; msousa@1909: } msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: static int __write_outwords(void *mem_map, u16 start_addr, u16 word_count, u16 *data_words) { msousa@1909: u16 count; msousa@1909: // return -ERR_ILLEGAL_FUNCTION; /* function not yet supported *//* ERR_ILLEGAL_FUNCTION defined in mb_util.h */ msousa@1909: msousa@1909: if ((start_addr + word_count) > MEM_AREA_SIZE) msousa@1909: return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */ msousa@1909: msousa@1909: /* WARNING: The data returned in the data_words[] array is not guaranteed to be 16 bit aligned. msousa@1909: * It is not therefore safe to cast it to an u16 data type. msousa@1909: * The following code cannot be used. memcpy() is used instead. msousa@1909: */ msousa@1909: /* msousa@1909: for (count = 0; count < word_count ; count++) msousa@1909: ((server_mem_t *)mem_map)->rw_words[count + start_addr] = data_words[count]; msousa@1909: */ msousa@1909: memcpy(/* dest */ (void *)&(((server_mem_t *)mem_map)->rw_words[start_addr]), msousa@1909: /* src */ (void *)data_words, msousa@1909: /* size */ word_count * 2); msousa@1909: return 0; msousa@1909: } msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: #include msousa@1909: msousa@1909: static void *__mb_server_thread(void *_server_node) { msousa@1909: server_node_t *server_node = _server_node; msousa@1909: mb_slave_callback_t callbacks = { msousa@1909: &__read_inbits, msousa@1909: &__read_outbits, msousa@1909: &__write_outbits, msousa@1909: &__read_inwords, msousa@1909: &__read_outwords, msousa@1909: &__write_outwords, msousa@1909: (void *)&(server_node->mem_area) msousa@1909: }; msousa@1909: msousa@1909: // Enable thread cancelation. Enabled is default, but set it anyway to be safe. msousa@1909: pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); msousa@1909: msousa@1909: // mb_slave_run() should never return! msousa@1909: mb_slave_run(server_node->mb_nd /* nd */, callbacks, server_node->slave_id); msousa@1909: fprintf(stderr, "Modbus plugin: Modbus server for node %%s died unexpectedly!\n", server_node->location); /* should never occur */ msousa@1909: return NULL; msousa@1909: } msousa@1909: msousa@1909: msousa@2479: #define timespec_add(ts, sec, nsec) { \ msousa@2479: ts.tv_sec += sec; \ msousa@2479: ts.tv_nsec += nsec; \ msousa@2479: if (ts.tv_nsec >= 1000000000) { \ msousa@2479: ts.tv_sec ++; \ msousa@2479: ts.tv_nsec -= 1000000000; \ msousa@2479: } \ msousa@2479: } msousa@2479: msousa@1909: msousa@1909: static void *__mb_client_thread(void *_index) { msousa@1909: int client_node_id = (char *)_index - (char *)NULL; // Use pointer arithmetic (more portable than cast) msousa@1909: struct timespec next_cycle; msousa@1909: int period_sec = client_nodes[client_node_id].comm_period / 1000; /* comm_period is in ms */ msousa@1909: int period_nsec = (client_nodes[client_node_id].comm_period %%1000)*1000000; /* comm_period is in ms */ msousa@1909: msousa@1909: // Enable thread cancelation. Enabled is default, but set it anyway to be safe. msousa@1909: pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); msousa@1909: msousa@1909: // get the current time msousa@1909: clock_gettime(CLOCK_MONOTONIC, &next_cycle); msousa@1909: msousa@1909: // loop the communication with the client msousa@1909: while (1) { msousa@1909: /* msousa@1909: struct timespec cur_time; msousa@1909: clock_gettime(CLOCK_MONOTONIC, &cur_time); msousa@1909: fprintf(stderr, "Modbus client thread - new cycle (%%ld:%%ld)!\n", cur_time.tv_sec, cur_time.tv_nsec); msousa@1909: */ msousa@1909: int req; msousa@1909: for (req=0; req < NUMBER_OF_CLIENT_REQTS; req ++){ msousa@1909: /*just do the requests belonging to the client */ msousa@1909: if (client_requests[req].client_node_id != client_node_id) msousa@1909: continue; msousa@1909: int res_tmp = __execute_mb_request(req); msousa@1909: switch (res_tmp) { msousa@1909: case PORT_FAILURE: { msousa@1909: if (res_tmp != client_nodes[client_node_id].prev_error) msousa@1909: fprintf(stderr, "Modbus plugin: Error connecting Modbus client %%s to remote server.\n", client_nodes[client_node_id].location); msousa@1909: client_nodes[client_node_id].prev_error = res_tmp; msousa@1909: break; msousa@1909: } msousa@1909: case INVALID_FRAME: { msousa@1909: if ((res_tmp != client_requests[req].prev_error) && (0 == client_nodes[client_node_id].prev_error)) msousa@1909: fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s was unsuccesful. Server/slave returned an invalid/corrupted frame.\n", client_requests[req].location); msousa@1909: client_requests[req].prev_error = res_tmp; msousa@1909: break; msousa@1909: } msousa@1909: case TIMEOUT: { msousa@1909: if ((res_tmp != client_requests[req].prev_error) && (0 == client_nodes[client_node_id].prev_error)) msousa@1909: fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s timed out waiting for reply from server.\n", client_requests[req].location); msousa@1909: client_requests[req].prev_error = res_tmp; msousa@1909: break; msousa@1909: } msousa@1909: case MODBUS_ERROR: { msousa@1909: if (client_requests[req].prev_error != client_requests[req].error_code) { msousa@1909: fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s was unsuccesful. Server/slave returned error code 0x%%2x", client_requests[req].location, client_requests[req].error_code); msousa@1909: if (client_requests[req].error_code <= MAX_MODBUS_ERROR_CODE ) { msousa@1909: fprintf(stderr, "(%%s)", modbus_error_messages[client_requests[req].error_code]); msousa@1909: fprintf(stderr, ".\n"); msousa@1909: } msousa@1909: } msousa@1909: client_requests[req].prev_error = client_requests[req].error_code; msousa@1909: break; msousa@1909: } msousa@1909: default: { msousa@1909: if ((res_tmp >= 0) && (client_nodes[client_node_id].prev_error != 0)) { msousa@1909: fprintf(stderr, "Modbus plugin: Modbus client %%s has reconnected to server/slave.\n", client_nodes[client_node_id].location); msousa@1909: } msousa@1909: if ((res_tmp >= 0) && (client_requests[req] .prev_error != 0)) { msousa@1909: fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s has succesfully resumed comunication.\n", client_requests[req].location); msousa@1909: } msousa@1909: client_nodes[client_node_id].prev_error = 0; msousa@1909: client_requests[req] .prev_error = 0; msousa@1909: break; msousa@1909: } msousa@1909: } msousa@1909: } msousa@1909: // Determine absolute time instant for starting the next cycle msousa@2479: struct timespec prev_cycle, now; msousa@2479: prev_cycle = next_cycle; msousa@2479: timespec_add(next_cycle, period_sec, period_nsec); msousa@2479: /* NOTE A: msousa@2479: * When we have difficulty communicating with remote client and/or server, then the communications get delayed and we will msousa@2479: * fall behind in the period. This means that when communication is re-established we may end up running this loop continuously msousa@2479: * for some time until we catch up. msousa@2479: * This is undesirable, so we detect it by making sure the next_cycle will start in the future. msousa@2479: * When this happens we will switch from a purely periodic task _activation_ sequence, to a fixed task suspension interval. msousa@2479: * msousa@2479: * NOTE B: msousa@2479: * It probably does not make sense to check for overflow of timer. msousa@1909: * Even in 32 bit systems this will take at least 68 years since the computer booted msousa@1909: * (remember, we are using CLOCK_MONOTONIC, which should start counting from 0 msousa@1909: * every time the system boots). On 64 bit systems, it will take over msousa@1909: * 10^11 years to overflow. msousa@1909: */ msousa@2479: clock_gettime(CLOCK_MONOTONIC, &now); msousa@2479: if ( ((now.tv_sec > next_cycle.tv_sec) || ((now.tv_sec == next_cycle.tv_sec) && (now.tv_nsec > next_cycle.tv_nsec))) msousa@2479: /* We are falling behind. See NOTE A above */ msousa@2479: || (next_cycle.tv_sec < prev_cycle.tv_sec) msousa@2479: /* Timer overflow. See NOTE B above */ msousa@2479: ) { msousa@2479: next_cycle = now; msousa@2479: timespec_add(next_cycle, period_sec, period_nsec); msousa@2479: } msousa@1909: clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_cycle, NULL); msousa@1909: } msousa@1909: msousa@1909: // humour the compiler. msousa@1909: return NULL; msousa@1909: } msousa@1909: msousa@1909: msousa@1909: msousa@1909: int __init_%(locstr)s (int argc, char **argv){ msousa@1909: int index; msousa@1909: msousa@1909: for (index=0; index < NUMBER_OF_CLIENT_NODES;index++) msousa@1909: client_nodes[index].mb_nd = -1; msousa@1909: for (index=0; index < NUMBER_OF_SERVER_NODES;index++) msousa@1909: // mb_nd with negative numbers indicate how far it has been initialised (or not) msousa@1909: // -2 --> no modbus node created; no thread created msousa@1909: // -1 --> modbus node created!; no thread created msousa@1909: // >=0 --> modbus node created!; thread created! msousa@1909: server_nodes[index].mb_nd = -2; msousa@1909: msousa@1909: /* modbus library init */ msousa@1909: /* Note that TOTAL_xxxNODE_COUNT are the nodes required by _ALL_ the instances of the modbus msousa@1909: * extension currently in the user's project. This file (MB_xx.c) is handling only one instance, msousa@1909: * but must initialize the library for all instances. Only the first call to mb_slave_and_master_init() msousa@1909: * will result in memory being allocated. All subsequent calls (by other MB_xx,c files) will be ignored msousa@1909: * by the mb_slave_and_master_init() funtion, as long as they are called with the same arguments. msousa@1909: */ msousa@1909: if (mb_slave_and_master_init(TOTAL_TCPNODE_COUNT, TOTAL_RTUNODE_COUNT, TOTAL_ASCNODE_COUNT) <0) { msousa@1909: fprintf(stderr, "Modbus plugin: Error starting modbus library\n"); msousa@1909: // return imediately. Do NOT goto error_exit, as we did not get to msousa@1909: // start the modbus library! msousa@1909: return -1; msousa@1909: } msousa@1909: msousa@1909: /* init the mutex for each client request */ msousa@1909: /* Must be done _before_ launching the client threads!! */ msousa@1909: for (index=0; index < NUMBER_OF_CLIENT_REQTS; index ++){ msousa@1909: if (pthread_mutex_init(&(client_requests[index].coms_buf_mutex), NULL)) { msousa@1909: fprintf(stderr, "Modbus plugin: Error initializing request for modbus client node %%s\n", client_nodes[client_requests[index].client_node_id].location); msousa@1909: goto error_exit; msousa@1909: } msousa@1909: } msousa@1909: msousa@1909: /* init each client connection to remote modbus server, and launch thread */ msousa@1909: /* NOTE: All client_nodes[].init_state are initialised to 0 in the code msousa@1909: * generated by the modbus plugin msousa@1909: */ msousa@1909: for (index=0; index < NUMBER_OF_CLIENT_NODES;index++){ msousa@1909: /* establish client connection */ msousa@1909: client_nodes[index].mb_nd = mb_master_connect (client_nodes[index].node_address); msousa@1909: if (client_nodes[index].mb_nd < 0){ msousa@1909: fprintf(stderr, "Modbus plugin: Error creating modbus client node %%s\n", client_nodes[index].location); msousa@1909: goto error_exit; msousa@1909: } msousa@1909: client_nodes[index].init_state = 1; // we have created the node msousa@1909: msousa@1909: /* launch a thread to handle this client node */ msousa@1909: { msousa@1909: int res = 0; msousa@1909: pthread_attr_t attr; msousa@1909: res |= pthread_attr_init(&attr); msousa@1909: res |= pthread_create(&(client_nodes[index].thread_id), &attr, &__mb_client_thread, (void *)((char *)NULL + index)); msousa@1909: if (res != 0) { msousa@1909: fprintf(stderr, "Modbus plugin: Error starting modbus client thread for node %%s\n", client_nodes[index].location); msousa@1909: goto error_exit; msousa@1909: } msousa@1909: } msousa@1909: client_nodes[index].init_state = 2; // we have created the node and a thread msousa@1909: } msousa@1909: msousa@1909: /* init each local server */ msousa@1909: /* NOTE: All server_nodes[].init_state are initialised to 0 in the code msousa@1909: * generated by the modbus plugin msousa@1909: */ msousa@1909: for (index=0; index < NUMBER_OF_SERVER_NODES;index++){ msousa@1909: /* create the modbus server */ msousa@1909: server_nodes[index].mb_nd = mb_slave_new (server_nodes[index].node_address); msousa@1909: if (server_nodes[index].mb_nd < 0){ msousa@1909: fprintf(stderr, "Modbus plugin: Error creating modbus server node %%s\n", server_nodes[index].location); msousa@1909: goto error_exit; msousa@1909: } msousa@1909: server_nodes[index].init_state = 1; // we have created the node msousa@1909: msousa@1909: /* launch a thread to handle this server node */ msousa@1909: { msousa@1909: int res = 0; msousa@1909: pthread_attr_t attr; msousa@1909: res |= pthread_attr_init(&attr); msousa@1909: res |= pthread_create(&(server_nodes[index].thread_id), &attr, &__mb_server_thread, (void *)&(server_nodes[index])); msousa@1909: if (res != 0) { msousa@1909: fprintf(stderr, "Modbus plugin: Error starting modbus server thread for node %%s\n", server_nodes[index].location); msousa@1909: goto error_exit; msousa@1909: } msousa@1909: } msousa@1909: server_nodes[index].init_state = 2; // we have created the node and thread msousa@1909: } msousa@1909: msousa@1909: return 0; msousa@1909: msousa@1909: error_exit: msousa@1909: __cleanup_%(locstr)s (); msousa@1909: return -1; msousa@1909: } msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: void __publish_%(locstr)s (){ msousa@1909: int index; msousa@1909: msousa@1909: for (index=0; index < NUMBER_OF_CLIENT_REQTS; index ++){ msousa@1909: /*just do the output requests */ msousa@1909: if (client_requests[index].req_type == req_output){ msousa@1909: pthread_mutex_lock(&(client_requests[index].coms_buf_mutex)); msousa@1909: // copy from plcv_buffer to coms_buffer msousa@1909: memcpy((void *)client_requests[index].coms_buffer /* destination */, msousa@1909: (void *)client_requests[index].plcv_buffer /* source */, msousa@1909: REQ_BUF_SIZE * sizeof(u16) /* size in bytes */); msousa@1909: pthread_mutex_unlock(&(client_requests[index].coms_buf_mutex)); msousa@1909: } msousa@1909: } msousa@1909: } msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: void __retrieve_%(locstr)s (){ msousa@1909: int index; msousa@1909: msousa@1909: for (index=0; index < NUMBER_OF_CLIENT_REQTS; index ++){ msousa@1909: /*just do the input requests */ msousa@1909: if (client_requests[index].req_type == req_input){ msousa@1909: pthread_mutex_lock(&(client_requests[index].coms_buf_mutex)); msousa@1909: // copy from coms_buffer to plcv_buffer msousa@1909: memcpy((void *)client_requests[index].plcv_buffer /* destination */, msousa@1909: (void *)client_requests[index].coms_buffer /* source */, msousa@1909: REQ_BUF_SIZE * sizeof(u16) /* size in bytes */); msousa@1909: pthread_mutex_unlock(&(client_requests[index].coms_buf_mutex)); msousa@1909: } msousa@1909: } msousa@1909: } msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: msousa@1909: int __cleanup_%(locstr)s (){ msousa@1909: int index, close; msousa@1909: int res = 0; msousa@1909: msousa@1909: /* kill thread and close connections of each modbus client node */ msousa@1909: for (index=0; index < NUMBER_OF_CLIENT_NODES; index++) { msousa@1909: close = 0; msousa@1909: if (client_nodes[index].init_state >= 2) { msousa@1909: // thread was launched, so we try to cancel it! msousa@1909: close = pthread_cancel(client_nodes[index].thread_id); msousa@1909: close |= pthread_join (client_nodes[index].thread_id, NULL); msousa@1909: if (close < 0) msousa@1909: fprintf(stderr, "Modbus plugin: Error closing thread for modbus client %%s\n", client_nodes[index].location); msousa@1909: } msousa@1909: res |= close; msousa@1909: msousa@1909: close = 0; msousa@1909: if (client_nodes[index].init_state >= 1) { msousa@1909: // modbus client node was created, so we try to close it! msousa@1909: close = mb_master_close (client_nodes[index].mb_nd); msousa@1909: if (close < 0){ msousa@1909: fprintf(stderr, "Modbus plugin: Error closing modbus client node %%s\n", client_nodes[index].location); msousa@1909: // We try to shut down as much as possible, so we do not return noW! msousa@1909: } msousa@1909: client_nodes[index].mb_nd = -1; msousa@1909: } msousa@1909: res |= close; msousa@1909: client_nodes[index].init_state = 0; msousa@1909: } msousa@1909: msousa@1909: /* kill thread and close connections of each modbus server node */ msousa@1909: for (index=0; index < NUMBER_OF_SERVER_NODES; index++) { msousa@1909: close = 0; msousa@1909: if (server_nodes[index].init_state >= 2) { msousa@1909: // thread was launched, so we try to cancel it! msousa@1909: close = pthread_cancel(server_nodes[index].thread_id); msousa@1909: close |= pthread_join (server_nodes[index].thread_id, NULL); msousa@1909: if (close < 0) msousa@1909: fprintf(stderr, "Modbus plugin: Error closing thread for modbus server %%s\n", server_nodes[index].location); msousa@1909: } msousa@1909: res |= close; msousa@1909: msousa@1909: close = 0; msousa@1909: if (server_nodes[index].init_state >= 1) { msousa@1909: // modbus server node was created, so we try to close it! msousa@1909: close = mb_slave_close (server_nodes[index].mb_nd); msousa@1909: if (close < 0) { msousa@1909: fprintf(stderr, "Modbus plugin: Error closing node for modbus server %%s (%%d)\n", server_nodes[index].location, server_nodes[index].mb_nd); msousa@1909: // We try to shut down as much as possible, so we do not return noW! msousa@1909: } msousa@1909: server_nodes[index].mb_nd = -1; msousa@1909: } msousa@1909: res |= close; msousa@1909: server_nodes[index].init_state = 0; msousa@1909: } msousa@1909: msousa@1909: /* destroy the mutex of each client request */ msousa@1909: for (index=0; index < NUMBER_OF_CLIENT_REQTS; index ++) { msousa@1909: if (pthread_mutex_destroy(&(client_requests[index].coms_buf_mutex))) { msousa@1909: fprintf(stderr, "Modbus plugin: Error destroying request for modbus client node %%s\n", client_nodes[client_requests[index].client_node_id].location); msousa@1909: // We try to shut down as much as possible, so we do not return noW! msousa@1909: res |= -1; msousa@1909: } msousa@1909: } msousa@1909: msousa@1909: /* modbus library close */ msousa@1909: //fprintf(stderr, "Shutting down modbus library...\n"); msousa@1909: if (mb_slave_and_master_done()<0) { msousa@1909: fprintf(stderr, "Modbus plugin: Error shutting down modbus library\n"); msousa@1909: res |= -1; msousa@1909: } msousa@1909: msousa@1909: return res; msousa@1909: } msousa@1909: