Commit 3be9ff9b authored by electrolab's avatar electrolab

mb2halv2 is an enhanced version of mb2hal with new HAL_MAP_PIN keyword

parent 0b93932a
all: mb2halv2
CFLAGS=-I/usr/include/linuxcnc -DULAPI -DINIFILE_LEGACY
%.o: %.c
g++ -c $(CFLAGS) $(CPPFLAGS) $< -o $@
mb2halv2: mb2hal.o mb2hal_init.o mb2hal_modbus.o mb2hal_hal.o
g++ $(CFLAGS) $^ -o $@ -llinuxcnchal -llinuxcncini -lpthread -lmodbus
mb2hal.o: mb2hal.c
mb2hal_init.o: mb2hal_init.c
mb2hal_modbus.o: mb2hal_modbus.c
mb2hal_hal.o: mb2hal_hal.c
install:
sudo install -m 0755 -g root -o root mb2halv2 /usr/local/bin
valid: mb2halv2
cd tests; python test05.py
clean:
rm -f mb2halv2 *.o
This diff is collapsed.
#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 "emcglb.h"
#include <modbus/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_FNCT15_ELEMENTS 100
#define MB2HAL_MAX_FNCT16_ELEMENTS 100
#define MB2HAL_MAX_HAL_MAP_PIN 100
#ifdef MODULE_VERBOSE
MODULE_VERBOSE(emc2, "component:mb2halv2:Userspace HAL component to communicate with one or more Modbus devices");
MODULE_VERBOSE(emc2, "license:LGPL");
MODULE_LICENSE("LGPL");
#endif
typedef enum {
linkUndefined = 1,
linkRTU,
linkTCP
} link_type_t;
typedef enum { mbtxERR,
mbtx_02_READ_DISCRETE_INPUTS,
mbtx_03_READ_HOLDING_REGISTERS,
mbtx_04_READ_INPUT_REGISTERS,
mbtx_05_WRITE_SINGLE_COIL,
mbtx_15_WRITE_MULTIPLE_COILS,
mbtx_16_WRITE_MULTIPLE_REGISTERS,
mbtxMAX
} mb_tx_fnct_t; //modbus transaction code
typedef enum { debugSILENT, debugERR, debugOK, debugDEBUG, debugMAX
} DEBUG_TYPE; //message levels
typedef enum { retOK, retOKwithWarning, retERR
} retCode; //funtions return codes
#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);}
// Structure used to store enhanced pin mapping configuration
typedef struct {
char *name; // The name of the HAL pin
int addr;
int width; // Number of successive Modbus registers associated to this pin (useful to make 32bits value from 2 x 16bits registers
hal_type_t type; // HAL_BIT, HAL_FLOAT, HAL_S32, HAL_U32
hal_float_t scale;
hal_float_t offset;
int bitnumber;
} hal_map_pin_t;
typedef union {
hal_bit_t _b;
hal_s32_t _s;
hal_u32_t _u;
hal_float_t _f;
} hal_data_u;
//Modbus transaction structure (mb_tx_t)
//Store each transaction defined in INI config file
//Plus HAL and run time parameters for each transaction
typedef struct {
//cfg_* are link params only for INI config reading purpose
//then we use the parameters of mb_link_t
link_type_t cfg_link_type; //RTU (serial) or TCP
char cfg_link_type_str[10]; //str version of lp_link_type
char cfg_serial_device[MB2HAL_MAX_DEVICE_LENGTH]; //device: example "/dev/ttyS0"
int cfg_serial_baud; //bauds
char cfg_serial_parity[5]; //parity: "even", "odd", "none"
int cfg_serial_data_bit; //data bit
int cfg_serial_stop_bit; //stop bit
int cfg_serial_delay_ms; //delay between tx in serial lines
char cfg_tcp_ip[17]; //tcp address
int cfg_tcp_port; //tcp port number
//mb_* are Modbus transaction protocol related params
int mb_tx_slave_id; //MB device id
mb_tx_fnct_t mb_tx_fnct; //MB function code id
char mb_tx_fnct_name[64]; //str version of mb_tx_fnct
int mb_tx_1st_addr; //MB first register
int mb_tx_nelem; //MB n registers
int mb_response_timeout_ms; //MB response timeout
int mb_byte_timeout_ms; //MB byte timeout
//cfg_* are others INI config params
double cfg_update_rate; //tx update rate
int cfg_debug; //tx debug level (program, may be also protocol)
//Modbus protocol debug
int protocol_debug; //Flag debug Modbus protocol
//internal processing values
int mb_tx_num; //each tx know it's own number
int mb_link_num; //each tx know it's own link
//internal processing values
double time_increment; //wait time between tx
double next_time; //next time for this tx
double last_time_ok; //last OK tx time
//HAL related params
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; //num of acummulated errors (0=last tx OK)
hal_s32_t **cumul_errors; //num of errors, never reset
hal_s32_t **cumul_transactions;//num of transactions
hal_bit_t **modbus_ok; //true if modbus communication is ok
int nb_hal_map_pin;
hal_map_pin_t hal_map_pin[MB2HAL_MAX_HAL_MAP_PIN];
hal_data_u **pin_value;
} mb_tx_t;
//Modbus link structure (mb_link_t)
//Group common transaction's links in one unique link
//Store each run time Modbus link parameters here
typedef struct {
//lp_* are real link params for real time use
link_type_t lp_link_type; //RTU (serial) or TCP
char lp_type_com_str[10]; //str version of lp_type_com
char lp_serial_device[MB2HAL_MAX_DEVICE_LENGTH]; //device: example "/dev/ttyS0"
int lp_serial_baud; //bauds
char lp_serial_parity; //parity: 'E', 'O', 'N'
//NOTE in mb_tx is "even", "odd", "none"
int lp_serial_data_bit; //data bit
int lp_serial_stop_bit; //stop bit
int lp_serial_delay_ms; //delay between tx in serial lines
char lp_tcp_ip[17]; //tcp address
int lp_tcp_port; //tcp port number
//run time processing values
int mb_link_num; //corresponding number of this link/thread
modbus_t *modbus;
pthread_t thrd;
} mb_link_t;
//Structure of global data (gbl_t)
//Reduce functions parameters using this common global structure.
typedef struct {
//INI config file
FILE *ini_file_ptr;
char *ini_file_path;
//INI config, common section
int init_dbg;
double slowdown;
//HAL related
int hal_mod_id;
const char *hal_mod_name;
//mb_tx
mb_tx_t *mb_tx;
int tot_mb_tx;
//mb_links
mb_link_t *mb_links;
int tot_mb_links;
//others
const char *mb_tx_fncts[mbtxMAX];
int quit_flag;
} gbl_t;
extern gbl_t gbl;
//mb2hal.c
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);
//mb2hal_init.c
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();
//mb2hal_hal.c
retCode create_HAL_pins();
retCode create_each_mb_tx_hal_pins(mb_tx_t *mb_tx);
//mb2hal_modbus.c
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_16_write_multiple_registers(mb_tx_t *this_mb_tx, mb_link_t *this_mb_link);
retCode fnct_05_write_single_coil(mb_tx_t *this_mb_tx, mb_link_t *this_mb_link);
#This .INI file is also the HELP, MANUAL and HOW-TO file for mb2hal.
#Load the modbus HAL userspace module as the examples below,
#change to match your own HAL_MODULE_NAME and .ini file name
#Using HAL_MODULE_NAME=mb2hal or nothing (default): loadusr -W mb2hal config=config_file.ini
#Using HAL_MODULE_NAME=mymodule: loadusr -Wn mymodule mb2hal config=config_file.ini
#Common section
[MB2HAL_INIT]
#OPTIONAL: Debug level of init and INI file parsing.
# 0 = silent.
# 1 = error messages (default).
# 2 = OK confirmation messages.
# 3 = debugging messages.
INIT_DEBUG=3
#OPTIONAL: HAL module (component) name. Defaults to "mb2hal".
HAL_MODULE_NAME=mb2hal
#OPTIONAL: Insert a delay of "FLOAT seconds" between transactions in order
#to not to have a lot of logging and facilitate the debugging.
#Usefull when using DEBUG=3 (NOT INIT_DEBUG=3)
#It affects ALL transactions.
#Use "0.0" for normal activity.
SLOWDOWN=0.0
#REQUIRED: The number of total Modbus transactions. There is no maximum.
TOTAL_TRANSACTIONS=9
#One transaction section is required per transaction, starting at 00 and counting up sequentially.
#If there is a new link (not transaction), you must provide the REQUIRED parameters 1st time.
#Warning: Any OPTIONAL parameter not specified are copied from the previous transaction.
[TRANSACTION_00]
#REQUIRED: You must specify either a "serial" or "tcp" link for the first transaction.
#Later transaction will use the previous transaction link if not specified.
LINK_TYPE=tcp
#if LINK_TYPE=tcp then REQUIRED (only 1st time): The Modbus slave device ip address.
#if LINK_TYPE=serial then IGNORED
TCP_IP=192.168.2.10
#if LINK_TYPE=tcp then OPTIONAL.
#if LINK_TYPE=serial then IGNORED
#The Modbus slave device tcp port. Defaults to 502.
TCP_PORT=502
#if LINK_TYPE=serial then REQUIRED (only 1st time).
#if LINK_TYPE=tcp then IGNORED
#The serial port.
SERIAL_PORT=/dev/ttyS0
#if LINK_TYPE=serial then REQUIRED (only 1st time).
#if LINK_TYPE=tcp then IGNORED
#The baud rate.
SERIAL_BAUD=115200
#if LINK_TYPE=serial then REQUIRED (only 1st time).
#if LINK_TYPE=tcp then IGNORED
#Data bits. One of 5,6,7,8.
SERIAL_BITS=8
#if LINK_TYPE=serial then REQUIRED (only 1st time).
#if LINK_TYPE=tcp then IGNORED
#Data parity. One of: even, odd, none.
SERIAL_PARITY=none
#if LINK_TYPE=serial then REQUIRED (only 1st time).
#if LINK_TYPE=tcp then IGNORED
#Stop bits. One of 1, 2.
SERIAL_STOP=2
#if LINK_TYPE=serial then OPTIONAL:
#if LINK_TYPE=tcp then IGNORED
#Serial port delay between for this transaction only.
#In ms. Defaults to 0.
SERIAL_DELAY_MS=10
#REQUIRED (only 1st time).
#Modbus slave number.
MB_SLAVE_ID=1
#REQUIRED: The first element address.
FIRST_ELEMENT=0
#REQUIRED: The number of elements.
NELEMENTS=16
#REQUIRED: Modbus transaction function code (see www.modbus.org specifications).
# fnct_02_read_discrete_inputs (02 = 0x02)
# fnct_03_read_holding_registers (03 = 0x03)
# fnct_04_read_input_registers (04 = 0x04)
# fnct_15_write_multiple_coils (15 = 0x0F)
# fnct_16_write_multiple_registers (16 = 0x10)
#fnct_02_read_discrete_inputs: creates boolean output HAL pins.
#fnct_03_read_holding_registers: creates a floating point output HAL pins.
# also creates a u32 output HAL pins.
#fnct_04_read_input_registers: creates a floating point output HAL pins.
# also creates a u32 output HAL pins.
#fnct_15_write_multiple_coils: creates boolean input HAL pins.
#fnct_16_write_multiple_registers: creates a floating point input HAL pins.
#The pins are named based on component name, transaction number and order number.
#Example: mb2hal.00.01 (transaction=00, second register=01 (00 is the first one))
MB_TX_CODE=fnct_03_read_holding_registers
#OPTIONAL: Response timeout for this transaction. In INTEGER ms. Defaults to 500 ms.
#This is how much to wait for 1st byte before raise an error.
MB_RESPONSE_TIMEOUT_MS=500
#OPTIONAL: Byte timeout for this transaction. In INTEGER ms. Defaults to 500 ms.
#This is how much to wait from byte to byte before raise an error.
MB_BYTE_TIMEOUT_MS=500
#OPTIONAL: Instead of giving the transaction number, use a name.
#Example: mb2hal.00.01 could become mb2hal.plcin.01
#The name must not exceed 32 characters.
#NOTE: when using names be careful that you dont end up with two transactions
#usign the same name.
HAL_TX_NAME=remoteIOcfg
#OPTIONAL: Maximum update rate in HZ. Defaults to 0.0 (0.0 = as soon as available = infinit).
#NOTE: This is a maximum rate and the actual rate may be lower.
#If you want to calculate it in ms use (1000 / required_ms).
#Example: 100 ms = MAX_UPDATE_RATE=10.0, because 1000.0 ms / 100.0 ms = 10.0 Hz
MAX_UPDATE_RATE=0.0
#OPTIONAL: Debug level for this transaction only.
#See INIT_DEBUG parameter above.
DEBUG=1
#While DEBUGGING transactions note the returned "ret[]" value correspond to:
#/* Modbus protocol exceptions */
#ILLEGAL_FUNCTION -0x01 the FUNCTION code received in the query is not allowed or invalid.
#ILLEGAL_DATA_ADDRESS -0x02 the DATA ADDRESS received in the query is not an allowable address for the slave or is invalid.
#ILLEGAL_DATA_VALUE -0x03 a VALUE contained in the data query field is not an allowable value or is invalid.
#SLAVE_DEVICE_FAILURE -0x04 SLAVE (or MASTER) device unrecoverable FAILUER while attemping to perform the requested action.
#SERVER_FAILURE -0x04 (see above).
#ACKNOWLEDGE -0x05 This response is returned to PREVENT A TIMEOUT in the master.
# A long duration of time is required to process the request in the slave.
#SLAVE_DEVICE_BUSY -0x06 The slave (or server) is BUSY. Retrasmit the request later.
#SERVER_BUSY -0x06 (see above).
#NEGATIVE_ACKNOWLEDGE -0x07 Unsuccessful programming request using function code 13 or 14.
#MEMORY_PARITY_ERROR -0x08 SLAVE parity error in MEMORY.
#GATEWAY_PROBLEM_PATH -0x0A (-10) Gateway path(s) not available.
#GATEWAY_PROBLEM_TARGET -0x0B (-11) The target device failed to repond (generated by master, not slave).
#/* Program or connection */
#COMM_TIME_OUT -0x0C (-12)
#PORT_SOCKET_FAILURE -0x0D (-13)
#SELECT_FAILURE -0x0E (-14)
#TOO_MANY_DATAS -0x0F (-15)
#INVALID_CRC -0x10 (-16)
#INVALID_EXCEPTION_CODE -0x11 (-17)
[TRANSACTION_01]
MB_TX_CODE=fnct_02_read_discrete_inputs
FIRST_ELEMENT=1024
NELEMENTS=24
HAL_TX_NAME=remoteIOin
MAX_UPDATE_RATE=0.0
DEBUG=1
[TRANSACTION_02]
MB_TX_CODE=fnct_15_write_multiple_coils
FIRST_ELEMENT=1280
NELEMENTS=8
HAL_TX_NAME=remoteIOout
MAX_UPDATE_RATE=0.0
[TRANSACTION_03]
LINK_TYPE=serial
SERIAL_PORT=/dev/ttyS0
SERIAL_BAUD=115200
SERIAL_BITS=8
SERIAL_PARITY=none
SERIAL_STOP=2
SERIAL_DELAY_MS=50
MB_SLAVE_ID=1
MB_TX_CODE=fnct_03_read_holding_registers
FIRST_ELEMENT=1
NELEMENTS=2
HAL_TX_NAME=XDrive01
MAX_UPDATE_RATE=0.0
DEBUG=1
[TRANSACTION_04]
MB_TX_CODE=fnct_03_read_holding_registers
FIRST_ELEMENT=4
NELEMENTS=3
HAL_TX_NAME=XDrive02
MAX_UPDATE_RATE=0.0
DEBUG=1
[TRANSACTION_05]
MB_TX_CODE=fnct_03_read_holding_registers
FIRST_ELEMENT=9
NELEMENTS=1
HAL_TX_NAME=XDrive03
MAX_UPDATE_RATE=0.0
[TRANSACTION_06]
MB_TX_CODE=fnct_03_read_holding_registers
FIRST_ELEMENT=1024
NELEMENTS=1
HAL_TX_NAME=XDrive04
MAX_UPDATE_RATE=0.0
[TRANSACTION_07]
MB_TX_CODE=fnct_03_read_holding_registers
FIRST_ELEMENT=1030
NELEMENTS=2
HAL_TX_NAME=XDrive05
MAX_UPDATE_RATE=0.0
[TRANSACTION_08]
MB_TX_CODE=fnct_03_read_holding_registers
FIRST_ELEMENT=1033
NELEMENTS=1
HAL_TX_NAME=XDrive06
MAX_UPDATE_RATE=0.0
#include "mb2hal.h"
retCode create_HAL_pins()
{
const char *fnct_name = "create_HAL_pins";
int tx_counter;
for (tx_counter = 0; tx_counter < gbl.tot_mb_tx; tx_counter++) {
if (create_each_mb_tx_hal_pins(&gbl.mb_tx[tx_counter]) != retOK) {
ERR(gbl.init_dbg, "failed to initialize hal pins in tx_num[%d] [%d] [%s]",
tx_counter, gbl.mb_tx[tx_counter].mb_tx_fnct, gbl.mb_tx[tx_counter].mb_tx_fnct_name);
return retERR;
}
}
return retOK;
}
#define CREATE_PIN(C, T, F)\
mb_tx->C = (T **)hal_malloc(sizeof(T *));\
if (mb_tx->C == NULL) {\
ERR(gbl.init_dbg, "[%d] [%s] NULL hal_malloc num_errors",\
mb_tx->mb_tx_fnct, mb_tx->mb_tx_fnct_name);\
return retERR;\
}\
memset(mb_tx->C, 0, sizeof(T *));\
snprintf(hal_pin_name, HAL_NAME_LEN, "%s.%s.%s", gbl.hal_mod_name, mb_tx->hal_tx_name, #C);\
if (0 != F(HAL_OUT, mb_tx->C, gbl.hal_mod_id, "%s", hal_pin_name)) {\
ERR(gbl.init_dbg, "[%d] [%s] [%s] " #F " pin failed", mb_tx->mb_tx_fnct, mb_tx->mb_tx_fnct_name, hal_pin_name);\
return retERR;\
}\
**(mb_tx->num_errors) = 0;\
DBG(gbl.init_dbg, "mb_tx_num [%d] pin_name [%s]", mb_tx->mb_tx_num, hal_pin_name);
retCode create_each_mb_tx_hal_pins(mb_tx_t *mb_tx)
{
const char *fnct_name = "create_each_mb_tx_hal_pins";
char hal_pin_name[HAL_NAME_LEN + 1];
int pin_counter;
if (mb_tx == NULL) {
ERR(gbl.init_dbg, "NULL pointer");
return retERR;
}
//num_errors hal pin
mb_tx->num_errors = (hal_u32_t**)hal_malloc(sizeof(hal_u32_t *));
if (mb_tx->num_errors == NULL) {
ERR(gbl.init_dbg, "[%d] [%s] NULL hal_malloc num_errors",
mb_tx->mb_tx_fnct, mb_tx->mb_tx_fnct_name);
return retERR;
}
memset(mb_tx->num_errors, 0, sizeof(hal_u32_t *));
snprintf(hal_pin_name, HAL_NAME_LEN, "%s.%s.num_errors", gbl.hal_mod_name, mb_tx->hal_tx_name);
if (0 != hal_pin_u32_newf(HAL_OUT, mb_tx->num_errors, gbl.hal_mod_id, "%s", hal_pin_name)) {
ERR(gbl.init_dbg, "[%d] [%s] [%s] hal_pin_u32_newf failed", mb_tx->mb_tx_fnct, mb_tx->mb_tx_fnct_name, hal_pin_name);
return retERR;
}
**(mb_tx->num_errors) = 0;
DBG(gbl.init_dbg, "mb_tx_num [%d] pin_name [%s]", mb_tx->mb_tx_num, hal_pin_name);
// modbus_ok hal pin
CREATE_PIN(modbus_ok, hal_bit_t, hal_pin_bit_newf);
CREATE_PIN(cumul_errors, hal_s32_t, hal_pin_s32_newf);
CREATE_PIN(cumul_transactions, hal_s32_t, hal_pin_s32_newf);
if (!mb_tx->nb_hal_map_pin) { // Old fashioned pin management
switch (mb_tx->mb_tx_fnct) {
case mbtx_02_READ_DISCRETE_INPUTS:
case mbtx_15_WRITE_MULTIPLE_COILS:
case mbtx_05_WRITE_SINGLE_COIL:
mb_tx->bit = (hal_bit_t **)hal_malloc(sizeof(hal_bit_t *) * mb_tx->mb_tx_nelem);
if (mb_tx->bit == NULL) {
ERR(gbl.init_dbg, "[%d] [%s] NULL hal_malloc [%d] elements",
mb_tx->mb_tx_fnct, mb_tx->mb_tx_fnct_name, mb_tx->mb_tx_nelem);
return retERR;
}
memset(mb_tx->bit, 0, sizeof(hal_bit_t *) * mb_tx->mb_tx_nelem);
break;
case mbtx_03_READ_HOLDING_REGISTERS:
case mbtx_04_READ_INPUT_REGISTERS:
case mbtx_16_WRITE_MULTIPLE_REGISTERS:
mb_tx->float_value= (hal_float_t **)hal_malloc(sizeof(hal_float_t *) * mb_tx->mb_tx_nelem);
mb_tx->int_value = (hal_s32_t **)hal_malloc(sizeof(hal_s32_t *) * mb_tx->mb_tx_nelem);
//mb_tx->scale = hal_malloc(sizeof(hal_float_t) * mb_tx->mb_tx_nelem);
//mb_tx->offset = hal_malloc(sizeof(hal_float_t) * mb_tx->mb_tx_nelem);
//if (mb_tx->float_value == NULL || mb_tx->int_value == NULL
// || mb_tx->scale == NULL || mb_tx->offset == NULL) {
if (mb_tx->float_value == NULL || mb_tx->int_value == NULL) {
ERR(gbl.init_dbg, "[%d] [%s] NULL hal_malloc [%d] elements",
mb_tx->mb_tx_fnct, mb_tx->mb_tx_fnct_name, mb_tx->mb_tx_nelem);
return retERR;
}
memset(mb_tx->float_value, 0, sizeof(hal_float_t *) * mb_tx->mb_tx_nelem);
memset(mb_tx->int_value, 0, sizeof(hal_s32_t *) * mb_tx->mb_tx_nelem);
//memset((void *) mb_tx->scale, 0, sizeof(hal_float_t) * mb_tx->mb_tx_nelem);
//memset((void *) mb_tx->offset, 0, sizeof(hal_float_t) * mb_tx->mb_tx_nelem);
break;
default:
ERR(gbl.init_dbg, "[%d] wrong mb_tx_fnct", mb_tx->mb_tx_fnct);
return retERR;
break;
}
for (pin_counter = 0; pin_counter < mb_tx->mb_tx_nelem; pin_counter++) {
snprintf(hal_pin_name, HAL_NAME_LEN, "%s.%s.%02d", gbl.hal_mod_name, mb_tx->hal_tx_name, pin_counter);
DBG(gbl.init_dbg, "mb_tx_num [%d] pin_name [%s]", mb_tx->mb_tx_num, hal_pin_name);
switch (mb_tx->mb_tx_fnct) {
case mbtx_15_WRITE_MULTIPLE_COILS:
case mbtx_05_WRITE_SINGLE_COIL:
if (0 != hal_pin_bit_newf(HAL_IN, mb_tx->bit + pin_counter, gbl.hal_mod_id,
"%s", hal_pin_name)) {
ERR(gbl.init_dbg, "[%d] [%s] [%s] hal_pin_bit_newf failed",
mb_tx->mb_tx_fnct, mb_tx->mb_tx_fnct_name, hal_pin_name);
return retERR;
}
*mb_tx->bit[pin_counter] = 0;
break;
case mbtx_02_READ_DISCRETE_INPUTS:
if (0 != hal_pin_bit_newf(HAL_OUT, mb_tx->bit + pin_counter, gbl.hal_mod_id,
"%s", hal_pin_name)) {
ERR(gbl.init_dbg, "[%d] [%s] [%s] hal_pin_bit_newf failed",
mb_tx->mb_tx_fnct, mb_tx->mb_tx_fnct_name, hal_pin_name);
return retERR;
}
*mb_tx->bit[pin_counter] = 0;
break;
case mbtx_04_READ_INPUT_REGISTERS:
case mbtx_03_READ_HOLDING_REGISTERS:
if (0 != hal_pin_float_newf(HAL_OUT, mb_tx->float_value + pin_counter, gbl.hal_mod_id,
"%s.float", hal_pin_name)) {
ERR(gbl.init_dbg, "[%d] [%s] [%s] hal_pin_float_newf failed",
mb_tx->mb_tx_fnct, mb_tx->mb_tx_fnct_name, hal_pin_name);
return retERR;
}
if (0 != hal_pin_s32_newf(HAL_OUT, mb_tx->int_value + pin_counter, gbl.hal_mod_id,
"%s.int", hal_pin_name)) {
ERR(gbl.init_dbg, "[%d] [%s] [%s] hal_pin_s32_newf failed",
mb_tx->mb_tx_fnct, mb_tx->mb_tx_fnct_name, hal_pin_name);
return retERR;
}
*mb_tx->float_value[pin_counter] = 0;
*mb_tx->int_value[pin_counter] = 0;
break;
case mbtx_16_WRITE_MULTIPLE_REGISTERS:
if (0 != hal_pin_float_newf(HAL_IN, mb_tx->float_value + pin_counter, gbl.hal_mod_id,
"%s", hal_pin_name)) {
ERR(gbl.init_dbg, "[%d] [%s] [%s] hal_pin_float_newf failed",
mb_tx->mb_tx_fnct, mb_tx->mb_tx_fnct_name, hal_pin_name);
return retERR;
}
*mb_tx->float_value[pin_counter] = 0;
break;
default:
ERR(gbl.init_dbg, "[%d]", mb_tx->mb_tx_fnct);
return retERR;
break;
}
}
}
else { // We are using enhanced pin mapping
hal_pin_dir_t dir;
switch (mb_tx->mb_tx_fnct) {
case mbtx_15_WRITE_MULTIPLE_COILS:
case mbtx_16_WRITE_MULTIPLE_REGISTERS:
case mbtx_05_WRITE_SINGLE_COIL:
dir = HAL_IN;
break;
case mbtx_02_READ_DISCRETE_INPUTS:
case mbtx_04_READ_INPUT_REGISTERS:
case mbtx_03_READ_HOLDING_REGISTERS:
dir = HAL_OUT;
break;
default:
ERR(gbl.init_dbg, "[%d]", mb_tx->mb_tx_fnct);
return retERR;
break;
}
mb_tx->pin_value = (hal_data_u **)hal_malloc(sizeof(hal_data_u *) * mb_tx->nb_hal_map_pin);
if (mb_tx->pin_value == NULL) {
ERR(gbl.init_dbg, "[%d] [%s] NULL hal_malloc [%d] pins",
mb_tx->mb_tx_fnct, mb_tx->mb_tx_fnct_name, mb_tx->nb_hal_map_pin);
return retERR;
}
memset(mb_tx->pin_value, 0, sizeof(hal_data_u *) * mb_tx->nb_hal_map_pin);
for (int index=0; index<mb_tx->nb_hal_map_pin; index++) {
hal_map_pin_t *m = &mb_tx->hal_map_pin[index];
int rc = 1;
switch (m->type) {
case HAL_BIT:
rc = hal_pin_bit_newf(dir, (hal_bit_t **)mb_tx->pin_value + index, gbl.hal_mod_id,
"%s.%s.%s", gbl.hal_mod_name, mb_tx->hal_tx_name, m->name);
break;
case HAL_FLOAT:
rc = hal_pin_float_newf(dir, (hal_float_t **)mb_tx->pin_value + index, gbl.hal_mod_id,
"%s.%s.%s", gbl.hal_mod_name, mb_tx->hal_tx_name, m->name);
break;
case HAL_S32:
rc = hal_pin_s32_newf(dir, (hal_s32_t **)mb_tx->pin_value + index, gbl.hal_mod_id,
"%s.%s.%s", gbl.hal_mod_name, mb_tx->hal_tx_name, m->name);
break;
case HAL_U32:
rc = hal_pin_u32_newf(dir, (hal_u32_t **)mb_tx->pin_value + index, gbl.hal_mod_id,
"%s.%s.%s", gbl.hal_mod_name, mb_tx->hal_tx_name, m->name);
break;
}
if (0 != rc) {
ERR(gbl.init_dbg, "hal_pin_xxx_newf(type=%d, name=%s.%s.%s) error",
m->type, gbl.hal_mod_name, mb_tx->hal_tx_name, m->name);
return retERR;
}
}
}
return retOK;
}
This diff is collapsed.
This diff is collapsed.
#TEST 01: TCP and RS232.
# - TCP = Remote IO Delta RTU-EN01, 24 inputs, 8 outputs.
# - RS232 = Servo Drive Delta ASDA-B (1021-A 1Kw).
[MB2HAL_INIT]
INIT_DEBUG=2
SLOWDOWN=0.0
TOTAL_TRANSACTIONS=9
[TRANSACTION_00]
LINK_TYPE=tcp
TCP_IP=192.168.2.10
TCP_PORT=502
MB_SLAVE_ID=1
FIRST_ELEMENT=0
NELEMENTS=16
MB_TX_CODE=fnct_03_read_holding_registers
HAL_TX_NAME=remoteIOcfg
MAX_UPDATE_RATE=10.0
DEBUG=1
[TRANSACTION_01]
MB_TX_CODE=fnct_02_read_discrete_inputs
FIRST_ELEMENT=1024
NELEMENTS=24
HAL_TX_NAME=remoteIOin