#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "rtapi.h"
#ifdef RTAPI
#include "rtapi_app.h"
#endif
#include "rtapi_string.h"
#include "rtapi_errno.h"
#include "hal.h"
#include "inifile.h"
#include <modbus.h>
#define MB2HAL_MAX_LINKS 32
#define MB2HAL_MAX_DEVICE_LENGTH 32
#define MB2HAL_DEFAULT_TCP_PORT 502
#define MB2HAL_DEFAULT_MB_RESPONSE_TIMEOUT_MS 500
#define MB2HAL_DEFAULT_MB_BYTE_TIMEOUT_MS 500
#define MB2HAL_DEFAULT_TCP_PORT 502
#define MB2HAL_MAX_FNCT02_ELEMENTS 100
#define MB2HAL_MAX_FNCT03_ELEMENTS 100
#define MB2HAL_MAX_FNCT04_ELEMENTS 100
#define MB2HAL_MAX_FNCT05_ELEMENTS 100
#define MB2HAL_MAX_FNCT06_ELEMENTS 1
#define MB2HAL_MAX_FNCT15_ELEMENTS 100
#define MB2HAL_MAX_FNCT16_ELEMENTS 100
#ifdef MODULE_VERBOSE
MODULE_VERBOSE(emc2, "component:mb2hal:Userspace HAL component to communicate with one or more Modbus devices");
MODULE_VERBOSE(emc2, "license:LGPL");
MODULE_LICENSE("LGPL");
#endif
typedef enum { linkRTU,
linkTCP
} link_type_t;
typedef enum { mbtxERR,
mbtx_02_READ_DISCRETE_INPUTS,
mbtx_03_READ_HOLDING_REGISTERS,
mbtx_04_READ_INPUT_REGISTERS,
mbtx_06_WRITE_SINGLE_REGISTER,
mbtx_15_WRITE_MULTIPLE_COILS,
mbtx_16_WRITE_MULTIPLE_REGISTERS,
mbtxMAX
} mb_tx_fnct; typedef enum { debugSILENT, debugERR, debugOK, debugDEBUG, debugMAX
} DEBUG_TYPE; typedef enum { retOK, retOKwithWarning, retERR
} retCode;
#define ERR(debug, fmt, args...) if(debug >= debugERR) {fprintf(stderr, "%s %s ERR: "fmt"\n", gbl.hal_mod_name, fnct_name, ## args);}
#define OK(debug, fmt, args...) if(debug >= debugOK) {fprintf(stdout, "%s %s OK: "fmt"\n", gbl.hal_mod_name, fnct_name, ## args);}
#define DBG(debug, fmt, args...) if(debug >= debugDEBUG) {fprintf(stdout, "%s %s DEBUG: "fmt"\n", gbl.hal_mod_name, fnct_name, ## args);}
typedef struct {
link_type_t cfg_link_type; char cfg_link_type_str[10]; char cfg_serial_device[MB2HAL_MAX_DEVICE_LENGTH]; int cfg_serial_baud; char cfg_serial_parity[5]; int cfg_serial_data_bit; int cfg_serial_stop_bit; int cfg_serial_delay_ms; char cfg_tcp_ip[17]; int cfg_tcp_port; int mb_tx_slave_id; mb_tx_fnct mb_tx_fnct; char mb_tx_fnct_name[64]; int mb_tx_1st_addr; int mb_tx_nelem; char ** mb_tx_names; int mb_response_timeout_ms; int mb_byte_timeout_ms; double cfg_update_rate; int cfg_debug; int protocol_debug; int mb_tx_num; int mb_link_num; double time_increment; double next_time; double last_time_ok; char hal_tx_name[HAL_NAME_LEN + 1];
hal_float_t **float_value;
hal_s32_t **int_value;
hal_bit_t **bit;
hal_u32_t **num_errors; } mb_tx_t;
typedef struct {
link_type_t lp_link_type; char lp_type_com_str[10]; char lp_serial_device[MB2HAL_MAX_DEVICE_LENGTH]; int lp_serial_baud; char lp_serial_parity; int lp_serial_data_bit; int lp_serial_stop_bit; int lp_serial_delay_ms; char lp_tcp_ip[17]; int lp_tcp_port; int mb_link_num; modbus_t *modbus;
pthread_t thrd;
} mb_link_t;
typedef struct {
FILE *ini_file_ptr;
char *ini_file_path;
int init_dbg;
double slowdown;
int hal_mod_id;
char *hal_mod_name;
mb_tx_t *mb_tx;
int tot_mb_tx;
mb_link_t *mb_links;
int tot_mb_links;
const char *mb_tx_fncts[mbtxMAX];
int quit_flag;
} gbl_t;
extern gbl_t gbl;
void *link_loop_and_logic(void *thrd_link_num);
retCode is_this_tx_ready(const int this_mb_link_num, const int this_mb_tx_num, int *ret_available);
retCode get_tx_connection(const int mb_tx_num, int *ret_connected);
void set_init_gbl_params();
double get_time();
void quit_signal(int signal);
void quit_cleanup(void);
retCode parse_main_args(int argc, char **argv);
retCode parse_ini_file();
retCode parse_common_section();
retCode parse_transaction_section(const int mb_tx_num);
retCode parse_tcp_subsection(const char *section, const int mb_tx_num);
retCode parse_serial_subsection(const char *section, const int mb_tx_num);
retCode check_int_in(int n_args, const int int_value, ...);
retCode check_str_in(int n_args, const char *str_value, ...);
retCode init_mb_links();
retCode init_mb_tx();
retCode create_HAL_pins();
retCode create_each_mb_tx_hal_pins(mb_tx_t *mb_tx);
retCode fnct_15_write_multiple_coils(mb_tx_t *this_mb_tx, mb_link_t *this_mb_link);
retCode fnct_02_read_discrete_inputs(mb_tx_t *this_mb_tx, mb_link_t *this_mb_link);
retCode fnct_04_read_input_registers(mb_tx_t *this_mb_tx, mb_link_t *this_mb_link);
retCode fnct_03_read_holding_registers(mb_tx_t *this_mb_tx, mb_link_t *this_mb_link);
retCode fnct_06_write_single_register(mb_tx_t *this_mb_tx, mb_link_t *this_mb_link);
retCode fnct_16_write_multiple_registers(mb_tx_t *this_mb_tx, mb_link_t *this_mb_link);