-1

I am trying to create a software lighting desk by using Qt and Arduino with a DMX Shield. I've been able to establish communication between these two and can send commands over to Arduino Mega (at the moment the communication goes only one way). I am periodically (every 200 ms) sending values of 11 faders to Mega as a String.

eg.: A123 B234 C050 ... J222 M255

The values in the string above are variables based on the position of the sliders and should be used to adjust the values of light intensities saved into each fader on the Mega side. The Letters in each section identify corresponding fader. A = fader1, B = fader2, ... Just for clarity: I can bring up a light/s at a specific intensity -> these intensities are then assigned to a fader and when that fader is moved I want these values to adjust and be sent out to the actual lights/dimmers. The calculations work fine but my Mega would eventually become unresponsive.

I think my problem is parsing the incoming string. I have tried the strtok() method and readStringUntil() to no avail. It is also difficult to monitor the incoming strings in Serial Monitor as this is used for the communication with Qt.

Would be happy for any kind of help. Please ask questions if anything is unclear.

Edit:

This is one of my attempts at solutions

const char delim[2] = " ";
char *token;

if(Serial.available())
{
    //incomingMessage = Serial.readString();
    incomingMessage = Serial.readStringUntil("\n");     // read the whole string until newline
    //Serial.println(incomingMessage);
    const char* str = incomingMessage.c_str();          // convert it to a C String terminated by a null character "\0"
    //Serial.println(str);
    token = strtok(str, delim);                         // first part is a first section until delimiter occurs "-space- "

    //Serial.println(token);
    LX_Rated.commandLineResolve(token);                 // resolve it

    while( token != NULL ) {                            // continue splitting and resolving the incoming message until it reaches the end
      token = strtok(NULL, delim);
      LX_Rated.commandLineResolve(token);
    }


}

Edit2:

I have confirmed that I receive the whole string sent by Qt. When I try to tokenise it using the strtok() function and print out the first token I get back the whole string, the other tokens are empty. I don't see any mistake in my code here. I even tried to slow down the sending of the string from Qt to one per 5 sec. Does anybody have any idea what is going on? I don't see why this standard function doesn't work as expected. Please see the amended code below.

if(Serial.available()) {
        incomingMessage = Serial.readStringUntil("\n");
        Serial.println("ok");
        Serial.flush();

        char* nullTerminatedIncomingMessage = incomingMessage.c_str();
        const char delimiter = " ";
        char* token;
        char* token1;
        char* token2;
        //char* secondToken;

        token = strtok(nullTerminatedIncomingMessage, delimiter);
        token1 = strtok(NULL, delimiter);
        token2 = strtok(NULL, delimiter);
        Serial.println(token);              // print the first section
        //Serial.println(incomingMessage);
        Serial.flush();
        Serial.println(token1);
        Serial.flush();
        Serial.println(token2);
        Serial.flush();
        //while(token != NULL)
        //    secondToken = strtok(NULL, delimiter);

        //Serial.println(secondToken);
        //Serial.flush();
        incomingMessage = "";

    }
Zedd1983
  • 11
  • 2

2 Answers2

0

As for difficulty in monitoring communication, you can(in Qt) dump everything you read into console and do the same for everything you write into the serial port. It will show in the console tab of QtCreator

#include <QDebug>
...
qDebug() << "whatever" << endl;

Aso for parsing the data you read from to serial port, take a look at this to see how to easily split the sliders info into individual strings(with QRegExp) How Can I Split a String According To Delimiters in Qt?

I can't possibly guess why your arduino would be unresponsive without the code.

EDIT: Is it possible, when you generate the string in Qt, that you separate the tokens by something other than space? Maybe tab("\t") or something? strtok accepts multiple delimiters in the delimiter string, may be something to try. If that is not the case, there is the unlikely possibility that something's wrong with the strtok(...) function(btw. it modifies the original string, that in itself could be a problem). Also, strtok could return a NULL pointer, you don't seem to handle that case(some wrong input - print a message). You could try this as an alternative to normal strtok:

/**
 * @brief custom strtok replacement with the same interface
 * It does not modify the original string
 * Token length is limited to 63 characters
 * @param ptr pointer to the string or NULL
 * @param delim delimiting character(only the first character will be used)
 */
const char * my_strtok(const char * ptr, const char * delim) {
    // Persistent variables, it will remember pointer to the processed string
    static const char * src;
    static char buffer[64]; // Token is limited to 63 characters

    if(ptr) { // Remember the pointer, if a new one was supplied
        src = ptr;
    }

    if(src == NULL || *src == '\0')// Invalid / empty string / no next token - return NULL
        return NULL;

    char i = 0;
    for(i = 0; i < 63 && *src != delim[0]; i++) {// Copy token until delimiter or end of buffer
        buffer[i] = *(src++);
    }

    if(*src == delim[0]) // Skip over the delimiter to the begining of the next token
        ++src;

    buffer[i] = '\0'; // Any returned string must be terminated
    return buffer;
}

#include <cstdlib>
#include <cstring>
#include <cassert>
void test() {
    const char * str1 = "123 456 asdf jkl;";
    assert(strcmp("123", my_strtok(str1, " ")) == 0);
    assert(strcmp("456", my_strtok(NULL, " ")) == 0);
    assert(strcmp("asdf", my_strtok(NULL, " ")) == 0);
    assert(strcmp("jkl;", my_strtok(NULL, " ")) == 0);
    assert(NULL == my_strtok(NULL, " "));
    assert(NULL == my_strtok(NULL, " "));
    assert(strcmp("123", my_strtok(str1, " ")) == 0);

}
Martin
  • 333
  • 1
  • 8
  • I am already using qDebug() and I can see the string being sent to Arduino. I can also see in Atom editor that I use for the Arduino side of things that the string reaches the Arduino but because I try to Serial.print the incoming message while also writing into the Serial by Qt every 200ms they seem to compete and eventually this seems to lead to loss of connection and the unresponsiveness. – Zedd1983 Mar 28 '18 at 15:23
  • Ok, try to use your _Serial.println(str);_ again and _Serial.flush()_ after every one of them - it will block execution until the output serial buffer is empty - should delay the "hanging" until data is sent. That should work. Another possibility is to connect LED to the arduino and turn it on somewhere in the code to see where it hangs. – Martin Mar 28 '18 at 15:51
  • Incomming and outgoing data shold not compete, they are in separate buffers. - https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/HardwareSerial.h – Martin Mar 28 '18 at 16:00
  • If you are using the serial monitor in Atom and your Qt application that is also accessing the same serial port, than that is possibly the problem with serial connection(if it works at all). You should pick one or the other, or possibly use 2 serial ports - one for debuging, the other for data(some Arduinos have more than one) – Martin Mar 28 '18 at 16:12
  • I have now confirmed that i am getting the full string, however I am unable to parse it. I can't understand why the code above doesn't work as expected. When I print out the first token, the whole incoming message gets printed, the other tokens are empty. I don't see a mistake anywhere. Any idea what might be causing this? – Zedd1983 Apr 01 '18 at 09:33
0

Your mistake - at the very least - is in assuming that all the input is available when you expect it. You need to defer processing until an entire line has been assembled. Serial.readStringUntil blocks until an entire line is available, and that's not what you expect. You essentially need to replace Serial.available() with Serial.lineAvailable(), except the latter is not implemented.

This answer contains a complete solution to your issue - including both Qt and Arduino code - and an Arudino emulation layer. It might be a good starting point, especially that you can easily co-debug both Qt and Arduino projects from within one application and using one debugger!

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313