Arduino: overriding Print class problems - c++

I am trying to make a library for redirection of data printed to Print class. I am unfortunately stuck on error that reads
error: cannot declare variable 'diagData' to be of abstract type 'PrintToString'
note: because the following virtual functions are pure within 'PrintToString'
note: virtual size_t PrintToString::write(uint8_t)
I tried several variations of how to implement this but with no luck. (Sourced from the internet)
Links
Print class: github.com/ Print.h and Print.cpp
My code
PrintToString.h
#ifndef PRINT_TO_STRING_H
#define PRINT_TO_STRING_H
#include <Arduino.h>
class PrintToString : public Print
{
private:
String* data;
public:
PrintToString();
~PrintToString();
String* results();
void clear();
size_t write(uint8_t) = 0;
size_t write(const uint8_t* buffer, size_t size);
};
#endif
PrintToString.cpp
#include "PrintToString.h"
PrintToString::PrintToString()
{
data = new String();
}
PrintToString::~PrintToString()
{
delete data;
data = NULL;
}
String* PrintToString::results()
{
return data;
}
void PrintToString::clear()
{
delete data;
data = new String();
}
size_t PrintToString::write(const uint8_t* buffer, size_t size)
{
size_t n = 0;
while (size--)
{
if (data->concat(*buffer++))
n++;
else
break;
}
return n;
}
TestSketch.ino (I have left out content of all the constants)
#include <ESP8266WiFi.h>
#include <PrintToString.h>
const char* WIFI_SSID
const char* WIFI_PASS
const char* API_HOST
const uint16_t API_PORT
const uint16_t LOCAL_UDP_PORT
WiFiUDP UDPClint;
PrintToString diagData;
uint64_t packetNumber = 0;
void setup()
{
WiFi.begin(WIFI_SSID, WIFI_PASS);
UDPClint.begin(LOCAL_UDP_PORT);
while (WiFi.status() != WL_CONNECTED)
delay(500);
WiFi.printDiag(diagData);
sendStringPacket(diagData.result());
diagData.clear();
}
void loop()
{
delay(1000);
}
void sendStringPacket(String payload)
{
UDPClint.beginPacket(API_HOST, API_PORT);
uint64_t thisPNumber = packetNumber++;
String thisPNumberStr;
while (thisPNumber > 0)
{
uint8_t digit = thisPNumber % 10;
thisPNumberStr.concat(digit);
thisPNumber /= 10;
}
UDPClint.write(';');
for (uint64_t i = 0; i < payload.length(); i++)
UDPClint.write(payload.charAt(i));
UDPClint.endPacket();
}

This is because this class has a pure virtual function here:
size_t write(uint8_t) = 0;
A class with a pure virtual function cannot be instantiated. So method write(uint8_t) must be somehow implemented in your code.
EDIT: Consider making use of the code you used in sendStringPacket() for write(uint8_t). You may be able to redirect output without using sendStringPacket(diagData.result()); statement.

Related

Arduino split char* based on delimiter to value

thanks for your time, so I have a Char* from mqtt
I want to break this down into 3 seperate values
Char* mqttvalue
//Input Would be like the below for example.
mqttvalue = (255,200,230);
// I would like to split the values into the below.
int 1 = 255
int 2 = 200
int 3 = 230
I've tried strtok with no luck. probably something really dumb but some guidance would help.
Thank you
Edit, what I tried.
//Dummy Value for testing
Split("255,240,230");
//Split Value
void Split(char* e) {
String v[3];
char *p;
int i = 0;
p = strtok(e, ",");
while(p && i < 3)
{
v[i] = p;
p = strtok(NULL, ",");
Serial.println(p);
++i;
};
Serial.println(v[0]);
Serial.println(v[1]);
Serial.println(v[2]);
}
Updated the code to the below from a string to char* its all now working.
//Split Value
void Split(char* e) {
char* v[3];
char *p;
int i = 0;
p = strtok(rgb, ",");
while(p && i < 3)
{
v[i] = p;
p = strtok(NULL, ",");
i++;
};
Serial.println(v[0]);
Serial.println(v[1]);
Serial.println(v[2]);
};
As this is quite often asked question and I'd propose more like using wrapper class inheriting Stream interface on C string (and it can be initialized from Arduino String object too).
However usage with Arduino String class is tricky as the original String shouldn't be altered during usage of StringStream, but it's possible to reinitialize it again. Using rvalue (String literal, passed into the class) is forbidden by using non const reference as the parameter of setData method and constructor.
However it's not tested much, so there might be some mistakes. The copy/move constructor and assigment is ommited (and it shouldn't be :D), also using operator=(String&) and operator=(const char*) would be more intuitive interface for it.
class StringStream : public Stream
{
public:
StringStream()
{
setTimeout(1);
}
StringStream(const char * str)
{
setData(str);
}
StringStream(const char * begin, const char * end)
{
setData(begin, end);
}
explicit StringStream(String & view) // cannot be String literal (rvalue) and it gets invalidated if you change original String
{
setData(view);
}
////////////////////////////////////
inline void setData(const char * begin, const char * end)
{
m_start = begin;
m_end = end;
setTimeout(1);
}
inline void setData(const char * begin)
{
setData(begin, begin + strlen(begin));
}
inline void setData(String & view)
{
setData(view.c_str(), m_start + view.length());
}
//////////////////////////////////
// Stream Interface:
virtual int available() override
{
return m_end - m_start;
}
virtual int read() override
{
if (m_start < m_end)
{
return *(m_start++);
}
return -1;
}
virtual int peek() override
{
if (m_start < m_end)
{
return *m_start;
}
return -1;
}
virtual size_t write(uint8_t) override {
return 0;
}
protected:
const char * m_start{0};
const char * m_end{0};
};
And the test program would be like:
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println("Output:");
StringStream test{" 144, 7899, -5478"};
Serial.println(test.parseInt());
Serial.println(test.parseInt());
Serial.println(test.parseInt());
test.setData("1 2");
Serial.println(test.parseInt());
Serial.println(test.parseInt());
delay(2000);
}

C++ & Esp8266 LoadStoreAlignmentCause with pointer

