Trouble linking structures from C file in Arduino sketchbook

I am having trouble referencing a structure written in a separate C file in my Arduino sketchbook.

In my main INO, I have:

#include "Sensor.hh"
#include <Wire.h>

extern const Sensor_Handle Sensor_0;

void setup()
{
  Wire.begin();
  Sensor_config(Sensor_0);
  Serial.begin(9600);
}

And I have the following error:
undefined reference to Sensor_0

Is the only solution to write the entire structure inside the main INO file?

the double h isn't helping you. (unless you have some odd reason for that?)

if I define a structure in a header file, I need only create a normal instance of it in my main file. I certainly could be wrong, but I dont think extern is needed here.

can you post sensor.h so we can see what you're working with?

Welcome to the forum

Please post the contents of Sensor.hh
Why does it have an extension of hh rather than the more normal (at least to me) single h

Is there a const Sensor_Handle Sensor_0; line in the "external C file" that you haven't shown us?

It MIGHT need to be something like extern "C" const Sensor_Handle Sensor_0; (but I thought that was mainly for functions in C code.)

I realized two issues from your responses:

  1. These are actually C++ files, apologies about the error in my thread title.

  2. Still, I somehow incorrectly used .hh for my header files. I've corrected all the include statements to be .hpp and changed the file names to .hpp

Even after those fixes, I still have the same error about the unidentified reference.

Also, I can't attach file directly because I'm a new user, so here's the whole of Sensor.hpp inline (this is code I borrowed from the manufacturer's website, to be fair I'm not sure they anticipated folks attempting to get it to work in the Arduino MCU/IDE):

/*
 *  ======== Sensor.hpp ========
 *  Sensor Interface
 */
#ifndef sensors_Sensor__include
#define sensors_Sensor__include 1

#include <stdint.h>

