0

I have three libraries that I've written and I'm trying to use. They're stored as follows

Documents
├── Some/Path/To/Folder
│   └── firmware.ino
└── Arduino
    └── libraries
        ├── error
        │   ├── error.h
        │   └── error.cpp
        ├── lmp91000
        │   ├── lmp91000.h
        │   └── lmp91000.cpp
        └── tps7a7100
            ├── tps7a7100.h
            └── tps7a7100.cpp

Both lmp91000.h and tps7a7100.h have #include "../error/error.h" and are able to access variables and functions declared in error.h and error.cpp just fine.

firmware.ino includes all three libraries as you would expect them to be included and it is able to create instances of classes defined in both lmp91000 and tps7a7100 and use their methods (which depend on error). I am also able to create instances of a struct (ERROR) defined in error.h from firmware.ino, however I am not able to access functions from error.h and error.cpp. Error recived is

firmware.ino:19: undefined reference to `LOG_E(ERROR)'

However when I remove the guards in error.h that error no longer appears (implying that LOG_E can be resolved) but I get the expected errors of multiple definitions as there are multiple #include error.h.

My thoughts are that because of the guards error is not being included in a location where the sketch has access to the functions, but I may be completely off on that. I know there must be a way around this, as I'm able to access Wire.h for example from firmware.ino even though that is included in lmp91000.h - how do I solve this?

firmware.ino

#include <error.h>
#include <lmp91000.h>
#include <tps7a7100.h>
#include <Wire.h>

lmp91000 pot(12);
tpsa7100 vreg(10,9,8,7,6,5,4);

void setup() {
    Wire.begin();
    Serial.begin(115200);
    while(!Serial);
    vreg.enable();
    pot.enable();
    ERROR misc;
    misc.errorCode = 0x50;
    LOG_E(misc);
}

void loop() {
}

error.h

#ifndef error_h_included
#define error_h_included

#include "Arduino.h"


// Error Structure
typedef struct{
    int errorCode;
    char const *errorName;
    char const *errorDesc;
    bool isFatalError;
    bool shouldRetry;
}ERROR;

// Global error types
const ERROR E_SUCCESS = {0x00, "E_SUCCESS", "Success", false, false};
const ERROR E_INVALID_ARG = {0x10, "E_INVALID_ARG", "Invalid argument passed", true, false};
const ERROR E_I2C_NACK_ADDR = {0x20, "E_I2C_NACK_ADDR", "NACK on I2C address byte", false, true};
const ERROR E_I2C_NACK_DATA = {0x21, "E_I2C_NACK_DATA", "NACK on I2C data byte", false, true};
const ERROR E_I2C_BUFF_LEN = {0x22, "E_I2C_BUFF_LEN", "Transmit Data too long for I2C buffer", true, false};
const ERROR E_I2C_ERROR = {0x23, "E_I2C_ERROR", "Undefined I2C Error", true, false};
const ERROR E_I2C_TARGET_DISABLED = {0x24, "E_I2C_TARGET_DISABLED", "Target device for I2C comms disabled", false, false};
const ERROR E_I2C_READ_ERROR = {0x25, "E_I2C_READ_ERROR", "I2C Data could not be read", false, false};
const ERROR E_I2C_WRITE_ERROR = {0x26, "E_I2C_WRITE_ERROR", "Attempting to write zero bytes to I2C bus", false, false};

// Function Definitions
bool E(ERROR error_struct);
void LOG_E(ERROR error_struct);
ERROR WireErrorDecode(int code); 


#endif

error.cpp

#include "error.h"


// Error Handling Functions

// E(ERROR)
// Evaluate the successfullness of the error
// Return 0 if error is a success error
// Return >0 if error is not success error
bool E(ERROR error_struct) {
    return (int)(error_struct.errorCode & 0xF0);
}

// LOG(ERROR)
// Log the error 
void LOG_E(ERROR error_struct) {
    Serial.print(error_struct.errorCode);
    Serial.print("\t");
    Serial.print(error_struct.errorName);
    Serial.print("\t");
    Serial.println(error_struct.errorDesc);
}

// WireErrorDecode(code)
// Decode Wire.EndTransmission error codes
ERROR WireErrorDecode(int code) {
    switch(code) {
        case 0:
            return E_SUCCESS;
        case 1:
            return E_I2C_BUFF_LEN;
        case 2:
            return E_I2C_NACK_ADDR;
        case 3:
            return E_I2C_NACK_DATA;
        case 4:
            return E_I2C_ERROR;
        default:
            return E_INVALID_ARG;
    }
}

Update: These errors seem to be board specific - see question here

6
  • 1
    "... implying that LOG_E can be resolved". No, it does not imply anything like that. "Undefined reference" is a linker error. And without include guards you simply never get to the linking stage because of an avalanche of other errors. Commented May 11, 2019 at 17:12
  • check if guard defines are unique
    – Juraj
    Commented May 11, 2019 at 17:49
  • Did you add library.properties files to your libraries? At least test moving all the library files into the sketch folder. That might give some additional information about the build on this "unique" Arduino :) Commented May 14, 2019 at 17:14
  • @MikaelPatel moving the libaries into the sketch folder does allow it to compile without error. I don't unerstand why that would make a difference though, as they were originally in the libaries folder of the Arduino path. Additionally why would it only have an impact on the 101 and not on any other board as descirbed in the linked question Commented May 14, 2019 at 17:21
  • 1
    Next step is to turn on verbose mode when building in the Arduino IDE so that you get the actual compile and link command lines. Study the output and you will find your error. Commented May 14, 2019 at 18:57

1 Answer 1

1

The filename error.h is not a good name for a library. Some compilers and cores (such as the ESP32 and Curie cores) have a file error.h of their own which will be used in preference to yours.

Instead, name your library something more sensible.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.