没有回调的 Nanopb
Nanopb without callbacks
我正在使用 Nanopb 尝试从基于 VxWorks 的 National Instruments Compact RIO (9025) 发送 protobuf 消息。我的交叉编译效果很好,我什至可以发送一个完整的消息,其中包含不需要额外编码的数据类型。让我兴奋的是回调。我的代码是从 LabVIEW 交叉编译和调用的,Nanopb 的基于回调的结构似乎在目标机器上中断(错误、崩溃、目标重启等)。如果我 运行 它没有任何回调,它会很好用。
这里是有问题的代码:
bool encode_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
char *str = "Woo hoo!";
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_string(stream, (uint8_t*)str, strlen(str));
}
extern "C" uint16_t getPacket(uint8_t* packet)
{
uint8_t buffer[256];
uint16_t packetSize;
ExampleMsg msg = {};
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
msg.name.funcs.encode = &encode_string;
msg.value = 17;
msg.number = 18;
pb_encode(&stream, ExampleMsg_fields, &msg);
packetSize = stream.bytes_written;
memcpy(packet, buffer, 256);
return packetSize;
}
这是原型文件:
syntax = "proto2"
message ExampleMsg {
required int32 value = 1;
required int32 number = 2;
required string name = 3;
}
我也尝试过将回调设为外部 "C",但没有任何改变。我还尝试添加一个具有最大长度的 nanopb 选项文件,但要么没有正确理解它,要么它也不起作用。
如果我从原型消息中删除字符串并删除回调,效果会很好。似乎回调结构在这个 LabVIEW -> C 库环境中不起作用。还有另一种方法可以在没有回调结构的情况下对消息进行编码吗?或者以某种方式将回调嵌入到 getPacket() 函数中?
更新代码:
extern "C" uint16_t getPacket(uint8_t* packet)
{
uint8_t buffer[256];
for (unsigned int i = 0; i < 256; ++i)
buffer[i] = 0;
uint16_t packetSize;
ExampleMsg msg = {};
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
msg.name.funcs.encode = &encode_string;
msg.value = 17;
msg.number = 18;
char name[] = "Woo hoo!";
strncpy(msg.name, name, strlen(name));
pb_encode(&stream, ExampleMsg_fields, &msg);
packetSize = stream.bytes_written;
memcpy(packet, buffer, sizeof(buffer));
return packetSize;
}
更新的原型文件:
syntax = "proto2"
import "nanopb.proto";
message ExampleMsg {
required int32 value = 1;
required int32 number = 2;
required string name = 3 [(nanopb).max_size = 40];
}
您可以通过在 .proto 文件中使用选项 (nanopb).max_size = 123
为字符串字段指定最大大小来避免回调。然后nanopb可以在结构中生成一个简单的char
数组(relevant part of documentation).
关于为什么回调不起作用:只是猜测,但尝试将 extern "C"
也添加到回调函数。我假设您在那里使用 C++,所以也许在该平台上 C 和 C++ 调用约定不同,这会导致崩溃。
VxWorks 串行控制台是否提供有关崩溃的更多信息?我不记得它是否对从 LabView 调用的函数执行此操作,因此 运行 一些直接来自 VxWorks shell 的测试代码也值得一试。
也许第一个障碍是代码如何处理字符串。
LabVIEW 的原生字符串表示不像 C 那样以 null 结尾,但您可以配置 LabVIEW 使用不同的表示或更新您的代码以处理 LabVIEW 的原生格式。
LabVIEW stores a string in a special format in which the first four bytes of the array of characters form a 32-bit signed integer that stores how many characters appear in the string. Thus, a string with n characters requires n + 4 bytes to store in memory.
LabVIEW 帮助:在调用库函数节点中使用数组和字符串
http://zone.ni.com/reference/en-XX/help/371361L-01/lvexcodeconcepts/array_and_string_options/
我正在使用 Nanopb 尝试从基于 VxWorks 的 National Instruments Compact RIO (9025) 发送 protobuf 消息。我的交叉编译效果很好,我什至可以发送一个完整的消息,其中包含不需要额外编码的数据类型。让我兴奋的是回调。我的代码是从 LabVIEW 交叉编译和调用的,Nanopb 的基于回调的结构似乎在目标机器上中断(错误、崩溃、目标重启等)。如果我 运行 它没有任何回调,它会很好用。
这里是有问题的代码:
bool encode_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
char *str = "Woo hoo!";
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_string(stream, (uint8_t*)str, strlen(str));
}
extern "C" uint16_t getPacket(uint8_t* packet)
{
uint8_t buffer[256];
uint16_t packetSize;
ExampleMsg msg = {};
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
msg.name.funcs.encode = &encode_string;
msg.value = 17;
msg.number = 18;
pb_encode(&stream, ExampleMsg_fields, &msg);
packetSize = stream.bytes_written;
memcpy(packet, buffer, 256);
return packetSize;
}
这是原型文件:
syntax = "proto2"
message ExampleMsg {
required int32 value = 1;
required int32 number = 2;
required string name = 3;
}
我也尝试过将回调设为外部 "C",但没有任何改变。我还尝试添加一个具有最大长度的 nanopb 选项文件,但要么没有正确理解它,要么它也不起作用。
如果我从原型消息中删除字符串并删除回调,效果会很好。似乎回调结构在这个 LabVIEW -> C 库环境中不起作用。还有另一种方法可以在没有回调结构的情况下对消息进行编码吗?或者以某种方式将回调嵌入到 getPacket() 函数中?
更新代码:
extern "C" uint16_t getPacket(uint8_t* packet)
{
uint8_t buffer[256];
for (unsigned int i = 0; i < 256; ++i)
buffer[i] = 0;
uint16_t packetSize;
ExampleMsg msg = {};
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
msg.name.funcs.encode = &encode_string;
msg.value = 17;
msg.number = 18;
char name[] = "Woo hoo!";
strncpy(msg.name, name, strlen(name));
pb_encode(&stream, ExampleMsg_fields, &msg);
packetSize = stream.bytes_written;
memcpy(packet, buffer, sizeof(buffer));
return packetSize;
}
更新的原型文件:
syntax = "proto2"
import "nanopb.proto";
message ExampleMsg {
required int32 value = 1;
required int32 number = 2;
required string name = 3 [(nanopb).max_size = 40];
}
您可以通过在 .proto 文件中使用选项 (nanopb).max_size = 123
为字符串字段指定最大大小来避免回调。然后nanopb可以在结构中生成一个简单的char
数组(relevant part of documentation).
关于为什么回调不起作用:只是猜测,但尝试将 extern "C"
也添加到回调函数。我假设您在那里使用 C++,所以也许在该平台上 C 和 C++ 调用约定不同,这会导致崩溃。
VxWorks 串行控制台是否提供有关崩溃的更多信息?我不记得它是否对从 LabView 调用的函数执行此操作,因此 运行 一些直接来自 VxWorks shell 的测试代码也值得一试。
也许第一个障碍是代码如何处理字符串。
LabVIEW 的原生字符串表示不像 C 那样以 null 结尾,但您可以配置 LabVIEW 使用不同的表示或更新您的代码以处理 LabVIEW 的原生格式。
LabVIEW stores a string in a special format in which the first four bytes of the array of characters form a 32-bit signed integer that stores how many characters appear in the string. Thus, a string with n characters requires n + 4 bytes to store in memory.
LabVIEW 帮助:在调用库函数节点中使用数组和字符串
http://zone.ni.com/reference/en-XX/help/371361L-01/lvexcodeconcepts/array_and_string_options/