/* support C++ sources */
#ifdef __cplusplus
extern "C" {
#endif

#define Sensor_config_register 0x00U
#define Sensor_config_register_rst_NormalOperation 0x0000U
#define Sensor_config_register_rst_SystemReset 0x8000U
#define Sensor_config_register_zoom_8194mV 0x0000U
#define Sensor_config_register_zoom_2048mV 0x1000U
#define Sensor_config_register_avg_1 0x0000U
#define Sensor_config_register_avg_4 0x0200U
#define Sensor_config_register_avg_16 0x0400U
#define Sensor_config_register_avg_64 0x0600U
#define Sensor_config_register_avg_128 0x0800U
#define Sensor_config_register_avg_256 0x0A00U
#define Sensor_config_register_avg_512 0x0C00U
#define Sensor_config_register_avg_1024 0x0E00U
#define Sensor_config_register_vbusct_140us 0x0000U
#define Sensor_config_register_vbusct_204us 0x0040U
#define Sensor_config_register_vbusct_332us 0x0080U
#define Sensor_config_register_vbusct_588us 0x00C0U
#define Sensor_config_register_vbusct_1100us 0x0100U
#define Sensor_config_register_vbusct_2116us 0x0140U
#define Sensor_config_register_vbusct_4156us 0x0180U
#define Sensor_config_register_vbusct_8244us 0x01C0U
#define Sensor_config_register_vshct_140us 0x0000U
#define Sensor_config_register_vshct_204us 0x0008U
#define Sensor_config_register_vshct_332us 0x0010U
#define Sensor_config_register_vshct_588us 0x0018U
#define Sensor_config_register_vshct_1100us 0x0020U
#define Sensor_config_register_vshct_2116us 0x0028U
#define Sensor_config_register_vshct_4156us 0x0030U
#define Sensor_config_register_vshct_8244us 0x0038U
#define Sensor_config_register_mode_Shutdown 0x0000U
#define Sensor_config_register_mode_Shuntvoltagetriggeredsingleshot 0x0001U
#define Sensor_config_register_mode_Busvoltagetriggeredsingleshot 0x0002U
#define Sensor_config_register_mode_Shuntvoltageandbusvoltagetriggeredsingleshot 0x0003U
#define Sensor_config_register_mode_Shutdown2 0x0004U
#define Sensor_config_register_mode_Continuousshuntvoltage 0x0005U
#define Sensor_config_register_mode_Continuousbusvoltage 0x0006U
#define Sensor_config_register_mode_Continuousshuntandbusvoltage 0x0007U
#define Sensor_calibration_register 0x05U
#define Sensor_calibration_register_reserved0_ENABLE 0x8000U
#define Sensor_calibration_register_reserved0_DISABLE 0x0000U
#define Sensor_alert_limit_register 0x07U
#define Sensor_vshunt_register 0x01U
#define Sensor_vbus_register 0x02U
#define Sensor_vbus_register_reserved0_ENABLE 0x8000U
#define Sensor_vbus_register_reserved0_DISABLE 0x0000U
#define Sensor_power_register 0x03U
#define Sensor_current_register 0x04U
#define Sensor_flags_alert_register 0x06U
#define Sensor_flags_alert_register_sol_DisableVshuntovervoltageonALERTpin 0x0000U
#define Sensor_flags_alert_register_sol_EnableVshuntovervoltageonALERTpin 0x8000U
#define Sensor_flags_alert_register_sul_DisableVshuntundervoltageonALERTpin 0x0000U
#define Sensor_flags_alert_register_sul_EnableVshuntunderrvoltageonALERTpin 0x4000U
#define Sensor_flags_alert_register_bol_DisableVbusovervoltageonALERTpin 0x0000U
#define Sensor_flags_alert_register_bol_EnableVbusovervoltageonALERTpin 0x2000U
#define Sensor_flags_alert_register_bul_DisableVbusunderrvoltageonALERTpin 0x0000U
#define Sensor_flags_alert_register_bul_EnableVbusundervoltageonALERTpin 0x1000U
#define Sensor_flags_alert_register_pol_DisablePowerovervoltageonALERTpin 0x0000U
#define Sensor_flags_alert_register_pol_EnablePowerovervoltageonALERTpin 0x0800U
#define Sensor_flags_alert_register_cnvr_DisableConversionReadyonALERTpin 0x0000U
#define Sensor_flags_alert_register_cnvr_EnableConversionReadyALERTpin 0x0400U
#define Sensor_flags_alert_register_memerror_ENABLE 0x0020U
#define Sensor_flags_alert_register_memerror_DISABLE 0x0000U
#define Sensor_flags_alert_register_aff_ENABLE 0x0010U
#define Sensor_flags_alert_register_aff_DISABLE 0x0000U
#define Sensor_flags_alert_register_cvrf_ENABLE 0x0008U
#define Sensor_flags_alert_register_cvrf_DISABLE 0x0000U
#define Sensor_flags_alert_register_ovf_ENABLE 0x0004U
#define Sensor_flags_alert_register_ovf_DISABLE 0x0000U
#define Sensor_flags_alert_register_apol_activelowopendrain 0x0000U
#define Sensor_flags_alert_register_apol_activehigh 0x0002U
#define Sensor_flags_alert_register_len_Transparent 0x0000U
#define Sensor_flags_alert_register_len_Latched 0x0001U
#define Sensor_manufacture_id_register 0x3EU
#define Sensor_device_id_register 0x3FU


/*
 *  ======== Sensor_State ========
 *  Initial configuration state for the sensor
 */
typedef struct Sensor_State {
    uint16_t config; //config_register
    uint16_t calibration; //shunt_cal_register
    uint16_t alert_limit; //alert_limit_register

    uint16_t adcrange; //config_register_adcrange
    float currentlsb; //current lsb value

    uint8_t busId;   /* I2C bus id */
    uint8_t devAddr; /* Sensor's I2C address on the bus */

    uint16_t osWait; /* One shot conversion time (in ms)  */
} Sensor_State;

/*
 *  ======== Sensor_Handle ========
 *  First argument to all Sensor methods
 */
typedef Sensor_State *Sensor_Handle;

/*
 *  ======== Sensor_writeReg ========
  * Write register
  */
extern void Sensor_writeReg(Sensor_Handle sensor, uint8_t regAddr, uint16_t value);

/*
 *  ======== Sensor_config ========
 *  Configure device with current settings
 */
extern void Sensor_config(Sensor_Handle sensor);

/*
 *  ======== Sensor_setCURRENT_LSB ========
 *  Set the CURRENT_LSB value used for calculations
 */
extern void Sensor_setCURRENT_LSB(Sensor_Handle sensor, float CURRENT_LSB);

/*
 *  ======== Sensor_readReg ========
 *  Read register
 */
extern uint64_t Sensor_readReg(Sensor_Handle sensor, uint8_t regAddr);

/*
 *  ======== Sensor_getVSHUNT_mV ========
 *  Get VSHUNT value (mV)
 */
extern float Sensor_getVSHUNT_mV(Sensor_Handle sensor);

/*
 *  ======== Sensor_getVBUS_V ========
 *  Get VBUS value (V)
 */
extern float Sensor_getVBUS_V(Sensor_Handle sensor);

/*
 *  ======== Sensor_getCURRENT_signedLSB ========
 *  Get CURRENT value (signed value in LSBs)
 */
extern float Sensor_getCURRENT_signedLSB(Sensor_Handle sensor);

/*
 *  ======== Sensor_getCURRENT_A ========
 *  Get CURRENT value (A)
 */
extern float Sensor_getCURRENT_A(Sensor_Handle sensor);

/*
 *  ======== Sensor_getPOWER_signedLSB ========
 *  Get POWER value (signed value in LSBs)
 */
extern float Sensor_getPOWER_signedLSB(Sensor_Handle sensor);

/*
 *  ======== Sensor_getPOWER_W ========
 *  Get POWER value (W)
 */
extern float Sensor_getPOWER_W(Sensor_Handle sensor);

/* support C++ sources */
#ifdef __cplusplus
}
#endif

