storing data in a string and re-use it as chars (for serial ICSC communication)

Hi folks,
first of all again thank you for so much support during the last months and years while I am more and more familiar with arduino and programming.

Backgroud of my project:
I would like to extend the ICSC lib of Majenko (see at github) with a confirmation function in the way that the receiver always returns the transmitted data with another command. Then the sender can compare the sent data with the received data to ensure it was transmitted correctly.

Solution:
First I send my data on the way.
Second I store al the necessary values in a string with separators.
Third In case of unsuccessful transmission I unfold the string with strtok or whatever and then I can send the data again.

Problem:
When I unfold the string there is something going wrong. First I was trying to use strtok but this didn’t work out because data was empty. So I tried to do it on the long why (code below), which compiles without errors but is not accepted by the ICSC library in the way that nothing is sent so far.

The function I use to send messages:
boolean _ICSC::send(unsigned char origin, unsigned char station, char command, unsigned char len, char *data)

Do you have any idea what went wrong in this case?

If you have a completely different approach I would also be open to discuss.

Thank you so much,

curtuino

    // demo message:
    char b[10];
    sprintf(b, "%ld", last_sent);
    Serial.print("Sending ");
    Serial.print(millis());
    Serial.print(": ");
    Serial.println(b);
    last_sent = millis();
    // this works perfect sending a message:
    //ICSC.send(slaveAddress, demoCommand, 10, b);

    String saveString = String(slaveAddress) + ";" + String(demoCommand) + ";" + String(b);
    Serial.print("SaveString: "); Serial.println(saveString);
    char saveChar[saveString.length() + 1];
    saveString.toCharArray(saveChar, saveString.length() + 1);
    char recT[3];
    char comT[3];
    char datT[saveString.length() + 1];

    // slow way instead of strtok ;-/    
    int var = 0; 
    int recInt = 0;
    int comInt = 0;
    int datInt = 0;
    String strRec, strCom, strDat;
    for(int i = 0; i < sizeof(saveChar); i++){
      //Serial.print("current i: "); Serial.print(i);
      if(saveChar[i] != ';'){
        //Serial.print(" var: "); Serial.print(var);
        //Serial.print(" current character: "); Serial.println(saveChar[i]);
        switch (var){
          case 0:
            strRec += saveChar[i];
            recInt++;
            break;
          case 1:
            strCom += saveChar[i];
            comInt++;
            break;
          case 2:
            strDat += saveChar[i];
            datInt++;
            break;   
          }         
       } else {
         //Serial.print(" current character: "); Serial.println(saveChar[i]);
         var++;
      }
      
    }
    
/*  
    //This is the approach I left behind:
    char recPointer[] = strtok(saveChar, stringSeparator);
    int comPointer = strtok(NULL, stringSeparator);
    
    char *rec= {strtok(saveChar, stringSeparator)};
    char recChar[] = { rec, "\0"};
    char com[] = {strtok(NULL, stringSeparator)};
    //char len[] = strtok(NULL, stringSeparator)};
    char dat[] = {strtok(NULL, stringSeparator)};
*/
    
    // this looks correct as far as I can see in serial debugging:
    Serial.print(recInt); Serial.print(":");
    Serial.print(strRec); 
    Serial.print("-");
    Serial.print(comInt); Serial.print(":");
    Serial.print(strCom); 
    Serial.print("-");
    Serial.print(datInt); Serial.print(":");
    Serial.print(strDat); 
    Serial.println("");

    char charRec[strRec.length()+1];
    strRec.toCharArray(charRec, strRec.length()+1);
    int newRec = atoi(charRec);
    char newCom[strCom.length()+1];
    strCom.toCharArray(newCom, strCom.length()+1);
    newCom[strCom.length()+1] = '\n';
    char* newDat;
    strDat.toCharArray(newDat, strDat.length()+1);    
    newDat[strDat.length()+1] = '\n';
    // sending a message here doesn't work ;-(
    ICSC.send(newRec, newCom[0], strDat.length(), *newDat);
    //This is the approach I left behind:
    char recPointer[] = strtok(saveChar, stringSeparator);

The strtok() function returns a pointer, NOT an array. While there are similarities, strtok() does NOT allocate space for the array. It returns a pointer to an existing allocation of memory.

    int comPointer = strtok(NULL, stringSeparator);

It doesn't return an int, either.

    char *rec= {strtok(saveChar, stringSeparator)};

