mirror of
https://github.com/google/pebble.git
synced 2025-09-05 18:25:57 -04:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
18
third_party/nanopb/examples/cmake_relpath/README.txt
vendored
Normal file
18
third_party/nanopb/examples/cmake_relpath/README.txt
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
Nanopb example "simple" using CMake
|
||||
=======================
|
||||
|
||||
This example is the same as the simple nanopb example but built using CMake.
|
||||
|
||||
Example usage
|
||||
-------------
|
||||
|
||||
On Linux, create a build directory and then call cmake:
|
||||
|
||||
nanopb/examples/cmake_simple$ mkdir build
|
||||
nanopb/examples/cmake_simple$ cd build/
|
||||
nanopb/examples/cmake_simple/build$ cmake ..
|
||||
nanopb/examples/cmake_simple/build$ make
|
||||
|
||||
After that, you can run it with the command: ./simple
|
||||
|
||||
On other platforms supported by CMake, refer to CMake instructions.
|
11
third_party/nanopb/examples/cmake_relpath/proto/simple.proto
vendored
Normal file
11
third_party/nanopb/examples/cmake_relpath/proto/simple.proto
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
// A very simple protocol definition, consisting of only
|
||||
// one message.
|
||||
syntax = "proto2";
|
||||
|
||||
import "sub/unlucky.proto";
|
||||
|
||||
message SimpleMessage {
|
||||
required int32 lucky_number = 1;
|
||||
required UnluckyNumber unlucky = 2;
|
||||
}
|
||||
|
5
third_party/nanopb/examples/cmake_relpath/proto/sub/unlucky.proto
vendored
Normal file
5
third_party/nanopb/examples/cmake_relpath/proto/sub/unlucky.proto
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
syntax = "proto2";
|
||||
|
||||
message UnluckyNumber {
|
||||
required uint32 number = 1;
|
||||
}
|
73
third_party/nanopb/examples/cmake_relpath/simple.c
vendored
Normal file
73
third_party/nanopb/examples/cmake_relpath/simple.c
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
#include <stdio.h>
|
||||
#include <pb_encode.h>
|
||||
#include <pb_decode.h>
|
||||
#include "simple.pb.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
/* This is the buffer where we will store our message. */
|
||||
uint8_t buffer[128];
|
||||
size_t message_length;
|
||||
bool status;
|
||||
|
||||
/* Encode our message */
|
||||
{
|
||||
/* Allocate space on the stack to store the message data.
|
||||
*
|
||||
* Nanopb generates simple struct definitions for all the messages.
|
||||
* - check out the contents of simple.pb.h!
|
||||
* It is a good idea to always initialize your structures
|
||||
* so that you do not have garbage data from RAM in there.
|
||||
*/
|
||||
SimpleMessage message = SimpleMessage_init_zero;
|
||||
|
||||
/* Create a stream that will write to our buffer. */
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
|
||||
|
||||
/* Fill in the lucky number */
|
||||
message.lucky_number = 13;
|
||||
message.unlucky.number = 42;
|
||||
|
||||
/* Now we are ready to encode the message! */
|
||||
status = pb_encode(&stream, SimpleMessage_fields, &message);
|
||||
message_length = stream.bytes_written;
|
||||
|
||||
/* Then just check for any errors.. */
|
||||
if (!status)
|
||||
{
|
||||
printf("Encoding failed: %s\n", PB_GET_ERROR(&stream));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we could transmit the message over network, store it in a file or
|
||||
* wrap it to a pigeon's leg.
|
||||
*/
|
||||
|
||||
/* But because we are lazy, we will just decode it immediately. */
|
||||
|
||||
{
|
||||
/* Allocate space for the decoded message. */
|
||||
SimpleMessage message = SimpleMessage_init_zero;
|
||||
|
||||
/* Create a stream that reads from the buffer. */
|
||||
pb_istream_t stream = pb_istream_from_buffer(buffer, message_length);
|
||||
|
||||
/* Now we are ready to decode the message. */
|
||||
status = pb_decode(&stream, SimpleMessage_fields, &message);
|
||||
|
||||
/* Check for errors... */
|
||||
if (!status)
|
||||
{
|
||||
printf("Decoding failed: %s\n", PB_GET_ERROR(&stream));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Print the data contained in the message. */
|
||||
printf("Your lucky number was %d!\n", message.lucky_number);
|
||||
printf("Your unlucky number was %u!\n", message.unlucky.number);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
18
third_party/nanopb/examples/cmake_simple/README.txt
vendored
Normal file
18
third_party/nanopb/examples/cmake_simple/README.txt
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
Nanopb example "simple" using CMake
|
||||
=======================
|
||||
|
||||
This example is the same as the simple nanopb example but built using CMake.
|
||||
|
||||
Example usage
|
||||
-------------
|
||||
|
||||
On Linux, create a build directory and then call cmake:
|
||||
|
||||
nanopb/examples/cmake_simple$ mkdir build
|
||||
nanopb/examples/cmake_simple$ cd build/
|
||||
nanopb/examples/cmake_simple/build$ cmake ..
|
||||
nanopb/examples/cmake_simple/build$ make
|
||||
|
||||
After that, you can run it with the command: ./simple
|
||||
|
||||
On other platforms supported by CMake, refer to CMake instructions.
|
71
third_party/nanopb/examples/cmake_simple/simple.c
vendored
Normal file
71
third_party/nanopb/examples/cmake_simple/simple.c
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
#include <stdio.h>
|
||||
#include <pb_encode.h>
|
||||
#include <pb_decode.h>
|
||||
#include "simple.pb.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
/* This is the buffer where we will store our message. */
|
||||
uint8_t buffer[128];
|
||||
size_t message_length;
|
||||
bool status;
|
||||
|
||||
/* Encode our message */
|
||||
{
|
||||
/* Allocate space on the stack to store the message data.
|
||||
*
|
||||
* Nanopb generates simple struct definitions for all the messages.
|
||||
* - check out the contents of simple.pb.h!
|
||||
* It is a good idea to always initialize your structures
|
||||
* so that you do not have garbage data from RAM in there.
|
||||
*/
|
||||
SimpleMessage message = SimpleMessage_init_zero;
|
||||
|
||||
/* Create a stream that will write to our buffer. */
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
|
||||
|
||||
/* Fill in the lucky number */
|
||||
message.lucky_number = 13;
|
||||
|
||||
/* Now we are ready to encode the message! */
|
||||
status = pb_encode(&stream, SimpleMessage_fields, &message);
|
||||
message_length = stream.bytes_written;
|
||||
|
||||
/* Then just check for any errors.. */
|
||||
if (!status)
|
||||
{
|
||||
printf("Encoding failed: %s\n", PB_GET_ERROR(&stream));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we could transmit the message over network, store it in a file or
|
||||
* wrap it to a pigeon's leg.
|
||||
*/
|
||||
|
||||
/* But because we are lazy, we will just decode it immediately. */
|
||||
|
||||
{
|
||||
/* Allocate space for the decoded message. */
|
||||
SimpleMessage message = SimpleMessage_init_zero;
|
||||
|
||||
/* Create a stream that reads from the buffer. */
|
||||
pb_istream_t stream = pb_istream_from_buffer(buffer, message_length);
|
||||
|
||||
/* Now we are ready to decode the message. */
|
||||
status = pb_decode(&stream, SimpleMessage_fields, &message);
|
||||
|
||||
/* Check for errors... */
|
||||
if (!status)
|
||||
{
|
||||
printf("Decoding failed: %s\n", PB_GET_ERROR(&stream));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Print the data contained in the message. */
|
||||
printf("Your lucky number was %d!\n", message.lucky_number);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
9
third_party/nanopb/examples/cmake_simple/simple.proto
vendored
Normal file
9
third_party/nanopb/examples/cmake_simple/simple.proto
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
// A very simple protocol definition, consisting of only
|
||||
// one message.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
message SimpleMessage {
|
||||
required int32 lucky_number = 1;
|
||||
}
|
||||
|
17
third_party/nanopb/examples/network_server/Makefile
vendored
Normal file
17
third_party/nanopb/examples/network_server/Makefile
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Include the nanopb provided Makefile rules
|
||||
include ../../extra/nanopb.mk
|
||||
|
||||
# Compiler flags to enable all warnings & debug info
|
||||
CFLAGS = -ansi -Wall -Werror -g -O0
|
||||
CFLAGS += -I$(NANOPB_DIR)
|
||||
|
||||
all: server client
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
clean:
|
||||
rm -f server client fileproto.pb.c fileproto.pb.h
|
||||
|
||||
%: %.c common.c fileproto.pb.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(NANOPB_CORE)
|
||||
|
60
third_party/nanopb/examples/network_server/README.txt
vendored
Normal file
60
third_party/nanopb/examples/network_server/README.txt
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
Nanopb example "network_server"
|
||||
===============================
|
||||
|
||||
This example demonstrates the use of nanopb to communicate over network
|
||||
connections. It consists of a server that sends file listings, and of
|
||||
a client that requests the file list from the server.
|
||||
|
||||
Example usage
|
||||
-------------
|
||||
|
||||
user@host:~/nanopb/examples/network_server$ make # Build the example
|
||||
protoc -ofileproto.pb fileproto.proto
|
||||
python ../../generator/nanopb_generator.py fileproto.pb
|
||||
Writing to fileproto.pb.h and fileproto.pb.c
|
||||
cc -ansi -Wall -Werror -I .. -g -O0 -I../.. -o server server.c
|
||||
../../pb_decode.c ../../pb_encode.c fileproto.pb.c common.c
|
||||
cc -ansi -Wall -Werror -I .. -g -O0 -I../.. -o client client.c
|
||||
../../pb_decode.c ../../pb_encode.c fileproto.pb.c common.c
|
||||
|
||||
user@host:~/nanopb/examples/network_server$ ./server & # Start the server on background
|
||||
[1] 24462
|
||||
|
||||
petteri@oddish:~/nanopb/examples/network_server$ ./client /bin # Request the server to list /bin
|
||||
Got connection.
|
||||
Listing directory: /bin
|
||||
1327119 bzdiff
|
||||
1327126 bzless
|
||||
1327147 ps
|
||||
1327178 ntfsmove
|
||||
1327271 mv
|
||||
1327187 mount
|
||||
1327259 false
|
||||
1327266 tempfile
|
||||
1327285 zfgrep
|
||||
1327165 gzexe
|
||||
1327204 nc.openbsd
|
||||
1327260 uname
|
||||
|
||||
|
||||
Details of implementation
|
||||
-------------------------
|
||||
fileproto.proto contains the portable Google Protocol Buffers protocol definition.
|
||||
It could be used as-is to implement a server or a client in any other language, for
|
||||
example Python or Java.
|
||||
|
||||
fileproto.options contains the nanopb-specific options for the protocol file. This
|
||||
sets the amount of space allocated for file names when decoding messages.
|
||||
|
||||
common.c/h contains functions that allow nanopb to read and write directly from
|
||||
network socket. This way there is no need to allocate a separate buffer to store
|
||||
the message.
|
||||
|
||||
server.c contains the code to open a listening socket, to respond to clients and
|
||||
to list directory contents.
|
||||
|
||||
client.c contains the code to connect to a server, to send a request and to print
|
||||
the response message.
|
||||
|
||||
The code is implemented using the POSIX socket api, but it should be easy enough
|
||||
to port into any other socket api, such as lwip.
|
138
third_party/nanopb/examples/network_server/client.c
vendored
Normal file
138
third_party/nanopb/examples/network_server/client.c
vendored
Normal file
|
@ -0,0 +1,138 @@
|
|||
/* This is a simple TCP client that connects to port 1234 and prints a list
|
||||
* of files in a given directory.
|
||||
*
|
||||
* It directly deserializes and serializes messages from network, minimizing
|
||||
* memory use.
|
||||
*
|
||||
* For flexibility, this example is implemented using posix api.
|
||||
* In a real embedded system you would typically use some other kind of
|
||||
* a communication and filesystem layer.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <pb_encode.h>
|
||||
#include <pb_decode.h>
|
||||
|
||||
#include "fileproto.pb.h"
|
||||
#include "common.h"
|
||||
|
||||
/* This callback function will be called once for each filename received
|
||||
* from the server. The filenames will be printed out immediately, so that
|
||||
* no memory has to be allocated for them.
|
||||
*/
|
||||
bool ListFilesResponse_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
|
||||
{
|
||||
PB_UNUSED(ostream);
|
||||
if (istream != NULL && field->tag == ListFilesResponse_file_tag)
|
||||
{
|
||||
FileInfo fileinfo = {};
|
||||
|
||||
if (!pb_decode(istream, FileInfo_fields, &fileinfo))
|
||||
return false;
|
||||
|
||||
printf("%-10lld %s\n", (long long)fileinfo.inode, fileinfo.name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This function sends a request to socket 'fd' to list the files in
|
||||
* directory given in 'path'. The results received from server will
|
||||
* be printed to stdout.
|
||||
*/
|
||||
bool listdir(int fd, char *path)
|
||||
{
|
||||
/* Construct and send the request to server */
|
||||
{
|
||||
ListFilesRequest request = {};
|
||||
pb_ostream_t output = pb_ostream_from_socket(fd);
|
||||
|
||||
/* In our protocol, path is optional. If it is not given,
|
||||
* the server will list the root directory. */
|
||||
if (path == NULL)
|
||||
{
|
||||
request.has_path = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
request.has_path = true;
|
||||
if (strlen(path) + 1 > sizeof(request.path))
|
||||
{
|
||||
fprintf(stderr, "Too long path.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy(request.path, path);
|
||||
}
|
||||
|
||||
/* Encode the request. It is written to the socket immediately
|
||||
* through our custom stream. */
|
||||
if (!pb_encode_delimited(&output, ListFilesRequest_fields, &request))
|
||||
{
|
||||
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&output));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read back the response from server */
|
||||
{
|
||||
ListFilesResponse response = {};
|
||||
pb_istream_t input = pb_istream_from_socket(fd);
|
||||
|
||||
if (!pb_decode_delimited(&input, ListFilesResponse_fields, &response))
|
||||
{
|
||||
fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&input));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If the message from server decodes properly, but directory was
|
||||
* not found on server side, we get path_error == true. */
|
||||
if (response.path_error)
|
||||
{
|
||||
fprintf(stderr, "Server reported error.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int sockfd;
|
||||
struct sockaddr_in servaddr;
|
||||
char *path = NULL;
|
||||
|
||||
if (argc > 1)
|
||||
path = argv[1];
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
/* Connect to server running on localhost:1234 */
|
||||
memset(&servaddr, 0, sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
servaddr.sin_port = htons(1234);
|
||||
|
||||
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
|
||||
{
|
||||
perror("connect");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Send the directory listing request */
|
||||
if (!listdir(sockfd, path))
|
||||
return 2;
|
||||
|
||||
/* Close connection */
|
||||
close(sockfd);
|
||||
|
||||
return 0;
|
||||
}
|
43
third_party/nanopb/examples/network_server/common.c
vendored
Normal file
43
third_party/nanopb/examples/network_server/common.c
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* Simple binding of nanopb streams to TCP sockets.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <pb_encode.h>
|
||||
#include <pb_decode.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static bool write_callback(pb_ostream_t *stream, const uint8_t *buf, size_t count)
|
||||
{
|
||||
int fd = (intptr_t)stream->state;
|
||||
return send(fd, buf, count, 0) == count;
|
||||
}
|
||||
|
||||
static bool read_callback(pb_istream_t *stream, uint8_t *buf, size_t count)
|
||||
{
|
||||
int fd = (intptr_t)stream->state;
|
||||
int result;
|
||||
|
||||
if (count == 0)
|
||||
return true;
|
||||
|
||||
result = recv(fd, buf, count, MSG_WAITALL);
|
||||
|
||||
if (result == 0)
|
||||
stream->bytes_left = 0; /* EOF */
|
||||
|
||||
return result == count;
|
||||
}
|
||||
|
||||
pb_ostream_t pb_ostream_from_socket(int fd)
|
||||
{
|
||||
pb_ostream_t stream = {&write_callback, (void*)(intptr_t)fd, SIZE_MAX, 0};
|
||||
return stream;
|
||||
}
|
||||
|
||||
pb_istream_t pb_istream_from_socket(int fd)
|
||||
{
|
||||
pb_istream_t stream = {&read_callback, (void*)(intptr_t)fd, SIZE_MAX};
|
||||
return stream;
|
||||
}
|
9
third_party/nanopb/examples/network_server/common.h
vendored
Normal file
9
third_party/nanopb/examples/network_server/common.h
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef _PB_EXAMPLE_COMMON_H_
|
||||
#define _PB_EXAMPLE_COMMON_H_
|
||||
|
||||
#include <pb.h>
|
||||
|
||||
pb_ostream_t pb_ostream_from_socket(int fd);
|
||||
pb_istream_t pb_istream_from_socket(int fd);
|
||||
|
||||
#endif
|
16
third_party/nanopb/examples/network_server/fileproto.options
vendored
Normal file
16
third_party/nanopb/examples/network_server/fileproto.options
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
# This file defines the nanopb-specific options for the messages defined
|
||||
# in fileproto.proto.
|
||||
#
|
||||
# If you come from high-level programming background, the hardcoded
|
||||
# maximum lengths may disgust you. However, if your microcontroller only
|
||||
# has a few kB of ram to begin with, setting reasonable limits for
|
||||
# filenames is ok.
|
||||
#
|
||||
# On the other hand, using the callback interface, it is not necessary
|
||||
# to set a limit on the number of files in the response.
|
||||
|
||||
* include:"sys/types.h"
|
||||
* include:"dirent.h"
|
||||
ListFilesResponse.file type:FT_CALLBACK, callback_datatype:"DIR*"
|
||||
ListFilesRequest.path max_size:128
|
||||
FileInfo.name max_size:128
|
20
third_party/nanopb/examples/network_server/fileproto.proto
vendored
Normal file
20
third_party/nanopb/examples/network_server/fileproto.proto
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
// This defines protocol for a simple server that lists files.
|
||||
//
|
||||
// See also the nanopb-specific options in fileproto.options.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
message ListFilesRequest {
|
||||
optional string path = 1 [default = "/"];
|
||||
}
|
||||
|
||||
message FileInfo {
|
||||
required uint64 inode = 1;
|
||||
required string name = 2;
|
||||
}
|
||||
|
||||
message ListFilesResponse {
|
||||
optional bool path_error = 1 [default = false];
|
||||
repeated FileInfo file = 2;
|
||||
}
|
||||
|
164
third_party/nanopb/examples/network_server/server.c
vendored
Normal file
164
third_party/nanopb/examples/network_server/server.c
vendored
Normal file
|
@ -0,0 +1,164 @@
|
|||
/* This is a simple TCP server that listens on port 1234 and provides lists
|
||||
* of files to clients, using a protocol defined in file_server.proto.
|
||||
*
|
||||
* It directly deserializes and serializes messages from network, minimizing
|
||||
* memory use.
|
||||
*
|
||||
* For flexibility, this example is implemented using posix api.
|
||||
* In a real embedded system you would typically use some other kind of
|
||||
* a communication and filesystem layer.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <pb_encode.h>
|
||||
#include <pb_decode.h>
|
||||
|
||||
#include "fileproto.pb.h"
|
||||
#include "common.h"
|
||||
|
||||
/* This callback function will be called during the encoding.
|
||||
* It will write out any number of FileInfo entries, without consuming unnecessary memory.
|
||||
* This is accomplished by fetching the filenames one at a time and encoding them
|
||||
* immediately.
|
||||
*/
|
||||
bool ListFilesResponse_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
|
||||
{
|
||||
PB_UNUSED(istream);
|
||||
if (ostream != NULL && field->tag == ListFilesResponse_file_tag)
|
||||
{
|
||||
DIR *dir = *(DIR**)field->pData;
|
||||
struct dirent *file;
|
||||
FileInfo fileinfo = {};
|
||||
|
||||
while ((file = readdir(dir)) != NULL)
|
||||
{
|
||||
fileinfo.inode = file->d_ino;
|
||||
strncpy(fileinfo.name, file->d_name, sizeof(fileinfo.name));
|
||||
fileinfo.name[sizeof(fileinfo.name) - 1] = '\0';
|
||||
|
||||
/* This encodes the header for the field, based on the constant info
|
||||
* from pb_field_t. */
|
||||
if (!pb_encode_tag_for_field(ostream, field))
|
||||
return false;
|
||||
|
||||
/* This encodes the data for the field, based on our FileInfo structure. */
|
||||
if (!pb_encode_submessage(ostream, FileInfo_fields, &fileinfo))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Because the main program uses pb_encode_delimited(), this callback will be
|
||||
* called twice. Rewind the directory for the next call. */
|
||||
rewinddir(dir);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Handle one arriving client connection.
|
||||
* Clients are expected to send a ListFilesRequest, terminated by a '0'.
|
||||
* Server will respond with a ListFilesResponse message.
|
||||
*/
|
||||
void handle_connection(int connfd)
|
||||
{
|
||||
DIR *directory = NULL;
|
||||
|
||||
/* Decode the message from the client and open the requested directory. */
|
||||
{
|
||||
ListFilesRequest request = {};
|
||||
pb_istream_t input = pb_istream_from_socket(connfd);
|
||||
|
||||
if (!pb_decode_delimited(&input, ListFilesRequest_fields, &request))
|
||||
{
|
||||
printf("Decode failed: %s\n", PB_GET_ERROR(&input));
|
||||
return;
|
||||
}
|
||||
|
||||
directory = opendir(request.path);
|
||||
printf("Listing directory: %s\n", request.path);
|
||||
}
|
||||
|
||||
/* List the files in the directory and transmit the response to client */
|
||||
{
|
||||
ListFilesResponse response = {};
|
||||
pb_ostream_t output = pb_ostream_from_socket(connfd);
|
||||
|
||||
if (directory == NULL)
|
||||
{
|
||||
perror("opendir");
|
||||
|
||||
/* Directory was not found, transmit error status */
|
||||
response.has_path_error = true;
|
||||
response.path_error = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Directory was found, transmit filenames */
|
||||
response.has_path_error = false;
|
||||
response.file = directory;
|
||||
}
|
||||
|
||||
if (!pb_encode_delimited(&output, ListFilesResponse_fields, &response))
|
||||
{
|
||||
printf("Encoding failed: %s\n", PB_GET_ERROR(&output));
|
||||
}
|
||||
}
|
||||
|
||||
if (directory != NULL)
|
||||
closedir(directory);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int listenfd, connfd;
|
||||
struct sockaddr_in servaddr;
|
||||
int reuse = 1;
|
||||
|
||||
/* Listen on localhost:1234 for TCP connections */
|
||||
listenfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
|
||||
|
||||
memset(&servaddr, 0, sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
servaddr.sin_port = htons(1234);
|
||||
if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0)
|
||||
{
|
||||
perror("bind");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (listen(listenfd, 5) != 0)
|
||||
{
|
||||
perror("listen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
/* Wait for a client */
|
||||
connfd = accept(listenfd, NULL, NULL);
|
||||
|
||||
if (connfd < 0)
|
||||
{
|
||||
perror("accept");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Got connection.\n");
|
||||
|
||||
handle_connection(connfd);
|
||||
|
||||
printf("Closing connection.\n");
|
||||
|
||||
close(connfd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
5
third_party/nanopb/examples/platformio/.gitignore
vendored
Normal file
5
third_party/nanopb/examples/platformio/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
.pio/
|
||||
.idea/
|
||||
cmake-build-*/
|
||||
/CMakeLists.txt
|
||||
CMakeListsPrivate.txt
|
48
third_party/nanopb/examples/platformio/platformio.ini
vendored
Normal file
48
third_party/nanopb/examples/platformio/platformio.ini
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
;
|
||||
; You can setup `custom_nanopb_protos` `nanopb_options` vars to generate code from proto files
|
||||
;
|
||||
; Generator will use next folders:
|
||||
;
|
||||
; `$BUILD_DIR/nanopb/generated-src` - `*.pb.h` and `*.pb.c` files
|
||||
; `$BUILD_DIR/nanopb/md5` - MD5 files to track changes in source .proto/.options
|
||||
;
|
||||
; Compiled `.pb.o` files will be located under `$BUILD_DIR/nanopb/generated-build`
|
||||
;
|
||||
; Example:
|
||||
|
||||
[env:pio_with_options]
|
||||
platform = native
|
||||
lib_deps = Nanopb
|
||||
|
||||
src_filter =
|
||||
+<pio_with_options.c>
|
||||
|
||||
; All path are relative to the `$PROJECT_DIR`
|
||||
custom_nanopb_protos =
|
||||
+<proto/pio_with_options.proto>
|
||||
custom_nanopb_options =
|
||||
--error-on-unmatched
|
||||
|
||||
[env:pio_without_options]
|
||||
platform = native
|
||||
lib_deps = Nanopb
|
||||
|
||||
src_filter =
|
||||
+<pio_without_options.c>
|
||||
|
||||
; All path are relative to the `$PROJECT_DIR`
|
||||
custom_nanopb_protos =
|
||||
+<proto/pio_without_options.proto>
|
||||
|
||||
|
||||
[env:pio_esp32_idf]
|
||||
platform = espressif32
|
||||
board = firebeetle32
|
||||
framework = espidf
|
||||
lib_deps = Nanopb
|
||||
|
||||
; Warning: the 'src_filter' option cannot be used with ESP-IDF. Select source files to build in the project CMakeLists.txt file.
|
||||
; So, we specified source files in src/CMakeLists.txt
|
||||
|
||||
custom_nanopb_protos =
|
||||
+<proto/pio_without_options.proto>
|
1
third_party/nanopb/examples/platformio/proto/pio_with_options.options
vendored
Normal file
1
third_party/nanopb/examples/platformio/proto/pio_with_options.options
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
TestMessageWithOptions.str max_size:16
|
5
third_party/nanopb/examples/platformio/proto/pio_with_options.proto
vendored
Normal file
5
third_party/nanopb/examples/platformio/proto/pio_with_options.proto
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
syntax = "proto3";
|
||||
|
||||
message TestMessageWithOptions {
|
||||
string str = 1;
|
||||
}
|
5
third_party/nanopb/examples/platformio/proto/pio_without_options.proto
vendored
Normal file
5
third_party/nanopb/examples/platformio/proto/pio_without_options.proto
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
syntax = "proto3";
|
||||
|
||||
message TestMessageWithoutOptions {
|
||||
int32 number = 1;
|
||||
}
|
34
third_party/nanopb/examples/platformio/src/pio_esp32_idf.c
vendored
Normal file
34
third_party/nanopb/examples/platformio/src/pio_esp32_idf.c
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
#include "pb_encode.h"
|
||||
#include "pb_decode.h"
|
||||
|
||||
#include "test.h"
|
||||
|
||||
#include "pio_without_options.pb.h"
|
||||
|
||||
void app_main() {
|
||||
int status = 0;
|
||||
|
||||
uint8_t buffer[256];
|
||||
pb_ostream_t ostream;
|
||||
pb_istream_t istream;
|
||||
size_t written;
|
||||
|
||||
TestMessageWithoutOptions original = TestMessageWithoutOptions_init_zero;
|
||||
original.number = 45;
|
||||
|
||||
ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
|
||||
|
||||
TEST(pb_encode(&ostream, &TestMessageWithoutOptions_msg, &original));
|
||||
|
||||
written = ostream.bytes_written;
|
||||
|
||||
istream = pb_istream_from_buffer(buffer, written);
|
||||
|
||||
TestMessageWithoutOptions decoded = TestMessageWithoutOptions_init_zero;
|
||||
|
||||
TEST(pb_decode(&istream, &TestMessageWithoutOptions_msg, &decoded));
|
||||
|
||||
TEST(decoded.number == 45);
|
||||
|
||||
return status;
|
||||
}
|
35
third_party/nanopb/examples/platformio/src/pio_with_options.c
vendored
Normal file
35
third_party/nanopb/examples/platformio/src/pio_with_options.c
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include "pb_encode.h"
|
||||
#include "pb_decode.h"
|
||||
|
||||
#include "test.h"
|
||||
|
||||
#include "pio_with_options.pb.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
int status = 0;
|
||||
|
||||
uint8_t buffer[256];
|
||||
pb_ostream_t ostream;
|
||||
pb_istream_t istream;
|
||||
size_t written;
|
||||
|
||||
TestMessageWithOptions original = TestMessageWithOptions_init_zero;
|
||||
strcpy(original.str,"Hello");
|
||||
|
||||
ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
|
||||
|
||||
TEST(pb_encode(&ostream, &TestMessageWithOptions_msg, &original));
|
||||
|
||||
written = ostream.bytes_written;
|
||||
|
||||
istream = pb_istream_from_buffer(buffer, written);
|
||||
|
||||
TestMessageWithOptions decoded = TestMessageWithOptions_init_zero;
|
||||
|
||||
TEST(pb_decode(&istream, &TestMessageWithOptions_msg, &decoded));
|
||||
|
||||
TEST(strcmp(decoded.str,"Hello") == 0);
|
||||
|
||||
return status;
|
||||
}
|
35
third_party/nanopb/examples/platformio/src/pio_without_options.c
vendored
Normal file
35
third_party/nanopb/examples/platformio/src/pio_without_options.c
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include "pb_encode.h"
|
||||
#include "pb_decode.h"
|
||||
|
||||
#include "test.h"
|
||||
|
||||
#include "pio_without_options.pb.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
int status = 0;
|
||||
|
||||
uint8_t buffer[256];
|
||||
pb_ostream_t ostream;
|
||||
pb_istream_t istream;
|
||||
size_t written;
|
||||
|
||||
TestMessageWithoutOptions original = TestMessageWithoutOptions_init_zero;
|
||||
original.number = 45;
|
||||
|
||||
ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
|
||||
|
||||
TEST(pb_encode(&ostream, &TestMessageWithoutOptions_msg, &original));
|
||||
|
||||
written = ostream.bytes_written;
|
||||
|
||||
istream = pb_istream_from_buffer(buffer, written);
|
||||
|
||||
TestMessageWithoutOptions decoded = TestMessageWithoutOptions_init_zero;
|
||||
|
||||
TEST(pb_decode(&istream, &TestMessageWithoutOptions_msg, &decoded));
|
||||
|
||||
TEST(decoded.number == 45);
|
||||
|
||||
return status;
|
||||
}
|
9
third_party/nanopb/examples/platformio/src/test.h
vendored
Normal file
9
third_party/nanopb/examples/platformio/src/test.h
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define TEST(x) \
|
||||
if (!(x)) { \
|
||||
fprintf(stderr, "\033[31;1mFAILED:\033[22;39m %s:%d %s\n", __FILE__, __LINE__, #x); \
|
||||
status = 1; \
|
||||
} else { \
|
||||
printf("\033[32;1mOK:\033[22;39m %s\n", #x); \
|
||||
}
|
22
third_party/nanopb/examples/simple/Makefile
vendored
Normal file
22
third_party/nanopb/examples/simple/Makefile
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Include the nanopb provided Makefile rules
|
||||
include ../../extra/nanopb.mk
|
||||
|
||||
# Compiler flags to enable all warnings & debug info
|
||||
CFLAGS = -Wall -Werror -g -O0
|
||||
CFLAGS += "-I$(NANOPB_DIR)"
|
||||
|
||||
# C source code files that are required
|
||||
CSRC = simple.c # The main program
|
||||
CSRC += simple.pb.c # The compiled protocol definition
|
||||
CSRC += $(NANOPB_DIR)/pb_encode.c # The nanopb encoder
|
||||
CSRC += $(NANOPB_DIR)/pb_decode.c # The nanopb decoder
|
||||
CSRC += $(NANOPB_DIR)/pb_common.c # The nanopb common parts
|
||||
|
||||
# Build rule for the main program
|
||||
simple: $(CSRC)
|
||||
$(CC) $(CFLAGS) -osimple $(CSRC)
|
||||
|
||||
# Build rule for the protocol
|
||||
simple.pb.c: simple.proto
|
||||
$(PROTOC) $(PROTOC_OPTS) --nanopb_out=. simple.proto
|
||||
|
29
third_party/nanopb/examples/simple/README.txt
vendored
Normal file
29
third_party/nanopb/examples/simple/README.txt
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
Nanopb example "simple"
|
||||
=======================
|
||||
|
||||
This example demonstrates the very basic use of nanopb. It encodes and
|
||||
decodes a simple message.
|
||||
|
||||
The code uses four different API functions:
|
||||
|
||||
* pb_ostream_from_buffer() to declare the output buffer that is to be used
|
||||
* pb_encode() to encode a message
|
||||
* pb_istream_from_buffer() to declare the input buffer that is to be used
|
||||
* pb_decode() to decode a message
|
||||
|
||||
Example usage
|
||||
-------------
|
||||
|
||||
On Linux, simply type "make" to build the example. After that, you can
|
||||
run it with the command: ./simple
|
||||
|
||||
On other platforms, you first have to compile the protocol definition using
|
||||
the following command::
|
||||
|
||||
../../generator-bin/protoc --nanopb_out=. simple.proto
|
||||
|
||||
After that, add the following five files to your project and compile:
|
||||
|
||||
simple.c simple.pb.c pb_encode.c pb_decode.c pb_common.c
|
||||
|
||||
|
71
third_party/nanopb/examples/simple/simple.c
vendored
Normal file
71
third_party/nanopb/examples/simple/simple.c
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
#include <stdio.h>
|
||||
#include <pb_encode.h>
|
||||
#include <pb_decode.h>
|
||||
#include "simple.pb.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
/* This is the buffer where we will store our message. */
|
||||
uint8_t buffer[128];
|
||||
size_t message_length;
|
||||
bool status;
|
||||
|
||||
/* Encode our message */
|
||||
{
|
||||
/* Allocate space on the stack to store the message data.
|
||||
*
|
||||
* Nanopb generates simple struct definitions for all the messages.
|
||||
* - check out the contents of simple.pb.h!
|
||||
* It is a good idea to always initialize your structures
|
||||
* so that you do not have garbage data from RAM in there.
|
||||
*/
|
||||
SimpleMessage message = SimpleMessage_init_zero;
|
||||
|
||||
/* Create a stream that will write to our buffer. */
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
|
||||
|
||||
/* Fill in the lucky number */
|
||||
message.lucky_number = 13;
|
||||
|
||||
/* Now we are ready to encode the message! */
|
||||
status = pb_encode(&stream, SimpleMessage_fields, &message);
|
||||
message_length = stream.bytes_written;
|
||||
|
||||
/* Then just check for any errors.. */
|
||||
if (!status)
|
||||
{
|
||||
printf("Encoding failed: %s\n", PB_GET_ERROR(&stream));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we could transmit the message over network, store it in a file or
|
||||
* wrap it to a pigeon's leg.
|
||||
*/
|
||||
|
||||
/* But because we are lazy, we will just decode it immediately. */
|
||||
|
||||
{
|
||||
/* Allocate space for the decoded message. */
|
||||
SimpleMessage message = SimpleMessage_init_zero;
|
||||
|
||||
/* Create a stream that reads from the buffer. */
|
||||
pb_istream_t stream = pb_istream_from_buffer(buffer, message_length);
|
||||
|
||||
/* Now we are ready to decode the message. */
|
||||
status = pb_decode(&stream, SimpleMessage_fields, &message);
|
||||
|
||||
/* Check for errors... */
|
||||
if (!status)
|
||||
{
|
||||
printf("Decoding failed: %s\n", PB_GET_ERROR(&stream));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Print the data contained in the message. */
|
||||
printf("Your lucky number was %d!\n", (int)message.lucky_number);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
9
third_party/nanopb/examples/simple/simple.proto
vendored
Normal file
9
third_party/nanopb/examples/simple/simple.proto
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
// A very simple protocol definition, consisting of only
|
||||
// one message.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
message SimpleMessage {
|
||||
required int32 lucky_number = 1;
|
||||
}
|
||||
|
20
third_party/nanopb/examples/using_union_messages/Makefile
vendored
Normal file
20
third_party/nanopb/examples/using_union_messages/Makefile
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Include the nanopb provided Makefile rules
|
||||
include ../../extra/nanopb.mk
|
||||
|
||||
# Compiler flags to enable all warnings & debug info
|
||||
CFLAGS = -ansi -Wall -Werror -g -O0
|
||||
CFLAGS += -I$(NANOPB_DIR)
|
||||
|
||||
all: encode decode
|
||||
./encode 1 | ./decode
|
||||
./encode 2 | ./decode
|
||||
./encode 3 | ./decode
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
clean:
|
||||
rm -f encode unionproto.pb.h unionproto.pb.c
|
||||
|
||||
%: %.c unionproto.pb.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(NANOPB_CORE)
|
||||
|
55
third_party/nanopb/examples/using_union_messages/README.txt
vendored
Normal file
55
third_party/nanopb/examples/using_union_messages/README.txt
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
Nanopb example "using_union_messages"
|
||||
=====================================
|
||||
|
||||
Union messages is a common technique in Google Protocol Buffers used to
|
||||
represent a group of messages, only one of which is passed at a time.
|
||||
It is described in Google's documentation:
|
||||
https://developers.google.com/protocol-buffers/docs/techniques#union
|
||||
|
||||
This directory contains an example on how to encode and decode union messages
|
||||
with minimal memory usage. Usually, nanopb would allocate space to store
|
||||
all of the possible messages at the same time, even though at most one of
|
||||
them will be used at a time.
|
||||
|
||||
By using some of the lower level nanopb APIs, we can manually generate the
|
||||
top level message, so that we only need to allocate the one submessage that
|
||||
we actually want. Similarly when decoding, we can manually read the tag of
|
||||
the top level message, and only then allocate the memory for the submessage
|
||||
after we already know its type.
|
||||
|
||||
NOTE: There is a newer protobuf feature called `oneof` that is also supported
|
||||
by nanopb. It might be a better option for new code.
|
||||
|
||||
|
||||
Example usage
|
||||
-------------
|
||||
|
||||
Type `make` to run the example. It will build it and run commands like
|
||||
following:
|
||||
|
||||
./encode 1 | ./decode
|
||||
Got MsgType1: 42
|
||||
./encode 2 | ./decode
|
||||
Got MsgType2: true
|
||||
./encode 3 | ./decode
|
||||
Got MsgType3: 3 1415
|
||||
|
||||
This simply demonstrates that the "decode" program has correctly identified
|
||||
the type of the received message, and managed to decode it.
|
||||
|
||||
|
||||
Details of implementation
|
||||
-------------------------
|
||||
|
||||
unionproto.proto contains the protocol used in the example. It consists of
|
||||
three messages: MsgType1, MsgType2 and MsgType3, which are collected together
|
||||
into UnionMessage.
|
||||
|
||||
encode.c takes one command line argument, which should be a number 1-3. It
|
||||
then fills in and encodes the corresponding message, and writes it to stdout.
|
||||
|
||||
decode.c reads a UnionMessage from stdin. Then it calls the function
|
||||
decode_unionmessage_type() to determine the type of the message. After that,
|
||||
the corresponding message is decoded and the contents of it printed to the
|
||||
screen.
|
||||
|
95
third_party/nanopb/examples/using_union_messages/decode.c
vendored
Normal file
95
third_party/nanopb/examples/using_union_messages/decode.c
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
/* This program reads a message from stdin, detects its type and decodes it.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <pb_decode.h>
|
||||
#include <pb_common.h>
|
||||
#include "unionproto.pb.h"
|
||||
|
||||
/* This function reads manually the first tag from the stream and finds the
|
||||
* corresponding message type. It doesn't yet decode the actual message.
|
||||
*
|
||||
* Returns a pointer to the MsgType_fields array, as an identifier for the
|
||||
* message type. Returns null if the tag is of unknown type or an error occurs.
|
||||
*/
|
||||
const pb_msgdesc_t* decode_unionmessage_type(pb_istream_t *stream)
|
||||
{
|
||||
pb_wire_type_t wire_type;
|
||||
uint32_t tag;
|
||||
bool eof;
|
||||
|
||||
while (pb_decode_tag(stream, &wire_type, &tag, &eof))
|
||||
{
|
||||
if (wire_type == PB_WT_STRING)
|
||||
{
|
||||
pb_field_iter_t iter;
|
||||
if (pb_field_iter_begin(&iter, UnionMessage_fields, NULL) &&
|
||||
pb_field_iter_find(&iter, tag))
|
||||
{
|
||||
/* Found our field. */
|
||||
return iter.submsg_desc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wasn't our field.. */
|
||||
pb_skip_field(stream, wire_type);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool decode_unionmessage_contents(pb_istream_t *stream, const pb_msgdesc_t *messagetype, void *dest_struct)
|
||||
{
|
||||
pb_istream_t substream;
|
||||
bool status;
|
||||
if (!pb_make_string_substream(stream, &substream))
|
||||
return false;
|
||||
|
||||
status = pb_decode(&substream, messagetype, dest_struct);
|
||||
pb_close_string_substream(stream, &substream);
|
||||
return status;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
/* Read the data into buffer */
|
||||
uint8_t buffer[512];
|
||||
size_t count = fread(buffer, 1, sizeof(buffer), stdin);
|
||||
pb_istream_t stream = pb_istream_from_buffer(buffer, count);
|
||||
|
||||
const pb_msgdesc_t *type = decode_unionmessage_type(&stream);
|
||||
bool status = false;
|
||||
|
||||
if (type == MsgType1_fields)
|
||||
{
|
||||
MsgType1 msg = {};
|
||||
status = decode_unionmessage_contents(&stream, MsgType1_fields, &msg);
|
||||
printf("Got MsgType1: %d\n", msg.value);
|
||||
}
|
||||
else if (type == MsgType2_fields)
|
||||
{
|
||||
MsgType2 msg = {};
|
||||
status = decode_unionmessage_contents(&stream, MsgType2_fields, &msg);
|
||||
printf("Got MsgType2: %s\n", msg.value ? "true" : "false");
|
||||
}
|
||||
else if (type == MsgType3_fields)
|
||||
{
|
||||
MsgType3 msg = {};
|
||||
status = decode_unionmessage_contents(&stream, MsgType3_fields, &msg);
|
||||
printf("Got MsgType3: %d %d\n", msg.value1, msg.value2);
|
||||
}
|
||||
|
||||
if (!status)
|
||||
{
|
||||
printf("Decode failed: %s\n", PB_GET_ERROR(&stream));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
90
third_party/nanopb/examples/using_union_messages/encode.c
vendored
Normal file
90
third_party/nanopb/examples/using_union_messages/encode.c
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
/* This program takes a command line argument and encodes a message in
|
||||
* one of MsgType1, MsgType2 or MsgType3.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <pb_encode.h>
|
||||
#include <pb_common.h>
|
||||
#include "unionproto.pb.h"
|
||||
|
||||
/* This function is the core of the union encoding process. It handles
|
||||
* the top-level pb_field_t array manually, in order to encode a correct
|
||||
* field tag before the message. The pointer to MsgType_fields array is
|
||||
* used as an unique identifier for the message type.
|
||||
*/
|
||||
bool encode_unionmessage(pb_ostream_t *stream, const pb_msgdesc_t *messagetype, void *message)
|
||||
{
|
||||
pb_field_iter_t iter;
|
||||
|
||||
if (!pb_field_iter_begin(&iter, UnionMessage_fields, message))
|
||||
return false;
|
||||
|
||||
do
|
||||
{
|
||||
if (iter.submsg_desc == messagetype)
|
||||
{
|
||||
/* This is our field, encode the message using it. */
|
||||
if (!pb_encode_tag_for_field(stream, &iter))
|
||||
return false;
|
||||
|
||||
return pb_encode_submessage(stream, messagetype, message);
|
||||
}
|
||||
} while (pb_field_iter_next(&iter));
|
||||
|
||||
/* Didn't find the field for messagetype */
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s (1|2|3)\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t buffer[512];
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
|
||||
|
||||
bool status = false;
|
||||
int msgtype = atoi(argv[1]);
|
||||
if (msgtype == 1)
|
||||
{
|
||||
/* Send message of type 1 */
|
||||
MsgType1 msg = {42};
|
||||
status = encode_unionmessage(&stream, MsgType1_fields, &msg);
|
||||
}
|
||||
else if (msgtype == 2)
|
||||
{
|
||||
/* Send message of type 2 */
|
||||
MsgType2 msg = {true};
|
||||
status = encode_unionmessage(&stream, MsgType2_fields, &msg);
|
||||
}
|
||||
else if (msgtype == 3)
|
||||
{
|
||||
/* Send message of type 3 */
|
||||
MsgType3 msg = {3, 1415};
|
||||
status = encode_unionmessage(&stream, MsgType3_fields, &msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Unknown message type: %d\n", msgtype);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (!status)
|
||||
{
|
||||
fprintf(stderr, "Encoding failed!\n");
|
||||
return 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
fwrite(buffer, 1, stream.bytes_written, stdout);
|
||||
return 0; /* Success */
|
||||
}
|
||||
}
|
||||
|
||||
|
32
third_party/nanopb/examples/using_union_messages/unionproto.proto
vendored
Normal file
32
third_party/nanopb/examples/using_union_messages/unionproto.proto
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
// This is an example of how to handle 'union' style messages
|
||||
// with nanopb, without allocating memory for all the message types.
|
||||
//
|
||||
// There is no official type in Protocol Buffers for describing unions,
|
||||
// but they are commonly implemented by filling out exactly one of
|
||||
// several optional fields.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
message MsgType1
|
||||
{
|
||||
required int32 value = 1;
|
||||
}
|
||||
|
||||
message MsgType2
|
||||
{
|
||||
required bool value = 1;
|
||||
}
|
||||
|
||||
message MsgType3
|
||||
{
|
||||
required int32 value1 = 1;
|
||||
required int32 value2 = 2;
|
||||
}
|
||||
|
||||
message UnionMessage
|
||||
{
|
||||
optional MsgType1 msg1 = 1;
|
||||
optional MsgType2 msg2 = 2;
|
||||
optional MsgType3 msg3 = 3;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue