Storing Variables in a Class - arduino

I am trying to keep track of a set of data by declaring a class.
The class is initialized with a unique ID but then fills the rest of the variables out later in the code after some calculations.
First, is that even an acceptable way to do this?
Second, I'm trying to pass it a char array but it does not want to take the value. Is this the correct way to define the fileName and call it back when creating the file?
Here's the example, I define a variable from the Customer class then try to store its filename:
#ifndef customer_h
#define customer_h
class Customer
{
public:
Customer (char *number);
char *ID;
double current;
double voltage;
double powerConsumption;
double remainingCredit;
int relay;
char *lastName;
char *firstName;
char *fileName;
private:
};
Customer::Customer(char *number)
{
ID = number;
}
#endif
void setup()
{
cust1.fileName = getFileName(cust1.ID);
}
char *getFileName(char *customerID)
{
char *charID;
String newID;
for (int i = strlen(customerID)-4; i<= strlen(customerID)-1; i++)
{
newID += customerID[i];
}
newID += ".csv";
int lenID = newID.length() + 1;
char fileName[lenID];
newID.toCharArray(fileName,lenID);
return fileName;
}
Thanks a lot in advance for any help and info you can provide!

Be better to use a structured rather than a class. They are pretty similar but in this case seems like a structure will be much better go and read about the differences and you'll see

Related

Converting char starting with "0b" or "0B" to unsigned long

I am working on a project for a client so I am given a lot of code I cannot modify. I am stuff in a weird situation because of this problem. Nonetheless, I have a char with 34 indexes that I need to convert into an unsigned long type. I have seen numerous methods to accomplish this such as strtout, atol, etc. None have worked because the string starts with "0b" (ie "0b10000010000010000010000010000000"). Without the "0b", the rest of the code will not function properly. I tested with varying beginning 2 chars but nothing has led to a successful trial. Is there a function or code available that can convert the previously mentioned string into unsigned long? Any help is greatly appreciated.
You can combine the fact that a character - '0' is the number of that digit and use bit shifting to build the number up from the string:
unsigned long binaryToUL(String numberString){
int i;
unsigned long answer = 0;
if(numberString.startsWith("0b"))
for(i = 2; i<numberString.length(); i++)
answer = (answer << 1) + (numberString[i] - '0');
return answer;
}
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
unsigned long test;
String testString = "0b10000010000010000010000010000000";
test = binaryToUL(testString);
Serial.println(testString);
Serial.println(test,BIN);
Serial.println(test);
while(true)
;
}
To convert a string a string representation of a binary that started with a "0b" or "0B", you need to remove the header first, then convert to the an unsigned long (uint32_t). Depend on what is the original string type (char[], char*) but an Arduino String in this case would make it easier to work with.
String myStr = "0b10000010000010000010000010000000";
void setup(){
Serial.begin(115200);
myStr.toUpperCase();
myStr.replace("0B", "");
uint32_t ul = strtoul(myStr.c_str(), NULL, 2);
Serial.println(ul, BIN);
}
void loop(){
}

Correct Assignment for Pointers

