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

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(){
}

Related

Overloading function handling char and String

I'm making a function to handle a message, then print the message using Serial.println(). I have it working, but ran into an issue I can't explain. The first sample code below works, the second (swapping the order of my function declaration) will compile and load, but causes the Teensy 4.1 to crash. I'm using PlatformIO on VSCode.
Can anyone tell me what is wrong with the second code, and why it will compile without error, but not run?
This works:
#include <Arduino.h>
void LogMsg(const char *msg){
Serial.println(msg);
}
void LogMsg(String s){ LogMsg(s.c_str()); }
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("reset");
}
void loop() {
// put your main code here, to run repeatedly:
String str3 = "testing string cat ";
uint32_t var = 12345;
LogMsg(str3 + var);
delay(500);
}
This compiles, loads, but crashes, causing continuous resets:
#include <Arduino.h>
void LogMsg(String s){ LogMsg(s.c_str()); } // <-- swapped order
void LogMsg(const char *msg){ // <-- swapped order
Serial.println(msg);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("reset");
}
void loop() {
// put your main code here, to run repeatedly:
String str3 = "testing string cat ";
uint32_t var = 12345;
LogMsg(str3 + var);
delay(500);
}
Edit: The definition of void LogMsg(String s) was changed to reflect error in original and the simplification suggested by #hcheung. Behavior remains the same. The first instance works, the second crashes.
C strings are terminated with '\0'. So toCharArray() will append a null character to your Ardunio String. Otherwise you would have to provide a length with the char pointer everytime you want to use that string.
Your char array must be big enough to fit this extra character or you will cause an access violation if toCharArray does not throw an exception first.

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.

Convert string as hex to hexadecimal

I have a function that takes an uint64_t variable. Normally I would do this:
irsend.sendNEC(result.value);
result.value is an uint64_t as hexadecimal (I think). If I do this:
String((uint32_t) results.value, HEX)
I get this:
FF02FD
If I do:
irsend.sendNEC(0x00FF02FD)
it works perfectly and is what I want.
Instead of grabbing the result.value, I want to write it as a string (because that's what I get from the GET request). How do I make "FF02FD" into 0x00FF02FD?
EDIT:
Maybe this makes it easier to understand:
GET: http://192.168.1.125/code=FF02FD
//Arduino grabs the FF02FD by doing:
for (int i = 0; i < server.args(); i++) {
if (server.argName(i) == "code") {
String code = server.arg(i);
irsend.sendNEC(code);
}
}
This is where I get the error:
no matching function for call to 'IRsend::sendNEC(String&)'
because:
void sendNEC(uint64_t data, uint16_t nbits = NEC_BITS, uint16_t repeat = 0);
Comment writeup:
As already suggested, a string containing a hexadecimal value can be converted to an actual integer value using the C standard library functions such as "string to unsigned long" (strtoul) or "string to unsigned long long" (strtoull). From Arduino-type String one can get the actual const char* to the data using the c_str() member function. All in all, one does a hex-string to integer conversion as
uint64_t StrToHex(const char* str)
{
return (uint64_t) strtoull(str, 0, 16);
}
Which can then in code be called as
for (int i = 0; i < server.args(); i++) {
if (server.argName(i) == "code") {
String code = server.arg(i);
irsend.sendNEC(StrToHex(code.c_str()));
}
}
Appendum: Be carefull about using int or long on different platforms. On a Arduino Uno/Nano with a 8-bit microcontroller, such as the ATMega328P, an int is a int16_t. On the 32-bit ESP8266 CPU, an int is int32_t.

Storing Variables in a Class

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

seg fault / pointer assistance

so i know the bases of programming, i have a decent amount of experience with java, but im learning C for school right now. I still dont completely understand the whole pointer aspect, which is what im sure caused the fault. This program works fine when run on my computer, but when i try and run it on my schools unix shell it gives me a seg fault. if someone could please explain to me why or how ive misused hte pointers, that would help me greatly.
//Matthew Gerton
//CS 222 - 002
//10/10/14
//HW Six
//libraries
#include<stdio.h>
#include<string.h>
#define max_Length 256
//prototypes
void decode(char *a, char *b);
void trimWhite(char *a);
void encode(char *a, char *b);
int main(void)
{
//character arrays
char coded[max_Length], decoded[max_Length];
//decode the sample phrase
char sample[] = {'P','H','H','W','D','W','C','R','R','F','D','Q','F','H','O','H','G','J',
'R','W','R','P','H','W','U','R','K','R','W','H','O','U','R','R','P','I','R','X','U'};
decode(sample, decoded);
//scans a user input string to decode, and decodes it
printf("\nPlease enter a phrase to decode: ");
gets(coded);
trimWhite(coded);
decode(coded, decoded);
//scans a user input phrase to encode
printf("\nPlease enter a phrase to encode: ");
gets(coded);
trimWhite(coded);
encode(coded, decoded);
}
//removes any spaces from the input
void trimWhite(char *a)
{
char temp[max_Length];
int z=0, y=0;
while(a[z]!='\0')
{
if(a[z]!=' ')
{
temp[y]=a[z];
y++;
}
z++;
}
temp[y] = '\0';
strcpy(a,temp);
}
//decodes any phrase
void decode(char *a, char *b)
{
int i=0,n;
memset(b, '\0', sizeof(b));
while(a[i]!='\0')
{
n=(int)a[i];
if(n<97)
n=n+32;
if(n<=99)
n=n+23;
else
n = n-3;
b[i]= (char) n;
i++;
}
b[i]='\0';
printf("Coded message: %s\n", a);
printf("Decoded message: %s\n", b);
}
//codes an input phrase
void encode(char *a, char *b)
{
int i=0,n;
memset(b, '\0', sizeof(b));
strcpy(b,a);
while(a[i]!='\0')
{
n=(int)a[i];
if(n<97)
a[i] = (char)(n+32);
if((n>120)
a[i] = (char)(n-23);
else
a[i] = (char)((n+3);
i++;
}
printf("Coded message: %s\n", a);
}
Your main problem is here:
char sample[] = {'P','H','H', /* snip */ ,'R','X','U'};
The sample[] array is not zero-terminated which may cause the decode() function to copy many more characters than intended, thus overwriting other variables. You need to explicitly add a terminating zero when using an initializer-list:
char sample[] = {'P','H','H', /* ... */ ,'R','X','U',0};
Or you can initialize the array using a string literal, which does include a terminating zero:
char sample[] = "PHHWDWCRRFDQFHOHGJRWRPHWURKRWHOURRPIRXU";
You should probably read "Why is the gets function dangerous".
...
void decode(char *a, char *b)
{
int i=0,n;
memset(b, '\0', sizeof(b));
Also note that the size of the array is lost when it is passed to a function. The function only receives a pointer to its first element. The memset() call above will only zero sizeof(char*) bytes (usually 4 or 8). This doesn't matter though because, as far as I can tell, you only need to zero the first byte. You could simply write:
b[0] = 0;

Resources