I am trying to access a function of a pointer and it does not work and it gives me an LoadStoreAlignmentCause Exception. Furthermore I want to check if the pointer does exist, but it always returns true for that.
LedFunction.h
#include "Led/LedStates.h"
class LedStates;
class LedFunction {
public:
LedStates *state;
virtual bool init();
bool loadValues();
virtual void render() = 0;
};
LedFunction.cpp
#include "Led/LedFunction.h"
bool LedFunction::init() {
return false;
}
RainbowFunction.h
class RainbowFunction: public LedFunction {
public:
RainbowFunction() {
Serial.println("Rainbow Constructor.");
}
void render() {
Serial.println("From Rainbow...");
}
}
};
LedStates.h
#include "Handlers/LedHandler.h"
#include "Led/LedFunction.h"
class LedHandler;
class LedFunction;
class LedStates {
public:
uint8_t (*values)[3];
int count = 0;
bool dirty = false;
LedHandler* ledHandler;
LedFunction* function = 0;
LedStates(LedHandler* handler);
void setFunction(LedFunction *newFunction);
void setRgb(int i, uint8_t r, uint8_t g, uint8_t b);
void render(); //TODO check virtual key
void setValues(LedStates &to);
void commit();
void fade(LedStates &to, long f0, long f1);
};
LedStates.cpp
#include "Led/LedStates.h"
#include "Led/Animations/RainbowFunction.h"
LedStates::LedStates(LedHandler* handler) {
this->ledHandler = handler;
count = ledHandler->getLength();
values = new uint8_t[count][3];
this->setFunction(new RainbowFunction());
}
void LedStates::setFunction(LedFunction* newFunction) {
Serial.println("SETTING FUNCTION");
if(function)
delete function; //TODO check virtual destructor
function = newFunction;
if(!function)
return;
function->state = this;
Serial.println("-----Setting Done-----");
}
void LedStates::render() {
Serial.println(2);
Serial.println("B:" + (String) (function != 0));
Serial.println("B:" + (String) (function != false));
if(function == nullptr) { //This is the check that is not working properly
Serial.println(22222);
//delay(1000);
//function->render();
} else {
Serial.println(33333);
function->render();
}
Serial.println(3);
}
LedHandler.h
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#include <FastLED.h>
//#include "Led/LedFunction.h"
#include "Led/LedStates.h"
#include "Led/Fading.h"
class LedStates;
class LedHandler {
public:
LedHandler(int length, uint16_t pin);
void clear();
void show();
void setColor(int s, int r, int g, int b);
void loop();
Adafruit_NeoPixel getStrip();
int getLength();
private:
LedStates* currentState;
LedStates* targetState;
Fader<LedStates> *ledFader;
int length;
Adafruit_NeoPixel strip;
CRGB* leds;
};
LedHandler.cpp
#include "Handlers/LedHandler.h"
LedHandler::LedHandler(int length, uint16_t pin) {
Serial.begin(115200);
this->length = length;
this->strip = Adafruit_NeoPixel(length, pin);
this->strip.begin();
CRGB* arr = new CRGB[length];
this->leds = arr;
FastLED.addLeds<WS2812B, 6, RGB>(leds, 60).setCorrection(TypicalLEDStrip);
//Serial.println("-----Creating States-----");
LedStates currentLedStates = LedStates(this);
LedStates targetLedStates = LedStates(this);
Fader<LedStates> ledFader = Fader<LedStates>(currentLedStates, targetLedStates);
//Serial.println("-----Created States-----");
this->currentState = &currentLedStates;
this->targetState = &targetLedStates;
this->ledFader = &ledFader;
}
void LedHandler::loop() {
Serial.println("--::--::--::--::--::--::--");
currentState->render();
Serial.println(99);
Serial.println(6);
currentState->commit();
Serial.println("-------------------------");
delay(10000);
}
The Serialmonitor output:
SETTING FUNCTION
-----Setting Done-----
Rainbow Constructor.
SETTING FUNCTION
-----Setting Done-----
--::--::--::--::--::--::--
2
B:1
B:1
33333
Exception (9):
epc1=0x40202a92 epc2=0x00000000 epc3=0x00000000 excvaddr=0x4020d32d depc=0x00000000
These lines define local variables inside the function LedHandler::LedHandler(int length, uint16_t pin):
LedStates currentLedStates = LedStates(this);
LedStates targetLedStates = LedStates(this);
These lines remember the address of the local variables:
this->currentState = &currentLedStates;
this->targetState = &targetLedStates;
This line deletes the local variables so the memory can be used for something else:
}
and this line calls the something else (nobody knows what it will be):
currentState->render();

Pure virtual function error

I receive this error:
In function 'bool detect_feedback(AudioEffect*)':
54:30: error: cannot convert 'std::shared_ptr<AudioEffect>' to 'AudioEffect*' in assignment
55:16: error: cannot convert 'std::shared_ptr<AudioEffect>' to 'AudioEffect*' in assignment
55:40: error: cannot convert 'std::shared_ptr<AudioEffect>' to 'AudioEffect*' in assignment
The code is as follows:
#include<stdlib.h>
#include<iostream>
#include<memory>`
//BASE CLASS
// audio and have a subsequent effect (next).
struct AudioEffect
{
virtual ~AudioEffect() = default;
virtual void process(float* buf, size_t num) = 0;
std::shared_ptr<AudioEffect> next;
};
//DERIVING MULTIPLE AUDIO-EFFECTS
//Noise Gate
struct NoiseGate: public AudioEffect
{
float threshold;
void process(float *buf, size_t num)
{
if (*buf > threshold)
*buf = threshold;
}
};
//Gain Boost
struct GainBoost: public AudioEffect
{
float signal;
void process(float *buf, size_t num)
{
*buf = *buf + signal;
}
};
//Compressor
struct Compressor: public AudioEffect
{
float offset;
void process(float *buf, size_t num)
{
*buf = *buf - offset;
}
};
//Function
// Implement a function that checks if there is a feedback loop
// in the effects chain.
//... detect_feedback(...)
//{
//}
bool detect_feedback (AudioEffect *ae)
{
AudioEffect *p, *q;
for (p = ae;p != NULL; p = p->next)
for (q = p->next; q != NULL; q = q->next)
if (typeid(*p) == typeid(*q))
return true;
return false;
}
//MAIN
int main(int argc, char *argv[])
{
return 0;
}
You can not assign a shared_ptr to a raw pointer. You need to use the .get() method to obtain a raw pointer.
(p->next).get()