#endif

It is much more convenient if you post the code here in code tags rather than attaching it

To post images etc you need trust level 1, you can get there by:

  • Entering at least 5 topics
  • Reading at least 30 posts
  • Spend a total of 10 minutes reading posts

Users at trust level 1 can…

  • Use all core Discourse functions; all new user restrictions are removed
  • Send PMs
  • Upload images and attachments

@internet_user1a, when you do post a complete set of files, make it an MRE. This is the smallest possible code that reproduces the problem. We don't need to see a bunch of files with messy, mostly irrelevant code.

There is really no magic associated with creating your on C/C++ headers with C/C++ code/structs:

image

Below are a few lines from each tab. Notice that the TAB functions.h has the extern "C" declaration.

First TAB:

/* by Ray Burnette 20161013 compiled on Linux 17.3 using Arduino 1.8.2
    Sketch uses 227213 bytes (21%) of program storage space. Maximum is 1044464 bytes.
    Global variables use 45132 bytes (55%) of dynamic memory, leaving 36788 bytes for local variables. Maximum is 81920 bytes.

*/

#include <ESP8266WiFi.h>
//#include <WiFi.h>
#include "./functions.h"

Second TAB:

// Notes.h tab in Arduino IDE is only for comments and references!

// based on RandDruid/esp8266-deauth (MIT) https://github.com/RandDruid/esp8266-deauth
// inspired by kripthor/WiFiBeaconJam (no license) https://github.com/kripthor/WiFiBeaconJam
// https://git.schneefux.xyz/schneefux/jimmiejammer/src/master/jimmiejammer.ino
// requires SDK v1.3: install esp8266/Arduino from git and checkout commit 1c5751460b7988041fdc80e0f28a31464cdf97a3
// Modified by M. Ray Burnette for publication as WiFi Sniffer 20161013

Third TAB:

// This-->tab == "functions.h"

// Expose Espressif SDK functionality
extern "C" {
#include "user_interface.h"
  typedef void (*freedom_outside_cb_t)(uint8 status);
  int  wifi_register_send_pkt_freedom_cb(freedom_outside_cb_t cb);
  void wifi_unregister_send_pkt_freedom_cb(void);
  int  wifi_send_pkt_freedom(uint8 *buf, int len, bool sys_seq);
}

