使用 deserializeBinary 函数反序列化 protobuf 的 Uint8Array 消息
Deserialize Uint8Array memssage for protobuf with deserializeBinary function
正在尝试读取通过 BLE 从 ESP32 芯片发送的 protobuf 消息的结果,但无法反序列化传入消息。在 Android 设备的 Ionic 应用程序中将 protobuf 用于 javascript。这是我的代码:
import * as goog from 'google-protobuf';
export class PrepareMessageService {
protoMessages = require('../assets/proto-js/wifi_config_pb.js');
cmdSetConfig = new this.protoMessages.CmdSetConfig();
respSetConfig = new this.protoMessages.RespSetConfig();
wiFiConfigPayload = new this.protoMessages.WiFiConfigPayload();
deserializeToBinary(message: any){
const binMsg = new Uint8Array(message);
const deserializedMsg = this.protoMessages.RespSetConfig.deserializeBinary(binMsg);
console.log(JSON.stringify(deserializedMsg));
}
console.log 的输出是:{"wrappers_":null,"arrayIndexOffset_":-1,"array":[],"pivot_":1.7976931348623157e+308,"convertedPrimitiveFields_":{}
我期待在“数组”中看到一些内容,但它是空的。相反,如果我使用以下代码通过 BLE 打印从 EPS32 芯片接收到的消息的每个元素(函数 deserializeToBinary 的参数):
for (let i = 0; i < message.byteLength; i++){
console.log('message[', i, ']: ', message.getUint8(i));
}
这是输出:
message[0]: 8
message[1]: 3
message[2]: 106
message[3]: 2
message[4]: 8
message[5]: 6
现在我知道消息 [5] 正确表示 RespSetConfig 的状态(显示在下面我的主要 protobuf 文件中)因为每次我在 ESP32 芯片端更改它时,我都会在消息中得到正确的代码[5].下面显示的 constants.proto 文件显示了 RespSetConfig 的各种状态代码。那么,为什么我在 deserializeToBinary 中的代码没有为 message
参数的所有元素提供正确的表示形式?尽管 ESP32 向我发送了不同的 RespSetConfig 状态值,但 deserializeToBinary 的控制台日志打印出完全相同的内容,但没有明确指示 RespSetConfig 的状态值是什么。在这种情况下,我可以使用 message
参数的不同元素,但在我需要正确反序列化传入的 protobuf 响应的其他情况下,这不一定能解决我的问题。
这是主要的 protobuf 文件:
syntax = "proto3";
package espressif;
import "constants.proto";
import "wifi_constants.proto";
message CmdGetStatus {}
message RespGetStatus {
Status status = 1;
WifiStationState sta_state = 2;
oneof state {
WifiConnectFailedReason fail_reason = 10;
WifiConnectedState connected = 11;
}
}
message CmdSetConfig {
string ssid = 1;
string passphrase = 2;
bytes bssid = 3;
int32 channel = 4;
}
message RespSetConfig {
Status status = 1;
}
message CmdApplyConfig {}
message RespApplyConfig {
Status status = 1;
}
enum WiFiConfigMsgType {
TypeCmdGetStatus = 0;
TypeRespGetStatus = 1;
TypeCmdSetConfig = 2;
TypeRespSetConfig = 3;
TypeCmdApplyConfig = 4;
TypeRespApplyConfig = 5;
}
message WiFiConfigPayload {
WiFiConfigMsgType msg = 1;
oneof payload {
CmdGetStatus cmd_get_status = 10;
RespGetStatus resp_get_status = 11;
CmdSetConfig cmd_set_config = 12;
RespSetConfig resp_set_config = 13;
CmdApplyConfig cmd_apply_config = 14;
RespApplyConfig resp_apply_config = 15;
}
}
这是在主 proto 文件中导入的 constants.proto 文件:
syntax = "proto3";
package espressif;
/* Allowed values for the status
* of a protocomm instance */
enum Status {
Success = 0;
InvalidSecScheme = 1;
InvalidProto = 2;
TooManySessions = 3;
InvalidArgument = 4;
InternalError = 5;
CryptoError = 6;
InvalidSession = 7;
}
弄清楚为什么这不起作用。我的 deserializeToBinary 函数中有不少错误。这有效:
deserializeToBinary(message: any){
dataViewToNumbers(message) //dataViewToNumbers can be imported from @capacitor-community/bluetooth-le
console.log(message); //this prints protobuf response elements stored in the array array. Output is as expected in question.
};
然后,我们可以在消息上使用deserializeBinary 来反序列化它,然后在反序列化的消息上使用protobuf 生成的函数来获取我们需要的数据。例如,下面的代码将通过先用deserializeBinary
反序列化消息,然后用getRestSetConfig().getStatus()
获取消息状态,来提供WifiConfigPayload对象中respSetConfig消息类型的状态,两者都是由[=生成的27=] protobuf 编译器:this.messages.WiFiConfigPayload.deserializeBinary(message).getRespSetConfig().getStatus()
要使用 protobuf 消息,必须了解 encoding/decoding 进出 protobuf 消息。 Google 网站上的以下 link 可以让您开始了解如何 code/decode protobuf 消息:https://developers.google.com/protocol-buffers/docs/encoding
也就是说,Google 自己的文档对于 protobufs 的新手来说是不够的。以下 link 在解释 protobuf 消息的 coding/decoding 方面做得更好:https://medium.com/nerd-for-tech/protobuf-what-why-fcb324a64564
正在尝试读取通过 BLE 从 ESP32 芯片发送的 protobuf 消息的结果,但无法反序列化传入消息。在 Android 设备的 Ionic 应用程序中将 protobuf 用于 javascript。这是我的代码:
import * as goog from 'google-protobuf';
export class PrepareMessageService {
protoMessages = require('../assets/proto-js/wifi_config_pb.js');
cmdSetConfig = new this.protoMessages.CmdSetConfig();
respSetConfig = new this.protoMessages.RespSetConfig();
wiFiConfigPayload = new this.protoMessages.WiFiConfigPayload();
deserializeToBinary(message: any){
const binMsg = new Uint8Array(message);
const deserializedMsg = this.protoMessages.RespSetConfig.deserializeBinary(binMsg);
console.log(JSON.stringify(deserializedMsg));
}
console.log 的输出是:{"wrappers_":null,"arrayIndexOffset_":-1,"array":[],"pivot_":1.7976931348623157e+308,"convertedPrimitiveFields_":{}
我期待在“数组”中看到一些内容,但它是空的。相反,如果我使用以下代码通过 BLE 打印从 EPS32 芯片接收到的消息的每个元素(函数 deserializeToBinary 的参数):
for (let i = 0; i < message.byteLength; i++){
console.log('message[', i, ']: ', message.getUint8(i));
}
这是输出:
message[0]: 8
message[1]: 3
message[2]: 106
message[3]: 2
message[4]: 8
message[5]: 6
现在我知道消息 [5] 正确表示 RespSetConfig 的状态(显示在下面我的主要 protobuf 文件中)因为每次我在 ESP32 芯片端更改它时,我都会在消息中得到正确的代码[5].下面显示的 constants.proto 文件显示了 RespSetConfig 的各种状态代码。那么,为什么我在 deserializeToBinary 中的代码没有为 message
参数的所有元素提供正确的表示形式?尽管 ESP32 向我发送了不同的 RespSetConfig 状态值,但 deserializeToBinary 的控制台日志打印出完全相同的内容,但没有明确指示 RespSetConfig 的状态值是什么。在这种情况下,我可以使用 message
参数的不同元素,但在我需要正确反序列化传入的 protobuf 响应的其他情况下,这不一定能解决我的问题。
这是主要的 protobuf 文件:
syntax = "proto3";
package espressif;
import "constants.proto";
import "wifi_constants.proto";
message CmdGetStatus {}
message RespGetStatus {
Status status = 1;
WifiStationState sta_state = 2;
oneof state {
WifiConnectFailedReason fail_reason = 10;
WifiConnectedState connected = 11;
}
}
message CmdSetConfig {
string ssid = 1;
string passphrase = 2;
bytes bssid = 3;
int32 channel = 4;
}
message RespSetConfig {
Status status = 1;
}
message CmdApplyConfig {}
message RespApplyConfig {
Status status = 1;
}
enum WiFiConfigMsgType {
TypeCmdGetStatus = 0;
TypeRespGetStatus = 1;
TypeCmdSetConfig = 2;
TypeRespSetConfig = 3;
TypeCmdApplyConfig = 4;
TypeRespApplyConfig = 5;
}
message WiFiConfigPayload {
WiFiConfigMsgType msg = 1;
oneof payload {
CmdGetStatus cmd_get_status = 10;
RespGetStatus resp_get_status = 11;
CmdSetConfig cmd_set_config = 12;
RespSetConfig resp_set_config = 13;
CmdApplyConfig cmd_apply_config = 14;
RespApplyConfig resp_apply_config = 15;
}
}
这是在主 proto 文件中导入的 constants.proto 文件:
syntax = "proto3";
package espressif;
/* Allowed values for the status
* of a protocomm instance */
enum Status {
Success = 0;
InvalidSecScheme = 1;
InvalidProto = 2;
TooManySessions = 3;
InvalidArgument = 4;
InternalError = 5;
CryptoError = 6;
InvalidSession = 7;
}
弄清楚为什么这不起作用。我的 deserializeToBinary 函数中有不少错误。这有效:
deserializeToBinary(message: any){
dataViewToNumbers(message) //dataViewToNumbers can be imported from @capacitor-community/bluetooth-le
console.log(message); //this prints protobuf response elements stored in the array array. Output is as expected in question.
};
然后,我们可以在消息上使用deserializeBinary 来反序列化它,然后在反序列化的消息上使用protobuf 生成的函数来获取我们需要的数据。例如,下面的代码将通过先用deserializeBinary
反序列化消息,然后用getRestSetConfig().getStatus()
获取消息状态,来提供WifiConfigPayload对象中respSetConfig消息类型的状态,两者都是由[=生成的27=] protobuf 编译器:this.messages.WiFiConfigPayload.deserializeBinary(message).getRespSetConfig().getStatus()
要使用 protobuf 消息,必须了解 encoding/decoding 进出 protobuf 消息。 Google 网站上的以下 link 可以让您开始了解如何 code/decode protobuf 消息:https://developers.google.com/protocol-buffers/docs/encoding
也就是说,Google 自己的文档对于 protobufs 的新手来说是不够的。以下 link 在解释 protobuf 消息的 coding/decoding 方面做得更好:https://medium.com/nerd-for-tech/protobuf-what-why-fcb324a64564