From 4414054d922b90b0111b7ea345b7f14e31cd679a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 14 Jun 2017 20:40:31 +0200 Subject: [PATCH] bootloader: migrate to nanopb --- .gitmodules | 3 + Makefile.bootloader | 9 +- micropython/bootloader/main.c | 70 +- micropython/bootloader/messages.c | 143 +- micropython/bootloader/messages.h | 17 +- micropython/bootloader/nanopb/pb.h | 583 +++++++ micropython/bootloader/nanopb/pb_common.c | 97 ++ micropython/bootloader/nanopb/pb_common.h | 42 + micropython/bootloader/nanopb/pb_decode.c | 1379 +++++++++++++++++ micropython/bootloader/nanopb/pb_decode.h | 153 ++ micropython/bootloader/nanopb/pb_encode.c | 777 ++++++++++ micropython/bootloader/nanopb/pb_encode.h | 154 ++ micropython/bootloader/protob/.gitignore | 2 + micropython/bootloader/protob/Makefile | 10 + .../bootloader/protob/messages.options | 0 micropython/bootloader/protob/messages.pb.c | 492 ++++++ micropython/bootloader/protob/messages.pb.h | 1099 +++++++++++++ micropython/bootloader/protob/messages.proto | 1 + micropython/bootloader/protob/types.options | 0 micropython/bootloader/protob/types.pb.c | 233 +++ micropython/bootloader/protob/types.pb.h | 384 +++++ micropython/bootloader/protob/types.proto | 1 + micropython/bootloader/protobuf.c | 96 -- micropython/bootloader/protobuf.h | 26 - vendor/trezor-common | 1 + 25 files changed, 5548 insertions(+), 224 deletions(-) create mode 100644 micropython/bootloader/nanopb/pb.h create mode 100644 micropython/bootloader/nanopb/pb_common.c create mode 100644 micropython/bootloader/nanopb/pb_common.h create mode 100644 micropython/bootloader/nanopb/pb_decode.c create mode 100644 micropython/bootloader/nanopb/pb_decode.h create mode 100644 micropython/bootloader/nanopb/pb_encode.c create mode 100644 micropython/bootloader/nanopb/pb_encode.h create mode 100644 micropython/bootloader/protob/.gitignore create mode 100644 micropython/bootloader/protob/Makefile create mode 100644 micropython/bootloader/protob/messages.options create mode 100644 micropython/bootloader/protob/messages.pb.c create mode 100644 micropython/bootloader/protob/messages.pb.h create mode 120000 micropython/bootloader/protob/messages.proto create mode 100644 micropython/bootloader/protob/types.options create mode 100644 micropython/bootloader/protob/types.pb.c create mode 100644 micropython/bootloader/protob/types.pb.h create mode 120000 micropython/bootloader/protob/types.proto delete mode 100644 micropython/bootloader/protobuf.c delete mode 100644 micropython/bootloader/protobuf.h create mode 160000 vendor/trezor-common diff --git a/.gitmodules b/.gitmodules index 075894e4e..18067e4ec 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "vendor/norcow"] path = vendor/norcow url = https://github.com/trezor/norcow.git +[submodule "vendor/trezor-common"] + path = vendor/trezor-common + url = https://github.com/trezor/trezor-common.git diff --git a/Makefile.bootloader b/Makefile.bootloader index 4a889ed20..ff50d17db 100644 --- a/Makefile.bootloader +++ b/Makefile.bootloader @@ -68,7 +68,11 @@ OBJ_BOOTLOADER += $(addprefix $(BUILD_FW)/, \ bootloader/header.o \ bootloader/main.o \ bootloader/messages.o \ - bootloader/protobuf.o \ + bootloader/nanopb/pb_common.o \ + bootloader/nanopb/pb_decode.o \ + bootloader/nanopb/pb_encode.o \ + bootloader/protob/messages.pb.o \ + bootloader/protob/types.pb.o \ extmod/modtrezorcrypto/trezor-crypto/ed25519-donna/ed25519.o \ extmod/modtrezorcrypto/trezor-crypto/blake2s.o \ extmod/modtrezorcrypto/trezor-crypto/sha2.o \ @@ -109,6 +113,8 @@ CROSS_COMPILE = arm-none-eabi- INC += -I. INC += -I$(SRCDIR_FW)/$(PROJECT) +INC += -I$(SRCDIR_FW)/$(PROJECT)/nanopb +INC += -I$(SRCDIR_FW)/$(PROJECT)/protob INC += -I$(SRCDIR_FW)/extmod/modtrezorui INC += -I$(SRCDIR_FW)/trezorhal INC += -I$(SRCDIR_FW)/trezorhal/hal @@ -131,6 +137,7 @@ CFLAGS += -mthumb -mtune=cortex-m4 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi CFLAGS += -DSTM32F405xx -DMCU_SERIES_F4 CFLAGS += -DSTM32_HAL_H='' CFLAGS += -DTREZOR_STM32 +CFLAGS += -DPB_FIELD_16BIT=1 LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) diff --git a/micropython/bootloader/main.c b/micropython/bootloader/main.c index 1faba5492..0531fa5ad 100644 --- a/micropython/bootloader/main.c +++ b/micropython/bootloader/main.c @@ -14,7 +14,6 @@ #include "mini_printf.h" #include "messages.h" -#include "protobuf.h" #define IMAGE_MAGIC 0x465A5254 // TRZF #define IMAGE_MAXSIZE (7 * 128 * 1024) @@ -90,6 +89,9 @@ void check_and_jump(void) } } +#define USB_PACKET_SIZE 64 +#define USB_IFACE_NUM 0 + int usb_init_all(void) { static const usb_dev_info_t dev_info = { .vendor_id = 0x1209, @@ -101,7 +103,7 @@ int usb_init_all(void) { .configuration_str = (const uint8_t *)"", .interface_str = (const uint8_t *)"", }; - static uint8_t hid_rx_buffer[64]; + static uint8_t hid_rx_buffer[USB_PACKET_SIZE]; static const uint8_t hid_report_desc[] = { 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined) 0x09, 0x01, // USAGE (1) @@ -121,7 +123,7 @@ int usb_init_all(void) { 0xc0 // END_COLLECTION }; static const usb_hid_info_t hid_info = { - .iface_num = 0, + .iface_num = USB_IFACE_NUM, .ep_in = USB_EP_DIR_IN | 0x01, .ep_out = USB_EP_DIR_OUT | 0x01, .subclass = 0, @@ -146,41 +148,6 @@ int usb_init_all(void) { return 0; } -#define UPLOAD_CHUNK_SIZE (128*1024) -#define USB_PACKET_SIZE 64 -#define USB_IFACE_NUM 0 - -void process_upload_chunk(const uint8_t *buf, uint32_t len) -{ - // TODO: write to flash -} - -uint32_t process_upload_message(uint32_t msg_size, const uint8_t *initbuf, uint32_t initlen) -{ - int remains = msg_size - initlen; - // TODO: process initbuf - - if (initbuf[0] != 0x0A) { - return 0; // ERROR - payload field not found - } - uint32_t payload_len; - uint32_t p = pb_read_varint(initbuf, &payload_len); - process_upload_chunk(initbuf + p, initlen - p); - - uint8_t buf[USB_PACKET_SIZE]; - while (remains > 0) { - int r = usb_hid_read_blocking(USB_IFACE_NUM, buf, USB_PACKET_SIZE, 100); - if (r <= 0) { - continue; - } - assert(r == USB_PACKET_SIZE); - process_upload_chunk(buf, 63); - remains -= USB_PACKET_SIZE; - } - display_printf("done\n"); - return 0; // should return >0 if more data required -} - void mainloop(void) { if (0 != flash_init()) { @@ -194,6 +161,7 @@ void mainloop(void) uint8_t buf[USB_PACKET_SIZE]; for (;;) { + display_printf("Waiting for message ...\n"); int r = usb_hid_read_blocking(USB_IFACE_NUM, buf, USB_PACKET_SIZE, 100); if (r <= 0) { continue; @@ -201,35 +169,30 @@ void mainloop(void) assert(r == USB_PACKET_SIZE); uint16_t msg_id; uint32_t msg_size; - // invalid header - if (!pb_parse_header(buf, &msg_id, &msg_size)) { + if (!msg_parse_header(buf, &msg_id, &msg_size)) { + // invalid header -> discard continue; } switch (msg_id) { case 0: // Initialize display_printf("received Initialize\n"); - send_msg_Features(USB_IFACE_NUM, false); + process_msg_Initialize(USB_IFACE_NUM); break; case 1: // Ping display_printf("received Ping\n"); - send_msg_Success(USB_IFACE_NUM); + process_msg_Ping(USB_IFACE_NUM); break; case 6: // FirmwareErase display_printf("received FirmwareErase\n"); - send_msg_FirmwareRequest(USB_IFACE_NUM, 0, UPLOAD_CHUNK_SIZE); + process_msg_FirmwareErase(USB_IFACE_NUM); break; case 7: // FirmwareUpload display_printf("received FirmwareUpload\n"); - uint32_t req_offset = process_upload_message(msg_size, buf + PB_HEADER_LEN, USB_PACKET_SIZE - PB_HEADER_LEN); - if (req_offset > 0) { - send_msg_FirmwareRequest(USB_IFACE_NUM, req_offset, UPLOAD_CHUNK_SIZE); - } else { - send_msg_Success(USB_IFACE_NUM); - } + process_msg_FirmwareUpload(USB_IFACE_NUM); break; default: display_printf("received unknown message\n"); - send_msg_Failure(USB_IFACE_NUM); + process_msg_unknown(USB_IFACE_NUM); break; } } @@ -254,7 +217,12 @@ int main(void) display_printf("=================\n"); display_printf("starting bootloader\n"); - if (touch_read() != 0) { + uint32_t touched = 0; + for (int i = 0; i < 10; i++) { + touched |= touch_read(); + } + + if (touched != 0) { mainloop(); } else { check_and_jump(); diff --git a/micropython/bootloader/messages.c b/micropython/bootloader/messages.c index 247ac8e23..2e40d04f9 100644 --- a/micropython/bootloader/messages.c +++ b/micropython/bootloader/messages.c @@ -1,62 +1,115 @@ -#include -#include +#include +#include "messages.pb.h" #include "usb.h" #include "version.h" -#include "protobuf.h" #include "messages.h" -void send_msg_Success(int iface) +#define UPLOAD_CHUNK_SIZE (128*1024) + +// DECODE + +bool msg_parse_header(const uint8_t *buf, uint16_t *msg_id, uint32_t *msg_size) { - // response: Success message (id 2), payload len 0 - PB_CTX ctx; - pb_start(&ctx, 2); - pb_end(&ctx); - usb_hid_write_blocking(iface, ctx.buf, ctx.pos, 1); + if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { + return false; + } + *msg_id = (buf[3] << 8) + buf[4]; + *msg_size = (buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; + return true; } -void send_msg_Failure(int iface) +// ENCODE + +bool _encode_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) { - // response: Failure message (id 3), payload len 2 - // - code = 99 (Failure_FirmwareError) - PB_CTX ctx; - pb_start(&ctx, 3); - pb_add_varint(&ctx, 1, 99); - pb_end(&ctx); - usb_hid_write_blocking(iface, ctx.buf, ctx.pos, 1); + if (!pb_encode_tag_for_field(stream, field)) { + return false; + } + return pb_encode_string(stream, *arg, strlen(*arg)); } -void send_msg_Features(int iface, bool firmware_present) +bool _send_msg(uint8_t iface_num, uint16_t msg_id, const pb_field_t fields[], const void *msg) { - // response: Features message (id 17), payload len 22 - // - vendor = "trezor.io" - // - major_version = VERSION_MAJOR - // - minor_version = VERSION_MINOR - // - patch_version = VERSION_PATCH - // - bootloader_mode = True - // - firmware_present = True/False - PB_CTX ctx; - pb_start(&ctx, 17); - pb_add_string(&ctx, 1, "trezor.io"); - pb_add_varint(&ctx, 2, VERSION_MAJOR); - pb_add_varint(&ctx, 3, VERSION_MINOR); - pb_add_varint(&ctx, 4, VERSION_PATCH); - pb_add_bool(&ctx, 5, true); - pb_add_bool(&ctx, 18, firmware_present); - pb_end(&ctx); - usb_hid_write_blocking(iface, ctx.buf, ctx.pos, 1); + // determine message size by serializing it into dummy stream + pb_ostream_t sizestream = {0, 0, SIZE_MAX, 0, 0}; + if (!pb_encode(&sizestream, fields, msg)) { + return false; + } + + // TODO: properly send + + uint8_t buf[64]; + + buf[0] = '?'; + buf[1] = '#'; + buf[2] = '#'; + buf[3] = (msg_id >> 8) & 0xFF; + buf[4] = msg_id & 0xFF; + buf[5] = (sizestream.bytes_written >> 24) & 0xFF; + buf[6] = (sizestream.bytes_written >> 16) & 0xFF; + buf[7] = (sizestream.bytes_written >> 8) & 0xFF; + buf[8] = sizestream.bytes_written & 0xFF; + + pb_ostream_t stream = pb_ostream_from_buffer(buf + MSG_HEADER_LEN, sizeof(buf) - MSG_HEADER_LEN); + if (!pb_encode(&stream, fields, msg)) { + return false; + } + + usb_hid_write_blocking(iface_num, buf, 64, 1); + + return true; } -void send_msg_FirmwareRequest(int iface, uint32_t offset, uint32_t length) +#define MSG_INIT(TYPE) TYPE msg = TYPE##_init_default +#define MSG_ASSIGN_VALUE(FIELD, VALUE) do { msg.has_##FIELD = true; msg.FIELD = VALUE; } while (0) +#define MSG_ASSIGN_STRING(FIELD, VALUE) do { msg.FIELD.funcs.encode = &_encode_string; msg.FIELD.arg = VALUE; } while (0) +#define MSG_SEND(TYPE) do { _send_msg(iface_num, MessageType_MessageType_##TYPE, TYPE##_fields, &msg); } while (0) + +void process_msg_Initialize(uint8_t iface_num) { - // response: FirmwareRequest message (id 8), payload len X - // - offset = offset - // - length = length - PB_CTX ctx; - pb_start(&ctx, 8); - pb_add_varint(&ctx, 1, offset); - pb_add_varint(&ctx, 2, length); - pb_end(&ctx); - usb_hid_write_blocking(iface, ctx.buf, ctx.pos, 1); + MSG_INIT(Features); + MSG_ASSIGN_STRING(vendor, "trezor.io"); + MSG_ASSIGN_VALUE(major_version, VERSION_MAJOR); + MSG_ASSIGN_VALUE(minor_version, VERSION_MINOR); + MSG_ASSIGN_VALUE(patch_version, VERSION_PATCH); + MSG_ASSIGN_VALUE(bootloader_mode, true); + // TODO: properly detect firmware + MSG_ASSIGN_VALUE(firmware_present, false); + MSG_SEND(Features); +} + +void process_msg_Ping(uint8_t iface_num) +{ + MSG_INIT(Success); + // TODO: read message from Ping + MSG_ASSIGN_STRING(message, "PONG!"); + MSG_SEND(Success); +} + +void process_msg_FirmwareErase(uint8_t iface_num) +{ + // TODO: implement + MSG_INIT(Failure); + MSG_ASSIGN_VALUE(code, FailureType_Failure_FirmwareError); + MSG_ASSIGN_STRING(message, "Unsupported message"); + MSG_SEND(Failure); +} + +void process_msg_FirmwareUpload(uint8_t iface_num) +{ + // TODO: implement + MSG_INIT(Failure); + MSG_ASSIGN_VALUE(code, FailureType_Failure_FirmwareError); + MSG_ASSIGN_STRING(message, "Unsupported message"); + MSG_SEND(Failure); +} + +void process_msg_unknown(uint8_t iface_num) +{ + MSG_INIT(Failure); + MSG_ASSIGN_VALUE(code, FailureType_Failure_UnexpectedMessage); + MSG_ASSIGN_STRING(message, "Unexpected message"); + MSG_SEND(Failure); } diff --git a/micropython/bootloader/messages.h b/micropython/bootloader/messages.h index 6e2cb3f9c..1ba6d7b31 100644 --- a/micropython/bootloader/messages.h +++ b/micropython/bootloader/messages.h @@ -1,12 +1,19 @@ #ifndef __MESSAGES_H__ #define __MESSAGES_H__ -#include #include +#include -void send_msg_Success(int iface); -void send_msg_Failure(int iface); -void send_msg_Features(int iface, bool firmware_present); -void send_msg_FirmwareRequest(int iface, uint32_t offset, uint32_t length); +#include + +#define MSG_HEADER_LEN 9 + +bool msg_parse_header(const uint8_t *buf, uint16_t *msg_id, uint32_t *msg_size); + +void process_msg_Initialize(uint8_t iface_num); +void process_msg_Ping(uint8_t iface_num); +void process_msg_FirmwareErase(uint8_t iface_num); +void process_msg_FirmwareUpload(uint8_t iface_num); +void process_msg_unknown(uint8_t iface_num); #endif diff --git a/micropython/bootloader/nanopb/pb.h b/micropython/bootloader/nanopb/pb.h new file mode 100644 index 000000000..bf05a63c7 --- /dev/null +++ b/micropython/bootloader/nanopb/pb.h @@ -0,0 +1,583 @@ +/* Common parts of the nanopb library. Most of these are quite low-level + * stuff. For the high-level interface, see pb_encode.h and pb_decode.h. + */ + +#ifndef PB_H_INCLUDED +#define PB_H_INCLUDED + +/***************************************************************** + * Nanopb compilation time options. You can change these here by * + * uncommenting the lines, or on the compiler command line. * + *****************************************************************/ + +/* Enable support for dynamically allocated fields */ +/* #define PB_ENABLE_MALLOC 1 */ + +/* Define this if your CPU / compiler combination does not support + * unaligned memory access to packed structures. */ +/* #define PB_NO_PACKED_STRUCTS 1 */ + +/* Increase the number of required fields that are tracked. + * A compiler warning will tell if you need this. */ +/* #define PB_MAX_REQUIRED_FIELDS 256 */ + +/* Add support for tag numbers > 255 and fields larger than 255 bytes. */ +/* #define PB_FIELD_16BIT 1 */ + +/* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */ +/* #define PB_FIELD_32BIT 1 */ + +/* Disable support for error messages in order to save some code space. */ +/* #define PB_NO_ERRMSG 1 */ + +/* Disable support for custom streams (support only memory buffers). */ +/* #define PB_BUFFER_ONLY 1 */ + +/* Switch back to the old-style callback function signature. + * This was the default until nanopb-0.2.1. */ +/* #define PB_OLD_CALLBACK_STYLE */ + + +/****************************************************************** + * You usually don't need to change anything below this line. * + * Feel free to look around and use the defined macros, though. * + ******************************************************************/ + + +/* Version of the nanopb library. Just in case you want to check it in + * your own program. */ +#define NANOPB_VERSION nanopb-0.3.8 + +/* Include all the system headers needed by nanopb. You will need the + * definitions of the following: + * - strlen, memcpy, memset functions + * - [u]int_least8_t, uint_fast8_t, [u]int_least16_t, [u]int32_t, [u]int64_t + * - size_t + * - bool + * + * If you don't have the standard header files, you can instead provide + * a custom header that defines or includes all this. In that case, + * define PB_SYSTEM_HEADER to the path of this file. + */ +#ifdef PB_SYSTEM_HEADER +#include PB_SYSTEM_HEADER +#else +#include +#include +#include +#include + +#ifdef PB_ENABLE_MALLOC +#include +#endif +#endif + +/* Macro for defining packed structures (compiler dependent). + * This just reduces memory requirements, but is not required. + */ +#if defined(PB_NO_PACKED_STRUCTS) + /* Disable struct packing */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed +#elif defined(__GNUC__) || defined(__clang__) + /* For GCC and clang */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed __attribute__((packed)) +#elif defined(__ICCARM__) || defined(__CC_ARM) + /* For IAR ARM and Keil MDK-ARM compilers */ +# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)") +# define PB_PACKED_STRUCT_END _Pragma("pack(pop)") +# define pb_packed +#elif defined(_MSC_VER) && (_MSC_VER >= 1500) + /* For Microsoft Visual C++ */ +# define PB_PACKED_STRUCT_START __pragma(pack(push, 1)) +# define PB_PACKED_STRUCT_END __pragma(pack(pop)) +# define pb_packed +#else + /* Unknown compiler */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed +#endif + +/* Handly macro for suppressing unreferenced-parameter compiler warnings. */ +#ifndef PB_UNUSED +#define PB_UNUSED(x) (void)(x) +#endif + +/* Compile-time assertion, used for checking compatible compilation options. + * If this does not work properly on your compiler, use + * #define PB_NO_STATIC_ASSERT to disable it. + * + * But before doing that, check carefully the error message / place where it + * comes from to see if the error has a real cause. Unfortunately the error + * message is not always very clear to read, but you can see the reason better + * in the place where the PB_STATIC_ASSERT macro was called. + */ +#ifndef PB_NO_STATIC_ASSERT +#ifndef PB_STATIC_ASSERT +#define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; +#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) +#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##LINE##COUNTER +#endif +#else +#define PB_STATIC_ASSERT(COND,MSG) +#endif + +/* Number of required fields to keep track of. */ +#ifndef PB_MAX_REQUIRED_FIELDS +#define PB_MAX_REQUIRED_FIELDS 64 +#endif + +#if PB_MAX_REQUIRED_FIELDS < 64 +#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64). +#endif + +/* List of possible field types. These are used in the autogenerated code. + * Least-significant 4 bits tell the scalar type + * Most-significant 4 bits specify repeated/required/packed etc. + */ + +typedef uint_least8_t pb_type_t; + +/**** Field data types ****/ + +/* Numeric types */ +#define PB_LTYPE_VARINT 0x00 /* int32, int64, enum, bool */ +#define PB_LTYPE_UVARINT 0x01 /* uint32, uint64 */ +#define PB_LTYPE_SVARINT 0x02 /* sint32, sint64 */ +#define PB_LTYPE_FIXED32 0x03 /* fixed32, sfixed32, float */ +#define PB_LTYPE_FIXED64 0x04 /* fixed64, sfixed64, double */ + +/* Marker for last packable field type. */ +#define PB_LTYPE_LAST_PACKABLE 0x04 + +/* Byte array with pre-allocated buffer. + * data_size is the length of the allocated PB_BYTES_ARRAY structure. */ +#define PB_LTYPE_BYTES 0x05 + +/* String with pre-allocated buffer. + * data_size is the maximum length. */ +#define PB_LTYPE_STRING 0x06 + +/* Submessage + * submsg_fields is pointer to field descriptions */ +#define PB_LTYPE_SUBMESSAGE 0x07 + +/* Extension pseudo-field + * The field contains a pointer to pb_extension_t */ +#define PB_LTYPE_EXTENSION 0x08 + +/* Byte array with inline, pre-allocated byffer. + * data_size is the length of the inline, allocated buffer. + * This differs from PB_LTYPE_BYTES by defining the element as + * pb_byte_t[data_size] rather than pb_bytes_array_t. */ +#define PB_LTYPE_FIXED_LENGTH_BYTES 0x09 + +/* Number of declared LTYPES */ +#define PB_LTYPES_COUNT 0x0A +#define PB_LTYPE_MASK 0x0F + +/**** Field repetition rules ****/ + +#define PB_HTYPE_REQUIRED 0x00 +#define PB_HTYPE_OPTIONAL 0x10 +#define PB_HTYPE_REPEATED 0x20 +#define PB_HTYPE_ONEOF 0x30 +#define PB_HTYPE_MASK 0x30 + +/**** Field allocation types ****/ + +#define PB_ATYPE_STATIC 0x00 +#define PB_ATYPE_POINTER 0x80 +#define PB_ATYPE_CALLBACK 0x40 +#define PB_ATYPE_MASK 0xC0 + +#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK) +#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK) +#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK) + +/* Data type used for storing sizes of struct fields + * and array counts. + */ +#if defined(PB_FIELD_32BIT) + typedef uint32_t pb_size_t; + typedef int32_t pb_ssize_t; +#elif defined(PB_FIELD_16BIT) + typedef uint_least16_t pb_size_t; + typedef int_least16_t pb_ssize_t; +#else + typedef uint_least8_t pb_size_t; + typedef int_least8_t pb_ssize_t; +#endif +#define PB_SIZE_MAX ((pb_size_t)-1) + +/* Data type for storing encoded data and other byte streams. + * This typedef exists to support platforms where uint8_t does not exist. + * You can regard it as equivalent on uint8_t on other platforms. + */ +typedef uint_least8_t pb_byte_t; + +/* This structure is used in auto-generated constants + * to specify struct fields. + * You can change field sizes if you need structures + * larger than 256 bytes or field tags larger than 256. + * The compiler should complain if your .proto has such + * structures. Fix that by defining PB_FIELD_16BIT or + * PB_FIELD_32BIT. + */ +PB_PACKED_STRUCT_START +typedef struct pb_field_s pb_field_t; +struct pb_field_s { + pb_size_t tag; + pb_type_t type; + pb_size_t data_offset; /* Offset of field data, relative to previous field. */ + pb_ssize_t size_offset; /* Offset of array size or has-boolean, relative to data */ + pb_size_t data_size; /* Data size in bytes for a single item */ + pb_size_t array_size; /* Maximum number of entries in array */ + + /* Field definitions for submessage + * OR default value for all other non-array, non-callback types + * If null, then field will zeroed. */ + const void *ptr; +} pb_packed; +PB_PACKED_STRUCT_END + +/* Make sure that the standard integer types are of the expected sizes. + * Otherwise fixed32/fixed64 fields can break. + * + * If you get errors here, it probably means that your stdint.h is not + * correct for your platform. + */ +PB_STATIC_ASSERT(sizeof(int64_t) == 2 * sizeof(int32_t), INT64_T_WRONG_SIZE) +PB_STATIC_ASSERT(sizeof(uint64_t) == 2 * sizeof(uint32_t), UINT64_T_WRONG_SIZE) + +/* This structure is used for 'bytes' arrays. + * It has the number of bytes in the beginning, and after that an array. + * Note that actual structs used will have a different length of bytes array. + */ +#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; pb_byte_t bytes[n]; } +#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes)) + +struct pb_bytes_array_s { + pb_size_t size; + pb_byte_t bytes[1]; +}; +typedef struct pb_bytes_array_s pb_bytes_array_t; + +/* This structure is used for giving the callback function. + * It is stored in the message structure and filled in by the method that + * calls pb_decode. + * + * The decoding callback will be given a limited-length stream + * If the wire type was string, the length is the length of the string. + * If the wire type was a varint/fixed32/fixed64, the length is the length + * of the actual value. + * The function may be called multiple times (especially for repeated types, + * but also otherwise if the message happens to contain the field multiple + * times.) + * + * The encoding callback will receive the actual output stream. + * It should write all the data in one call, including the field tag and + * wire type. It can write multiple fields. + * + * The callback can be null if you want to skip a field. + */ +typedef struct pb_istream_s pb_istream_t; +typedef struct pb_ostream_s pb_ostream_t; +typedef struct pb_callback_s pb_callback_t; +struct pb_callback_s { +#ifdef PB_OLD_CALLBACK_STYLE + /* Deprecated since nanopb-0.2.1 */ + union { + bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg); + bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, const void *arg); + } funcs; +#else + /* New function signature, which allows modifying arg contents in callback. */ + union { + bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg); + bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg); + } funcs; +#endif + + /* Free arg for use by callback */ + void *arg; +}; + +/* Wire types. Library user needs these only in encoder callbacks. */ +typedef enum { + PB_WT_VARINT = 0, + PB_WT_64BIT = 1, + PB_WT_STRING = 2, + PB_WT_32BIT = 5 +} pb_wire_type_t; + +/* Structure for defining the handling of unknown/extension fields. + * Usually the pb_extension_type_t structure is automatically generated, + * while the pb_extension_t structure is created by the user. However, + * if you want to catch all unknown fields, you can also create a custom + * pb_extension_type_t with your own callback. + */ +typedef struct pb_extension_type_s pb_extension_type_t; +typedef struct pb_extension_s pb_extension_t; +struct pb_extension_type_s { + /* Called for each unknown field in the message. + * If you handle the field, read off all of its data and return true. + * If you do not handle the field, do not read anything and return true. + * If you run into an error, return false. + * Set to NULL for default handler. + */ + bool (*decode)(pb_istream_t *stream, pb_extension_t *extension, + uint32_t tag, pb_wire_type_t wire_type); + + /* Called once after all regular fields have been encoded. + * If you have something to write, do so and return true. + * If you do not have anything to write, just return true. + * If you run into an error, return false. + * Set to NULL for default handler. + */ + bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension); + + /* Free field for use by the callback. */ + const void *arg; +}; + +struct pb_extension_s { + /* Type describing the extension field. Usually you'll initialize + * this to a pointer to the automatically generated structure. */ + const pb_extension_type_t *type; + + /* Destination for the decoded data. This must match the datatype + * of the extension field. */ + void *dest; + + /* Pointer to the next extension handler, or NULL. + * If this extension does not match a field, the next handler is + * automatically called. */ + pb_extension_t *next; + + /* The decoder sets this to true if the extension was found. + * Ignored for encoding. */ + bool found; +}; + +/* Memory allocation functions to use. You can define pb_realloc and + * pb_free to custom functions if you want. */ +#ifdef PB_ENABLE_MALLOC +# ifndef pb_realloc +# define pb_realloc(ptr, size) realloc(ptr, size) +# endif +# ifndef pb_free +# define pb_free(ptr) free(ptr) +# endif +#endif + +/* This is used to inform about need to regenerate .pb.h/.pb.c files. */ +#define PB_PROTO_HEADER_VERSION 30 + +/* These macros are used to declare pb_field_t's in the constant array. */ +/* Size of a structure member, in bytes. */ +#define pb_membersize(st, m) (sizeof ((st*)0)->m) +/* Number of entries in an array. */ +#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0])) +/* Delta from start of one member to the start of another member. */ +#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2)) +/* Marks the end of the field list */ +#define PB_LAST_FIELD {0,(pb_type_t) 0,0,0,0,0,0} + +/* Macros for filling in the data_offset field */ +/* data_offset for first field in a message */ +#define PB_DATAOFFSET_FIRST(st, m1, m2) (offsetof(st, m1)) +/* data_offset for subsequent fields */ +#define PB_DATAOFFSET_OTHER(st, m1, m2) (offsetof(st, m1) - offsetof(st, m2) - pb_membersize(st, m2)) +/* data offset for subsequent fields inside an union (oneof) */ +#define PB_DATAOFFSET_UNION(st, m1, m2) (PB_SIZE_MAX) +/* Choose first/other based on m1 == m2 (deprecated, remains for backwards compatibility) */ +#define PB_DATAOFFSET_CHOOSE(st, m1, m2) (int)(offsetof(st, m1) == offsetof(st, m2) \ + ? PB_DATAOFFSET_FIRST(st, m1, m2) \ + : PB_DATAOFFSET_OTHER(st, m1, m2)) + +/* Required fields are the simplest. They just have delta (padding) from + * previous field end, and the size of the field. Pointer is used for + * submessages and default values. + */ +#define PB_REQUIRED_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Optional fields add the delta to the has_ variable. */ +#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ + fd, \ + pb_delta(st, has_ ## m, m), \ + pb_membersize(st, m), 0, ptr} + +#define PB_SINGULAR_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Repeated fields have a _count field and also the maximum number of entries. */ +#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \ + fd, \ + pb_delta(st, m ## _count, m), \ + pb_membersize(st, m[0]), \ + pb_arraysize(st, m), ptr} + +/* Allocated fields carry the size of the actual data, not the pointer */ +#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Optional fields don't need a has_ variable, as information would be redundant */ +#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Same as optional fields*/ +#define PB_SINGULAR_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Repeated fields have a _count field and a pointer to array of pointers */ +#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \ + fd, pb_delta(st, m ## _count, m), \ + pb_membersize(st, m[0]), 0, ptr} + +/* Callbacks are much like required fields except with special datatype. */ +#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_SINGULAR_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Optional extensions don't have the has_ field, as that would be redundant. + * Furthermore, the combination of OPTIONAL without has_ field is used + * for indicating proto3 style fields. Extensions exist in proto2 mode only, + * so they should be encoded according to proto2 rules. To avoid the conflict, + * extensions are marked as REQUIRED instead. + */ +#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \ + 0, \ + 0, \ + pb_membersize(st, m), 0, ptr} + +#define PB_OPTEXT_POINTER(tag, st, m, fd, ltype, ptr) \ + PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) + +#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \ + PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) + +/* The mapping from protobuf types to LTYPEs is done using these macros. */ +#define PB_LTYPE_MAP_BOOL PB_LTYPE_VARINT +#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES +#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT +#define PB_LTYPE_MAP_UENUM PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT +#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT +#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE +#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT +#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT +#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING +#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION +#define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES + +/* This is the actual macro used in field descriptions. + * It takes these arguments: + * - Field tag number + * - Field type: BOOL, BYTES, DOUBLE, ENUM, UENUM, FIXED32, FIXED64, + * FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64 + * SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION + * - Field rules: REQUIRED, OPTIONAL or REPEATED + * - Allocation: STATIC, CALLBACK or POINTER + * - Placement: FIRST or OTHER, depending on if this is the first field in structure. + * - Message name + * - Field name + * - Previous field name (or field name again for first field) + * - Pointer to default value or submsg fields. + */ + +#define PB_FIELD(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ ## rules ## _ ## allocation(tag, message, field, \ + PB_DATAOFFSET_ ## placement(message, field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +/* Field description for oneof fields. This requires taking into account the + * union name also, that's why a separate set of macros is needed. + */ +#define PB_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, u.m), \ + pb_membersize(st, u.m), 0, ptr} + +#define PB_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, u.m), \ + pb_membersize(st, u.m[0]), 0, ptr} + +#define PB_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ONEOF_ ## allocation(union_name, tag, message, field, \ + PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +#define PB_ANONYMOUS_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, m), \ + pb_membersize(st, m), 0, ptr} + +#define PB_ANONYMOUS_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, m), \ + pb_membersize(st, m[0]), 0, ptr} + +#define PB_ANONYMOUS_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ANONYMOUS_ONEOF_ ## allocation(union_name, tag, message, field, \ + PB_DATAOFFSET_ ## placement(message, field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +/* These macros are used for giving out error messages. + * They are mostly a debugging aid; the main error information + * is the true/false return value from functions. + * Some code space can be saved by disabling the error + * messages if not used. + * + * PB_SET_ERROR() sets the error message if none has been set yet. + * msg must be a constant string literal. + * PB_GET_ERROR() always returns a pointer to a string. + * PB_RETURN_ERROR() sets the error and returns false from current + * function. + */ +#ifdef PB_NO_ERRMSG +#define PB_SET_ERROR(stream, msg) PB_UNUSED(stream) +#define PB_GET_ERROR(stream) "(errmsg disabled)" +#else +#define PB_SET_ERROR(stream, msg) (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg)) +#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)") +#endif + +#define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false + +#endif diff --git a/micropython/bootloader/nanopb/pb_common.c b/micropython/bootloader/nanopb/pb_common.c new file mode 100644 index 000000000..4fb7186b7 --- /dev/null +++ b/micropython/bootloader/nanopb/pb_common.c @@ -0,0 +1,97 @@ +/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c. + * + * 2014 Petteri Aimonen + */ + +#include "pb_common.h" + +bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct) +{ + iter->start = fields; + iter->pos = fields; + iter->required_field_index = 0; + iter->dest_struct = dest_struct; + iter->pData = (char*)dest_struct + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + + return (iter->pos->tag != 0); +} + +bool pb_field_iter_next(pb_field_iter_t *iter) +{ + const pb_field_t *prev_field = iter->pos; + + if (prev_field->tag == 0) + { + /* Handle empty message types, where the first field is already the terminator. + * In other cases, the iter->pos never points to the terminator. */ + return false; + } + + iter->pos++; + + if (iter->pos->tag == 0) + { + /* Wrapped back to beginning, reinitialize */ + (void)pb_field_iter_begin(iter, iter->start, iter->dest_struct); + return false; + } + else + { + /* Increment the pointers based on previous field size */ + size_t prev_size = prev_field->data_size; + + if (PB_HTYPE(prev_field->type) == PB_HTYPE_ONEOF && + PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF && + iter->pos->data_offset == PB_SIZE_MAX) + { + /* Don't advance pointers inside unions */ + return true; + } + else if (PB_ATYPE(prev_field->type) == PB_ATYPE_STATIC && + PB_HTYPE(prev_field->type) == PB_HTYPE_REPEATED) + { + /* In static arrays, the data_size tells the size of a single entry and + * array_size is the number of entries */ + prev_size *= prev_field->array_size; + } + else if (PB_ATYPE(prev_field->type) == PB_ATYPE_POINTER) + { + /* Pointer fields always have a constant size in the main structure. + * The data_size only applies to the dynamically allocated area. */ + prev_size = sizeof(void*); + } + + if (PB_HTYPE(prev_field->type) == PB_HTYPE_REQUIRED) + { + /* Count the required fields, in order to check their presence in the + * decoder. */ + iter->required_field_index++; + } + + iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + return true; + } +} + +bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) +{ + const pb_field_t *start = iter->pos; + + do { + if (iter->pos->tag == tag && + PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) + { + /* Found the wanted field */ + return true; + } + + (void)pb_field_iter_next(iter); + } while (iter->pos != start); + + /* Searched all the way back to start, and found nothing. */ + return false; +} + + diff --git a/micropython/bootloader/nanopb/pb_common.h b/micropython/bootloader/nanopb/pb_common.h new file mode 100644 index 000000000..60b3d3749 --- /dev/null +++ b/micropython/bootloader/nanopb/pb_common.h @@ -0,0 +1,42 @@ +/* pb_common.h: Common support functions for pb_encode.c and pb_decode.c. + * These functions are rarely needed by applications directly. + */ + +#ifndef PB_COMMON_H_INCLUDED +#define PB_COMMON_H_INCLUDED + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Iterator for pb_field_t list */ +struct pb_field_iter_s { + const pb_field_t *start; /* Start of the pb_field_t array */ + const pb_field_t *pos; /* Current position of the iterator */ + unsigned required_field_index; /* Zero-based index that counts only the required fields */ + void *dest_struct; /* Pointer to start of the structure */ + void *pData; /* Pointer to current field value */ + void *pSize; /* Pointer to count/has field */ +}; +typedef struct pb_field_iter_s pb_field_iter_t; + +/* Initialize the field iterator structure to beginning. + * Returns false if the message type is empty. */ +bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct); + +/* Advance the iterator to the next field. + * Returns false when the iterator wraps back to the first field. */ +bool pb_field_iter_next(pb_field_iter_t *iter); + +/* Advance the iterator until it points at a field with the given tag. + * Returns false if no such field exists. */ +bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif + diff --git a/micropython/bootloader/nanopb/pb_decode.c b/micropython/bootloader/nanopb/pb_decode.c new file mode 100644 index 000000000..e2e90caab --- /dev/null +++ b/micropython/bootloader/nanopb/pb_decode.c @@ -0,0 +1,1379 @@ +/* pb_decode.c -- decode a protobuf using minimal resources + * + * 2011 Petteri Aimonen + */ + +/* Use the GCC warn_unused_result attribute to check that all return values + * are propagated correctly. On other compilers and gcc before 3.4.0 just + * ignore the annotation. + */ +#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) + #define checkreturn +#else + #define checkreturn __attribute__((warn_unused_result)) +#endif + +#include "pb.h" +#include "pb_decode.h" +#include "pb_common.h" + +/************************************** + * Declarations internal to this file * + **************************************/ + +typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; + +static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); +static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size); +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension); +static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); +static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn find_extension_field(pb_field_iter_t *iter); +static void pb_field_set_to_default(pb_field_iter_t *iter); +static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); +static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_skip_varint(pb_istream_t *stream); +static bool checkreturn pb_skip_string(pb_istream_t *stream); + +#ifdef PB_ENABLE_MALLOC +static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); +static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter); +static void pb_release_single_field(const pb_field_iter_t *iter); +#endif + +/* --- Function pointers to field decoders --- + * Order in the array must match pb_action_t LTYPE numbering. + */ +static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { + &pb_dec_varint, + &pb_dec_uvarint, + &pb_dec_svarint, + &pb_dec_fixed32, + &pb_dec_fixed64, + + &pb_dec_bytes, + &pb_dec_string, + &pb_dec_submessage, + NULL, /* extensions */ + &pb_dec_fixed_length_bytes +}; + +/******************************* + * pb_istream_t implementation * + *******************************/ + +static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) +{ + size_t i; + const pb_byte_t *source = (const pb_byte_t*)stream->state; + stream->state = (pb_byte_t*)stream->state + count; + + if (buf != NULL) + { + for (i = 0; i < count; i++) + buf[i] = source[i]; + } + + return true; +} + +bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) +{ +#ifndef PB_BUFFER_ONLY + if (buf == NULL && stream->callback != buf_read) + { + /* Skip input bytes */ + pb_byte_t tmp[16]; + while (count > 16) + { + if (!pb_read(stream, tmp, 16)) + return false; + + count -= 16; + } + + return pb_read(stream, tmp, count); + } +#endif + + if (stream->bytes_left < count) + PB_RETURN_ERROR(stream, "end-of-stream"); + +#ifndef PB_BUFFER_ONLY + if (!stream->callback(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#else + if (!buf_read(stream, buf, count)) + return false; +#endif + + stream->bytes_left -= count; + return true; +} + +/* Read a single byte from input stream. buf may not be NULL. + * This is an optimization for the varint decoding. */ +static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf) +{ + if (stream->bytes_left == 0) + PB_RETURN_ERROR(stream, "end-of-stream"); + +#ifndef PB_BUFFER_ONLY + if (!stream->callback(stream, buf, 1)) + PB_RETURN_ERROR(stream, "io error"); +#else + *buf = *(const pb_byte_t*)stream->state; + stream->state = (pb_byte_t*)stream->state + 1; +#endif + + stream->bytes_left--; + + return true; +} + +pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize) +{ + pb_istream_t stream; + /* Cast away the const from buf without a compiler error. We are + * careful to use it only in a const manner in the callbacks. + */ + union { + void *state; + const void *c_state; + } state; +#ifdef PB_BUFFER_ONLY + stream.callback = NULL; +#else + stream.callback = &buf_read; +#endif + state.c_state = buf; + stream.state = state.state; + stream.bytes_left = bufsize; +#ifndef PB_NO_ERRMSG + stream.errmsg = NULL; +#endif + return stream; +} + +/******************** + * Helper functions * + ********************/ + +bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) +{ + pb_byte_t byte; + uint32_t result; + + if (!pb_readbyte(stream, &byte)) + return false; + + if ((byte & 0x80) == 0) + { + /* Quick case, 1 byte value */ + result = byte; + } + else + { + /* Multibyte case */ + uint_fast8_t bitpos = 7; + result = byte & 0x7F; + + do + { + if (bitpos >= 32) + PB_RETURN_ERROR(stream, "varint overflow"); + + if (!pb_readbyte(stream, &byte)) + return false; + + result |= (uint32_t)(byte & 0x7F) << bitpos; + bitpos = (uint_fast8_t)(bitpos + 7); + } while (byte & 0x80); + } + + *dest = result; + return true; +} + +bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) +{ + pb_byte_t byte; + uint_fast8_t bitpos = 0; + uint64_t result = 0; + + do + { + if (bitpos >= 64) + PB_RETURN_ERROR(stream, "varint overflow"); + + if (!pb_readbyte(stream, &byte)) + return false; + + result |= (uint64_t)(byte & 0x7F) << bitpos; + bitpos = (uint_fast8_t)(bitpos + 7); + } while (byte & 0x80); + + *dest = result; + return true; +} + +bool checkreturn pb_skip_varint(pb_istream_t *stream) +{ + pb_byte_t byte; + do + { + if (!pb_read(stream, &byte, 1)) + return false; + } while (byte & 0x80); + return true; +} + +bool checkreturn pb_skip_string(pb_istream_t *stream) +{ + uint32_t length; + if (!pb_decode_varint32(stream, &length)) + return false; + + return pb_read(stream, NULL, length); +} + +bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) +{ + uint32_t temp; + *eof = false; + *wire_type = (pb_wire_type_t) 0; + *tag = 0; + + if (!pb_decode_varint32(stream, &temp)) + { + if (stream->bytes_left == 0) + *eof = true; + + return false; + } + + if (temp == 0) + { + *eof = true; /* Special feature: allow 0-terminated messages. */ + return false; + } + + *tag = temp >> 3; + *wire_type = (pb_wire_type_t)(temp & 7); + return true; +} + +bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) +{ + switch (wire_type) + { + case PB_WT_VARINT: return pb_skip_varint(stream); + case PB_WT_64BIT: return pb_read(stream, NULL, 8); + case PB_WT_STRING: return pb_skip_string(stream); + case PB_WT_32BIT: return pb_read(stream, NULL, 4); + default: PB_RETURN_ERROR(stream, "invalid wire_type"); + } +} + +/* Read a raw value to buffer, for the purpose of passing it to callback as + * a substream. Size is maximum size on call, and actual size on return. + */ +static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size) +{ + size_t max_size = *size; + switch (wire_type) + { + case PB_WT_VARINT: + *size = 0; + do + { + (*size)++; + if (*size > max_size) return false; + if (!pb_read(stream, buf, 1)) return false; + } while (*buf++ & 0x80); + return true; + + case PB_WT_64BIT: + *size = 8; + return pb_read(stream, buf, 8); + + case PB_WT_32BIT: + *size = 4; + return pb_read(stream, buf, 4); + + default: PB_RETURN_ERROR(stream, "invalid wire_type"); + } +} + +/* Decode string length from stream and return a substream with limited length. + * Remember to close the substream using pb_close_string_substream(). + */ +bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) +{ + uint32_t size; + if (!pb_decode_varint32(stream, &size)) + return false; + + *substream = *stream; + if (substream->bytes_left < size) + PB_RETURN_ERROR(stream, "parent stream too short"); + + substream->bytes_left = size; + stream->bytes_left -= size; + return true; +} + +bool checkreturn pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) +{ + if (substream->bytes_left) { + if (!pb_read(substream, NULL, substream->bytes_left)) + return false; + } + + stream->state = substream->state; + +#ifndef PB_NO_ERRMSG + stream->errmsg = substream->errmsg; +#endif + return true; +} + +/************************* + * Decode a single field * + *************************/ + +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ + pb_type_t type; + pb_decoder_t func; + + type = iter->pos->type; + func = PB_DECODERS[PB_LTYPE(type)]; + + switch (PB_HTYPE(type)) + { + case PB_HTYPE_REQUIRED: + return func(stream, iter->pos, iter->pData); + + case PB_HTYPE_OPTIONAL: + if (iter->pSize != iter->pData) + *(bool*)iter->pSize = true; + return func(stream, iter->pos, iter->pData); + + case PB_HTYPE_REPEATED: + if (wire_type == PB_WT_STRING + && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) + { + /* Packed array */ + bool status = true; + pb_size_t *size = (pb_size_t*)iter->pSize; + pb_istream_t substream; + if (!pb_make_string_substream(stream, &substream)) + return false; + + while (substream.bytes_left > 0 && *size < iter->pos->array_size) + { + void *pItem = (char*)iter->pData + iter->pos->data_size * (*size); + if (!func(&substream, iter->pos, pItem)) + { + status = false; + break; + } + (*size)++; + } + + if (substream.bytes_left != 0) + PB_RETURN_ERROR(stream, "array overflow"); + if (!pb_close_string_substream(stream, &substream)) + return false; + + return status; + } + else + { + /* Repeated field */ + pb_size_t *size = (pb_size_t*)iter->pSize; + void *pItem = (char*)iter->pData + iter->pos->data_size * (*size); + if (*size >= iter->pos->array_size) + PB_RETURN_ERROR(stream, "array overflow"); + + (*size)++; + return func(stream, iter->pos, pItem); + } + + case PB_HTYPE_ONEOF: + *(pb_size_t*)iter->pSize = iter->pos->tag; + if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + { + /* We memset to zero so that any callbacks are set to NULL. + * Then set any default values. */ + memset(iter->pData, 0, iter->pos->data_size); + pb_message_set_to_defaults((const pb_field_t*)iter->pos->ptr, iter->pData); + } + return func(stream, iter->pos, iter->pData); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +#ifdef PB_ENABLE_MALLOC +/* Allocate storage for the field and store the pointer at iter->pData. + * array_size is the number of entries to reserve in an array. + * Zero size is not allowed, use pb_free() for releasing. + */ +static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) +{ + void *ptr = *(void**)pData; + + if (data_size == 0 || array_size == 0) + PB_RETURN_ERROR(stream, "invalid size"); + + /* Check for multiplication overflows. + * This code avoids the costly division if the sizes are small enough. + * Multiplication is safe as long as only half of bits are set + * in either multiplicand. + */ + { + const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4); + if (data_size >= check_limit || array_size >= check_limit) + { + const size_t size_max = (size_t)-1; + if (size_max / array_size < data_size) + { + PB_RETURN_ERROR(stream, "size too large"); + } + } + } + + /* Allocate new or expand previous allocation */ + /* Note: on failure the old pointer will remain in the structure, + * the message must be freed by caller also on error return. */ + ptr = pb_realloc(ptr, array_size * data_size); + if (ptr == NULL) + PB_RETURN_ERROR(stream, "realloc failed"); + + *(void**)pData = ptr; + return true; +} + +/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ +static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter) +{ + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || + PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) + { + *(void**)pItem = NULL; + } + else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) + { + pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem); + } +} +#endif + +static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ +#ifndef PB_ENABLE_MALLOC + PB_UNUSED(wire_type); + PB_UNUSED(iter); + PB_RETURN_ERROR(stream, "no malloc support"); +#else + pb_type_t type; + pb_decoder_t func; + + type = iter->pos->type; + func = PB_DECODERS[PB_LTYPE(type)]; + + switch (PB_HTYPE(type)) + { + case PB_HTYPE_REQUIRED: + case PB_HTYPE_OPTIONAL: + case PB_HTYPE_ONEOF: + if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && + *(void**)iter->pData != NULL) + { + /* Duplicate field, have to release the old allocation first. */ + pb_release_single_field(iter); + } + + if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + *(pb_size_t*)iter->pSize = iter->pos->tag; + } + + if (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES) + { + return func(stream, iter->pos, iter->pData); + } + else + { + if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1)) + return false; + + initialize_pointer_field(*(void**)iter->pData, iter); + return func(stream, iter->pos, *(void**)iter->pData); + } + + case PB_HTYPE_REPEATED: + if (wire_type == PB_WT_STRING + && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) + { + /* Packed array, multiple items come in at once. */ + bool status = true; + pb_size_t *size = (pb_size_t*)iter->pSize; + size_t allocated_size = *size; + void *pItem; + pb_istream_t substream; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + while (substream.bytes_left) + { + if ((size_t)*size + 1 > allocated_size) + { + /* Allocate more storage. This tries to guess the + * number of remaining entries. Round the division + * upwards. */ + allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1; + + if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size)) + { + status = false; + break; + } + } + + /* Decode the array entry */ + pItem = *(char**)iter->pData + iter->pos->data_size * (*size); + initialize_pointer_field(pItem, iter); + if (!func(&substream, iter->pos, pItem)) + { + status = false; + break; + } + + if (*size == PB_SIZE_MAX) + { +#ifndef PB_NO_ERRMSG + stream->errmsg = "too many array entries"; +#endif + status = false; + break; + } + + (*size)++; + } + if (!pb_close_string_substream(stream, &substream)) + return false; + + return status; + } + else + { + /* Normal repeated field, i.e. only one item at a time. */ + pb_size_t *size = (pb_size_t*)iter->pSize; + void *pItem; + + if (*size == PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "too many array entries"); + + (*size)++; + if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size)) + return false; + + pItem = *(char**)iter->pData + iter->pos->data_size * (*size - 1); + initialize_pointer_field(pItem, iter); + return func(stream, iter->pos, pItem); + } + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +#endif +} + +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ + pb_callback_t *pCallback = (pb_callback_t*)iter->pData; + +#ifdef PB_OLD_CALLBACK_STYLE + void *arg = pCallback->arg; +#else + void **arg = &(pCallback->arg); +#endif + + if (pCallback->funcs.decode == NULL) + return pb_skip_field(stream, wire_type); + + if (wire_type == PB_WT_STRING) + { + pb_istream_t substream; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + do + { + if (!pCallback->funcs.decode(&substream, iter->pos, arg)) + PB_RETURN_ERROR(stream, "callback failed"); + } while (substream.bytes_left); + + if (!pb_close_string_substream(stream, &substream)) + return false; + + return true; + } + else + { + /* Copy the single scalar value to stack. + * This is required so that we can limit the stream length, + * which in turn allows to use same callback for packed and + * not-packed fields. */ + pb_istream_t substream; + pb_byte_t buffer[10]; + size_t size = sizeof(buffer); + + if (!read_raw_value(stream, wire_type, buffer, &size)) + return false; + substream = pb_istream_from_buffer(buffer, size); + + return pCallback->funcs.decode(&substream, iter->pos, arg); + } +} + +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ +#ifdef PB_ENABLE_MALLOC + /* When decoding an oneof field, check if there is old data that must be + * released first. */ + if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF) + { + if (!pb_release_union_field(stream, iter)) + return false; + } +#endif + + switch (PB_ATYPE(iter->pos->type)) + { + case PB_ATYPE_STATIC: + return decode_static_field(stream, wire_type, iter); + + case PB_ATYPE_POINTER: + return decode_pointer_field(stream, wire_type, iter); + + case PB_ATYPE_CALLBACK: + return decode_callback_field(stream, wire_type, iter); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension) +{ + /* Fake a field iterator for the extension field. + * It is not actually safe to advance this iterator, but decode_field + * will not even try to. */ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + (void)pb_field_iter_begin(iter, field, extension->dest); + iter->pData = extension->dest; + iter->pSize = &extension->found; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { + /* For pointer extensions, the pointer is stored directly + * in the extension structure. This avoids having an extra + * indirection. */ + iter->pData = &extension->dest; + } +} + +/* Default handler for extension fields. Expects a pb_field_t structure + * in extension->type->arg. */ +static bool checkreturn default_extension_decoder(pb_istream_t *stream, + pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) +{ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + pb_field_iter_t iter; + + if (field->tag != tag) + return true; + + iter_from_extension(&iter, extension); + extension->found = true; + return decode_field(stream, wire_type, &iter); +} + +/* Try to decode an unknown field as an extension field. Tries each extension + * decoder in turn, until one of them handles the field or loop ends. */ +static bool checkreturn decode_extension(pb_istream_t *stream, + uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ + pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; + size_t pos = stream->bytes_left; + + while (extension != NULL && pos == stream->bytes_left) + { + bool status; + if (extension->type->decode) + status = extension->type->decode(stream, extension, tag, wire_type); + else + status = default_extension_decoder(stream, extension, tag, wire_type); + + if (!status) + return false; + + extension = extension->next; + } + + return true; +} + +/* Step through the iterator until an extension field is found or until all + * entries have been checked. There can be only one extension field per + * message. Returns false if no extension field is found. */ +static bool checkreturn find_extension_field(pb_field_iter_t *iter) +{ + const pb_field_t *start = iter->pos; + + do { + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) + return true; + (void)pb_field_iter_next(iter); + } while (iter->pos != start); + + return false; +} + +/* Initialize message fields to default values, recursively */ +static void pb_field_set_to_default(pb_field_iter_t *iter) +{ + pb_type_t type; + type = iter->pos->type; + + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) + { + pb_extension_t *ext = *(pb_extension_t* const *)iter->pData; + while (ext != NULL) + { + pb_field_iter_t ext_iter; + ext->found = false; + iter_from_extension(&ext_iter, ext); + pb_field_set_to_default(&ext_iter); + ext = ext->next; + } + } + else if (PB_ATYPE(type) == PB_ATYPE_STATIC) + { + bool init_data = true; + if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && iter->pSize != iter->pData) + { + /* Set has_field to false. Still initialize the optional field + * itself also. */ + *(bool*)iter->pSize = false; + } + else if (PB_HTYPE(type) == PB_HTYPE_REPEATED || + PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + /* REPEATED: Set array count to 0, no need to initialize contents. + ONEOF: Set which_field to 0. */ + *(pb_size_t*)iter->pSize = 0; + init_data = false; + } + + if (init_data) + { + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) + { + /* Initialize submessage to defaults */ + pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, iter->pData); + } + else if (iter->pos->ptr != NULL) + { + /* Initialize to default value */ + memcpy(iter->pData, iter->pos->ptr, iter->pos->data_size); + } + else + { + /* Initialize to zeros */ + memset(iter->pData, 0, iter->pos->data_size); + } + } + } + else if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + /* Initialize the pointer to NULL. */ + *(void**)iter->pData = NULL; + + /* Initialize array count to 0. */ + if (PB_HTYPE(type) == PB_HTYPE_REPEATED || + PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + *(pb_size_t*)iter->pSize = 0; + } + } + else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) + { + /* Don't overwrite callback */ + } +} + +static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) +{ + pb_field_iter_t iter; + + if (!pb_field_iter_begin(&iter, fields, dest_struct)) + return; /* Empty message type */ + + do + { + pb_field_set_to_default(&iter); + } while (pb_field_iter_next(&iter)); +} + +/********************* + * Decode all fields * + *********************/ + +bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + uint32_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 31) / 32] = {0, 0}; + const uint32_t allbits = ~(uint32_t)0; + uint32_t extension_range_start = 0; + pb_field_iter_t iter; + + /* Return value ignored, as empty message types will be correctly handled by + * pb_field_iter_find() anyway. */ + (void)pb_field_iter_begin(&iter, fields, dest_struct); + + while (stream->bytes_left) + { + uint32_t tag; + pb_wire_type_t wire_type; + bool eof; + + if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) + { + if (eof) + break; + else + return false; + } + + if (!pb_field_iter_find(&iter, tag)) + { + /* No match found, check if it matches an extension. */ + if (tag >= extension_range_start) + { + if (!find_extension_field(&iter)) + extension_range_start = (uint32_t)-1; + else + extension_range_start = iter.pos->tag; + + if (tag >= extension_range_start) + { + size_t pos = stream->bytes_left; + + if (!decode_extension(stream, tag, wire_type, &iter)) + return false; + + if (pos != stream->bytes_left) + { + /* The field was handled */ + continue; + } + } + } + + /* No match found, skip data */ + if (!pb_skip_field(stream, wire_type)) + return false; + continue; + } + + if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED + && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) + { + uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31)); + fields_seen[iter.required_field_index >> 5] |= tmp; + } + + if (!decode_field(stream, wire_type, &iter)) + return false; + } + + /* Check that all required fields were present. */ + { + /* First figure out the number of required fields by + * seeking to the end of the field array. Usually we + * are already close to end after decoding. + */ + unsigned req_field_count; + pb_type_t last_type; + unsigned i; + do { + req_field_count = iter.required_field_index; + last_type = iter.pos->type; + } while (pb_field_iter_next(&iter)); + + /* Fixup if last field was also required. */ + if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) + req_field_count++; + + if (req_field_count > 0) + { + /* Check the whole words */ + for (i = 0; i < (req_field_count >> 5); i++) + { + if (fields_seen[i] != allbits) + PB_RETURN_ERROR(stream, "missing required field"); + } + + /* Check the remaining bits */ + if (fields_seen[req_field_count >> 5] != (allbits >> (32 - (req_field_count & 31)))) + PB_RETURN_ERROR(stream, "missing required field"); + } + } + + return true; +} + +bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + bool status; + pb_message_set_to_defaults(fields, dest_struct); + status = pb_decode_noinit(stream, fields, dest_struct); + +#ifdef PB_ENABLE_MALLOC + if (!status) + pb_release(fields, dest_struct); +#endif + + return status; +} + +bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + pb_istream_t substream; + bool status; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + status = pb_decode(&substream, fields, dest_struct); + + if (!pb_close_string_substream(stream, &substream)) + return false; + return status; +} + +#ifdef PB_ENABLE_MALLOC +/* Given an oneof field, if there has already been a field inside this oneof, + * release it before overwriting with a different one. */ +static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter) +{ + pb_size_t old_tag = *(pb_size_t*)iter->pSize; /* Previous which_ value */ + pb_size_t new_tag = iter->pos->tag; /* New which_ value */ + + if (old_tag == 0) + return true; /* Ok, no old data in union */ + + if (old_tag == new_tag) + return true; /* Ok, old data is of same type => merge */ + + /* Release old data. The find can fail if the message struct contains + * invalid data. */ + if (!pb_field_iter_find(iter, old_tag)) + PB_RETURN_ERROR(stream, "invalid union tag"); + + pb_release_single_field(iter); + + /* Restore iterator to where it should be. + * This shouldn't fail unless the pb_field_t structure is corrupted. */ + if (!pb_field_iter_find(iter, new_tag)) + PB_RETURN_ERROR(stream, "iterator error"); + + return true; +} + +static void pb_release_single_field(const pb_field_iter_t *iter) +{ + pb_type_t type; + type = iter->pos->type; + + if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + if (*(pb_size_t*)iter->pSize != iter->pos->tag) + return; /* This is not the current field in the union */ + } + + /* Release anything contained inside an extension or submsg. + * This has to be done even if the submsg itself is statically + * allocated. */ + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) + { + /* Release fields from all extensions in the linked list */ + pb_extension_t *ext = *(pb_extension_t**)iter->pData; + while (ext != NULL) + { + pb_field_iter_t ext_iter; + iter_from_extension(&ext_iter, ext); + pb_release_single_field(&ext_iter); + ext = ext->next; + } + } + else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + { + /* Release fields in submessage or submsg array */ + void *pItem = iter->pData; + pb_size_t count = 1; + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + pItem = *(void**)iter->pData; + } + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + count = *(pb_size_t*)iter->pSize; + + if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size) + { + /* Protect against corrupted _count fields */ + count = iter->pos->array_size; + } + } + + if (pItem) + { + while (count--) + { + pb_release((const pb_field_t*)iter->pos->ptr, pItem); + pItem = (char*)pItem + iter->pos->data_size; + } + } + } + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + if (PB_HTYPE(type) == PB_HTYPE_REPEATED && + (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES)) + { + /* Release entries in repeated string or bytes array */ + void **pItem = *(void***)iter->pData; + pb_size_t count = *(pb_size_t*)iter->pSize; + while (count--) + { + pb_free(*pItem); + *pItem++ = NULL; + } + } + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + /* We are going to release the array, so set the size to 0 */ + *(pb_size_t*)iter->pSize = 0; + } + + /* Release main item */ + pb_free(*(void**)iter->pData); + *(void**)iter->pData = NULL; + } +} + +void pb_release(const pb_field_t fields[], void *dest_struct) +{ + pb_field_iter_t iter; + + if (!dest_struct) + return; /* Ignore NULL pointers, similar to free() */ + + if (!pb_field_iter_begin(&iter, fields, dest_struct)) + return; /* Empty message type */ + + do + { + pb_release_single_field(&iter); + } while (pb_field_iter_next(&iter)); +} +#endif + +/* Field decoders */ + +bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest) +{ + uint64_t value; + if (!pb_decode_varint(stream, &value)) + return false; + + if (value & 1) + *dest = (int64_t)(~(value >> 1)); + else + *dest = (int64_t)(value >> 1); + + return true; +} + +bool pb_decode_fixed32(pb_istream_t *stream, void *dest) +{ + pb_byte_t bytes[4]; + + if (!pb_read(stream, bytes, 4)) + return false; + + *(uint32_t*)dest = ((uint32_t)bytes[0] << 0) | + ((uint32_t)bytes[1] << 8) | + ((uint32_t)bytes[2] << 16) | + ((uint32_t)bytes[3] << 24); + return true; +} + +bool pb_decode_fixed64(pb_istream_t *stream, void *dest) +{ + pb_byte_t bytes[8]; + + if (!pb_read(stream, bytes, 8)) + return false; + + *(uint64_t*)dest = ((uint64_t)bytes[0] << 0) | + ((uint64_t)bytes[1] << 8) | + ((uint64_t)bytes[2] << 16) | + ((uint64_t)bytes[3] << 24) | + ((uint64_t)bytes[4] << 32) | + ((uint64_t)bytes[5] << 40) | + ((uint64_t)bytes[6] << 48) | + ((uint64_t)bytes[7] << 56); + + return true; +} + +static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint64_t value; + int64_t svalue; + int64_t clamped; + if (!pb_decode_varint(stream, &value)) + return false; + + /* See issue 97: Google's C++ protobuf allows negative varint values to + * be cast as int32_t, instead of the int64_t that should be used when + * encoding. Previous nanopb versions had a bug in encoding. In order to + * not break decoding of such messages, we cast <=32 bit fields to + * int32_t first to get the sign correct. + */ + if (field->data_size == sizeof(int64_t)) + svalue = (int64_t)value; + else + svalue = (int32_t)value; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(int64_t)) + clamped = *(int64_t*)dest = svalue; + else if (field->data_size == sizeof(int32_t)) + clamped = *(int32_t*)dest = (int32_t)svalue; + else if (field->data_size == sizeof(int_least16_t)) + clamped = *(int_least16_t*)dest = (int_least16_t)svalue; + else if (field->data_size == sizeof(int_least8_t)) + clamped = *(int_least8_t*)dest = (int_least8_t)svalue; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != svalue) + PB_RETURN_ERROR(stream, "integer too large"); + + return true; +} + +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint64_t value, clamped; + if (!pb_decode_varint(stream, &value)) + return false; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(uint64_t)) + clamped = *(uint64_t*)dest = value; + else if (field->data_size == sizeof(uint32_t)) + clamped = *(uint32_t*)dest = (uint32_t)value; + else if (field->data_size == sizeof(uint_least16_t)) + clamped = *(uint_least16_t*)dest = (uint_least16_t)value; + else if (field->data_size == sizeof(uint_least8_t)) + clamped = *(uint_least8_t*)dest = (uint_least8_t)value; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != value) + PB_RETURN_ERROR(stream, "integer too large"); + + return true; +} + +static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + int64_t value, clamped; + if (!pb_decode_svarint(stream, &value)) + return false; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(int64_t)) + clamped = *(int64_t*)dest = value; + else if (field->data_size == sizeof(int32_t)) + clamped = *(int32_t*)dest = (int32_t)value; + else if (field->data_size == sizeof(int_least16_t)) + clamped = *(int_least16_t*)dest = (int_least16_t)value; + else if (field->data_size == sizeof(int_least8_t)) + clamped = *(int_least8_t*)dest = (int_least8_t)value; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != value) + PB_RETURN_ERROR(stream, "integer too large"); + + return true; +} + +static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + PB_UNUSED(field); + return pb_decode_fixed32(stream, dest); +} + +static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + PB_UNUSED(field); + return pb_decode_fixed64(stream, dest); +} + +static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + size_t alloc_size; + pb_bytes_array_t *bdest; + + if (!pb_decode_varint32(stream, &size)) + return false; + + if (size > PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "bytes overflow"); + + alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size); + if (size > alloc_size) + PB_RETURN_ERROR(stream, "size too large"); + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (!allocate_field(stream, dest, alloc_size, 1)) + return false; + bdest = *(pb_bytes_array_t**)dest; +#endif + } + else + { + if (alloc_size > field->data_size) + PB_RETURN_ERROR(stream, "bytes overflow"); + bdest = (pb_bytes_array_t*)dest; + } + + bdest->size = (pb_size_t)size; + return pb_read(stream, bdest->bytes, size); +} + +static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + size_t alloc_size; + bool status; + if (!pb_decode_varint32(stream, &size)) + return false; + + /* Space for null terminator */ + alloc_size = size + 1; + + if (alloc_size < size) + PB_RETURN_ERROR(stream, "size too large"); + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (!allocate_field(stream, dest, alloc_size, 1)) + return false; + dest = *(void**)dest; +#endif + } + else + { + if (alloc_size > field->data_size) + PB_RETURN_ERROR(stream, "string overflow"); + } + + status = pb_read(stream, (pb_byte_t*)dest, size); + *((pb_byte_t*)dest + size) = 0; + return status; +} + +static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + bool status; + pb_istream_t substream; + const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + if (field->ptr == NULL) + PB_RETURN_ERROR(stream, "invalid field descriptor"); + + /* New array entries need to be initialized, while required and optional + * submessages have already been initialized in the top-level pb_decode. */ + if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) + status = pb_decode(&substream, submsg_fields, dest); + else + status = pb_decode_noinit(&substream, submsg_fields, dest); + + if (!pb_close_string_substream(stream, &substream)) + return false; + return status; +} + +static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + + if (!pb_decode_varint32(stream, &size)) + return false; + + if (size > PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "bytes overflow"); + + if (size == 0) + { + /* As a special case, treat empty bytes string as all zeros for fixed_length_bytes. */ + memset(dest, 0, field->data_size); + return true; + } + + if (size != field->data_size) + PB_RETURN_ERROR(stream, "incorrect fixed length bytes size"); + + return pb_read(stream, (pb_byte_t*)dest, field->data_size); +} diff --git a/micropython/bootloader/nanopb/pb_decode.h b/micropython/bootloader/nanopb/pb_decode.h new file mode 100644 index 000000000..a426bdd70 --- /dev/null +++ b/micropython/bootloader/nanopb/pb_decode.h @@ -0,0 +1,153 @@ +/* pb_decode.h: Functions to decode protocol buffers. Depends on pb_decode.c. + * The main function is pb_decode. You also need an input stream, and the + * field descriptions created by nanopb_generator.py. + */ + +#ifndef PB_DECODE_H_INCLUDED +#define PB_DECODE_H_INCLUDED + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structure for defining custom input streams. You will need to provide + * a callback function to read the bytes from your storage, which can be + * for example a file or a network socket. + * + * The callback must conform to these rules: + * + * 1) Return false on IO errors. This will cause decoding to abort. + * 2) You can use state to store your own data (e.g. buffer pointer), + * and rely on pb_read to verify that no-body reads past bytes_left. + * 3) Your callback may be used with substreams, in which case bytes_left + * is different than from the main stream. Don't use bytes_left to compute + * any pointers. + */ +struct pb_istream_s +{ +#ifdef PB_BUFFER_ONLY + /* Callback pointer is not used in buffer-only configuration. + * Having an int pointer here allows binary compatibility but + * gives an error if someone tries to assign callback function. + */ + int *callback; +#else + bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count); +#endif + + void *state; /* Free field for use by callback implementation */ + size_t bytes_left; + +#ifndef PB_NO_ERRMSG + const char *errmsg; +#endif +}; + +/*************************** + * Main decoding functions * + ***************************/ + +/* Decode a single protocol buffers message from input stream into a C structure. + * Returns true on success, false on any failure. + * The actual struct pointed to by dest must match the description in fields. + * Callback fields of the destination structure must be initialized by caller. + * All other fields will be initialized by this function. + * + * Example usage: + * MyMessage msg = {}; + * uint8_t buffer[64]; + * pb_istream_t stream; + * + * // ... read some data into buffer ... + * + * stream = pb_istream_from_buffer(buffer, count); + * pb_decode(&stream, MyMessage_fields, &msg); + */ +bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except does not initialize the destination structure + * to default values. This is slightly faster if you need no default values + * and just do memset(struct, 0, sizeof(struct)) yourself. + * + * This can also be used for 'merging' two messages, i.e. update only the + * fields that exist in the new message. + * + * Note: If this function returns with an error, it will not release any + * dynamically allocated fields. You will need to call pb_release() yourself. + */ +bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except expects the stream to start with the message size + * encoded as varint. Corresponds to parseDelimitedFrom() in Google's + * protobuf API. + */ +bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +#ifdef PB_ENABLE_MALLOC +/* Release any allocated pointer fields. If you use dynamic allocation, you should + * call this for any successfully decoded message when you are done with it. If + * pb_decode() returns with an error, the message is already released. + */ +void pb_release(const pb_field_t fields[], void *dest_struct); +#endif + + +/************************************** + * Functions for manipulating streams * + **************************************/ + +/* Create an input stream for reading from a memory buffer. + * + * Alternatively, you can use a custom stream that reads directly from e.g. + * a file or a network socket. + */ +pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize); + +/* Function to read from a pb_istream_t. You can use this if you need to + * read some custom header data, or to read data in field callbacks. + */ +bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); + + +/************************************************ + * Helper functions for writing field callbacks * + ************************************************/ + +/* Decode the tag for the next field in the stream. Gives the wire type and + * field tag. At end of the message, returns false and sets eof to true. */ +bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof); + +/* Skip the field payload data, given the wire type. */ +bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type); + +/* Decode an integer in the varint format. This works for bool, enum, int32, + * int64, uint32 and uint64 field types. */ +bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest); + +/* Decode an integer in the varint format. This works for bool, enum, int32, + * and uint32 field types. */ +bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); + +/* Decode an integer in the zig-zagged svarint format. This works for sint32 + * and sint64. */ +bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest); + +/* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to + * a 4-byte wide C variable. */ +bool pb_decode_fixed32(pb_istream_t *stream, void *dest); + +/* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to + * a 8-byte wide C variable. */ +bool pb_decode_fixed64(pb_istream_t *stream, void *dest); + +/* Make a limited-length substream for reading a PB_WT_STRING field. */ +bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream); +bool pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/micropython/bootloader/nanopb/pb_encode.c b/micropython/bootloader/nanopb/pb_encode.c new file mode 100644 index 000000000..30f60d83b --- /dev/null +++ b/micropython/bootloader/nanopb/pb_encode.c @@ -0,0 +1,777 @@ +/* pb_encode.c -- encode a protobuf using minimal resources + * + * 2011 Petteri Aimonen + */ + +#include "pb.h" +#include "pb_encode.h" +#include "pb_common.h" + +/* Use the GCC warn_unused_result attribute to check that all return values + * are propagated correctly. On other compilers and gcc before 3.4.0 just + * ignore the annotation. + */ +#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) + #define checkreturn +#else + #define checkreturn __attribute__((warn_unused_result)) +#endif + +/************************************** + * Declarations internal to this file * + **************************************/ +typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn; + +static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); +static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func); +static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); +static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); +static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); +static void *pb_const_cast(const void *p); +static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); + +/* --- Function pointers to field encoders --- + * Order in the array must match pb_action_t LTYPE numbering. + */ +static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { + &pb_enc_varint, + &pb_enc_uvarint, + &pb_enc_svarint, + &pb_enc_fixed32, + &pb_enc_fixed64, + + &pb_enc_bytes, + &pb_enc_string, + &pb_enc_submessage, + NULL, /* extensions */ + &pb_enc_fixed_length_bytes +}; + +/******************************* + * pb_ostream_t implementation * + *******************************/ + +static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) +{ + size_t i; + pb_byte_t *dest = (pb_byte_t*)stream->state; + stream->state = dest + count; + + for (i = 0; i < count; i++) + dest[i] = buf[i]; + + return true; +} + +pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize) +{ + pb_ostream_t stream; +#ifdef PB_BUFFER_ONLY + stream.callback = (void*)1; /* Just a marker value */ +#else + stream.callback = &buf_write; +#endif + stream.state = buf; + stream.max_size = bufsize; + stream.bytes_written = 0; +#ifndef PB_NO_ERRMSG + stream.errmsg = NULL; +#endif + return stream; +} + +bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) +{ + if (stream->callback != NULL) + { + if (stream->bytes_written + count > stream->max_size) + PB_RETURN_ERROR(stream, "stream full"); + +#ifdef PB_BUFFER_ONLY + if (!buf_write(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#else + if (!stream->callback(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#endif + } + + stream->bytes_written += count; + return true; +} + +/************************* + * Encode a single field * + *************************/ + +/* Encode a static array. Handles the size calculations and possible packing. */ +static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, + const void *pData, size_t count, pb_encoder_t func) +{ + size_t i; + const void *p; + size_t size; + + if (count == 0) + return true; + + if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) + PB_RETURN_ERROR(stream, "array max size exceeded"); + + /* We always pack arrays if the datatype allows it. */ + if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) + { + if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) + return false; + + /* Determine the total size of packed array. */ + if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) + { + size = 4 * count; + } + else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) + { + size = 8 * count; + } + else + { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + p = pData; + for (i = 0; i < count; i++) + { + if (!func(&sizestream, field, p)) + return false; + p = (const char*)p + field->data_size; + } + size = sizestream.bytes_written; + } + + if (!pb_encode_varint(stream, (uint64_t)size)) + return false; + + if (stream->callback == NULL) + return pb_write(stream, NULL, size); /* Just sizing.. */ + + /* Write the data */ + p = pData; + for (i = 0; i < count; i++) + { + if (!func(stream, field, p)) + return false; + p = (const char*)p + field->data_size; + } + } + else + { + p = pData; + for (i = 0; i < count; i++) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + /* Normally the data is stored directly in the array entries, but + * for pointer-type string and bytes fields, the array entries are + * actually pointers themselves also. So we have to dereference once + * more to get to the actual data. */ + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER && + (PB_LTYPE(field->type) == PB_LTYPE_STRING || + PB_LTYPE(field->type) == PB_LTYPE_BYTES)) + { + if (!func(stream, field, *(const void* const*)p)) + return false; + } + else + { + if (!func(stream, field, p)) + return false; + } + p = (const char*)p + field->data_size; + } + } + + return true; +} + +/* In proto3, all fields are optional and are only encoded if their value is "non-zero". + * This function implements the check for the zero value. */ +static bool pb_check_proto3_default_value(const pb_field_t *field, const void *pData) +{ + if (PB_ATYPE(field->type) == PB_ATYPE_STATIC) + { + if (PB_LTYPE(field->type) == PB_LTYPE_BYTES) + { + const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData; + return bytes->size == 0; + } + else if (PB_LTYPE(field->type) == PB_LTYPE_STRING) + { + return *(const char*)pData == '\0'; + } + else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED_LENGTH_BYTES) + { + /* Fixed length bytes is only empty if its length is fixed + * as 0. Which would be pretty strange, but we can check + * it anyway. */ + return field->data_size == 0; + } + else if (PB_LTYPE(field->type) == PB_LTYPE_SUBMESSAGE) + { + /* Check all fields in the submessage to find if any of them + * are non-zero. The comparison cannot be done byte-per-byte + * because the C struct may contain padding bytes that must + * be skipped. + */ + pb_field_iter_t iter; + if (pb_field_iter_begin(&iter, (const pb_field_t*)field->ptr, pb_const_cast(pData))) + { + do + { + if (!pb_check_proto3_default_value(iter.pos, iter.pData)) + { + return false; + } + } while (pb_field_iter_next(&iter)); + } + return true; + } + } + + { + /* Catch-all branch that does byte-per-byte comparison for zero value. + * + * This is for all pointer fields, and for static PB_LTYPE_VARINT, + * UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also + * callback fields. These all have integer or pointer value which + * can be compared with 0. + */ + pb_size_t i; + const char *p = (const char*)pData; + for (i = 0; i < field->data_size; i++) + { + if (p[i] != 0) + { + return false; + } + } + + return true; + } +} + +/* Encode a field with static or pointer allocation, i.e. one whose data + * is available to the encoder directly. */ +static bool checkreturn encode_basic_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + pb_encoder_t func; + bool implicit_has; + const void *pSize = &implicit_has; + + func = PB_ENCODERS[PB_LTYPE(field->type)]; + + if (field->size_offset) + { + /* Static optional, repeated or oneof field */ + pSize = (const char*)pData + field->size_offset; + } + else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL) + { + /* Proto3 style field, optional but without explicit has_ field. */ + implicit_has = !pb_check_proto3_default_value(field, pData); + } + else + { + /* Required field, always present */ + implicit_has = true; + } + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { + /* pData is a pointer to the field, which contains pointer to + * the data. If the 2nd pointer is NULL, it is interpreted as if + * the has_field was false. + */ + pData = *(const void* const*)pData; + implicit_has = (pData != NULL); + } + + switch (PB_HTYPE(field->type)) + { + case PB_HTYPE_REQUIRED: + if (!pData) + PB_RETURN_ERROR(stream, "missing required field"); + if (!pb_encode_tag_for_field(stream, field)) + return false; + if (!func(stream, field, pData)) + return false; + break; + + case PB_HTYPE_OPTIONAL: + if (*(const bool*)pSize) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + if (!func(stream, field, pData)) + return false; + } + break; + + case PB_HTYPE_REPEATED: + if (!encode_array(stream, field, pData, *(const pb_size_t*)pSize, func)) + return false; + break; + + case PB_HTYPE_ONEOF: + if (*(const pb_size_t*)pSize == field->tag) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + if (!func(stream, field, pData)) + return false; + } + break; + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } + + return true; +} + +/* Encode a field with callback semantics. This means that a user function is + * called to provide and encode the actual data. */ +static bool checkreturn encode_callback_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + const pb_callback_t *callback = (const pb_callback_t*)pData; + +#ifdef PB_OLD_CALLBACK_STYLE + const void *arg = callback->arg; +#else + void * const *arg = &(callback->arg); +#endif + + if (callback->funcs.encode != NULL) + { + if (!callback->funcs.encode(stream, field, arg)) + PB_RETURN_ERROR(stream, "callback error"); + } + return true; +} + +/* Encode a single field of any callback or static type. */ +static bool checkreturn encode_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + switch (PB_ATYPE(field->type)) + { + case PB_ATYPE_STATIC: + case PB_ATYPE_POINTER: + return encode_basic_field(stream, field, pData); + + case PB_ATYPE_CALLBACK: + return encode_callback_field(stream, field, pData); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +/* Default handler for extension fields. Expects to have a pb_field_t + * pointer in the extension->type->arg field. */ +static bool checkreturn default_extension_encoder(pb_ostream_t *stream, + const pb_extension_t *extension) +{ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { + /* For pointer extensions, the pointer is stored directly + * in the extension structure. This avoids having an extra + * indirection. */ + return encode_field(stream, field, &extension->dest); + } + else + { + return encode_field(stream, field, extension->dest); + } +} + +/* Walk through all the registered extensions and give them a chance + * to encode themselves. */ +static bool checkreturn encode_extension_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + const pb_extension_t *extension = *(const pb_extension_t* const *)pData; + PB_UNUSED(field); + + while (extension) + { + bool status; + if (extension->type->encode) + status = extension->type->encode(stream, extension); + else + status = default_extension_encoder(stream, extension); + + if (!status) + return false; + + extension = extension->next; + } + + return true; +} + +/********************* + * Encode all fields * + *********************/ + +static void *pb_const_cast(const void *p) +{ + /* Note: this casts away const, in order to use the common field iterator + * logic for both encoding and decoding. */ + union { + void *p1; + const void *p2; + } t; + t.p2 = p; + return t.p1; +} + +bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + pb_field_iter_t iter; + if (!pb_field_iter_begin(&iter, fields, pb_const_cast(src_struct))) + return true; /* Empty message type */ + + do { + if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION) + { + /* Special case for the extension field placeholder */ + if (!encode_extension_field(stream, iter.pos, iter.pData)) + return false; + } + else + { + /* Regular field */ + if (!encode_field(stream, iter.pos, iter.pData)) + return false; + } + } while (pb_field_iter_next(&iter)); + + return true; +} + +bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + return pb_encode_submessage(stream, fields, src_struct); +} + +bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct) +{ + pb_ostream_t stream = PB_OSTREAM_SIZING; + + if (!pb_encode(&stream, fields, src_struct)) + return false; + + *size = stream.bytes_written; + return true; +} + +/******************** + * Helper functions * + ********************/ +bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value) +{ + pb_byte_t buffer[10]; + size_t i = 0; + + if (value <= 0x7F) + { + pb_byte_t v = (pb_byte_t)value; + return pb_write(stream, &v, 1); + } + + while (value) + { + buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80); + value >>= 7; + i++; + } + buffer[i-1] &= 0x7F; /* Unset top bit on last byte */ + + return pb_write(stream, buffer, i); +} + +bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value) +{ + uint64_t zigzagged; + if (value < 0) + zigzagged = ~((uint64_t)value << 1); + else + zigzagged = (uint64_t)value << 1; + + return pb_encode_varint(stream, zigzagged); +} + +bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value) +{ + uint32_t val = *(const uint32_t*)value; + pb_byte_t bytes[4]; + bytes[0] = (pb_byte_t)(val & 0xFF); + bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); + bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); + bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); + return pb_write(stream, bytes, 4); +} + +bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) +{ + uint64_t val = *(const uint64_t*)value; + pb_byte_t bytes[8]; + bytes[0] = (pb_byte_t)(val & 0xFF); + bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); + bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); + bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); + bytes[4] = (pb_byte_t)((val >> 32) & 0xFF); + bytes[5] = (pb_byte_t)((val >> 40) & 0xFF); + bytes[6] = (pb_byte_t)((val >> 48) & 0xFF); + bytes[7] = (pb_byte_t)((val >> 56) & 0xFF); + return pb_write(stream, bytes, 8); +} + +bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) +{ + uint64_t tag = ((uint64_t)field_number << 3) | wiretype; + return pb_encode_varint(stream, tag); +} + +bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field) +{ + pb_wire_type_t wiretype; + switch (PB_LTYPE(field->type)) + { + case PB_LTYPE_VARINT: + case PB_LTYPE_UVARINT: + case PB_LTYPE_SVARINT: + wiretype = PB_WT_VARINT; + break; + + case PB_LTYPE_FIXED32: + wiretype = PB_WT_32BIT; + break; + + case PB_LTYPE_FIXED64: + wiretype = PB_WT_64BIT; + break; + + case PB_LTYPE_BYTES: + case PB_LTYPE_STRING: + case PB_LTYPE_SUBMESSAGE: + case PB_LTYPE_FIXED_LENGTH_BYTES: + wiretype = PB_WT_STRING; + break; + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } + + return pb_encode_tag(stream, wiretype, field->tag); +} + +bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size) +{ + if (!pb_encode_varint(stream, (uint64_t)size)) + return false; + + return pb_write(stream, buffer, size); +} + +bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + /* First calculate the message size using a non-writing substream. */ + pb_ostream_t substream = PB_OSTREAM_SIZING; + size_t size; + bool status; + + if (!pb_encode(&substream, fields, src_struct)) + { +#ifndef PB_NO_ERRMSG + stream->errmsg = substream.errmsg; +#endif + return false; + } + + size = substream.bytes_written; + + if (!pb_encode_varint(stream, (uint64_t)size)) + return false; + + if (stream->callback == NULL) + return pb_write(stream, NULL, size); /* Just sizing */ + + if (stream->bytes_written + size > stream->max_size) + PB_RETURN_ERROR(stream, "stream full"); + + /* Use a substream to verify that a callback doesn't write more than + * what it did the first time. */ + substream.callback = stream->callback; + substream.state = stream->state; + substream.max_size = size; + substream.bytes_written = 0; +#ifndef PB_NO_ERRMSG + substream.errmsg = NULL; +#endif + + status = pb_encode(&substream, fields, src_struct); + + stream->bytes_written += substream.bytes_written; + stream->state = substream.state; +#ifndef PB_NO_ERRMSG + stream->errmsg = substream.errmsg; +#endif + + if (substream.bytes_written != size) + PB_RETURN_ERROR(stream, "submsg size changed"); + + return status; +} + +/* Field encoders */ + +static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + int64_t value = 0; + + if (field->data_size == sizeof(int_least8_t)) + value = *(const int_least8_t*)src; + else if (field->data_size == sizeof(int_least16_t)) + value = *(const int_least16_t*)src; + else if (field->data_size == sizeof(int32_t)) + value = *(const int32_t*)src; + else if (field->data_size == sizeof(int64_t)) + value = *(const int64_t*)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + return pb_encode_varint(stream, (uint64_t)value); +} + +static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + uint64_t value = 0; + + if (field->data_size == sizeof(uint_least8_t)) + value = *(const uint_least8_t*)src; + else if (field->data_size == sizeof(uint_least16_t)) + value = *(const uint_least16_t*)src; + else if (field->data_size == sizeof(uint32_t)) + value = *(const uint32_t*)src; + else if (field->data_size == sizeof(uint64_t)) + value = *(const uint64_t*)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + return pb_encode_varint(stream, value); +} + +static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + int64_t value = 0; + + if (field->data_size == sizeof(int_least8_t)) + value = *(const int_least8_t*)src; + else if (field->data_size == sizeof(int_least16_t)) + value = *(const int_least16_t*)src; + else if (field->data_size == sizeof(int32_t)) + value = *(const int32_t*)src; + else if (field->data_size == sizeof(int64_t)) + value = *(const int64_t*)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + return pb_encode_svarint(stream, value); +} + +static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + PB_UNUSED(field); + return pb_encode_fixed64(stream, src); +} + +static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + PB_UNUSED(field); + return pb_encode_fixed32(stream, src); +} + +static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + const pb_bytes_array_t *bytes = NULL; + + bytes = (const pb_bytes_array_t*)src; + + if (src == NULL) + { + /* Treat null pointer as an empty bytes field */ + return pb_encode_string(stream, NULL, 0); + } + + if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && + PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size) + { + PB_RETURN_ERROR(stream, "bytes size exceeded"); + } + + return pb_encode_string(stream, bytes->bytes, bytes->size); +} + +static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + size_t size = 0; + size_t max_size = field->data_size; + const char *p = (const char*)src; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + max_size = (size_t)-1; + + if (src == NULL) + { + size = 0; /* Treat null pointer as an empty string */ + } + else + { + /* strnlen() is not always available, so just use a loop */ + while (size < max_size && *p != '\0') + { + size++; + p++; + } + } + + return pb_encode_string(stream, (const pb_byte_t*)src, size); +} + +static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + if (field->ptr == NULL) + PB_RETURN_ERROR(stream, "invalid field descriptor"); + + return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src); +} + +static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + return pb_encode_string(stream, (const pb_byte_t*)src, field->data_size); +} + diff --git a/micropython/bootloader/nanopb/pb_encode.h b/micropython/bootloader/nanopb/pb_encode.h new file mode 100644 index 000000000..d9909fb01 --- /dev/null +++ b/micropython/bootloader/nanopb/pb_encode.h @@ -0,0 +1,154 @@ +/* pb_encode.h: Functions to encode protocol buffers. Depends on pb_encode.c. + * The main function is pb_encode. You also need an output stream, and the + * field descriptions created by nanopb_generator.py. + */ + +#ifndef PB_ENCODE_H_INCLUDED +#define PB_ENCODE_H_INCLUDED + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structure for defining custom output streams. You will need to provide + * a callback function to write the bytes to your storage, which can be + * for example a file or a network socket. + * + * The callback must conform to these rules: + * + * 1) Return false on IO errors. This will cause encoding to abort. + * 2) You can use state to store your own data (e.g. buffer pointer). + * 3) pb_write will update bytes_written after your callback runs. + * 4) Substreams will modify max_size and bytes_written. Don't use them + * to calculate any pointers. + */ +struct pb_ostream_s +{ +#ifdef PB_BUFFER_ONLY + /* Callback pointer is not used in buffer-only configuration. + * Having an int pointer here allows binary compatibility but + * gives an error if someone tries to assign callback function. + * Also, NULL pointer marks a 'sizing stream' that does not + * write anything. + */ + int *callback; +#else + bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); +#endif + void *state; /* Free field for use by callback implementation. */ + size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */ + size_t bytes_written; /* Number of bytes written so far. */ + +#ifndef PB_NO_ERRMSG + const char *errmsg; +#endif +}; + +/*************************** + * Main encoding functions * + ***************************/ + +/* Encode a single protocol buffers message from C structure into a stream. + * Returns true on success, false on any failure. + * The actual struct pointed to by src_struct must match the description in fields. + * All required fields in the struct are assumed to have been filled in. + * + * Example usage: + * MyMessage msg = {}; + * uint8_t buffer[64]; + * pb_ostream_t stream; + * + * msg.field1 = 42; + * stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + * pb_encode(&stream, MyMessage_fields, &msg); + */ +bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +/* Same as pb_encode, but prepends the length of the message as a varint. + * Corresponds to writeDelimitedTo() in Google's protobuf API. + */ +bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +/* Encode the message to get the size of the encoded data, but do not store + * the data. */ +bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct); + +/************************************** + * Functions for manipulating streams * + **************************************/ + +/* Create an output stream for writing into a memory buffer. + * The number of bytes written can be found in stream.bytes_written after + * encoding the message. + * + * Alternatively, you can use a custom stream that writes directly to e.g. + * a file or a network socket. + */ +pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize); + +/* Pseudo-stream for measuring the size of a message without actually storing + * the encoded data. + * + * Example usage: + * MyMessage msg = {}; + * pb_ostream_t stream = PB_OSTREAM_SIZING; + * pb_encode(&stream, MyMessage_fields, &msg); + * printf("Message size is %d\n", stream.bytes_written); + */ +#ifndef PB_NO_ERRMSG +#define PB_OSTREAM_SIZING {0,0,0,0,0} +#else +#define PB_OSTREAM_SIZING {0,0,0,0} +#endif + +/* Function to write into a pb_ostream_t stream. You can use this if you need + * to append or prepend some custom headers to the message. + */ +bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); + + +/************************************************ + * Helper functions for writing field callbacks * + ************************************************/ + +/* Encode field header based on type and field number defined in the field + * structure. Call this from the callback before writing out field contents. */ +bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field); + +/* Encode field header by manually specifing wire type. You need to use this + * if you want to write out packed arrays from a callback field. */ +bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number); + +/* Encode an integer in the varint format. + * This works for bool, enum, int32, int64, uint32 and uint64 field types. */ +bool pb_encode_varint(pb_ostream_t *stream, uint64_t value); + +/* Encode an integer in the zig-zagged svarint format. + * This works for sint32 and sint64. */ +bool pb_encode_svarint(pb_ostream_t *stream, int64_t value); + +/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */ +bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size); + +/* Encode a fixed32, sfixed32 or float value. + * You need to pass a pointer to a 4-byte wide C variable. */ +bool pb_encode_fixed32(pb_ostream_t *stream, const void *value); + +/* Encode a fixed64, sfixed64 or double value. + * You need to pass a pointer to a 8-byte wide C variable. */ +bool pb_encode_fixed64(pb_ostream_t *stream, const void *value); + +/* Encode a submessage field. + * You need to pass the pb_field_t array and pointer to struct, just like + * with pb_encode(). This internally encodes the submessage twice, first to + * calculate message size and then to actually write it out. + */ +bool pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/micropython/bootloader/protob/.gitignore b/micropython/bootloader/protob/.gitignore new file mode 100644 index 000000000..7dd49fbe6 --- /dev/null +++ b/micropython/bootloader/protob/.gitignore @@ -0,0 +1,2 @@ +*.pb +__pycache__/ diff --git a/micropython/bootloader/protob/Makefile b/micropython/bootloader/protob/Makefile new file mode 100644 index 000000000..c17ee1756 --- /dev/null +++ b/micropython/bootloader/protob/Makefile @@ -0,0 +1,10 @@ +all: messages.pb.c types.pb.c + +%.pb.c: %.pb %.options + nanopb_generator.py $< -T + +%.pb: %.proto + protoc -I/usr/include -I. $< -o $@ + +clean: + rm -f *.pb *.o *.pb.c *.pb.h diff --git a/micropython/bootloader/protob/messages.options b/micropython/bootloader/protob/messages.options new file mode 100644 index 000000000..e69de29bb diff --git a/micropython/bootloader/protob/messages.pb.c b/micropython/bootloader/protob/messages.pb.c new file mode 100644 index 000000000..7094ff0bc --- /dev/null +++ b/micropython/bootloader/protob/messages.pb.c @@ -0,0 +1,492 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.8 */ + +#include "messages.pb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +const InputScriptType GetAddress_script_type_default = InputScriptType_SPENDADDRESS; +const uint32_t ResetDevice_strength_default = 256u; +const uint32_t SignTx_version_default = 1u; +const uint32_t SignTx_lock_time_default = 0u; +const uint32_t SimpleSignTx_version_default = 1u; +const uint32_t SimpleSignTx_lock_time_default = 0u; + + +const pb_field_t Initialize_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t GetFeatures_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t Features_fields[19] = { + PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, Features, vendor, vendor, 0), + PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, Features, major_version, vendor, 0), + PB_FIELD( 3, UINT32 , OPTIONAL, STATIC , OTHER, Features, minor_version, major_version, 0), + PB_FIELD( 4, UINT32 , OPTIONAL, STATIC , OTHER, Features, patch_version, minor_version, 0), + PB_FIELD( 5, BOOL , OPTIONAL, STATIC , OTHER, Features, bootloader_mode, patch_version, 0), + PB_FIELD( 6, STRING , OPTIONAL, CALLBACK, OTHER, Features, device_id, bootloader_mode, 0), + PB_FIELD( 7, BOOL , OPTIONAL, STATIC , OTHER, Features, pin_protection, device_id, 0), + PB_FIELD( 8, BOOL , OPTIONAL, STATIC , OTHER, Features, passphrase_protection, pin_protection, 0), + PB_FIELD( 9, STRING , OPTIONAL, CALLBACK, OTHER, Features, language, passphrase_protection, 0), + PB_FIELD( 10, STRING , OPTIONAL, CALLBACK, OTHER, Features, label, language, 0), + PB_FIELD( 11, MESSAGE , REPEATED, CALLBACK, OTHER, Features, coins, label, &CoinType_fields), + PB_FIELD( 12, BOOL , OPTIONAL, STATIC , OTHER, Features, initialized, coins, 0), + PB_FIELD( 13, BYTES , OPTIONAL, CALLBACK, OTHER, Features, revision, initialized, 0), + PB_FIELD( 14, BYTES , OPTIONAL, CALLBACK, OTHER, Features, bootloader_hash, revision, 0), + PB_FIELD( 15, BOOL , OPTIONAL, STATIC , OTHER, Features, imported, bootloader_hash, 0), + PB_FIELD( 16, BOOL , OPTIONAL, STATIC , OTHER, Features, pin_cached, imported, 0), + PB_FIELD( 17, BOOL , OPTIONAL, STATIC , OTHER, Features, passphrase_cached, pin_cached, 0), + PB_FIELD( 18, BOOL , OPTIONAL, STATIC , OTHER, Features, firmware_present, passphrase_cached, 0), + PB_LAST_FIELD +}; + +const pb_field_t ClearSession_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t ApplySettings_fields[5] = { + PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, ApplySettings, language, language, 0), + PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, ApplySettings, label, language, 0), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, ApplySettings, use_passphrase, label, 0), + PB_FIELD( 4, BYTES , OPTIONAL, CALLBACK, OTHER, ApplySettings, homescreen, use_passphrase, 0), + PB_LAST_FIELD +}; + +const pb_field_t ChangePin_fields[2] = { + PB_FIELD( 1, BOOL , OPTIONAL, STATIC , FIRST, ChangePin, remove, remove, 0), + PB_LAST_FIELD +}; + +const pb_field_t Ping_fields[5] = { + PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, Ping, message, message, 0), + PB_FIELD( 2, BOOL , OPTIONAL, STATIC , OTHER, Ping, button_protection, message, 0), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, Ping, pin_protection, button_protection, 0), + PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, Ping, passphrase_protection, pin_protection, 0), + PB_LAST_FIELD +}; + +const pb_field_t Success_fields[2] = { + PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, Success, message, message, 0), + PB_LAST_FIELD +}; + +const pb_field_t Failure_fields[3] = { + PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, Failure, code, code, 0), + PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, Failure, message, code, 0), + PB_LAST_FIELD +}; + +const pb_field_t ButtonRequest_fields[3] = { + PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, ButtonRequest, code, code, 0), + PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, ButtonRequest, data, code, 0), + PB_LAST_FIELD +}; + +const pb_field_t ButtonAck_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t PinMatrixRequest_fields[2] = { + PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, PinMatrixRequest, type, type, 0), + PB_LAST_FIELD +}; + +const pb_field_t PinMatrixAck_fields[2] = { + PB_FIELD( 1, STRING , REQUIRED, CALLBACK, FIRST, PinMatrixAck, pin, pin, 0), + PB_LAST_FIELD +}; + +const pb_field_t Cancel_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t PassphraseRequest_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t PassphraseAck_fields[2] = { + PB_FIELD( 1, STRING , REQUIRED, CALLBACK, FIRST, PassphraseAck, passphrase, passphrase, 0), + PB_LAST_FIELD +}; + +const pb_field_t GetEntropy_fields[2] = { + PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, GetEntropy, size, size, 0), + PB_LAST_FIELD +}; + +const pb_field_t Entropy_fields[2] = { + PB_FIELD( 1, BYTES , REQUIRED, CALLBACK, FIRST, Entropy, entropy, entropy, 0), + PB_LAST_FIELD +}; + +const pb_field_t GetPublicKey_fields[5] = { + PB_FIELD( 1, UINT32 , REPEATED, CALLBACK, FIRST, GetPublicKey, address_n, address_n, 0), + PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, GetPublicKey, ecdsa_curve_name, address_n, 0), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, GetPublicKey, show_display, ecdsa_curve_name, 0), + PB_FIELD( 4, STRING , OPTIONAL, CALLBACK, OTHER, GetPublicKey, coin_name, show_display, 0), + PB_LAST_FIELD +}; + +const pb_field_t PublicKey_fields[3] = { + PB_FIELD( 1, MESSAGE , REQUIRED, STATIC , FIRST, PublicKey, node, node, &HDNodeType_fields), + PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, PublicKey, xpub, node, 0), + PB_LAST_FIELD +}; + +const pb_field_t GetAddress_fields[6] = { + PB_FIELD( 1, UINT32 , REPEATED, CALLBACK, FIRST, GetAddress, address_n, address_n, 0), + PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, GetAddress, coin_name, address_n, 0), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, GetAddress, show_display, coin_name, 0), + PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, GetAddress, multisig, show_display, &MultisigRedeemScriptType_fields), + PB_FIELD( 5, ENUM , OPTIONAL, STATIC , OTHER, GetAddress, script_type, multisig, &GetAddress_script_type_default), + PB_LAST_FIELD +}; + +const pb_field_t EthereumGetAddress_fields[3] = { + PB_FIELD( 1, UINT32 , REPEATED, CALLBACK, FIRST, EthereumGetAddress, address_n, address_n, 0), + PB_FIELD( 2, BOOL , OPTIONAL, STATIC , OTHER, EthereumGetAddress, show_display, address_n, 0), + PB_LAST_FIELD +}; + +const pb_field_t Address_fields[2] = { + PB_FIELD( 1, STRING , REQUIRED, CALLBACK, FIRST, Address, address, address, 0), + PB_LAST_FIELD +}; + +const pb_field_t EthereumAddress_fields[2] = { + PB_FIELD( 1, BYTES , REQUIRED, CALLBACK, FIRST, EthereumAddress, address, address, 0), + PB_LAST_FIELD +}; + +const pb_field_t WipeDevice_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t LoadDevice_fields[9] = { + PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, LoadDevice, mnemonic, mnemonic, 0), + PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, LoadDevice, node, mnemonic, &HDNodeType_fields), + PB_FIELD( 3, STRING , OPTIONAL, CALLBACK, OTHER, LoadDevice, pin, node, 0), + PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, passphrase_protection, pin, 0), + PB_FIELD( 5, STRING , OPTIONAL, CALLBACK, OTHER, LoadDevice, language, passphrase_protection, 0), + PB_FIELD( 6, STRING , OPTIONAL, CALLBACK, OTHER, LoadDevice, label, language, 0), + PB_FIELD( 7, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, skip_checksum, label, 0), + PB_FIELD( 8, UINT32 , OPTIONAL, STATIC , OTHER, LoadDevice, u2f_counter, skip_checksum, 0), + PB_LAST_FIELD +}; + +const pb_field_t ResetDevice_fields[8] = { + PB_FIELD( 1, BOOL , OPTIONAL, STATIC , FIRST, ResetDevice, display_random, display_random, 0), + PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, ResetDevice, strength, display_random, &ResetDevice_strength_default), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, passphrase_protection, strength, 0), + PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, pin_protection, passphrase_protection, 0), + PB_FIELD( 5, STRING , OPTIONAL, CALLBACK, OTHER, ResetDevice, language, pin_protection, 0), + PB_FIELD( 6, STRING , OPTIONAL, CALLBACK, OTHER, ResetDevice, label, language, 0), + PB_FIELD( 7, UINT32 , OPTIONAL, STATIC , OTHER, ResetDevice, u2f_counter, label, 0), + PB_LAST_FIELD +}; + +const pb_field_t EntropyRequest_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t EntropyAck_fields[2] = { + PB_FIELD( 1, BYTES , OPTIONAL, CALLBACK, FIRST, EntropyAck, entropy, entropy, 0), + PB_LAST_FIELD +}; + +const pb_field_t RecoveryDevice_fields[9] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, RecoveryDevice, word_count, word_count, 0), + PB_FIELD( 2, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, passphrase_protection, word_count, 0), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, pin_protection, passphrase_protection, 0), + PB_FIELD( 4, STRING , OPTIONAL, CALLBACK, OTHER, RecoveryDevice, language, pin_protection, 0), + PB_FIELD( 5, STRING , OPTIONAL, CALLBACK, OTHER, RecoveryDevice, label, language, 0), + PB_FIELD( 6, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, enforce_wordlist, label, 0), + PB_FIELD( 8, UINT32 , OPTIONAL, STATIC , OTHER, RecoveryDevice, type, enforce_wordlist, 0), + PB_FIELD( 9, UINT32 , OPTIONAL, STATIC , OTHER, RecoveryDevice, u2f_counter, type, 0), + PB_LAST_FIELD +}; + +const pb_field_t WordRequest_fields[2] = { + PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, WordRequest, type, type, 0), + PB_LAST_FIELD +}; + +const pb_field_t WordAck_fields[2] = { + PB_FIELD( 1, STRING , REQUIRED, CALLBACK, FIRST, WordAck, word, word, 0), + PB_LAST_FIELD +}; + +const pb_field_t SignMessage_fields[4] = { + PB_FIELD( 1, UINT32 , REPEATED, CALLBACK, FIRST, SignMessage, address_n, address_n, 0), + PB_FIELD( 2, BYTES , REQUIRED, CALLBACK, OTHER, SignMessage, message, address_n, 0), + PB_FIELD( 3, STRING , OPTIONAL, CALLBACK, OTHER, SignMessage, coin_name, message, 0), + PB_LAST_FIELD +}; + +const pb_field_t VerifyMessage_fields[5] = { + PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, VerifyMessage, address, address, 0), + PB_FIELD( 2, BYTES , OPTIONAL, CALLBACK, OTHER, VerifyMessage, signature, address, 0), + PB_FIELD( 3, BYTES , OPTIONAL, CALLBACK, OTHER, VerifyMessage, message, signature, 0), + PB_FIELD( 4, STRING , OPTIONAL, CALLBACK, OTHER, VerifyMessage, coin_name, message, 0), + PB_LAST_FIELD +}; + +const pb_field_t MessageSignature_fields[3] = { + PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, MessageSignature, address, address, 0), + PB_FIELD( 2, BYTES , OPTIONAL, CALLBACK, OTHER, MessageSignature, signature, address, 0), + PB_LAST_FIELD +}; + +const pb_field_t EncryptMessage_fields[6] = { + PB_FIELD( 1, BYTES , OPTIONAL, CALLBACK, FIRST, EncryptMessage, pubkey, pubkey, 0), + PB_FIELD( 2, BYTES , OPTIONAL, CALLBACK, OTHER, EncryptMessage, message, pubkey, 0), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, EncryptMessage, display_only, message, 0), + PB_FIELD( 4, UINT32 , REPEATED, CALLBACK, OTHER, EncryptMessage, address_n, display_only, 0), + PB_FIELD( 5, STRING , OPTIONAL, CALLBACK, OTHER, EncryptMessage, coin_name, address_n, 0), + PB_LAST_FIELD +}; + +const pb_field_t EncryptedMessage_fields[4] = { + PB_FIELD( 1, BYTES , OPTIONAL, CALLBACK, FIRST, EncryptedMessage, nonce, nonce, 0), + PB_FIELD( 2, BYTES , OPTIONAL, CALLBACK, OTHER, EncryptedMessage, message, nonce, 0), + PB_FIELD( 3, BYTES , OPTIONAL, CALLBACK, OTHER, EncryptedMessage, hmac, message, 0), + PB_LAST_FIELD +}; + +const pb_field_t DecryptMessage_fields[5] = { + PB_FIELD( 1, UINT32 , REPEATED, CALLBACK, FIRST, DecryptMessage, address_n, address_n, 0), + PB_FIELD( 2, BYTES , OPTIONAL, CALLBACK, OTHER, DecryptMessage, nonce, address_n, 0), + PB_FIELD( 3, BYTES , OPTIONAL, CALLBACK, OTHER, DecryptMessage, message, nonce, 0), + PB_FIELD( 4, BYTES , OPTIONAL, CALLBACK, OTHER, DecryptMessage, hmac, message, 0), + PB_LAST_FIELD +}; + +const pb_field_t DecryptedMessage_fields[3] = { + PB_FIELD( 1, BYTES , OPTIONAL, CALLBACK, FIRST, DecryptedMessage, message, message, 0), + PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, DecryptedMessage, address, message, 0), + PB_LAST_FIELD +}; + +const pb_field_t CipherKeyValue_fields[8] = { + PB_FIELD( 1, UINT32 , REPEATED, CALLBACK, FIRST, CipherKeyValue, address_n, address_n, 0), + PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, CipherKeyValue, key, address_n, 0), + PB_FIELD( 3, BYTES , OPTIONAL, CALLBACK, OTHER, CipherKeyValue, value, key, 0), + PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, encrypt, value, 0), + PB_FIELD( 5, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_encrypt, encrypt, 0), + PB_FIELD( 6, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_decrypt, ask_on_encrypt, 0), + PB_FIELD( 7, BYTES , OPTIONAL, CALLBACK, OTHER, CipherKeyValue, iv, ask_on_decrypt, 0), + PB_LAST_FIELD +}; + +const pb_field_t CipheredKeyValue_fields[2] = { + PB_FIELD( 1, BYTES , OPTIONAL, CALLBACK, FIRST, CipheredKeyValue, value, value, 0), + PB_LAST_FIELD +}; + +const pb_field_t EstimateTxSize_fields[4] = { + PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, EstimateTxSize, outputs_count, outputs_count, 0), + PB_FIELD( 2, UINT32 , REQUIRED, STATIC , OTHER, EstimateTxSize, inputs_count, outputs_count, 0), + PB_FIELD( 3, STRING , OPTIONAL, CALLBACK, OTHER, EstimateTxSize, coin_name, inputs_count, 0), + PB_LAST_FIELD +}; + +const pb_field_t TxSize_fields[2] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxSize, tx_size, tx_size, 0), + PB_LAST_FIELD +}; + +const pb_field_t SignTx_fields[6] = { + PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, SignTx, outputs_count, outputs_count, 0), + PB_FIELD( 2, UINT32 , REQUIRED, STATIC , OTHER, SignTx, inputs_count, outputs_count, 0), + PB_FIELD( 3, STRING , OPTIONAL, CALLBACK, OTHER, SignTx, coin_name, inputs_count, 0), + PB_FIELD( 4, UINT32 , OPTIONAL, STATIC , OTHER, SignTx, version, coin_name, &SignTx_version_default), + PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, SignTx, lock_time, version, &SignTx_lock_time_default), + PB_LAST_FIELD +}; + +const pb_field_t SimpleSignTx_fields[7] = { + PB_FIELD( 1, MESSAGE , REPEATED, CALLBACK, FIRST, SimpleSignTx, inputs, inputs, &TxInputType_fields), + PB_FIELD( 2, MESSAGE , REPEATED, CALLBACK, OTHER, SimpleSignTx, outputs, inputs, &TxOutputType_fields), + PB_FIELD( 3, MESSAGE , REPEATED, CALLBACK, OTHER, SimpleSignTx, transactions, outputs, &TransactionType_fields), + PB_FIELD( 4, STRING , OPTIONAL, CALLBACK, OTHER, SimpleSignTx, coin_name, transactions, 0), + PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, SimpleSignTx, version, coin_name, &SimpleSignTx_version_default), + PB_FIELD( 6, UINT32 , OPTIONAL, STATIC , OTHER, SimpleSignTx, lock_time, version, &SimpleSignTx_lock_time_default), + PB_LAST_FIELD +}; + +const pb_field_t TxRequest_fields[4] = { + PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, TxRequest, request_type, request_type, 0), + PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, details, request_type, &TxRequestDetailsType_fields), + PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, serialized, details, &TxRequestSerializedType_fields), + PB_LAST_FIELD +}; + +const pb_field_t TxAck_fields[2] = { + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, TxAck, tx, tx, &TransactionType_fields), + PB_LAST_FIELD +}; + +const pb_field_t EthereumSignTx_fields[10] = { + PB_FIELD( 1, UINT32 , REPEATED, CALLBACK, FIRST, EthereumSignTx, address_n, address_n, 0), + PB_FIELD( 2, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, nonce, address_n, 0), + PB_FIELD( 3, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, gas_price, nonce, 0), + PB_FIELD( 4, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, gas_limit, gas_price, 0), + PB_FIELD( 5, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, to, gas_limit, 0), + PB_FIELD( 6, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, value, to, 0), + PB_FIELD( 7, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, data_initial_chunk, value, 0), + PB_FIELD( 8, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_length, data_initial_chunk, 0), + PB_FIELD( 9, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, chain_id, data_length, 0), + PB_LAST_FIELD +}; + +const pb_field_t EthereumTxRequest_fields[5] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, EthereumTxRequest, data_length, data_length, 0), + PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, EthereumTxRequest, signature_v, data_length, 0), + PB_FIELD( 3, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumTxRequest, signature_r, signature_v, 0), + PB_FIELD( 4, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumTxRequest, signature_s, signature_r, 0), + PB_LAST_FIELD +}; + +const pb_field_t EthereumTxAck_fields[2] = { + PB_FIELD( 1, BYTES , OPTIONAL, CALLBACK, FIRST, EthereumTxAck, data_chunk, data_chunk, 0), + PB_LAST_FIELD +}; + +const pb_field_t SignIdentity_fields[5] = { + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, SignIdentity, identity, identity, &IdentityType_fields), + PB_FIELD( 2, BYTES , OPTIONAL, CALLBACK, OTHER, SignIdentity, challenge_hidden, identity, 0), + PB_FIELD( 3, STRING , OPTIONAL, CALLBACK, OTHER, SignIdentity, challenge_visual, challenge_hidden, 0), + PB_FIELD( 4, STRING , OPTIONAL, CALLBACK, OTHER, SignIdentity, ecdsa_curve_name, challenge_visual, 0), + PB_LAST_FIELD +}; + +const pb_field_t SignedIdentity_fields[4] = { + PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, SignedIdentity, address, address, 0), + PB_FIELD( 2, BYTES , OPTIONAL, CALLBACK, OTHER, SignedIdentity, public_key, address, 0), + PB_FIELD( 3, BYTES , OPTIONAL, CALLBACK, OTHER, SignedIdentity, signature, public_key, 0), + PB_LAST_FIELD +}; + +const pb_field_t GetECDHSessionKey_fields[4] = { + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, GetECDHSessionKey, identity, identity, &IdentityType_fields), + PB_FIELD( 2, BYTES , OPTIONAL, CALLBACK, OTHER, GetECDHSessionKey, peer_public_key, identity, 0), + PB_FIELD( 3, STRING , OPTIONAL, CALLBACK, OTHER, GetECDHSessionKey, ecdsa_curve_name, peer_public_key, 0), + PB_LAST_FIELD +}; + +const pb_field_t ECDHSessionKey_fields[2] = { + PB_FIELD( 1, BYTES , OPTIONAL, CALLBACK, FIRST, ECDHSessionKey, session_key, session_key, 0), + PB_LAST_FIELD +}; + +const pb_field_t SetU2FCounter_fields[2] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, SetU2FCounter, u2f_counter, u2f_counter, 0), + PB_LAST_FIELD +}; + +const pb_field_t FirmwareErase_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t FirmwareRequest_fields[3] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, FirmwareRequest, offset, offset, 0), + PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, FirmwareRequest, length, offset, 0), + PB_LAST_FIELD +}; + +const pb_field_t FirmwareUpload_fields[3] = { + PB_FIELD( 1, BYTES , REQUIRED, CALLBACK, FIRST, FirmwareUpload, payload, payload, 0), + PB_FIELD( 2, BYTES , OPTIONAL, CALLBACK, OTHER, FirmwareUpload, hash, payload, 0), + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkDecision_fields[2] = { + PB_FIELD( 1, BOOL , REQUIRED, STATIC , FIRST, DebugLinkDecision, yes_no, yes_no, 0), + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkGetState_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkState_fields[11] = { + PB_FIELD( 1, BYTES , OPTIONAL, CALLBACK, FIRST, DebugLinkState, layout, layout, 0), + PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, DebugLinkState, pin, layout, 0), + PB_FIELD( 3, STRING , OPTIONAL, CALLBACK, OTHER, DebugLinkState, matrix, pin, 0), + PB_FIELD( 4, STRING , OPTIONAL, CALLBACK, OTHER, DebugLinkState, mnemonic, matrix, 0), + PB_FIELD( 5, MESSAGE , OPTIONAL, STATIC , OTHER, DebugLinkState, node, mnemonic, &HDNodeType_fields), + PB_FIELD( 6, BOOL , OPTIONAL, STATIC , OTHER, DebugLinkState, passphrase_protection, node, 0), + PB_FIELD( 7, STRING , OPTIONAL, CALLBACK, OTHER, DebugLinkState, reset_word, passphrase_protection, 0), + PB_FIELD( 8, BYTES , OPTIONAL, CALLBACK, OTHER, DebugLinkState, reset_entropy, reset_word, 0), + PB_FIELD( 9, STRING , OPTIONAL, CALLBACK, OTHER, DebugLinkState, recovery_fake_word, reset_entropy, 0), + PB_FIELD( 10, UINT32 , OPTIONAL, STATIC , OTHER, DebugLinkState, recovery_word_pos, recovery_fake_word, 0), + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkStop_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkLog_fields[4] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkLog, level, level, 0), + PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, DebugLinkLog, bucket, level, 0), + PB_FIELD( 3, STRING , OPTIONAL, CALLBACK, OTHER, DebugLinkLog, text, bucket, 0), + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkMemoryRead_fields[3] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkMemoryRead, address, address, 0), + PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, DebugLinkMemoryRead, length, address, 0), + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkMemory_fields[2] = { + PB_FIELD( 1, BYTES , OPTIONAL, CALLBACK, FIRST, DebugLinkMemory, memory, memory, 0), + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkMemoryWrite_fields[4] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkMemoryWrite, address, address, 0), + PB_FIELD( 2, BYTES , OPTIONAL, CALLBACK, OTHER, DebugLinkMemoryWrite, memory, address, 0), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, DebugLinkMemoryWrite, flash, memory, 0), + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkFlashErase_fields[2] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkFlashErase, sector, sector, 0), + PB_LAST_FIELD +}; + + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_FirmwareErase_FirmwareRequest_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(PublicKey, node) < 256 && pb_membersize(GetAddress, multisig) < 256 && pb_membersize(LoadDevice, node) < 256 && pb_membersize(TxRequest, details) < 256 && pb_membersize(TxRequest, serialized) < 256 && pb_membersize(TxAck, tx) < 256 && pb_membersize(SignIdentity, identity) < 256 && pb_membersize(GetECDHSessionKey, identity) < 256 && pb_membersize(DebugLinkState, node) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_FirmwareErase_FirmwareRequest_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/micropython/bootloader/protob/messages.pb.h b/micropython/bootloader/protob/messages.pb.h new file mode 100644 index 000000000..b233aeac2 --- /dev/null +++ b/micropython/bootloader/protob/messages.pb.h @@ -0,0 +1,1099 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.8 */ + +#ifndef PB_MESSAGES_PB_H_INCLUDED +#define PB_MESSAGES_PB_H_INCLUDED +#include + +#include "types.pb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Enum definitions */ +typedef enum _MessageType { + MessageType_MessageType_Initialize = 0, + MessageType_MessageType_Ping = 1, + MessageType_MessageType_Success = 2, + MessageType_MessageType_Failure = 3, + MessageType_MessageType_ChangePin = 4, + MessageType_MessageType_WipeDevice = 5, + MessageType_MessageType_FirmwareErase = 6, + MessageType_MessageType_FirmwareUpload = 7, + MessageType_MessageType_FirmwareRequest = 8, + MessageType_MessageType_GetEntropy = 9, + MessageType_MessageType_Entropy = 10, + MessageType_MessageType_GetPublicKey = 11, + MessageType_MessageType_PublicKey = 12, + MessageType_MessageType_LoadDevice = 13, + MessageType_MessageType_ResetDevice = 14, + MessageType_MessageType_SignTx = 15, + MessageType_MessageType_SimpleSignTx = 16, + MessageType_MessageType_Features = 17, + MessageType_MessageType_PinMatrixRequest = 18, + MessageType_MessageType_PinMatrixAck = 19, + MessageType_MessageType_Cancel = 20, + MessageType_MessageType_TxRequest = 21, + MessageType_MessageType_TxAck = 22, + MessageType_MessageType_CipherKeyValue = 23, + MessageType_MessageType_ClearSession = 24, + MessageType_MessageType_ApplySettings = 25, + MessageType_MessageType_ButtonRequest = 26, + MessageType_MessageType_ButtonAck = 27, + MessageType_MessageType_GetAddress = 29, + MessageType_MessageType_Address = 30, + MessageType_MessageType_EntropyRequest = 35, + MessageType_MessageType_EntropyAck = 36, + MessageType_MessageType_SignMessage = 38, + MessageType_MessageType_VerifyMessage = 39, + MessageType_MessageType_MessageSignature = 40, + MessageType_MessageType_PassphraseRequest = 41, + MessageType_MessageType_PassphraseAck = 42, + MessageType_MessageType_EstimateTxSize = 43, + MessageType_MessageType_TxSize = 44, + MessageType_MessageType_RecoveryDevice = 45, + MessageType_MessageType_WordRequest = 46, + MessageType_MessageType_WordAck = 47, + MessageType_MessageType_CipheredKeyValue = 48, + MessageType_MessageType_EncryptMessage = 49, + MessageType_MessageType_EncryptedMessage = 50, + MessageType_MessageType_DecryptMessage = 51, + MessageType_MessageType_DecryptedMessage = 52, + MessageType_MessageType_SignIdentity = 53, + MessageType_MessageType_SignedIdentity = 54, + MessageType_MessageType_GetFeatures = 55, + MessageType_MessageType_EthereumGetAddress = 56, + MessageType_MessageType_EthereumAddress = 57, + MessageType_MessageType_EthereumSignTx = 58, + MessageType_MessageType_EthereumTxRequest = 59, + MessageType_MessageType_EthereumTxAck = 60, + MessageType_MessageType_GetECDHSessionKey = 61, + MessageType_MessageType_ECDHSessionKey = 62, + MessageType_MessageType_SetU2FCounter = 63, + MessageType_MessageType_DebugLinkDecision = 100, + MessageType_MessageType_DebugLinkGetState = 101, + MessageType_MessageType_DebugLinkState = 102, + MessageType_MessageType_DebugLinkStop = 103, + MessageType_MessageType_DebugLinkLog = 104, + MessageType_MessageType_DebugLinkMemoryRead = 110, + MessageType_MessageType_DebugLinkMemory = 111, + MessageType_MessageType_DebugLinkMemoryWrite = 112, + MessageType_MessageType_DebugLinkFlashErase = 113 +} MessageType; +#define _MessageType_MIN MessageType_MessageType_Initialize +#define _MessageType_MAX MessageType_MessageType_DebugLinkFlashErase +#define _MessageType_ARRAYSIZE ((MessageType)(MessageType_MessageType_DebugLinkFlashErase+1)) + +/* Struct definitions */ +typedef struct _Address { + pb_callback_t address; +/* @@protoc_insertion_point(struct:Address) */ +} Address; + +typedef struct _ButtonAck { + char dummy_field; +/* @@protoc_insertion_point(struct:ButtonAck) */ +} ButtonAck; + +typedef struct _Cancel { + char dummy_field; +/* @@protoc_insertion_point(struct:Cancel) */ +} Cancel; + +typedef struct _CipheredKeyValue { + pb_callback_t value; +/* @@protoc_insertion_point(struct:CipheredKeyValue) */ +} CipheredKeyValue; + +typedef struct _ClearSession { + char dummy_field; +/* @@protoc_insertion_point(struct:ClearSession) */ +} ClearSession; + +typedef struct _DebugLinkGetState { + char dummy_field; +/* @@protoc_insertion_point(struct:DebugLinkGetState) */ +} DebugLinkGetState; + +typedef struct _DebugLinkMemory { + pb_callback_t memory; +/* @@protoc_insertion_point(struct:DebugLinkMemory) */ +} DebugLinkMemory; + +typedef struct _DebugLinkStop { + char dummy_field; +/* @@protoc_insertion_point(struct:DebugLinkStop) */ +} DebugLinkStop; + +typedef struct _DecryptMessage { + pb_callback_t address_n; + pb_callback_t nonce; + pb_callback_t message; + pb_callback_t hmac; +/* @@protoc_insertion_point(struct:DecryptMessage) */ +} DecryptMessage; + +typedef struct _DecryptedMessage { + pb_callback_t message; + pb_callback_t address; +/* @@protoc_insertion_point(struct:DecryptedMessage) */ +} DecryptedMessage; + +typedef struct _ECDHSessionKey { + pb_callback_t session_key; +/* @@protoc_insertion_point(struct:ECDHSessionKey) */ +} ECDHSessionKey; + +typedef struct _EncryptedMessage { + pb_callback_t nonce; + pb_callback_t message; + pb_callback_t hmac; +/* @@protoc_insertion_point(struct:EncryptedMessage) */ +} EncryptedMessage; + +typedef struct _Entropy { + pb_callback_t entropy; +/* @@protoc_insertion_point(struct:Entropy) */ +} Entropy; + +typedef struct _EntropyAck { + pb_callback_t entropy; +/* @@protoc_insertion_point(struct:EntropyAck) */ +} EntropyAck; + +typedef struct _EntropyRequest { + char dummy_field; +/* @@protoc_insertion_point(struct:EntropyRequest) */ +} EntropyRequest; + +typedef struct _EthereumAddress { + pb_callback_t address; +/* @@protoc_insertion_point(struct:EthereumAddress) */ +} EthereumAddress; + +typedef struct _EthereumTxAck { + pb_callback_t data_chunk; +/* @@protoc_insertion_point(struct:EthereumTxAck) */ +} EthereumTxAck; + +typedef struct _FirmwareErase { + char dummy_field; +/* @@protoc_insertion_point(struct:FirmwareErase) */ +} FirmwareErase; + +typedef struct _FirmwareUpload { + pb_callback_t payload; + pb_callback_t hash; +/* @@protoc_insertion_point(struct:FirmwareUpload) */ +} FirmwareUpload; + +typedef struct _GetFeatures { + char dummy_field; +/* @@protoc_insertion_point(struct:GetFeatures) */ +} GetFeatures; + +typedef struct _Initialize { + char dummy_field; +/* @@protoc_insertion_point(struct:Initialize) */ +} Initialize; + +typedef struct _MessageSignature { + pb_callback_t address; + pb_callback_t signature; +/* @@protoc_insertion_point(struct:MessageSignature) */ +} MessageSignature; + +typedef struct _PassphraseAck { + pb_callback_t passphrase; +/* @@protoc_insertion_point(struct:PassphraseAck) */ +} PassphraseAck; + +typedef struct _PassphraseRequest { + char dummy_field; +/* @@protoc_insertion_point(struct:PassphraseRequest) */ +} PassphraseRequest; + +typedef struct _PinMatrixAck { + pb_callback_t pin; +/* @@protoc_insertion_point(struct:PinMatrixAck) */ +} PinMatrixAck; + +typedef struct _SignMessage { + pb_callback_t address_n; + pb_callback_t message; + pb_callback_t coin_name; +/* @@protoc_insertion_point(struct:SignMessage) */ +} SignMessage; + +typedef struct _SignedIdentity { + pb_callback_t address; + pb_callback_t public_key; + pb_callback_t signature; +/* @@protoc_insertion_point(struct:SignedIdentity) */ +} SignedIdentity; + +typedef struct _Success { + pb_callback_t message; +/* @@protoc_insertion_point(struct:Success) */ +} Success; + +typedef struct _VerifyMessage { + pb_callback_t address; + pb_callback_t signature; + pb_callback_t message; + pb_callback_t coin_name; +/* @@protoc_insertion_point(struct:VerifyMessage) */ +} VerifyMessage; + +typedef struct _WipeDevice { + char dummy_field; +/* @@protoc_insertion_point(struct:WipeDevice) */ +} WipeDevice; + +typedef struct _WordAck { + pb_callback_t word; +/* @@protoc_insertion_point(struct:WordAck) */ +} WordAck; + +typedef struct _ApplySettings { + pb_callback_t language; + pb_callback_t label; + bool has_use_passphrase; + bool use_passphrase; + pb_callback_t homescreen; +/* @@protoc_insertion_point(struct:ApplySettings) */ +} ApplySettings; + +typedef struct _ButtonRequest { + bool has_code; + ButtonRequestType code; + pb_callback_t data; +/* @@protoc_insertion_point(struct:ButtonRequest) */ +} ButtonRequest; + +typedef struct _ChangePin { + bool has_remove; + bool remove; +/* @@protoc_insertion_point(struct:ChangePin) */ +} ChangePin; + +typedef struct _CipherKeyValue { + pb_callback_t address_n; + pb_callback_t key; + pb_callback_t value; + bool has_encrypt; + bool encrypt; + bool has_ask_on_encrypt; + bool ask_on_encrypt; + bool has_ask_on_decrypt; + bool ask_on_decrypt; + pb_callback_t iv; +/* @@protoc_insertion_point(struct:CipherKeyValue) */ +} CipherKeyValue; + +typedef struct _DebugLinkDecision { + bool yes_no; +/* @@protoc_insertion_point(struct:DebugLinkDecision) */ +} DebugLinkDecision; + +typedef struct _DebugLinkFlashErase { + bool has_sector; + uint32_t sector; +/* @@protoc_insertion_point(struct:DebugLinkFlashErase) */ +} DebugLinkFlashErase; + +typedef struct _DebugLinkLog { + bool has_level; + uint32_t level; + pb_callback_t bucket; + pb_callback_t text; +/* @@protoc_insertion_point(struct:DebugLinkLog) */ +} DebugLinkLog; + +typedef struct _DebugLinkMemoryRead { + bool has_address; + uint32_t address; + bool has_length; + uint32_t length; +/* @@protoc_insertion_point(struct:DebugLinkMemoryRead) */ +} DebugLinkMemoryRead; + +typedef struct _DebugLinkMemoryWrite { + bool has_address; + uint32_t address; + pb_callback_t memory; + bool has_flash; + bool flash; +/* @@protoc_insertion_point(struct:DebugLinkMemoryWrite) */ +} DebugLinkMemoryWrite; + +typedef struct _DebugLinkState { + pb_callback_t layout; + pb_callback_t pin; + pb_callback_t matrix; + pb_callback_t mnemonic; + bool has_node; + HDNodeType node; + bool has_passphrase_protection; + bool passphrase_protection; + pb_callback_t reset_word; + pb_callback_t reset_entropy; + pb_callback_t recovery_fake_word; + bool has_recovery_word_pos; + uint32_t recovery_word_pos; +/* @@protoc_insertion_point(struct:DebugLinkState) */ +} DebugLinkState; + +typedef struct _EncryptMessage { + pb_callback_t pubkey; + pb_callback_t message; + bool has_display_only; + bool display_only; + pb_callback_t address_n; + pb_callback_t coin_name; +/* @@protoc_insertion_point(struct:EncryptMessage) */ +} EncryptMessage; + +typedef struct _EstimateTxSize { + uint32_t outputs_count; + uint32_t inputs_count; + pb_callback_t coin_name; +/* @@protoc_insertion_point(struct:EstimateTxSize) */ +} EstimateTxSize; + +typedef struct _EthereumGetAddress { + pb_callback_t address_n; + bool has_show_display; + bool show_display; +/* @@protoc_insertion_point(struct:EthereumGetAddress) */ +} EthereumGetAddress; + +typedef struct _EthereumSignTx { + pb_callback_t address_n; + pb_callback_t nonce; + pb_callback_t gas_price; + pb_callback_t gas_limit; + pb_callback_t to; + pb_callback_t value; + pb_callback_t data_initial_chunk; + bool has_data_length; + uint32_t data_length; + bool has_chain_id; + uint32_t chain_id; +/* @@protoc_insertion_point(struct:EthereumSignTx) */ +} EthereumSignTx; + +typedef struct _EthereumTxRequest { + bool has_data_length; + uint32_t data_length; + bool has_signature_v; + uint32_t signature_v; + pb_callback_t signature_r; + pb_callback_t signature_s; +/* @@protoc_insertion_point(struct:EthereumTxRequest) */ +} EthereumTxRequest; + +typedef struct _Failure { + bool has_code; + FailureType code; + pb_callback_t message; +/* @@protoc_insertion_point(struct:Failure) */ +} Failure; + +typedef struct _Features { + pb_callback_t vendor; + bool has_major_version; + uint32_t major_version; + bool has_minor_version; + uint32_t minor_version; + bool has_patch_version; + uint32_t patch_version; + bool has_bootloader_mode; + bool bootloader_mode; + pb_callback_t device_id; + bool has_pin_protection; + bool pin_protection; + bool has_passphrase_protection; + bool passphrase_protection; + pb_callback_t language; + pb_callback_t label; + pb_callback_t coins; + bool has_initialized; + bool initialized; + pb_callback_t revision; + pb_callback_t bootloader_hash; + bool has_imported; + bool imported; + bool has_pin_cached; + bool pin_cached; + bool has_passphrase_cached; + bool passphrase_cached; + bool has_firmware_present; + bool firmware_present; +/* @@protoc_insertion_point(struct:Features) */ +} Features; + +typedef struct _FirmwareRequest { + bool has_offset; + uint32_t offset; + bool has_length; + uint32_t length; +/* @@protoc_insertion_point(struct:FirmwareRequest) */ +} FirmwareRequest; + +typedef struct _GetAddress { + pb_callback_t address_n; + pb_callback_t coin_name; + bool has_show_display; + bool show_display; + bool has_multisig; + MultisigRedeemScriptType multisig; + bool has_script_type; + InputScriptType script_type; +/* @@protoc_insertion_point(struct:GetAddress) */ +} GetAddress; + +typedef struct _GetECDHSessionKey { + bool has_identity; + IdentityType identity; + pb_callback_t peer_public_key; + pb_callback_t ecdsa_curve_name; +/* @@protoc_insertion_point(struct:GetECDHSessionKey) */ +} GetECDHSessionKey; + +typedef struct _GetEntropy { + uint32_t size; +/* @@protoc_insertion_point(struct:GetEntropy) */ +} GetEntropy; + +typedef struct _GetPublicKey { + pb_callback_t address_n; + pb_callback_t ecdsa_curve_name; + bool has_show_display; + bool show_display; + pb_callback_t coin_name; +/* @@protoc_insertion_point(struct:GetPublicKey) */ +} GetPublicKey; + +typedef struct _LoadDevice { + pb_callback_t mnemonic; + bool has_node; + HDNodeType node; + pb_callback_t pin; + bool has_passphrase_protection; + bool passphrase_protection; + pb_callback_t language; + pb_callback_t label; + bool has_skip_checksum; + bool skip_checksum; + bool has_u2f_counter; + uint32_t u2f_counter; +/* @@protoc_insertion_point(struct:LoadDevice) */ +} LoadDevice; + +typedef struct _PinMatrixRequest { + bool has_type; + PinMatrixRequestType type; +/* @@protoc_insertion_point(struct:PinMatrixRequest) */ +} PinMatrixRequest; + +typedef struct _Ping { + pb_callback_t message; + bool has_button_protection; + bool button_protection; + bool has_pin_protection; + bool pin_protection; + bool has_passphrase_protection; + bool passphrase_protection; +/* @@protoc_insertion_point(struct:Ping) */ +} Ping; + +typedef struct _PublicKey { + HDNodeType node; + pb_callback_t xpub; +/* @@protoc_insertion_point(struct:PublicKey) */ +} PublicKey; + +typedef struct _RecoveryDevice { + bool has_word_count; + uint32_t word_count; + bool has_passphrase_protection; + bool passphrase_protection; + bool has_pin_protection; + bool pin_protection; + pb_callback_t language; + pb_callback_t label; + bool has_enforce_wordlist; + bool enforce_wordlist; + bool has_type; + uint32_t type; + bool has_u2f_counter; + uint32_t u2f_counter; +/* @@protoc_insertion_point(struct:RecoveryDevice) */ +} RecoveryDevice; + +typedef struct _ResetDevice { + bool has_display_random; + bool display_random; + bool has_strength; + uint32_t strength; + bool has_passphrase_protection; + bool passphrase_protection; + bool has_pin_protection; + bool pin_protection; + pb_callback_t language; + pb_callback_t label; + bool has_u2f_counter; + uint32_t u2f_counter; +/* @@protoc_insertion_point(struct:ResetDevice) */ +} ResetDevice; + +typedef struct _SetU2FCounter { + bool has_u2f_counter; + uint32_t u2f_counter; +/* @@protoc_insertion_point(struct:SetU2FCounter) */ +} SetU2FCounter; + +typedef struct _SignIdentity { + bool has_identity; + IdentityType identity; + pb_callback_t challenge_hidden; + pb_callback_t challenge_visual; + pb_callback_t ecdsa_curve_name; +/* @@protoc_insertion_point(struct:SignIdentity) */ +} SignIdentity; + +typedef struct _SignTx { + uint32_t outputs_count; + uint32_t inputs_count; + pb_callback_t coin_name; + bool has_version; + uint32_t version; + bool has_lock_time; + uint32_t lock_time; +/* @@protoc_insertion_point(struct:SignTx) */ +} SignTx; + +typedef struct _SimpleSignTx { + pb_callback_t inputs; + pb_callback_t outputs; + pb_callback_t transactions; + pb_callback_t coin_name; + bool has_version; + uint32_t version; + bool has_lock_time; + uint32_t lock_time; +/* @@protoc_insertion_point(struct:SimpleSignTx) */ +} SimpleSignTx; + +typedef struct _TxAck { + bool has_tx; + TransactionType tx; +/* @@protoc_insertion_point(struct:TxAck) */ +} TxAck; + +typedef struct _TxRequest { + bool has_request_type; + RequestType request_type; + bool has_details; + TxRequestDetailsType details; + bool has_serialized; + TxRequestSerializedType serialized; +/* @@protoc_insertion_point(struct:TxRequest) */ +} TxRequest; + +typedef struct _TxSize { + bool has_tx_size; + uint32_t tx_size; +/* @@protoc_insertion_point(struct:TxSize) */ +} TxSize; + +typedef struct _WordRequest { + bool has_type; + WordRequestType type; +/* @@protoc_insertion_point(struct:WordRequest) */ +} WordRequest; + +/* Default values for struct fields */ +extern const InputScriptType GetAddress_script_type_default; +extern const uint32_t ResetDevice_strength_default; +extern const uint32_t SignTx_version_default; +extern const uint32_t SignTx_lock_time_default; +extern const uint32_t SimpleSignTx_version_default; +extern const uint32_t SimpleSignTx_lock_time_default; + +/* Initializer values for message structs */ +#define Initialize_init_default {0} +#define GetFeatures_init_default {0} +#define Features_init_default {{{NULL}, NULL}, false, 0, false, 0, false, 0, false, 0, {{NULL}, NULL}, false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0, false, 0, false, 0} +#define ClearSession_init_default {0} +#define ApplySettings_init_default {{{NULL}, NULL}, {{NULL}, NULL}, false, 0, {{NULL}, NULL}} +#define ChangePin_init_default {false, 0} +#define Ping_init_default {{{NULL}, NULL}, false, 0, false, 0, false, 0} +#define Success_init_default {{{NULL}, NULL}} +#define Failure_init_default {false, (FailureType)0, {{NULL}, NULL}} +#define ButtonRequest_init_default {false, (ButtonRequestType)0, {{NULL}, NULL}} +#define ButtonAck_init_default {0} +#define PinMatrixRequest_init_default {false, (PinMatrixRequestType)0} +#define PinMatrixAck_init_default {{{NULL}, NULL}} +#define Cancel_init_default {0} +#define PassphraseRequest_init_default {0} +#define PassphraseAck_init_default {{{NULL}, NULL}} +#define GetEntropy_init_default {0} +#define Entropy_init_default {{{NULL}, NULL}} +#define GetPublicKey_init_default {{{NULL}, NULL}, {{NULL}, NULL}, false, 0, {{NULL}, NULL}} +#define PublicKey_init_default {HDNodeType_init_default, {{NULL}, NULL}} +#define GetAddress_init_default {{{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, MultisigRedeemScriptType_init_default, false, InputScriptType_SPENDADDRESS} +#define EthereumGetAddress_init_default {{{NULL}, NULL}, false, 0} +#define Address_init_default {{{NULL}, NULL}} +#define EthereumAddress_init_default {{{NULL}, NULL}} +#define WipeDevice_init_default {0} +#define LoadDevice_init_default {{{NULL}, NULL}, false, HDNodeType_init_default, {{NULL}, NULL}, false, 0, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0} +#define ResetDevice_init_default {false, 0, false, 256u, false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}, false, 0} +#define EntropyRequest_init_default {0} +#define EntropyAck_init_default {{{NULL}, NULL}} +#define RecoveryDevice_init_default {false, 0, false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0, false, 0} +#define WordRequest_init_default {false, (WordRequestType)0} +#define WordAck_init_default {{{NULL}, NULL}} +#define SignMessage_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define VerifyMessage_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define MessageSignature_init_default {{{NULL}, NULL}, {{NULL}, NULL}} +#define EncryptMessage_init_default {{{NULL}, NULL}, {{NULL}, NULL}, false, 0, {{NULL}, NULL}, {{NULL}, NULL}} +#define EncryptedMessage_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define DecryptMessage_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define DecryptedMessage_init_default {{{NULL}, NULL}, {{NULL}, NULL}} +#define CipherKeyValue_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0, false, 0, {{NULL}, NULL}} +#define CipheredKeyValue_init_default {{{NULL}, NULL}} +#define EstimateTxSize_init_default {0, 0, {{NULL}, NULL}} +#define TxSize_init_default {false, 0} +#define SignTx_init_default {0, 0, {{NULL}, NULL}, false, 1u, false, 0u} +#define SimpleSignTx_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 1u, false, 0u} +#define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default} +#define TxAck_init_default {false, TransactionType_init_default} +#define EthereumSignTx_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0} +#define EthereumTxRequest_init_default {false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}} +#define EthereumTxAck_init_default {{{NULL}, NULL}} +#define SignIdentity_init_default {false, IdentityType_init_default, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define SignedIdentity_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define GetECDHSessionKey_init_default {false, IdentityType_init_default, {{NULL}, NULL}, {{NULL}, NULL}} +#define ECDHSessionKey_init_default {{{NULL}, NULL}} +#define SetU2FCounter_init_default {false, 0} +#define FirmwareErase_init_default {0} +#define FirmwareRequest_init_default {false, 0, false, 0} +#define FirmwareUpload_init_default {{{NULL}, NULL}, {{NULL}, NULL}} +#define DebugLinkDecision_init_default {0} +#define DebugLinkGetState_init_default {0} +#define DebugLinkState_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, HDNodeType_init_default, false, 0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0} +#define DebugLinkStop_init_default {0} +#define DebugLinkLog_init_default {false, 0, {{NULL}, NULL}, {{NULL}, NULL}} +#define DebugLinkMemoryRead_init_default {false, 0, false, 0} +#define DebugLinkMemory_init_default {{{NULL}, NULL}} +#define DebugLinkMemoryWrite_init_default {false, 0, {{NULL}, NULL}, false, 0} +#define DebugLinkFlashErase_init_default {false, 0} +#define Initialize_init_zero {0} +#define GetFeatures_init_zero {0} +#define Features_init_zero {{{NULL}, NULL}, false, 0, false, 0, false, 0, false, 0, {{NULL}, NULL}, false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0, false, 0, false, 0} +#define ClearSession_init_zero {0} +#define ApplySettings_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, false, 0, {{NULL}, NULL}} +#define ChangePin_init_zero {false, 0} +#define Ping_init_zero {{{NULL}, NULL}, false, 0, false, 0, false, 0} +#define Success_init_zero {{{NULL}, NULL}} +#define Failure_init_zero {false, (FailureType)0, {{NULL}, NULL}} +#define ButtonRequest_init_zero {false, (ButtonRequestType)0, {{NULL}, NULL}} +#define ButtonAck_init_zero {0} +#define PinMatrixRequest_init_zero {false, (PinMatrixRequestType)0} +#define PinMatrixAck_init_zero {{{NULL}, NULL}} +#define Cancel_init_zero {0} +#define PassphraseRequest_init_zero {0} +#define PassphraseAck_init_zero {{{NULL}, NULL}} +#define GetEntropy_init_zero {0} +#define Entropy_init_zero {{{NULL}, NULL}} +#define GetPublicKey_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, false, 0, {{NULL}, NULL}} +#define PublicKey_init_zero {HDNodeType_init_zero, {{NULL}, NULL}} +#define GetAddress_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, MultisigRedeemScriptType_init_zero, false, (InputScriptType)0} +#define EthereumGetAddress_init_zero {{{NULL}, NULL}, false, 0} +#define Address_init_zero {{{NULL}, NULL}} +#define EthereumAddress_init_zero {{{NULL}, NULL}} +#define WipeDevice_init_zero {0} +#define LoadDevice_init_zero {{{NULL}, NULL}, false, HDNodeType_init_zero, {{NULL}, NULL}, false, 0, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0} +#define ResetDevice_init_zero {false, 0, false, 0, false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}, false, 0} +#define EntropyRequest_init_zero {0} +#define EntropyAck_init_zero {{{NULL}, NULL}} +#define RecoveryDevice_init_zero {false, 0, false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0, false, 0} +#define WordRequest_init_zero {false, (WordRequestType)0} +#define WordAck_init_zero {{{NULL}, NULL}} +#define SignMessage_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define VerifyMessage_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define MessageSignature_init_zero {{{NULL}, NULL}, {{NULL}, NULL}} +#define EncryptMessage_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, false, 0, {{NULL}, NULL}, {{NULL}, NULL}} +#define EncryptedMessage_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define DecryptMessage_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define DecryptedMessage_init_zero {{{NULL}, NULL}, {{NULL}, NULL}} +#define CipherKeyValue_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0, false, 0, {{NULL}, NULL}} +#define CipheredKeyValue_init_zero {{{NULL}, NULL}} +#define EstimateTxSize_init_zero {0, 0, {{NULL}, NULL}} +#define TxSize_init_zero {false, 0} +#define SignTx_init_zero {0, 0, {{NULL}, NULL}, false, 0, false, 0} +#define SimpleSignTx_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0} +#define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero} +#define TxAck_init_zero {false, TransactionType_init_zero} +#define EthereumSignTx_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0} +#define EthereumTxRequest_init_zero {false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}} +#define EthereumTxAck_init_zero {{{NULL}, NULL}} +#define SignIdentity_init_zero {false, IdentityType_init_zero, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define SignedIdentity_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define GetECDHSessionKey_init_zero {false, IdentityType_init_zero, {{NULL}, NULL}, {{NULL}, NULL}} +#define ECDHSessionKey_init_zero {{{NULL}, NULL}} +#define SetU2FCounter_init_zero {false, 0} +#define FirmwareErase_init_zero {0} +#define FirmwareRequest_init_zero {false, 0, false, 0} +#define FirmwareUpload_init_zero {{{NULL}, NULL}, {{NULL}, NULL}} +#define DebugLinkDecision_init_zero {0} +#define DebugLinkGetState_init_zero {0} +#define DebugLinkState_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, HDNodeType_init_zero, false, 0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0} +#define DebugLinkStop_init_zero {0} +#define DebugLinkLog_init_zero {false, 0, {{NULL}, NULL}, {{NULL}, NULL}} +#define DebugLinkMemoryRead_init_zero {false, 0, false, 0} +#define DebugLinkMemory_init_zero {{{NULL}, NULL}} +#define DebugLinkMemoryWrite_init_zero {false, 0, {{NULL}, NULL}, false, 0} +#define DebugLinkFlashErase_init_zero {false, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define Address_address_tag 1 +#define CipheredKeyValue_value_tag 1 +#define DebugLinkMemory_memory_tag 1 +#define DecryptMessage_address_n_tag 1 +#define DecryptMessage_nonce_tag 2 +#define DecryptMessage_message_tag 3 +#define DecryptMessage_hmac_tag 4 +#define DecryptedMessage_message_tag 1 +#define DecryptedMessage_address_tag 2 +#define ECDHSessionKey_session_key_tag 1 +#define EncryptedMessage_nonce_tag 1 +#define EncryptedMessage_message_tag 2 +#define EncryptedMessage_hmac_tag 3 +#define Entropy_entropy_tag 1 +#define EntropyAck_entropy_tag 1 +#define EthereumAddress_address_tag 1 +#define EthereumTxAck_data_chunk_tag 1 +#define FirmwareUpload_payload_tag 1 +#define FirmwareUpload_hash_tag 2 +#define MessageSignature_address_tag 1 +#define MessageSignature_signature_tag 2 +#define PassphraseAck_passphrase_tag 1 +#define PinMatrixAck_pin_tag 1 +#define SignMessage_address_n_tag 1 +#define SignMessage_message_tag 2 +#define SignMessage_coin_name_tag 3 +#define SignedIdentity_address_tag 1 +#define SignedIdentity_public_key_tag 2 +#define SignedIdentity_signature_tag 3 +#define Success_message_tag 1 +#define VerifyMessage_address_tag 1 +#define VerifyMessage_signature_tag 2 +#define VerifyMessage_message_tag 3 +#define VerifyMessage_coin_name_tag 4 +#define WordAck_word_tag 1 +#define ApplySettings_language_tag 1 +#define ApplySettings_label_tag 2 +#define ApplySettings_use_passphrase_tag 3 +#define ApplySettings_homescreen_tag 4 +#define ButtonRequest_code_tag 1 +#define ButtonRequest_data_tag 2 +#define ChangePin_remove_tag 1 +#define CipherKeyValue_address_n_tag 1 +#define CipherKeyValue_key_tag 2 +#define CipherKeyValue_value_tag 3 +#define CipherKeyValue_encrypt_tag 4 +#define CipherKeyValue_ask_on_encrypt_tag 5 +#define CipherKeyValue_ask_on_decrypt_tag 6 +#define CipherKeyValue_iv_tag 7 +#define DebugLinkDecision_yes_no_tag 1 +#define DebugLinkFlashErase_sector_tag 1 +#define DebugLinkLog_level_tag 1 +#define DebugLinkLog_bucket_tag 2 +#define DebugLinkLog_text_tag 3 +#define DebugLinkMemoryRead_address_tag 1 +#define DebugLinkMemoryRead_length_tag 2 +#define DebugLinkMemoryWrite_address_tag 1 +#define DebugLinkMemoryWrite_memory_tag 2 +#define DebugLinkMemoryWrite_flash_tag 3 +#define DebugLinkState_layout_tag 1 +#define DebugLinkState_pin_tag 2 +#define DebugLinkState_matrix_tag 3 +#define DebugLinkState_mnemonic_tag 4 +#define DebugLinkState_node_tag 5 +#define DebugLinkState_passphrase_protection_tag 6 +#define DebugLinkState_reset_word_tag 7 +#define DebugLinkState_reset_entropy_tag 8 +#define DebugLinkState_recovery_fake_word_tag 9 +#define DebugLinkState_recovery_word_pos_tag 10 +#define EncryptMessage_pubkey_tag 1 +#define EncryptMessage_message_tag 2 +#define EncryptMessage_display_only_tag 3 +#define EncryptMessage_address_n_tag 4 +#define EncryptMessage_coin_name_tag 5 +#define EstimateTxSize_outputs_count_tag 1 +#define EstimateTxSize_inputs_count_tag 2 +#define EstimateTxSize_coin_name_tag 3 +#define EthereumGetAddress_address_n_tag 1 +#define EthereumGetAddress_show_display_tag 2 +#define EthereumSignTx_address_n_tag 1 +#define EthereumSignTx_nonce_tag 2 +#define EthereumSignTx_gas_price_tag 3 +#define EthereumSignTx_gas_limit_tag 4 +#define EthereumSignTx_to_tag 5 +#define EthereumSignTx_value_tag 6 +#define EthereumSignTx_data_initial_chunk_tag 7 +#define EthereumSignTx_data_length_tag 8 +#define EthereumSignTx_chain_id_tag 9 +#define EthereumTxRequest_data_length_tag 1 +#define EthereumTxRequest_signature_v_tag 2 +#define EthereumTxRequest_signature_r_tag 3 +#define EthereumTxRequest_signature_s_tag 4 +#define Failure_code_tag 1 +#define Failure_message_tag 2 +#define Features_vendor_tag 1 +#define Features_major_version_tag 2 +#define Features_minor_version_tag 3 +#define Features_patch_version_tag 4 +#define Features_bootloader_mode_tag 5 +#define Features_device_id_tag 6 +#define Features_pin_protection_tag 7 +#define Features_passphrase_protection_tag 8 +#define Features_language_tag 9 +#define Features_label_tag 10 +#define Features_coins_tag 11 +#define Features_initialized_tag 12 +#define Features_revision_tag 13 +#define Features_bootloader_hash_tag 14 +#define Features_imported_tag 15 +#define Features_pin_cached_tag 16 +#define Features_passphrase_cached_tag 17 +#define Features_firmware_present_tag 18 +#define FirmwareRequest_offset_tag 1 +#define FirmwareRequest_length_tag 2 +#define GetAddress_address_n_tag 1 +#define GetAddress_coin_name_tag 2 +#define GetAddress_show_display_tag 3 +#define GetAddress_multisig_tag 4 +#define GetAddress_script_type_tag 5 +#define GetECDHSessionKey_identity_tag 1 +#define GetECDHSessionKey_peer_public_key_tag 2 +#define GetECDHSessionKey_ecdsa_curve_name_tag 3 +#define GetEntropy_size_tag 1 +#define GetPublicKey_address_n_tag 1 +#define GetPublicKey_ecdsa_curve_name_tag 2 +#define GetPublicKey_show_display_tag 3 +#define GetPublicKey_coin_name_tag 4 +#define LoadDevice_mnemonic_tag 1 +#define LoadDevice_node_tag 2 +#define LoadDevice_pin_tag 3 +#define LoadDevice_passphrase_protection_tag 4 +#define LoadDevice_language_tag 5 +#define LoadDevice_label_tag 6 +#define LoadDevice_skip_checksum_tag 7 +#define LoadDevice_u2f_counter_tag 8 +#define PinMatrixRequest_type_tag 1 +#define Ping_message_tag 1 +#define Ping_button_protection_tag 2 +#define Ping_pin_protection_tag 3 +#define Ping_passphrase_protection_tag 4 +#define PublicKey_node_tag 1 +#define PublicKey_xpub_tag 2 +#define RecoveryDevice_word_count_tag 1 +#define RecoveryDevice_passphrase_protection_tag 2 +#define RecoveryDevice_pin_protection_tag 3 +#define RecoveryDevice_language_tag 4 +#define RecoveryDevice_label_tag 5 +#define RecoveryDevice_enforce_wordlist_tag 6 +#define RecoveryDevice_type_tag 8 +#define RecoveryDevice_u2f_counter_tag 9 +#define ResetDevice_display_random_tag 1 +#define ResetDevice_strength_tag 2 +#define ResetDevice_passphrase_protection_tag 3 +#define ResetDevice_pin_protection_tag 4 +#define ResetDevice_language_tag 5 +#define ResetDevice_label_tag 6 +#define ResetDevice_u2f_counter_tag 7 +#define SetU2FCounter_u2f_counter_tag 1 +#define SignIdentity_identity_tag 1 +#define SignIdentity_challenge_hidden_tag 2 +#define SignIdentity_challenge_visual_tag 3 +#define SignIdentity_ecdsa_curve_name_tag 4 +#define SignTx_outputs_count_tag 1 +#define SignTx_inputs_count_tag 2 +#define SignTx_coin_name_tag 3 +#define SignTx_version_tag 4 +#define SignTx_lock_time_tag 5 +#define SimpleSignTx_inputs_tag 1 +#define SimpleSignTx_outputs_tag 2 +#define SimpleSignTx_transactions_tag 3 +#define SimpleSignTx_coin_name_tag 4 +#define SimpleSignTx_version_tag 5 +#define SimpleSignTx_lock_time_tag 6 +#define TxAck_tx_tag 1 +#define TxRequest_request_type_tag 1 +#define TxRequest_details_tag 2 +#define TxRequest_serialized_tag 3 +#define TxSize_tx_size_tag 1 +#define WordRequest_type_tag 1 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t Initialize_fields[1]; +extern const pb_field_t GetFeatures_fields[1]; +extern const pb_field_t Features_fields[19]; +extern const pb_field_t ClearSession_fields[1]; +extern const pb_field_t ApplySettings_fields[5]; +extern const pb_field_t ChangePin_fields[2]; +extern const pb_field_t Ping_fields[5]; +extern const pb_field_t Success_fields[2]; +extern const pb_field_t Failure_fields[3]; +extern const pb_field_t ButtonRequest_fields[3]; +extern const pb_field_t ButtonAck_fields[1]; +extern const pb_field_t PinMatrixRequest_fields[2]; +extern const pb_field_t PinMatrixAck_fields[2]; +extern const pb_field_t Cancel_fields[1]; +extern const pb_field_t PassphraseRequest_fields[1]; +extern const pb_field_t PassphraseAck_fields[2]; +extern const pb_field_t GetEntropy_fields[2]; +extern const pb_field_t Entropy_fields[2]; +extern const pb_field_t GetPublicKey_fields[5]; +extern const pb_field_t PublicKey_fields[3]; +extern const pb_field_t GetAddress_fields[6]; +extern const pb_field_t EthereumGetAddress_fields[3]; +extern const pb_field_t Address_fields[2]; +extern const pb_field_t EthereumAddress_fields[2]; +extern const pb_field_t WipeDevice_fields[1]; +extern const pb_field_t LoadDevice_fields[9]; +extern const pb_field_t ResetDevice_fields[8]; +extern const pb_field_t EntropyRequest_fields[1]; +extern const pb_field_t EntropyAck_fields[2]; +extern const pb_field_t RecoveryDevice_fields[9]; +extern const pb_field_t WordRequest_fields[2]; +extern const pb_field_t WordAck_fields[2]; +extern const pb_field_t SignMessage_fields[4]; +extern const pb_field_t VerifyMessage_fields[5]; +extern const pb_field_t MessageSignature_fields[3]; +extern const pb_field_t EncryptMessage_fields[6]; +extern const pb_field_t EncryptedMessage_fields[4]; +extern const pb_field_t DecryptMessage_fields[5]; +extern const pb_field_t DecryptedMessage_fields[3]; +extern const pb_field_t CipherKeyValue_fields[8]; +extern const pb_field_t CipheredKeyValue_fields[2]; +extern const pb_field_t EstimateTxSize_fields[4]; +extern const pb_field_t TxSize_fields[2]; +extern const pb_field_t SignTx_fields[6]; +extern const pb_field_t SimpleSignTx_fields[7]; +extern const pb_field_t TxRequest_fields[4]; +extern const pb_field_t TxAck_fields[2]; +extern const pb_field_t EthereumSignTx_fields[10]; +extern const pb_field_t EthereumTxRequest_fields[5]; +extern const pb_field_t EthereumTxAck_fields[2]; +extern const pb_field_t SignIdentity_fields[5]; +extern const pb_field_t SignedIdentity_fields[4]; +extern const pb_field_t GetECDHSessionKey_fields[4]; +extern const pb_field_t ECDHSessionKey_fields[2]; +extern const pb_field_t SetU2FCounter_fields[2]; +extern const pb_field_t FirmwareErase_fields[1]; +extern const pb_field_t FirmwareRequest_fields[3]; +extern const pb_field_t FirmwareUpload_fields[3]; +extern const pb_field_t DebugLinkDecision_fields[2]; +extern const pb_field_t DebugLinkGetState_fields[1]; +extern const pb_field_t DebugLinkState_fields[11]; +extern const pb_field_t DebugLinkStop_fields[1]; +extern const pb_field_t DebugLinkLog_fields[4]; +extern const pb_field_t DebugLinkMemoryRead_fields[3]; +extern const pb_field_t DebugLinkMemory_fields[2]; +extern const pb_field_t DebugLinkMemoryWrite_fields[4]; +extern const pb_field_t DebugLinkFlashErase_fields[2]; + +/* Maximum encoded size of messages (where known) */ +#define Initialize_size 0 +#define GetFeatures_size 0 +/* Features_size depends on runtime parameters */ +#define ClearSession_size 0 +/* ApplySettings_size depends on runtime parameters */ +#define ChangePin_size 2 +/* Ping_size depends on runtime parameters */ +/* Success_size depends on runtime parameters */ +/* Failure_size depends on runtime parameters */ +/* ButtonRequest_size depends on runtime parameters */ +#define ButtonAck_size 0 +#define PinMatrixRequest_size 11 +/* PinMatrixAck_size depends on runtime parameters */ +#define Cancel_size 0 +#define PassphraseRequest_size 0 +/* PassphraseAck_size depends on runtime parameters */ +#define GetEntropy_size 6 +/* Entropy_size depends on runtime parameters */ +/* GetPublicKey_size depends on runtime parameters */ +/* PublicKey_size depends on runtime parameters */ +/* GetAddress_size depends on runtime parameters */ +/* EthereumGetAddress_size depends on runtime parameters */ +/* Address_size depends on runtime parameters */ +/* EthereumAddress_size depends on runtime parameters */ +#define WipeDevice_size 0 +/* LoadDevice_size depends on runtime parameters */ +/* ResetDevice_size depends on runtime parameters */ +#define EntropyRequest_size 0 +/* EntropyAck_size depends on runtime parameters */ +/* RecoveryDevice_size depends on runtime parameters */ +#define WordRequest_size 11 +/* WordAck_size depends on runtime parameters */ +/* SignMessage_size depends on runtime parameters */ +/* VerifyMessage_size depends on runtime parameters */ +/* MessageSignature_size depends on runtime parameters */ +/* EncryptMessage_size depends on runtime parameters */ +/* EncryptedMessage_size depends on runtime parameters */ +/* DecryptMessage_size depends on runtime parameters */ +/* DecryptedMessage_size depends on runtime parameters */ +/* CipherKeyValue_size depends on runtime parameters */ +/* CipheredKeyValue_size depends on runtime parameters */ +/* EstimateTxSize_size depends on runtime parameters */ +#define TxSize_size 6 +/* SignTx_size depends on runtime parameters */ +/* SimpleSignTx_size depends on runtime parameters */ +#define TxRequest_size (23 + TxRequestDetailsType_size + TxRequestSerializedType_size) +#define TxAck_size (6 + TransactionType_size) +/* EthereumSignTx_size depends on runtime parameters */ +/* EthereumTxRequest_size depends on runtime parameters */ +/* EthereumTxAck_size depends on runtime parameters */ +/* SignIdentity_size depends on runtime parameters */ +/* SignedIdentity_size depends on runtime parameters */ +/* GetECDHSessionKey_size depends on runtime parameters */ +/* ECDHSessionKey_size depends on runtime parameters */ +#define SetU2FCounter_size 6 +#define FirmwareErase_size 0 +#define FirmwareRequest_size 12 +/* FirmwareUpload_size depends on runtime parameters */ +#define DebugLinkDecision_size 2 +#define DebugLinkGetState_size 0 +/* DebugLinkState_size depends on runtime parameters */ +#define DebugLinkStop_size 0 +/* DebugLinkLog_size depends on runtime parameters */ +#define DebugLinkMemoryRead_size 12 +/* DebugLinkMemory_size depends on runtime parameters */ +/* DebugLinkMemoryWrite_size depends on runtime parameters */ +#define DebugLinkFlashErase_size 6 + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define MESSAGES_MESSAGES \ + + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/micropython/bootloader/protob/messages.proto b/micropython/bootloader/protob/messages.proto new file mode 120000 index 000000000..e98952c70 --- /dev/null +++ b/micropython/bootloader/protob/messages.proto @@ -0,0 +1 @@ +../../../vendor/trezor-common/protob/messages.proto \ No newline at end of file diff --git a/micropython/bootloader/protob/types.options b/micropython/bootloader/protob/types.options new file mode 100644 index 000000000..e69de29bb diff --git a/micropython/bootloader/protob/types.pb.c b/micropython/bootloader/protob/types.pb.c new file mode 100644 index 000000000..12c14b617 --- /dev/null +++ b/micropython/bootloader/protob/types.pb.c @@ -0,0 +1,233 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.8 */ + +#include "types.pb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +const uint32_t CoinType_address_type_default = 0u; +const uint32_t CoinType_address_type_p2sh_default = 5u; +const uint32_t CoinType_xpub_magic_default = 76067358u; +const uint32_t CoinType_xprv_magic_default = 76066276u; +const uint32_t TxInputType_sequence_default = 4294967295u; +const InputScriptType TxInputType_script_type_default = InputScriptType_SPENDADDRESS; +const uint32_t IdentityType_index_default = 0u; + + +const pb_field_t HDNodeType_fields[7] = { + PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, HDNodeType, depth, depth, 0), + PB_FIELD( 2, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, fingerprint, depth, 0), + PB_FIELD( 3, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, child_num, fingerprint, 0), + PB_FIELD( 4, BYTES , REQUIRED, CALLBACK, OTHER, HDNodeType, chain_code, child_num, 0), + PB_FIELD( 5, BYTES , OPTIONAL, CALLBACK, OTHER, HDNodeType, private_key, chain_code, 0), + PB_FIELD( 6, BYTES , OPTIONAL, CALLBACK, OTHER, HDNodeType, public_key, private_key, 0), + PB_LAST_FIELD +}; + +const pb_field_t HDNodePathType_fields[3] = { + PB_FIELD( 1, MESSAGE , REQUIRED, STATIC , FIRST, HDNodePathType, node, node, &HDNodeType_fields), + PB_FIELD( 2, UINT32 , REPEATED, CALLBACK, OTHER, HDNodePathType, address_n, node, 0), + PB_LAST_FIELD +}; + +const pb_field_t CoinType_fields[10] = { + PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, CoinType, coin_name, coin_name, 0), + PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, CoinType, coin_shortcut, coin_name, 0), + PB_FIELD( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, &CoinType_address_type_default), + PB_FIELD( 4, UINT64 , OPTIONAL, STATIC , OTHER, CoinType, maxfee_kb, address_type, 0), + PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2sh, maxfee_kb, &CoinType_address_type_p2sh_default), + PB_FIELD( 8, STRING , OPTIONAL, CALLBACK, OTHER, CoinType, signed_message_header, address_type_p2sh, 0), + PB_FIELD( 9, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, xpub_magic, signed_message_header, &CoinType_xpub_magic_default), + PB_FIELD( 10, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, xprv_magic, xpub_magic, &CoinType_xprv_magic_default), + PB_FIELD( 11, BOOL , OPTIONAL, STATIC , OTHER, CoinType, segwit, xprv_magic, 0), + PB_LAST_FIELD +}; + +const pb_field_t MultisigRedeemScriptType_fields[4] = { + PB_FIELD( 1, MESSAGE , REPEATED, CALLBACK, FIRST, MultisigRedeemScriptType, pubkeys, pubkeys, &HDNodePathType_fields), + PB_FIELD( 2, BYTES , REPEATED, CALLBACK, OTHER, MultisigRedeemScriptType, signatures, pubkeys, 0), + PB_FIELD( 3, UINT32 , OPTIONAL, STATIC , OTHER, MultisigRedeemScriptType, m, signatures, 0), + PB_LAST_FIELD +}; + +const pb_field_t TxInputType_fields[9] = { + PB_FIELD( 1, UINT32 , REPEATED, CALLBACK, FIRST, TxInputType, address_n, address_n, 0), + PB_FIELD( 2, BYTES , REQUIRED, CALLBACK, OTHER, TxInputType, prev_hash, address_n, 0), + PB_FIELD( 3, UINT32 , REQUIRED, STATIC , OTHER, TxInputType, prev_index, prev_hash, 0), + PB_FIELD( 4, BYTES , OPTIONAL, CALLBACK, OTHER, TxInputType, script_sig, prev_index, 0), + PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, TxInputType, sequence, script_sig, &TxInputType_sequence_default), + PB_FIELD( 6, UENUM , OPTIONAL, STATIC , OTHER, TxInputType, script_type, sequence, &TxInputType_script_type_default), + PB_FIELD( 7, MESSAGE , OPTIONAL, STATIC , OTHER, TxInputType, multisig, script_type, &MultisigRedeemScriptType_fields), + PB_FIELD( 8, UINT64 , OPTIONAL, STATIC , OTHER, TxInputType, amount, multisig, 0), + PB_LAST_FIELD +}; + +const pb_field_t TxOutputType_fields[7] = { + PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, TxOutputType, address, address, 0), + PB_FIELD( 2, UINT32 , REPEATED, CALLBACK, OTHER, TxOutputType, address_n, address, 0), + PB_FIELD( 3, UINT64 , REQUIRED, STATIC , OTHER, TxOutputType, amount, address_n, 0), + PB_FIELD( 4, UENUM , REQUIRED, STATIC , OTHER, TxOutputType, script_type, amount, 0), + PB_FIELD( 5, MESSAGE , OPTIONAL, STATIC , OTHER, TxOutputType, multisig, script_type, &MultisigRedeemScriptType_fields), + PB_FIELD( 6, BYTES , OPTIONAL, CALLBACK, OTHER, TxOutputType, op_return_data, multisig, 0), + PB_LAST_FIELD +}; + +const pb_field_t TxOutputBinType_fields[3] = { + PB_FIELD( 1, UINT64 , REQUIRED, STATIC , FIRST, TxOutputBinType, amount, amount, 0), + PB_FIELD( 2, BYTES , REQUIRED, CALLBACK, OTHER, TxOutputBinType, script_pubkey, amount, 0), + PB_LAST_FIELD +}; + +const pb_field_t TransactionType_fields[10] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, TransactionType, version, version, 0), + PB_FIELD( 2, MESSAGE , REPEATED, CALLBACK, OTHER, TransactionType, inputs, version, &TxInputType_fields), + PB_FIELD( 3, MESSAGE , REPEATED, CALLBACK, OTHER, TransactionType, bin_outputs, inputs, &TxOutputBinType_fields), + PB_FIELD( 4, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, lock_time, bin_outputs, 0), + PB_FIELD( 5, MESSAGE , REPEATED, CALLBACK, OTHER, TransactionType, outputs, lock_time, &TxOutputType_fields), + PB_FIELD( 6, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, inputs_cnt, outputs, 0), + PB_FIELD( 7, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, outputs_cnt, inputs_cnt, 0), + PB_FIELD( 8, BYTES , OPTIONAL, CALLBACK, OTHER, TransactionType, extra_data, outputs_cnt, 0), + PB_FIELD( 9, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, extra_data_len, extra_data, 0), + PB_LAST_FIELD +}; + +const pb_field_t TxRequestDetailsType_fields[5] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestDetailsType, request_index, request_index, 0), + PB_FIELD( 2, BYTES , OPTIONAL, CALLBACK, OTHER, TxRequestDetailsType, tx_hash, request_index, 0), + PB_FIELD( 3, UINT32 , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, extra_data_len, tx_hash, 0), + PB_FIELD( 4, UINT32 , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, extra_data_offset, extra_data_len, 0), + PB_LAST_FIELD +}; + +const pb_field_t TxRequestSerializedType_fields[4] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestSerializedType, signature_index, signature_index, 0), + PB_FIELD( 2, BYTES , OPTIONAL, CALLBACK, OTHER, TxRequestSerializedType, signature, signature_index, 0), + PB_FIELD( 3, BYTES , OPTIONAL, CALLBACK, OTHER, TxRequestSerializedType, serialized_tx, signature, 0), + PB_LAST_FIELD +}; + +const pb_field_t IdentityType_fields[7] = { + PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, IdentityType, proto, proto, 0), + PB_FIELD( 2, STRING , OPTIONAL, CALLBACK, OTHER, IdentityType, user, proto, 0), + PB_FIELD( 3, STRING , OPTIONAL, CALLBACK, OTHER, IdentityType, host, user, 0), + PB_FIELD( 4, STRING , OPTIONAL, CALLBACK, OTHER, IdentityType, port, host, 0), + PB_FIELD( 5, STRING , OPTIONAL, CALLBACK, OTHER, IdentityType, path, port, 0), + PB_FIELD( 6, UINT32 , OPTIONAL, STATIC , OTHER, IdentityType, index, path, &IdentityType_index_default), + PB_LAST_FIELD +}; + +typedef struct { + bool wire_in; +} wire_in_struct; + +static const pb_field_t wire_in_field = + PB_FIELD(50002, BOOL , OPTEXT, STATIC , FIRST, wire_in_struct, wire_in, wire_in, 0); + +const pb_extension_type_t wire_in = { + NULL, + NULL, + &wire_in_field +}; + +typedef struct { + bool wire_out; +} wire_out_struct; + +static const pb_field_t wire_out_field = + PB_FIELD(50003, BOOL , OPTEXT, STATIC , FIRST, wire_out_struct, wire_out, wire_out, 0); + +const pb_extension_type_t wire_out = { + NULL, + NULL, + &wire_out_field +}; + +typedef struct { + bool wire_debug_in; +} wire_debug_in_struct; + +static const pb_field_t wire_debug_in_field = + PB_FIELD(50004, BOOL , OPTEXT, STATIC , FIRST, wire_debug_in_struct, wire_debug_in, wire_debug_in, 0); + +const pb_extension_type_t wire_debug_in = { + NULL, + NULL, + &wire_debug_in_field +}; + +typedef struct { + bool wire_debug_out; +} wire_debug_out_struct; + +static const pb_field_t wire_debug_out_field = + PB_FIELD(50005, BOOL , OPTEXT, STATIC , FIRST, wire_debug_out_struct, wire_debug_out, wire_debug_out, 0); + +const pb_extension_type_t wire_debug_out = { + NULL, + NULL, + &wire_debug_out_field +}; + +typedef struct { + bool wire_tiny; +} wire_tiny_struct; + +static const pb_field_t wire_tiny_field = + PB_FIELD(50006, BOOL , OPTEXT, STATIC , FIRST, wire_tiny_struct, wire_tiny, wire_tiny, 0); + +const pb_extension_type_t wire_tiny = { + NULL, + NULL, + &wire_tiny_field +}; + +typedef struct { + bool wire_bootloader; +} wire_bootloader_struct; + +static const pb_field_t wire_bootloader_field = + PB_FIELD(50007, BOOL , OPTEXT, STATIC , FIRST, wire_bootloader_struct, wire_bootloader, wire_bootloader, 0); + +const pb_extension_type_t wire_bootloader = { + NULL, + NULL, + &wire_bootloader_field +}; + + + + + + + + + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(HDNodePathType, node) < 65536 && pb_membersize(TxInputType, multisig) < 65536 && pb_membersize(TxOutputType, multisig) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_HDNodePathType_CoinType_MultisigRedeemScriptType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType_IdentityType) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(HDNodePathType, node) < 256 && pb_membersize(TxInputType, multisig) < 256 && pb_membersize(TxOutputType, multisig) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_HDNodeType_HDNodePathType_CoinType_MultisigRedeemScriptType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType_IdentityType) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/micropython/bootloader/protob/types.pb.h b/micropython/bootloader/protob/types.pb.h new file mode 100644 index 000000000..ae42e1ba0 --- /dev/null +++ b/micropython/bootloader/protob/types.pb.h @@ -0,0 +1,384 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.8 */ + +#ifndef PB_TYPES_PB_H_INCLUDED +#define PB_TYPES_PB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Enum definitions */ +typedef enum _FailureType { + FailureType_Failure_UnexpectedMessage = 1, + FailureType_Failure_ButtonExpected = 2, + FailureType_Failure_SyntaxError = 3, + FailureType_Failure_ActionCancelled = 4, + FailureType_Failure_PinExpected = 5, + FailureType_Failure_PinCancelled = 6, + FailureType_Failure_PinInvalid = 7, + FailureType_Failure_InvalidSignature = 8, + FailureType_Failure_Other = 9, + FailureType_Failure_NotEnoughFunds = 10, + FailureType_Failure_NotInitialized = 11, + FailureType_Failure_FirmwareError = 99 +} FailureType; +#define _FailureType_MIN FailureType_Failure_UnexpectedMessage +#define _FailureType_MAX FailureType_Failure_FirmwareError +#define _FailureType_ARRAYSIZE ((FailureType)(FailureType_Failure_FirmwareError+1)) + +typedef enum _OutputScriptType { + OutputScriptType_PAYTOADDRESS = 0, + OutputScriptType_PAYTOSCRIPTHASH = 1, + OutputScriptType_PAYTOMULTISIG = 2, + OutputScriptType_PAYTOOPRETURN = 3, + OutputScriptType_PAYTOWITNESS = 4, + OutputScriptType_PAYTOP2SHWITNESS = 5 +} OutputScriptType; +#define _OutputScriptType_MIN OutputScriptType_PAYTOADDRESS +#define _OutputScriptType_MAX OutputScriptType_PAYTOP2SHWITNESS +#define _OutputScriptType_ARRAYSIZE ((OutputScriptType)(OutputScriptType_PAYTOP2SHWITNESS+1)) + +typedef enum _InputScriptType { + InputScriptType_SPENDADDRESS = 0, + InputScriptType_SPENDMULTISIG = 1, + InputScriptType_EXTERNAL = 2, + InputScriptType_SPENDWITNESS = 3, + InputScriptType_SPENDP2SHWITNESS = 4 +} InputScriptType; +#define _InputScriptType_MIN InputScriptType_SPENDADDRESS +#define _InputScriptType_MAX InputScriptType_SPENDP2SHWITNESS +#define _InputScriptType_ARRAYSIZE ((InputScriptType)(InputScriptType_SPENDP2SHWITNESS+1)) + +typedef enum _RequestType { + RequestType_TXINPUT = 0, + RequestType_TXOUTPUT = 1, + RequestType_TXMETA = 2, + RequestType_TXFINISHED = 3, + RequestType_TXEXTRADATA = 4 +} RequestType; +#define _RequestType_MIN RequestType_TXINPUT +#define _RequestType_MAX RequestType_TXEXTRADATA +#define _RequestType_ARRAYSIZE ((RequestType)(RequestType_TXEXTRADATA+1)) + +typedef enum _ButtonRequestType { + ButtonRequestType_ButtonRequest_Other = 1, + ButtonRequestType_ButtonRequest_FeeOverThreshold = 2, + ButtonRequestType_ButtonRequest_ConfirmOutput = 3, + ButtonRequestType_ButtonRequest_ResetDevice = 4, + ButtonRequestType_ButtonRequest_ConfirmWord = 5, + ButtonRequestType_ButtonRequest_WipeDevice = 6, + ButtonRequestType_ButtonRequest_ProtectCall = 7, + ButtonRequestType_ButtonRequest_SignTx = 8, + ButtonRequestType_ButtonRequest_FirmwareCheck = 9, + ButtonRequestType_ButtonRequest_Address = 10, + ButtonRequestType_ButtonRequest_PublicKey = 11 +} ButtonRequestType; +#define _ButtonRequestType_MIN ButtonRequestType_ButtonRequest_Other +#define _ButtonRequestType_MAX ButtonRequestType_ButtonRequest_PublicKey +#define _ButtonRequestType_ARRAYSIZE ((ButtonRequestType)(ButtonRequestType_ButtonRequest_PublicKey+1)) + +typedef enum _PinMatrixRequestType { + PinMatrixRequestType_PinMatrixRequestType_Current = 1, + PinMatrixRequestType_PinMatrixRequestType_NewFirst = 2, + PinMatrixRequestType_PinMatrixRequestType_NewSecond = 3 +} PinMatrixRequestType; +#define _PinMatrixRequestType_MIN PinMatrixRequestType_PinMatrixRequestType_Current +#define _PinMatrixRequestType_MAX PinMatrixRequestType_PinMatrixRequestType_NewSecond +#define _PinMatrixRequestType_ARRAYSIZE ((PinMatrixRequestType)(PinMatrixRequestType_PinMatrixRequestType_NewSecond+1)) + +typedef enum _RecoveryDeviceType { + RecoveryDeviceType_RecoveryDeviceType_ScrambledWords = 0, + RecoveryDeviceType_RecoveryDeviceType_Matrix = 1 +} RecoveryDeviceType; +#define _RecoveryDeviceType_MIN RecoveryDeviceType_RecoveryDeviceType_ScrambledWords +#define _RecoveryDeviceType_MAX RecoveryDeviceType_RecoveryDeviceType_Matrix +#define _RecoveryDeviceType_ARRAYSIZE ((RecoveryDeviceType)(RecoveryDeviceType_RecoveryDeviceType_Matrix+1)) + +typedef enum _WordRequestType { + WordRequestType_WordRequestType_Plain = 0, + WordRequestType_WordRequestType_Matrix9 = 1, + WordRequestType_WordRequestType_Matrix6 = 2 +} WordRequestType; +#define _WordRequestType_MIN WordRequestType_WordRequestType_Plain +#define _WordRequestType_MAX WordRequestType_WordRequestType_Matrix6 +#define _WordRequestType_ARRAYSIZE ((WordRequestType)(WordRequestType_WordRequestType_Matrix6+1)) + +/* Struct definitions */ +typedef struct _CoinType { + pb_callback_t coin_name; + pb_callback_t coin_shortcut; + bool has_address_type; + uint32_t address_type; + bool has_maxfee_kb; + uint64_t maxfee_kb; + bool has_address_type_p2sh; + uint32_t address_type_p2sh; + pb_callback_t signed_message_header; + bool has_xpub_magic; + uint32_t xpub_magic; + bool has_xprv_magic; + uint32_t xprv_magic; + bool has_segwit; + bool segwit; +/* @@protoc_insertion_point(struct:CoinType) */ +} CoinType; + +typedef struct _HDNodeType { + uint32_t depth; + uint32_t fingerprint; + uint32_t child_num; + pb_callback_t chain_code; + pb_callback_t private_key; + pb_callback_t public_key; +/* @@protoc_insertion_point(struct:HDNodeType) */ +} HDNodeType; + +typedef struct _IdentityType { + pb_callback_t proto; + pb_callback_t user; + pb_callback_t host; + pb_callback_t port; + pb_callback_t path; + bool has_index; + uint32_t index; +/* @@protoc_insertion_point(struct:IdentityType) */ +} IdentityType; + +typedef struct _MultisigRedeemScriptType { + pb_callback_t pubkeys; + pb_callback_t signatures; + bool has_m; + uint32_t m; +/* @@protoc_insertion_point(struct:MultisigRedeemScriptType) */ +} MultisigRedeemScriptType; + +typedef struct _TransactionType { + bool has_version; + uint32_t version; + pb_callback_t inputs; + pb_callback_t bin_outputs; + bool has_lock_time; + uint32_t lock_time; + pb_callback_t outputs; + bool has_inputs_cnt; + uint32_t inputs_cnt; + bool has_outputs_cnt; + uint32_t outputs_cnt; + pb_callback_t extra_data; + bool has_extra_data_len; + uint32_t extra_data_len; +/* @@protoc_insertion_point(struct:TransactionType) */ +} TransactionType; + +typedef struct _TxOutputBinType { + uint64_t amount; + pb_callback_t script_pubkey; +/* @@protoc_insertion_point(struct:TxOutputBinType) */ +} TxOutputBinType; + +typedef struct _TxRequestDetailsType { + bool has_request_index; + uint32_t request_index; + pb_callback_t tx_hash; + bool has_extra_data_len; + uint32_t extra_data_len; + bool has_extra_data_offset; + uint32_t extra_data_offset; +/* @@protoc_insertion_point(struct:TxRequestDetailsType) */ +} TxRequestDetailsType; + +typedef struct _TxRequestSerializedType { + bool has_signature_index; + uint32_t signature_index; + pb_callback_t signature; + pb_callback_t serialized_tx; +/* @@protoc_insertion_point(struct:TxRequestSerializedType) */ +} TxRequestSerializedType; + +typedef struct _HDNodePathType { + HDNodeType node; + pb_callback_t address_n; +/* @@protoc_insertion_point(struct:HDNodePathType) */ +} HDNodePathType; + +typedef struct _TxInputType { + pb_callback_t address_n; + pb_callback_t prev_hash; + uint32_t prev_index; + pb_callback_t script_sig; + bool has_sequence; + uint32_t sequence; + bool has_script_type; + InputScriptType script_type; + bool has_multisig; + MultisigRedeemScriptType multisig; + bool has_amount; + uint64_t amount; +/* @@protoc_insertion_point(struct:TxInputType) */ +} TxInputType; + +typedef struct _TxOutputType { + pb_callback_t address; + pb_callback_t address_n; + uint64_t amount; + OutputScriptType script_type; + bool has_multisig; + MultisigRedeemScriptType multisig; + pb_callback_t op_return_data; +/* @@protoc_insertion_point(struct:TxOutputType) */ +} TxOutputType; + +/* Extensions */ +extern const pb_extension_type_t wire_in; /* field type: bool wire_in; */ +extern const pb_extension_type_t wire_out; /* field type: bool wire_out; */ +extern const pb_extension_type_t wire_debug_in; /* field type: bool wire_debug_in; */ +extern const pb_extension_type_t wire_debug_out; /* field type: bool wire_debug_out; */ +extern const pb_extension_type_t wire_tiny; /* field type: bool wire_tiny; */ +extern const pb_extension_type_t wire_bootloader; /* field type: bool wire_bootloader; */ + +/* Default values for struct fields */ +extern const uint32_t CoinType_address_type_default; +extern const uint32_t CoinType_address_type_p2sh_default; +extern const uint32_t CoinType_xpub_magic_default; +extern const uint32_t CoinType_xprv_magic_default; +extern const uint32_t TxInputType_sequence_default; +extern const InputScriptType TxInputType_script_type_default; +extern const uint32_t IdentityType_index_default; + +/* Initializer values for message structs */ +#define HDNodeType_init_default {0, 0, 0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define HDNodePathType_init_default {HDNodeType_init_default, {{NULL}, NULL}} +#define CoinType_init_default {{{NULL}, NULL}, {{NULL}, NULL}, false, 0u, false, 0, false, 5u, {{NULL}, NULL}, false, 76067358u, false, 76066276u, false, 0} +#define MultisigRedeemScriptType_init_default {{{NULL}, NULL}, {{NULL}, NULL}, false, 0} +#define TxInputType_init_default {{{NULL}, NULL}, {{NULL}, NULL}, 0, {{NULL}, NULL}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default, false, 0} +#define TxOutputType_init_default {{{NULL}, NULL}, {{NULL}, NULL}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, {{NULL}, NULL}} +#define TxOutputBinType_init_default {0, {{NULL}, NULL}} +#define TransactionType_init_default {false, 0, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, {{NULL}, NULL}, false, 0, false, 0, {{NULL}, NULL}, false, 0} +#define TxRequestDetailsType_init_default {false, 0, {{NULL}, NULL}, false, 0, false, 0} +#define TxRequestSerializedType_init_default {false, 0, {{NULL}, NULL}, {{NULL}, NULL}} +#define IdentityType_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0u} +#define HDNodeType_init_zero {0, 0, 0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define HDNodePathType_init_zero {HDNodeType_init_zero, {{NULL}, NULL}} +#define CoinType_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, 0, false, 0, {{NULL}, NULL}, false, 0, false, 0, false, 0} +#define MultisigRedeemScriptType_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, false, 0} +#define TxInputType_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, 0, {{NULL}, NULL}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, 0} +#define TxOutputType_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, {{NULL}, NULL}} +#define TxOutputBinType_init_zero {0, {{NULL}, NULL}} +#define TransactionType_init_zero {false, 0, {{NULL}, NULL}, {{NULL}, NULL}, false, 0, {{NULL}, NULL}, false, 0, false, 0, {{NULL}, NULL}, false, 0} +#define TxRequestDetailsType_init_zero {false, 0, {{NULL}, NULL}, false, 0, false, 0} +#define TxRequestSerializedType_init_zero {false, 0, {{NULL}, NULL}, {{NULL}, NULL}} +#define IdentityType_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define CoinType_coin_name_tag 1 +#define CoinType_coin_shortcut_tag 2 +#define CoinType_address_type_tag 3 +#define CoinType_maxfee_kb_tag 4 +#define CoinType_address_type_p2sh_tag 5 +#define CoinType_signed_message_header_tag 8 +#define CoinType_xpub_magic_tag 9 +#define CoinType_xprv_magic_tag 10 +#define CoinType_segwit_tag 11 +#define HDNodeType_depth_tag 1 +#define HDNodeType_fingerprint_tag 2 +#define HDNodeType_child_num_tag 3 +#define HDNodeType_chain_code_tag 4 +#define HDNodeType_private_key_tag 5 +#define HDNodeType_public_key_tag 6 +#define IdentityType_proto_tag 1 +#define IdentityType_user_tag 2 +#define IdentityType_host_tag 3 +#define IdentityType_port_tag 4 +#define IdentityType_path_tag 5 +#define IdentityType_index_tag 6 +#define MultisigRedeemScriptType_pubkeys_tag 1 +#define MultisigRedeemScriptType_signatures_tag 2 +#define MultisigRedeemScriptType_m_tag 3 +#define TransactionType_version_tag 1 +#define TransactionType_inputs_tag 2 +#define TransactionType_bin_outputs_tag 3 +#define TransactionType_outputs_tag 5 +#define TransactionType_lock_time_tag 4 +#define TransactionType_inputs_cnt_tag 6 +#define TransactionType_outputs_cnt_tag 7 +#define TransactionType_extra_data_tag 8 +#define TransactionType_extra_data_len_tag 9 +#define TxOutputBinType_amount_tag 1 +#define TxOutputBinType_script_pubkey_tag 2 +#define TxRequestDetailsType_request_index_tag 1 +#define TxRequestDetailsType_tx_hash_tag 2 +#define TxRequestDetailsType_extra_data_len_tag 3 +#define TxRequestDetailsType_extra_data_offset_tag 4 +#define TxRequestSerializedType_signature_index_tag 1 +#define TxRequestSerializedType_signature_tag 2 +#define TxRequestSerializedType_serialized_tx_tag 3 +#define HDNodePathType_node_tag 1 +#define HDNodePathType_address_n_tag 2 +#define TxInputType_address_n_tag 1 +#define TxInputType_prev_hash_tag 2 +#define TxInputType_prev_index_tag 3 +#define TxInputType_script_sig_tag 4 +#define TxInputType_sequence_tag 5 +#define TxInputType_script_type_tag 6 +#define TxInputType_multisig_tag 7 +#define TxInputType_amount_tag 8 +#define TxOutputType_address_tag 1 +#define TxOutputType_address_n_tag 2 +#define TxOutputType_amount_tag 3 +#define TxOutputType_script_type_tag 4 +#define TxOutputType_multisig_tag 5 +#define TxOutputType_op_return_data_tag 6 +#define wire_in_tag 50002 +#define wire_out_tag 50003 +#define wire_debug_in_tag 50004 +#define wire_debug_out_tag 50005 +#define wire_tiny_tag 50006 +#define wire_bootloader_tag 50007 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t HDNodeType_fields[7]; +extern const pb_field_t HDNodePathType_fields[3]; +extern const pb_field_t CoinType_fields[10]; +extern const pb_field_t MultisigRedeemScriptType_fields[4]; +extern const pb_field_t TxInputType_fields[9]; +extern const pb_field_t TxOutputType_fields[7]; +extern const pb_field_t TxOutputBinType_fields[3]; +extern const pb_field_t TransactionType_fields[10]; +extern const pb_field_t TxRequestDetailsType_fields[5]; +extern const pb_field_t TxRequestSerializedType_fields[4]; +extern const pb_field_t IdentityType_fields[7]; + +/* Maximum encoded size of messages (where known) */ +/* HDNodeType_size depends on runtime parameters */ +/* HDNodePathType_size depends on runtime parameters */ +/* CoinType_size depends on runtime parameters */ +/* MultisigRedeemScriptType_size depends on runtime parameters */ +/* TxInputType_size depends on runtime parameters */ +/* TxOutputType_size depends on runtime parameters */ +/* TxOutputBinType_size depends on runtime parameters */ +/* TransactionType_size depends on runtime parameters */ +/* TxRequestDetailsType_size depends on runtime parameters */ +/* TxRequestSerializedType_size depends on runtime parameters */ +/* IdentityType_size depends on runtime parameters */ + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define TYPES_MESSAGES \ + + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/micropython/bootloader/protob/types.proto b/micropython/bootloader/protob/types.proto new file mode 120000 index 000000000..99f282e4a --- /dev/null +++ b/micropython/bootloader/protob/types.proto @@ -0,0 +1 @@ +../../../vendor/trezor-common/protob/types.proto \ No newline at end of file diff --git a/micropython/bootloader/protobuf.c b/micropython/bootloader/protobuf.c deleted file mode 100644 index 20c1be4d4..000000000 --- a/micropython/bootloader/protobuf.c +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include "protobuf.h" - -void pb_start(PB_CTX *ctx, uint16_t msg_id) -{ - memset(ctx->buf, 0, sizeof(ctx->buf)); - ctx->buf[0] = '?'; - ctx->buf[1] = '#'; - ctx->buf[2] = '#'; - ctx->buf[3] = (msg_id >> 8) & 0xFF; - ctx->buf[4] = msg_id & 0xFF; - ctx->pos = 9; - ctx->len = 0; -} - -void pb_end(PB_CTX *ctx) -{ - ctx->buf[5] = (ctx->len >> 24) & 0xFF; - ctx->buf[6] = (ctx->len >> 16) & 0xFF; - ctx->buf[7] = (ctx->len >> 8) & 0xFF; - ctx->buf[8] = ctx->len & 0xFF; - // align to 64 bytes - ctx->pos += (-ctx->pos) & 63; -} - -inline static void pb_append(PB_CTX *ctx, uint8_t b) -{ - ctx->buf[ctx->pos] = b; - ctx->pos++; - if (ctx->pos % 64 == 0) { - ctx->buf[ctx->pos] = '?'; - ctx->pos++; - } - ctx->len++; -} - -static void pb_varint(PB_CTX *ctx, uint32_t val) -{ - for (;;) { - if (val < 0x80) { - pb_append(ctx, val & 0x7F); - break; - } else { - pb_append(ctx, (val & 0x7F) | 0x80); - val >>= 7; - } - } -} - -void pb_add_bool(PB_CTX *ctx, uint32_t field_number, bool val) -{ - pb_add_varint(ctx, field_number, val); -} - -void pb_add_bytes(PB_CTX *ctx, uint32_t field_number, const uint8_t *val, uint32_t len) -{ - field_number = (field_number << 3) | 2; - pb_varint(ctx, field_number); - pb_varint(ctx, len); - for (uint32_t i = 0; i < len; i++) { - pb_append(ctx, val[i]); - } -} - -void pb_add_string(PB_CTX *ctx, uint32_t field_number, const char *val) -{ - pb_add_bytes(ctx, field_number, (const uint8_t *)val, strlen(val)); -} - -void pb_add_varint(PB_CTX *ctx, uint32_t field_number, uint32_t val) -{ - field_number = (field_number << 3) | 0; - pb_varint(ctx, field_number); - pb_varint(ctx, val); -} - -bool pb_parse_header(const uint8_t *buf, uint16_t *msg_id, uint32_t *msg_size) -{ - if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { - return false; - } - *msg_id = (buf[3] << 8) + buf[4]; - *msg_size = (buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; - return true; -} - -uint32_t pb_read_varint(const uint8_t *buf, uint32_t *num) -{ - uint32_t offset = 0; - *num = 0; - do { - *num += ((*(buf + offset)) & 0x7F) << (7 * offset); - offset++; - } while ((*(buf + offset)) & 0x80); - return offset; -} diff --git a/micropython/bootloader/protobuf.h b/micropython/bootloader/protobuf.h deleted file mode 100644 index 8bff045da..000000000 --- a/micropython/bootloader/protobuf.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __PROTOBUF_H__ -#define __PROTOBUF_H__ - -#include -#include - -#define PB_HEADER_LEN 9 - -typedef struct { - uint8_t buf[128]; - uint32_t pos; - uint32_t len; -} PB_CTX; - -void pb_start(PB_CTX *ctx, uint16_t msg_id); -void pb_end(PB_CTX *ctx); - -void pb_add_bool(PB_CTX *ctx, uint32_t field_number, bool val); -void pb_add_bytes(PB_CTX *ctx, uint32_t field_number, const uint8_t *val, uint32_t len); -void pb_add_string(PB_CTX *ctx, uint32_t field_number, const char *val); -void pb_add_varint(PB_CTX *ctx, uint32_t field_number, uint32_t val); - -bool pb_parse_header(const uint8_t *buf, uint16_t *msg_id, uint32_t *msg_size); -uint32_t pb_read_varint(const uint8_t *buf, uint32_t *num); - -#endif diff --git a/vendor/trezor-common b/vendor/trezor-common new file mode 160000 index 000000000..73b9ffc36 --- /dev/null +++ b/vendor/trezor-common @@ -0,0 +1 @@ +Subproject commit 73b9ffc36a9b54c56bbfa643b4735c63cf309ca2