I have no idea what you think this is doing...

    char charRec[strRec.length()+1];
    strRec.toCharArray(charRec, strRec.length()+1);
    int newRec = atoi(charRec);

Why not simply use

int newRec = strRec.toInt();
    char* newDat;
    strDat.toCharArray(newDat, strDat.length()+1);

newDat does NOT point to any memory that you are allowed to write to. You have NO idea what value is in newDat, so you have no idea what memory you just shit on.

    // sending a message here doesn't work ;-(
    ICSC.send(newRec, newCom[0], strDat.length(), *newDat);

Well, of course not. You really do not seem to know what you are doing.

Dear PaulS,

thank you so much for your help! Although for some people to use chars, pointers and that kind of stuff seems to be very clear, for me it is not fully understood. Unfortunately. I know, some of my approaches seem to be a poor try, but if it would be clear and obvious for me how to handle it I wouldn’t post this question :wink:
I hope you forgive me my basic understanding of chars.

Would you mind giving me a hint how to solve the problem of newDat?
This is the main message, which can contain 1 to 200 characters and is basically the last item in the string with separators.

Again thank you very much,

curtino

Ok, I worked on this issue again, so I got a lot further. But still there is this problem with chars and unsigned chars and so on. Does anyone has a clou what is wrong here?

I get the int number from a String:

String strRec

and I have to inject it in a unsigned char in the following function as first argument:

void sendMessage(unsigned char src, char command, char *data, bool ackMsg){

Surprisingly, this line with an equal function and equal arguments is working fine…:

ICSC.send(newRec, newCom[0], strDat.length()+1, newDat);

How to cast a String or an int to an unsigned Char???

Thank you so much for your help,

curtino

PS: Here is the complete code to check:

void reSendData(){
  if(millis() > lastReSend + reSendCycle && QUEUE_NUMBER > 0){
    
    char unfoldChar[queueDataString[0].length() + 1];
    queueDataString[0].toCharArray(unfoldChar, queueDataString[0].length() + 1);
    
    int var = 0; 
    int recInt = 0;
    int comInt = 0;
    int datInt = 0;
    String strRec, strCom, strDat;
    for(int i = 0; i < sizeof(unfoldChar); i++){
      // Serial.print("current i: "); Serial.print(i);
      if(unfoldChar[i] != ';'){
        // Serial.print(" var: "); Serial.print(var);
        // Serial.print(" current character: "); Serial.println(saveChar[i]);
        switch (var){
          case 0:
            strRec += unfoldChar[i];
            recInt++;
            break;
          case 1:
            strCom += unfoldChar[i];
            comInt++;
            break;
          case 2:
            strDat += unfoldChar[i];
            datInt++;
            break;   
          }         
       } else {
         //Serial.print(" current character: "); Serial.println(saveChar[i]);
         var++;
      }  // if end
    } // for end

    // prepare vars for sending:
    //int newRec = strRec.toInt();
    unsigned char newRec;
    strRec.toCharArray(newRec, strRec.length()+1);
    char newCom[strCom.length()+1];
    strCom.toCharArray(newCom, strCom.length()+1);
    char newDat[strDat.length()+1];
    strDat.toCharArray(newDat, strDat.length()+1);  
    
    //ICSC.send(newRec, newCom[0], strDat.length()+1, newDat); // this line is working though!!
    sendMessage(newRec, newCom[0], strDat.length()+1, newDat, true);

    //delete sent data from queue list:
    rearrangeArray(0);
  } // if time end
}

void sendMessage(unsigned char src, char command, char *data, bool ackMsg){
  ICSC.send(src, command, data);
  // if Acknowledgement is expected save data to compare:
  if(ackMsg){
    saveSentData(src, command, data);
  }
}

How to cast a String or an int to an unsigned Char???

You can NOT cast a String as an unsigned char.

I really have no idea what idiot decided that the type of the argument should be unsigned char. But, all that really means is that the value of the first argument needs to be in the range 0 to 255, which is exactly the range of a byte or of a uint8_t. The byte type is non-standard, but the uint8_t type is standard.

So, the function REALLY should have declared that the argument type is uint8_t.

But, they didn't. So, what do you need to do when what you have is an int? Nothing. An implicit cast will be performed for you.

   int x = 14;
   ICSC.send(x, ...

will work perfectly well. (As long as you supply proper data for the rest of the arguments, that is.)