reading structured data from the serial port

Hi evrybody,
im pretty new to arduino so please forgive me for any dumb "why?", "how?" etc

//Im actually triyng to make arduino and raspberry pi talk with each others (im building a domotic crazy network) through UART, and it //seems to work:
//i already unlocked the pi port, built a logic level adapter, and did some tests (it worked pretty well), "words" sent from one are sent to //the other and viceversa

since that i have to program both of them i can chose the communication protocol i prefer, and i found (JSON http://interactive-matter.eu/how-to/ajson-arduino-json-library/) to be easy enough for my purpose. I know there exist a library but i would like to biuld my own function/functions in order to know perfectly the code and learn something more about programming arduinos.

//json example: {light1:true} i.e. "light1" is switched on {window1:false} i.e. the "window1" is open {rainsensor1:false}
//i.e. "rainsensor1" does not sense any water

and here comes the question: is there any efficient method to read STRUCTURED data from the serial port?
something like ("{", string nameStuff, ":", boolean stuffStatus, "}")

or reading a string (or array of chars) possibly until it reads "}" or at least of a known fixed lenght and to extract from that string the already mentioned data?

i am pretty new to arduino coding, so please post codes as much as possible, i still have some syntax problems

thank you :slight_smile:

//Im actually triyng to make arduino and raspberry pi talk with each others (im building a domotic crazy network) through UART, and it //seems to work:
//i already unlocked the pi port, built a logic level adapter, and did some tests (it worked pretty well), "words" sent from one are sent to //the other and viceversa

You really should post your code using code tags.

If that's not supposed to be code, what's with all the useless characters?

since that i have to program both of them i can chose the communication protocol i prefer, and i found (JSON http://interactive-matter.eu/how-to/ajson-arduino-json-library/) to be easy enough for my purpose. I know there exist a library but i would like to biuld my own function/functions in order to know perfectly the code and learn something more about programming arduinos.

Why use something as complicated as that? What, exactly, is the Arduino capable of doing? It can read from digital pins (all it needs to know is that is should read a digital pin, and which pin). It can write to digital pins (all it needs to know is that is should write, which pin to write to, and what value). And, it can read from analog pins (all it needs to know is that is should read an analog pin, and which pin). <R,7>, <W,6,1>, and <A,4> could convey the information that you wanted to read from digital pin 7, write a 1 to digital pin 6, and read analog pin 4.

Oh, I forgot the PWM pins. <P,3,127> Set the pin to 50% duty cycle.

Much simpler than parsing text from a bunch of weird characters.

i am pretty new to arduino coding, so please post codes as much as possible, i still have some syntax problems

Then, simple is better, isn't it?

PaulS:

//Im actually triyng to make arduino and raspberry pi talk with each others (im building a domotic crazy network) through UART, and it //seems to work:
//i already unlocked the pi port, built a logic level adapter, and did some tests (it worked pretty well), "words" sent from one are sent to //the other and viceversa

You really should post your code using code tags.

If that's not supposed to be code, what's with all the useless characters?

i just wanted to point out the fact that this is not part of te problem but just only some contextualization

PaulS:
Then, simple is better, isn't it?

im not gonna do something that simple because:
1)raspberry hasnt enough GPIO to send all the information i need using 1 pin for each state (high=true, low=false) as you suggested
2)i need to do a network, i.e. raspberry + mega + others arduinos and in order to make the code more clean, relaiable etc i want to define a protocol via serial connection that is globally accepted by my network

here i post some WRONG CODE in order to better explain what i would like to do:
return a string and "split" this retuned string into several varibles, "cutting" away syntax parts like { : }

char serialCommand[15] checkCommand()
{
    char inChar;
    byte index = 0;
    do
    {
      inChar = Serial.read(); // Read a character
      serialCommand[index] = inChar; // Store it
      index++; // Increment where to write next
      serialCommnad[15] = '\0'; // Null terminate the string
    }
    while ((serialCommand[index] != '}') 
    and (index <= 15)
    and (Serial.available))  
    return serialCommand[];
  }
  }

1)raspberry hasnt enough GPIO to send all the information i need using 1 pin for each state (high=true, low=false) as you suggested

What does the PI sending "<R,4>" or "<S,9,1>" or "<P,5,100>" or "<A,0>" have to do with the number of GPIO pins it has?

2)i need to do a network, i.e. raspberry + mega + others arduinos and in order to make the code more clean, relaiable etc i want to define a protocol via serial connection that is globally accepted by my network

The network doesn't give a rats ass about the protocol. Only the end devices do.

