eModbus / eModbus

Modbus library for RTU, ASCII and TCP protocols. Primarily developed on and for ESP32 MCUs.

Home Page:https://emodbus.github.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Compile-problem

KLelong opened this issue · comments

Hi,
Last week I tried to create an application on a ESP32, using Visual Studio Code and platformio.
It's a client using tcp to connect to my solar-inverter.
I struggled to get the correct addresses of the holding registers so I gave up to study the documentation of the inverter.
In other words, the application worked but I did get unexpected results.

Today, I modified the addresses and tried to compile the application. So only the addresses changed.
But the compiler gave errors.
So I created a new project and I copied the example TCP03Async-source to my new main.cpp file and added the eModbus library to the platformio.ini-file.
Again, the compiler complained and gave up.
It seems there is a dependency on an Ethernet-library. As far as I can see, that library is used for wired networks, but I'm using WiFi.
FWIW, here is the compiler-output :

Processing az-delivery-devkit-v4 (platform: espressif32; board: az-delivery-devkit-v4; framework: arduino)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/az-delivery-devkit-v4.html
PLATFORM: Espressif 32 (2024.1.1) > AZ-Delivery ESP-32 Dev Kit C V4
HARDWARE: ESP32 240MHz, 520KB RAM, 4MB Flash
DEBUG: Current (cmsis-dap) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES: 
 - framework-arduinoespressif32 @ 2.0.14 
 - tool-esptoolpy @ 1.40700.0 (4.7.0) 
 - tool-mklittlefs @ 3.2.0 
 - toolchain-xtensa-esp32 @ 8.4.0+2021r2-patch5
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 28 compatible libraries
Scanning dependencies...
Dependency Graph
|-- eModbus @ 1.7.1
|-- WiFi @ 2.0.0
Building in release mode
Compiling .pio/build/az-delivery-devkit-v4/src/main.cpp.o
Building .pio/build/az-delivery-devkit-v4/bootloader.bin
Generating partitions .pio/build/az-delivery-devkit-v4/partitions.bin
esptool.py v4.7.0
Creating esp32 image...
Merged 1 ELF section
Successfully created esp32 image.
Compiling .pio/build/az-delivery-devkit-v4/lib907/AsyncTCP/AsyncTCP.cpp.o
Compiling .pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/Dhcp.cpp.o
Compiling .pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/Dns.cpp.o
Compiling .pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/Ethernet.cpp.o
Compiling .pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/EthernetClient.cpp.o
Compiling .pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/EthernetServer.cpp.o
Compiling .pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/EthernetUdp.cpp.o
In file included from .pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/Ethernet.cpp:23:
.pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/utility/w5100.h:18:10: fatal error: SPI.h: No such file or directory

*************************************************************
* Looking for SPI.h dependency? Check our library registry!
*
* CLI  > platformio lib search "header:SPI.h"
* Web  > https://registry.platformio.org/search?q=header:SPI.h
*
*************************************************************

 #include <SPI.h>
          ^~~~~~~
compilation terminated.
*** [.pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/Ethernet.cpp.o] Error 1
In file included from .pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/Dhcp.cpp:7:
.pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/utility/w5100.h:18:10: fatal error: SPI.h: No such file or directory

*************************************************************
* Looking for SPI.h dependency? Check our library registry!
*
* CLI  > platformio lib search "header:SPI.h"
* Web  > https://registry.platformio.org/search?q=header:SPI.h
*
*************************************************************

 #include <SPI.h>
          ^~~~~~~
compilation terminated.
*** [.pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/Dhcp.cpp.o] Error 1
In file included from .pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/EthernetClient.cpp:24:
.pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/utility/w5100.h:18:10: fatal error: SPI.h: No such file or directory

*************************************************************
* Looking for SPI.h dependency? Check our library registry!
*
* CLI  > platformio lib search "header:SPI.h"
* Web  > https://registry.platformio.org/search?q=header:SPI.h
*
*************************************************************

 #include <SPI.h>
          ^~~~~~~
compilation terminated.
*** [.pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/EthernetClient.cpp.o] Error 1
In file included from .pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/Dns.cpp:8:
.pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/utility/w5100.h:18:10: fatal error: SPI.h: No such file or directory

*************************************************************
* Looking for SPI.h dependency? Check our library registry!
*
* CLI  > platformio lib search "header:SPI.h"
* Web  > https://registry.platformio.org/search?q=header:SPI.h
*
*************************************************************

 #include <SPI.h>
          ^~~~~~~
compilation terminated.
*** [.pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/Dns.cpp.o] Error 1
In file included from .pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/EthernetServer.cpp:23:
.pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/utility/w5100.h:18:10: fatal error: SPI.h: No such file or directory

