Different result between Serial.print and Serial.printf in ESP32 - arduino

I want to print my string variable using printf method:
id = 6415F1BF713C
Serial.printf("id: %s\n\n", id);
Serial.print(id);
The result that I got was:
id: ⸮⸮⸮?
6415F1BF713C
is there any thing that's wrong?
Thanks.
Update :
//get device id
String getDeviceID() {
uint64_t chipid = ESP.getEfuseMac(); // The chip ID is essentially its MAC address(length: 6 bytes).
uint16_t chip = (uint16_t)(chipid >> 32);
char devID[40];
snprintf(devID, 40, "%04X%08X", chip, (uint32_t)chipid);
return devID;
}
String id = getDeviceID();
Serial.printf("id: %s\n\n", id);
Serial.print(id);

You didn't offer enough code to properly debug this, but I'm guessing what you mean is
String id = "6415F1BF713C";
Serial.printf("id: %s\n\n", id);
Serial.print(id);
The %s format in the printf() method expects to take a C/C++ char *, not a String. When you passed it a String, it printed the memory address of the String object - four characters which would appear as garbage, as you saw.
C and C++ use char * (pointers to characters) and char [] (arrays of characters) to represent strings. These are different from the Arduino String class, and people often confuse them.
To use the printf() method with a String you need to get its C string pointer, like this:
Serial.printf("id: %s\n\n", id.c_str());
The reason that this:
Serial.print(id);
works is that the print() method has a form that specifically expects to take a String object as an argument.

Related

Recieving two sets of string-data from Processing to Arduino into two variables

I'm desperatly trying to get arduino to divide a string from processing into two sets of variables. In the code below I've decided to just type the important parts but x and y does of course contain the correct values. Any solution would be appreciated. These are my two attempts so far:
Attempt 1 doesn't work at all.
1.Processing:
myPort.write(x + "," + y + "\n");
1.Arduino:
String tempX = Serial.readStringUntil(44);
String tempY = Serial.readStringUntil(10);
String x = tempX.substring(0,tempX.length() -1);
String y = tempY.substring(0,tempY.length() -1);
Attempt 2 where x works correctly but not y.
2.Processing:
String [] dataToSend = new String [2];
dataToSend [0] = x;
dataToSend [1] = y;
String joinedData = join(dataToSend, ":");
myPort.write(joinedData);
2.Arduino:
String x = Serial.readStringUntil(":");
Serial.read(); //next character is comma, so skip it using this
String y = Serial.readStringUntil('\0');
First, don't worry about combining them on the Processing side. Sending two strings one right after the other is the same as sending one long string. It's all being broken into bytes on the Serial line and nobody can tell where one print line stops and the next starts.
myport.write(x);
myport.write(',');
myport.write(y);
myport.write('\n')
will work just as good.
Then on the Arduino side you most likely want to shy away from the String class. Read the data character by character into a char array.
char myArray[howLongTheStringIs];
char x[howLongXIs];
char y[howLongYIs];
int index = 0;
This gets called over and over in loop and picks up serial data as it comes in:
while (Serial.available()){
char c = Serial.read();
myArray[index] = c; // add c to the string
myArray[++index] = 0; // null terminate our string
if(c == '\n'){ // if we are at the end of the string
handleString();
}
}
Then you have a function to parse your string there are lots of ways to do that:
If you don't know anything about the strings other than the separator use strtok:
void handleString(){
char* ptr = strtok(myArray, ":"); // get up to the ":" from the string
strcpy(x, ptr); // copy into x
ptr = strtok(NULL, "\n"); // get from the separator last time up to the next "\n"
strcpy(y, ptr); // copy into y
index = 0 // reset our index and
myArray[0] = 0; // and clear the string
}
That's all untested and uncompiled and written in the reply box, so if I made a little typo in there please forgive and correct. But something like this should work. If you already know the exact lengths of the strings (or can send them from the processing code) then the handleString method can be simpler. If you've got something short to do with x and y and don't need them after that then maybe you can just keep pointers to where they are in myArray. It all depends on what the larger picture goal of your code is. But something like this should get the job done.

