Go Down

Topic: Nanopb String from encoded message (Read 1 time) previous topic - next topic

oyarzopablo

How do I get the whole message in a string? I'm planning on sending it over HTTP.
I thought of using the "pb_read" but it's giving me trouble with the buffers.

Robin2

Without seeing your program it is impossible to make sense of your question.

What is a Nanopb?

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

oyarzopablo

Nanopb is a C implementation of the Protocol Buffers library from google.
I'm compiling this example from the library.
https://github.com/nanopb/nanopb/blob/master/examples/simple/simple.c
As you can see it has the code for coding and decoding the function, but say I print the whole function over serial.

This guy has pretty much my problem, but I didn't understand how he did it.
https://stackoverflow.com/questions/31272735/nanopb-get-string-from-pb-ostream-t

Robin2

What is "Protocol Buffers" ?

If you really want to get help you need to provide as much information as you can.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

oyarzopablo

From their website: "Protocol buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data." Protocol Buffers.

If you open the second link on my last reply, it sums up the problem I'm having.

dannable

I realise that I'm not the most observant of people, but I am struggling to see the connection with Arduino?
Beginners guide to using the Seeedstudio SIM900 GPRS/GSM Shield

Robin2

From their website: "Protocol buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data." Protocol Buffers.
I don't understand that and I have a sneaking suspicion that you don't either.

How about a simple explanation that your Granny would understand?

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

crabel

This is a little late to the comment thread, I came across this thread when researching nanopb on the Arduino. For anyone else going forward looking to solve similar problems, here ya go.

Nanopb is a great way of taking a bunch of data and wrapping it all together into a structure that you can send out over whichever protocol you desire and then unpack it in a variety of different programming languages/environments.

My current project takes a bunch of different data streams and bundles it all together and sends it out over Ethernet using MQTT. It also receives commands over the same pipe. Another client on the MQTT host analyzes the data and directs the arduino to do what it's supposed to do.

Here are a couple of things that I found helpful:
https://blog.noser.com/arduino-iot-with-mqtt-and-nanopb/
http://zakovinko.com/57-how-to-speak-from-arduino-to-python-and-back.html

As for getting it to encode and decode you are going to have to use a structure. The order is important of when you do things (e.g. submessages have to be handled first when decoding and last when encoding). The example here shows how to encode/decode for various data structures.
https://github.com/nanopb/nanopb/tree/master/tests/callbacks

for the example below, here are the pertinent globals and declarations:
Code: [Select]

// Header Files
#include "PubSubClient.h"  // MQTT library
#include "pb_decode.h"     // nanopb decode library
#include "pb_encode.h"     // nanopb encode library
#include "RCB_Protocol_Buffer.pb.h" // nanopb generated protobuf library


// Create various objects
  RCB_Protocol_Buffer_ClientMessage_MinerStatus minerStatus[2 * shelfNumber];


 and from void setup():
Code: [Select]

  // initialize protobuf structures
  for (uint8_t i = 0; i < 2 * shelfNumber; i++) {
    minerStatus[i] = RCB_Protocol_Buffer_ClientMessage_MinerStatus_init_zero;
    minerStatus[i].Error = true; // set up so that the program assumes nothing installed
    minerStatus[i].id = i;
  }



Here is an example of encoding a message to be sent:
Code: [Select]

void mqtt_send_rsr() {
  uint8_t sMsg[MSG_SIZE];
  _RCB_Protocol_Buffer_ClientMessage msg = RCB_Protocol_Buffer_ClientMessage_init_zero;
  pb_ostream_t buffer = pb_ostream_from_buffer(sMsg, MSG_SIZE);

  Conv32 bigmac;
  bigmac.bytes[0] = mac[5];
  bigmac.bytes[1] = mac[4];
  bigmac.bytes[2] = mac[3];
  bigmac.bytes[3] = mac[2];
  msg.mac = bigmac.value;
  msg.BoardTemp = temp.readCelsius();
  msg.InletTemp = temp.readInternal();
  msg.Flow = digitalRead(flowSwitchPin);
  msg.PowerAvail = digitalRead(powerAvailPin);
  msg.IPRFlag = ipFlag;
  msg.time = getTimestamp();
  msg.miners.funcs.encode = &mqtt_encode_callback;
  //Encode the message
 if (!pb_encode(&buffer, RCB_Protocol_Buffer_ClientMessage_fields, &msg)) {
   Serial.println(F("Encoding failed"));
   Serial.println(PB_GET_ERROR(&buffer));
  }
  /*
  // check message content
  Serial.println(buffer.bytes_written);
  for (uint8_t i = 0; i < buffer.bytes_written; i++) {
    Serial.print(sMsg[i],HEX);
    Serial.print(F(":"));
  }
  Serial.println();
  */
  ethClient.disableInterrupt();
  // publish the buffer
  if(!client.publish("rcb", sMsg)) {
    Serial.println(F("Publishing Failed"));
    tReconnect.restart();
    tGenerateRSR.enableDelayed(5000);
  }
  else {
    ipFlag = false;
  }
  ethClient.enableInterrupt(); // restore interrupt
}

/*
 * Callback function to read in the individual miner status
 */
bool mqtt_encode_callback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
  for (uint8_t i = 0; i < 2 * shelfNumber; i++)
 if (!pb_encode_submessage(stream, RCB_Protocol_Buffer_ClientMessage_MinerStatus_fields, &minerStatus[i]))
  return false;
  return true;
}



Here is an example of decoding a message:
Code: [Select]

int mqtt_callback(char* topic, byte* payload, unsigned int length){
  mqtt_ping_reset(); // reset the ping timer
  if (length > MQTT_MAX_PACKET_SIZE) {
    payload = {'\0'}; // if garbage, flush the buffer
    return 0;
  }

  RCB_Protocol_Buffer_BrokerMessage msg = RCB_Protocol_Buffer_BrokerMessage_init_default;
  pb_istream_t stream = pb_istream_from_buffer(payload, length);

  msg.miners.funcs.decode = &mqtt_decode_callback;
  //msg.miners.funcs.arg = *minerTemp;
  if (!pb_decode(&stream, RCB_Protocol_Buffer_BrokerMessage_fields, &msg)) // This has to follow the submessages
    return 1;
  
  Conv32 bigmac;
  // enendianess is set properly here don't mess it up
  bigmac.bytes[0] = mac[5];
  bigmac.bytes[1] = mac[4];
  bigmac.bytes[2] = mac[3];
  bigmac.bytes[3] = mac[2];
  if (msg.mac != bigmac.value)
    return 0;

  parseCommand(msg); // execute the control function
  return 0;
}

bool mqtt_decode_callback(pb_istream_t *stream, const pb_field_t *field, void * const **arg) {
  RCB_Protocol_Buffer_BrokerMessage_MinerCmdMessage minermsg = RCB_Protocol_Buffer_BrokerMessage_MinerCmdMessage_init_default;
 if (!pb_decode(stream, RCB_Protocol_Buffer_BrokerMessage_MinerCmdMessage_fields, &minermsg))
 return false;
  bitWrite(minerIPReport, minermsg.id, minermsg.IPReport);
  bitWrite(minerReset, minermsg.id, minermsg.Reset);
  bitWrite(minerPower, minermsg.id, minermsg.Power);
  return true;
}

crabel

I forgot this link was increadibly helpful in figuring out how to get everythign to work, it is from the nanopb wiki
https://jpa.kapsi.fi/nanopb/docs/concepts.html#id10

adn a correction to the use of structure above, it is a stream.

Go Up