How to pass struct to a class in c++? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm getting these results:
constructor
setFunc
setFunc
Basically I want my class-object globally and pass the struct array to setMethod of the class. and Program is successfully compiling but not getting any results.
DataInput.h
#ifndef DATAINPUT_H_
#define DATAINPUT_H_
#include <stdio.h>
struct Data{
const char *name;
int salary;
void set(int salary, const char *name){
printf("setFunc \n");
this->name = name;
this->salary = salary;
}
};
This class in a seprate cpp file with above header file
class DataInput {
public:
int dataSize;
struct Data data[];
DataInput();
virtual ~DataInput();
void setData(struct Data d[], int numberOfData);
void printData();
private:
};
#endif
-------eof----------
DataInput.cpp
#include "DataInput.h"
DataInput::DataInput() {
printf("constructor \n");
dataSize = 0;
}
DataInput::~DataInput() {
}
void DataInput :: setData(struct Data d[], int numberOfData){
dataSize = numberOfData;
for (int i = 0; i< numberOfData; i++){
printf("i-val in setData() --> %d",i);
this->data[i] = data[i];
}
}
void DataInput::printData(){
for (int i = 0; i< dataSize; i++){
printf("name--> %s \n",data[i].name);
printf("salary--> %d \n",data[i].salary);
}
}
--------eof-----------
main.cpp
#include <stdlib.h>
#include "DataInput.h"
#include <stdio.h>
DataInput *dataInput;
int main(void) {
DataInput in;
dataInput = &in;
struct Data d[2];
d[0].set(1000, "ABC");
d[1].set(2000, "XYZ");
dataInput->setData(d, 2); //not setting data
dataInput->printData(); //not printing
return 0;
}
Note: May not compile, is just illustrative
Few things:
DataInputconstructor do not reserve space for new items. So, this->data[i] = data[i]; result is undefined.
This is C++, Rule of three, strings, ....
struct Data
{
std::string name;
int salary;
Data(const std::string & n, int s);
Data & operator=(const Data & d);
};
Data::Data(const std::string & n, int s) :
name(n), salary(s)
{
}
Data & Data::operator=(const Data & d)
{
name = d.name;
salary = d.salary;
return *this;
}
Use standards containers:
class DataInput
{
private:
std::vector<Data> data;
public:
DataInput();
virtual ~DataInput();
// you don't need use size
void setData(const std::vector<Data> & d);
void printData();
};
void DataInput::setData(const std::vector<Data> & d)
{
data = d;
}
void DataInput::printData()
{
for (std::vector<Data>::iterator it = data.begin(); it != data.end(); ++it)
{
std::cout << it->name << ":" << it->salary << std::endl;
}
}
Now, you can use it from main (without pointers):
int main(void)
{
DataInput in;
std::vector<Data> d;
d.push_back(Data(1000, "ABC"));
d.push_back(Data(2000, "XYZ"));
dataInput.setData(d); // yes setting data
dataInput.printData(); // yes printing
return 0;
}
Do a memcpy of the entire array, just assigning the data might lead to memory leaks due to stack frame removal or deletion. This way however you lose the logging simultaneously avoiding the for loop increasing performance
void DataInput :: setData(const struct Data const* d, const int numberOfData) {
// Cleanup old data!
if(this->data) delete [] this->data;
if(!d) throw new std::invalid_argument("Cannot set NULL data!"); // Remove this line if NULL may be assigned and replace with the commented code.
// if(!d) {
// this->data = NULL;
// this->dataSize = 0;
// } else {
this->data = new Data[(this->dataSize = numberOfData)];
memcpy(this->data, d, sizeof(struct Data) * numberOfData);
// }
}
Don't forget to update the DataInput class!
class DataInput {
public:
int dataSize;
struct Data* data;
DataInput();
virtual ~DataInput();
void setData(const struct Data const* d, const int numberOfData);
void printData();
private:
};
void DataInput::printData() {
for (int i = 0; i< this->dataSize; i++){
printf("name--> %s \n",this->data[i].name);
printf("salary--> %d \n",this->data[i].salary);
}
}
DataInput::~DataInput() {
if(this->data) delete [] this->data;
}