#include <ESP8266WiFi.h>
#include "./structures.h"

Fourth TAB:

// This-->tab == "structures.h"

#define ETH_MAC_LEN 6

uint8_t broadcast1[3] = { 0x01, 0x00, 0x5e };
uint8_t broadcast2[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
uint8_t broadcast3[3] = { 0x33, 0x33, 0x00 };

struct beaconinfo
{
  uint8_t bssid[ETH_MAC_LEN];
  uint8_t ssid[33];
  int ssid_len;
  int channel;
  int err;
  signed rssi;
  uint8_t capa[2];
};

I have compiled under Windows 11 since it has been years ... seems to still be OK:

Creating BIN file "C:\Users\Ray\AppData\Local\Temp\arduino_build_113126/Sniffing6.ino.bin" using "C:\Users\Ray\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2/bootloaders/eboot/eboot.elf" and "C:\Users\Ray\AppData\Local\Temp\arduino_build_113126/Sniffing6.ino.elf"
"C:\\Users\\Ray\\AppData\\Local\\Arduino15\\packages\\esp8266\\tools\\python3\\3.7.2-post1/python3" -I "C:\\Users\\Ray\\AppData\\Local\\Arduino15\\packages\\esp8266\\hardware\\esp8266\\3.0.2/tools/signing.py" --mode sign --privatekey "C:\\Users\\Ray\\Documents\\Arduino\\Mickey_Sketches\\ESP8266\\Sniffing\\Sniffing6/private.key" --bin "C:\\Users\\Ray\\AppData\\Local\\Temp\\arduino_build_113126/Sniffing6.ino.bin" --out "C:\\Users\\Ray\\AppData\\Local\\Temp\\arduino_build_113126/Sniffing6.ino.bin.signed" --legacy "C:\\Users\\Ray\\AppData\\Local\\Temp\\arduino_build_113126/Sniffing6.ino.bin.legacy_sig"
"C:\\Users\\Ray\\AppData\\Local\\Arduino15\\packages\\esp8266\\tools\\python3\\3.7.2-post1/python3" -I "C:\\Users\\Ray\\AppData\\Local\\Arduino15\\packages\\esp8266\\hardware\\esp8266\\3.0.2/tools/sizes.py" --elf "C:\\Users\\Ray\\AppData\\Local\\Temp\\arduino_build_113126/Sniffing6.ino.elf" --path "C:\\Users\\Ray\\AppData\\Local\\Arduino15\\packages\\esp8266\\tools\\xtensa-lx106-elf-gcc\\3.0.4-gcc10.3-1757bed/bin" --mmu "-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000"
Executable segment sizes:
ICACHE : 32768           - flash instruction cache 
IROM   : 238128          - code in flash         (default or ICACHE_FLASH_ATTR) 
IRAM   : 26729   / 32768 - code in IRAM          (IRAM_ATTR, ISRs...) 
DATA   : 1512  )         - initialized variables (global, static) in RAM/HEAP 
RODATA : 1072  ) / 81920 - constants             (global, static) in RAM/HEAP 
BSS    : 38816 )         - zeroed variables      (global, static) in RAM/HEAP 
Using library ESP8266WiFi at version 1.0 in folder: C:\Users\Ray\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\ESP8266WiFi 
"C:\\Users\\Ray\\AppData\\Local\\Arduino15\\packages\\esp8266\\tools\\xtensa-lx106-elf-gcc\\3.0.4-gcc10.3-1757bed/bin/xtensa-lx106-elf-size" -A "C:\\Users\\Ray\\AppData\\Local\\Temp\\arduino_build_113126/Sniffing6.ino.elf"
Sketch uses 267441 bytes (27%) of program storage space. Maximum is 958448 bytes.
Global variables use 41400 bytes (50%) of dynamic memory, leaving 40520 bytes for local variables. Maximum is 81920 bytes.

