Serial.println() not sent to Qt application

Complimentary Qt Forum post: QSerialPort not reading from Arduino | Qt Forum

Hi. I have the following code on the Arduino Uno:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200); // usb port serial
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  //Collect data.
  bool readyRead = true;
  int i = 0;
  //Serial.println("Serial available.");
  if (Serial.available() > 0) {
    //Serial.println("Serial available.");
    i = msgReceiver('\n', readyRead); //msgReceiver is for turning the input to a char array. '\n' is end char. The output of msgReceiver is the char array position, so need to ++.
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); //This turns an LED on and off.
    messageArray[27] = '\0'; // terminate the string

    int msgLength = i + 1;

    for (i = msgLength; i > 22; i--) {  //messageArray[22] is the 2nd char of the checkSum. Should not be ablated.
      messageArray[i] = '\0';
    }
    bool canSend = true;

    char checkSumCharacters[2] = {messageArray[i - 1], messageArray[i]}; //Values are ascii code of the base16 numbers.
    int receivedCheckSum = strtoul(checkSumCharacters, NULL, 16);  //Converts the base16 characters to an int.

    int checkSum = checkSumGenerator(messageArray);

    for (i = 0; i < sizeof(cmdtarget); i++) { //Length of cmdtarget is 5.
      cmdtarget[i] = messageArray[i];
    }
    cmdtarget[5] = '\0';
    for (i = 0; i < sizeof(input_cmdtype) - 1; i++) { //Length of cmdtype is 5.
      input_cmdtype[i] = messageArray[i + 6];
    }
    input_cmdtype[5] = '\0';
    for (i = 0; i < sizeof(input_cmdparam) - 1; i++) { //Length of cmdparam is 8.
      input_cmdparam[i] = messageArray[i + 12];
    }
    input_cmdparam[8] = '\0';
    //An attempt at a function pointer to be called for rtnProtocols. Pointer used to decrease negative effects of conditionals.
    stringFunction *rtnpointer[] = {
      FIRMV_F, VALCN_F, RQSPC_F, CTFTC_F, LIDVM_F, LIDVC_F, PREVC_F, STPWM_F, CHPWM_F, STPER_F, CHPER_F, CHIGH_F, SHIGH_F, MOTST_F, MHIGH_F, MTRTT_F,
      RCTIC_F, RCTGM_F, RCTGC_F, SAVEA_F, PREST_F, PREND_F, RQPRE_F, CLPRE_F, RQDAT_F, CUPTC_F, LIDTC_F, CURPR_F, CUPTT_F, CDATE_F, CTIME_F, SDATE_F, RDTTM_F,
      SPROG_F, SLOAD_F, CUFAC_F, LIFAC_F, STFAC_F, MTFAC_F, PPFAC_F, PCOFF_F, CUPFM_F, CUPFC_F, LIDFM_F, LIDFC_F, PREFC_F, FCPWM_F, FCPER_F, FHIGH_F,
    };

    input in = convert(input_cmdtype);  //Using the char to enum converter.
    canSend = errorStack(cmdtarget, receivedCheckSum, checkSum, msgLength, in, canSend);

    if (canSend) {
      char verak[6] = "VERAK";
      rtnProtocols(verak, input_cmdparam);

      rtnpointer[in](input_cmdtype, input_cmdparam);
    }
  }
}

//Reads message.
int msgReceiver(char endMarker, bool readyRead) {
  char rc;
  int ndx = 0;
  while (readyRead == true) {
    if (Serial.available() > 0) {
      rc = Serial.read();
      if (rc != endMarker) {
        messageArray[ndx] = rc;
        ndx++;
      }
      else if (rc == endMarker) {
        messageArray[ndx] = '\0'; // terminate the string
        //Serial.println("Received \n.");
        rc = 0;
        readyRead = false;
      }
      else {
        readyRead = true;
      }
    }
  }
  return ndx;
}