*************************************************************
* Looking for SPI.h dependency? Check our library registry!
*
* CLI  > platformio lib search "header:SPI.h"
* Web  > https://registry.platformio.org/search?q=header:SPI.h
*
*************************************************************

 #include <SPI.h>
          ^~~~~~~
compilation terminated.
*** [.pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/EthernetServer.cpp.o] Error 1
In file included from .pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/EthernetUdp.cpp:32:
.pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/utility/w5100.h:18:10: fatal error: SPI.h: No such file or directory

*************************************************************
* Looking for SPI.h dependency? Check our library registry!
*
* CLI  > platformio lib search "header:SPI.h"
* Web  > https://registry.platformio.org/search?q=header:SPI.h
*
*************************************************************

 #include <SPI.h>
          ^~~~~~~
compilation terminated.
*** [.pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/EthernetUdp.cpp.o] Error 1
===================================================================================== [FAILED] Took 5.87 seconds =====================================================================================

 *  The terminal process "platformio 'run'" terminated with exit code: 1. 
 *  Terminal will be reused by tasks, press any key to close it. 

My original application used SPI, so there were other errors, also from that Ethernet-library. I can provide the compiler-output of that application if needed.

Any thoughts ?

This is strange, as SPI.h is part of the arduino-esp32 core code.

You wrote you are trying to use the ModbusClientTCPasync variety on the ESP32. Is there any reason for not using the regular ModbusClientWiFi? Else I would suggest you giving that a try.

If you really need the async variant, I will need to loop in @bertmelis , as he is the one who wrote the code for it.

ModbusClientWifi seems not to exist.
Now I copied the source from TCP03Example. That gives the same error.
When I #include SPI.h the other errors appear again. After a "Full Clean" :

