Declaring a structure in a structure

Hello everyone!

I have a problem regarding on how can i declare a typedef structure in a typedef structure globally, not in loop fuction. Here is my variables.

#include "MapFloat.h"
#include <TimerOne.h>
#include <EEPROM.h>

#define UPS A0
#define SENSOR_TEMP1 A1
#define SENSOR_TEMP2 A2
#define SENSOR_HUMEDAD1 A3
#define SENSOR_HUMEDAD2 A4
#define BUTTON_IMPORTE A5
#define BUTTON_RESET 2
#define LED_V1 3
#define LED_V2 4
#define LED_MOTOR1 5
#define LED_MOTOR2 6
#define LED_EV1 7
#define LED_EV2 8
#define LED_COMPRESOR 9
#define LED_ERROR 10
#define BUTTON_CAIDA 11
#define LED_CAMBIOS 12
#define LEDpin 13

#define LINE_BUF_SIZE 32   //Maximum input string length
#define ARG_BUF_SIZE 16     //Maximum argument string length
#define MAX_NUM_ARGS 4      //Maximum number of arguments

typedef struct t_time {
  unsigned int hour;
  unsigned int mins;
  unsigned int seconds;
};

typedef struct t_product {
  String product_name;
  char product_key [3];
  float price;
  int motor_pin;
  unsigned long int activation_time;
  int product_quantity;
} ;



typedef struct t_humidity_sensor {
  float hysteresis;
  float gain;
};

typedef struct t_temperature_sensor {
  float hysteresis;
  float gain;
};

typedef struct t_control_zones {
  t_temperature_sensor temperature;
  t_humidity_sensor humidity;
  float target_temperature;
  float current_temperature;
  float target_humidity;
  float current_humidity;
  float limit_temperature;
  float limit_humidity;
  t_product products[5];
  bool fridge_actuator;
  bool fan_actuator;
};

typedef struct t_vending_machine {
  t_time real_time_clock;
  t_time On;
  t_time low;
  t_control_zones control_zones[2];
  float credit;
  float change;
  float supply_voltage;
  float limit_voltage;
  bool power_mode;
  unsigned int error_indicator;
};


t_vending_machine vendingMachine;


bool error_flag = false;

char line[LINE_BUF_SIZE];
char args[MAX_NUM_ARGS][ARG_BUF_SIZE];

int cmd_help();
int cmd_prod();
int cmd_set();


//List of functions pointers corresponding to each command
int (*commands_func[])() {
  &cmd_help,
  &cmd_prod,
  &cmd_set

};

//List of command names
const char *commands_str[] = {
  "help",
  "product",
  "setting",
};


int num_commands = sizeof(commands_str) / sizeof(char *);

int arrayProd;
bool isDetected = false;

enum estadoMaquina {
  DEFAULT_MODE,
  INTRODUCIR_IMPORTE,
  ELEGIR_PRODUCTOS,
  COMPROBACION,
  DISPENSAR_PRODUCTOS,
  DETECCION_CAIDA,
  DEVOLVER_CAMBIOS,
  REINICIAR_MAQUINA,
};
enum estadoMaquina mode = DEFAULT_MODE;


In this project i have the main variable t_vending_machine vendingMachine in which all the other typedef structures are contain inside this variable. I would like to declare all the variables globally with respect to the main variable such as for example vendingMachine.real_time_clock = {6, 30, 0}. This declaration would give me an error if i put this globally but working just fine if i put this inside the loop. I need to declare this globally because the real time can't always be the same everytime it goes through the loop function. How can i declare this globally with respect to the vendingMachine ?

And any tips on how can i reduce the memory usage because all those functions/variables used quite a lot memory .

I hope i explained well the problem. Thanks in advanced and have a good day everyone !

If you want to initialize all the data in the struct, you can when declaring the variable, otherwise you can do individual items in setup.

t_vending_machine vendingMachine = {
  {6, 30, 0}, //real_time_clock
  {0, 0, 0}, //t_time On;
  {0, 0, 0}, //t_time low;
  { {{0, 0}, {0, 0}, 0, 0, 0, 0, 0, 0, {{"", "", 0, 0, 0, 0}, {"", "", 0, 0, 0, 0}, {"", "", 0, 0, 0, 0}, {"", "", 0, 0, 0, 0}, {"", "", 0, 0, 0, 0}}, false, false},
    {{0, 0}, {0, 0}, 0, 0, 0, 0, 0, 0, {{"", "", 0, 0, 0, 0}, {"", "", 0, 0, 0, 0}, {"", "", 0, 0, 0, 0}, {"", "", 0, 0, 0, 0}, {"", "", 0, 0, 0, 0}}, false, false}
  },//t_control_zones control_zones[2];
  0, //credit;
  0, //change;
  0, //supply_voltage;
  0, //limit_voltage;
  false, //power_mode;
  0 //error_indicator;
};