You can't return an array from a function. Even if you could, serialCommand[15] is an array with 1 elements, numbered 0 to 14, and serialCommnad[15] = '\0'; just stuffed a NULL in some other address that is NOT part of the array.

    do
    {
      inChar = Serial.read(); // Read a character
      serialCommand[index] = inChar; // Store it
      index++; // Increment where to write next
      serialCommnad[15] = '\0'; // Null terminate the string
    }
    while ((serialCommand[index] != '}')

Doesn't matter that there might not be anything to read, does it? Oh, wait, it certainly does.

Doesn't matter that the array might be full, does it? Oh, wait, it certainly does.

So, I'll repeat. Simple is good, isn't it?

If you are willing to consider alternatives to the JSON syntax you might consider using Bitlash to handle the parsing and bit fiddling.

-br

serialCommand[15] is an array with 1 elements, numbered 0 to 14, and serialCommnad[15] = '\0'; just stuffed a NULL in some other address that is NOT part of the arraybut it might be part of another array called serialCommnad defined as serialCommnad[16] of course.

PUNCTATORS, here the answer a frind suggested me: im posting a part if the code i wrote waiting for any suggestion or comment :slight_smile:

char* checkCommand()
{
  char *command;
  char readChar;
  byte index = 0;
  boolean error = false, openP = false, closeP = false, twoP = false; 
  /*malloc??*/
  do
  {
    readChar= Serial.read();
    switch (readChar)
    {
    case '{' : 
      if (openP == false)
        openP = true;
      else error = true;
      break;
    case ':' :
      if (twoP == false)
        twoP = true;
      else error = true;
      break;
    case '}' :
      if (closeP == false)
        closeP = true;
      else error = true;
      break;
    default:
      //read {nom1:00} {nom1:11}
      command[index] = readChar;
      index++;
      break;
    }
  }
  while ((Serial.available()) and (index < 6) and (error == false) 
  and ((closeP == false) or (openP == false) or (twoP == false)));
  return command;  
}

Your command variable isn't initialized to point at anything, so it's going to pick up whatever's on the stack and write incoming characters to that address. A good recipe for a crash or tricky bugs. I assume that malloc remark is related to this. Dynamic memory allocation is risky with so little memory and unnecessary here. Use a global array, or make it a static local.

  while ((Serial.available()) and (index < 6) and (error == false) 
  and ((closeP == false) or (openP == false) or (twoP == false)));

What a mess. Boolean values do NOT need to be compared to true or false. That mess would be a lot more readable like so:

  while ((Serial.available()) and (index < 6) && !error && (!closeP || !openP || !twoP));

Although one can only guess at what twoP is. A reason to find a urinal would be my guess.

wildbill:
Your command variable isn't initialized to point at anything, so it's going to pick up whatever's on the stack and write incoming characters to that address. A good recipe for a crash or tricky bugs. I assume that malloc remark is related to this. Dynamic memory allocation is risky with so little memory and unnecessary here. Use a global array, or make it a static local.

i knew it was a big deal, but i dont know how to solve it, imnot good at all with punctators ann memory allocations, can you please give me some advise? :slight_smile:

PaulS:

  while ((Serial.available()) and (index < 6) and (error == false) 

and ((closeP == false) or (openP == false) or (twoP == false)));



What a mess. Boolean values do NOT need to be compared to true or false. That mess would be a lot more readable like so:


while ((Serial.available()) and (index < 6) && !error && (!closeP || !openP || !twoP));

thank you, i replaced the code actually :slight_smile:

PaulS:
Although one can only guess at what twoP is. A reason to find a urinal would be my guess.

sorry while i wrote the program i had no access to internet so i did a literal translation (WRONG)

":" in italian is called "due punti" that literally means "two points". actually i will call this variable "colon" :roll_eyes:

i knew it was a big deal, but i dont know how to solve it, imnot good at all with punctators ann memory allocations, can you please give me some advise?

A pointer needs to point to memory. An array is also a pointer. The array name itself if a pointer.

So, figure out how much data your array needs to hold, and use an array instead of an uninitialized pointer. The index < 6 test is a pretty good indication that the array size should be 8.

  char command[8];

Now, the problem here is that the array is on the stack, so it will go away when the function ends, and the pointer you return will be garbage. You actually need to create the array in the caller (or as a global variable) and pass the pointer to the array to the function (if the array is defined in the caller). The function should not return a value.

   char command[8];
   chechCommand(command);
void checkCommand(char * command)
{
  // populate command...
}

Going back to the initial post ...

It seems to me you are confusing the capabilities of a PC (the PI running Linux) and a micro-controller. JSON and its equivalents are very long-winded and complex for a micro-controller.

If your examples are typical of your application

//json example: {light1:true} i.e. "light1" is switched on {window1:false} i.e. the "window1" is open {rainsensor1:false}
//i.e. "rainsensor1" does not sense any water

then it seems that you need to send 3 pieces of info to the Arduino which could be coded as L11/L10, W11/W10 and R11/R10. In fact you could reduce the code to a single character for each item.

A simple "protocol" would be to preface each command with a particular character that is not used for anything else and to make each command the same length. Then the Arduino can listen until it gets the start character following which it knows the next N characters are the command. It can then run different subroutines depending on the content of the command.

Use the power and convenience of the PC to do all the hard work and to make things as simple as possible for the PC. The PC is sufficiently powerful to be well able to transmit the same information in different formats for different purposes.

...R

would it be as easy as you said to use one letter+one number (easyer to improve, debug and add stuffs)?

Probably, yes. It'll certainly be easier when you're testing the arduino by typing commands from the serial monitor of the IDE. The point though is that as you have to code up the sender and receiver, there's no real need to use JSON or any other predefined protocol. Devise your own that is as simple as possible, but allows the expandability you need.

Devise your own that is as simple as possible, but allows the expandability you need.

Which is exactly what I was saying.