Attached for anyone interested (please, no support questions!)
functions.h (4.1 KB)
Notes.h (5.5 KB)
Sniffing6.ino (1.9 KB)
structures.h (4.1 KB)

Hello All,

I have simplified my example and included all files from my Arduino sketchbook below.

All files seem to be included in the sketch, it's just the struct itself that doesn't work. I've hardcoded the address instead of using the structure and everything worked fine, but when using the structure I'm still getting "undefined reference to `Sensor_0'" in main.

I removed the "extern" before const, and the error went away, but it still didn't recognize the structure data.

main.ino

/*
 *  ======== main.c ========
 *  Simple example that uses the Sensors APIs
 */
#include "Sensor.hpp"
#include <Wire.h>

extern const Sensor_Handle Sensor_0;

void setup()
{
  Wire.begin();
  Sensor_config(Sensor_0);
  Serial.begin(9600);
}

void loop()
{
    uint16_t result_hex1;
    result_hex1 = Sensor_readReg(Sensor_0, 0x3E);
    Serial.print(result_hex1);
    Serial.print("\n");
    delay(1000);
}

Sensor.cpp

#include <stddef.h>
#include <stdint.h>

#include "Sensor.hpp"
#include "mcu.hpp"

static Sensor_State Sensor_0_state = {

    .busId = 0,
    .devAddr = 0x43,

};
const Sensor_Handle Sensor_0 = &Sensor_0_state;

#define MSB(u16) (((u16) & 0xFF00U) >> 8)
#define LSB(u16) ((u16) & 0xFFU)

/*
 *  ======== Sensor_writeReg ========
 * Write register
 */
void Sensor_writeReg(Sensor_Handle sensor, uint8_t regAddr, uint16_t value)
{
    uint8_t txBuf[3] = {0}; //All writable registers are 2 bytes

    txBuf[0] = regAddr;
    txBuf[1] = MSB(value);
    txBuf[2] = LSB(value);
    mcu_i2cTransfer(sensor->busId, sensor->devAddr, txBuf, 3, NULL, 0);

}

/*
 *  ======== Sensor_Sensor ========
 * Sensorure device with current settings.
 */
void Sensor_config(Sensor_Handle sensor)
{
    //Initialize the bus containing this sensor
    mcu_i2cInit(sensor->busId);
}

/*
 *  ======== Sensor_readReg ========
 *  Read register
 */
uint64_t Sensor_readReg(Sensor_Handle sensor, uint8_t regAddr)
{
    uint64_t value;
    int i;
    
    uint8_t txBuf[1] = {0};
    uint8_t rxBuf[2] = {0}; //max buffer size

    txBuf[0] = regAddr;

    //Read register
    mcu_i2cTransfer(sensor->busId, sensor->devAddr, txBuf, 1, rxBuf, 2);

    //Combine bytes
    value = (rxBuf[0] << 8) | rxBuf[1];

    return value;
}

Sensor.hpp

/*
 *  ======== Sensor.h ========
 *  Sensor Interface
 */
#ifndef sensors_Sensor__include
#define sensors_Sensor__include 1

#include <stdint.h>

/* support C++ sources */
#ifdef __cplusplus
extern "C" {
#endif

/*
 *  ======== Sensor_State ========
 *  Initial configuration state for a Sensor sensor
 */
typedef struct Sensor_State {
  
    uint8_t busId;   /* I2C bus id */
    uint8_t devAddr; /* Sensor's I2C address on the bus */

} Sensor_State;

/*
 *  ======== Sensor_Handle ========
 *  First argument to all Sensor methods
 */
typedef Sensor_State *Sensor_Handle;

/*
 *  ======== Sensor_writeReg ========
  * Write register
  */
extern void Sensor_writeReg(Sensor_Handle sensor, uint8_t regAddr, uint16_t value);

/*
 *  ======== Sensor_config ========
 *  Configure device with current settings
 */
extern void Sensor_config(Sensor_Handle sensor);

/*
 *  ======== Sensor_readReg ========
 *  Read register
 */
extern uint64_t Sensor_readReg(Sensor_Handle sensor, uint8_t regAddr);

/* support C++ sources */
#ifdef __cplusplus
}
#endif

