4

在我正在处理的嵌入式应用程序中,我经常需要将来自多个不同对象的数据打包,以便通过串行端口发送出去。同样,数据进入需要写入多个不同对象的串行端口。

出于兼容性原因,数据包中数据的排序不允许与一个对象相关联的所有数据连续放置在数据包中。所以我不能轻易地对每个对象的数据等进行矢量化,然后将所有这些数据放入一个数据包中。

我可以使用数据包类用来创建/解码传输/接收数据包的大量getter/mutators来实现适当的功能。但这似乎不是很优雅。

我可以使数据包类成为它从/向其中提取/写入数据的类的朋友,但我总是被告知要避免使用朋友,因为这种做法违反了面向对象的原则。

理想情况下,处理实际应用程序的类对数据包类一无所知(并且不必专门为它提供 getter/mutators),如果数据包在更新之间进入,它们只会有新数据。

我想也许我可以在启动时将相关成员变量的引用或指针传递给数据包类,但这也很棘手,因为所有成员的大小都不相同。也许我也可以传递尺寸信息?是否有一种方法可以对指向成员的 void 指针列表和成员对的大小进行矢量化,以便数据包类不需要为其构造函数提供大量参数?

我不确定我对这个问题的描述有多好,但如果有帮助的话,我当然可以提供澄清和更多信息。非常感谢您的任何想法。

当前 tx 数据包类的缩写示例:

class PacketTx {
private:
  uint8_t buffer[MAX_PACKET_SIZE];   // MAX_PACKET_SIZE is 200
public:
  PacketTx(object1 *firstObject,
           object2 *secondObject,
           object3 *thirdObject
           // ...etc...
           )

  void sendPacket(void);
};

void PacketTx::sendPacket(void) {
  uint32_t i = 0;

  int16_t tempVar1 = firstObject->getVar1();
  uint32_t tempVar2 = secondObject->getVar2();
  uint8_t tempVar3 = firstObject->getVar3();
  int32_t tempVar4 = thirdObject->getVar4();
  // ...etc...

  memcpy(buffer + i, &tempVar1, sizeof(tempVar1));
  i += sizeof(tempVar1);

  memcpy(buffer + i, &tempVar2, sizeof(tempVar2));
  i += sizeof(tempVar2);

  memcpy(buffer + i, &tempVar3, sizeof(tempVar3));
  i += sizeof(tempVar3);

  memcpy(buffer + i), &tempVar4, sizeof(tempVar4));
  i += sizeof(tempVar4);

  // ...etc...

  for(uint32_t j = 0; j < i; ++j)
    putc(static_cast<char>(buffer[i]));
}

这个例子不包括标题、校验和等,但它应该让我大致了解导致我头痛的原因。

4

2 回答 2

2

因此,如果我了解您有一些 C 类,它具有任意数量的成员,需要以任意顺序写入缓冲区。然后同样的机制反过来发生。

串行 -> Packet.buffer() -> 对象(和反向)

我最初的想法是使用boost::tuple并使类型与数据包中数据的顺序相对应。(但元组中可能有 50 多个成员/条目,这可能是一个很大的编译时间命中)

例如

tuple<float, int, std::string> a(1.0f,  2, std::string("Some Words");
ostr << a;

这还需要您的类将元组作为参数并填写数据中的条目。因此,与其写入缓冲区,不如枚举元组中保存的字段,以便编写“漂亮”的代码:

enum Fields {Price,Amount,Reason};
typedef boost::tuple<...> MyTuple;

void MyClass::getData( MyTuple& t )
{
    t<Price>() = mPrice;
    t<Amount>() = mAmount;
    t<Reason>() = mSomeReason;
}

注意也可以反向工作。

不确定这是否完全符合您的尝试,但它可能会引发一些新的想法?

于 2012-10-26T14:12:50.300 回答
1

组合是您在这里需要的:

class packet {
    enum PacketType {
        type1,
        ...
    };
    std::vector<unsigned char> buffer;
    PacketType id;
public:
    void setData(std::vector<unsigned char> buffer);
    void setType(PacketType type);
    std::vector<usigned char> getData();
    PacketType getType();
    //serialize Packet;
};

class composition_packet {
    //other packet related detail.
    std::vector<packet> data;
public:
    void addPacket(packet p);
    void send();
    //serialize composition_packet
};

这里的想法是根据需要制作多个数据包,但将它们作为一个大数据包发送(composition_packet)。这里的另一个概念是数据包只负责序列化自己,而不是它应该知道的数据类型。数据包的数据必须已经被知道如何序列化它的对象序列化。


struct foo {
   std::string str;
   uint_8 u8;
   uint_32 u32;

   packet getPacket() {
       //simple dumb serialization
       std::stringstream ss(str);
       ss << "|";  //delimit character
       ss << u8 << "|";
       ss << u32;
       std::string s(ss.str());
       std::vector<unsigned char> data(s.begin(), s.end());
       packet p;
       p.setType(packet::fooType);
       p.setData(data);
       return p;
   }

};
于 2012-10-26T14:38:43.497 回答