char array variable name want to use in variable in Arduino IDE - arduino

i created char array
char Jan1[] = "1,2,3,4";
char Jan2[] = "5,7,3,4";
char Jan3[] = "10,9,3,4";`
the above char arrays i want to use it as shown below in for loop each time it will iterate and print, print is an example i am processing this string further in code, but it is giving error. if instead of yy i use Jan1 then it is printing properly. what is the other way i can use yy as to get print char array as string.
for(int i=1;i<=2;i++)
{
char yy[4];
sprintf(yy,"Jan%d",i);
String presentMonth = String(yy);
Serial.print(presntMonth);
}

So by the comments it seems that what you want is to print the contents of the JanX variable based on an index variable.
Missunderstanding
First of all you need to understand the difference between strings as datatypes and variable names. The former are ways to represent a sequence of characters (used mainly, but not only, to display output messages to any sort of output like a file, a console etc..). The latter are names that you use while coding and they can be whatever you want but they will never appear in the final program.
This for instance creates a String (datatype) named hello which contains the sequence of characters h e l l o.
String hello = "Hello";
Nothing prevents me to assign goodbye to it:
hello = "Goodbye"
Serial.print(hello); // This will print "Goodbye"
In general (apart from very hacky ways) you can't retrieve the name of the variable from your program and have them ready in your executable.
Issue
char Jan1[] = {'1','2','3'};
String yy = "Jan1"
Serial.print(yy); // This will print "Jan1"
To print the items in Jan1 you need to iterate through the values.
void printItems(char* s,int N){
for ( i = 0; i<N; i++ )
{ Serial.print(s[i]); }
}
Since Arduino provides the String class, however, it would be better to do this:
String Jan1 = "1,2,3,4";
Serial.print(Jan1); // This iterates under the hood, takes care of the length, and all the good stuff.
Solution
You want to do something a little more advanced, you want to point to a particular string based on a variable, then print the content of the retrieved string.
I can think of two ways for doing so: by using an list of strings or via a hashmap.
List of strings
String list[] = {"1,2,3,4" , "4,5,6,7", ... };
for(int i = 0; i < sizeof(list)/sizeof(String) ; i++ ){
Serial.print(list[i])
}
Hashmap
The reason I am thinking about this is because you want a string as the "index" that let's you lookup the string, so you can "search" by name. The easiest and quickest method I can think of is to declare an array of structs string_name;string_content and use strcmp to iterate through the array of structs until the needed one is found.
typedef struct{ String name; String content;} element_t;
element_t dict[] = { {"Jan1","1,2,3,4"} , {"Jan2","2,3,4,5"} ... }'
// Note this is not even close to perfect (for instance lacks check if key does not exists)
String lookup(element_t DICT, int DICT_SIZE, String key){
// Iterate through the elements, use strcmp to retrieve it
for(int i = 0; i < DICT_SIZE ; i++ ){
if(strcmp(DICT[i].name,key) {
return DICT[i].content;
}
}
}
// Now create the key, as in your code, and then lookup.
for(int i=1;i<=2;i++)
{
char yy[4];
sprintf(yy,"Jan%d",i);
String presentMonth = lookup(dict,dict_size,yy);
Serial.print(presntMonth);
}

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.

Convert String to Char* and Hash It using SHA-256

I'm trying to concatenate the current DateTime to my devices Mac Address in the following format: aa:bb:cc:dd:ee:ffYYmmDDhhMMss so I can hash it and send it to a web service every time I collect new data (so I'll have to hash it in every loop)
I managed to concatenate the two values (mac address + datetime) and converted it to char array
addressDateTime.toCharArray(thisThing, 28);
However, I'm kind of lost as to how to continue.
I've also tried to read the resulting char* with this cycle but I'm not understanding why it doesn't work:
void loop() {
while (!timeClient.update()) {
timeClient.forceUpdate();
}
String addressDateTime = getPayload(); //this gets the *aa:bb:cc:dd:ee:ffYYmmDDhhMMss* string
char* hashThis;
addressDateTime.toCharArray(hashThis, 28);
for (int i = 0; i < sizeof(hashThis); i++) {
char str[3];
sprintf(str, "%02x", hashThis[i]);
Serial.print(str);
}
delay(5000);
}
Am I converting the String to char* correctly?
How should I go about Hashing the char*?
Or can I Hash the String without converting it to to char*?
Update:
My code's looking like this atm
while (!timeClient.update()) {
timeClient.forceUpdate();
}
String addressDateTime = getPayload();
char hashThis[30];
addressDateTime.toCharArray(hashThis, 30);
for (int i = 0; i < sizeof(hashThis); i++) {
Serial.printf("%02x", hashThis[i]);
}
delay(5000);
}
So I managed to convert the String to Char* Except that the output is looking like this 33433a37313a42463a31443a34323a463431393035303531343038323700 instead of (for example) aa:bb:cc:dd:ee:ff190505141037
After figuring out why my char* array outputs like that I still have to hash it.
Thanks for helping me get this far, I still have ways to go
You're not allocating space to store the C string that you're getting from addressDateTime.
hashThis is a char* which is a pointer to a character. It hasn't been set to anything so it's just... random. Which will almost certainly make your program crash or at least misbehave badly.
Given your code, the quickest fix is to change
char* hashThis;
to
char hasThis[30];
addressDateTime.toCharArray(hashThis, 30);
I changed 28 to 30 because aa:bb:cc:dd:ee:ffYYmmDDhhMMss is actually 29 characters long and also requires an extra byte for the C string null terminator character. I'm not 100% sure if the toCharArray() method sets the null terminator; if it doesn't, you'd need to add
hasThis[29] = '\0';
You can avoid that by just using the String c_str() method, which returns a char* to the internal buffer that String uses to hold the string.
In that case you could rewrite
char* hashThis;
addressDateTime.toCharArray(hashThis, 28);
as
char* hashThis = addressDateTime.c_str();
By the way, you can also just do
Serial.printf("%02x", hashThis[i]);
and dispense with the snprintf(). Kudos on getting the right buffer size there, though!
UPDATE
In your updated question, you said that you're expecting to see output that looks like:
aa:bb:cc:dd:ee:ff190505141037
instead of:
33433a37313a42463a31443a34323a463431393035303531343038323700
Your code is
for (int i = 0; i < sizeof(hashThis); i++) {
Serial.printf("%02x", hashThis[i]);
}
You're writing each character as a two digit hexadecimal number, so you're going to see the number in hexadecimal that represents the character, not the character itself. If you want to see the characters, do:
for (int i = 0; i < strlen(hashThis); i++) {
Serial.printf("%c", hashThis[i]);
}
or (better)
for (int i = 0; i < strlen(hashThis); i++) {
Serial.print(hashThis[i]);
}
or (best)
Serial.println(hashThis);
Note that I changed your sizeof to a strlen. If for some reason you put a shorter string in hashThis, strlen will do the right thing whereas sizeof will always return the length that hashThis was declared with rather than the length of the string in it.

D lang appending to multidimensional dynamic array

I want to append a 2D array to my 3D array. I expect it should be same as int[] arr; arr ~= 3;
void readInput()
{
char[][][] candidate;
char[] buff;
size_t counter = 0;
while ( stdin.readln(buff) )
{
char[][] line = buff.chomp().split();
writeln(line);
candidate ~= line;
writeln(candidate);
if (++counter > 1 ) break;
}
}
And I send the inputs below
201212?4 64
20121235 93
I expect a output like
[["201212?4", "64"], ["20121235", "93"]]
But instead I see
[["20121235", "93"], ["20121235", "93"]]
=~ replaces all the elements in the array with the last added. Where am I doing wrong? How can I meet my expectation?
The problem here is that byLine is reusing buf (that's actually one reason why it asks for a mutable buffer and returns mutable - as a warning that it might change on you).
So when you ~= it, it is really appending the one array multiple times all with a pointer to the same data, so when it changes, that change is seen each time.
You can fix it by adding a .dup to the array you are appending.

Storing a char in a char pointer

I have a global variable that is a *char. My main function header reads as int main(int argc, char* argv[argc]){...}. These two lines of code have to remain the way they are. The first argument of my main function is a number of type *char, that I convert to a char using atoi(...);. I am basically changing the ASCII value to its corresponding character. Now I want to store this local variable character I have into the global variable that is a char pointer. I know the problem is related to allocation of memory, but I am not sure how to go about this.
My code:
char* delim;
int main(int argc, char* argv[argc])
{
char delimCharacter;
if (isdigit(*(argv[3])) == 0) delim = argv[3]; //you can pass in a character or its ascii value
else { //if the argument is a number, then the ascii value is taken
delimCharacter = atoi((argv[3]));
printf("%s\t,%c,\n", argv[3], delimCharacter);
//sprintf( delim, "%c", delimCharacter ); // a failed attempt to do this
*delim = delimCharacter;
//strncpy(delim, delimCharacter, 1); // another failed attempt to do this
}
//printf("%s\n",delim);
This yields a seg fault.
You need to verify you have got (at least) 3 arguments before you start using them.
if (argc < 4)
{
printf("Need 3 args");
exit(1);
}
Then you need to allocate some memory to put the character in.
delim = malloc(2);
// TODO: Should check the result of malloc before using it.
*delim = delimCharacter;
delim[1] = 0; // Need to NULL terminate char*
You're dereferencing an uninitialized pointer. delim never gets initialized when it goes into the else block.
char delim[] = ","; // anything really, as long as as it's one character string
...
delim[0] = delimCharacter;
In addition to your memory issue, I think you are confused about what atoi does. It parses a string representation of a number and returns the equivalent int value, e.g. "10000" => 10,000. I think that you think it will give you the ASCII value of a character, e.g. "A" =>65.
Since you have a char *, and you are (I think) assuming that it contains a single character, you could simply do this:
delimCharacter = *(argv[3]);
However, there really seems to be no need to use the intermediate step of assigning this value to a char variable at all. If the end goal is to have delim point to the char that is the delimiter, then it seems this is all you need to do:
delim = argv[3];
Not only does this remove unnecessary code, but it means you would no longer need to allocate additional memory for delim to point to.
I would also declare delim as a const char * since I assume there is no reason to change it.

Pointer won't return with assigned address

I'm using Qt Creator 4.5 with GCC 4.3 and I'm having the following problem that I am not sure is Qt or C++ related: I call a function with a char * as an input parameter. Inside that function I make a dynamic allocation and I assign the address to the char *. The problem is when the function returns it does not point to this address anymore.
bool FPSengine::putData (char CommandByte , int Index)
{
char *msgByte;
structSize=putDatagrams(CommandByte, Index, msgByte);
}
int FPSengine::putDatagrams (char CommandByte, int Index, char *msgByte)
{
int theSize;
switch ( CommandByte ) {
case (CHANGE_CONFIGURATION): {
theSize=sizeof(MsnConfigType);
msgByte=new char[theSize];
union MConfigUnion {
char cByte[sizeof(MsnConfigType)];
MsnConfigType m;
};
MConfigUnion * msnConfig=(MConfigUnion*)msgByte;
...Do some assignments. I verify and everything is OK.
}
}
return theSize;
}
When I return the pointer it contains a completely different address than the one assigned in putDatagrams(). Why?
...
Ok thx I understand my mistake(rookie mistake :( ). When sending a pointer as an input parameter to the function you send the address of your data but not the address of your pointer so you cant make the pointer point somewhere else...it is actually a local copy like Index. The only case the data would of been returned succesfully with the use of a char * is by allocating the memory before the function call:
bool FPSengine::putData (char CommandByte , int Index)
{
char *msgByte;
msgByte=new char[sizeof(MsnConfigType)];
structSize=putDatagrams(CommandByte, Index, msgByte);
}
int FPSengine::putDatagrams (char CommandByte, int Index, char *msgByte)
{
int theSize;
switch ( CommandByte ) {
case (CHANGE_CONFIGURATION): {
theSize=sizeof(MsnConfigType);
union MConfigUnion {
char cByte[sizeof(MsnConfigType)];
MsnConfigType m;
};
MConfigUnion * msnConfig=(MConfigUnion*)msgByte;
...Do some assignments. I verify and everything is OK.
}
}
return theSize;
}
There are two ways. The pass-by-value way (C style):
int FPSengine::putDatagrams (char CommandByte, int Index, char **msgByte)
Note the second * for msgByte. Then inside of putDatagrams(), do:
*msgByte = new char[theSize];
In fact, anywhere in that function where you currently have msgByte, use *msgByte. When calling putDatagrams(), do:
structSize=putDatagrams(CommandByte, Index, &msgByte);
And the second way, since you're in C++, you could use pass-by-reference. Just change the signature of putDatagrams() to:
int FPSengine::putDatagrams (char CommandByte, int Index, char * &msgByte)
And you should be good. In this case, you shouldn't need to modify the caller or anything inside of your putDatagrams() routine.
Well, yes. Everything in C++ is, by default, passed by value. Parameters in the call putDatagrams(a, b, c) are sent by value - you wouldn't expect assigning to index in the code to change the value of b at the call site. Your msgByte=new char[theSize]; is just assigning to the local variable msgByte, overwriting the value passed in.
If you want to change a passed parameter such that the call site variable changes, you'll need to either pass by reference, or (in this case) pass a "pointer to a pointer` (and deference away the first pointer, assigning to the actual pointer).

Resources