How to use strstr with an if statement more efficiently

Hi,

I am building my own version of a weather station and as I will be performing lots of data logging, I have configured a real time clock in both the external and internal units.

To ensure both ends are synchronised properly, I have written a function which sends a time string to the external unit, which is then received and using the "strstr" command, separated by finding a keyword (setT) and the results placed into a char array. This array is then used to update the external units RTC to be the same as the internal unit.

This all works properly and is fairly robust.

For information, the radio system is using the nRFL2410I.

However, it has occurred to me that I can use this code to control and do other things, so I have introduced an "if" statement, listing a second keyword.

This also works properly.

So here is my question.

You will see in the code, where I state, "// Do the whole thing again for second keyword search on the same received data", is there a smarter way of performing this?

/*-----------------------------------------------------------------*/

void receiveData() {

    char  receivedDataString[32];               // Char string to store received data.

    radio.startListening();                     // Now, resume listening so we catch the next packets.

    if (radio.available()) {

        while (radio.available()) {             // While there is data ready.
            radio.read(&receivedDataString, sizeof(receivedDataString));   // Get the payload.
        }

        if (!debug == false) {                  // Serial print the received data to check consistency.

            Serial.println();
            Serial.println(F("Time data received: "));
            Serial.println();
            Serial.println(receivedDataString);
            Serial.println();

        }

        char keyword1[] = "setT";                                               // Set first keyword.
        char* pointerToFoundData1 = strstr(receivedDataString, keyword1);       // Check for first keyword.

        if (pointerToFoundData1 != NULL) {                                      // Was it found?

            int positionInString = pointerToFoundData1 - receivedDataString;    
            strncpy(receivedDataString, &receivedDataString[positionInString + strlen(keyword1)], sizeof(receivedDataString));

            const char delimiter[] = ",";                                       // Ser delimiter.
            char stString[10][5];
            char* token = strtok(receivedDataString, delimiter);                // Search for delimiter.
            strncpy(stString[0], token, sizeof(stString[0]));

            for (int i = 1; i < 10; i++) {                                      // Do the same for each found delimiter.
                token = strtok(NULL, delimiter);
                strncpy(stString[i], token, sizeof(stString[i]));
            }

            for (int i = 0; i < 10; i++) {                                      // Print out the results.
                Serial.print("Set time string: ");
                Serial.println(stString[i]);
            }
            
            // Data is received in this format: setT,h,21,m,44,D,20,M,09,Y,2020.

            yearSet = atoi(stString[9]);                                        // Update time setting variables.
            monthSet = atoi(stString[7]);
            daySet = atoi(stString[5]);
            minSet = atoi(stString[3]);
            hourSet = atoi(stString[1]);

            // Use data to set DS3231 RTC module.

            rtc.adjust(DateTime(yearSet, monthSet, daySet, hourSet, minSet, 0));// Send updated variables to RTC module.

            if (!debug == false) {                               // Serial print the received data to check consistency.

                DateTime now = rtc.now();

                rtcArray[6] = now.year();
                rtcArray[5] = now.month();
                rtcArray[4] = now.day();
                rtcArray[3] = now.dayOfTheWeek(); //returns 0-6 where 0 = Sunday.
                rtcArray[2] = now.hour();
                rtcArray[1] = now.minute();
                rtcArray[0] = now.second();

                char* dayOfTheWeek = (dayArray[rtcArray[3]]);      // returns actual day of the week.
                char* monthOfTheYear = (monthArray[rtcArray[5]]);  // returns actual month of the year.

                sprintf_P(TimeAndDateString, PSTR("%02d:%02d on %s %02d %s %02d"), rtcArray[2], rtcArray[1], dayOfTheWeek, rtcArray[4], monthOfTheYear, rtcArray[6]);
                Serial.println();
                Serial.println("Time and Date have been set to: ");
                Serial.println();
                Serial.println(TimeAndDateString);

            }

            else { Serial.println("No setT keyword found..."); }

        }

        // Do the whole thing again for second keyword search on the same received data.

        char keyword2[] = "Blah";
        char* pointerToFoundData2 = strstr(receivedDataString, keyword2);

        if (pointerToFoundData2 != NULL) {

            int positionInString = pointerToFoundData2 - receivedDataString;
            strncpy(receivedDataString, &receivedDataString[positionInString + strlen(keyword2)], sizeof(receivedDataString));

            const char delimiter[] = ",";
            char blahString[10][5];
            char* token = strtok(receivedDataString, delimiter);
            strncpy(blahString[0], token, sizeof(blahString[0]));

            for (int i = 1; i < 10; i++) {
                token = strtok(NULL, delimiter);
                strncpy(blahString[i], token, sizeof(blahString[i]));
            }

            for (int i = 0; i < 10; i++) {
                Serial.print("Set time string: ");
                Serial.println(blahString[i]);
            }

        }

        else { Serial.println("No Blah keyword found..."); }
    }

} // Close function.

