I am trying to pass a char array variable as the 'msg' in the PubNub.publish(channel, msg) command. The 'msg' parameter in the command needs to be in JSON array format but my 'input' variable is a char array. The code is firmware for a Particle Photon
This works:
char msg[64] = "{\"Device\":\"on\"}";
PubNub.publish(channel, msg);
But this doesn't work
char msg[64] = "{\"DeviceID\": input}"; //'input' is my char variable for storing serial data
PubNub.publish(channel, msg);
#craig Conover Below is the code for "input" variable and there is data in it. It publishes correctly to particle.io but not to PubNub :
if(Serial1.available()){
Particle.publish("Tagged", "Tag Detected");
count = 0;
while(Serial1.available() && count < 12) // Read 12 characters and store them in input array
{
input[count] = Serial1.read();
count++;
delay(5);
}
Particle.publish("tagnumber", input, PRIVATE);
char msg[64] = "{\"DeviceID\": input}"; //'input' is my char variable for storing serial data
PubNub.publish(channel, msg);
Related
I have a uint8 array containing ASCII codes for characters and a string variable, and I wish to make a comparison between them. For example:
uint8[3] memory foo = [98, 97, 122]; // baz
string memory bar = "baz";
bool result = keccak256(abi.encodePacked(foo)) == keccak256(abi.encodePacked(bytes(bar))); // false
Here I want the comparison to succeed, but it's a failure because encodePacked will keep the padding of all the uint8 elements in the array when encoding it.
How can I do it instead?
You are currently comparing encoded value abi.encodePacked(foo)) to hashed value keccak256(abi.encodePacked(bytes(bar)), which would never equal.
The uint8 fixed-size array is stored in memory in three separate slots - one for each item - and each of the items is ordered right to left (little endian).
0x
0000000000000000000000000000000000000000000000000000000000000062
0000000000000000000000000000000000000000000000000000000000000061
000000000000000000000000000000000000000000000000000000000000007a
But the string literal is stored as a dynamic-size byte array ordered left to right (big endian):
0x
0000000000000000000000000000000000000000000000000000000000000020 # pointer
0000000000000000000000000000000000000000000000000000000000000003 # length
62617a0000000000000000000000000000000000000000000000000000000000 # value
So because the actual data is stored differently, you cannot perform a simple byte comparison of both arrays.
You can, however, loop through all items of the array and compare each item separately.
pragma solidity ^0.8;
contract MyContract {
function compare() external pure returns (bool) {
uint8[3] memory foo = [98, 97, 122]; // baz
string memory bar = "baz";
// typecast the `string` to `bytes` dynamic-length array
// so that you can use its `.length` member property
// and access its items individually (see `barBytes[i]` below, not possible with `bar[i]`)
bytes memory barBytes = bytes(bar);
// prevent accessing out-of-bounds index in the following loop
// as well as false positive if `foo` contains just the beginning of `bar` but not the whole string
if (foo.length != barBytes.length) {
return false;
}
// loop through each item of `foo`
for (uint i; i < foo.length; i++) {
uint8 barItemDecimal = uint8(barBytes[i]);
// and compare it to each decimal value of `bar` character
if (foo[i] != barItemDecimal) {
return false;
}
}
// all items have equal values
return true;
}
}
Can someone help me to understand how i need to send the parameters to the function "lora_rf_config" ? Thank you so much !
I try with:
char cfgred[7][10]={'lora_rf_config','915000000','10','0','1','8','14'};
lora_rf_config(7,&cfgred);
The function that im trying to use is:
static void lora_rf_config(int argc, char *argv[])
{
if (argc == 1) {
e_printf("OK%d,%d,%d,%d,%d,%d\r\n", g_lora_config.lorap2p_param.Frequency,
g_lora_config.lorap2p_param.Spreadfact,
g_lora_config.lorap2p_param.Bandwidth,
g_lora_config.lorap2p_param.Codingrate,
g_lora_config.lorap2p_param.Preamlen,
g_lora_config.lorap2p_param.Powerdbm );
return;
} else {
if (argc != 7) {
out_error(RAK_ARG_ERR);
return;
}
if (!(CHECK_P2P_FREQ(atoi(argv[1])) &&
CHECK_P2P_SF(atoi(argv[2])) &&
CHECK_P2P_BDW(atoi(argv[3])) &&
CHECK_P2P_CR(atoi(argv[4])) &&
CHECK_P2P_PREMLEN(atoi(argv[5])) &&
CHECK_P2P_PWR(atoi(argv[6])))) {
out_error(RAK_ARG_ERR);
return;
}
if (read_partition(PARTITION_0, (char *)&g_lora_config, sizeof(g_lora_config)) < 0) {
out_error(RAK_RD_CFG_ERR);
return;
}
g_lora_config.lorap2p_param.Frequency = atoi(argv[1]);
g_lora_config.lorap2p_param.Spreadfact = atoi(argv[2]);
g_lora_config.lorap2p_param.Bandwidth = atoi(argv[3]);
g_lora_config.lorap2p_param.Codingrate = atoi(argv[4]);
g_lora_config.lorap2p_param.Preamlen = atoi(argv[5]);
g_lora_config.lorap2p_param.Powerdbm = atoi(argv[6]);
write_partition(PARTITION_0, (char *)&g_lora_config, sizeof(g_lora_config));
e_printf("OK\r\n");
}
return;
}
The error that i got is:
..\..\..\src\application\RAK811\app.c(107): error: #26: too many characters in character constant
char cfgred[7][10]={'lora_rf_config','915000000','10','0','1','8','14'};
I dont have experience with this kind of arguments.
Thank you for your time.
lora_rf_config expects same arguments than main function: array of pointers to strings, and its length.
Strings in C are pointers to char, where the char buffer they point to has terminating NUL character (if NUL char is missing, then it's not a string, just a character array). In other words, there is no string type in C, but stringiness is determined by the actual data in the char array or buffer. Using "" string literal creates a string, IOW it adds that terminating NUL char in addition to what you write.
// cfgred is array([) of 7 pointers(*) to char.
// Note: string literals are read-only, so you must not modify these
// strings. If you want a modifiable string, this would be a bit more complex,
// but I think this is out of the scope of your question.
char *cfgred[7] = { "lora_rf_config" , "915000000", "10","0", "1", "8", "14"};
// you can get the number of elements in array by dividing its sizeof size (bytes)
// with the size of it's elements in bytes. Just make sure cfgred here is array...
// in the function it is pointer already (arrays get converted to pointers, so
// you can't do this inside the function, you have to do it where you still have
// the original array
int cfgred_len = sizeof cfgred / sizeof(cfgred[0]);
// when you pass array to function, it is automatically converted to pointer,
// so you must not use & when passing an array like this, otherwise types don't
// match
lora_rf_config(cfgred_len, cfgred);
As a side note, always turn on compiler warnings... They help you a lot, fix them. For gcc and clagn, use -Wall -Wextra, for Visual Studio use /W3 or prefereably /W4. And then fix any warnings you get, because they are probably something that doesn't do what you expect.
Your initialization is not done correctly, try changing
char cfgred[7][10]={'lora_rf_config','915000000','10','0','1','8','14'};
into
char cfgred[7][16]={"lora_rf_config","915000000","10","0","1","8","14"};
I'm trying to store results taken from a MySQL query into an array of structs. I can't seem to get the types to work though, and I've found the MySQL documentation difficult to sort through.
My struct is:
struct login_session
{
char* user[10];
time_t time;
int length;
};
And the loop where I'm trying to get the data is:
while ( (row = mysql_fetch_row(res)) != NULL ) {
strcpy(records[cnt].user, &row[0]);
cnt++;
}
No matter what I try though I constantly get the error:
test.c:45: warning: passing argument 1 of ‘strcpy’ from incompatible pointer type
/usr/include/string.h:128: note: expected ‘char * __restrict__’ but argument is of type ‘char **’
test.c:45: warning: passing argument 2 of ‘strcpy’ from incompatible pointer type
/usr/include/string.h:128: note: expected ‘const char * __restrict__’ but argument is of type ‘MYSQL_ROW’
Any pointers?
Multiple problems, all related to pointers and arrays, I recommend you do some reading.
First, char * user[10] is defining an array of 10 char * values, not an array of char, which is was I suspect you want. The warning even says as much, strcpy() expects a char *, the user field on its own is seen as a char **.
Second, you're one & away from what you want in the second argument.
Copied from mysql.h header:
typedef char **MYSQL_ROW; /* return data as array of strings */
A MYSQL_ROW is an array of char arrays. Using [] does a dereference, so you dereference down to a char * which is what strcpy() takes, but then you take the address of it using &.
Your code should look more like this:
struct login_session
{
char user[10];
time_t time;
int length;
};
while ( (row = mysql_fetch_row(res)) != NULL ) {
strcpy(records[cnt].user, row[0]);
cnt++;
}
I don't know what guarantees you have about the data coming from mysql, but if you can't be absolutely sure that the rows are <= 10 characters long and null ('\0') terminated, you should use strncpy() to avoid any possibility of overflowing the user array.
When i try to use the code, I find that row[i] is the i'th row in the form of a string. But I need to use my data which was in the form of a int. Also, the row[i] contains the entire row in the form of a string. How do I extract the data from it. I tried to parse the data and convert it into integer, but the entire data is just one string and does have any spaces! so i am having a difficult time doing the parsing as I have no way to know where the previous field ended and the next began in the dataset.
So to sum it up;
when i do:
mysql_real_connect(conn, "localhost", "root", "abcd", "Hybr", 0, NULL, 0);
mysql_query(conn, "SELECT * FROM Data");
result = mysql_store_result(conn);
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
for(i = 0; i < num_fields; i++)
{
row[i] //this is a string containing all the
//fields. I want the individual values !
}
}
My Data 34, 45, host gets converted into a string "34 45 host". And the wierd thing is that when i print row[i], atleast it prints the spaces but when i copy it into a char*, the space somehow disappears! so it becomes impossible to parse it.
I think there is a different way of reading records ,maybe I have overlooked some part of the API, but i cant seem to find which ...
EDIT
I realised I havent overlooked the API; its just that the row[i] is an array of strings. I still need help extracting the individual values from it.
You can use atoi on the field if you know it will be int. For example, units is int and so "SELECT units FROM data" could be read into an int array or whatever.
mysql_query conn, "SELECT units FROM data"
res = mysql_store_result(conn)
num_fields = mysql_num_fields(res)
while (row = mysql_fetch_row(res))
for i = 0; i < num_fields; i++
printf "%03i ",atoi(row[i])
puts ""
I try to execute mysql query passing variable. Here is my code
char str[100] = "My String";
mysql_query(conn, printf("INSERT INTO table VALUES %s"), str);
I get that warning during compile process
warning: passing argument 2 of ‘mysql_query’ makes pointer from integer without a cast
What I miss ?
Extending #ckruse's answer, you should take care to use mysql_real_escape_string() if your string comes from arbitrary sources.
int insert_data(MYSQL * mysql, char * str, int len)
{
if (len < 0) {
len = strlen(str);
}
char esc[2*len+1];
unsigned long esclen = mysql_real_escape_string(mysql, esc, str, len);
char statement[512];
snprintf(statement, sizeof statement, "INSERT INTO table VALUES ('%s')", esc);
return mysql_query(mysql, statement);
}
(An alternative could be mysql_hex_string() if dealt with correctly.)
You cannot do that. printf() returns the number of characters printed. You have to create the string before calling mysql_query():
char statement[512], *my_str = "MyString";
snprintf(statement, 512, "INSERT INTO table VALUES ('%s')", str);
mysql_query(conn, statement);
Also, be careful when creating those query strings. Don't use functions like sprintf() if you cannot be sure how long the resulting string is. Don't write over the boundaries of the memory segment.
you should put "'' in front and after the string
like this
mysql_query(conn, printf("INSERT INTO table VALUES ('%s')"), str);