【发布时间】:2020-05-03 05:17:09
【问题描述】:
我正在对 ArtNet 存储库进行一些更改。我想扩展它一点,但为了有效地做到这一点,我有几个问题我不知道答案。 请考虑下面的代码。 如您所见,我有三个结构:
- ArtNetNode:包含所有节点标识信息。 IP 和短/长名称可能会在计划期间发生变化。
- ArtPollReplyPack:此结构附加了打包参数。我稍后会使用这个结构,所以发送 udp 数据包。它确实是 artnet 协议规范中指定的整个包。
- ArtDmxPack:类似于第 2 点,但用于证明节点结构中的数据用于多个数据包。
目前的实施保留了很多来自特定信息的副本,我指的是IP地址、mac、短名称和长名称。如果这些参数之一发生变化,我需要在所有三个位置进行更改。这不是很有效。 我的问题是如何提高效率,所以我只需要更改 node.ip 而不是所有三个位置。搜索让我找到了指针,这真的很有意义。但是,这会弄乱结构打包,因为 ArtPollReplyPack 和 ArtDmxPack 确实是包的完整数据集。有什么可以帮助我克服这个问题吗?或许可以举个例子。
感谢您的宝贵时间!
仅供参考:我在带有 Wiz8xx 以太网端口的 Teensy 3.2 板上使用 Teensyduino 实现。
#include <Ethernet.h>
#include <EthernetUdp.h>
EthernetUDP Udp;
byte mac[] = {0x04, 0xE9, 0xE5, 0x00, 0x69, 0xEC};
IPAddress controllerIP(192, 168, 0, 2);
struct ArtNetNode {
IPAddress ip;
uint8_t mac[6];
uint8_t oemH;
uint8_t oemL;
uint8_t shortname[18];
uint8_t longname[64];
};
struct ArtPollReplyPack {
uint8_t id[8];
uint16_t opCode;
uint8_t ip[4];
uint8_t mac[6];
uint16_t port;
uint8_t oemH;
uint8_t oemL;
uint8_t shortname[18];
uint8_t longname[64];
}__attribute__((packed));
struct ArtDmxPack {
uint8_t id[8];
uint16_t opCode;
uint8_t ip[4];
uint16_t port;
uint8_t DmxData[512];
}__attribute__((packed));
struct ArtNetNode node;
struct ArtPollReplyPack ArtPollReply;
struct ArtDmxPack ArtDmx;
void setup() {
ArtPollReply.oemH = node.oemH;
ArtPollReply.oemL = node.oemL;
memcpy(ArtPollReply.shortname, node.shortname, sizeof(node.shortname));
memcpy(ArtPollReply.longname, node.longname, sizeof(node.longname));
memcpy(node.mac, mac, sizeof(mac));
memcpy(ArtPollReply.mac, node.mac, sizeof(node.mac));
Ethernet.begin(mac);
Udp.begin(6454);
}
void loop() {
switch(Ethernet.maintain()) {
case 1:
case 3:
// rebind / renew failed.
break;
case 2:
case 4:
// update the node IP address.
memcpy(node.ip, Ethernet.localIP(), 4);
case 0:
default:
break;
}
Udp.beginPacket(controllerIP, 6454);
Udp.write((uint8_t *)&ArtPollReply, sizeof(ArtPollReply));
Udp.endPacket();
}
【问题讨论】:
-
Arduino 使用 C++ 作为编程语言。这意味着您可以使用类来包装结构。这些类可能包含指向链接结构的成员。
-
@Someprogrammerdude 诚然,在没有特定领域知识的情况下,我假设这些结构对应于硬件或其他组件预期布局中的数据字段(注意
packed属性),因此它们并不是真正的主题任意更改。当然,可以设置某种类型的无冗余逻辑数据保持器类,它可以按需生成所需特定布局的二进制数据。就内存和运行时间而言,这肯定会降低效率。 -
@Peter-ReinstateMonica 包装结构并拥有合适的转换运算符和构造函数不会自动导致“效率”降低。如今的编译器非常擅长优化,因此可以在需要时直接使用包装的结构(特别是如果“包装”是通过继承完成的)。唯一需要的额外内存是链接类中的额外指针。
-
@Someprogrammerdude PACKED 是一个重要方面,因为数据包是在结构中定义的。例如,如果要添加一个指针而不是真正的操作码,这将导致数据包中有额外的字节来存储指针(teensy 有 16 位地址)。因此消息不再符合规范。
-
@Thieu 我不建议您更改当前结构,而是从它们继承,或者将它们包含在另一个类中(如
struct ArtNetNodeWrapper { ArtNetNode packet; /* Possible other needed extra data */ };)