Reputation: 186984
I'm trying to create a simple binary format to transmit over a BlueToothLE module on Arduino. I'm trying to describe properties of a list of objects. And for starters I'm trying to transmit just a single property.
The format I'm attempting to encode and pass around is as follows.
namePropertyID, nameLength, nameString...
So given a name of "Bob"
0x01 0x03 0x42 0x6F 0x62
nameID 3 chars "B" "o" "b"
But when I pass the buffer around, it seems to mutate.
before I pass it, it reads:
0x01 0x03 0x42 0x6F 0x62
But after I pass it, it reads:
0x00 0x3C 0x18 0x04 0x00
Program.h
typedef enum {
InfoTypeName = 0x01
} InfoType;
class Program {
public:
char *name;
uint8_t * data();
uint8_t dataLen();
};
Program.cpp
#include "Program.h"
uint8_t* Program::data() {
uint8_t nameLength = strlen(name);
uint8_t buff[dataLen()];
buff[0] = InfoTypeName;
buff[1] = nameLength;
for (uint8_t i = 0; i < nameLength; i++) {
buff[i+2] = (uint8_t)name[i];
}
// First check of data, things look ok.
for (uint8_t i = 0; i < nameLength+2; i++) {
Serial.print(F(" 0x")); Serial.print(buff[i], HEX);
}
Serial.println();
return buff;
}
uint8_t Program::dataLen() {
return strlen(name) + 2;
}
Elsewhere I pass this to the Bluetooth library:
BTLEserial.write(program.data(), program.dataLen());
Which is implemented like so, and is printing out seemingly incorrect data:
size_t Adafruit_BLE_UART::write(uint8_t * buffer, uint8_t len)
{
Serial.print(F("\tWriting out to BTLE:"));
for (uint8_t i=0; i<len; i++) {
Serial.print(F(" 0x")); Serial.print(buffer[i], HEX);
}
Serial.println();
// actually sends the data over bluetooth here...
}
So a few questions:
Upvotes: 1
Views: 862
Reputation: 227370
The problem is that in Program::data()
, buff
is a local variable. You are returning a pointer to its first element, which is a dangling pointer at the call side. You need to ensure the buffer you export is something that stays alive for long enough. There are different ways of doing this, but I am not entirely familiar with the limitations arduino places on what parts of the C and C++ standard libraries you can use.
The simplest approach could be to reserve a buffer in main
, and pass that around to the code that populates it and consumes it. Alternatively, you could give your Program
class a buffer data member. The main problem is going to be ensuring that the buffer is large enough for different messages.
I would first try something like this:
void create_msg_(const char* name, uint8_t buff, size_t size)
{
// populate buff with the message
}
void send_msg(const char* name)
{
size_t size = strlen(name) + 2;
uint8_t buff[size]; // VLA extension, not std C++
create_msg_(name, buff, size);
BTLEserial.write(buff, size);
}
Upvotes: 5