Passing structure referance to function

I have a program that stores the settings parameters for a LoRa device in the Flash of a ESP32S3 using the preferences.h library. In this way the settings of the LoRa device can be changed without re-programming the ESP32S3.

The settings are copied from Flash into a structure. When the structure was stored in Flash a CRC of the structure contents was also stored. Thus when the settings are downloaded from flash you can check that the settings are valid and not corrupted.

So I have a function that calculates the CRC of the structure in memory, the structure is called settings and an instance of it called var is created.

To call the CRC calculation I use;

CRC = CRC_structure(var, sizeof(var)); //get CRC of settings.var

And the function is;

uint16_t CRC_structure(settings &struc, uint8_t structsize)
{

It does work, the correct CRC is returned.

However note that the function needs to use the name of the structure as in the (settings &struc) bit.

Is there a way to avoid using the name of the structure (settings) in the function definition ? In that way the function could be used for any structure.

The reduced program is below;


/*******************************************************************************************************
  Programs for Arduino - Copyright of the author Stuart Robinson - 30/11/24

  This program is supplied as is, it is up to the user of the program to decide if the program is
  suitable for the intended purpose and free from errors.
*******************************************************************************************************/

#include <SPI.h>
#include <SX126XLT.h>
SX126XLT LoRa;

#include <Preferences.h>
Preferences Configurable;

#define RO_MODE true
#define RW_MODE false

struct settings
{
  uint32_t LORAFREQ;                   //Frequency of transmissions in hertz
  uint32_t LORAFREQOFF;                //Offset frequency for calibration purposes
  uint8_t LORASF;                      //LoRa spreading factor
  uint8_t LORABW;                      //LoRa bandwidth
  uint8_t LORACR;                      //LoRa coding rate
  uint8_t LORAOPT;                     //Low data rate optimisation setting, normally set to auto
  int8_t LORATXPOW;                    //LoRa transmit power in dBm
  uint32_t PKTDELAY;                   //delay in mS betwwen packets
  uint32_t MENUTIMEOUT;                //timeout in mS of menu
} __attribute__((packed, aligned(1))); //remove structure padding to ensure compatibility between 8bit and 32bit micros;

struct settings var;

//structure gives a Store CRC of 0xB483
uint32_t LORAFREQ = 434000000;           //Frequency of transmissions in hertz
uint32_t LORAFREQOFF = 0;                //Offset frequency in hertz for calibration purposes
uint8_t LORASF = LORA_SF7;               //LoRa spreading factor
uint8_t LORABW = LORA_BW_125;            //LoRa bandwidth
uint8_t LORACR = LORA_CR_4_5;            //LoRa coding rate
uint8_t LORAOPT = LDRO_AUTO;             //Low data rate optimisation setting, normally set to auto
int8_t LORATXPOW = 10;                   //LoRa transmit power in dBm
uint32_t PKTDELAY = 1000;                //delay between transmission of packets
uint32_t MENUTIMEOUT = 30000;            //timeout in mS of menus


void loop()
{
  uint16_t CRC;

  Configurable.begin("Store", RW_MODE);

  copy_settings_var();
  print_var();
  Configurable.putBytes( "Store", &var, sizeof(var));
  
  CRC = CRC_structure(var, sizeof(var));               //get CRC of settings.var
  Serial.print("var structure CRC 0x");
  Serial.println(CRC, HEX);

  while (1);
}


uint16_t CRC_structure(settings &struc, uint8_t structsize)
{
  uint8_t index, byteread;
  uint16_t i, structureCRC;
  uint8_t j;

  structureCRC = 0xFFFF;                   //start value for CRC16

  Serial.println("Structure contents");

  uint8_t* ptr = (uint8_t*)&struc;

  for (index = 0; index < structsize; index++)
  {
    byteread = (*(ptr + index));
    Serial.print(byteread, HEX);
    Serial.print(" ");
    structureCRC ^= ((uint16_t) byteread << 8);

    for (j = 0; j < 8; j++)
    {
      if (structureCRC & 0x8000)
        structureCRC = (structureCRC << 1) ^ 0x1021;
      else
        structureCRC <<= 1;
    }
  }
  Serial.println();
  return structureCRC;
}


void copy_settings_var()
{
  //copy settings from Settings.h into variables used by program
  var.LORAFREQ = LORAFREQ;                               //Frequency of transmissions in hertz
  var.LORAFREQOFF = LORAFREQOFF;                         //Offset frequency for calibration purposes
  var.LORASF = LORASF;                                   //LoRa spreading factor
  var.LORABW = LORABW;                                   //LoRa bandwidth
  var.LORACR = LORACR;                                   //LoRa coding rate
  var.LORAOPT = LORAOPT;                                 //Low data rate optimisation setting, normally set to auto
  var.LORATXPOW = LORATXPOW;                             //LoRa transmit power in dBm
  var.PKTDELAY = PKTDELAY;                               //delay in mS between packets
  var.MENUTIMEOUT = MENUTIMEOUT;                         //timeout in mS of menu
}


void print_var()
{
  Serial.println();
  Serial.println(F("Var Settings"));
  Serial.println(F("------------"));
  Serial.print(F("LORAFREQ,"));
  Serial.print(var.LORAFREQ);
  Serial.println(F("hz"));
  Serial.print(F("LORAFREQOFF,"));
  Serial.print(var.LORAFREQOFF);
  Serial.println(F("hz"));
  Serial.print(F("LORASF,"));
  Serial.println(var.LORASF);
  Serial.print(F("LORABW,"));
  Serial.print(LoRa.returnBandwidth(var.LORABW));
  Serial.println(F("hz"));
  Serial.print(F("LORACR,4:"));
  Serial.println(var.LORACR + 4);
  Serial.print(F("LORATXPOW,"));
  Serial.print(var.LORATXPOW);
  Serial.println(F("dBm"));
  Serial.print(F("PKTDELAY,"));
  Serial.print(var.PKTDELAY);
  Serial.println(F("mS"));
  Serial.print(F("MENUTIMEOUT,"));
  Serial.print(var.MENUTIMEOUT);
  Serial.println(F("mS"));
  Serial.println();
}


void setup()
{
  Serial.begin(115200);
  Serial.println(F("ESP32_Preferances_test starting"));
}

why not pass a uint8_t ptr, cast it in the call to the function

And how to do that, I am not much good at pointers and addresses etc ?

instead of

uint16_t CRC_structure(uint8_t* ptr , uint8_t structsize)
{

and remove the definition and cast of ptr inside the function since it's now defined as an argument

and instead of

  CRC = CRC_structure ((uint8_t*)&var, sizeof(var));
1 Like

Thanks, that appears to be OK.

The ability to save a structure to Flash so directly is rather useful too.

Revised code;


/*******************************************************************************************************
  Programs for Arduino - Copyright of the author Stuart Robinson - 30/11/24

  This program is supplied as is, it is up to the user of the program to decide if the program is
  suitable for the intended purpose and free from errors.
*******************************************************************************************************/

#include <SPI.h>
#include <SX126XLT.h>
SX126XLT LoRa;

#include <Preferences.h>
Preferences Configurable;

#define RO_MODE true
#define RW_MODE false

struct settings
{
  uint32_t LORAFREQ;                   //Frequency of transmissions in hertz
  uint32_t LORAFREQOFF;                //Offset frequency for calibration purposes
  uint8_t LORASF;                      //LoRa spreading factor
  uint8_t LORABW;                      //LoRa bandwidth
  uint8_t LORACR;                      //LoRa coding rate
  uint8_t LORAOPT;                     //Low data rate optimisation setting, normally set to auto
  int8_t LORATXPOW;                    //LoRa transmit power in dBm
  uint32_t PKTDELAY;                   //delay in mS betwwen packets
  uint32_t MENUTIMEOUT;                //timeout in mS of menu
} __attribute__((packed, aligned(1))); //remove structure padding to ensure compatibility between 8bit and 32bit micros;

struct settings var;

//structure gives a Store CRC of 0xB483
uint32_t LORAFREQ = 434000000;           //Frequency of transmissions in hertz
uint32_t LORAFREQOFF = 0;                //Offset frequency in hertz for calibration purposes
uint8_t LORASF = LORA_SF7;               //LoRa spreading factor
uint8_t LORABW = LORA_BW_125;            //LoRa bandwidth
uint8_t LORACR = LORA_CR_4_5;            //LoRa coding rate
uint8_t LORAOPT = LDRO_AUTO;             //Low data rate optimisation setting, normally set to auto
int8_t LORATXPOW = 10;                   //LoRa transmit power in dBm
uint32_t PKTDELAY = 1000;                //delay between transmission of packets
uint32_t MENUTIMEOUT = 30000;            //timeout in mS of menus


void loop()
{
  uint16_t CRC;

  Configurable.begin("Store", RW_MODE);

  copy_settings_var();
  print_var();
  Configurable.putBytes( "Store", &var, sizeof(var));

  CRC = CRC_structure ((uint8_t*)&var, sizeof(var));               //get CRC of settings.var
  Serial.print("var structure CRC 0x");
  Serial.println(CRC, HEX);

  while (1);
}


uint16_t CRC_structure(uint8_t* ptr , uint8_t structsize)

{
  uint8_t index, byteread;
  uint16_t i, structureCRC;
  uint8_t j;

  structureCRC = 0xFFFF;                   //start value for CRC16

  Serial.println("Structure contents");

  for (index = 0; index < structsize; index++)
  {
    byteread = (*(ptr + index));
    Serial.print(byteread, HEX);
    Serial.print(" ");
    structureCRC ^= ((uint16_t) byteread << 8);

    for (j = 0; j < 8; j++)
    {
      if (structureCRC & 0x8000)
        structureCRC = (structureCRC << 1) ^ 0x1021;
      else
        structureCRC <<= 1;
    }
  }
  Serial.println();
  return structureCRC;
}


void copy_settings_var()
{
  //copy settings from Settings.h into variables used by program
  var.LORAFREQ = LORAFREQ;                               //Frequency of transmissions in hertz
  var.LORAFREQOFF = LORAFREQOFF;                         //Offset frequency for calibration purposes
  var.LORASF = LORASF;                                   //LoRa spreading factor
  var.LORABW = LORABW;                                   //LoRa bandwidth
  var.LORACR = LORACR;                                   //LoRa coding rate
  var.LORAOPT = LORAOPT;                                 //Low data rate optimisation setting, normally set to auto
  var.LORATXPOW = LORATXPOW;                             //LoRa transmit power in dBm
  var.PKTDELAY = PKTDELAY;                               //delay in mS between packets
  var.MENUTIMEOUT = MENUTIMEOUT;                         //timeout in mS of menu
}


void print_var()
{
  Serial.println();
  Serial.println(F("Var Settings"));
  Serial.println(F("------------"));
  Serial.print(F("LORAFREQ,"));
  Serial.print(var.LORAFREQ);
  Serial.println(F("hz"));
  Serial.print(F("LORAFREQOFF,"));
  Serial.print(var.LORAFREQOFF);
  Serial.println(F("hz"));
  Serial.print(F("LORASF,"));
  Serial.println(var.LORASF);
  Serial.print(F("LORABW,"));
  Serial.print(LoRa.returnBandwidth(var.LORABW));
  Serial.println(F("hz"));
  Serial.print(F("LORACR,4:"));
  Serial.println(var.LORACR + 4);
  Serial.print(F("LORATXPOW,"));
  Serial.print(var.LORATXPOW);
  Serial.println(F("dBm"));
  Serial.print(F("PKTDELAY,"));
  Serial.print(var.PKTDELAY);
  Serial.println(F("mS"));
  Serial.print(F("MENUTIMEOUT,"));
  Serial.print(var.MENUTIMEOUT);
  Serial.println(F("mS"));
  Serial.println();
}


void setup()
{
  Serial.begin(115200);
  Serial.println(F("ESP32_Preferances_test starting"));
}

Here are three ways to improve on the concept:

  1. Change the pointer argument of the CRC function to void * instead of a uint8_t *. That way, a cast isn't required when the function is called:
uint16_t CRC_structure(const void *ptr, size_t dataSize) {
  uint16_t crc {0};
  const uint8_t *bytePtr {static_cast<const uint8_t *>(ptr)};

  //
  // Compute CRC Here
  //

  return crc;
}

void setup() {
  struct IntStruct {
    int a;
    int b;
    int c;
  };

  struct FloatStruct {
    float a;
    float b;
  };

  IntStruct struct1 {0, 1, 2};
  FloatStruct struct2 {1.5, 3.14159};

  uint16_t crc1 {CRC_structure(&struct1, sizeof(IntStruct))};
  uint16_t crc2 {CRC_structure(&struct2, sizeof(FloatStruct))};
}

void loop() {
}
  1. Use a template. That way, you don't have to take the address of the structure or it's size when the function is called:
template <typename T>
uint16_t CRC_structure(const T &dataRef) {
  uint16_t crc {0};
  const uint8_t *bytePtr {reinterpret_cast<const uint8_t *>(&dataRef)};
  size_t dataSize {sizeof(T)};

  //
  // Compute CRC Here
  //

  return crc;
}

void setup() {
  struct IntStruct {
    int a;
    int b;
    int c;
  };

  struct FloatStruct {
    float a;
    float b;
  };

  IntStruct struct1 {0, 1, 2};
  FloatStruct struct2 {1.5, 3.14159};

  uint16_t crc1 {CRC_structure(struct1)};
  uint16_t crc2 {CRC_structure(struct2)};
}

void loop() {
}
  1. Use a combination of #1 and #2:
uint16_t crcHelper(const void *ptr, size_t dataSize) {
  uint16_t crc {0};
  const uint8_t *bytePtr {static_cast<const uint8_t *>(ptr)};

  //
  // Compute CRC Here
  //

  return crc;
}

template <typename T>
inline uint16_t CRC_structure(const T &dataRef) {
  return crcHelper(&dataRef, sizeof(T));
}

void setup() {
  struct IntStruct {
    int a;
    int b;
    int c;
  };

  struct FloatStruct {
    float a;
    float b;
  };

  IntStruct struct1 {0, 1, 2};
  FloatStruct struct2 {1.5, 3.14159};

  uint16_t crc1 {CRC_structure(struct1)};
  uint16_t crc2 {CRC_structure(struct2)};
}

void loop() {
}
1 Like

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