Edited: Need help with MODBUS TCP on esp32 (wroom-32D - devkitc-v4)
Posted: Wed Oct 06, 2021 6:08 pm
i'm trying to stablish communications between an esp32 and a virtual modbus tcp opc server on my computer. to do so, i create a netif wifi station on the esp32 and connect it to my router (so far so good), the esp appears in the router page and i already assigned a static ip to it (i have AP isolation turned off on the router).
Edit: i updated the debug code with extra backtrace information, so i guess its a hostname error:
apparently, i can create the TCP slave (which has my computer IP address) but i can't get to the part where the connection starts, because i got the core 0 panic'ed error.
here's the code i used (i'm programming on platformio using esp-idf):
Edit: i updated the debug code with extra backtrace information, so i guess its a hostname error:
Code: Select all
I (31452) MB_TCP_MASTER_PORT: TCP master stack initialized.
D (31452) intr_alloc: Connected src 14 to int 13 (cpu 0)
I (31452) MB_TCP_MASTER_PORT: Host[IP]: "192.168.1.180"[192.168.1.180]
I (31452) MB_TCP_MASTER_PORT: Add slave IP: 192.168.1.180
Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x400e669b PS : 0x00060130 A0 : 0x800f19d3 A1 : 0x3ffbe1e0
0x400e669b: dns_gethostbyname_addrtype at C:/esp-idf/components/lwip/lwip/src/core/dns.c:1609
A2 : 0x00000002 A3 : 0x3ffba7a0 A4 : 0x400f085c A5 : 0x3ffba760
0x400f085c: lwip_netconn_do_dns_found at C:/esp-idf/components/lwip/lwip/src/api/api_msg.c:2219
A6 : 0x00000000 A7 : 0x00000000 A8 : 0x00000000 A9 : 0x00000000
A10 : 0x00000000 A11 : 0x3ffbe240 A12 : 0x3ffbd470 A13 : 0x00000000
A14 : 0x00000000 A15 : 0xff000000 SAR : 0x0000001c EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000002 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0xffffffff
Backtrace:0x400e6698:0x3ffbe1e0 0x400f19d0:0x3ffbe200 0x400e5855:0x3ffbe220 0x400e58fc:0x3ffbe240 0x4008c121:0x3ffbe270
0x400e6698: dns_gethostbyname_addrtype at C:/esp-idf/components/lwip/lwip/src/core/dns.c:1608
0x400f19d0: lwip_netconn_do_gethostbyname at C:/esp-idf/components/lwip/lwip/src/api/api_msg.c:2254
here's the code i used (i'm programming on platformio using esp-idf):
Code: Select all
/* WiFi station Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
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 <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "esp_modbus_master.h"
#include "sodium.h"
#include "sdkconfig.h"
#define MB_TCP_PORT 502
#define STR(fieldname) ((const char*)( fieldname ))
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }
#define MASTER_TAG "MASTER_TEST"
#define MASTER_CHECK(a, ret_val, str, ...) \
if (!(a)) { \
ESP_LOGE(MASTER_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
return (ret_val); \
}
// ***************************************************** wi-fi *****************************************************
/* The examples use WiFi configuration that you can set via project configuration menu
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID "APT_102_2G"
#define EXAMPLE_ESP_WIFI_PASS "101203vitoria"
#define EXAMPLE_ESP_MAXIMUM_RETRY 5
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;
/* The event group allows multiple bits for each event, but we only care about two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static const char *TAG = "wifi station";
static int s_retry_num = 0;
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG,"connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
esp_netif_t *netif_ptr;
int teste;
void wifi_init_sta(void)
{
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
netif_ptr = esp_netif_create_default_wifi_sta();
assert(netif_ptr);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&event_handler,
NULL,
&instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip));
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.password = EXAMPLE_ESP_WIFI_PASS,
/* Setting a password implies station will connect to all security modes including WEP/WPA.
* However these modes are deprecated and not advisable to be used. Incase your Access point
* doesn't support WPA2, these mode can be enabled by commenting below line */
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
.pmf_cfg = {
.capable = true,
.required = false
},
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
ESP_ERROR_CHECK(esp_wifi_start() );
ESP_LOGI(TAG, "wifi_init_sta finished.");
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
* happened. */
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
} else {
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
/* The event will not be processed after unregister */
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
vEventGroupDelete(s_wifi_event_group);
}
// ******************************************* MODBUS *************************************************
// Enumeration of modbus slave addresses accessed by master device
enum {
MB_DEVICE_ADDR1 = 3,
MB_SLAVE_COUNT
};
// Enumeration of all supported CIDs for device
enum {
CID_TENSAO = 0,
CID_SW_VER1,
CID_TEMP_DATA_1,
};
const mb_parameter_descriptor_t* param_descriptor = NULL;
uint8_t temp_data[4] = {0}; // temporary buffer to hold maximum CID size
uint8_t type = 0;
uint16_t cid = 0;
static esp_err_t read_modbus_parameter(uint16_t cid, uint16_t *par_data)
{
const mb_parameter_descriptor_t* param_descriptor = NULL;
esp_err_t err = mbc_master_get_cid_info(cid, ¶m_descriptor);
if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL)) {
uint8_t type = 0;
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
(uint8_t*)par_data, &type);
if (err == ESP_OK) {
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%04x) parameter read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
*(uint16_t*)par_data);
}
else
{
ESP_LOGE(MASTER_TAG, "Characteristic #%d %s (%s), parameter read fail.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units);
}
}
return err;
}
static esp_err_t write_modbus_parameter(uint16_t cid, uint16_t *par_data)
{
const mb_parameter_descriptor_t* param_descriptor = NULL;
esp_err_t err = mbc_master_get_cid_info(cid, ¶m_descriptor);
if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL)) {
uint8_t type = 0; // type of parameter from dictionary
err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
(uint8_t*)par_data, &type);
if (err == ESP_OK) {
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%04x), write successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
*(uint16_t*)par_data);
} else {
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(int)err,
(char*)esp_err_to_name(err));
}
}
return err;
}
// This is user function to read and write modbus holding registers
static void master_read_write_func(void *arg)
{
esp_err_t err = ESP_OK;
uint16_t register_data = 0;
ESP_LOGI(MASTER_TAG, "Start modbus test...");
for(uint16_t retry = 0; retry <= 5; retry++) {
// Simply read your register here CID_DEV_REG0 - one register from address 0 (see device_parameters)
err = read_modbus_parameter(CID_TENSAO, ®ister_data);
if (err == ESP_OK) {
// if read successful then increase value of the parameter
// Insert your modbus read_write register functionality here
register_data += 1;
err = write_modbus_parameter(CID_TENSAO, ®ister_data);
}
/*err = read_modbus_parameter(CID_DEV_REG1, ®ister_data);
if (err == ESP_OK) {
register_data += 1;
err = write_modbus_parameter(CID_DEV_REG1, ®ister_data);
}*/
}
ESP_LOGI(MASTER_TAG, "Modbus test is completed.");
}
// Inicializar MODBUS
static esp_err_t master_init(void){
// Dicionário MODBUS
// Example Data Dictionary for Modbus parameters in 1 slave in the segment
mb_parameter_descriptor_t device_parameters[] = {
// CID, Name, Units, Modbus addr, register type, Modbus Reg Start Addr, Modbus Reg read length,
// Instance offset (NA), Instance type, Instance length (bytes), Options (NA), Permissions
{ CID_TENSAO, STR("Tensão_1"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2,
0, PARAM_TYPE_U16, 2, OPTS( 0,0,0 ), PAR_PERMS_READ_WRITE_TRIGGER },
};
// Calculate number of parameters in the table
const uint16_t num_device_parameters = (sizeof(device_parameters)/sizeof(device_parameters[0]));
#define MB_SLAVE_COUNT 1 // Number of slaves in the segment being accessed (as defined in Data Dictionary)
void* master_handler = NULL; // Pointer to allocate interface structure
// Initialization of Modbus slave for TCP
esp_err_t err = mbc_master_init_tcp(&master_handler);
if (master_handler == NULL || err != ESP_OK) {
// Error handling is performed here
ESP_LOGE(MASTER_TAG, "mb controller initialization fail.");
}
char* slave_ip_address_table[MB_SLAVE_COUNT] = {
"192.168.1.180", // Address corresponds to UID1 and set to predefined value by user
};
mb_communication_info_t comm_info = {
.ip_port = MB_TCP_PORT, // Modbus TCP port number (default = 502)
.ip_addr_type = MB_IPV4, // version of IP protocol
.ip_mode = MB_MODE_TCP, // Port communication mode
.ip_addr = slave_ip_address_table, // assign table of IP addresses
.ip_netif_ptr = netif_ptr // esp_netif_ptr pointer to the corresponding network interface
};
ESP_ERROR_CHECK(mbc_master_setup((void*)&comm_info));
ESP_ERROR_CHECK(mbc_master_set_descriptor(&device_parameters[0], num_device_parameters));
// Início comunicação MODBUS
esp_err_t err1 = mbc_master_start();
if (err1 != ESP_OK) {
ESP_LOGE(MASTER_TAG, "mb controller start fail, err=%x.", err1);
}
vTaskDelay(5);
esp_err_t err2 = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
MASTER_CHECK((err2 == ESP_OK), ESP_ERR_INVALID_STATE,
"mb controller set descriptor fail, returns(0x%x).",
(uint32_t)err2);
ESP_LOGI(MASTER_TAG, "Modbus master stack initialized...");
return err2;
}
void app_main(void)
{
// *************************************************** Conectar wi-fi ***************************************************
//Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
wifi_init_sta();
vTaskDelay(50);
// ***************************************************** Modbus TCP *****************************************************
// Initialization of device peripheral and objects
ESP_ERROR_CHECK(master_init());
vTaskDelay(50);
master_read_write_func(NULL);
// Processamento de dados
// Criptografia
// Envio de dados
}