Struct arrays to fill master struct array based on condition

I am working on a project using an ESP32 WROOM hosting a webserver. The ESP32 is using the UART1 to read and write Modbus registers to a motor controller. I reference as HVFD. HVFD can be configured to either type "P1" or "WJ". The values in the P1 or WJ struct are never changing they are only used to fill the matching data in the HVFD struct. Is there a better way to do this?
FYI HVFD_Select is user selectable from the webserver the ESP is hosting. I actually pull the value for HVFD_Select from EEPROM but i am just simplifying the example.

int32_t Hoist_Output_Frequency;
int32_t Hoist_Output_Current;
int32_t Hoist_Output_Direction;
int32_t Hoist_Position;
int32_t Hoist_DI_Status;
int32_t Hoist_Operation_Status;

// Hoist EZSQ Settings Variables
int32_t Hoist_Micro_Low_Spd_Freq_Value = 0;
int32_t Hoist_Low_Spd_Freq_Value = 0;
int32_t Hoist_High_Spd_Freq_Value = 0;
int32_t Hoist_Micro_High_Spd_Freq_Value = 0;
int32_t Hoist_Speed_Control_Function_Value = 0;
int32_t Hoist_AAAS_Function_Value = 0;
int32_t Hoist_Load_Float_Value = 0;
int32_t Hoist_Shock_Load_Function_Value = 0;

// Hoist Accel & Decel Settings Settings Variables
int32_t Hoist_Alt_AD_Function_Value = 0;
int32_t Hoist_Acc1_Acc2_Function_Value = 0;
int32_t Hoist_Dec1_Dec2_Function_Value = 0;
int32_t Hoist_Acc1_Function_Value = 0;
int32_t Hoist_Dec1_Function_Value = 0;
int32_t Hoist_Acc2_Function_Value = 0;
int32_t Hoist_Dec2_Function_Value = 0;

typedef struct HVFD_Mon_s {
  const char *Abbrv;
  const char *Type;
  const char *Json_Var;
  bool Enable;
  byte Register[8];
  int Resp_Buf_Size;
  int32_t *Data_Pointer;
} HVFD_Mon_t;
HVFD_Mon_t HVFD_Mon[] = {
  // Monitors
  { "FM", "Monitor", "HOF", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, &Hoist_Output_Frequency },
  { "IOUT", "Monitor", "HOC", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, &Hoist_Output_Current },
  { "DIR", "Monitor", "HOD", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, &Hoist_Output_Direction },
  { "POS", "Monitor", "HPC", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, &Hoist_Position },
  { "DIM", "Monitor", "HDI", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, &Hoist_DI_Status },
  { "STATUS", "Monitor", "HOS", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, &Hoist_Operation_Status },
};

