PlatformIO Unidentified reference error to defined attributes - c++

I am creating a project using PlatformIO and a Nodemcuv2 micro-controller.
I have written a class for serial communication SerialCommunicationHandler. This class ICommunicationHandler implements a Interface. See the code below.
ICommunicationHandler.h
class ICommunicationHandler {
public:
virtual void sendTemperature(float temp) = 0;
virtual void receiveData() = 0;
virtual void update() = 0;
protected:
virtual void parseData() = 0;
virtual void showParsedData() = 0;
};
SerialCommunicationHandler
headerfile
#include "ICommunicationHandler.h"
class SerialCommunicationHandler : public ICommunicationHandler {
private:
//atributes needed for storing and modifying incoming data.
static char incomingData[6]; //char array to temporarily store incoming data.
static char receivedData[6]; //char array to copy incoming data to.
static unsigned int messagePosition; //index of the incomingData array.
bool receiving;
bool newData;
void parseData() override;
void receiveData() override;
void showParsedData() override;
public:
explicit SerialCommunicationHandler();
void sendTemperature(float temp) override;
void update() override;
};
.cpp
#include <Arduino.h>
#include "SerialCommunicationHandler.h"
SerialCommunicationHandler::SerialCommunicationHandler() {
messagePosition = 0;
receiving = false;
newData = false;
}
void SerialCommunicationHandler::receiveData() {
//check if there are bytes in the serial buffer.
while (Serial.available() > 0){
char inByte = Serial.read();
//check if the byte is a starting or ending character;
switch (inByte) {
case '<':
//start receiving characters
receiving = true;
break;
case '>':
//stop receiving and parse the incoming data.
receiving = false;
newData = true;
strcpy(receivedData, incomingData); //copy incoming data into receivedData for further parsing.
memset(incomingData, 0, sizeof(incomingData)); //resetting incomingData.
messagePosition = 0;
break;
default:
if (receiving) {
incomingData[messagePosition] = inByte; //add incoming byte to array.
messagePosition++;
}
break;
}
}
}
void SerialCommunicationHandler::parseData() {
if (newData) {
showParsedData();
}
newData = false;
}
void SerialCommunicationHandler::showParsedData() {
Serial.println(receivedData);
}
void SerialCommunicationHandler::sendTemperature(float temp) {
Serial.println(temp);
}
void SerialCommunicationHandler::update() {
receiveData();
parseData();
}
When building I get multiple undefined refernce errors:
*/ld.exe: .pio\build\nodemcuv2\src\SerialCommunicationHandler.cpp.o:(.text._ZN26SerialCommunicationHandler14s
howParsedDataEv+0x0): undefined reference to `_ZN26SerialCommunicationHandler12receivedDataE`
*/ld.exe: .pio\build\nodemcuv2\src\SerialCommunicationHandler.cpp.o:(.text._ZN26SerialCommunicationHandlerC2E
v+0x4): undefined reference to `_ZN26SerialCommunicationHandler15messagePositionE'
*/ld.exe: .pio\build\nodemcuv2\src\SerialCommunicationHandler.cpp.o:(.text._ZN26SerialCommunicationHandler11r
eceiveDataEv+0x0): undefined reference to `_ZN26SerialCommunicationHandler12incomingDataE'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\nodemcuv2\firmware.elf] Error 1
I have checked my code multiple times for syntax errors or misspelling but have found nothing. My IDE doesnt bring up any errors as well. Any information on what might be causing the undefined reference error is welcome.

