I am defining a breakdown for a battery pack. Packs are made of one or more Modules. Modules are made of 6 Cells.
I have been able to get the pack information minus the repeated modules. I believe my repeated modules are now encoding but get an error:
Decoding failed: parent stream too short
currently my proto looks like this
syntax = "proto2";
package TeslaBMS;
message Pack {
required int32 numberOfModules = 2;
required float currentVoltage = 3;
required float averagePacktemp = 4;
repeated Module modules = 5;
message Module {
required int32 id = 1;
required float moduleVoltage = 2;
required float moduleTemp = 3;
required float lowestCellVolt = 4;
required float highestCellVolt = 5;
// repeated Cell cells = 6;
// message Cell{
// required int32 cellId = 1;
// required float cellVolt = 2;
// required string balanceState = 3;
// }
}
}
Which produces these struct defs
/* Struct definitions */
typedef struct _TeslaBMS_Pack {
int32_t numberOfModules;
float currentVoltage;
float averagePacktemp;
pb_callback_t modules;
} TeslaBMS_Pack;
typedef struct _TeslaBMS_Pack_Module {
int32_t id;
float moduleVoltage;
float moduleTemp;
float lowestCellVolt;
float highestCellVolt;
} TeslaBMS_Pack_Module;
I have made a typedef struct to hold an array of modules
typedef struct{
TeslaBMS_Pack_Module modarr[MAX_MODULE_ADDR];
int listSize = 0;
}
ModuleList;
These are some helper functions to build module arrays
the modulelist_add_module
is used for decode and module_array_maker
is used for encode
Here is what I have for my encode/decode based on examples I could find.
Encode:
void encoder(){
// Setup pack message
TeslaBMS_Pack mypack = TeslaBMS_Pack_init_zero;
// stream to write buffer
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
// set deffinitions
mypack.averagePacktemp = bms.getAvgTemperature();
mypack.currentVoltage = bms.getPackVoltage();
mypack.numberOfModules = bms.getNumOfModules();
ModuleList modArr;
module_array_maker(&modArr);
// set the arg to data needed
mypack.modules.arg = &modArr;
// encode the modules
mypack.modules.funcs.encode = modules_encode;
//encode the pack
status = pb_encode(&stream, TeslaBMS_Pack_fields, &mypack);
message_length = stream.bytes_written;
if (!status) printf("Encoding failed: %s\n", PB_GET_ERROR(&stream));
}
Encode call back for repeated module field
bool modules_encode(pb_ostream_t *stream, const pb_field_iter_t *field, void * const *arg)
{
ModuleList *source = (ModuleList*)(*arg);
for(int i=0; i<bms.getNumOfModules();i++)
{
printf(" \n Mod %i is at %f \n",(int)source->modarr[i].id, source->modarr[i].moduleVoltage);
if (!pb_encode_tag_for_field(stream, field))
{
const char * error = PB_GET_ERROR(stream);
printf("encode_modules error: %s", error);
return false;
}
if (!(stream, TeslaBMS_Pack_Module_fields, &source->modarr[i]))
{
const char * error = PB_GET_ERROR(stream);
printf("SimpleMessage_encode_numbers error: %s", error);
return false;
}
}
return true;
}
Decode:
void decode(){
/* Allocate space for the decoded message. */
TeslaBMS_Pack myPack = TeslaBMS_Pack_init_zero;
/* Create a stream that reads from the buffer. */
ModuleList modArr;
module_array_maker(&modArr);
myPack.modules.arg = &modArr;
myPack.modules.funcs.decode = modules_decode;
pb_istream_t stream = pb_istream_from_buffer(buffer, message_length);
/* Now we are ready to decode the message. */
status = pb_decode(&stream, TeslaBMS_Pack_fields, &myPack);
/* Check for errors... */
if (!status)
{
printf("Decoding failed: %s\n", PB_GET_ERROR(&stream));
}
else
{
/* Print the data contained in the message. */
printf("\n********MESSAGE FROM NANOPB!*********\n");
// printf("Number Of Modules in Pack: ", myPack.numberOfModules);
printf("Pack Voltage: %.3f\n", myPack.currentVoltage);
printf("Average Temp: %.3f\n", myPack.averagePacktemp);
printf("Number of modules: %i\n", (int)myPack.numberOfModules);
for (size_t i = 0; i < myPack.numberOfModules ; i++)
{
printf("\n ************ Module %i ************\n", modArr.modarr[i].id);
printf(" Voltage: %.3f Temperature: %.3f \n" ,modArr.modarr[i].moduleVoltage, modArr.modarr[i].moduleTemp);
}
printf("********MESSAGE FROM NANOPB!*********\n");
}
}
Decode callback for modules
bool modules_decode(pb_istream_t *istream, const pb_field_t *field, void **arg){
ModuleList * dest = (ModuleList*)(*arg);
TeslaBMS_Pack_Module module;
if(!pb_decode(istream, TeslaBMS_Pack_Module_fields, &module)){
const char * error = PB_GET_ERROR(istream);
printf("module_decode error: %s", error);
return false;
}
modulelist_add_module(dest, module);
return true;
}
Forgot to update this.
Looks like we just needed to make a little more space for the message. We took the max message size we would expect and added a few more bytes to pass into the encoder function and changed the encoder function from: void encoder()
to: size_t encoder(pb_byte_t *buffer, size_t length)
Setup and calls to encode and decode
pb_byte_t buffer[128];
size_t msg_length = encoder(buffer, sizeof(buffer));
decode(buffer, msg_length);
Encode function:
size_t encoder(pb_byte_t *buffer, size_t length) {
// Setup pack message
TeslaBMS_Pack mypack = TeslaBMS_Pack_init_zero;
// stream to write buffer
pb_ostream_t stream = pb_ostream_from_buffer(buffer, length);
// set definitions
mypack.averagePacktemp = bms.getAvgTemperature();
mypack.currentVoltage = bms.getPackVoltage();
mypack.numberOfModules = bms.getNumOfModules();
ModuleList modArr;
module_array_maker(&modArr);
mypack.modules.arg = &modArr;
mypack.modules.funcs.encode = modules_encode;
//encode the pack
bool status = pb_encode(&stream, TeslaBMS_Pack_fields, &mypack);
if (!status) {
printf("Encoding failed: %s\n", PB_GET_ERROR(&stream));
}
printf("Encoded %d bytes\n", stream.bytes_written);
return stream.bytes_written;
}
Decode Function was changed to accept 2 parameters
void decode(pb_byte_t *buffer, size_t message_length){
/* Allocate space for the decoded message. */
TeslaBMS_Pack myPack = TeslaBMS_Pack_init_zero;
ModuleList modArr;
module_array_maker(&modArr);
myPack.modules.arg = &modArr;
myPack.modules.funcs.decode = modules_decode;
pb_istream_t stream = pb_istream_from_buffer(buffer, message_length);
bool status = pb_decode(&stream, TeslaBMS_Pack_fields, &myPack);
if (!status)
{
printf("Decoding failed: %s\n", PB_GET_ERROR(&stream));
return;
}
/* Print the data contained in the message. */
printf("\n********MESSAGE FROM NANOPB!*********\n");
// printf("Number Of Modules in Pack: ", myPack.numberOfModules);
printf("Pack Voltage: %.3f\n", myPack.currentVoltage);
printf("Average Temp: %.3f\n", myPack.averagePacktemp);
printf("Number of modules: %i\n", (int)myPack.numberOfModules);
for (size_t i = 0; i < myPack.numberOfModules ; i++)
{
printf("\n ************ Module %i ************\n", modArr.modarr[i].id);
printf(" Voltage: %.3f Temperature: %.3f \n" ,modArr.modarr[i].moduleVoltage, modArr.modarr[i].moduleTemp);
}
printf("********MESSAGE FROM NANOPB!*********\n");
}