There are a few variables that you can reduce in size, such as the time, which will easily fit within bytes. The same applies to t_product.motor_pin - I don't know of any arduino that has over 255 pins.

typedef struct t_time {
  unsigned int hour;
  unsigned int mins;
  unsigned int seconds;
};

I'm not really sure you need all the floats either, will depend on the actual values, but a small whole number takes less space to store as an int.

1 Like

Do you mean that you would like to initialize the contents of the global variable 'vendingMachine'? That's going to be a mess since the structures within structures within structures will all have to be specified.

Perhaps you would be better served by initializing each copy of each structure separately and use pointers to reference the initialized structures in other structures. Something like this:

struct t_product
{
  String product_name;
  char product_key [3];
  float price;
  int motor_pin;
  unsigned long int activation_time;
  int product_quantity;
};

t_product ZoneAProducts[5] =
{
  {"Pepsi", "A1", 2.50, MPA1, 1350, 0},
  {"Pepsi", "A2", 2.50, MPA2, 1350, 0},
  {"Pepsi", "A3", 2.50, MPA3, 1350, 0},
  {"Pepsi", "A4", 2.50, MPA4, 1350, 0},
  {"Pepsi", "A5", 2.50, MPA5, 1350, 0},
};

t_product ZoneBProducts[5] =
{
  {"Pepsi", "B1", 2.50, MPB1, 1350, 0},
  {"Pepsi", "B2", 2.50, MPB2, 1350, 0},
  {"Pepsi", "B3", 2.50, MPB3, 1350, 0},
  {"Pepsi", "B4", 2.50, MPB4, 1350, 0},
  {"Pepsi", "B5", 2.50, MPB5, 1350, 0},
};


struct t_control_zones
{
  t_temperature_sensor temperature;
  t_humidity_sensor humidity;
  float target_temperature;
  float current_temperature;
  float target_humidity;
  float current_humidity;
  float limit_temperature;
  float limit_humidity;
  t_product *products;
  bool fridge_actuator;
  bool fan_actuator;
};

t_control_zones ZoneA
{
  ...
  ZoneAProducts,
  ...
};

t_control_zones ZoneB
{
  ...
  ZoneBProducts,
  ...
};

typedef struct t_vending_machine
{
  t_time real_time_clock;
  t_time On;
  t_time low;
  t_control_zones *control_zones[2];
  float credit;
  float change;
  float supply_voltage;
  float limit_voltage;
  bool power_mode;
  unsigned int error_indicator;
} vendingMachine
{
  ...
  {ZoneA, ZoneB},
  ...
}; 

1 Like

Here are a few random things that might be helpful.

  • Your typedef declaration is ignored by the compiler because you did not name the type, but you named the struct.
typedef struct {
  unsigned int hour;
  unsigned int mins;
  unsigned int seconds;
} t_time;

I suspect you need to enable compiler warnings. Go to File -> Preferences and make sure Compiler Warning is set to ALL. Then you would get something like this:

C:\filepath sketch.ino ... warning: 'typedef' was ignored in this declaration
 typedef struct t_vending_machine {

  • When you are not using an 8-bit architecture the compiler will insert padding bytes into structs. Order your elements to align them in memory. When that is not possible you can force the compiler to remove the padding. This will cost a little bit of performance.
typedef struct
{
  int32_t p;
  int8_t t;
  int8_t x;
} data_t;

typedef struct __attribute__( ( packed ) )
{
  int8_t t;
  int32_t p; //this will not be memory aligned and access will be slower
  int8_t x;
} data_t;
  • The naming convention for types recommends _t as a suffix not prefix e.g., uint32_t

  • When you are worried about memory hour, minute and second can be stored in a byte instead of int which is minimum of 2 bytes on an 8-bit or 4 bytes on a 32-bit processor.

  • Try avoiding float if you do not need the dynamic range for computation. For instance, store your prices in cents instead of dollar. No floating point necessary. You can do the same for temperature, humidity ... This will save memory and get you better performance.

1 Like

Results in

Somewhere\nakedTypedef\nakedTypedef.ino:1:1: warning: 'typedef' was ignored in this declaration
 typedef struct t_time {
 ^~~~~~~
Somewhere\nakedTypedef\nakedTypedef.ino:7:1: warning: 'typedef' was ignored in this declaration
 typedef struct t_product {
 ^~~~~~~
  1. You did not name the type you wanted the struct to be typedefed to.
  2. You don't need to typedef structs, they are already a type, just like any class.
1 Like

I've made a modification just like what you've suggest.

typedef struct t_time {
  byte hour;
  byte mins;
  byte seconds;
};

typedef struct t_product {
  String product_name;
  char product_key [3];
  float price;
  byte motor_pin;
  unsigned long int activation_time;
  byte product_quantity;
} ;

t_product ZoneAProducts[5] = {
  {"Coca-Cola", "1A", 0.5, 5, 1000, 5},
  {"Zumo de Limon", "2A", 1.25, 5, 1000, 5},
  {"Zumo de Naranja", "3A", 1.25, 5, 1000, 5},
  {"Zumo de Uvas", "4A", 1.5, 5, 1000, 5},
  {"Zumo de Manzana", "5A", 1.5, 5, 1000, 5},
};

t_product ZoneBProducts[5] = {
  {"Doritos", "1B", 2.2, 6, 1000, 5},
  {"Lays", "2B", 2.0, 6, 1000, 5},
  {"Cacahuetes", "3B", 0.8, 6, 1000, 5},
  {"Oreo", "4B", 1.8, 6, 1000, 5},
  {"Milka", "5B", 2.5, 6, 1000, 5},
};


typedef struct t_humidity_sensor {
  float hysteresis;
  float gain;
};

typedef struct t_temperature_sensor {
  float hysteresis;
  float gain;
};

typedef struct t_control_zones {
  t_temperature_sensor temperature;
  t_humidity_sensor humidity;
  float target_temperature;
  float current_temperature;
  float target_humidity;
  float current_humidity;
  float limit_temperature;
  float limit_humidity;
  t_product *products;
  bool fridge_actuator;
  bool fan_actuator;
};

t_control_zones ZoneA = {
  {0.75, 0}, // temperature = { hysterisis, gain }
  {5, 0}, // humidity = { hysterisis, gain }
  16.0 , //target_temperature zone 1;
  0, // current_temperature;
  20.0, //target_humidity;
  0, //float current_humidity;
  26.0, //float limit_temperature;
  30.0, //float limit_humidity;
  ZoneAProducts,//t_product *products];
  false, //bool fridge_actuator;
  false,  //bool fan_actuator;
};

t_control_zones ZoneB = {
  {0.75, 0}, // temperature = { hysterisis, gain }
  {5, 0}, // humidity = { hysterisis, gain }
  22.0 , //target_temperature zone 2;
  0, // current_temperature;
  20.0, //target_humidity;
  0, //float current_humidity;
  26.0, //float limit_temperature;
  30.0, //float limit_humidity;
  ZoneBProducts,//t_product *products];
  false, //bool fridge_actuator;
  false,  //bool fan_actuator;
};

typedef struct t_vending_machine {
  t_time real_time_clock;
  t_time On;
  t_time low;
  t_control_zones *control_zones;
  float credit;
  float change;
  float supply_voltage;
  float limit_voltage;
  bool power_mode;
  byte error_indicator;
};

t_vending_machine vending_machine =
{
  {6, 29, 0},
  {6, 30, 0},
  {22, 30, 0},
  {ZoneA, ZoneB},
  0, //credit
  0, //chage
  0, //suppy volatge
  10.0, // limit volltage
  false, //power mode
  10, //error indicator
};


bool error_flag = false;

char line[LINE_BUF_SIZE];
char args[MAX_NUM_ARGS][ARG_BUF_SIZE];

int cmd_help();
int cmd_prod();
int cmd_set();


//List of functions pointers corresponding to each command
int (*commands_func[])() {
  &cmd_help,
  &cmd_prod,
  &cmd_set

};

//List of command names
const char *commands_str[] = {
  "help",
  "product",
  "setting",
};


int num_commands = sizeof(commands_str) / sizeof(char *);


int arrayProd;
bool isDetected = false;

enum estadoMaquina {
  DEFAULT_MODE,
  INTRODUCIR_IMPORTE,
  ELEGIR_PRODUCTOS,
  COMPROBACION,
  DISPENSAR_PRODUCTOS,
  DETECCION_CAIDA,
  DEVOLVER_CAMBIOS,
  REINICIAR_MAQUINA,
};
enum estadoMaquina mode = DEFAULT_MODE;

And now the error i got is "braces around scalar initializer for type 't_control_zones*' " .If i eliminate the braces, there would be too many arguments in t_vending_machine. Or should i make an array of vending_machine ? I can't wrap my head around this error. Glad if anyone could help me.

Thanks

You have the control_zones declared incorrectly, and the struct only has one instead of two.

t_vending_machine vending_machine =
{
  {6, 29, 0},
  {6, 30, 0},
  {22, 30, 0},
  {&ZoneA, &ZoneB}, //  t_control_zones *control_zones[2];
  0, //credit
  0, //chage
  0, //suppy volatge
  10.0, // limit volltage
  false, //power mode
  10, //error indicator
};

I had:

You have:

The compiler is complaining because you are trying to put the two pointers into one pointer.