headerfile
#include "ICommunicationHandler.h"
class SerialCommunicationHandler : public ICommunicationHandler {
private:
//atributes needed for storing and modifying incoming data.
static char incomingData[6]; //char array to temporarily store incoming data.
static char receivedData[6]; //char array to copy incoming data to.
static unsigned int messagePosition; //index of the incomingData array.
// ... etc
These are only declarations of the static member variables. You also have to define them in the cpp file, just like you do with the member functions:
.cpp file:
void SerialCommunicationHandler::showParsedData() {
Serial.println(receivedData);
}
// static data members
char SerialCommunicationHandler::incomingData[6] = {};
char SerialCommunicationHandler::receivedData[6] = {};
unsigned int SerialCommunicationHandler::messagePosition = 0;

Related

c++ int member changes on its own

I am new to c++.
It looks like member variable _scheduleSize gets value kind of "integer_half_max" without any reason. Could someone please explain me why is this happening?
Invocation
leds.addSchedulePoint(new ScheduledLedPoint(ScheduleTime(9), 0));
of method:
void ScheduledLeds::addSchedulePoint(ScheduledLedPoint *schedulePoint) {
Serial.print("_scheduleSize:");
Serial.println(_scheduleSize);
_schedule[_scheduleSize++] = schedulePoint;
Serial.print("_scheduleSize:");
Serial.println(_scheduleSize);
for (size_t i = 0; i < _scheduleSize; i++) {
Serial.println(_schedule[i]->getLevel());
}
}
results in such console output :
_scheduleSize:0
_scheduleSize:1073680860
0
Exception (28):
epc1=0x40206514 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000010 depc=0x00000000
Below you can see entire class:
class ScheduledLeds {
public:
ScheduledLeds(int pin);
void addSchedulePoint(ScheduledLedPoint *schedulePoint);
void process(ScheduleTime currentTime);
void freezeLedLevel(int targetLevel, int minutes);
int _pin;
private:
ScheduledLedPoint *_schedule[];
int _scheduleSize;
int _count;
int _size;
long _unfreezeTime;
int _lastLevel;
ScheduleTime _lastTime;
void setTransitionalLightLevel(ScheduleTime now, ScheduledLedPoint nextPoint);
void setLightLevel(int targetLevel);
};
ScheduledLeds::ScheduledLeds(int pin) {
pinMode(pin, OUTPUT);
_pin = pin;
_scheduleSize = 0;
_size = 10;
_unfreezeTime = millis();
ScheduledLedPoint *_schedule[_size];
}
void ScheduledLeds::addSchedulePoint(ScheduledLedPoint *schedulePoint) {
Serial.print("_scheduleSize:");
Serial.println(_scheduleSize);
_schedule[_scheduleSize++] = schedulePoint;
Serial.print("_scheduleSize:");
Serial.println(_scheduleSize);
for (size_t i = 0; i < _scheduleSize; i++) {
Serial.println(_schedule[i]->getLevel());
}
}
ScheduledLedPoint *_schedule[]; is not valid C++ and shouldn't compile. Some compilers accept it as an extension - but even there, it's an array of zero size; _schedule[x] exhibits undefined behavior for any value of x.
When you write ScheduledLedPoint *_schedule[_size] in the constructor, that doesn't affect the data member named _schedule, as you seem to believe. Instead, it creates and immediately destroys a local variable that also happens to be named _schedule; this has exactly zero net effect.
For an array-like data structure of variable size, use std::vector.
because you have syntax error including this recursive function

Arduino function changes argument for no reason

I wrote a class for Aduino, for reading an ads124x, and I am having one major problem, I can't call a function defined by the class. Here is how it is structured:
.ino calls functions using . operator
.h contains register map and class definition
.cpp contains all functions of the class
so far here is what is happening the .ino is successfully calling a function in .cpp, but when that same function calles another in .cpp it fails to call.
.ino:
#include "ADS124X.h"
void setup(){
ADS124X ADS124X(1,2,3,4);
Serial.begin(9600);
ADS124X.setUP(0x20, 0x20);}
.h:
class ADS124X{
public:
void reset(void);
void setUP(unsigned char* mux1, unsigned char* sys0);
private:
void SPI_Write(unsigned char* data, unsigned char size);
}
.cpp:
void ADS124X::setUP(unsigned char * mux1, unsigned char * sys0)
{
Serial.println("hi"); //prints this
delay(1);
reset(); // stops here
Serial.println("hi"); // doesn't print this
delay(1);
stopDataCont();
delay(210);
setREG(MUX1, mux1, 1);
setREG(SYS0, 0x01, 1);
delay(1);
}
void ADS124X::reset(void)
{
unsigned char dataToSend[] = { RESET };
START_HIGH;
CS_LOW;
Serial.println(RESET); // prints this as 0x06 (correct value)
SPI_Write(dataToSend, 1); // Seems to stop here
START_LOW;
CS_HIGH;
}
void ADS124X::SPI_Write(unsigned char * data, unsigned char size)
{
Serial.println("SPI_Write"); //prints this
for (unsigned int i = 0; i < size; i++) {
Serial.println("SPI_Write"); //prints this
Serial.println(* data); //prints this as 126 (if RESET is 3 * data becomes 189...)
SPI.transfer(*data);
Serial.println("SPI_Write");
data++;
}
}
This is not right...
Serial.println(RESET); // println expects a null terminated string
// you are sending a char.
You should define dataToSend as a null-terminated char array.
void ADS124X::reset(void)
{
char dataToSend[] = { RESET, 0 };
// ...
serial.println(dataToSend); // maybe println "reset" would be better?
SPI_Write(dataToSend, 1);
//...
}
Don't expect to see a nice 0x06 on your serial monitor, since that is not a printable character.

weird typing mismatch c++

So I am not sure why I am getting this error when in the .h files it was defined that format was a Parser*. The compiler tells me that in the method Parser::changeformat(int) I cannot convert an int* to a Parser* pointer(the cpp files aren't done yet so please ignore all the other methods if they throw errors or look weird). Why is this happening and how can I fix it. This may have something to do with inheritance so I'll point out a subclass of parser that would fit. Also, in any case if you have suggestions about other parts then be my guest.
Parser.h
#ifndef PARSER_H_
#define PARSER_H_
#include <string>
#include <iostream>
#include <fstream>
/*
* This is a parser for reading and writing files
* it takes in an integer for the file type it should read
* or none if you would like to change it later and reuse
* the parser
*/
class Parser {
public:
Parser();
Parser(int);
virtual ~Parser();
void open();
bool open(std::string&);
bool read();
bool write();
bool close();
void changeformat(int);
private:
int filetype = -1;
Parser* format = 0;
};
#endif /* PARSER_H_ */
Parser.cpp
#include "Parser.h"
Parser::Parser()
{
filetype = -1;
}
Parser::Parser(int filetype)
{
switch(filetype)
{
case 0:
{
//load xml format via instantiating xmlpar subclass and overloading methods
break;
}
case 1:
{
//load txt format
break;
}
}
}
Parser::~Parser()
{
if(this->format)
delete this->format;// TODO Auto-generated destructor stub
}
//the classes below are to be overloaded with a subclass's own method
void Parser::open()
{
return;
}
bool Parser::open(std::string& filename)
{
if(this->format->open(filename))
{
std::cout<<"OK: "+filename+" opened\n";
return true;
}
else
{
std::cout<<"Error: "+filename+" unable to be opened\n";
return false;
}
}
bool Parser::read()
{
//make failure checks for all past open in this cpp
return this->format->read();
}
bool Parser::write()
{
return this->format->write();
}
bool Parser::close()
{
return this->format->close();
}
void Parser::changeformat(int)
{
switch(filetype)
{
case -1:
break;
case 0:
{
this->format = new xmlpar();
break;
}
case 1:
{
//load txt format
break;
}
}
}
xmlpar.h
/*
* xmlpar.h
*
* Created on: Jul 22, 2015
* Author: root
*/
#ifndef XMLPAR_H_
#define XMLPAR_H_
#include "Parser.h"
#include <fstream>
#include <string>
class xmlpar: public Parser{
public:
xmlpar();
virtual ~xmlpar();
bool open(std::string&);//opens a stream and checks association
bool read(std::fstream&);//creats dom tree and hands it forward via reference
bool write(std::fstream&);//edits domtree but does not write to the physical file
bool close(std::fstream&);//the dom tree is flushed, the fstream associated to the file is closed and everyone is happy... I think
private:
std::fstream *file= 0;
bool flush();//write dom tree in memory to physical file
};
#endif /* XMLPAR_H_ */
xmlpar.cpp
/*
* xmlpar.cpp
*
* Created on: Jul 22, 2015
* Author: root
*/
#include "xmlpar.h"
xmlpar::xmlpar()
{
}
bool xmlpar::open(std::string& filename)
{
file = new std::fstream(filename, std::ios::in|std::ios::out);
return file->good();
}
bool xmlpar::close(std::fstream &file)
{
this->write(file);
file->close();
//write failcheck here
}
xmlpar::~xmlpar() {
this->close(file);
}
You are trying to instantiate an instance of xmlpar that is derived from Parser base class without including headers of derived class xmlpar at Parser.cpp. The compiler is not finding definition for xmlpar here:
this->format = new xmlpar();
I also doubt this is a good practice.

Pass string to class and save to eeprom

I'm writing a class to save data to the EEPROM of an Arduino.
The class is called Memory.
The class contains different functions and variabeles.
char serverdefault[15] = "0032484716340";
int pricedefault = 30;
void Memory::FactoryReset()
{
TotalSold = 0;
TotalCash = 0;
Sold = 0;
Cash = 0;
Items = 0;
EEPROM_writeAnything(10, TotalSold);
EEPROM_writeAnything(20, TotalCash);
EEPROM_writeAnything(30, Sold);
EEPROM_writeAnything(40, Cash);
EEPROM_writeAnything(50, pricedefault);
EEPROM_writeAnything(60, Items);
EEPROM_writeAnything(70, serverdefault);
ReadAll();
}
Annother function allows to change the default server number.
void Memory::ChangeServer(char *number_str)
{
EEPROM_writeAnything(70, number_str);
ReadAll();
}
This function doesn't work.
I call the function in the void setup().
void setup()
{
Serial.begin(9600);
Serial.println("started");
Serial.println("factory reset");
mem.FactoryReset();
Serial.println("change server number");
mem.ChangeServer("1234567890123");
}
The value saved in the EEPROM is replaced by "b32484716340" instead of "1234567890123". What am i doing wrong?
In Memory::ChangeServer you are writing the pointer itself to EEPROM (i.e. the address), rather than the string that the pointer points to. One way to fix this would be:
void Memory::ChangeServer(char *number_str)
{
for (int i = 0; i <= strlen(number_str); ++i)
{
EEPROM_writeAnything(70 + i, number_str[i]);
}
ReadAll();
}

Optimal technique to parse a real-time char* data received from a buffer for text content in C++

I have created a live continuous mjpeg stream. A crude illustration is like this
....[image (jpeg)]->[text "content-length"]->[image (jpeg)]->[text "content-length"]->....
As you can see I receive data from gstreamer media pipe line which contains image and my own injected text
(Note: Although I am using Gstreamer, my question is only related to C++ principles.)
In order to parse this real-time data, I am trying to receive and push it into the queue. Subsequently I plan to parse the data for the word "content-length" after queue contains a certain number of packets.
My code looks like the following:
void clear( std::queue<char> &q )
{
std::queue<char> empty;
std::swap( q, empty );
}
static GstFlowReturn new_buffer (GstAppSink *app_sink, gpointer user_data)
{
GstBuffer* buffer = gst_app_sink_pull_buffer(app_sink);
//create queue
std::queue<char> q;
g_print("The input buffer contents are\n");
gint i=0;
for(i=0; buffer->data[i];i++)
{
//g_print("\n%d",i);
q.push(buffer->data[i]);
}
//g_print("\nsize of inbuf is %d\n",GST_BUFFER_SIZE(buffer));
g_print("\n");
gst_buffer_unref(buffer);
//#####################
//parsing method here???
//#####################
clear(q);
return GST_FLOW_OK;
}
I have used circular queues/ ring buffer in C/C++ before. Is that the best option? Or is the C++ STL queues would be more appropriate in this scenario like above?
I ended up using ringbuffer class
In header file declare
//queue size
enum { rb_size = 5 }; // ---->element1 -> element2 -> .... -> elementN -> gap ->
// ^ |
// | |
// <--------------------<------------------<-------------V
typedef struct
{
char * data[rb_size];
int head, tail;
} ring_buffer_struct;
namespace myspace{
class ring_buffer{
private:
protected:
public:
//========= constructor ============
ring_buffer()
{
//If necessary initialization can happen here.
}
//========== destructor =============
virtual ~ring_buffer()
{
}
//===================================
virtual void rb_start(ring_buffer_struct *b);
virtual bool rb_empty(ring_buffer_struct const *b);
virtual char * rb_front(ring_buffer_struct const *b);
virtual char * rb_rear(ring_buffer_struct const *b);
virtual void rb_pop_front(ring_buffer_struct *b);
virtual ring_buffer_struct* rb_push_back(ring_buffer_struct *b);
}; //end of class
}
In cpp file
//start
void myspace::ring_buffer::rb_start(ring_buffer_struct *b)
{
b->head = 0; b->tail = 0;
}
//clear
bool myspace::ring_buffer::rb_empty(ring_buffer_struct const *b)
{
return b->head == b->tail;
}
//front element
char * myspace::ring_buffer::rb_front(ring_buffer_struct const *b)
{
return b->data[b->head]; //data gets popped
}
//rear element
char * myspace::ring_buffer::rb_rear(ring_buffer_struct const *b)
{
return b->data[b->tail]; //data gets pushed
}
//pop out front element
void myspace::ring_buffer::rb_pop_front(ring_buffer_struct *b)
{
if(b->head < b->tail)
{
++b->head;
}
if(b->head > b->tail)
{
b->head = 0;
}
}
//push in rear element
ring_buffer_struct* myspace::ring_buffer::rb_push_back(ring_buffer_struct *b)
{
int new_tail = b->tail;
if (++new_tail >= rb_size)
{ //beginning of the queue
new_tail = 0;
}
if (new_tail != b->head)
{
//middle of the queue
b->tail = new_tail;
}
if (new_tail <= b->head)
{
b->tail = 0;
}
return b;
}
And to use in the main()
...
char element1[10] = "abcdefghi";
char element2[10] = "bcdefghij";
char element3[10] = "cdefghijk";
ring_buffer_struct rb;
myspace::ring_buffer q;
q.rb_empty(&rb); //make sure empty
q.rb_start(&rb); //start - initialize
//initialize
uint16_t i;
for(i=0;i<rb_size;i++)
{
rb.data[rb.tail] = (char *)"000000000";
q.rb_push_back(&rb);
}
rb.data[rb.tail] = element1;
q.rb_push_back(&rb);
q.rb_pop_front(&rb); //now parse
rb.data[rb.tail] = element2;
q.rb_push_back(&rb);
q.rb_pop_front(&rb); //now parse
...
For parsing: I looked at this post
Simple string parsing with C++
Off topic suggestion:
When using the swap trick to clear out an STL container, don't call std::swap explicitly, as you may end up not getting a better-optimized version. The better way is:
void clear( std::queue<char> &q )
{
std::queue<char> empty;
using std::swap;
swap( q, empty );
}
This allows the compiler to choose a specialized version of swap that's optimized for the type of container you're using. You could also try q.swap(empty);, but I'm not sure all STL implementations offer that.