I'm trying to build an interface to enstablish serial communication between my board and a python script running on my computer to control a robotic arm. Every message is divided in a header (1 character) and a body. The body is composed of a series of keys and values, similar to a json file.
Message example:
Hvalue1:foo,value2:bar\n
The first request is made by the board and expects a confirm from the computer.
There are som functions which should help me with debugging, those are all static methods under the Debug class.
ENVIRONMENT: Platformio IDE
BOARD: Elegoo UNO R3 (ATMEGA328 U)
PROBLEM: There is something I'm probably doing wrong when accessing the object storing the last received serial message. I used Debug::logPointer to see what the address was at different points, for some reason I get a different value inside readSerialMessage than the one i get in loop. When I try to retrieve the value of the header with serialMessage.getHeader() execution just stops.
CODE:
//Main.cpp
#include <Arduino.h>
#include <Servo.h>
#include "pins.h"
#include "controls.h"
#include "interface.h"
//Object storing arm state
Arm arm(BASE_PINS, SERVO_ALFA_PIN, SERVO_BETA_PIN, SERVO_GAMMA_PIN);
const int BAUD = 9600;
void setup()
{
Serial.begin(BAUD);
}
unsigned long start_time, end_time; // Keep track of time taken by every iteration
unsigned int iteration = 0;
bool connected {false};
void loop()
{
Message startCommunicationMessage('s');
startCommunicationMessage.setIntValue("baud", BAUD);
Message serialMessage('n');
while (!connected){
if (Serial.available() > 0){
Debug::logPointer(serialMessage);
readSerialRequest(&serialMessage);
if (serialMessage.getHeader() != 'C'){ //AT THIS POINT THE EXECUTION STOPS
Debug::log("Invalid");
continue;
} else {
Debug::log("Received confirm");
connected = true;
break;
}
}
sendSerialMessage(startCommunicationMessage);
delay(1000);
}
Debug::log("Connected!");
while (connected){
start_time = micros();
if (iteration % 50){
//Check for serial commands every 12.5 ms
if (Serial.available() > 0){
readSerialRequest(&serialMessage);
parseSerialRequest(serialMessage, arm);
}
}
iteration += 1;
end_time = micros();
delayMicroseconds(min(max(0, 250 + start_time - end_time), 250));
}
}
//Interface.cpp
int readSerialRequest(char *dest, char terminator='\n'){
//Destination string MUST contain a number of characters >= MAX_REQUEST_LENGTH
size_t counter {0};
while (Serial.available() > 0){
char character = Serial.read();
if (character = terminator){
*dest = character;
dest++;
counter++;
} else {
*dest = '\0';
return counter;
}
}
}
void readSerialRequest(Message *message, char terminator='\n'){
Debug::logPointer(serialMessage);
char* content = message->getContent();
char header = Serial.read();
Debug::logPointer(*message);
message->setHeader(header);
readSerialRequest(content, terminator);
}
void sendSerialMessage(Message msg){
Serial.print(msg.getHeader());
Serial.println(msg.getContent());
}
//Message.cpp
class Message {
char m_header = '\0';
char m_content[MAX_REQUEST_LENGTH];
public:
Message(char header)
{
m_header = header;
char content[1]{""};
strcpy(m_content, content);
}
void setHeader(char header){
m_header = header;
}
char getHeader(){
return m_header;
}
void setContent(char *content){
strcpy(m_content, content);
}
char *getContent(){
return m_content;
}
void addValue(char *content, const char *key, const char *value){
char *ptr = &content[strlen(content)];
if (strlen(content) == 1)
{
*ptr = ','; // Add item separator
ptr++;
}
strcpy(ptr, key); // Copy key
ptr += strlen(key);
*ptr = ':'; // Add :
ptr++;
strcpy(ptr, value); // Copy value
}
void setValue(const char *key, const char *value){
char *val_ptr{searchValue(m_content, key)};
if (val_ptr == nullptr) // Value doesn't exist, must be added
{
addValue(m_content, key, value);
}
else
{
char *old_value_end = strstr(val_ptr, ","); // Locate the end of the old value
char *new_value_end{&val_ptr[strlen(value)]};
if (old_value_end == nullptr || old_value_end == new_value_end)
{ // Value is at the end or new value has the same length
strcpy(val_ptr, value);
}
else
{ // Subsequent values must be shifted
char *buffer = new char[strlen(old_value_end) + 1];
strcpy(buffer, old_value_end); // Store part of string to be shifted in a temporary buffer
strcpy(val_ptr, value); // Copy new value
strcpy(new_value_end, buffer); // Copy the buffer right after the new value
delete[] buffer;
buffer = nullptr;
}
}
}
//Not strictly relevant to the problem
//Basically these methods encode int, floats and bools and then send the result to the setValue method
void setIntValue(const char* key, const int &value){...}
void setFloatValue(const char* key, const float &value){...}
void setBoolValue(const char* key, const bool &value){...}
};
//Debug
template <typename T>
void Debug::log(T log){
Serial.print("llog_message:");
Serial.println(log);
}
template <typename T>
void Debug::logPointer(T log){
Serial.print("laddress:");
Serial.println((unsigned int)&log);
}