typedef struct HVFD_Settings_s {
  const char *Abbrv;
  const char *Type;
  const char *Json_Var;
  bool Enable;
  byte Register[8];
  int Resp_Buf_Size;
  int Min_Value;
  int Max_Value;
  int32_t *Data_Pointer;
} HVFD_Settings_t;
HVFD_Settings_t HVFD_Settings[] = {
  // EZSQ Settings
  { "MLSF", "Setting", "HMLSFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Micro_Low_Spd_Freq_Value },
  { "SLSF", "Setting", "HLSFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Low_Spd_Freq_Value },
  { "SHSF", "Setting", "HHSFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_High_Spd_Freq_Value },
  { "MHSF", "Setting", "HMHSFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Micro_High_Spd_Freq_Value },
  { "SSCM", "Setting", "HSCFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Speed_Control_Function_Value },
  { "ASFS", "Setting", "HASFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_AAAS_Function_Value },
  { "LFT", "Setting", "HLFTV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Load_Float_Value },
  { "SLF", "Setting", "HSLFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Shock_Load_Function_Value },
  // Accel & Decel Settings
  { "2CH", "Setting", "HALTAD", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Alt_AD_Function_Value},
  { "A1A2TF", "Setting", "HA1A2", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Acc1_Acc2_Function_Value},
  { "D1D2TF", "Setting", "HD1D2", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Dec1_Dec2_Function_Value},
  { "ACC1", "Setting", "HACC1",  false,{ 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Acc1_Function_Value},
  { "DECEL1", "Setting", "HDEC1", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Dec1_Function_Value},
  { "ACC2", "Setting", "HACC2", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Acc2_Function_Value},
  { "DECEL2", "Setting", "HDEC2", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Dec2_Function_Value}
};

typedef struct P1_s {
  const char *Param; // Just For Reference
  const char *Abbrv;
  const char *Desc; // Just For Reference
  const char *Type;
  byte Func_Addr[4];
  int Resp_Buf_Size;
  int Min_Value;
  int Max_Value;
} P1_t;
P1_t P1[] = {
  // Monitors
  { "dA-01", "FM", "Output Frequency Monitor", "Monitor", { 0x27, 0x10, 0x00, 0x01 }, 7, 0, 0 },
  { "dA-02", "IOUT", "Output Current Monitor", "Monitor", { 0x27, 0x11, 0x00, 0x01 }, 7, 0, 0 },
  { "dA-03", "DIR", "Output Direction Monitor", "Monitor", { 0x27, 0x12, 0x00, 0x01 }, 7, 0, 0 },
  { "dA-20", "POS", "Current Position Monitor", "Monitor", { 0x27, 0x23, 0x00, 0x02 }, 9, 0, 0 },
  { "dA-51", "DIM", "Input Terminal Monitor", "Monitor", { 0x27, 0x42, 0x00, 0x01 }, 7, 0, 0 },
  { "dC-35", "STATUS", "Operation Status Monitor", "Monitor", { 0x27, 0xFA, 0x00, 0x01 }, 7, 0, 0 },
  // EZSQ Settings
  { "UE-10", "MLSF", "Low Micro-Speed Freq Setting", "Setting", { 0x47, 0xE9, 0x00, 0x01 }, 7, 250, 6000 },
  { "UE-11", "SLSF", "Low Speed Freq Setting", "Setting", { 0x47, 0xEA, 0x00, 0x01 }, 7, 250, 6000 },
  { "UE-12", "SHSF", "High Speed Freq Setting", "Setting", { 0x47, 0xEB, 0x00, 0x01 }, 7, 250, 6000 },
  { "UE-15", "MHSF", "High Micro-Speed Freq Setting", "Setting", { 0x47, 0xEE, 0x00, 0x01 }, 7, 250, 6000 },
  { "UE-18", "SSCM", "Standard Speed Control Setting", "Setting", { 0x47, 0xF1, 0x00, 0x01 }, 7, 0, 6 },
  { "UE-21", "ASAL", "Auto Speed Activation Level Setting", "Setting", { 0x47, 0xF4, 0x00, 0x01 }, 7, 0, 1000 },
  { "UE-22", "ASFS", "Auto Speed Function Setting", "Setting", { 0x47, 0xF5, 0x00, 0x01 }, 7, 0, 2 },
  { "UE-29", "LFT", "Load Float Time Setting", "Setting", { 0x47, 0xFC, 0x00, 0x01 }, 7, 50, 3000 },
  { "UE-52", "SLF", "Shock Load Function Setting", "Setting", { 0x48, 0x13, 0x00, 0x01 }, 7, 0, 2 },
  // Accel & Decel Settings
  { "AC115", "2CH", "Switch Method To Acce2/Decel2 Setting", "Setting", { 0x2F, 0xB6, 0x00, 0x01 }, 7, 0, 2 },
  { "AC116", "A1A2TF", "Accel1 To Accel2 Trans Freq Setting", "Setting", { 0x2F, 0xB7, 0x00, 0x01 }, 7, 0, 59000 },
  { "AC117", "D1D2TF", "Decel1 To Decel2 Trans Freq Setting", "Setting", { 0x2F, 0xB8, 0x00, 0x01 }, 7, 0, 59000 },
  { "AC120", "ACC1", "Accel1 Setting", "Setting", { 0x2F, 0xBB, 0x00, 0x02 }, 9, 50, 59000 },
  { "AC122", "DECEL1", "Decel1 Setting", "Setting", { 0x2F, 0xBD, 0x00, 0x02 }, 9, 50, 59000 },
  { "AC124", "ACC2", "Accel2 Setting", "Setting", { 0x2F, 0xBF, 0x00, 0x02 }, 9, 50, 59000 },
  { "AC126", "DECEL2", "Decel2 Setting", "Setting", { 0x2F, 0xC1, 0x00, 0x02 }, 9, 50, 59000 }
};

typedef struct WJ_s {
  const char *Param; // Just For Reference
  const char *Abbrv;
  const char *Desc; // Just For Reference
  const char *Type;
  byte Func_Addr[4];
  int Resp_Buf_Size;
  int Min_Value;
  int Max_Value;
} WJ_t;
WJ_t WJ[] = {
    // Monitors
  { "d001", "FM", "Output Frequency Monitor", "Monitor", { 0x10, 0x00, 0x00, 0x02 }, 9, 0, 0 },
  { "d002", "IOUT", "Output Current Monitor", "Monitor", { 0x10, 0x02, 0x00, 0x01 }, 7, 0, 0 },
  { "d003", "DIR", "Output Direction Monitor", "Monitor", { 0x10, 0x03, 0x00, 0x01 }, 7, 0, 0 },
  { "d030", "POS", "Current Position Monitor", "Monitor", { 0x10, 0x37, 0x00, 0x02 }, 9, 0, 0 },
  { "d005", "DIM", "Input Terminal Monitor", "Monitor", { 0x10, 0x06, 0x00, 0x01 }, 7, 0, 0 },
  { "J002", "STATUS", "Operation Status Monitor", "Monitor", { 0x00, 0x03, 0x00, 0x01 }, 7, 0, 0 },
  // EZSQ Settings
  { "P100", "MLSF", "Low Micro-Speed Freq Setting", "Function", { 0x16, 0x65, 0x00, 0x01 }, 7, 250, 6000 },
  { "P101", "SLSF", "Low Speed Freq Setting", "Function", { 0x16, 0x66, 0x00, 0x01 }, 7, 250, 6000 },
  { "P102", "SHSF", "High Speed Freq Setting", "Function", { 0x16, 0x67, 0x00, 0x01 }, 7, 250, 6000 },
  { "P105", "MHSF", "High Micro-Speed Freq Setting", "Function", { 0x16, 0x6A, 0x00, 0x01 }, 7, 250, 6000 },
  { "P108", "SSCM", "Standard Speed Control Setting", "Function", { 0x16, 0x6D, 0x00, 0x01 }, 7, 0, 5 },
  { "P110", "ASFS", "Auto Speed Function Setting", "Function", { 0x16, 0x6F, 0x00, 0x01 }, 7, 0, 1 },
  { "P111", "ASAL", "Auto Speed Activation Level Setting", "Function", { 0x16, 0x70, 0x00, 0x01 }, 7, 0, 100 },
  // Accel & Decel Settings
  { "A094", "2CH", "Switch Method To Acce2/Decel2 Setting", "Function", { 0x12, 0x77, 0x00, 0x01 }, 7, 0, 2 },
  { "A095", "A1A2TF", "Accel1 To Accel2 Trans Freq Setting", "Function", { 0x12, 0x78, 0x00, 0x02 }, 9, 0, 59000 },
  { "A096", "D1D2TF", "Decel1 To Decel2 Trans Freq Setting", "Function", { 0x12, 0x7A, 0x00, 0x02 }, 9, 0, 59000 },
  { "F002", "ACC1", "Accel1 Setting", "Function", { 0x11, 0x02, 0x00, 0x02 }, 9, 50, 59000 },
  { "F003", "DECEL1", "Decel1 Setting", "Function", { 0x11, 0x04, 0x00, 0x02 }, 9, 50, 59000 },
  { "A092", "ACC2", "Accel2 Setting", "Function", { 0x12, 0x73, 0x00, 0x02 }, 9, 50, 59000 },
  { "A093", "DECEL2", "Decel2 Setting", "Function", { 0x12, 0x75, 0x00, 0x02 }, 9, 50, 59000 }
};

void setup() {
  int HVFD_Select = 1; // 1 = P1, 2 = WJ 
  int Hoist_VFD_Address = 3; // RS485 Node 1-10

 switch (HVFD_Select) {
    case 1: // P1 Model
    for (int i = 0; i < sizeof(HVFD_Mon) / sizeof(HVFD_Mon[0]); i++) {
          for (int j = 0; j < sizeof(P1) / sizeof(P1[0]); j++) {
            if (P1[j].Abbrv == HVFD_Mon[i].Abbrv && P1[j].Type == HVFD_Mon[i].Type) {
              HVFD_Mon[i].Enable = true;
              HVFD_Mon[i].Register[0] = Hoist_VFD_Address;
              HVFD_Mon[i].Register[2] = P1[j].Func_Addr[0];
              HVFD_Mon[i].Register[3] = P1[j].Func_Addr[1];
              HVFD_Mon[i].Register[4] = P1[j].Func_Addr[2];
              HVFD_Mon[i].Register[5] = P1[j].Func_Addr[3];
              uint16_t CRC = ModRTU_CRC(HVFD_Mon[i].Register, sizeof(HVFD_Mon[i].Register) - 2);
              HVFD_Mon[i].Register[6] = CRC;
              HVFD_Mon[i].Register[7] = (CRC >> 8);
              HVFD_Mon[i].Resp_Buf_Size = P1[j].Resp_Buf_Size;
            }
          }
        }
        for (int i = 0; i < sizeof(HVFD_Settings) / sizeof(HVFD_Settings[0]); i++) {
          for (int j = 0; j < sizeof(P1) / sizeof(P1[0]); j++) {
            if (P1[j].Abbrv == HVFD_Settings[i].Abbrv && P1[j].Type == HVFD_Settings[i].Type) {
              HVFD_Settings[i].Enable = true;
              HVFD_Settings[i].Register[0] = Hoist_VFD_Address;
              HVFD_Settings[i].Register[2] = P1[j].Func_Addr[0];
              HVFD_Settings[i].Register[3] = P1[j].Func_Addr[1];
              HVFD_Settings[i].Register[4] = P1[j].Func_Addr[2];
              HVFD_Settings[i].Register[5] = P1[j].Func_Addr[3];
              uint16_t CRC = ModRTU_CRC(HVFD_Settings[i].Register, sizeof(HVFD_Settings[i].Register) - 2);
              HVFD_Settings[i].Register[6] = CRC;
              HVFD_Settings[i].Register[7] = (CRC >> 8);
              HVFD_Settings[i].Resp_Buf_Size = P1[j].Resp_Buf_Size;
              HVFD_Settings[i].Min_Value = P1[j].Min_Value;
              HVFD_Settings[i].Max_Value = P1[j].Max_Value;
            }
          }
        }
    break;
    case 2:  // WJ200 Model
    for (int i = 0; i < sizeof(HVFD_Mon) / sizeof(HVFD_Mon[0]); i++) {
          for (int j = 0; j < sizeof(WJ) / sizeof(WJ[0]); j++) {
            if (WJ[j].Abbrv == HVFD_Mon[i].Abbrv && WJ[j].Type == HVFD_Mon[i].Type) {
              HVFD_Mon[i].Enable = true;
              HVFD_Mon[i].Register[0] = Hoist_VFD_Address;
              HVFD_Mon[i].Register[2] = WJ[j].Func_Addr[0];
              HVFD_Mon[i].Register[3] = WJ[j].Func_Addr[1];
              HVFD_Mon[i].Register[4] = WJ[j].Func_Addr[2];
              HVFD_Mon[i].Register[5] = WJ[j].Func_Addr[3];
              uint16_t CRC = ModRTU_CRC(HVFD_Mon[i].Register, sizeof(HVFD_Mon[i].Register) - 2);
              HVFD_Mon[i].Register[6] = CRC;
              HVFD_Mon[i].Register[7] = (CRC >> 8);
              HVFD_Mon[i].Resp_Buf_Size = WJ[j].Resp_Buf_Size;
            }
          }
        }
        for (int i = 0; i < sizeof(HVFD_Settings) / sizeof(HVFD_Settings[0]); i++) {
          for (int j = 0; j < sizeof(WJ) / sizeof(WJ[0]); j++) {
            if (WJ[j].Abbrv == HVFD_Settings[i].Abbrv && WJ[j].Type == HVFD_Settings[i].Type) {
              HVFD_Settings[i].Enable = true;
              HVFD_Settings[i].Register[0] = Hoist_VFD_Address;
              HVFD_Settings[i].Register[2] = WJ[j].Func_Addr[0];
              HVFD_Settings[i].Register[3] = WJ[j].Func_Addr[1];
              HVFD_Settings[i].Register[4] = WJ[j].Func_Addr[2];
              HVFD_Settings[i].Register[5] = WJ[j].Func_Addr[3];
              uint16_t CRC = ModRTU_CRC(HVFD_Settings[i].Register, sizeof(HVFD_Settings[i].Register) - 2);
              HVFD_Settings[i].Register[6] = CRC;
              HVFD_Settings[i].Register[7] = (CRC >> 8);
              HVFD_Settings[i].Resp_Buf_Size = WJ[j].Resp_Buf_Size;
              HVFD_Settings[i].Min_Value = WJ[j].Min_Value;
              HVFD_Settings[i].Max_Value = WJ[j].Max_Value;
            }
          }
        }
    break;
  }

}

void loop(){}

uint16_t ModRTU_CRC(byte buf[], int len) {
  uint16_t crc = 0xFFFF;
  for (int pos = 0; pos < len; pos++) {
    crc ^= (uint16_t)buf[pos];      // XOR byte into least sig. byte of crc
    for (int i = 8; i != 0; i--) {  // Loop over each bit
      if ((crc & 0x0001) != 0) {    // If the LSB is set
        crc >>= 1;                  // Shift right and XOR 0xA001
        crc ^= 0xA001;
      } else        // Else LSB is not set
        crc >>= 1;  // Just shift right
    }
  }
  return crc;
}
1 Like

could you use a ptr to the structure with the unchanging values, so instead of copying values, you just set a ptr in the work struct to the struct with the constants

1 Like

LOL. Could you not have spared a few more of your lifetime supply of typed letters?

@Mkinney88, @gcjr is suggesting using a pointer.

If you haven't heard of pointers, now you have. They are quite useful and you'll want to know about them sooner later.

google

  c++ pointer

and catch things like this

a7

You simplified too much. The posted code does not compile. 'Hoist_Micro_Low_Spd_Freq_Value' and similar are all undefined.

I'm using pointers in the struct array as you can see in HVFD_Settings and HVFD_Mon for the int32_t *Data_Pointer which is used like this. How would you use a pointer to reference the struct array to be used like the below code?

Also I would need to make a copy of the struct array data because there are actually (2) devices that may be configured to pull the struct array data from either "p1" or "wj" or both as "p1" but with a different rs485 addresses, and crc obviously.

void GetHVFDMonitorData() {
  for (int i = 0; i < sizeof(HVFD_Mon) / sizeof(HVFD_Mon[0]); i++) {
    if (HVFD_Mon[i].Enable) {
      *HVFD_Mon[i].Data_Pointer = Modbus_Request_Single(HVFD_Mon[i].Register, sizeof(HVFD_Mon[i].Register), HVFD_Mon[i].Resp_Buf_Size);
    }
  }
}

int32_t Modbus_Request_Single(byte Modbus_Message[], int Message_Len, int Response_Buffer_Size) {
  Serial1.write(Modbus_Message, Message_Len);  // Send Modbus message
  Serial1.flush();                             // Wait for the transmission of outgoing Serial1 data to complete
  delay(1);
  int32_t Modbus_Response_Data = 0;
  byte Modbus_Response_Buffer[Response_Buffer_Size];
  unsigned long start = millis();
  while (Serial1.available() < Response_Buffer_Size) {
    if (millis() - start > 500) {
      return Modbus_Response_Data;
    }
  }
  if (Serial1.available() == Response_Buffer_Size) {
    for (byte i = 0; i < Response_Buffer_Size; i++) {
      Modbus_Response_Buffer[i] = Serial1.read();
    }
    if (Response_Buffer_Size == 7) {
      Modbus_Response_Data = (int16_t)(Modbus_Response_Buffer[3] << 8) | Modbus_Response_Buffer[4];
    }
    if (Response_Buffer_Size == 9) {
      Modbus_Response_Data = ((int32_t)Modbus_Response_Buffer[3] << 24) | Modbus_Response_Buffer[4] << 16 | Modbus_Response_Buffer[5] << 8 | Modbus_Response_Buffer[6];
    }
  }
  while (Serial1.available() > 0) { Serial1.read(); }
  return Modbus_Response_Data;
}

Sorry about that! I edited the post the post to include the int32_t variables that are referenced in the code.

I'm looking through the tiny window, not circumstances conducive to analyzing your code and showing you how you should never need to copy data that won't change in order to use it elsewhere.

I can't look to see, but if you mean you have to copy the struct and then tinker with some of the values it holds, that may be true.

If the struct data does not change, you should be able to handle it w/o copying in all places where the struct variable is used.

If the struct data does have to change in order to be used, do so, but perhaps also think about how you've, um, structured your structs.

It is likely that a bit more complexity in the data structures you exploit to accomplish your goals woukd eliminate the need for copying.

Or just do the copying, if you have the resources. Fast small programs take way longer to create. If there are no objections other than aesthetic, just do the copying.

a7

instead of copying values from one struct to the other, your HVFD_MON_s would have a ptr to a P1_t

typedef struct HVFD_Mon_s {
  const char *Abbrv;

  const char *Type;
  const char *Json_Var;

  bool Enable;
  P1_s            *p1;

  int32_t *Data_Pointer;
} HVFD_Mon_t;

That would be correct if HVFD_Mon was always configured for "P1" correcct? If so keep in mind that HVFD_Mon gets data copied from either "P1" or "WJ" based on a user selection process from the ESP32 WebServer.

Think about it this way.
The P1 struct array is a master template of data for that type of device.
The WJ struct array is a master template of data for that type of device.

The HVFD struct array is a template that is configured based on the device selected and some data is copied and changed based on that selection.

Is there a way to do something like this? I know it doesn't compile but I'm using it as a reference.

int32_t Hoist_Output_Frequency;
int32_t Hoist_Output_Current;
int32_t Hoist_Output_Direction;
int32_t Hoist_Position;
int32_t Hoist_DI_Status;
int32_t Hoist_Operation_Status;

// Hoist EZSQ Settings Variables
int32_t Hoist_Micro_Low_Spd_Freq_Value = 0;
int32_t Hoist_Low_Spd_Freq_Value = 0;
int32_t Hoist_High_Spd_Freq_Value = 0;
int32_t Hoist_Micro_High_Spd_Freq_Value = 0;
int32_t Hoist_Speed_Control_Function_Value = 0;
int32_t Hoist_AAAS_Function_Value = 0;
int32_t Hoist_Load_Float_Value = 0;
int32_t Hoist_Shock_Load_Function_Value = 0;

// Hoist Accel & Decel Settings Settings Variables
int32_t Hoist_Alt_AD_Function_Value = 0;
int32_t Hoist_Acc1_Acc2_Function_Value = 0;
int32_t Hoist_Dec1_Dec2_Function_Value = 0;
int32_t Hoist_Acc1_Function_Value = 0;
int32_t Hoist_Dec1_Function_Value = 0;
int32_t Hoist_Acc2_Function_Value = 0;
int32_t Hoist_Dec2_Function_Value = 0;

typedef struct HVFD_Mon_s {
  const char *Abbrv;
  const char *Type;
  const char *Json_Var;
  bool Enable;
  byte Register[8];
  int Resp_Buf_Size;
  int32_t *Data_Pointer;
} HVFD_Mon_t;
HVFD_Mon_t HVFD_Mon[] = {
  // Monitors
  { "FM", "Monitor", "HOF", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, &Hoist_Output_Frequency },
  { "IOUT", "Monitor", "HOC", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, &Hoist_Output_Current },
  { "DIR", "Monitor", "HOD", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, &Hoist_Output_Direction },
  { "POS", "Monitor", "HPC", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, &Hoist_Position },
  { "DIM", "Monitor", "HDI", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, &Hoist_DI_Status },
  { "STATUS", "Monitor", "HOS", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, &Hoist_Operation_Status },
};

typedef struct HVFD_Settings_s {
  const char *Abbrv;
  const char *Type;
  const char *Json_Var;
  bool Enable;
  byte Register[8];
  int Resp_Buf_Size;
  int Min_Value;
  int Max_Value;
  int32_t *Data_Pointer;
} HVFD_Settings_t;
HVFD_Settings_t HVFD_Settings[] = {
  // EZSQ Settings
  { "MLSF", "Setting", "HMLSFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Micro_Low_Spd_Freq_Value },
  { "SLSF", "Setting", "HLSFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Low_Spd_Freq_Value },
  { "SHSF", "Setting", "HHSFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_High_Spd_Freq_Value },
  { "MHSF", "Setting", "HMHSFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Micro_High_Spd_Freq_Value },
  { "SSCM", "Setting", "HSCFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Speed_Control_Function_Value },
  { "ASFS", "Setting", "HASFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_AAAS_Function_Value },
  { "LFT", "Setting", "HLFTV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Load_Float_Value },
  { "SLF", "Setting", "HSLFV", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Shock_Load_Function_Value },
  // Accel & Decel Settings
  { "2CH", "Setting", "HALTAD", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Alt_AD_Function_Value},
  { "A1A2TF", "Setting", "HA1A2", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Acc1_Acc2_Function_Value},
  { "D1D2TF", "Setting", "HD1D2", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Dec1_Dec2_Function_Value},
  { "ACC1", "Setting", "HACC1",  false,{ 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Acc1_Function_Value},
  { "DECEL1", "Setting", "HDEC1", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Dec1_Function_Value},
  { "ACC2", "Setting", "HACC2", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Acc2_Function_Value},
  { "DECEL2", "Setting", "HDEC2", false, { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0, 0, &Hoist_Dec2_Function_Value}
};

typedef struct P1_s {
  const char *Param; // Just For Reference
  const char *Abbrv;
  const char *Desc; // Just For Reference
  const char *Type;
  byte Func_Addr[4];
  int Resp_Buf_Size;
  int Min_Value;
  int Max_Value;
} P1_t;
P1_t P1[] = {
  // Monitors
  { "dA-01", "FM", "Output Frequency Monitor", "Monitor", { 0x27, 0x10, 0x00, 0x01 }, 7, 0, 0 },
  { "dA-02", "IOUT", "Output Current Monitor", "Monitor", { 0x27, 0x11, 0x00, 0x01 }, 7, 0, 0 },
  { "dA-03", "DIR", "Output Direction Monitor", "Monitor", { 0x27, 0x12, 0x00, 0x01 }, 7, 0, 0 },
  { "dA-20", "POS", "Current Position Monitor", "Monitor", { 0x27, 0x23, 0x00, 0x02 }, 9, 0, 0 },
  { "dA-51", "DIM", "Input Terminal Monitor", "Monitor", { 0x27, 0x42, 0x00, 0x01 }, 7, 0, 0 },
  { "dC-35", "STATUS", "Operation Status Monitor", "Monitor", { 0x27, 0xFA, 0x00, 0x01 }, 7, 0, 0 },
  // EZSQ Settings
  { "UE-10", "MLSF", "Low Micro-Speed Freq Setting", "Setting", { 0x47, 0xE9, 0x00, 0x01 }, 7, 250, 6000 },
  { "UE-11", "SLSF", "Low Speed Freq Setting", "Setting", { 0x47, 0xEA, 0x00, 0x01 }, 7, 250, 6000 },
  { "UE-12", "SHSF", "High Speed Freq Setting", "Setting", { 0x47, 0xEB, 0x00, 0x01 }, 7, 250, 6000 },
  { "UE-15", "MHSF", "High Micro-Speed Freq Setting", "Setting", { 0x47, 0xEE, 0x00, 0x01 }, 7, 250, 6000 },
  { "UE-18", "SSCM", "Standard Speed Control Setting", "Setting", { 0x47, 0xF1, 0x00, 0x01 }, 7, 0, 6 },
  { "UE-21", "ASAL", "Auto Speed Activation Level Setting", "Setting", { 0x47, 0xF4, 0x00, 0x01 }, 7, 0, 1000 },
  { "UE-22", "ASFS", "Auto Speed Function Setting", "Setting", { 0x47, 0xF5, 0x00, 0x01 }, 7, 0, 2 },
  { "UE-29", "LFT", "Load Float Time Setting", "Setting", { 0x47, 0xFC, 0x00, 0x01 }, 7, 50, 3000 },
  { "UE-52", "SLF", "Shock Load Function Setting", "Setting", { 0x48, 0x13, 0x00, 0x01 }, 7, 0, 2 },
  // Accel & Decel Settings
  { "AC115", "2CH", "Switch Method To Acce2/Decel2 Setting", "Setting", { 0x2F, 0xB6, 0x00, 0x01 }, 7, 0, 2 },
  { "AC116", "A1A2TF", "Accel1 To Accel2 Trans Freq Setting", "Setting", { 0x2F, 0xB7, 0x00, 0x01 }, 7, 0, 59000 },
  { "AC117", "D1D2TF", "Decel1 To Decel2 Trans Freq Setting", "Setting", { 0x2F, 0xB8, 0x00, 0x01 }, 7, 0, 59000 },
  { "AC120", "ACC1", "Accel1 Setting", "Setting", { 0x2F, 0xBB, 0x00, 0x02 }, 9, 50, 59000 },
  { "AC122", "DECEL1", "Decel1 Setting", "Setting", { 0x2F, 0xBD, 0x00, 0x02 }, 9, 50, 59000 },
  { "AC124", "ACC2", "Accel2 Setting", "Setting", { 0x2F, 0xBF, 0x00, 0x02 }, 9, 50, 59000 },
  { "AC126", "DECEL2", "Decel2 Setting", "Setting", { 0x2F, 0xC1, 0x00, 0x02 }, 9, 50, 59000 }
};

typedef struct WJ_s {
  const char *Param; // Just For Reference
  const char *Abbrv;
  const char *Desc; // Just For Reference
  const char *Type;
  byte Func_Addr[4];
  int Resp_Buf_Size;
  int Min_Value;
  int Max_Value;
} WJ_t;
WJ_t WJ[] = {
    // Monitors
  { "d001", "FM", "Output Frequency Monitor", "Monitor", { 0x10, 0x00, 0x00, 0x02 }, 9, 0, 0 },
  { "d002", "IOUT", "Output Current Monitor", "Monitor", { 0x10, 0x02, 0x00, 0x01 }, 7, 0, 0 },
  { "d003", "DIR", "Output Direction Monitor", "Monitor", { 0x10, 0x03, 0x00, 0x01 }, 7, 0, 0 },
  { "d030", "POS", "Current Position Monitor", "Monitor", { 0x10, 0x37, 0x00, 0x02 }, 9, 0, 0 },
  { "d005", "DIM", "Input Terminal Monitor", "Monitor", { 0x10, 0x06, 0x00, 0x01 }, 7, 0, 0 },
  { "J002", "STATUS", "Operation Status Monitor", "Monitor", { 0x00, 0x03, 0x00, 0x01 }, 7, 0, 0 },
  // EZSQ Settings
  { "P100", "MLSF", "Low Micro-Speed Freq Setting", "Function", { 0x16, 0x65, 0x00, 0x01 }, 7, 250, 6000 },
  { "P101", "SLSF", "Low Speed Freq Setting", "Function", { 0x16, 0x66, 0x00, 0x01 }, 7, 250, 6000 },
  { "P102", "SHSF", "High Speed Freq Setting", "Function", { 0x16, 0x67, 0x00, 0x01 }, 7, 250, 6000 },
  { "P105", "MHSF", "High Micro-Speed Freq Setting", "Function", { 0x16, 0x6A, 0x00, 0x01 }, 7, 250, 6000 },
  { "P108", "SSCM", "Standard Speed Control Setting", "Function", { 0x16, 0x6D, 0x00, 0x01 }, 7, 0, 5 },
  { "P110", "ASFS", "Auto Speed Function Setting", "Function", { 0x16, 0x6F, 0x00, 0x01 }, 7, 0, 1 },
  { "P111", "ASAL", "Auto Speed Activation Level Setting", "Function", { 0x16, 0x70, 0x00, 0x01 }, 7, 0, 100 },
  // Accel & Decel Settings
  { "A094", "2CH", "Switch Method To Acce2/Decel2 Setting", "Function", { 0x12, 0x77, 0x00, 0x01 }, 7, 0, 2 },
  { "A095", "A1A2TF", "Accel1 To Accel2 Trans Freq Setting", "Function", { 0x12, 0x78, 0x00, 0x02 }, 9, 0, 59000 },
  { "A096", "D1D2TF", "Decel1 To Decel2 Trans Freq Setting", "Function", { 0x12, 0x7A, 0x00, 0x02 }, 9, 0, 59000 },
  { "F002", "ACC1", "Accel1 Setting", "Function", { 0x11, 0x02, 0x00, 0x02 }, 9, 50, 59000 },
  { "F003", "DECEL1", "Decel1 Setting", "Function", { 0x11, 0x04, 0x00, 0x02 }, 9, 50, 59000 },
  { "A092", "ACC2", "Accel2 Setting", "Function", { 0x12, 0x73, 0x00, 0x02 }, 9, 50, 59000 },
  { "A093", "DECEL2", "Decel2 Setting", "Function", { 0x12, 0x75, 0x00, 0x02 }, 9, 50, 59000 }
};

void setup() {
  int HVFD_Select = 1; // 1 = P1, 2 = WJ 
  int Hoist_VFD_Address = 3; // RS485 Node 1-10
  Init_Array(HVFD_Mon, P1, Hoist_VFD_Address); 
}

void Init_Array(dest[], src[], int DeviceAddr) {
  for (int i = 0; i < sizeof(dest) / sizeof(dest[0]); i++) {
          for (int j = 0; j < sizeof(src) / sizeof(src[0]); j++) {
            if (src[j].Abbrv == dest[i].Abbrv && src[j].Type == dest[i].Type) {
              dest[i].Enable = true;
              dest[i].Register[0] = DeviceAddr;
              dest[i].Register[2] = src[j].Func_Addr[0];
              dest[i].Register[3] = src[j].Func_Addr[1];
              dest[i].Register[4] = src[j].Func_Addr[2];
              dest[i].Register[5] = src[j].Func_Addr[3];
              uint16_t CRC = ModRTU_CRC(dest[i].Register, sizeof(dest[i].Register) - 2);
              dest[i].Register[6] = CRC;
              dest[i].Register[7] = (CRC >> 8);
              dest[i].Resp_Buf_Size = src[j].Resp_Buf_Size;
              dest[i].Min_Value = src[j].Min_Value;
              dest[i].Max_Value = src[j].Max_Value;
            }
          }
        }
}

void loop(){}

uint16_t ModRTU_CRC(byte buf[], int len) {
  uint16_t crc = 0xFFFF;
  for (int pos = 0; pos < len; pos++) {
    crc ^= (uint16_t)buf[pos];      // XOR byte into least sig. byte of crc
    for (int i = 8; i != 0; i--) {  // Loop over each bit
      if ((crc & 0x0001) != 0) {    // If the LSB is set
        crc >>= 1;                  // Shift right and XOR 0xA001
        crc ^= 0xA001;
      } else        // Else LSB is not set
        crc >>= 1;  // Just shift right
    }
  }
  return crc;
}

also, not all elements of a struct need to be initialized. unspecified values are set to zero by default.

so put the values that need to be initialized at the beginning of the struct.

for example

typedef struct HVFD_Mon_s {
    const char *Abbrv;
    const char *Type;
    const char *Json_Var;
    bool Enable;
    int32_t *Data_Pointer;

    byte Register[8];
    int Resp_Buf_Size;
} HVFD_Mon_t;

HVFD_Mon_t HVFD_Mon[] = {
    // Monitors
    { "FM",   "Monitor", "HOF", false, &Hoist_Output_Frequency },
    { "IOUT", "Monitor", "HOC", false, &Hoist_Output_Current },
    { "DIR",  "Monitor", "HOD", false, &Hoist_Output_Direction },
};

not sure i understand. guessing that you use different fields of HVFD_Settings depending on type of device. if so, P1 and WJ need to be of the same type and would be supersets of each other

make the data work for you, not constrain your code

1 Like

True only for a global instance.

you mean statically defined ?

Global. As in not local. As in not defined within a function.

I'm not sure about static local instances. Don't know if they are default initialized.

is there a way to do something like this? I know this doesn't compile but its just for reference.

void setup() {
  int HVFD_Select = 1; // 1 = P1, 2 = WJ 
  int Hoist_VFD_Address = 3; // RS485 Node 1-10
  Init_Array(HVFD_Mon, P1, Hoist_VFD_Address); 
}

void Init_Array(dest[], src[], int DeviceAddr) {
  for (int i = 0; i < sizeof(dest) / sizeof(dest[0]); i++) {
          for (int j = 0; j < sizeof(src) / sizeof(src[0]); j++) {
            if (src[j].Abbrv == dest[i].Abbrv && src[j].Type == dest[i].Type) {
              dest[i].Enable = true;
              dest[i].Register[0] = DeviceAddr;
              dest[i].Register[2] = src[j].Func_Addr[0];
              dest[i].Register[3] = src[j].Func_Addr[1];
              dest[i].Register[4] = src[j].Func_Addr[2];
              dest[i].Register[5] = src[j].Func_Addr[3];
              uint16_t CRC = ModRTU_CRC(dest[i].Register, sizeof(dest[i].Register) - 2);
              dest[i].Register[6] = CRC;
              dest[i].Register[7] = (CRC >> 8);
              dest[i].Resp_Buf_Size = src[j].Resp_Buf_Size;
              dest[i].Min_Value = src[j].Min_Value;
              dest[i].Max_Value = src[j].Max_Value;
            }
          }
        }
}

my point is that anything global is initialized (one way or another)

Absolutely agree. My point was stressing the global part of that since Post 11 did not.

Static local regular variables are initialized, it would be a large-ish mistake if all static local variables were not treated in the same way.

Or a huge surprise and disappointment.

googling.

a7

Agree. @Mkinney88's data structures are unnecessarily convoluted. Also, IMO, the posted example is too complex. It would have been preferable to post an MRE. This is the simplest, complete example that compiles and demonstrates the problem at hand. Something like:

struct FixedData {
  const char name[20];
  const uint32_t value1;
  const uint32_t value2;
};

FixedData fixedDataType1 {"Fixed Type1", 100, 0};
FixedData fixedDataType2 {"Fixed Type2", 33, 15678};

struct MainData {
  const char name[10];
  const char type[10];
  const FixedData *fixed;
};

MainData theData[] {
  {"Name1", "dog", nullptr},
  {"Name2", "cat", nullptr},
  {"Name3", "bird", nullptr},
};

void setup() {
  const uint8_t structType {1};
  FixedData *fixedDataPtr {nullptr};

  Serial.begin(115200);
  delay(2000);

  switch (structType) {
    case 1:
      fixedDataPtr = &fixedDataType1;
      break;

    case 2:
      fixedDataPtr = &fixedDataType2;
      break;

    default:
      assert(false && "Bad structType");
  }

  for(auto &data : theData) {
    data.fixed = fixedDataPtr;
    Serial.printf("Name: %s, Fixed Data: %s\n", data.name, data.fixed->name);
  }
}

void loop() {
}
1 Like