Library Manager: Installing miq19/eModbus @ ^1.7.1
Unpacking  [####################################]  100%
Library Manager: eModbus@1.7.1 has been installed!
Library Manager: Resolving dependencies...
Library Manager: Installing me-no-dev/AsyncTCP @ *
Unpacking  [####################################]  100%
Library Manager: AsyncTCP@1.1.1 has been installed!
Library Manager: Installing git+https://github.com/maxgerhardt/Ethernet.git
git version 2.34.1
Cloning into '/home/koenraad/.platformio/.cache/tmp/pkg-installing-2so31oy0'...
remote: Enumerating objects: 47, done.
remote: Counting objects: 100% (47/47), done.
remote: Compressing objects: 100% (40/40), done.
remote: Total 47 (delta 4), reused 19 (delta 0), pack-reused 0
Receiving objects: 100% (47/47), 52.74 KiB | 2.51 MiB/s, done.
Resolving deltas: 100% (4/4), done.
Library Manager: custom-Ethernet@2.0.0+sha.c9399a9 has been installed!
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/az-delivery-devkit-v4.html
PLATFORM: Espressif 32 (2024.1.1) > AZ-Delivery ESP-32 Dev Kit C V4
HARDWARE: ESP32 240MHz, 520KB RAM, 4MB Flash
DEBUG: Current (cmsis-dap) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES: 
 - framework-arduinoespressif32 @ 2.0.14 
 - tool-esptoolpy @ 1.40700.0 (4.7.0) 
 - tool-mklittlefs @ 3.2.0 
 - toolchain-xtensa-esp32 @ 8.4.0+2021r2-patch5
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 28 compatible libraries
Scanning dependencies...
Dependency Graph
|-- eModbus @ 1.7.1
|-- SPI @ 2.0.0
|-- WiFi @ 2.0.0
Building in release mode
Compiling .pio/build/az-delivery-devkit-v4/src/main.cpp.o
Building .pio/build/az-delivery-devkit-v4/bootloader.bin
Generating partitions .pio/build/az-delivery-devkit-v4/partitions.bin
esptool.py v4.7.0
Creating esp32 image...
Merged 1 ELF section
Successfully created esp32 image.
Compiling .pio/build/az-delivery-devkit-v4/lib907/AsyncTCP/AsyncTCP.cpp.o
Compiling .pio/build/az-delivery-devkit-v4/lib829/SPI/SPI.cpp.o
Compiling .pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/Dhcp.cpp.o
Compiling .pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/Dns.cpp.o
Compiling .pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/Ethernet.cpp.o
Compiling .pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/EthernetClient.cpp.o
Compiling .pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/EthernetServer.cpp.o
Compiling .pio/build/az-delivery-devkit-v4/libaf7/custom-Ethernet/EthernetUdp.cpp.o
In file included from .pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/Dns.cpp:8:
.pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/utility/w5100.h:457: warning: "htons" redefined
 #define htons(x) ( (((x)<<8)&0xFF00) | (((x)>>8)&0xFF) )
 
In file included from /home/koenraad/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/lwip/src/include/lwip/ip_addr.h:41,
                 from /home/koenraad/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/lwip/src/include/lwip/netif.h:46,
                 from /home/koenraad/.platformio/packages/framework-arduinoespressif32/cores/esp32/IPAddress.h:25,
                 from /home/koenraad/.platformio/packages/framework-arduinoespressif32/cores/esp32/Arduino.h:180,
                 from .pio/libdeps/az-delivery-devkit-v4/custom-Ethernet/src/Dns.cpp:5:
/home/koenraad/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/lwip/src/include/lwip/def.h:119: note: this is the location of the previous definition
 #define htons(x) lwip_htons(x)
 
  >>> cropped to improve readability
 
===================================================================================== [FAILED] Took 6.05 seconds =====================================================================================

My understanding of "Async" is that the esp32 can do other things while waiting for the modbus to respond. I would like to display those responses on a website provided by the esp32, so I chose async.

Sorry, my bad - ModbusClientTCP it should have been.

Something must be different with your setup. For some reason the guarding defines to separate the wireless and Ethernet code in the lib seem to have no effect. Can you post your platformio.ini here?

Here it is :

; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:az-delivery-devkit-v4]
platform = espressif32
board = az-delivery-devkit-v4
framework = arduino
lib_deps = miq19/eModbus@^1.7.1

Looks okay...

Here is mine for comparison, that will compile without any issues:

# PlatformIO Project Configuration File

[env]
platform = espressif32
board = az-delivery-devkit-v4
framework = arduino
monitor_speed = 115200
monitor_dtr = 0
monitor_rts = 0
monitor_filters = esp32_exception_decoder
board_build.partitions = default.csv
lib_ldf_mode = deep+
lib_deps =
  AsyncTCP
  Ethernet=https://github.com/maxgerhardt/Ethernet.git

(I have no lib_deps entry for eModbus, as this comes from the main library workspace. In your case a single eModbus would be sufficient for the latest published version - no need to specify owner and version normally)

Next would be to check your sketch for anormalities. Can you post that as well?

My understanding of "Async" is that the esp32 can do other things while waiting for the modbus to respond. I would like to display those responses on a website provided by the esp32, so I chose async.

I missed that, sorry. The library is internally using different tasks on the ESP32, so your wish should be granted even without the AsyncTCP stuff. I see the async stuff mostly relevant for the ESP8266, that has no real multitasking.

Isn't your platformio.ini file missing the modbus-lib ?

Here is the "sketch" (copied from TCP03Example, just modified the wifi-info) :

// =================================================================================================
// eModbus: Copyright 2020 by Michael Harwerth, Bert Melis and the contributors to ModbusClient
//               MIT license - see license.md for details
// =================================================================================================

// Example code to show the usage of the eModbus library. 
// Please refer to root/Readme.md for a full description.

// Includes: <Arduino.h> for Serial etc., WiFi.h for WiFi support
#include <Arduino.h>
#include <WiFi.h>
#include <SPI.h>

// Include the header for the ModbusClient TCP style
#include "ModbusClientTCP.h"

WiFiClient theClient;                          // Set up a client
#ifndef MY_SSID
#define MY_SSID "<myssid>"
#endif
#ifndef MY_PASS
#define MY_PASS "<obfuscated>"
#endif

char ssid[] = MY_SSID;                     // SSID and ...
char pass[] = MY_PASS;                     // password for the WiFi network used

// Create a ModbusTCP client instance
ModbusClientTCP MB(theClient);

// Define an onData handler function to receive the regular responses
// Arguments are the message plus a user-supplied token to identify the causing request
void handleData(ModbusMessage response, uint32_t token) 
{
  Serial.printf("Response: serverID=%d, FC=%d, Token=%08X, length=%d:\n", response.getServerID(), response.getFunctionCode(), token, response.size());
  for (auto& byte : response) {
    Serial.printf("%02X ", byte);
  }
  Serial.println("");
}

// Define an onError handler function to receive error responses
// Arguments are the error code returned and a user-supplied token to identify the causing request
void handleError(Error error, uint32_t token) 
{
  // ModbusError wraps the error code and provides a readable error message for it
  ModbusError me(error);
  Serial.printf("Error response: %02X - %s\n", (int)me, (const char *)me);
}

// Setup() - initialization happens here
void setup() {
// Init Serial monitor
  Serial.begin(115200);
  while (!Serial) {}
  Serial.println("__ OK __");

// Connect to WiFi
  WiFi.begin(ssid, pass);
  delay(200);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(". ");
    delay(1000);
  }
  IPAddress wIP = WiFi.localIP();
  Serial.printf("WIFi IP address: %u.%u.%u.%u\n", wIP[0], wIP[1], wIP[2], wIP[3]);

// Set up ModbusTCP client.
// - provide onData handler function
  MB.onDataHandler(&handleData);
// - provide onError handler function
  MB.onErrorHandler(&handleError);
// Set message timeout to 2000ms and interval between requests to the same host to 200ms
  MB.setTimeout(2000, 200);
// Start ModbusTCP background task
  MB.begin();

// Issue a request
// Set Modbus TCP server address and port number
// (Fill in your data here!)
  MB.setTarget(IPAddress(172,31,0,17),502);

// Create request for
// (Fill in your data here!)
// - token to match the response with the request. We take the current millis() value for it.
// - server ID = 20
// - function code = 0x03 (read holding register)
// - start address to read = word 10
// - number of words to read = 4
//
// If something is missing or wrong with the call parameters, we will immediately get an error code 
// and the request will not be issued
  Error err = MB.addRequest((uint32_t)millis(), 20, READ_HOLD_REGISTER, 10, 4);
  if (err!=SUCCESS) {
    ModbusError e(err);
    Serial.printf("Error creating request: %02X - %s\n", (int)e, (const char *)e);
  }

// Else the request is processed in the background task and the onData/onError handler functions will get the result.
//
// The output on the Serial Monitor will be (depending on your WiFi and Modbus the data will be different):
//     __ OK __
//     . WIFi IP address: 192.168.178.74
//     Response: serverID=20, FC=3, Token=0000056C, length=11:
//     14 03 04 01 F6 FF FF FF 00 C0 A8
}

