用C++管理二进制数据的缓冲区

Ale*_*yne 1 c++ binary buffer arduino

我正在尝试创建一个简单的二进制格式,通过Arduino上的BlueToothLE模块进行传输.我正在尝试描述对象列表的属性.对于初学者,我试图传输一个属性.

我试图编码和传递的格式如下.

namePropertyID, nameLength, nameString...
Run Code Online (Sandbox Code Playgroud)

所以给了一个名字"鲍勃"

0x01     0x03     0x42 0x6F 0x62
nameID   3 chars  "B"  "o"  "b"
Run Code Online (Sandbox Code Playgroud)

但是当我通过缓冲区时,它似乎是变异的.

在我通过它之前,它写道:

0x01 0x03 0x42 0x6F 0x62
Run Code Online (Sandbox Code Playgroud)

但在我通过之后,它写道:

0x00 0x3C 0x18 0x04 0x00
Run Code Online (Sandbox Code Playgroud)

Program.h

typedef enum {
  InfoTypeName = 0x01
} InfoType;

class Program {
  public:
    char *name;

    uint8_t * data();
    uint8_t dataLen();
};
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

在其他地方,我将其传递给蓝牙库:

BTLEserial.write(program.data(), program.dataLen());
Run Code Online (Sandbox Code Playgroud)

这是如此实现的,并打印出看似不正确的数据:

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...
}
Run Code Online (Sandbox Code Playgroud)

所以有几个问题:

  • 为什么数据会发生变异?
  • 这是生成缓冲区的好方法吗?
  • 有两个单独的方法,一个用于长度,一个用于数据是一个好的模式?

jua*_*nza 5

问题在于Program::data(),buff是一个局部变量.您正在返回指向其第一个元素的指针,该元素是呼叫侧的悬空指针.您需要确保导出的缓冲区保持足够长的时间.有不同的方法可以做到这一点,但我并不完全熟悉arduino对可以使用的C和C++标准库的哪些部分的限制.

最简单的方法可能是保留缓冲区main,并将其传递给填充它并使用它的代码.或者,您可以为您的Program类提供缓冲区数据成员.主要问题是确保缓冲区足够大以容纳不同的消息.

我会先尝试这样的事情:

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);
}
Run Code Online (Sandbox Code Playgroud)