PR-765 Rework the modbus master so that it is also configured as a service

This commit is contained in:
Garret Fick 2019-11-20 14:36:18 -05:00
parent e84dcd388f
commit 4da27d3724
No known key found for this signature in database
GPG Key ID: A1BBEF9D2AB249C6
2 changed files with 35 additions and 7 deletions

View File

@ -54,17 +54,24 @@ binding = sized
; ---------------------------------------------------------
[modbusmaster]
; Modbus master enables reading and writing located variables through the
; modbus interface. This starts capabilties to poll one or more Modbus
; modbus interface. This starts capabilities to poll one or more Modbus
; servers and exchange data with the located variables.
enabled = true
; We support multiple modbus masters. Each master should specify
; We support multiple Modbus masters. Each master should specify
; a complete set of configuration information within this section.
; Different masters are identified by a postfix which includes the
; index of the master. Indices start at 0 and go up from there.
; A user defined name for the connection. This name appears in log messages.
name.0 = 1
; The protocol to use for connection. This value must be one of:
; tcp
; rtu
; If you set this to any other value, then this configuration item group
; is not created. You might use this to disable connecting to a particular
; Modbus slave.
protocol.0 = tcp
slave_id.0 = 1
ip_address.0 = 127.0.0.1
@ -89,7 +96,7 @@ discrete_inputs_size.0 = 1
[pstorage]
; The pstorage service reads and writes persistent storage. It enables
; the runtime to restore important variables to the previous value
; if the runtime is restarated.
; if the runtime is restarted.
enabled = false
; How long should we wait between write cycle. The persistent storage
@ -155,12 +162,12 @@ enable_unsolicited = true
; max control commands for a single APDU
; max_controls_per_request = 16
; maximum fragment size the outstation will recieve
; maximum fragment size the outstation will receive
; default is the max value
; max_rx_frag_size = 2048
; maximum fragment size the outstation will send if
; it needs to fragment. Default is the max falue
; it needs to fragment. Default is the max falure
; max_tx_frag_size = 2048
; size of the event buffer
@ -170,7 +177,7 @@ enable_unsolicited = true
; sol_confirm_timeout = 5000
; Timeout for unsolicited confirms (milliseconds)
; unsol_conrfirm_timeout = 5000
; unsol_confirm_timeout = 5000
; Timeout for unsolicited retries (milliseconds)
; unsol_retry_timeout = 5000

View File

@ -75,14 +75,17 @@ void updateBuffersOut_MB()
pthread_mutex_unlock(&ioLock);
}
/// Defines the protocol that is selected by ser configuration.
enum MasterProtocol {
ProtocolInvalid,
ProtocolTcp,
ProtocolRtu,
};
/// How big of a buffer do we reserve for string items.
const uint8_t MASTER_ITEM_SIZE(100);
/// Define the mapping for modbus addresses located variables.
struct ModbusAddress
{
uint16_t start_address;
@ -106,8 +109,11 @@ struct Master {
uint8_t rtu_parity;
uint16_t rtu_data_bit;
uint16_t rtu_stop_bit;
/// The context for communcating with the device.
modbus_t* mb_ctx;
/// Device specific timeout.
uint16_t timeout;
/// Is the device currently connected.
bool is_connected;
struct ModbusAddress discrete_inputs;
@ -124,6 +130,8 @@ struct Master {
is_connected(false)
{}
/// Create the context for the device according to the configuration
/// parameters provided by the user.
void create() {
if (protocol == ProtocolTcp) {
mb_ctx = modbus_new_tcp(ip_address, ip_port);
@ -139,11 +147,15 @@ struct Master {
}
};
/// Configuration structure that is passed into the ini parsing library.
/// This structure is populated as we process configuration items.
struct ModbusMasterConfig {
chrono::milliseconds polling_period;
vector<Master>* masters;
/// Get (or create) the configuration items at the specified index.
/// This ensure that this index is addessable.
Master* config_item(uint8_t index) {
size_t required_size = max(masters->size(), static_cast<size_t>(index + 1));
if (masters->size() < required_size) {
@ -153,6 +165,8 @@ struct ModbusMasterConfig {
}
};
/// Callback function for the ini parser. This function is called for every
/// configuration item.
int modbus_master_cfg_handler(void* user_data, const char* section,
const char* name, const char* value) {
if (strcmp("modbusmaster", section) != 0) {
@ -216,12 +230,15 @@ int modbus_master_cfg_handler(void* user_data, const char* section,
return 0;
}
/// Arguments provided to the master polling thread.
struct MasterArgs {
volatile bool* run;
chrono::milliseconds polling_period;
vector<Master>* masters;
};
/// Polls modbus slaves. This is the main function created by this modbus
/// master.
void* modbus_master_poll_slaves(void* args) {
auto master_args = reinterpret_cast<MasterArgs*>(args);
@ -433,6 +450,8 @@ void* modbus_master_poll_slaves(void* args) {
return 0;
}
/// Run the modbus master. This function does not return until
/// this service is terminated.
void modbus_master_run(oplc::config_stream& cfg_stream,
const char* cfg_overrides,
const GlueVariablesBinding& bindings,
@ -476,7 +495,9 @@ void modbus_master_run(oplc::config_stream& cfg_stream,
this_thread::sleep_for(chrono::milliseconds(500));
}
// Terminate the unified polling thread.
// Terminate the unified polling thread. It is important to wait
// here because we passed information to the modbus thread that is
// on this stack.
pthread_join(thread, nullptr);
}