/*-----------------------------------------------------------------*/

I would make the function receiveData() very short - just what is needed to receive a message and save it.

Then I would create another function to parse the received data. It, in turn, might call one or more functions depending on the content of the message.

I presume you have also written the code that sends the wireless data. If so one of the major attractions of the nRF24 is that you can send a struct and receive the data into a similar struct which avoids most (if not all) of the need to parse the received data.

Please post an example of the messages that you are sending.

...R
Simple nRF24L01+ Tutorial

Thanks for your swift response, always appreciated.

As for structs, in my Arduino programming journey which I started at the beginning of Covid, I haven't gotten into them as yet....

Sending code is two functions, the first prepares the data, while the second sends it as follows:

/*-----------------------------------------------------------------*/

void rtcFunction() {

    DateTime now = rtc.now();

    nextDataLog = (now.minute());

    Serial.println();
    Serial.println(F("Current Time / Date is: "));

    rtcArray[6] = now.year();
    rtcArray[5] = now.month();
    rtcArray[4] = now.day();
    rtcArray[3] = now.dayOfTheWeek(); //returns 0-6 where 0 = Sunday.
    rtcArray[2] = now.hour();
    rtcArray[1] = now.minute();
    rtcArray[0] = now.second();

    sprintf_P(setTimeDateString, PSTR("setT,h,%02d,m,%02d,D,%02d,M,%02d,Y,%02d"), rtcArray[2], rtcArray[1], rtcArray[4], rtcArray[5], rtcArray[6]);
    Serial.println();
    Serial.println(setTimeDateString);


} // Close function.

/*-----------------------------------------------------------------*/

Then:

/*-----------------------------------------------------------------*/

void transmitTimeData() {

    radio.stopListening();                                  // First, stop listening so we can talk.

    Serial.print(F("Now sending time data: "));
    Serial.println(setTimeDateString);

    if (!radio.write(&setTimeDateString, sizeof(setTimeDateString))) {
        Serial.println(F("Data send failed..."));
    }

    radio.startListening();

} // Close function.

/*-----------------------------------------------------------------*/

P.S. I have your nRF24 tutorial and some of your others, they are great so thanks for those also.

c_m_cooper:
rtcArray[6] = now.year();
rtcArray[5] = now.month();
rtcArray[4] = now.day();
rtcArray[3] = now.dayOfTheWeek(); //returns 0-6 where 0 = Sunday.
rtcArray[2] = now.hour();
rtcArray[1] = now.minute();
rtcArray[0] = now.second();

sprintf_P(setTimeDateString, PSTR("setT,h,%02d,m,%02d,D,%02d,M,%02d,Y,%02d"), rtcArray[2], rtcArray[1], rtcArray[4], rtcArray[5], rtcArray[6]);

Don't bother with the sprintf() stuff.

Just send the array and receive it into a similar array

radio.write(&rtcArray, sizeof(rtcArray));

...R

You are making this much more difficult than it needs to be, send the time in unix time format. There is also no need to convert the data to text.

Do not get caught up in the idea that the data must be human-readable, using a keyword to indicate which type data is being sent is very inefficient, a single byte can contain a number indicating which type data is present.

Hi,

Thanks all, I will do some more reading.