diff --git a/.gitmodules b/.gitmodules index 9bb87d3574..e2a90fbd3b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -227,6 +227,10 @@ path = Sming/Libraries/MultipartParser/multipart-parser url = https://github.com/iafonov/multipart-parser-c.git ignore = dirty +[submodule "Libraries.nanopb"] + path = Sming/Libraries/nanopb/nanopb + url = https://github.com/nanopb/nanopb.git + ignore = dirty [submodule "Libraries.RapidXML"] path = Sming/Libraries/RapidXML url = https://github.com/mikee47/Sming-RapidXML diff --git a/Sming/Libraries/nanopb/README.rst b/Sming/Libraries/nanopb/README.rst new file mode 100644 index 0000000000..5a70236598 --- /dev/null +++ b/Sming/Libraries/nanopb/README.rst @@ -0,0 +1,56 @@ +Nano Protocol-Buffer +==================== + +Introduction +------------ + +This component adds support for `Nano Protocol-Buffer `_ implementation. + + Nanopb is a small code-size `Protocol Buffers `_ implementation in ansi C. It is especially suitable for use in microcontrollers, but fits any memory restricted system. + + +C file generation from Proto files +---------------------------------- + +Once this component is installed you can use it to add Nano Protocol-Buffer support to your project and generate C and header files from Proto files. +One possible way to call the generator is to go to the directory where the proto file is located and run the generator. As shown below:: + + make -C $SMING_HOME fetch nano-pb + cd + python $SMING_HOME/Libraries/nanopb/nanopb/generator/nanopb_generator.py .proto + +After the generator tool is run you will have newly generated C and header files that can be used in your Sming application. + +Using +----- + +1. Add ``COMPONENT_DEPENDS += nanopb`` to your application componenent.mk file. +2. Add these lines to your application:: + + #include + // The line below should be replaced with the generated header file + #include "cast_channel.pb.h" + +3. Example:: + + #include + #include "cast_channel.pb.h" + + void doSomething(const uint8_t* data, size_t length) + { + // ... + + extensions_api_cast_channel_CastMessage message = extensions_api_cast_channel_CastMessage_init_default; + + message.protocol_version = extensions_api_cast_channel_CastMessage_ProtocolVersion_CASTV2_1_0; + message.source_id.funcs.encode = &pbEncodeData; + message.source_id.arg = new PbData(sourceId); + message.destination_id.funcs.encode = &pbEncodeData; + message.destination_id.arg = new PbData(destinationId); + message.nameSpace.funcs.encode = &pbEncodeData; + message.nameSpace.arg = new PbData(ns); + message.payload_type = extensions_api_cast_channel_CastMessage_PayloadType_STRING; + message.payload_utf8.funcs.encode = &pbEncodeData; + message.payload_utf8.arg = new PbData((uint8_t*)data, length); + // ... + } \ No newline at end of file diff --git a/Sming/Libraries/nanopb/component.mk b/Sming/Libraries/nanopb/component.mk new file mode 100644 index 0000000000..7145d462d4 --- /dev/null +++ b/Sming/Libraries/nanopb/component.mk @@ -0,0 +1,4 @@ +COMPONENT_SRCDIRS := nanopb src +COMPONENT_INCDIRS := $(COMPONENT_SRCDIRS) + +COMPONENT_SUBMODULES += nanopb \ No newline at end of file diff --git a/Sming/Libraries/nanopb/nanopb b/Sming/Libraries/nanopb/nanopb new file mode 160000 index 0000000000..049485ff55 --- /dev/null +++ b/Sming/Libraries/nanopb/nanopb @@ -0,0 +1 @@ +Subproject commit 049485ff557178f646d573eca3bd647f543b760b diff --git a/Sming/Libraries/nanopb/src/PbUtils.cpp b/Sming/Libraries/nanopb/src/PbUtils.cpp new file mode 100644 index 0000000000..2ba2047d1b --- /dev/null +++ b/Sming/Libraries/nanopb/src/PbUtils.cpp @@ -0,0 +1,41 @@ +#include "PbUtils.h" + +// See: https://iam777.tistory.com/538 + +bool pbEncodeData(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) +{ + PbData *data = (PbData*) *arg; + if(data == nullptr) { + return false; + } + + if (!pb_encode_tag_for_field(stream, field)) { + return false; + } + + return pb_encode_string(stream, (uint8_t*)data->value, data->length); +} + +bool pbDecodeData(pb_istream_t *stream, const pb_field_t *field, void **arg) +{ + uint8_t buffer[1024] = {0}; + + /* We could read block-by-block to avoid the large buffer... */ + if (stream->bytes_left > sizeof(buffer) - 1) { + return false; + } + + size_t available = stream->bytes_left; + if (!pb_read(stream, buffer, stream->bytes_left)) { + return false; + } + + + MemoryDataStream* data = (MemoryDataStream*) *arg; + if(data == nullptr) { + data = new MemoryDataStream(); + *arg = (void*)data; + } + data->write(buffer, available); + return true; +} diff --git a/Sming/Libraries/nanopb/src/PbUtils.h b/Sming/Libraries/nanopb/src/PbUtils.h new file mode 100644 index 0000000000..78c221e659 --- /dev/null +++ b/Sming/Libraries/nanopb/src/PbUtils.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include +#include + +class PbData +{ +public: + uint8_t* value = nullptr; + size_t length = 0; + + PbData(const String& text) + { + PbData((uint8_t *)text.c_str(), text.length()); + } + + PbData(uint8_t* data, size_t length) + { + value = data; + this->length = length; + } +}; + +bool pbEncodeData(pb_ostream_t *stream, const pb_field_t *field, void * const *arg); +bool pbDecodeData(pb_istream_t *stream, const pb_field_t *field, void **arg);