#endif

mcu.cpp

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

#include "mcu.hpp"
#include <Wire.h>

void mcu_i2cInit(uint8_t busId)
{
    Wire.begin();
}

int8_t mcu_i2cTransfer( uint8_t busId, uint8_t i2cAddr,
                        uint8_t *dataToWrite, uint8_t writeLength,
                        uint8_t *dataToRead,  uint8_t readLength)
{
    if(writeLength > 0)
    {
        Wire.beginTransmission(i2cAddr); 
        Wire.write(dataToWrite, writeLength);        // sends five bytes
        Wire.endTransmission();    // stop transmitting
    }

    if(readLength > 0)
    {
        Wire.requestFrom(i2cAddr, readLength);    // request 6 bytes from slave device #8
        
        while (Wire.available()) // slave may send less than requested
        { 
          dataToRead = Wire.read(); // receive a byte as character
        }
    }    
    return (0);
}

mcu.hpp

/*
 *  ======== mcu.h ========
 *  MCU hardware abstraction used sensor API implementations
 */
#ifndef sensors_MCU__include
#define sensors_MCU__include 1

#include <stdint.h>

/* support C++ sources */
#ifdef __cplusplus
extern "C" {
#endif

/*
 *  ======== mcu_i2cInit ========
 *  Initialize the specified I2C bus for first use
 */
extern void mcu_i2cInit(uint8_t busId);

/*
 *  ======== mcu_i2cTransfer ========
 *  Transfer data to and from an I2C slave
 */
extern int8_t mcu_i2cTransfer(uint8_t busId, uint8_t sensorAddress,
                              uint8_t *dataToWrite, uint8_t writeLength,
                              uint8_t *dataToRead,  uint8_t readLength);

/* support C++ sources */
#ifdef __cplusplus
}
#endif
#endif /* sensors_MCU__include */

Before I start looking at your code, answer me this ... why do you insist on compiling any of this as 'C'? Why not compile it as 'C++'? Your life will be much easier.

I don't think they did. The comments in the file says "main.c", but the message text says it's "main.ino" (which should be c++)

Seems to be something to do with "const." Remove "const" from the declarations of Sensor_0 in sensor.cpp and main.ino, and the undefined references go away.

I'm not sure why. The way I read C++ docs, "extern" should fix that:

A global constant definition, on the other hand, has internal linkage by default, but can be given external linkage by applying the extern qualifier. Such a constant definition must contain an initializer, since a constant cannot be given a value after it has been defined. If you want that constant to be visible in another file, the constant must appear in an extern const declaration in that other file.