DXL convert hex string to char

I am parsing an OLE object in doors.
The representation mixes ascii characters and objdata (hex value of ASCII chars) numbers:
{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang2057{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
{\*\generator Riched20 10.0.17134}\viewkind4\uc1
\pard\f0\fs20{\object\objemb{\*\objclass Package}\objw4620\objh810{\*\objdata
01050000
02000000
08000000
5061636b61676500
00000000
00000000
d5c40000
02005f30306132636633392d323936612d346263612d396539342d383039343437336133343035
I am able to detect where my file starts using regex and objdata field.
Since my file extension is *.ole, I am going to search for the ".ole" string at the beginning of the objdata field (the long line starting with 0200) and backwards search for the 0200 hex string that.
My question is:
How can I convert from hex representation back to ascii a string in DXL?
Are there functions to perform this task? a simple cast would be enough? Or shall I write my own function to perform this task?
I wasn't able to find any hint on the ref manual, also some keyword or "RTFM page" would be gladly appreciated.
K.R.
The only support that I know of that might help you are char charOf(int asciiCode) and int(char ch).
I have not been able to spot ".OLE" (2E 4F 4C 45) or ".ole" (2E 6F 6C 65) in the line you posted, but assuming that these characters (or a combination of upper and lower characters) exist, one approach would be to walk through the objdata character for character (using a Buffer and an integer variable which loops over every character, something like int i = 0; int high; int low; Char c; while (...) { high = int(buf[i]); low = int(buf[i+1]); c = calculate_character_from_integers(high, low); i+=2; if c = ... then ...} and with this approach, whenever you have a new line, have another integer variable that points to the beginning of the line, and when you have something like "current character is 45 or 65 and the character before is 4C or 6C and the one before is 4F or 6F and the one before is 2E, then concatenate the file name from the start of the line." Not sure whether there are any scripts or snippets out in the wild that help here, perhaps you find something in the IBM DeveloperWorks DXL forums (hurry, they will cease to exist in two weeks)
I had to write a function from scratch based on Mike's reply and an old thread on IBM forums by user Mathias Mamsch.
I have many doubts on the buffer handling, buts it works fine for my purposes:
This functions performs the Hex2ascii translations of the string.
string Hex2Ascii(string &stringIn){
Buffer buf = create
string hexval
while(length(stringIn)>0){
hexval = iterateOnString(stringIn)
//print(charOf(intOfHex))
//print hexval
//print charOf(intOfHex(hexval))
buf += charOf(intOfHex(hexval))
}
return stringOf buf
}
It invokes other two functions; iterateOnString returns two chars to form a byte to be converted and removes it from the original string:
string iterateOnString(string &stringIn){
string StringOut
int x = length(stringIn)
if(x<2){
return ""
}
StringOut = stringIn[0:1]
stringIn = stringIn[2:]
return StringOut
}
then intOfHex converts the hex to int value, then the result is passed to charOf()
int intOfHex( string s ) {
if( "0x" == s[0:1] ) {
return intOf( realOf( eval_ "return_ (" s ") \"\"" ) )
} else {
return intOf( realOf( eval_ "return_ (0x" s ") \"\"" ) )
}
}
Any hint, optimization proposal or critic is welcome.
K.R.

Qt to Arduino Serial port communication and parsing

I am trying to create a software lighting desk by using Qt and Arduino with a DMX Shield. I've been able to establish communication between these two and can send commands over to Arduino Mega (at the moment the communication goes only one way). I am periodically (every 200 ms) sending values of 11 faders to Mega as a String.
eg.: A123 B234 C050 ... J222 M255
The values in the string above are variables based on the position of the sliders and should be used to adjust the values of light intensities saved into each fader on the Mega side. The Letters in each section identify corresponding fader. A = fader1, B = fader2, ... Just for clarity: I can bring up a light/s at a specific intensity -> these intensities are then assigned to a fader and when that fader is moved I want these values to adjust and be sent out to the actual lights/dimmers. The calculations work fine but my Mega would eventually become unresponsive.
I think my problem is parsing the incoming string. I have tried the strtok() method and readStringUntil() to no avail. It is also difficult to monitor the incoming strings in Serial Monitor as this is used for the communication with Qt.
Would be happy for any kind of help. Please ask questions if anything is unclear.
Edit:
This is one of my attempts at solutions
const char delim[2] = " ";
char *token;
if(Serial.available())
{
//incomingMessage = Serial.readString();
incomingMessage = Serial.readStringUntil("\n"); // read the whole string until newline
//Serial.println(incomingMessage);
const char* str = incomingMessage.c_str(); // convert it to a C String terminated by a null character "\0"
//Serial.println(str);
token = strtok(str, delim); // first part is a first section until delimiter occurs "-space- "
//Serial.println(token);
LX_Rated.commandLineResolve(token); // resolve it
while( token != NULL ) { // continue splitting and resolving the incoming message until it reaches the end
token = strtok(NULL, delim);
LX_Rated.commandLineResolve(token);
}
}
Edit2:
I have confirmed that I receive the whole string sent by Qt. When I try to tokenise it using the strtok() function and print out the first token I get back the whole string, the other tokens are empty. I don't see any mistake in my code here. I even tried to slow down the sending of the string from Qt to one per 5 sec. Does anybody have any idea what is going on? I don't see why this standard function doesn't work as expected. Please see the amended code below.
if(Serial.available()) {
incomingMessage = Serial.readStringUntil("\n");
Serial.println("ok");
Serial.flush();
char* nullTerminatedIncomingMessage = incomingMessage.c_str();
const char delimiter = " ";
char* token;
char* token1;
char* token2;
//char* secondToken;
token = strtok(nullTerminatedIncomingMessage, delimiter);
token1 = strtok(NULL, delimiter);
token2 = strtok(NULL, delimiter);
Serial.println(token); // print the first section
//Serial.println(incomingMessage);
Serial.flush();
Serial.println(token1);
Serial.flush();
Serial.println(token2);
Serial.flush();
//while(token != NULL)
// secondToken = strtok(NULL, delimiter);
//Serial.println(secondToken);
//Serial.flush();
incomingMessage = "";
}
Your mistake - at the very least - is in assuming that all the input is available when you expect it. You need to defer processing until an entire line has been assembled. Serial.readStringUntil blocks until an entire line is available, and that's not what you expect. You essentially need to replace Serial.available() with Serial.lineAvailable(), except the latter is not implemented.
This answer contains a complete solution to your issue - including both Qt and Arduino code - and an Arudino emulation layer. It might be a good starting point, especially that you can easily co-debug both Qt and Arduino projects from within one application and using one debugger!
As for difficulty in monitoring communication, you can(in Qt) dump everything you read into console and do the same for everything you write into the serial port. It will show in the console tab of QtCreator
#include <QDebug>
...
qDebug() << "whatever" << endl;
Aso for parsing the data you read from to serial port, take a look at this to see how to easily split the sliders info into individual strings(with QRegExp)
How Can I Split a String According To Delimiters in Qt?
I can't possibly guess why your arduino would be unresponsive without the code.
EDIT:
Is it possible, when you generate the string in Qt, that you separate the tokens by something other than space? Maybe tab("\t") or something? strtok accepts multiple delimiters in the delimiter string, may be something to try.
If that is not the case, there is the unlikely possibility that something's wrong with the strtok(...) function(btw. it modifies the original string, that in itself could be a problem). Also, strtok could return a NULL pointer, you don't seem to handle that case(some wrong input - print a message). You could try this as an alternative to normal strtok:
/**
* #brief custom strtok replacement with the same interface
* It does not modify the original string
* Token length is limited to 63 characters
* #param ptr pointer to the string or NULL
* #param delim delimiting character(only the first character will be used)
*/
const char * my_strtok(const char * ptr, const char * delim) {
// Persistent variables, it will remember pointer to the processed string
static const char * src;
static char buffer[64]; // Token is limited to 63 characters
if(ptr) { // Remember the pointer, if a new one was supplied
src = ptr;
}
if(src == NULL || *src == '\0')// Invalid / empty string / no next token - return NULL
return NULL;
char i = 0;
for(i = 0; i < 63 && *src != delim[0]; i++) {// Copy token until delimiter or end of buffer
buffer[i] = *(src++);
}
if(*src == delim[0]) // Skip over the delimiter to the begining of the next token
++src;
buffer[i] = '\0'; // Any returned string must be terminated
return buffer;
}
#include <cstdlib>
#include <cstring>
#include <cassert>
void test() {
const char * str1 = "123 456 asdf jkl;";
assert(strcmp("123", my_strtok(str1, " ")) == 0);
assert(strcmp("456", my_strtok(NULL, " ")) == 0);
assert(strcmp("asdf", my_strtok(NULL, " ")) == 0);
assert(strcmp("jkl;", my_strtok(NULL, " ")) == 0);
assert(NULL == my_strtok(NULL, " "));
assert(NULL == my_strtok(NULL, " "));
assert(strcmp("123", my_strtok(str1, " ")) == 0);
}

Send finger.fingerID to Bluetooth

I'm able to send some characters in blue tooth to my android device.
But after scanning my finger and send the finger.fingerID value to android device,
Only a special character was sent.
So it came to me that the value is Integer and tried to convert it to character but still getting some error.
When I run my code here, I immediately getting back to void setup();
int getFingerprintIDez() {
uint8_t p = finger.getImage();
if (p != FINGERPRINT_OK) return -1;
p = finger.image2Tz();
if (p != FINGERPRINT_OK) return -1;
p = finger.fingerFastSearch();
if (p != FINGERPRINT_OK) return -1;
// found a match!
Serial.print("Found ID #"); Serial.print(finger.fingerID);
Serial.print(" with confidence of "); Serial.println(finger.confidence);
String toStr;
char toChar[2];
toStr=String(finger.fingerID);
toStr.toCharArray(toChar, toStr.length());
BTSerial.write(toChar);
Serial.print(toChar);
return finger.fingerID;
}
Your toChar buffer is too small for a string that could possibly be 5 characters long. You should allocate 10 bytes instead, more than enough to hold any result.
toCharArray does not null-terminate the string so even if write() accepts null-terminated strings alone (it doesn't), it would run off the end of the string looking for a null. write() accepts either a single character or a pointer to a char array and the number of characters to be written.
You don't need to go through all this hassle; merely call:
BT.print(finger.fingerID);
And the built-in Print class will handle the conversion messiness for you.

Qt Check QString to see if it is a valid hex value

I'm working with Qt on an existing project. I'm trying to send a string over a serial cable to a thermostat to send it a command. I need to make sure the string only contains 0-9, a-f, and is no more or less than 6 characters long. I was trying to use QString.contains, but I'm am currently stuck. Any help would be appreciated.
You have two options:
Use QRegExp
Use the QRegExp class to create a regular expression that finds what you're looking for. In your case, something like the following might do the trick:
QRegExp hexMatcher("^[0-9A-F]{6}$", Qt::CaseInsensitive);
if (hexMatcher.exactMatch(someString))
{
// Found hex string of length 6.
}
Update
Qt 5 users should consider using QRegularExpression instead of QRegExp:
QRegularExpression hexMatcher("^[0-9A-F]{6}$",
QRegularExpression::CaseInsensitiveOption);
QRegularExpressionMatch match = hexMatcher.match(someString);
if (match.hasMatch())
{
// Found hex string of length 6.
}
Use QString Only
Check the length of the string and then check to see that you can convert it to an integer successfully (using a base 16 conversion):
bool conversionOk = false;
int value = myString.toInt(&conversionOk, 16);
if (conversionOk && myString.length() == 6)
{
// Found hex string of length 6.
}

Resources