Convert char array to struct

Hi,
I'm working on a project which transmits serial char array to receiver. I want to convert that char array in to my struct format. Can someone help me to solve this issue

//serial array format => |number of relayIDS|state|configuration|relay IDs|
char bufferData[32] = "5,h,l,1,2,3,4,5";

struct SerialPacket
{
  int payloadSize;
  char state;
  char configuation; // A -> Append, S -> SetRelays, C-> Clear all;
  int relayIDS[35];
  
}m_packet;

m_packet.payloadSize = atol(bufferData);
m_packet.state = bufferData[2];
 m_packet.configuation = bufferData[4];
 

I extracted above values. But I don't know how to extract relayIDS. (1,2,3,4,5). (number of relay IDS may change)

As many creators You're home blind. What are You talking about?
You need to explain the type, the organisation of the source data.
What is the source and data types, and what do You want to convert it to?

IF they are the same length, a "union" will do the job. See documentation on use of "union".
Paul

1 Like

Use strtok to split on the comma and atoi or strtoul to convert text to numbers where needed.

1 Like

that's the reason, bufferData[] arraydont have same length.
ex.
It could be
5,h,l,1,2,3,4,5
6,h,l,1,2,10,14,20,23
2,h,l,25,19

like this

what is h and l supposed to be?

I threw something together.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define DELIMITER ","

static char bufferData[32] = "5,h,l,1,2,3,4,5";

struct SerialPacket {
    unsigned int count;
    char state;
    char configuration;
    unsigned int relayIDS[35];
};

enum ValueType {
    Count,
    State,
    Configuration,
    RelayId
};

static struct SerialPacket parsePayload(char *data) {

    enum ValueType nextValueType = Count;
    struct SerialPacket packet = {0};

    char *next;
    char *token = strtok(data, DELIMITER);
    unsigned int position = 0;

    while (token != NULL) {

        switch (nextValueType) {

            case Count:
                packet.count = strtoul(token, &next, 10);
                nextValueType = State;
                break;

            case State:
                packet.state = token[0];
                nextValueType = Configuration;
                break;

            case Configuration:
                packet.configuration = token[0];
                nextValueType = RelayId;
                break;

            case RelayId:
                packet.relayIDS[position++] = strtoul(token, &next, 10);
                break;
        }

        token = strtok(NULL, DELIMITER);
    }

    return packet;
}

int main() {

    struct SerialPacket somePacket = parsePayload(bufferData);

    printf("Count = %u\n", somePacket.count);
    printf("State = %c\n", somePacket.state);
    printf("Configuration = %c\n", somePacket.configuration);

    for (unsigned int i = 0; i < somePacket.count; i++) {
        printf("\tRelay Id = %u\n", somePacket.relayIDS[i]);
    }

    return 0;
}

I think it does what you want. It was quicker for me to test it on my PC, but it should be easily transferable to Arduino.

Edit:

Since the string is terminated, it's not strictly necessary to send "number of relayIDS".

1 Like

Packet format is :
|number of relay ids|relay state(h-high/l-low)|relay settings (which function should the streamer call (C- off all, S - config etc)| relay ids|

If you need to switch relays, select 0/1 or enum state {LOW, HIGH}; for the relay state, especially since they are already defined in Arduino.

1 Like

Hi,
I uploaded this code to my ESP32 board.
It gives me this type of output.
image

It doesn't give the actual values

Hello,

Here is an example using only strtoul : nDcCVu - Online C++ Compiler & Debugging Tool - Ideone.com

Also, it could be simplified a lot if you could reduce the size of relayIDS to 32, you would need a single 32-bits variable where each bit is the state of one relay

Or at least change the type of relayIDS (and payloadSize) to uint8_t

1 Like

@guix Thank you. It works.

It works fine on my end. If you want me to I can take a look at it, but you'll have to post the actual code that you're using.

1 Like

@nicolajna 'm using ESp32 Module

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char bufferData[32] = "5,H,L,1,2,3,4,6";

#define DELIMITER ","

struct SerialPacket
{
  uint8_t count;
  char state;
  char configuration; // A -> Append, S -> SetRelays, C-> Clear all;
  uint8_t relayIDS[32];
  
}packet;
enum ValueType
{
  COUNT,
  STATE,
  CONFIGURATION,
  RELAYID,
};

static struct SerialPacket parsePayload(char* dataVal)
{
  enum ValueType nextValueType = COUNT;
  struct SerialPacket packet = {0};
  
  char* next;
  char* token = strtok(dataVal,DELIMITER);
  unsigned int pos =0;
  while(token != NULL)
  {
    switch(nextValueType)
    {
      case COUNT:
        packet.count = strtoul(token, &next,10);
        nextValueType = STATE;
        break;
      case STATE:
        packet.state = token[0];
        nextValueType = CONFIGURATION;
        break;
      case CONFIGURATION:
        packet.configuration = token[0];
        nextValueType = RELAYID;
        break;
      case RELAYID:
        packet.relayIDS[pos++] = strtoul(token,&next,10);
        break;
    }
    token = strtok(NULL,DELIMITER);
  }
  return packet;
  
  
}
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}
void loop() {
  struct SerialPacket packet = parsePayload(bufferData);
  Serial.println(packet.count);
  Serial.print("State:");Serial.println(packet.state);
  Serial.print("configuration:");Serial.println(packet.configuration);
  for(int i=0;i<packet.count;i++)
  {
    Serial.println(packet.relayIDS[i]);
  }
}

I tried running it on an esp32 and there's definitely something wrong on that platform. It seemed to me like the strtok function returns a null pointer every call for some reason. It might have something to do with all the stuff going on under the hood in the esp32 arduino core.

I'm off for work now and I'm really not all that familiar with the esp32, so I think my investigation is done for now, since you've gotten another snippet of code that seems to work for you.

1 Like

Maybe because you run the code in loop() indefinitely. After the first call to parsePayload, bufferData has been modified ( , were replaced by \0 ) so the next calls to parsePayload will fail

2 Likes

Now that you say it it's quite obvious. I cannot believe I didn't catch that. Well spotted, thank you.

Solved the problem. It occurs because of serial.println.

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