// loop() - nothing done here today!
void loop() {
}

Well, you did not modify the relevant code. So it really must be related to how you had set up your Platformio environment.

As I wrote above you will have to add a plain eModbus to the lib_deps. It is missing in my platformio.ini because the library code is the source proper in the workspace.

I did a run from scratch:

  • create new project
  • board and Arduino framework selected
  • added my monitor, memory and lib finder options and the lib_deps

That gave me this platformio.ini:

; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:az-delivery-devkit-v4]
platform = espressif32
board = az-delivery-devkit-v4
framework = arduino
lib_deps = 
  eModbus
monitor_speed = 115200
monitor_dtr = 0
monitor_rts = 0
monitor_filters = esp32_exception_decoder
board_build.partitions = default.csv
build_flags = -DLOG_LEVEL=3 -DMY_SSID=\"hidden_ssid\" -DMY_PASS=\"hidden_password\"
lib_ldf_mode = deep+
  • copied the TCP03example main.cpp into src
  • clicked on Compile

Ran like a charm...

@KLelong To keep you posted: Our release builds on Github are now failing with the same errors (without me knowing about the root cause). Looks like something has changed unnoticed in the environment.

I installed Visual Studio Code on a computer where it never was installed before.
Added platformio and compiled the test-application. Worked fine !
Then I tried to compile my own application and that also compiled fine.
I flashed the application and it runs fine. If it works, I don't know yet, I don't have access to the modbus-device at the moment.

I don't know what's different on my dev-machine.
FWIW, I think I'm also on core 6.6.0 (the file platform.json gives that version ).

I checked on my dev-pc.
I don't know what I am using there but now I checked with 5.3.0 and that seems to compile OK, as is 6.6.0.
That is with explicitly stating the version to use.
When I don't state a version, I'm having the old issues.
So this dos not compile :

[env]
platform = espressif32
framework = arduino

While this compiles :

[env]
platform = espressif32@5.3
framework = arduino

as does :

[env]
platform = espressif32@6
framework = arduino

So for some reason, the wrong core is chosen on my dev-pc.

Strange indeed. It seems to be related to the proprietary Ethernet lib by @maxgerhardt, though, that may have grown too old now for the recent cores. I managed to compile with the standard Ethernet library with two modifications:

  • in platformio.ini have a line lib_deps = Ethernet=https://github.com/arduino-libraries/Ethernet.git
  • In the then installed Ethernet lib, modify .pio/lib_deps/<your project>/Ethernet/src/Ethernet.h in line 254 to read class EthernetServer : public Print {

Update: forget about the second part, I created a wrapper class in the eModbus code that solves it as well without any modification necessary.

Found it. In PlatformIO you need to add lib_ldf_mode = deep+ to have it find the libraries. I had not done this yet on Github for the test builds, so that is why it worked in my local environment ionly.

I will roll a 1.7.2 release update in short that has all the relevant changes.

Closing this now as it seems to be resolved.