Passing Arrays In a Library Arduino

I am trying to write a library that reads 5 variables, then sends them through the serial port to a bluetooth reciever, I am getting a number of errors and I am not sure where to go from here, do I need to implement pointers?
Here is the Arduino code....
#include <serialComms.h>
serialComms testing;
void setup()
{
Serial.begin(9600);
}
char data[] = {1,2,3,4,5,6};
void loop()
{
for(int t = 0;t<6;t++)
{
data[t] = data[t]++;
}
testing.updateUser(data);
delay(250);
}
serialComms.cpp
#include <Arduino.h>
#include <serialComms.h>
void serialComms::init()
{
// This is where the constructor would be...right now we are too stupid to have one
}
void serialComms::readAllBytes() // Target Pin,Values
{
}
void serialComms::assignBytes()
{
for(int t = 0;t<5;t++)
{
digitalWrite(12,HIGH);
delay(250);
digitalWrite(12,LOW);
}
}
void serialComms::updateUser(char t[])
{
Serial.write(t,5);
}
serialComms.h
#ifndef serialComms_h
#define serialComms_h
/* serialComms Class */
class serialComms
{
public:
serialComms() {};
void init();
void readAllBytes(); // Will be used to create the array --> two variables for now...
void assignBytes();
void updateUser(char t[]);
};
#endif
Here are the errors that I am getting...
- serialComms.cpp:28: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'
-
- serialComms.cpp:28: error: invalid conversion from 'char*' to 'const uint8_t*'
- serialComms.cpp: In member function 'void serialComms::updateUser(char*)':
- serialComms.cpp:27: error: expected primary-expression before ']' token
Example:
void setup()
{
Serial.begin(9600);
char string_array[] = "hello";
char data_array[] = {1,2,3,4,5,6};
unsigned char data_array_uchar[] = {21,22,23,24,25,26};
uint8_t uint8_array[] = {11,12,13,14,15,16};
char alpha_array[] = {0x41,0x42,0x43,0x44,0x45,0x46};
// take note that sizeof() is a precompile command... number of places/size of each place.
updateUserPrint(string_array);
updateUserWrite(data_array, sizeof(string_array));
updateUserWriteUchar(data_array_uchar, sizeof(data_array_uchar));
updateUserWriteUchar(uint8_array, sizeof(uint8_array));
updateUserWriteUint(uint8_array, sizeof(string_array));
updateUserAlpha(alpha_array, sizeof(string_array));
}
void updateUserPrint(char *s)
{ //note a string aka array of char's is ended with a null.
Serial.print(s); // this can detect.
Serial.println();
}
void updateUserWrite(char *t, size_t len)
{ //note an array of int's is not ended with a null. so you need to know how long it is.
for (int n = 0; n < len ; n++) {
Serial.print(t[n],DEC);
Serial.print(",");
}
Serial.println();
}
void updateUserWriteUchar(unsigned char *t, size_t len)
{ //note an array of int's is not ended with a null. so you need to know how long it is.
for (int n = 0; n < len ; n++) {
Serial.print(t[n],DEC);
Serial.print(",");
}
Serial.println();
}
void updateUserWriteUint(uint8_t *t, size_t len)
{ //note an array of int's is not ended with a null. so you need to know how long it is.
for (int n = 0; n < len ; n++) {
Serial.print(t[n],DEC);
Serial.print(",");
}
Serial.println();
}
void updateUserAlpha(char *t, int len)
{ //note an array of int's is not ended with a null. so you need to know how long it is.
for (int n = 0; n < len ; n++) {
Serial.write(t[n]);
}
Serial.println();
}
produces the following:
hello
1,2,3,4,5,6,
21,22,23,24,25,26,
11,12,13,14,15,16,
11,12,13,14,15,16,
ABCDEF
Serial.write can only send constant strings like
Serial.write(“hello”);
That is why the error error: invalid conversion from 'char*' to 'const uint8_t*'
use as
char temp[max_length];
sprintf(temp,"%s",t);
Serial.write(temp);