| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- /* FreeModbus Slave Example ESP32
- Unless required by applicable law or agreed to in writing, this
- software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
- CONDITIONS OF ANY KIND, either express or implied.
- */
- #include <stdio.h>
- #include <stdint.h>
- #include "esp_err.h"
- #include "mbcontroller.h" // for mbcontroller defines and api
- #include "modbus_params.h" // for modbus parameters structures
- #include "esp_log.h" // for log_write
- #include "sdkconfig.h"
- #define MB_PORT_NUM (CONFIG_MB_UART_PORT_NUM) // Number of UART port used for Modbus connection
- #define MB_SLAVE_ADDR (CONFIG_MB_SLAVE_ADDR) // The address of device in Modbus network
- #define MB_DEV_SPEED (CONFIG_MB_UART_BAUD_RATE) // The communication speed of the UART
- // Note: Some pins on target chip cannot be assigned for UART communication.
- // Please refer to documentation for selected board and target to configure pins using Kconfig.
- // Defines below are used to define register start address for each type of Modbus registers
- #define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) >> 1))
- #define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) >> 1))
- #define MB_REG_DISCRETE_INPUT_START (0x0000)
- #define MB_REG_COILS_START (0x0000)
- #define MB_REG_INPUT_START_AREA0 (INPUT_OFFSET(input_data0)) // register offset input area 0
- #define MB_REG_INPUT_START_AREA1 (INPUT_OFFSET(input_data4)) // register offset input area 1
- #define MB_REG_HOLDING_START_AREA0 (HOLD_OFFSET(holding_data0))
- #define MB_REG_HOLDING_START_AREA1 (HOLD_OFFSET(holding_data4))
- #define MB_PAR_INFO_GET_TOUT (10) // Timeout for get parameter info
- #define MB_CHAN_DATA_MAX_VAL (6)
- #define MB_CHAN_DATA_OFFSET (0.2f)
- #define MB_READ_MASK (MB_EVENT_INPUT_REG_RD \
- | MB_EVENT_HOLDING_REG_RD \
- | MB_EVENT_DISCRETE_RD \
- | MB_EVENT_COILS_RD)
- #define MB_WRITE_MASK (MB_EVENT_HOLDING_REG_WR \
- | MB_EVENT_COILS_WR)
- #define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
- static const char *SLAVE_TAG = "SLAVE_TEST";
- static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
- // Set register values into known state
- static void setup_reg_data(void)
- {
- // Define initial state of parameters
- discrete_reg_params.discrete_input0 = 1;
- discrete_reg_params.discrete_input1 = 0;
- discrete_reg_params.discrete_input2 = 1;
- discrete_reg_params.discrete_input3 = 0;
- discrete_reg_params.discrete_input4 = 1;
- discrete_reg_params.discrete_input5 = 0;
- discrete_reg_params.discrete_input6 = 1;
- discrete_reg_params.discrete_input7 = 0;
- holding_reg_params.holding_data0 = 1.34;
- holding_reg_params.holding_data1 = 2.56;
- holding_reg_params.holding_data2 = 3.78;
- holding_reg_params.holding_data3 = 4.90;
- holding_reg_params.holding_data4 = 5.67;
- holding_reg_params.holding_data5 = 6.78;
- holding_reg_params.holding_data6 = 7.79;
- holding_reg_params.holding_data7 = 8.80;
- coil_reg_params.coils_port0 = 0x55;
- coil_reg_params.coils_port1 = 0xAA;
- input_reg_params.input_data0 = 1.12;
- input_reg_params.input_data1 = 2.34;
- input_reg_params.input_data2 = 3.56;
- input_reg_params.input_data3 = 4.78;
- input_reg_params.input_data4 = 1.12;
- input_reg_params.input_data5 = 2.34;
- input_reg_params.input_data6 = 3.56;
- input_reg_params.input_data7 = 4.78;
- }
- // An example application of Modbus slave. It is based on freemodbus stack.
- // See deviceparams.h file for more information about assigned Modbus parameters.
- // These parameters can be accessed from main application and also can be changed
- // by external Modbus master host.
- void app_main(void)
- {
- mb_param_info_t reg_info; // keeps the Modbus registers access information
- mb_communication_info_t comm_info; // Modbus communication parameters
- mb_register_area_descriptor_t reg_area; // Modbus register area descriptor structure
- // Set UART log level
- esp_log_level_set(SLAVE_TAG, ESP_LOG_INFO);
- void* mbc_slave_handler = NULL;
- ESP_ERROR_CHECK(mbc_slave_init(MB_PORT_SERIAL_SLAVE, &mbc_slave_handler)); // Initialization of Modbus controller
- // Setup communication parameters and start stack
- #if CONFIG_MB_COMM_MODE_ASCII
- comm_info.mode = MB_MODE_ASCII,
- #elif CONFIG_MB_COMM_MODE_RTU
- comm_info.mode = MB_MODE_RTU,
- #endif
- comm_info.slave_addr = MB_SLAVE_ADDR;
- comm_info.port = MB_PORT_NUM;
- comm_info.baudrate = MB_DEV_SPEED;
- comm_info.parity = MB_PARITY_NONE;
- ESP_ERROR_CHECK(mbc_slave_setup((void*)&comm_info));
- // The code below initializes Modbus register area descriptors
- // for Modbus Holding Registers, Input Registers, Coils and Discrete Inputs
- // Initialization should be done for each supported Modbus register area according to register map.
- // When external master trying to access the register in the area that is not initialized
- // by mbc_slave_set_descriptor() API call then Modbus stack
- // will send exception response for this register area.
- reg_area.type = MB_PARAM_HOLDING; // Set type of register area
- reg_area.start_offset = MB_REG_HOLDING_START_AREA0; // Offset of register area in Modbus protocol
- reg_area.address = (void*)&holding_reg_params.holding_data0; // Set pointer to storage instance
- // Set the size of register storage instance = 150 holding registers
- reg_area.size = (size_t)(HOLD_OFFSET(holding_data4) - HOLD_OFFSET(test_regs));
- ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
- reg_area.type = MB_PARAM_HOLDING; // Set type of register area
- reg_area.start_offset = MB_REG_HOLDING_START_AREA1; // Offset of register area in Modbus protocol
- reg_area.address = (void*)&holding_reg_params.holding_data4; // Set pointer to storage instance
- reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
- ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
- // Initialization of Input Registers area
- reg_area.type = MB_PARAM_INPUT;
- reg_area.start_offset = MB_REG_INPUT_START_AREA0;
- reg_area.address = (void*)&input_reg_params.input_data0;
- reg_area.size = sizeof(float) << 2;
- ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
- reg_area.type = MB_PARAM_INPUT;
- reg_area.start_offset = MB_REG_INPUT_START_AREA1;
- reg_area.address = (void*)&input_reg_params.input_data4;
- reg_area.size = sizeof(float) << 2;
- ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
- // Initialization of Coils register area
- reg_area.type = MB_PARAM_COIL;
- reg_area.start_offset = MB_REG_COILS_START;
- reg_area.address = (void*)&coil_reg_params;
- reg_area.size = sizeof(coil_reg_params);
- ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
- // Initialization of Discrete Inputs register area
- reg_area.type = MB_PARAM_DISCRETE;
- reg_area.start_offset = MB_REG_DISCRETE_INPUT_START;
- reg_area.address = (void*)&discrete_reg_params;
- reg_area.size = sizeof(discrete_reg_params);
- ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
- setup_reg_data(); // Set values into known state
- // Starts of modbus controller and stack
- ESP_ERROR_CHECK(mbc_slave_start());
- // Set UART pin numbers
- ESP_ERROR_CHECK(uart_set_pin(MB_PORT_NUM, CONFIG_MB_UART_TXD,
- CONFIG_MB_UART_RXD, CONFIG_MB_UART_RTS,
- UART_PIN_NO_CHANGE));
- // Set UART driver mode to Half Duplex
- ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX));
- ESP_LOGI(SLAVE_TAG, "Modbus slave stack initialized.");
- ESP_LOGI(SLAVE_TAG, "Start modbus test...");
- // The cycle below will be terminated when parameter holdingRegParams.dataChan0
- // incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
- for(;holding_reg_params.holding_data0 < MB_CHAN_DATA_MAX_VAL;) {
- // Check for read/write events of Modbus master for certain events
- mb_event_group_t event = mbc_slave_check_event(MB_READ_WRITE_MASK);
- const char* rw_str = (event & MB_READ_MASK) ? "READ" : "WRITE";
- // Filter events and process them accordingly
- if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
- // Get parameter information from parameter queue
- ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
- ESP_LOGI(SLAVE_TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
- rw_str,
- (uint32_t)reg_info.time_stamp,
- (uint32_t)reg_info.mb_offset,
- (uint32_t)reg_info.type,
- (uint32_t)reg_info.address,
- (uint32_t)reg_info.size);
- if (reg_info.address == (uint8_t*)&holding_reg_params.holding_data0)
- {
- portENTER_CRITICAL(¶m_lock);
- holding_reg_params.holding_data0 += MB_CHAN_DATA_OFFSET;
- if (holding_reg_params.holding_data0 >= (MB_CHAN_DATA_MAX_VAL - MB_CHAN_DATA_OFFSET)) {
- coil_reg_params.coils_port1 = 0xFF;
- }
- portEXIT_CRITICAL(¶m_lock);
- }
- } else if (event & MB_EVENT_INPUT_REG_RD) {
- ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
- ESP_LOGI(SLAVE_TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
- (uint32_t)reg_info.time_stamp,
- (uint32_t)reg_info.mb_offset,
- (uint32_t)reg_info.type,
- (uint32_t)reg_info.address,
- (uint32_t)reg_info.size);
- } else if (event & MB_EVENT_DISCRETE_RD) {
- ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
- ESP_LOGI(SLAVE_TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
- (uint32_t)reg_info.time_stamp,
- (uint32_t)reg_info.mb_offset,
- (uint32_t)reg_info.type,
- (uint32_t)reg_info.address,
- (uint32_t)reg_info.size);
- } else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
- ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
- ESP_LOGI(SLAVE_TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
- rw_str,
- (uint32_t)reg_info.time_stamp,
- (uint32_t)reg_info.mb_offset,
- (uint32_t)reg_info.type,
- (uint32_t)reg_info.address,
- (uint32_t)reg_info.size);
- if (coil_reg_params.coils_port1 == 0xFF) break;
- }
- }
- // Destroy of Modbus controller on alarm
- ESP_LOGI(SLAVE_TAG,"Modbus controller destroyed.");
- vTaskDelay(100);
- ESP_ERROR_CHECK(mbc_slave_destroy());
- }
|