we are using the nanopb library as our Protocol Buffers library. We defined the following messages:
simple.proto:
syntax = "proto2";
message repField {
required float x = 1;
required float y = 2;
required float z = 3;
}
message SimpleMessage {
required float lucky_number = 1;
repeated repField vector = 2;
}
with simple.options
SimpleMessage.vector max_count:300
So we know the repField has a fixed size of 300 and thus defining it as such.
Parts of the generated one looks like:
simple.pb.c:
const pb_field_t repField_fields[4] = {
PB_FIELD( 1, FLOAT , REQUIRED, STATIC , FIRST, repField, x, x, 0),
PB_FIELD( 2, FLOAT , REQUIRED, STATIC , OTHER, repField, y, x, 0),
PB_FIELD( 3, FLOAT , REQUIRED, STATIC , OTHER, repField, z, y, 0),
PB_LAST_FIELD
};
const pb_field_t SimpleMessage_fields[3] = {
PB_FIELD( 1, FLOAT , REQUIRED, STATIC , FIRST, SimpleMessage, lucky_number, lucky_number, 0),
PB_FIELD( 2, MESSAGE , REPEATED, STATIC , OTHER, SimpleMessage, vector, lucky_number, &repField_fields),
PB_LAST_FIELD
};
and part of simple.pb.h:
/* Struct definitions */
typedef struct _repField {
float x;
float y;
float z;
/* ##protoc_insertion_point(struct:repField) */
} repField;
typedef struct _SimpleMessage {
float lucky_number;
pb_size_t vector_count;
repField vector[300];
/* ##protoc_insertion_point(struct:SimpleMessage) */
} SimpleMessage;
We try to encode the message by doing:
// Init message
SimpleMessage message = SimpleMessage_init_zero;
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
// Fill in message
[...]
// Encode message
status = pb_encode(&stream, SimpleMessage_fields, &message);
// stream.bytes_written is wrong!
But the stream.bytes_written is wrong which means it is not encoded correctly, although status=1.
In the documentation for pb_encode() it says:
[...] However, submessages must be serialized twice: first to
calculate their size and then to actually write them to output. This
causes some constraints for callback fields, which must return the
same data on every call.
But, we are not sure how to interpret this sentence - what steps to follow exactly to achieve this.
So our question is:
What is the correct way to encode messages that contain fixed-size (repeated) submessages using the nanopb library?
Thank you!
You're not using callback fields here, so that quote doesn't matter for you. But if you were, it would just mean that in some situations your callback would be called multiple times.
Are you the same person as on the forum? Your stack overflow question does not show it, but the person on the forum has a similar problem that appears to be due to not setting vector_count. Then it will remain as 0 length array. So try adding:
message.vector_count = 300;
In the future, please wait a few days before posting the same question in multiple places. It's a waste of volunteer time to answer the same question multiple times.
Related
First of all please excuse me, I can't reproduce the problem, it comes from a big project and when I recover the functions one by one in a more minimalist file it suddenly works (without modifying almost anything) and I can't understand where it can come from.
First of all the project contains these structures:
typedef struct {
uint32_t x, y;
uint16_t w, h;
char* str;
} Text;
typedef struct {
uint32_t last_tick;
uint32_t delta_ms;
float delta;
float t_fps;
uint16_t fps;
} Clock;
I initialize the Text structure which is present in another structure that I will call Other from an initialization function for Other like this:
other->text_frame_rate = (Text){ 0,0,0,0, (char[8]){} };
It is supposed to contain text that looks like this FPS: 60.
Then I use snprintf to write the desired text to it in another function, like this:
void _render_frame_rate(Other* other, Clock clock)
{
snprintf(other->text_frame_rate.str, 8, "FPS: %d", clock->fps);
...
}
This _render_frame_rate function is itself called from another function which looks like this at the parameter level void Render_game(SDL_Renderer* renderer, Other* other, Clock* clock);
But I get a segfault unless I redefine the frame again in _render_frame_rate like this:
void _render_frame_rate(Other* other, Clock clock)
{
other->text_frame_rate = (Text){ 0,0,0,0, (char[8]){} }; // redefine and no problem
snprintf(other->text_frame_rate.str, 8, "FPS: %d", clock->fps);
...
}
And in this case, where the struct Text has been redefined it finally works.
I also checked with a printf("%p\n"); if the address of the pointer was always the same at initialization and at the display function and yes it remains the same.
I also specify that at no time is the text_frame_rate value used or modified elsewhere.
What do you think could be causing this behavior?
UPDATE: Thanks to #IanAbbott's hint I was able to solve the problem by dynamically allocating text_frame_rate like this:
other->text_frame_rate = (Text){ 0,0,0,0, NULL };
other->text_frame_rate.str = malloc(8);
Here is one erroneous example:
void init_other_text_frame_rate(Other *other)
{
other->text_frame_rate = (Text){0, 0, 0, 0, (char[8]){0}};
}
void render_frame_rate(Other* other, Clock clock)
{
snprintf(other->text_frame_rate.str, 8, "FPS: %d", clock->fps);
}
void foo(Other* other, Clock clock)
{
init_other_text_frame_rate(other, clock);
render_frame_rate(other, clock); // invalid!
}
The lifetime of the array of char pointed to by other->text_frame_rate.str expired when init_other_text_frame_rate(other, clock); returned to foo, so its use in the call to snprintf is invalid.
I am trying to make a c-program that will will a string, but I want it only to read a very small part of it.
The NMEA-telegram that I try to read is $WIXDR, and do receive the necessary strings.
Here's 2 examples of strings that I get into the CPU:
$WIXDR,C,1.9,C,0,H,83.2,P,0,P,1023.9,H,0*46
$WIXDR,V,0.01,M,0,Z,10,s,0,R,0.8,M,0,V,0.0,M,1,Z,0,s,1,R,0.0,M,1,R,89.9,M,2,R,0.0,M,3*60
If it were only 1 string (not both C and V), this would not be a problem for me.
The problem here is that it's 2 seperate strings. One with the temperature, and one with rain-info.
The only thing that I'm interested in is the value "1.9" from
$WIXDR,C,1.9,C,0......
Here's what I have so far:
void ProcessXDR(char* buffPtr)
{
char valueBuff[10];
int result, x;
float OutSideTemp;
USHORT uOutSideTemp;
// char charTemperature, charRain
IODBerr eCode;
//Outside Temperature
result = ReadAsciiVariable(buffPtr, &valueBuff[0], &buffPtr, sizeof(valueBuff));
sscanf(&valueBuff[0],"%f",&OutSideTemp);
OutSideTemp *= 10;
uOutSideTemp = (USHORT)OutSideTemp;
eCode = IODBWrite(ANALOG_IN,REG_COM_XDR,1,&uOutSideTemp,NULL);
}
// XDR ...
if(!strcmp(&nmeaHeader[0],"$WIXDR"))
{
if(PrintoutEnable)printf("XDR\n");
ProcessXDR(buffPtr);
Timer[TIMER_XDR] = 1200; // Update every minute
ComStateXDR = 1;
eCode = IODBWrite(DISCRETE_IN,REG_COM_STATE_XDR,1,&ComStateXDR,NULL);
}
There's more, but this is the main part that I have.
I have found the answer to my own question. The code that would do as I intented is as follows:
What my little code does, is to look for the letter C, and if the C is found, it will take the value after it and put it into "OutSideTemp". The reason I had to look for C is that there is also a similar string received with the letter V (Rain).
If someone have any input in a way it could be better, I don't mind, but this little piece here does what I need it to do.
Here's to example telegrams I receive (I wanted the value 3.0 to be put into "OutSideTemp"):
$WIXDR,C,3.0,C,0,H,59.2,P,0,P,1026.9,H,04F
$WIXDR,V,0.00,M,0,Z,0,s,0,R,0.0,M,0,V,0.0,M,1,Z,0,s,1,R,0.0,M,1,R,89.9,M,2,R,0.0,M,358
void ProcessXDR(char* buffPtr)
{
char valueBuff[10];
int result, x;
float OutSideTemp;
USHORT uOutSideTemp;
// char charTemperature, charRain
IODBerr eCode;
// Look for "C"
result = ReadAsciiVariable(buffPtr, &valueBuff[0], &buffPtr, sizeof(valueBuff));
// sscanf(&valueBuff[0],"%f",&charTemperature);
if (valueBuff[0] == 'C')
//Outside Temperature
result = ReadAsciiVariable(buffPtr, &valueBuff[0], &buffPtr, sizeof(valueBuff));
sscanf(&valueBuff[0],"%f",&OutSideTemp);
OutSideTemp *= 10;
uOutSideTemp = (USHORT)OutSideTemp;
eCode = IODBWrite(ANALOG_IN,REG_COM_XDR,1,&uOutSideTemp,NULL);
}
I am using RE-Mote Development Board along with Contiki-OS. I am interfacing it with Adafruit BNO055 Absolute Orientation Sensor.
I want particularly:
the Accelerometer Data in floating point precision.
the Euler Angles in floating point precision.
I did some digging in and found out that the printf in Contiki is Board dependent and not many boards have floating point printing implementation. source
However this might become critical for creating a CoAP Resource because when returning data the code uses snprintf.
The snippet:
/*GET Method*/
RESOURCE(res_bno055,
"title=\"BNO055 Euler\";rt=\"bno055\"",
res_get_handler,
NULL,
NULL,
NULL);
static void res_get_handler(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset) {
adafruit_bno055_vector_t euler_data = getVector(VECTOR_EULER);
double eu_x = euler_data.x;
double eu_y = euler_data.y;
double eu_z = euler_data.z;
unsigned int accept = -1;
REST.get_header_accept(request, &accept);
if(accept == -1 || accept == REST.type.TEXT_PLAIN) {
/*PLAIN TEXT Response*/
REST.set_header_content_type(response, REST.type.TEXT_PLAIN);
// >>>>>>>>>>will snprintf create a problem? <<<<<<<<<<<<<<<<<
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%lf, %lf, %lf",eu_x,eu_y, eu_z,);
REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer));
} else if (accept == REST.type.APPLICATION_JSON) {
/*Return JSON REPONSE*/
REST.set_header_content_type(response, REST.type.APPLICATION_JSON);
// >>>>>>>>>>>>>>>same question here.. <<<<<<<<<<<<<<<<<<<<<<<<<<<<
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'bno055_eu':{ 'X':%f, 'Y':%f, 'Z':%f}}",
eu_x, eu_y, eu_z);
REST.set_response_payload(response, buffer, strlen((char *)buffer));
} else {
REST.set_response_status(response, REST.status.NOT_ACCEPTABLE);
const char *msg = "Only text/plain and application/json";
REST.set_response_payload(response, msg, strlen(msg));
}
}
I have tried the above mentioned Resource Code and setup a CoAP Server but I get
plain-text response:
, , ,
json response:
{'bno055_eu: { 'X': , 'Y': , 'Z': }}
the struct:
typedef struct {
double x;
double y;
double z;
}adafruit_bno055_vector_t
What would be an optimal way to create a GET CoAP Resource with floating point response?
#eugene-nikolaev I am just playing by the examples available. I am not sure what you mean but I think set_payload_response() function might not take the values of double. If you can give me a hint as to how to proceed I can try it out.
I am not very experienced in C so I cannot' show you a good snippet. But you're casting your buffer to (uint8_t) and for sure set_payload_response acquires binary payload.
It would be like (I note again - it could be not too correct):
REST.set_response_payload(response, (uint8_t *) &euler_data, sizeof(adafruit_bno055_vector_t));
But it will work only for your else branch.
In a classical meaning of CoAP I am used to send a binary payload or CBOR-encoded payload, and parse it on the other side in the similar cases. It all depends on what are your CoAP peers and what do you want to achieve.
UPD: Regarding the plaintext/json branches - I'd advise you to check which range/precision of values your module provides. Maybe there is no big point to use double as #Lundin said.
Also, do you really need plain-text and json format?
I'm have read c++ sample from samples folder of openCV source distribution, and, if omit random picture generation, kmeans call looks pretty simple – author even doesn't allocate centers/labels arrays (you can find it here). However, I can't do the same in C. If I don't allocate labels, I get assertion error:
OpenCV Error: Assertion failed (labels.isContinuous() && labels.type()
== CV_32S && (labels.cols == 1 || labels.rows == 1) && labels.cols + labels.rows - 1 == data.rows) in cvKMeans2, file
/tmp/opencv-xiht/opencv-2.4.9/modules/core/src/matrix.cpp, line 3094
Ok, I tried to create empty labels matrix, but assertion message don't changes at all.
IplImage* image = cvLoadImage("test.jpg", -1);
IplImage* normal = cvCreateImage(cvGetSize(image), IPL_DEPTH_32F, image->nChannels);
cvConvertScale(image, normal, 1/255.0, 0);
CvMat* points = cvCreateMat(image->width, image->height, CV_32F);
points->data.fl = normal->imageData;
CvMat* labels = cvCreateMat(1, points->cols, CV_32S);
CvMat* centers = NULL;
CvTermCriteria criteria = cvTermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0);
// KMEANS_PP_CENTERS is undefined
int KMEANS_PP_CENTERS = 2;
cvKMeans2(points, 4, labels, criteria, 3, NULL, KMEANS_PP_CENTERS, centers, 0);
The thing that drives me nuts:
CvMat* labels = cvCreateMat(1, points->cols, CV_32S);
int good = labels->type == CV_32S; // FALSE here
It's obviously one (not sure if the only) issue that causes assertion fail. How this supposed to work? I can't use С++ API since whole application is in plain C.
the assertion tells you:
type must be CV_32S which seems to be the case in your code, maybe your if-statement is false because the type is changed to CV_32SC1 automatically? no idea...
you can either place each point in a row or in a column, so rows/cols is set to 1 and the other dimension must be set to data.rows which indicates that data holds the points you want to cluster in the format that each point is placed in a row, leading to #points rows. So your error seems to be CvMat* labels = cvCreateMat(1, points->cols, CV_32S); which should be CvMat* labels = cvCreateMat(1, points->rows, CV_32S); instead, to make the assertion go away, but your use of points seems to be conceptually wrong.
You probably have to hold your points (you want to cluster) in a cvMat with n rows and 2 cols of type CV_32FC1 or 1 col and type CV_32FC2 (maybe both versions work, maybe only one, or maybe I'm wrong there at all).
edit: I've written a short code snippet that works for me:
// here create the data array where your input points will be hold:
CvMat* points = cvCreateMat( numberOfPoints , 2 /* 2D points*/ , CV_32F);
// this is a float array of the
float* pointsDataPtr = points->data.fl;
// fill the mat:
for(unsigned int r=0; r<samples.size(); ++r)
{
pointsDataPtr[2*r] = samples.at(r).x; // this is the x coordinate of your r-th point
pointsDataPtr[2*r+1] = samples.at(r).y; // this is the y coordinate of your r-th point
}
// this is the data array for the labels, which will be the output of the method.
CvMat* labels = cvCreateMat(1, points->rows, CV_32S);
// this is the quit criteria, which I did neither check nor modify, just used your version here.
CvTermCriteria criteria = cvTermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0);
// call the method for 2 cluster
cvKMeans2(points, 2, labels, criteria);
// now labels holds numberOfPoints labels which have either value 0 or 1 since we searched for 2 cluster
int* labelData = labels->data.i; // array to the labels
for(unsigned int r=0; r<samples.size(); ++r)
{
int labelOfPointR = labelData[r]; // this is the value of the label of point number r
// here I use c++ API to draw the points, do whatever else you want to do with the label information (in C API). I choose different color for different labels.
cv::Scalar outputColor;
switch(labelOfPointR)
{
case 0: outputColor = cv::Scalar(0,255,0); break;
case 1: outputColor = cv::Scalar(0,0,255); break;
default: outputColor = cv::Scalar(255,0,255); break; // this should never happen for 2 clusters...
}
cv::circle(outputMat, samples.at(r), 2, outputColor);
}
giving me this result for some generated point data:
Maybe you need the centers too, the C API gives you the option to return them, but didnt check how it works.
It's been over a year since I last used C, so I'm pretty much back to basics.
I have this code as part of a larger file:
typedef struct
{
float ix;
float iy;
float iz;
} InitialPosition;
typedef struct
{
InitialPosition init;
} Particle;
void particle()
{
Particle p1 =
{
.init = { .ix = 10, .iy = 10, .iz = 10 },
};
glPointSize(10);
glBegin(GL_POINTS);
glVertex3f(p1.init.ix,p1.init.iy,p1.init.iz);
//glVertex3f( 0, 0, 0 );
glEnd();
}
It works/appears correctly with my particle being plotted onto an axis, but it seems like there must be a quicker way to feed the variables from the struct into the glVertex3f method.
On the off-chance it makes any difference I'm using openGL & glut.
Should I also be using pointers? (If so an example of use would be great.) Like I said it has been a while so any help appreciated.
Functions that take three separate parameters require that you break each value out. If you're going to be using these calls a lot, you have two ways to make it more convenient.
1) make a helper function:
void myglVertexParticle(Particle * apoint) { glVertex3f(init->ix, init->iy, init->iz) ; }
myglVertexParticle( & (p1.init)) ;
2) use an expansion macro:
#define PARTICLE3f(uuu) uuu.ix, uuu.iy, uuu.iz
glVertex3f( PARTICLE3f( p1.init)) ;
Most people are probably going to frown on the second choice from a style point of view, and a good optimizing compiler should make the first case run nearly as quickly as the second.