//Function write back to PC
void rtnProtocols(char cmdtype[], char cmdparam[]) {
  char outputString[28] = "TOWST_";
  strcat (outputString, cmdtype);
  strcat (outputString, "_");
  strcat (outputString, cmdparam);
  strcat (outputString, "_");

  int outputCheckSum = checkSumGenerator(outputString);
  char outputCheckSumHex[3] = "00";
  itoa (outputCheckSum, outputCheckSumHex, 16);
  if (outputCheckSum < 16) { //Adds a 0 if CS has fewer than 2 numbers
    outputCheckSumHex[1] = outputCheckSumHex[0];
    outputCheckSumHex[0] = '0';
  }
  outputCheckSumHex[0] = toupper (outputCheckSumHex[0]);
  outputCheckSumHex[1] = toupper (outputCheckSumHex[1]);
  strcat (outputString, outputCheckSumHex); //Now displayed in base16
  outputString[23] = {'\r'}; //Not displayed in port. This should be happening, I think.
  outputString[24] = {'\n'};

  Serial.write(outputString);
}

(The full code will be at the bottom of this post)

When I send a message through to the Arduino code from the Arduino serial monitor, the code does successfully process the message and return it on the Arduino serial monitor. However, when sending messages through to the code via a custom Qt application, the code no longer processes the message and returns it to the Qt application at baud rates higher than 9600.

My Qt code, if it helps:

//attempts a connection with the next device in the list of available ports
void DeviceConnection::connectDevice()
{
    serialPort_Controller->close();
    portsAvailable = QSerialPortInfo::availablePorts();
    qDebug() << "connecting";
    qDebug() << portsAvailable.count();
    QSerialPortInfo port;
    if (currentPosInList < portsAvailable.count())
    {
        portName = portsAvailable.at(currentPosInList).portName();
        qDebug() << portName;
        serialPort_Controller->setPortName(portName);     //My computer
        serialPort_Controller->setBaudRate(115200);
        serialPort_Controller->setDataBits(QSerialPort::Data8);
        serialPort_Controller->setParity(QSerialPort::NoParity);
        serialPort_Controller->setStopBits(QSerialPort::OneStop);
        serialPort_Controller->setFlowControl(QSerialPort::SoftwareControl);
        currentPosInList++;
        if(serialPort_Controller->open(QIODevice::ReadWrite))
        {
            qDebug() << "Connected";
            int i = serialPort_Controller->write("TOPIC_VALCN_00000000_48\r\n");    //"TOPIC_VALCN_00000000_48\r\n"
            qDebug() << i;
            qDebug() << "TOPIC_VALCN_00000000_48\r\n";
        }
        else
        {
            qDebug() << "Connection error";
        }
        if (!serialPort_Controller->isOpen())
        {
            qDebug() << "Cannot open controller serial port";
        }
    }
    else
    {
        currentPosInList = 0;
    } 
}

//received messages get processed here into the correct format
void DeviceConnection::serialReady()
{
    QString allReceived = QString(serialPort_Controller->readAll());

    //    if (SystemSettings::get()->getValue(PROTOCOL_DEBUG_MODE) == "1")
    //        backSerialPort->write(allReceived.toUtf8());
    qDebug() << "recieved messages: " << allReceived;
    allReceived = incomingRemainder + allReceived;

    QStringList fullMessages = allReceived.split("\r\n");
    incomingRemainder = fullMessages.last();
    fullMessages.removeLast();

    foreach (QString message, fullMessages) {
        //qDebug() << message; For seeing the message on debugs.
        emit receivedMessage(message);
    }
}

Things I've attempted, two of which kinda worked:

1: Changing the data bits and baud rates. Changing the databits did not work, but changing the baud rate to 9600 worked.

2: Using a different Uno. That did not work and the same problem persisted.

3: Adding a delay here:

void loop() {
  //Collect data.
  //char endMarker = '\n';
  bool readyRead = true;
  int i = 0;
  //digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  //Serial.println("Serial available.");
  if (Serial.available() > 0) {
    //Serial.println("Serial available.");
    i = msgReceiver('\n', readyRead); //msgReceiver is for turning the input to a char array. '\n' is end char. The output of msgReceiver is the char array position, so need to ++.
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); //This turns an LED on and off.
    messageArray[27] = '\0'; // terminate the string
    delay(200);

This did not work.

4: Adding another Serial.println here:

void loop() {
  //Collect data.
  //char endMarker = '\n';
  bool readyRead = true;
  int i = 0;
  //digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  //Serial.println("Serial available.");
  if (Serial.available() > 0) {
    //Serial.println("Serial available.");
    i = msgReceiver('\n', readyRead); //msgReceiver is for turning the input to a char array. '\n' is end char. The output of msgReceiver is the char array position, so need to ++.
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); //This turns an LED on and off.
    messageArray[27] = '\0'; // terminate the string
    Serial.println("11111");

This worked. I don't know why.

I have looked into the Serial.println documentation and was unable to find anything apparently relevant to this situation. Please let me know if more information is required.

Full code:

#define EXPECTED_MSGLENGTH 25   //23 char message, plus '/r' and '/n', each 1 char in length.

char input_cmdtype[6]; //The 5-letter command
char input_cmdparam[9]; //The 8-digit data thingy
char messageArray[28];
char cmdtarget[6];

typedef void stringFunction(char cmdtype[6], char cmdparam[9]); //Update this, update the switch-case file, update the converter, and add the function
enum input {FIRMV, VALCN, RQSPC, CTFTC, LIDVM, LIDVC, PREVC, STPWM, CHPWM, STPER, CHPER, CHIGH, SHIGH, MOTST, MHIGH, MTRTT, RCTIC, RCTGM,
            RCTGC, SAVEA, PREST, PREND, RQPRE, CLPRE, RQDAT, CUPTC, LIDTC, CURPR, CUPTT, CDATE, CTIME, SDATE, RDTTM, SPROG, SLOAD, CUFAC, LIFAC,
            STFAC, MTFAC, PPFAC, PCOFF, CUPFM, CUPFC, LIDFM, LIDFC, PREFC, FCPWM, FCPER, FHIGH, INVAL
           };

input convert(char str[]) { //A char to enum converter.
  switch (str[0]) {
    case 'C':
      if (str[1] == 'U') {
        if (strcmp (str, "CUPTC") == 0) return CUPTC;
        else if (strcmp (str, "CURPR") == 0) return CURPR;
        else if (strcmp (str, "CUPTT") == 0) return CUPTT;
        else if (strcmp (str, "CUFAC") == 0) return CUFAC;
        else if (strcmp (str, "CUPFM") == 0) return CUPFM;
        else if (strcmp (str, "CUPFC") == 0) return CUPFC;
      }
      else if (str[1] == 'H') {
        if (strcmp (str, "CHPER") == 0) return CHPER;
        else if (strcmp (str, "CHIGH") == 0) return CHIGH;
        else if (strcmp (str, "CHPWM") == 0) return CHPWM;
      }
      else if (strcmp (str, "CLPRE") == 0) return CLPRE;
      else if (strcmp (str, "CDATE") == 0) return CDATE;
      else if (strcmp (str, "CTIME") == 0) return CTIME;
      else if (strcmp (str, "CTFTC") == 0) return CTFTC;
      else return INVAL;
      break;
    case 'F':
      if (strcmp (str, "FIRMV") == 0) return FIRMV;
      else if (strcmp (str, "FCPWM") == 0) return FCPER;
      else if (strcmp (str, "FCPER") == 0) return FCPER;
      else if (strcmp (str, "FHIGH") == 0) return FHIGH;
      else return INVAL;
      break;
    case 'L':
      if (str[2] == 'D') {
        if (strcmp (str, "LIDVM") == 0) return LIDVM;
        else if (strcmp (str, "LIDVC") == 0) return LIDVC;
        else if (strcmp (str, "LIDTC") == 0) return LIDTC;
        else if (strcmp (str, "LIDFM") == 0) return LIDFM;
        else if (strcmp (str, "LIDFC") == 0) return LIDFM;
      }
      else if (strcmp (str, "LIFAC") == 0) return LIFAC;
      else return INVAL;
      break;
    case 'P':
      if (str[1] == 'R') {
        if (strcmp (str, "PREVC") == 0) return PREVC;
        else if (strcmp (str, "PREST") == 0) return PREST;
        else if (strcmp (str, "PREND") == 0) return PREND;
        else if (strcmp (str, "PREFC") == 0) return PREFC;
      }
      else if (strcmp (str, "PPFAC") == 0) return PPFAC;
      else if (strcmp (str, "PCOFF") == 0) return PCOFF;
      else return INVAL;
      break;
    case 'S':
      if (str[1] == 'T') {
        if (strcmp (str, "STFAC") == 0) return STFAC;
        else if (strcmp (str, "STPER") == 0) return STPER;
        else if (strcmp (str, "STPWM") == 0) return STPWM;
        else if (strcmp (str, "STFAC") == 0) return STFAC;
      }
      else if (strcmp (str, "SHIGH") == 0) return SHIGH;
      else if (strcmp (str, "SDATE") == 0) return SDATE;
      else if (strcmp (str, "SPROG") == 0) return SPROG;
      else if (strcmp (str, "SLOAD") == 0) return SLOAD;
      else if (strcmp (str, "SAVEA") == 0) return SAVEA;
      else return INVAL;
      break;
    case 'R':
      if (str[1] == 'Q') {
        if (strcmp (str, "RQSPC") == 0) return RQSPC;
        else if (strcmp (str, "RQPRE") == 0) return RQPRE;
        else if (strcmp (str, "RQDAT") == 0) return RQDAT;
      }
      if (str[1] == 'C') {
        if (strcmp (str, "RCTIC") == 0) return RCTIC;
        else if (strcmp (str, "RCTGM") == 0) return RCTGM;
        else if (strcmp (str, "RCTGC") == 0) return RCTGC;
      }
      else if (strcmp (str, "RDTTM") == 0) return RDTTM;
      else return INVAL;
      break;
    case 'M':
      if (strcmp (str, "MTFAC") == 0) return MTFAC;
      else if (strcmp (str, "MOTST") == 0) return MOTST;
      else if (strcmp (str, "MHIGH") == 0) return MHIGH;
      else if (strcmp (str, "MTRTT") == 0) return MTRTT;
      else return INVAL;
      break;
    case 'V':
      if (strcmp (str, "VALCN") == 0) return VALCN;
      else return INVAL;
      break;
    default:
      return INVAL;
  }
}

//Executing protocols.

void FIRMV_F(char output_cmdtype[], char output_cmdparam[]) { //Get firmware version number
  strcpy(output_cmdparam, "01050A00");  //In the unlikely event strcpy stops working, switch to strncpy().
  //Serial.println(output_cmdparam);
  rtnProtocols(output_cmdtype, output_cmdparam); //Combines TOWST, cmdtype, cmdparam, generates a CS, then adds \r\n. See desktop code for reason why output_cmdparam is what it is.
}

void VALCN_F(char output_cmdtype[], char output_cmdparam[]) { //Get Connection verification
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void RQSPC_F(char output_cmdtype[], char output_cmdparam[]) { //Get device information (i.e. serial num, last date calibrated, etc. See protocol doc for full list.)
  strcpy(output_cmdtype, "GVSPC");    //Send device info signal
  strcpy(output_cmdparam, "00101201");  //cmdparam is serial number
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam,  "30082022");  //cmdparam is date of lid calibration
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam,  "16062019");  //cmdparam is date of cup calibration
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam,  "01072003");  //cmdparam is date of pressure calibration
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdtype, "ENSPC");    //Send device info signal.
  strcpy(output_cmdparam, "00000000");
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void CTFTC_F(char output_cmdtype[], char output_cmdparam[]) { //Get m value for lid temperature calibration
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void LIDVM_F(char output_cmdtype[], char output_cmdparam[]) { //Get m value for lid temperature calibration
  strcpy(output_cmdtype, "LIDVM");
  strcpy(output_cmdparam, "3F7DBA0A");
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void LIDVC_F(char output_cmdtype[], char output_cmdparam[]) { //Get c value for lid temperature calibration
  strcpy(output_cmdparam, "3F7DBA0A");
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void PREVC_F(char output_cmdtype[], char output_cmdparam[]) { //Get calibration constant c for pressure
  strcpy(output_cmdparam, "3F7DBA0A");
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void STPWM_F(char output_cmdtype[], char output_cmdparam[]) { //Sets the PWM of the air pump
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void CHPWM_F(char output_cmdtype[], char output_cmdparam[]) { //Instructs the air pump to turn on with the PWM value specified
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void STPER_F(char output_cmdtype[], char output_cmdparam[]) { //Set the percentage value of the stirrer
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void CHPER_F(char output_cmdtype[], char output_cmdparam[]) { //Instructs the stirrer to turn on with the percentage specified
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void CHIGH_F(char output_cmdtype[], char output_cmdparam[]) { //Requests the device to change the stepper motor to move the cup to the appropriate height
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void SHIGH_F(char output_cmdtype[], char output_cmdparam[]) { //Sets the given height to be the height the cup goes to during a test
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void MOTST_F(char output_cmdtype[], char output_cmdparam[]) { //Starts the cup motor to keep going up
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void MHIGH_F(char output_cmdtype[], char output_cmdparam[]) { //Notifies the machine that the top has been reached
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void MTRTT_F(char output_cmdtype[], char output_cmdparam[]) { //Notifies the amount of time that’s taken the machine to reach the top
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void RCTIC_F(char output_cmdtype[], char output_cmdparam[]) { //Resistance calibration test is being conducted, returns detected resistance from calibration test
  long resistanceValue = strtol(output_cmdparam, NULL, 16);
  for (int repeat = 0; repeat < 5; repeat++) {
    //    resistanceValue = random(resistanceValue * 0.98, resistanceValue * 1.02); //Scrambles the resistanceValue slightly by up to 2%
    long long mCResistanceValue = random(1120, 1156) * resistanceValue / 1000 + random(23, 27);
    ltoa(mCResistanceValue, output_cmdparam, 16);
    //Serial.print("rV: ");
    //Serial.println(resistanceValue);
    //    Serial.print("mCRV: ");
    //    Serial.println(mCResistanceValue);
    //    Serial.print("The pre-memmove o_c is: ");
    //    Serial.println(output_cmdparam);
    int num_digits = log(mCResistanceValue) / log(16) + 1;
    //    Serial.print("num_digits: ");
    //    Serial.println(num_digits);
    memmove(&(output_cmdparam[8 - num_digits]), &(output_cmdparam[0]), num_digits);
    //    Serial.print("The pre-0 o_c is: ");
    //    Serial.println(output_cmdparam);
    for (int i = 1; i <= 8 - num_digits; i++)
      output_cmdparam[i - 1] = '0';
    strcpy(output_cmdtype, "RCTIC");
    //    Serial.print("The post-0 o_c is: ");
    //    Serial.println(output_cmdparam);
    rtnProtocols(output_cmdtype, output_cmdparam);
    delay(950);
  }
}

void RCTGM_F(char output_cmdtype[], char output_cmdparam[]) { //Sends the resistance calibration m value
  rtnProtocols(output_cmdtype, output_cmdparam);
  //Don't think we need to process the data in actual.
}

void RCTGC_F(char output_cmdtype[], char output_cmdparam[]) { //Sends the resistance calibration c value
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void SAVEA_F(char output_cmdtype[], char output_cmdparam[]) { //Sends the introduced air volume
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void PREST_F(char output_cmdtype[], char output_cmdparam[]) { //Send method pre-sets
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void PREND_F(char output_cmdtype[], char output_cmdparam[]) { //End of method pre-sets
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void RQPRE_F(char output_cmdtype[], char output_cmdparam[]) { //Request device pre-sets
  //char cmdparam[] = {output_cmdparam}; //Error is that char* shouldn't be converted to char. Why? Isn't cmdparam[] a char*
  char cmdparam[9];
  strcpy(cmdparam, output_cmdparam);  //Saving the output_cmdparam for later use.
  strcpy(output_cmdtype, "GVPRE");
  strcpy(output_cmdparam, "01000000"); //cmdparam is config name
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "02952751"); //cmdparam is start temp
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "03012019"); //cmdparam is end temp
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "04043321"); //cmdparam is temp rate
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "05121212"); //cmdparam is ignition frequency
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "06888888"); //cmdparam is pressure threshold
  rtnProtocols(output_cmdtype, output_cmdparam);

  strcpy(output_cmdtype, "ENPRE");
  strcpy(output_cmdparam, cmdparam);
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void CLPRE_F(char output_cmdtype[], char output_cmdparam[]) { //Delete all pre-sets on device
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void RQDAT_F(char output_cmdtype[], char output_cmdparam[]) { //Get results data
  strcpy(output_cmdtype, "GVDAT");
  strcpy(output_cmdparam, "01689689"); //A random output for date. CMBN, when the order itself is updated.
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "02777777"); //A random output for time
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "03198919"); //A random output for sample
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "04111111"); //A random output for method
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "05515151"); //A random output for flash
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "06141614"); //A random output for corrected flash
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "07070707"); //A random output for flashed?
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "08080808"); //A random output for start temp
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "09090909"); //A random output for temp rate
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "10101010"); //A random output for ignition frequency
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "11111111"); //A random output for pressure
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdparam, "12121212"); //A random output for pressure threshold
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdtype, "ENDAT");
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void CUPTC_F(char output_cmdtype[], char output_cmdparam[]) { //Get current cup temp
  strcpy(output_cmdparam, "C1CAE148");
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void LIDTC_F(char output_cmdtype[], char output_cmdparam[]) { //Get current lid temp
  strcpy(output_cmdparam, "C1CAE148");
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void CURPR_F(char output_cmdtype[], char output_cmdparam[]) { //Get current pressure
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void CUPTT_F(char output_cmdtype[], char output_cmdparam[]) { //Set cup temperature
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void CDATE_F(char output_cmdtype[], char output_cmdparam[]) { //Receive the date
  //rtnProtocols(output_cmdtype, output_cmdparam);
}

void CTIME_F(char output_cmdtype[], char output_cmdparam[]) { //Receive the date
  //rtnProtocols(output_cmdtype, output_cmdparam);
}

void SDATE_F(char output_cmdtype[], char output_cmdparam[]) { //Receive the date
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void RDTTM_F(char output_cmdtype[], char output_cmdparam[]) { //Receive the date
  strcpy(output_cmdtype, "CDATE");
  strcpy(output_cmdparam, "30082022");  //30th Aug, 2022
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdtype, "CTIME");
  strcpy(output_cmdparam, "15113800"); //15:11:38
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void SPROG_F(char output_cmdtype[], char output_cmdparam[]) { //Sets progress bar speed
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void SLOAD_F(char output_cmdtype[], char output_cmdparam[]) { //Sets loading circle speed
  rtnProtocols(output_cmdtype, output_cmdparam);
}


void CUFAC_F(char output_cmdtype[], char output_cmdparam[]) { //Factory reset the cup temperature calibration
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdtype, "CDATE");
  strcpy(output_cmdparam, "30082022");
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void LIFAC_F(char output_cmdtype[], char output_cmdparam[]) { //Factory reset the lid temperature calibration
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdtype, "CDATE");
  strcpy(output_cmdparam, "30082022");
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void STFAC_F(char output_cmdtype[], char output_cmdparam[]) { //Factory reset the stirrer calibration
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdtype, "CDATE");
  strcpy(output_cmdparam, "30082022");
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void MTFAC_F(char output_cmdtype[], char output_cmdparam[]) { //Factory reset the motor calibration
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdtype, "CDATE");
  strcpy(output_cmdparam, "30082022");
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void PPFAC_F(char output_cmdtype[], char output_cmdparam[]) { //Factory reset the pump calibration
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdtype, "CDATE");
  strcpy(output_cmdparam, "30082022");
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void PCOFF_F(char output_cmdtype[], char output_cmdparam[]) { //End any on-going process related to the desktop Software
  rtnProtocols(output_cmdtype, output_cmdparam);
  strcpy(output_cmdtype, "CNOFF");
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void CUPFM_F(char output_cmdtype[], char output_cmdparam[]) { //Factory setting cup M
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void CUPFC_F(char output_cmdtype[], char output_cmdparam[]) { //Factory setting cup C
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void LIDFM_F(char output_cmdtype[], char output_cmdparam[]) { //Factory setting lid M
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void LIDFC_F(char output_cmdtype[], char output_cmdparam[]) { //Factory setting lid C
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void PREFC_F(char output_cmdtype[], char output_cmdparam[]) { //Factory setting pressure C
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void FCPWM_F(char output_cmdtype[], char output_cmdparam[]) { //Factory setting pump PWM
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void FCPER_F(char output_cmdtype[], char output_cmdparam[]) { //Factory setting stirrer percentage
  rtnProtocols(output_cmdtype, output_cmdparam);
}

void FHIGH_F(char output_cmdtype[], char output_cmdparam[]) { //Factory setting motor height
  rtnProtocols(output_cmdtype, output_cmdparam);
}

int checkSumGenerator(char message[]) {
  int checkSum = 0;
  for (int i = 0; i < 21; ++i)  //Remove the Checksum character, as well as the Null Character
  {
    checkSum ^= message[i];
    //Serial.println(message[i]);
  }
  return checkSum;
}

void rtnProtocols(char cmdtype[], char cmdparam[]) {
  char outputString[28] = "TOWST_";
  strcat (outputString, cmdtype);
  strcat (outputString, "_");
  strcat (outputString, cmdparam);
  strcat (outputString, "_");

  int outputCheckSum = checkSumGenerator(outputString);
  char outputCheckSumHex[3] = "00";    //Receives data up to 255. And an extra line for '/0'.
  itoa (outputCheckSum, outputCheckSumHex, 16); //Converts CheckSum to Hex. If value is under 16, char will only be in Hex[0].
  if (outputCheckSum < 16) { //Adds a 0 if CS has fewer than 2 numbers
    outputCheckSumHex[1] = outputCheckSumHex[0];
    outputCheckSumHex[0] = '0';
  }
  outputCheckSumHex[0] = toupper (outputCheckSumHex[0]);
  outputCheckSumHex[1] = toupper (outputCheckSumHex[1]);
  //Serial.println(outputCheckSumHex);
  strcat (outputString, outputCheckSumHex); //Now displayed in base16
  outputString[23] = {'\r'}; //Not displayed in port. This should be happening, I think.
  outputString[24] = {'\n'};
  //  for (int i = 0; i < strlen(outputString); i++) { //WST seems to have issues with taking CheckSum in lowercase
  //    outputString[i] = toupper (outputString[i]);  //
  //  }
  Serial.write(outputString);
  //Serial.flush();
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200); // usb port serial
  pinMode(LED_BUILTIN, OUTPUT);
}

int msgReceiver(char endMarker, bool readyRead) {
  char rc;
  int ndx = 0;
  while (readyRead == true) {
    if (Serial.available() > 0) {
      //Serial.println("In msgr.");
      rc = Serial.read();
      //Serial.print(rc);
      //Serial.println("rc");
      if (rc != endMarker) {
        messageArray[ndx] = rc;
        ndx++;
      }
      else if (rc == endMarker) {
        messageArray[ndx] = '\0'; // terminate the string
        //Serial.println("Received \n.");
        rc = 0;
        readyRead = false;
      }
      else {
        readyRead = true;
      }
    }
  }
  return ndx;
}

void loop() {
  //Collect data.
  //char endMarker = '\n';
  bool readyRead = true;
  int i = 0;
  //digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  //Serial.println("Serial available.");
  if (Serial.available() > 0) {
    //Serial.println("Serial available.");
    i = msgReceiver('\n', readyRead); //msgReceiver is for turning the input to a char array. '\n' is end char. The output of msgReceiver is the char array position, so need to ++.
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); //This turns an LED on and off.
    messageArray[27] = '\0'; // terminate the string

    int msgLength = i + 1;
    //Serial.println(msgLength);
    //Serial.println("Message received.");
    for (i = msgLength; i > 22; i--) {  //messageArray[22] is the 2nd char of the checkSum. Should not be ablated.
      messageArray[i] = '\0';
    }
    bool canSend = true;
    //Serial.println(messageArray);
    //Serial.println(msgLength);
    char checkSumCharacters[2] = {messageArray[i - 1], messageArray[i]}; //Values are ascii code of the base16 numbers.
    int receivedCheckSum = strtoul(checkSumCharacters, NULL, 16);  //Converts the base16 characters to an int.

    int checkSum = checkSumGenerator(messageArray);
    //Serial.println(checkSum);

    for (i = 0; i < sizeof(cmdtarget); i++) { //Length of cmdtarget is 5.
      cmdtarget[i] = messageArray[i];
      //      Serial.println(cmdtarget[i]);
      //      Serial.println(messageArray[i]);
    }
    cmdtarget[5] = '\0';
    for (i = 0; i < sizeof(input_cmdtype) - 1; i++) { //Length of cmdtype is 5.
      input_cmdtype[i] = messageArray[i + 6];
    }
    input_cmdtype[5] = '\0';
    for (i = 0; i < sizeof(input_cmdparam) - 1; i++) { //Length of cmdparam is 8.
      input_cmdparam[i] = messageArray[i + 12];
    }
    input_cmdparam[8] = '\0';
    //Serial.println(cmdtarget);
    //An attempt at a function pointer to be called for rtnProtocols. Pointer used to decrease negative effects of conditionals.
    stringFunction *rtnpointer[] = {
      FIRMV_F, VALCN_F, RQSPC_F, CTFTC_F, LIDVM_F, LIDVC_F, PREVC_F, STPWM_F, CHPWM_F, STPER_F, CHPER_F, CHIGH_F, SHIGH_F, MOTST_F, MHIGH_F, MTRTT_F,
      RCTIC_F, RCTGM_F, RCTGC_F, SAVEA_F, PREST_F, PREND_F, RQPRE_F, CLPRE_F, RQDAT_F, CUPTC_F, LIDTC_F, CURPR_F, CUPTT_F, CDATE_F, CTIME_F, SDATE_F, RDTTM_F,
      SPROG_F, SLOAD_F, CUFAC_F, LIFAC_F, STFAC_F, MTFAC_F, PPFAC_F, PCOFF_F, CUPFM_F, CUPFC_F, LIDFM_F, LIDFC_F, PREFC_F, FCPWM_F, FCPER_F, FHIGH_F,
    };

    input in = convert(input_cmdtype);  //Using the char to enum converter.
    canSend = errorStack(cmdtarget, receivedCheckSum, checkSum, msgLength, in, canSend);

    if (canSend) {
      char verak[6] = "VERAK";
      rtnProtocols(verak, input_cmdparam);

      //Serial.println(in);
      rtnpointer[in](input_cmdtype, input_cmdparam);
    }
  }
}

bool errorStack(char cmdtarget[], int receivedCheckSum, int checkSum, int msgLength, input in, bool canSend) {
  char output_cmdparam[9];
  if (strcmp (cmdtarget, "TOWST") == 0) {
    strcpy(output_cmdparam, "00000001");
    canSend = false;
  }
  if (strcmp (cmdtarget, "TOWST") != 0 && strcmp (cmdtarget, "TOARM") != 0) {
    strcpy(output_cmdparam, "00000002");
    canSend = false;
  }
  if (receivedCheckSum != checkSum) {
    strcpy(output_cmdparam, "00000005");
    //Serial.println(checkSum);
    //canSend = false;
  }
  if (msgLength < EXPECTED_MSGLENGTH) {
    strcpy(output_cmdparam, "AAAAAA03");
    canSend = false;
  }
  if (msgLength > EXPECTED_MSGLENGTH) {
    strcpy(output_cmdparam, "AAAAAA04");
    canSend = false;
  }
  //Need to determine data value
  if (in == INVAL) {
    strcpy(output_cmdparam, "00000007");
    canSend = false;
  }
  if (canSend == false) {
    char output_cmdtype[6] = "ERROR";
    rtnProtocols(output_cmdtype, output_cmdparam);
  }
  return canSend;
}

When an application opens the Serial port to the Arduino, it causes the Arduino to reset so you need to wait for it to boot up and be ready to receive commands before you send them. For this reason, it is usually best to have your Arduino send a welcome string like "ready" inside of setup() that your application can detect before sending anything else.

I see, I will add a message in the "setup" section too then.

If it's any help, the Arduino was also able to receive and send messages from other serial consoles, such as Putty.

Followup question: Why is it important that the Arduino sends a welcome string before sending anything else when opening a serial port? Why not just have it wait until the end of the code where it will eventually be sent? Is opening a serial port a time-sensitive affair?

Update: I have added the code here:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200); // usb port serial
  pinMode(LED_BUILTIN, OUTPUT);
  char ard[] = "ARDUI";
  char data[] = "00000000";
  rtnProtocols(ard, data);
}

This is able to be sent every time the Arduino is reconnected to the serial port. However, the original message (which is processed in the loop part) is still unable to be received.

However: This is my other attempt:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200); // usb port serial
  pinMode(LED_BUILTIN, OUTPUT);

  //NOTE I am unsure why this logic is needed, but everything seems to fall apart when it is removed.
  //
  char ard[] = "TOWST_ARDUI_00000000_5F";
  Serial.println(ard);
}

The setup message is not displayed, but the loop message is displayed perfectly. I don't know why.

So that the application at the other end knows that the Arduino is ready to accept data. After a reset, the Arduino waits a few seconds to see if an upload will be started; after a timeout it will hand over the control to the sketch and that is when you can start sending data to the Arduino.

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