Populate array of struct containing an array from config.h

Hi folks,

I have the following:
config.h

#define _TEMPERATURE_SENSOR_COUNT                           7

#define _TEMPERATURE_SENSOR_CABINET_IDX                     0
#define _TEMPERATURE_SENSOR_CABINET_ADDR                    { 0x01, 0x01, 0x02, 0x16, 0xa8, 0x1, 0x3C, 0x9E }  //16 a8 1 3c 9e

#define _TEMPERATURE_SENSOR_HEATER_OUT_IDX                  1
#define _TEMPERATURE_SENSOR_HEATER_OUT_ADDR                 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }   //16a813c89

in my setup code I have:


typedef struct
  {
      DeviceAddress  address;
      float temperature;
      byte  isValid = false;
  }  sensor;

sensor sensorsArr[_TEMPERATURE_SENSOR_COUNT];

void mySetup(){
  memcpy(sensorsArr[_TEMPERATURE_SENSOR_CABINET_IDX].address, (DeviceAddress)_TEMPERATURE_SENSOR_CABINET_ADDR, sizeof((DeviceAddress)_TEMPERATURE_SENSOR_CABINET_ADDR[0])*8);
}

I want to populate the array of struct for use later on. How do I copy the values in?
When I compile I get an error:

error: taking address of temporary array
memcpy(sensorsArr[_TEMPERATURE_SENSOR_CABINET_IDX].address, (DeviceAddress)_TEMPERATURE_SENSOR_CABINET_ADDR, sizeof((DeviceAddress)_TEMPERATURE_SENSOR_CABINET_ADDR[0])*8);
^
Thanks
C

Please post a complete sketch that illustrates the problem. For instance, where is DeviceAddress declared ?

Apologies, rather daft of me. It's a ds18b20

I've recreated a smaller sketch to show as I cannot post the whole one (to big)

It seems the problem is actually with the arrary as a #define as compile time it cannot determine it's size. Sort of makes sense.
if I use the option below where it is declared as a const, it works (obviously). But that's not really what I want.

How better to store the value in a config file?

#include <OneWire.h>
#include <DallasTemperature.h>

#define _TEMPERATURE_SENSOR_COUNT                           7

#define _TEMPERATURE_SENSOR_CABINET_IDX                     0
const DeviceAddress _TEMPERATURE_SENSOR_CABINET_ADDR =                    { 0x01, 0x01, 0x02, 0x16, 0xa8, 0x1, 0x3C, 0x9E };  

#define _TEMPERATURE_SENSOR_HEATER_OUT_IDX                  1
#define _TEMPERATURE_SENSOR_HEATER_OUT_ADDR                 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } 


//unsigned int numSensors = 0;

OneWire oneWireTemperature(4);

// Pass our oneWire reference to Dallas Temperature sensor 
DallasTemperature sensorsTemperatures(&oneWireTemperature);

typedef struct
  {
      DeviceAddress  address;
      float temperature;
      byte  isValid = false;
  }  sensor;

sensor sensorsArr[_TEMPERATURE_SENSOR_COUNT];

void setup() {
  // put your setup code here, to run once:
  memcpy(sensorsArr[_TEMPERATURE_SENSOR_CABINET_IDX].address, _TEMPERATURE_SENSOR_CABINET_ADDR, sizeof(_TEMPERATURE_SENSOR_CABINET_ADDR));
  //memcpy(sensorsArr[_TEMPERATURE_SENSOR_HEATER_OUT_IDX].address, _TEMPERATURE_SENSOR_HEATER_OUT_ADDR, sizeof(_TEMPERATURE_SENSOR_HEATER_OUT_ADDR));
  memcpy(sensorsArr[_TEMPERATURE_SENSOR_HEATER_OUT_IDX].address, _TEMPERATURE_SENSOR_HEATER_OUT_ADDR, 8);
}

void loop() {
  // put your main code here, to run repeatedly:

}

don't use #define for your second array.

Given everything is known, why don't you do (typed here, mind typos)

#include <OneWire.h>
#include <DallasTemperature.h>
#define _TEMPERATURE_SENSOR_CABINET_IDX     0
#define _TEMPERATURE_SENSOR_HEATER_OUT_IDX  1
OneWire oneWireTemperature(4);
DallasTemperature sensorsTemperatures(&oneWireTemperature);

struct t_sensor {
  DeviceAddress  address;
  float temperature;
  byte  isValid;
} sensorsArr[] = {
  {{0x01, 0x01, 0x02, 0x16, 0xa8, 0x01, 0x3C, 0x9E}, 0 , false},
  {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0 , false},
};
const byte _TEMPERATURE_SENSOR_COUNT = sizeof sensorsArr / sizeof sensorsArr[0];

void setup() {
  Serial.begin(115200);
  for (byte s = 0; s < _TEMPERATURE_SENSOR_COUNT; s++) {
    for (byte b = 0; b < sizeof(DeviceAddress); b++) {
      if (sensorsArr[s].address[b] < 0x10) Serial.write('0');
      Serial.print(sensorsArr[s].address[b], HEX);
      Serial.write(' ');
    }
    Serial.println();
  }
}

void loop() {}

Yup, I could certainly do that. Given that it will only ever be me using this and the sensors are unlikely to change (much) it's perfectly ok.

I was looking for the "proper" way to do it and use it within a config file but it may be a step to far.
One option I now have is:
store the string version of the sensors in config.
At startup I can list all sensors found, find the string version and map them that way.
It's clunky as my struct will now have a string key which I wanted to avoid.

you could instantiate the t_sensor array dynamically and he version could be a number

Reading the config file will require a bit of parsing to extract the values

can you explain what you're trying to do and what your configuration depends on?

i worked on a project where we built different versions of code for different RF card using .h files specific to the RF board. i'm sure this isn't what you're trying to do, but do you have different devices or simply one device with numerous sensors?