I am shifting from Python to C so bit rusty on the semantics as well as coding habit. In Python everything is treated as an object and objects are passed to functions. This is not the case in C so I want to increment an integer using pointers. What is the correct assignment to do so. I want to do it the following way but have the assignments wrong:
#include <stdio.h>
int i = 24;
int increment(*i){
*i++;
return i;
}
int main() {
increment(&i);
printf("i = %d, i);
return 0;
}
I fixed your program:
#include <stdio.h>
int i = 24;
// changed from i to j in order to avoid confusion.
// note you could declare the return type as void instead
int increment(int *j){
(*j)++;
return *j;
}
int main() {
increment(&i);
printf("i = %d", i);
return 0;
}
Your main error was the missing int in the function's argument (also a missing " in the printf).
Also I would prefer using parentheses in expressions as *j++ and specify exactly the precedence like I did in (*j)++, because I want to increment the content of the variable in the 'j' location not to increment the pointer - meaning to point it on the next memory cell - and then use its content.

How do i store data from HTTPREAD into a variable?

I need a way to store HTTPREAD data into a variable because I will be comparing its value to another variable. Is there any way?
{
myGsm.print("AT+HTTPPARA=\"URL\",\"http://7ae0eae2.ngrok.io/get-ignition/ccb37bd2-a59e-4e56-a7e1-68fd0d7cf845"); // Send PARA command
myGsm.print("\"\r\n");
delay(1000);
printSerialData();
myGsm.println();
myGsm.println("AT+HTTPACTION=0");//submit the GET request
delay(8000);//the delay is important if the return datas are very large, the time required longer.
printSerialData();
myGsm.println("AT+HTTPREAD=0,17");// read the data from the website you access
delay(3000);
printSerialData();
delay(1000);
}
void printSerialData()
{
while(myGsm.available()!=0)
Serial.write(myGsm.read());
}
I am assuming that the Serial.write(myGsm.read()) is where you want to get the data from. In other words, you are receiving the data through the serial connection, and you want to parse the data returned from the AT+HTTPREAD command.
Since you did not provide any clue about what that command is returning in the serial, I gonna use as an example a different command that I know the output, the below one:
TX=> AT+CCLK?
RX=> AT+CCLK?\n\r
\t+CCLK: "2020/03/03, 22:00:14"\n\r
So, the string you are going to get from the above AT+CCLK? command is this (I am assigning to a char pointer for the sake of understanding):
char *answer = "AT+CCLK?\n\r\t+CCLK: "2020/03/03, 22:00:14"\n\r";
What you need is to parse the answer (the char *answer in this example) to get the "numbers" into variables.
How to do that?
You need to walk over that string, moving to specific places. For example, to be able to convert the 2020 into a variable, you need to be at position answer[19], and then you can use, let's say, the strtoul() to convert to an integer and store it into a variable.
uint32_t year = strtoul(&answer[19], NULL, 10);
Then, to get the month, you need to walk a bit more to reach the position at the month on the string:
uint32_t month = strtoul(&answer[24], NULL, 10);
And so on, but you are using magic numbers for that, in other words, the numbers 19, 24 are positions specific for this string.
Then, how to make this "walking" smarter?
You can use tokens in conjunction with the strstr() to go to the specific points you want in the string. In this case, we want to move the pointer to the first 2, so we can pass that pointer to the strtoul() to convert it into an integer.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
int main() {
char *answer = "AT+CCLK?\n\r\t+CCLK: "2020/03/03, 22:00:14"\n\r";
char *token = "CCLK: \"";
char *ptr;
uint32_t year;
ptr = strstr(answer, token);
if (ptr == NULL) {
printf("Token not found\n");
return -1;
}
year = strtoul(++ptr, NULL, 10);
printf("Year = %d\n", year);
Then, to make this code into a function to be more generic, here it is:
bool parse_answer_to_uint32(char *buff, char *tokens[], uint32_t *val)
{
char *ptr;
int i;
if (val == NULL)
return false;
for (i = 0; buff != NULL && tokens[i] != NULL; i++) {
ptr = strstr(buff, tokens[i]);
if (ptr == NULL)
return false;
buff = (ptr + strlen(tokens[i]));
}
// Here, you reached the point you want, based on the tokens you seek
if (buff == NULL)
return false;
*val = strtoul(buff, NULL, 10);
}
So, you can be able to call this function like this:
char *tokens[] = { "CCLK: \"" };
uint32_t year;
if (parse_answer_to_uint32(myGsm.read().c_str(), tokens, &year) == false)
return -1;
printf("year is = %d\n", year);
The printf will print 2020 based on the example above.
This function is pretty flexible and generic enough. All you need is to pass different tokens to reach different points of the string and reach the value you want.
Take character buffer, Concat data comming from serial into this buffer, and process that buffer for comparison.

Connecting signals coming from widgets in a QVector

I'm working on the following Window with QT:
For my rows i have the following structure:
typedef struct
{
struct{
int x;
int y;
int width;
int height;
int layer;
int idx;
}outputSettings;
QDoubleSpinBox *xSpinBox;
QDoubleSpinBox *ySpinBox;
QDoubleSpinBox *heightSpinBox;
QDoubleSpinBox *widthSpinBox;
QDoubleSpinBox *layerSpinBox;
// Checkboxes
QCheckBox *channelCheckBox;
}myUI;
QVector<myUI> inputBoxes; // Create a row of input boxes per channel
I then create them in a for loop:
for(i = 0; i < inputChannels; ++i)
{
inputBoxes[i].channelCheckBox = new QCheckBox;
inputBoxes[i].channelCheckBox->setChecked(true);
inputBoxes[i].xSpinBox = new QDoubleSpinBox;
inputBoxes[i].xSpinBox->setRange(minXPos, maxXPos);
inputBoxes[i].xSpinBox->setSingleStep(1);
inputBoxes[i].xSpinBox->setValue(0);
inputBoxes[i].xSpinBox->setDecimals(0);
connect(inputBoxes[i].xSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setXValue(double)));
inputBoxes[i].ySpinBox = new QDoubleSpinBox;
inputBoxes[i].ySpinBox->setRange(minYPos, maxYPos);
inputBoxes[i].ySpinBox->setSingleStep(1);
inputBoxes[i].ySpinBox->setValue(0);
inputBoxes[i].ySpinBox->setDecimals(0);
connect(inputBoxes[i].ySpinBox, SIGNAL(valueChanged(double)), this, SLOT(setYValue(double)));
...
Now i get stuck on the connect. I want to connect the valueChanged property of my spinboxes to my outputSettings struct. This struct will be my return type at the end.
I implemented the following slots:
public slots:
void setXValue(double x){inputBoxes[0].outputSettings.x = int(x);}
void setYValue(double y){inputBoxes[0].outputSettings.y = int(y);}
...
But here i don't know what vector item called the function. (currently i just entered inputBoxes[0] as a dummy)
My first idea was to add an extra parameter int channel. But then the connect doesn't work. So i tried to work around that with QMapper. But that doesn't seem to be a good option to me and i didn't really get it running.
I would largely appreciate if someone could help me out here or at least point me in the right direction.
Cheers.
Implement it by using a lambda function in your connect
connect(inputBoxes[i], static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
[i](double value)
{
// use i as your vector index here
handleDoubleSpinBoxChanged(i, value);
});
Then you can change your slot function to
void handleDoubleSpinBoxChanged(int i, double value)
{
inputBoxes[i].outputSettings.x = int(x);
}
Second option is to get the spin box index from the sender object
you will have to store it first inside your loop
inputBoxes[i].xSpinBox->setProperty("index",i);
Then you can get it
void MainWindow::setXValue(double d)
{
QDoubleSpinBox * sb = qobject_cast<QDoubleSpinBox *>(QObject::sender());
int iCallerVectorIndex = -1;
if (sb != Q_NULLPTR)
{
iCallerVectorIndex = sb->property("index").toInt(); // to get the caller index.
}
}
If I got you right, in your SLOT method you can call sender() to retrieve the object who emitted the signal. You can compare in a loop the spinBoxes of each of your inputBoxes to find out what caused the SLOT to execute, something like:
// in your SLOT method:
for (int i = 0; i < inputChannels; i++){
if (inputBoxes[i].xSpinBox == (QDoubleSpinBox *)sender()){
// the xSpinBox of the i-th inputBox emitted the signal
break();
}
}
You can also just make myUI a QObject and add slot function there.
You wouldnt need any indexes then.
typedef struct
{
Q_OBJECT
struct{
int x;
int y;
int width;
int height;
int layer;
int idx;
}outputSettings;
QDoubleSpinBox *xSpinBox;
QDoubleSpinBox *ySpinBox;
QDoubleSpinBox *heightSpinBox;
QDoubleSpinBox *widthSpinBox;
QDoubleSpinBox *layerSpinBox;
// Checkboxes
QCheckBox *channelCheckBox;
public slots:
setXValue(double);
setYValue(double);
}myUI;
Example of connect call:
connect(inputBoxes[i].ySpinBox, SIGNAL(valueChanged(double)), inputBoxes[i], SLOT(setYValue(double))
or you can call connect in constructor of myUI:
myUI() {
connect(xSpinBox, SIGNAL(valueChanged(double)),
this, SLOT(setXValue(double))
connect(ySpinBox, SIGNAL(valueChanged(double)),
this, SLOT(setYValue(double))
}
I think that would be much simpler and intuitive because your object is responsible to setting his own members and you dont need to remember any indexes.

How can i make a QList<QVector3D> unique

I have a QList consist of QVector3D. A QVector3D represents a vertex or a point. This List holds also all vertices of a STL-File. The problem is that a vertex exist multiple times in the list. In need a list of the unique vertices of a STL-File. How can i implement it with Qt 5.0.2?
QSet uses a hash-function for ensuring the uniqueness of the value (QMap uses operator <)
There is no qHash implementation for QVector3D in Qt.
You could implement your own one e.g. as in example:
//place anywhere in Qt-code
#include <QSet>
#include <QVector3D>
#include <QList>
uint qHash(const QVector3D &v)
{
return qHash( QString( "%1x%2x%3" ).arg(v.x()).arg(v.y()).arg(v.z()) ) ;
}
int foo()
{
QList<QVector3D> uvector3D_1;
QSet<QVector3D> uvector3D_2;
uvector3D_2 = QSet<QVector3D>::fromList(uvector3D_1);
return 0;
}
static int testFoo = foo();
Of cause it is not the fastest one, it relies on Qt's function qHash for QString. But I think it's good for demonstration.
QList<QVector3D> originalVector = ...;
then either:
QSet<QVector3D> noDublicatesSet = QSet<QVector3D>::fromList(originalVector);
or
QSet<QVector3D> noDublicatesSet = originalVector.toSet();
also you can add something like if you need QList back..
QList<QVector3D> destinationVector = QList<QVector3D>::fromSet(noDublicatesSet);
you also will need those things (sorry has them in my code for ages.. forgot that they are external).. you might want to change hash function:
#define ROTL10(x) (((x) << 10) | (((x) >> 22) & 0x000000ff))
#define ROTL20(x) (((x) << 20) | (((x) >> 12) & 0x0000ffff))
uint qHash(double data)
{
union U {
quint64 n;
double f;
};
U u;
u.f = data;
return u.f;
}
inline uint qHash(const QVector3D &v, uint seed)
{
return qHash(v.x()) ^ ROTL10(qHash(v.y())) ^ ROTL20(qHash(v.z()));
}
P.S. that's a code for Qt 5.0, actually to add missing qHash() for vectors, that's why they dont fit in QSet/QHash by default
Starting from Qt 5.14, you can use the new constructor:
template <typename InputIterator> QSet::QSet(InputIterator first, InputIterator last
Here is an example taken from the docs:
// For example, if you have code like
QStringList list;
QSet<QString> set = QSet<QString>::fromList(list);
// you can rewrite it as
QStringList list;
QSet<QString> set(list.begin(), list.end());

Resources