Then the title of this thread seems rather misleading. And there's certainly no need for all the 'extern "C" {' nonsense.

OK, here it is, cleaned up and corrected for compilation as C++:
Main .ino

/*
    ======== main.c ========
    Simple example that uses the Sensors APIs
*/
#include "Sensor.hpp"
#include <Wire.h>

void setup()
{
  Wire.begin();
  Sensor_config(Sensor_0);
  Serial.begin(9600);
}

void loop()
{
  uint16_t result_hex1;
  result_hex1 = Sensor_readReg(Sensor_0, 0x3E);
  Serial.print(result_hex1);
  Serial.print("\n");
  delay(1000);
}

Sensor.hpp

/*
    ======== Sensor.h ========
    Sensor Interface
*/
#ifndef sensors_Sensor__include
#define sensors_Sensor__include

#include <Arduino.h>

/*
    ======== Sensor_State ========
    Initial configuration state for a Sensor sensor
*/
typedef struct Sensor_State {

  uint8_t busId;   /* I2C bus id */
  uint8_t devAddr; /* Sensor's I2C address on the bus */

} Sensor_State;

/*
    ======== Sensor_Handle ========
    First argument to all Sensor methods
*/
typedef Sensor_State *Sensor_Handle;

/*
    ======== Sensor_writeReg ========
    Write register
*/
void Sensor_writeReg(Sensor_Handle sensor, uint8_t regAddr, uint16_t value);

/*
    ======== Sensor_config ========
    Configure device with current settings
*/
void Sensor_config(Sensor_Handle sensor);

/*
    ======== Sensor_readReg ========
    Read register
*/
uint64_t Sensor_readReg(Sensor_Handle sensor, uint8_t regAddr);

extern const Sensor_Handle Sensor_0;

#endif

Mcu.hpp

/*
    ======== mcu.h ========
    MCU hardware abstraction used sensor API implementations
*/
#ifndef sensors_MCU__include
#define sensors_MCU__include

#include <Arduino.h>

/*
    ======== mcu_i2cInit ========
    Initialize the specified I2C bus for first use
*/
void mcu_i2cInit(uint8_t busId);

/*
    ======== mcu_i2cTransfer ========
    Transfer data to and from an I2C slave
*/
int8_t mcu_i2cTransfer(uint8_t busId, uint8_t sensorAddress,
                       uint8_t *dataToWrite, uint8_t writeLength,
                       uint8_t *dataToRead,  uint8_t readLength);

#endif /* sensors_MCU__include */

Sensor.cpp

#include "Sensor.hpp"
#include "Mcu.hpp"

static Sensor_State Sensor_0_state = {

  .busId = 0,
  .devAddr = 0x43,

};
const Sensor_Handle Sensor_0 = &Sensor_0_state;

#define MSB(u16) (((u16) & 0xFF00U) >> 8)
#define LSB(u16) ((u16) & 0xFFU)

/*
    ======== Sensor_writeReg ========
   Write register
*/
void Sensor_writeReg(Sensor_Handle sensor, uint8_t regAddr, uint16_t value)
{
  uint8_t txBuf[3] = {0}; //All writable registers are 2 bytes

  txBuf[0] = regAddr;
  txBuf[1] = MSB(value);
  txBuf[2] = LSB(value);
  mcu_i2cTransfer(sensor->busId, sensor->devAddr, txBuf, 3, NULL, 0);
}

/*
    ======== Sensor_Sensor ========
   Sensorure device with current settings.
*/
void Sensor_config(Sensor_Handle sensor)
{
  //Initialize the bus containing this sensor
  mcu_i2cInit(sensor->busId);
}

/*
    ======== Sensor_readReg ========
    Read register
*/
uint64_t Sensor_readReg(Sensor_Handle sensor, uint8_t regAddr)
{
  uint64_t value;
  int i;

  uint8_t txBuf[1] = {0};
  uint8_t rxBuf[2] = {0}; //max buffer size

  txBuf[0] = regAddr;

  //Read register
  mcu_i2cTransfer(sensor->busId, sensor->devAddr, txBuf, 1, rxBuf, 2);

  //Combine bytes
  value = (rxBuf[0] << 8) | rxBuf[1];

  return value;
}

Mcu.cpp

#include <Arduino.h>
#include "Mcu.hpp"
#include <Wire.h>

void mcu_i2cInit(uint8_t busId)
{
  Wire.begin();
}

int8_t mcu_i2cTransfer( uint8_t busId, uint8_t i2cAddr,
                        uint8_t *dataToWrite, uint8_t writeLength,
                        uint8_t *dataToRead,  uint8_t readLength)
{
  if (writeLength > 0)
  {
    Wire.beginTransmission(i2cAddr);
    Wire.write(dataToWrite, writeLength);        // sends five bytes
    Wire.endTransmission();    // stop transmitting
  }

  if (readLength > 0)
  {
    Wire.requestFrom(i2cAddr, readLength);    // request 6 bytes from slave device #8

    while (Wire.available()) // slave may send less than requested
    {
      dataToRead = Wire.read(); // receive a byte as character
    }
  }
  return (0);
}

Note that there's a serious flaw in the mcu_i2cTransfer() function. Fixing that is left as an exercise for the OP.

Thank you very much!

Moving the struct declaration extern const Sensor_Handle Sensor_0 from main.ino to Sensor.hpp fixed my compiling issues! FYI to future thread readers, that also seemed to be the only issue.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.