I have this piece of code posted in the French section that might give you some ideas. (use google translate if you don't read French)

Your code compiles if you change from a define to a const:

//#define _TEMPERATURE_SENSOR_HEATER_OUT_ADDR                 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } 
const DeviceAddress _TEMPERATURE_SENSOR_HEATER_OUT_ADDR = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

If you do the preprocessor substitution manually, using define does look like an obvious error:

  //memcpy(sensorsArr[_TEMPERATURE_SENSOR_HEATER_OUT_IDX].address, _TEMPERATURE_SENSOR_HEATER_OUT_ADDR, sizeof(_TEMPERATURE_SENSOR_HEATER_OUT_ADDR));
  memcpy(sensorsArr[_TEMPERATURE_SENSOR_HEATER_OUT_IDX].address, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 8);

Yes, it would but within the config.h the type DeviceAddress would not be known unless I include the lib for it. I would have thought that would be "distasteful" in a config file?

or I could remove them from the config file and keep them in the cpp file.

Right, I have a solution. Not what I would have thought first time round but works.

I scan all connected sensors, grab their address, a fugly if-else statement then builds a map of them in the original array.
it costs me 121ms but is probably nastier on RAM due to the string compare. Ho hum.

config.h

#define _TEMPERATURE_SENSOR_RESOLUTION                      12      // res in {9,10,11,12}
#define _TEMPERATURE_SENSOR_COUNT                           7

#define _TEMPERATURE_SENSOR_CABINET_IDX                     0
#define _TEMPERATURE_SENSOR_CABINET_ADDR                    "16a813c9e"

#define _TEMPERATURE_SENSOR_HEATER_OUT_IDX                  1
#define _TEMPERATURE_SENSOR_HEATER_OUT_ADDR                 "16a813c89"

#define _TEMPERATURE_SENSOR_HEATER_RETURN_IDX               2
#define _TEMPERATURE_SENSOR_HEATER_RETURN_ADDR              "16a813c9f"

#define _TEMPERATURE_SENSOR_EXCHANGER_EXHAUST_IN_IDX        3
#define _TEMPERATURE_SENSOR_EXCHANGER_EXHAUST_IN_ADDR       "09ccb062"

#define _TEMPERATURE_SENSOR_EXCHANGER_EXHAUST_OUT_IDX       4
#define _TEMPERATURE_SENSOR_EXCHANGER_EXHAUST_OUT_ADDR      "16a813c3e"

#define _TEMPERATURE_SENSOR_EXCHANGER_POOL_IN_IDX           5
#define _TEMPERATURE_SENSOR_EXCHANGER_POOL_IN_ADDR          "96f013c6f"

#define _TEMPERATURE_SENSOR_EXCHANGER_POOL_OUT_IDX          6
#define _TEMPERATURE_SENSOR_EXCHANGER_POOL_OUT_ADDR         "96f013c4b"

code snip.


String saveAddress(uint8_t deviceAddress[8])
{
  String address = "";
    for (uint8_t i = 3; i < 8; i++) {
        // zero pad the address if necessary
//        if (deviceAddress[i] < 16)
//            address += 0;
        address += String(deviceAddress[i],HEX);
    }
    return address;
} //end print address function


void setup(){
  for (int i=0;i<=_TEMPERATURE_SENSOR_COUNT-1;i++){
    DeviceAddress addr;
    if (!sensorsTemperatures.getAddress(addr, i)){
      printDebug("No more sensors");
      continue;
    }
    
    String sen = saveAddress(addr);
    if (sen == _TEMPERATURE_SENSOR_CABINET_ADDR)
      memcpy(t_sensors[_TEMPERATURE_SENSOR_CABINET_IDX].address, addr, sizeof(addr));
    else if (sen == _TEMPERATURE_SENSOR_HEATER_OUT_ADDR)
      memcpy(t_sensors[_TEMPERATURE_SENSOR_HEATER_OUT_IDX].address, addr, sizeof(addr));
    else if (sen == _TEMPERATURE_SENSOR_HEATER_RETURN_ADDR)
      memcpy(t_sensors[_TEMPERATURE_SENSOR_HEATER_RETURN_IDX].address, addr, sizeof(addr));
    else if (sen == _TEMPERATURE_SENSOR_EXCHANGER_EXHAUST_IN_ADDR)
      memcpy(t_sensors[_TEMPERATURE_SENSOR_EXCHANGER_EXHAUST_IN_IDX].address, addr, sizeof(addr));
    else if (sen == _TEMPERATURE_SENSOR_EXCHANGER_EXHAUST_OUT_ADDR)
      memcpy(t_sensors[_TEMPERATURE_SENSOR_EXCHANGER_EXHAUST_OUT_IDX].address, addr, sizeof(addr));
    else if (sen == _TEMPERATURE_SENSOR_EXCHANGER_POOL_IN_ADDR)
      memcpy(t_sensors[_TEMPERATURE_SENSOR_EXCHANGER_POOL_IN_IDX].address, addr, sizeof(addr));
    else if (sen == _TEMPERATURE_SENSOR_EXCHANGER_POOL_OUT_ADDR)
      memcpy(t_sensors[_TEMPERATURE_SENSOR_EXCHANGER_POOL_OUT_IDX].address, addr, sizeof(addr));
    else {
      printDebug("UNKNOWN SENSOR!", false);
      printDebug(sen);
    }
  }

  printDebug("done");

  for (int i=0;i<=_TEMPERATURE_SENSOR_COUNT-1;i++){
    printDebug("Sensor: ", false);
    printDebug(saveAddress(t_sensors[i].address));
  }
}

output: (I've only one sensor connected atm)

[2368 ] Building sensor arrary
[2403 ] No more sensors
[2419 ] No more sensors
[2435 ] No more sensors
[2454 ] No more sensors
[2474 ] No more sensors
[2489 ] No more sensors
[2490 ] done
[2490 ] Sensor: 16a813c9e
[2490 ] Sensor: 00000
[2490 ] Sensor: 00000
[2490 ] Sensor: 00000
[2491 ] Sensor: 00000
[2493 ] Sensor: 00000
[2495 ] Sensor: 00000
[2499 ] Setting up temperature sensors...done

Thanks for the help and ideas! Great community.

or set a pointer to the array of structs with the values

Look at the library to see how DeviceAddress is defined, and create the array using the same data type. Downside would be a change in the library definition could break your code.

It's a uint8_t 8. That would make it a lot simpler to do?

If you use the #define form above, this should work:

struct t_sensor {
  DeviceAddress  address;
  float temperature;
  byte  isValid;
} sensorsArr[] = {
  {_TEMPERATURE_SENSOR_CABINET_ADDR, 0 , false},
  {_TEMPERATURE_SENSOR_HEATER_OUT_ADDR, 0 , false},
};