In my project i want to communicate between an Arduino and a phone using the Flutter framework. I created a library for the Arduino part in c++, but I'm struggling to create the same thing in dart.
In the Arduino code I created class, and then used the memory structure of the class, something like this:
struct MessageHeaderData {
unsigned char protocol;
IP source, destination;
MessageType messageType;
unsigned char checksum;
unsigned short int sizeOfPayload;
unsigned char numberOfHops;
};
// This is how I get the byte representation in c++
void getMemoryRepresenation(MessageHeaderData data) {
unsigned char* buffer = (unsigned char*)&value;
for (int i = 0; i < sizeof(MessageHeaderData); i++) {
out[i] = buffer[i];
}
// Do something with the array
}
Can I do something similar in dart?
Related
I would like to copy a variable of 1 byte to relatively larger char array, and copy it back? How can I do that?
/* memcpy example */
#include <stdio.h>
#include <string.h>
struct Data {
unsigned char name[40];
int age;
};
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
int main ()
{
uint8_t myval = 8;
uint8_t myval_2 = 8;
Data mypass;
memcpy(&mypass.name, &myval, sizeof(uint8_t));
memcpy(&mypass.name+1, &myval_2, sizeof(uint8_t));
uint8_t* myvalnew = nullptr;
uint8_t* myvalnew_2 = nullptr;
memcpy(myvalnew, (uint8_t*)&mypass.name, sizeof(uint8_t));
memcpy(myvalnew_2, (uint8_t*)&mypass.name+1, sizeof(uint8_t));
return 0;
}
However I am getting errors.
&mypass.name creates a pointer to your name array, you want a pointer to the first element of your array, you can use either simply mypass.name or &mypass.name[0]. memcpy is unnecessary here as you can simply assign the elements:
mypass.name[0] = myval;
mypass.name[1] = myval_2;
Your second set of memcpys will fail as your myvalnew pointers are null, I'm not sure what you're trying to achieve here. If you're trying to get the values back you can again just use normal array access:
uint8_t myvalnew = mypass.name[0];
uint8_t myvalnew_2 = mypass.name[1];
I have a function definition like this in an Arduino library:
bool RHReliableDatagram::sendtoWait(uint8_t * buf, uint8_t len, uint8_t address)
When I use:
uint8_t timePacket[] = "time\n";
sendtoWait(timePacket, sizeof(timePacket), SERVER_ADDRESS)
I get a perfectly fine string with "time" at the other end (SERVER_ADDRESS) in pyserial's readline() function which is decoded perfectly using utf-8 encoding.
Now I need to send some bytes using the same sendtoWait() function. I first define a char array of 60 bytes
char packetBuff[60] = "";
Then I get every byte and cast it as a char
char value = (char)flash.readByte(dumpCounter++);
Then put each value in the char array like this:
packetBuff[charNo] = value;
After I find a new line character I try to send the char array again using the sendtoWait() function:
if (value == '\n') {
Serial.println(packetBuff);
uint8_t buff[charNo];
for (int i = 0; i < charNo; i++) {
buff[i] = packetBuff[i];
}
sendtoWait(buff, charNo, SERVER_ADDRESS))
charNo++;
But although Serial.println(packetBuff) shows the proper characters e.g. something like "1559105487\n" (unix timestamp), buff array is just not working correctly and shows random characters something like a semi-colon, random single digit numbers etc.
How do I properly cast the char array and send it properly using the sendtoWait() function like "time\n" was sent?
EDIT:
Full code:
int charNo = 0;
char packetBuff[60] = "";
if (dumpCounter != 0) {
dumpCounter--;
}
while(dumpCounter < currentFlashLoc) {
char value = (char)flash.readByte(dumpCounter++);
packetBuff[charNo] = value;
if (value == '\n') {
Serial.println(packetBuff);
uint8_t buff[charNo];
for (int i = 0; i < charNo; i++) {
buff[i] = packetBuff[i];
}
if (manager.sendtoWait(buff, charNo, SERVER_ADDRESS)) {
// packet sent successfully
}
charNo = -1;
}
charNo++;
}
Casting the char array like this:
sendtoWait((uint8_t*)packetBuff, sizeof(packetBuff), SERVER_ADDRESS)
works correctly. buff is not required.
I'm trying to pass a string as part of a structure over the network using the rpcgen packages. This is my IDL code :
struct param
{
char* name;
int voterid;
};
program VOTECLIENT_PROG
{
version VOTECLIENT_VERS
{
string ZEROIZE() = 1;
string ADDVOTER(int) = 2;
string VOTEFOR(param) = 3;
string LISTCANDIDATES() = 4;
int VOTECOUNT(string) = 5;
} = 1;
} = 0x2345111;
Somehow, the string is being truncated to a single character at the server. For example, if I pass name = "abc", I get "a" at the server. It looks like this is happening because of some issue inside the stubs, but I can't seem to figure out where the bug is.
My client code for the function that passes the string as an argument :
void
voteclient_prog_1(char *host, char* c, int id)
{
CLIENT *clnt;
char * *result_3;
param votefor_1_arg;
#ifndef DEBUG
clnt = clnt_create (host, VOTECLIENT_PROG, VOTECLIENT_VERS, "udp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
#endif /* DEBUG */
votefor_1_arg.name = c;
votefor_1_arg.voterid = id;
result_3 = votefor_1(&votefor_1_arg, clnt);
if (result_3 == (char **) NULL) {
clnt_perror (clnt, "call failed");
}
clnt_perror (clnt, "call failed");
#ifndef DEBUG
clnt_destroy (clnt);
#endif /* DEBUG */
}
int
main (int argc, char *argv[])
{
char *host;
int id;
char* c = new char[20];
if (argc < 4) {
printf ("usage: %s server_host name voterid\n", argv[0]);
exit (1);
}
host = argv[1];
c = argv[2];
id = atoi(argv[3]);
voteclient_prog_1 (host, c, id);
exit (0);
}
Any help will be greatly appreciated.
From rpcgen Programming Guide, 6.9. Special Cases:
Strings: C has no built-in string type, but instead uses the
null-terminated “char *” convention. In XDR language, strings are
declared using the “string” keyword, and compiled into “char *”s in
the output header file. The maximum size contained in the angle
brackets specifies the maximum number of characters allowed in the
strings (not counting the NULL character). The maximum size may be
left off, indicating a string of arbitrary length.
Examples:
string name<32>; --> char *name;
string longname<>; --> char *longname;
So, you should declare name like above, e. g. string name<20>;.
Adding something to the comment above, the usage of this kind of array in rpcgen is like follows:
In your struct declare arrays (of any type) like this
struct myStruct {
//In my case I used an array of floats
float nums<>;
}
This declare an "array" of type float. This kind of struct has two members of variables
struct {
u_int nums_len;
float *nums_val;
}nums;
Now you can allocate memory to the array of type float:
//totNums is the number of elements in the array
nums.nums_val = (float*)malloc(totNums*sizeof(float));
nums.nums_len = totNums;
Now in the server you can use your array with all the elements.
relating to my post linux writing string value as hex to serial (which was solved on a x86 System)
I have a problem on an i368 system.
The code works on an intel atom ubuntu system.
But on an intel xeon with ubuntu this doesnt work anymore.
Could that be a problem o little/big endian?
I used the code of the mentioned post from Erik.
I am using this method to convert
int convert(std::string str, unsigned char*& charArr)
{
// count the number of character pairs (i.e. bytes) in the string
// and dynamically allocate an array of the required size
const int numBytes = str.size() / 2;
charArr = new unsigned char[numBytes];
for (int i = 0; i < numBytes; ++i)
{
// grab two characters from the string...
std::string twoChars = str.substr(2 * i, 2);
// ...and convert them to an integer using a stringstream
int byte;
std::stringstream ss(twoChars);
ss >> std::hex >> byte;
// store the result in our char array
charArr[i] = byte;
}
}
Calling the method by
const std::string str ="8C000002008E";
unsigned char* toSend;
convert(str, toSend);
And writing to the serial Port with:
int kWrite = write(mFd, toSend , sizeof(toSend));
The serial device react on the atom system, but not on the xeon.
The response i get says: undefined format or checksum error
I need to serialize various structs to a file.
If possible I'd like the files to be pure ASCII. I could write some kind of serializer for each struct, but there are hundreds and many contain floats and doubles which I'd like to represent accurately.
I can't use a third-party serialization library and I don't have the time to write hundreds of serializiers.
How can I ASCII-safe serialize this data?
Also streams please, I hate the look of C-style printf("%02x",data).
I found this solution online and it addresses just this problem:
https://jdale88.wordpress.com/2009/09/24/c-anything-tofrom-a-hex-string/
Reproduced below:
#include <string>
#include <sstream>
#include <iomanip>
// ------------------------------------------------------------------
/*!
Convert a block of data to a hex string
*/
void toHex(
void *const data, //!< Data to convert
const size_t dataLength, //!< Length of the data to convert
std::string &dest //!< Destination string
)
{
unsigned char *byteData = reinterpret_cast<unsigned char*>(data);
std::stringstream hexStringStream;
hexStringStream << std::hex << std::setfill('0');
for(size_t index = 0; index < dataLength; ++index)
hexStringStream << std::setw(2) << static_cast<int>(byteData[index]);
dest = hexStringStream.str();
}
// ------------------------------------------------------------------
/*!
Convert a hex string to a block of data
*/
void fromHex(
const std::string &in, //!< Input hex string
void *const data //!< Data store
)
{
size_t length = in.length();
unsigned char *byteData = reinterpret_cast<unsigned char*>(data);
std::stringstream hexStringStream; hexStringStream >> std::hex;
for(size_t strIndex = 0, dataIndex = 0; strIndex < length; ++dataIndex)
{
// Read out and convert the string two characters at a time
const char tmpStr[3] = { in[strIndex++], in[strIndex++], 0 };
// Reset and fill the string stream
hexStringStream.clear();
hexStringStream.str(tmpStr);
// Do the conversion
int tmpValue = 0;
hexStringStream >> tmpValue;
byteData[dataIndex] = static_cast<unsigned char>(tmpValue);
}
}
This can be easily adapted to read/write to file streams, although the stringstream used in fromHex is still necessary, the conversion must be done two read characters at a time.
Any way you do it, you're going to need serialization code for
each struct type. You can't just bit-copy a struct to the
external world, and expect it to work.
And if you want pure ascii, don't bother with hex. For
serializing float and double, set the output stream to
scientific, and the precision to 8 for float, and 16 for
double. (It will take a few more bytes, but it will actually
work.)
For the rest: if the struct are written cleanly, according to
some in house programming guidelines, and only contain basic
types, you should be able to parse them directly. Otherwise,
the simplest solution is generally to design a very simple
descriptor language, describe each struct in it, and run a code
generator over it to get the serialization code.