Including libraries properly

Hi everyone,
I’m developing a sketch using the MKR ETH shield. I want to initialize the ethernet into a seperate file (not in sketch file)
For that reason I created the LAN.h and LAN.c files but something is going totally wrong with the way I am including the libraries. Initially I include the ethernet.h and SPI.h libraries in LAN.h but the program were not compiled. So after digging around I found that I must also include the ethernet and spi libraries in the sketch file. Then the sketch was started compiling..

The problem is when I try to include the LAN.h into the sketch file and the program does not compile… any suggestion?
This is the structure of my files:

This is the main.cpp file

#include <SPI.h>
#include <Ethernet.h>
#include <Arduino.h>
#include "config.h"
#include "../lib/Ethernet_lib/LAN.h"

byte mac[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; // MAC address for ethernet shield. This is a random address and you can change it
byte CS_PIN = 5;

void setup()
{

  Serial.begin(115200);
  delay(1000); // give some time for the serial monitor to open

  ethernet_init(CS_PIN);
  DHCP_config(mac);
}

void loop()
{

}

This is the LAN.h file

#ifndef LAN_H
#define LAN_H

#include <Arduino.h>
#include <SPI.h>
#include <Ethernet.h>

void ethernet_init(byte CS_PIN);
void DHCP_config(byte *MAC);
void hardware_present(void);
void connection_link(void);

#endif

This is the LAN.c file

#include "LAN.h"

// Configure the CS pin
void ethernet_init(byte CS_PIN)
{
    Ethernet.init(CS_PIN);
}

void DHCP_config(byte *MAC)
{
    bool dhcp = Ethernet.begin(mac); // Returns 0 if the DHCP configuration failed, and 1 if it succeeded

    if (!dhcp)
    {
        Serial.println("DHCP configuration failed");
    }
    else if (dhcp)
    {
        Serial.println("DHCP configuration succeed");
    }
}

Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware)
{
    Serial.println("Ethernet shield was not found. Connect ethernet shield");
    while (true)
    {
        delay(1); // do nothing, no point running without Ethernet hardware
    }
}
else
{
    Serial.print("Ethernet shield found: ");
    switch (Ethernet.hardwareStatus())
    {
    case 1:
        Serial.println("EthernetW5100");
        break;
    case 2:
        Serial.println("EthernetW5200");
        break;
    case 3:
        Serial.println("EthernetW5500");
        break;
    default:
        break;
    }
}

//Check if the ethernet cable is conencted
while (Ethernet.linkStatus() == LinkOFF)
{
    Serial.println("Ethernet cable is not connected.");
    delay(500);
}

// give the Ethernet shield a second to initialize:
delay(1000);
Serial.println("connecting...");

"the program does not compile" is a useless statement, sorry. Please post the error messagen

If you use the Arduino IDE, there are requirements for the structure; only .c an .cpp files in certain directories will be compiled.

I'm not behind a PC at the at the moment; one solution is to move the .h and .c file into the sketch directory.

Oh, and I suggest that you rename your .c to .cpp.

The problem is when I try to include the LAN.h into the sketch file and the program does not compile… any suggestion?

Please post the error messages

What happens if you put your library files in the sketch directory ?

Why not a .h and a .cpp file rather than .c ?

This is the main.cpp file

Do you mean it is the main .ino file ?

More details of the files and their locations please

the program does not compile… any suggestion?

Please include the entire error message. It is easy to do. There is a button (lower right of the IDE window) called "copy error message". Copy the error and paste into a post in code tags. Paraphrasing the error message leaves out important information.

Thank you for you answers,

sterretje:
Oh, and I suggest that you rename your .c to .cpp.

It seems that my problem solved as soon as renamed the LAN.c to LAN.cpp.
I know that arduino IDE accepts both c and c++ libraries but for the current project I use VScode and Platformio, so maybe this is the problem?

Nikosant03:
I know that arduino IDE accepts both c and c++ libraries but for the current project I use VScode and Platformio, so maybe this is the problem?

If you posted the error message that would likely be very easy for us to answer.

If I had to take a wild guess, with only a quick glance at your code, I'd say you could have also fixed the issue by wrapping your C function declarations in extern "C" {}, like so:

pert:
If you posted the error message that would likely be very easy for us to answer.

This is the error logging before renaming from .c to .cpp

In file included from lib\Ethernet_lib\LAN.h:5:0,
                 from lib\Ethernet_lib\LAN.c:1:
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\libraries\SPI/SPI.h:48:1: error: unknown type name 'class'
 class SPISettings {
 ^~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\libraries\SPI/SPI.h:48:19: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token  
 class SPISettings {
                   ^
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\libraries\SPI/SPI.h:112:7: error: unknown type name 'SPISettings'
 const SPISettings DEFAULT_SPI_SETTINGS = SPISettings();
       ^~~~~~~~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\libraries\SPI/SPI.h:112:42: warning: implicit declaration of function 'SPISettings' [-Wimplicit-function-declaration]
 const SPISettings DEFAULT_SPI_SETTINGS = SPISettings();

In file included from C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Print.h:26:0,
                 from C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Client.h:22,
Compiling .pio\build\mkrwifi1010\FrameworkArduino\Tone.cpp.o
                 from .pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:52,
                 from lib\Ethernet_lib\LAN.h:6,
Compiling .pio\build\mkrwifi1010\FrameworkArduino\USB\CDC.cpp.o
                 from lib\Ethernet_lib\LAN.c:1:
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Printable.h:24:1: error: unknown type name 'class'
Archiving .pio\build\mkrwifi1010\libFrameworkArduinoVariant.a
 class Print;
 ^~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Printable.h:32:1: error: unknown type name 'class'
 class Printable
 ^~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Printable.h:33:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
 {
Indexing .pio\build\mkrwifi1010\libFrameworkArduinoVariant.a
Compiling .pio\build\mkrwifi1010\FrameworkArduino\USB\PluggableUSB.cpp.o
 ^
In file included from C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Client.h:22:0,
                 from .pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:52,
Compiling .pio\build\mkrwifi1010\FrameworkArduino\USB\USBCore.cpp.o
Compiling .pio\build\mkrwifi1010\FrameworkArduino\USB\samd21_host.c.o
                 from lib\Ethernet_lib\LAN.h:6,
                 from lib\Ethernet_lib\LAN.c:1:
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Print.h:36:1: error: unknown type name 'class'
 class Print
Compiling .pio\build\mkrwifi1010\FrameworkArduino\Uart.cpp.o
 ^~~~~
Compiling .pio\build\mkrwifi1010\FrameworkArduino\WInterrupts.c.o
Compiling .pio\build\mkrwifi1010\FrameworkArduino\WMath.cpp.o
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Print.h:37:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
 {
 ^
In file included from C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Client.h:23:0,
                 from .pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:52,
                 from lib\Ethernet_lib\LAN.h:6,
Compiling .pio\build\mkrwifi1010\FrameworkArduino\WString.cpp.o
                 from lib\Ethernet_lib\LAN.c:1:
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Stream.h:49:1: error: unknown type name 'class'
 class Stream : public Print
Compiling .pio\build\mkrwifi1010\FrameworkArduino\abi.cpp.o
 ^~~~~

Compiling .pio\build\mkrwifi1010\FrameworkArduino\main.cpp.o
                             ^
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/IPAddress.h:76:31: error: expected declaration specifiers or '...' before numeric constant
 const IPAddress INADDR_NONE(0,0,0,0);
Compiling .pio\build\mkrwifi1010\FrameworkArduino\new.cpp.o

.pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:72:1: error: unknown type name 'class'
 class DhcpClass;
 ^~~~~
.pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:74:1: error: unknown type name 'class'
 class EthernetClass {
 ^~~~~
.pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:74:21: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
 class EthernetClass {
                     ^
.pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:147:8: error: unknown type name 'EthernetClass'
 extern EthernetClass Ethernet;
        ^~~~~~~~~~~~~
.pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:152:1: error: unknown type name 'class'
 class EthernetUDP : public UDP {
 ^~~~~
.pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:152:19: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token
 class EthernetUDP : public UDP {
                   ^
In file included from lib\Ethernet_lib\LAN.h:6:0,
                 from lib\Ethernet_lib\LAN.c:1:
.pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:214:1: error: unknown type name 'class'
 class EthernetClient : public Client {
 ^~~~~
                    ^
In file included from C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/delay.h:23:0,
                 from C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Arduino.h:81,
                 from lib\Ethernet_lib\LAN.h:4,
                 from lib\Ethernet_lib\LAN.c:1:
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\variants\mkrwifi1010/variant.h:222:37: error: 'SerialUSB' undeclared (first use in this function); did you mean 'Serial'?
 #define Serial                      SerialUSB
                                     ^
lib\Ethernet_lib\LAN.c:59:9: note: in expansion of macro 'Serial'
         Serial.println("Ethernet cable is not connected.");
         ^~~~~~
*** [.pio\build\mkrwifi1010\libe6c\Ethernet_lib\LAN.c.o] Error 1

After renaming the file from .c to .cpp, two separate errors popped up

Building in release mode
Compiling .pio\build\mkrwifi1010\src\main.cpp.o
Linking .pio\build\mkrwifi1010\firmware.elf
.pio\build\mkrwifi1010\src\main.cpp.o: In function `setup':
main.cpp:(.text.setup+0x18): undefined reference to `ethernet_init(unsigned char)'
main.cpp:(.text.setup+0x1e): undefined reference to `DHCP_config(unsigned char*)'
main.cpp:(.text.setup+0x22): undefined reference to `hardware_present()'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\mkrwifi1010\firmware.elf] Error 1
Building in release mode
Compiling .pio\build\mkrwifi1010\libe6c\Ethernet_lib\LAN.cpp.o
Archiving .pio\build\mkrwifi1010\libe6c\libEthernet_lib.a
arm-none-eabi-ar: unable to rename '.pio\build\mkrwifi1010\libe6c\libEthernet_lib.a'; reason: File exists
*** [.pio\build\mkrwifi1010\libe6c\libEthernet_lib.a] Error 1

I solved these error by removing the project folder from the workspace and adding it back again… This is something like a bug or what? As I said I am using platformio and VScode, so I don't know if it was going to compile smoothly on Arduino IDE.

This error was about trying to use C++ in C, so not something that can be fixed easily like the thing I mentioned in my last reply that allows using C in C++.

C doesn't have classes, but the "SPI" library and most Arduino libraries do use classes, so can't be used in C code.

Perhaps an issue with caching.

The Arduino IDE has some issues like this in rare circumstances, so it's possible you might have some thing similar in the Arduino IDE (though in the case of the IDE it would be cleared by restarting the IDE or compiling for a different board, rather than the workspace fix you found).

1 Like

Thank you pert!!

I tried to use extern "C" just for validation but it doesn't compile.. Do I have any syntax error when using extern "C"?

#ifndef LAN_H
#define LAN_H

#include <Arduino.h>
#include <SPI.h>
#include <Ethernet.h>

#ifdef __cplusplus
extern "C" {
#endif

/** @file
 */

/** @brief                Funtion for configuring the CS (Chip Slelect) pin 
 *  @param[in]  CS_PIN    For ethernet usage CS_PIN = 5, for SD card usage CS_PIN = 4
 */
void ethernet_init(byte CS_PIN);

/** @brief                Funtion for configuring through DHCP server using the provided MAC address 
 *  @param[in]  mac       Pointer to the MAC address 
 */
void DHCP_config(uint8_t *mac);

/** @brief                Funtion for checking if ethernet shield is present 
 */
void hardware_present(void);

/** @brief                Funtion for checking if ethernet cable is connected
 */
void connection_link(void);

#ifdef __cplusplus
}
#endif

#endif

/**
 *@}
 */

Error logging

Compiling .pio\build\mkrwifi1010\FrameworkArduino\Reset.cpp.o
*** [.pio\build\mkrwifi1010\lib2d5\libSPI.a] Error 1
In file included from lib\Ethernet_lib\LAN.h:5:0,
                 from lib\Ethernet_lib\LAN.c:1:
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\libraries\SPI/SPI.h:48:1: error: unknown type name 'class'
 class SPISettings {
 ^~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\libraries\SPI/SPI.h:48:19: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token  
 class SPISettings {
                   ^
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\libraries\SPI/SPI.h:112:7: error: unknown type name 'SPISettings'
 const SPISettings DEFAULT_SPI_SETTINGS = SPISettings();
       ^~~~~~~~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\libraries\SPI/SPI.h:112:42: warning: implicit declaration of function 'SPISettings' [-Wimplicit-function-declaration]
 const SPISettings DEFAULT_SPI_SETTINGS = SPISettings();
                                          ^~~~~~~~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\libraries\SPI/SPI.h:112:42: error: initializer element is not constant
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\libraries\SPI/SPI.h:114:1: error: unknown type name 'class'
 class SPIClass {
 ^~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\libraries\SPI/SPI.h:114:16: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
 class SPIClass {
                ^
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\libraries\SPI/SPI.h:160:10: error: unknown type name 'SPIClass'
   extern SPIClass SPI;
          ^~~~~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\libraries\SPI/SPI.h:163:10: error: unknown type name 'SPIClass'
   extern SPIClass SPI1;
          ^~~~~~~~
In file included from C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Print.h:26:0,
                 from C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Client.h:22,
                 from .pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:52,
                 from lib\Ethernet_lib\LAN.h:6,
                 from lib\Ethernet_lib\LAN.c:1:
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Printable.h:24:1: error: unknown type name 'class'
 class Print;
 ^~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Printable.h:32:1: error: unknown type name 'class'
 class Printable
 ^~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Printable.h:33:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
 {
 ^
In file included from C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Client.h:22:0,
                 from .pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:52,
                 from lib\Ethernet_lib\LAN.h:6,
                 from lib\Ethernet_lib\LAN.c:1:
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Print.h:36:1: error: unknown type name 'class'
 class Print
 ^~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Print.h:37:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
 {
 ^
In file included from C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Client.h:23:0,
                 from .pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:52,
                 from lib\Ethernet_lib\LAN.h:6,
                 from lib\Ethernet_lib\LAN.c:1:
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Stream.h:49:1: error: unknown type name 'class'
 class Stream : public Print
 ^~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Stream.h:49:14: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token
 class Stream : public Print
              ^
In file included from C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/Client.h:24:0,
                 from .pio\libdeps\mkrwifi1010\Ethernet\src/Ethernet.h:52,
                 from lib\Ethernet_lib\LAN.h:6,
                 from lib\Ethernet_lib\LAN.c:1:
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/IPAddress.h:29:1: error: unknown type name 'class'
 class IPAddress : public Printable {
 ^~~~~
C:\Users\n.antoniou\.platformio\packages\framework-arduino-samd\cores\arduino/IPAddress.h:29:17: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token
 class IPAddress : public Printable {
                 ^
lib\Ethernet_lib\LAN.c:59:9: note: in expansion of macro 'Serial'
         Serial.println("Ethernet cable is not connected.");
         ^~~~~~
*** [.pio\build\mkrwifi1010\libe6c\Ethernet_lib\LAN.c.o] Error 1

It's the same problem. extern "C" {} allows you to use functions defined in .c files in .cpp or .ino (.ino files are compiled as C++ after some minor preprocessing). But the cause of these error is that you're trying to use the SPI, etc. library header files which use a C++-specific feature, classes, in a C file, which has no support for classes. As far as I know, there is no workaround for this. You simply can't use classes in C.

There are some parts of the Arduino core library and other libraries that are compatible with C. You can see an example of how this is handled in the Arduino SAMD Boards platform's Arduino.h (and I'm guessing the PlatformIO SAMD boards platform uses something at least similar, if not identical):

#ifdef __cplusplus
extern "C"{
#endif // __cplusplus

// Include Atmel headers
#include "sam.h"

#include "wiring_constants.h"

#define clockCyclesPerMicrosecond() ( SystemCoreClock / 1000000L )
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (SystemCoreClock / 1000L) )
#define microsecondsToClockCycles(a) ( (a) * (SystemCoreClock / 1000000L) )

void yield( void ) ;

/* system functions */
int main( void );
void init( void );

/* sketch */
void setup( void ) ;
void loop( void ) ;

#include "WVariant.h"

#ifdef __cplusplus
} // extern "C"
#endif

// The following headers are for C++ only compilation
#ifdef __cplusplus
  #include "WCharacter.h"
  #include "WString.h"
  #include "Tone.h"
  #include "WMath.h"
  #include "HardwareSerial.h"
  #include "pulse.h"
#endif
#include "delay.h"
#ifdef __cplusplus
  #include "Uart.h"
#endif

So you can use a significant amount of the Arduino core API in C, but not all.

But most of the Arduino libraries are C++, so if you chose to write Arduino code in C you'll need to resign yourself to doing without them.

Thank you so much Pert!!