From 64a552f7a69e20c174f929c5d4e800aa24b480f3 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 27 Aug 2017 00:49:24 +0200 Subject: Make go getable --- car/NOTES.md | 53 -- car/car.ino | 144 ----- car/config.h | 55 -- car/elegoo.pb.c | 34 -- car/elegoo.pb.h | 93 ---- car/elegoo/elegoo.pb.go | 167 ------ car/elegoo/elegoo.proto | 23 - car/elegoo/main.go | 143 ----- car/pb/pb.h | 583 -------------------- car/pb/pb_common.c | 97 ---- car/pb/pb_common.h | 42 -- car/pb/pb_decode.c | 1391 ----------------------------------------------- car/pb/pb_decode.h | 153 ------ car/pb/pb_encode.c | 803 --------------------------- car/pb/pb_encode.h | 154 ------ car/pb/pb_stream.cpp | 48 -- car/pb/pb_stream.h | 12 - elegoo.pb.go | 167 ++++++ elegoo.proto | 23 + elegoo/NOTES.md | 53 ++ elegoo/car.ino | 144 +++++ elegoo/config.h | 55 ++ elegoo/elegoo.pb.c | 34 ++ elegoo/elegoo.pb.h | 93 ++++ elegoo/pb/pb.h | 583 ++++++++++++++++++++ elegoo/pb/pb_common.c | 97 ++++ elegoo/pb/pb_common.h | 42 ++ elegoo/pb/pb_decode.c | 1391 +++++++++++++++++++++++++++++++++++++++++++++++ elegoo/pb/pb_decode.h | 153 ++++++ elegoo/pb/pb_encode.c | 803 +++++++++++++++++++++++++++ elegoo/pb/pb_encode.h | 154 ++++++ elegoo/pb/pb_stream.cpp | 48 ++ elegoo/pb/pb_stream.h | 12 + main.go | 143 +++++ 34 files changed, 3995 insertions(+), 3995 deletions(-) delete mode 100644 car/NOTES.md delete mode 100644 car/car.ino delete mode 100644 car/config.h delete mode 100644 car/elegoo.pb.c delete mode 100644 car/elegoo.pb.h delete mode 100644 car/elegoo/elegoo.pb.go delete mode 100644 car/elegoo/elegoo.proto delete mode 100644 car/elegoo/main.go delete mode 100644 car/pb/pb.h delete mode 100644 car/pb/pb_common.c delete mode 100644 car/pb/pb_common.h delete mode 100644 car/pb/pb_decode.c delete mode 100644 car/pb/pb_decode.h delete mode 100644 car/pb/pb_encode.c delete mode 100644 car/pb/pb_encode.h delete mode 100644 car/pb/pb_stream.cpp delete mode 100644 car/pb/pb_stream.h create mode 100644 elegoo.pb.go create mode 100644 elegoo.proto create mode 100644 elegoo/NOTES.md create mode 100644 elegoo/car.ino create mode 100644 elegoo/config.h create mode 100644 elegoo/elegoo.pb.c create mode 100644 elegoo/elegoo.pb.h create mode 100644 elegoo/pb/pb.h create mode 100644 elegoo/pb/pb_common.c create mode 100644 elegoo/pb/pb_common.h create mode 100644 elegoo/pb/pb_decode.c create mode 100644 elegoo/pb/pb_decode.h create mode 100644 elegoo/pb/pb_encode.c create mode 100644 elegoo/pb/pb_encode.h create mode 100644 elegoo/pb/pb_stream.cpp create mode 100644 elegoo/pb/pb_stream.h create mode 100644 main.go diff --git a/car/NOTES.md b/car/NOTES.md deleted file mode 100644 index 99a8dd0..0000000 --- a/car/NOTES.md +++ /dev/null @@ -1,53 +0,0 @@ -Pinout ------- - -Trig = A0 orange -Echo = A1 red - - -ENA = 10 green left -IN1 = 9 blue -IN2 = 8 brown - -IN3 = 7 gray right -IN4 = 6 white -ENB = 5 black - - ->>> - ENA 5 green - ENB 6 black - IN1 7 blue - IN2 8 brown - IN3 9 gray - IN4 10 white -<<< - -Servo = 3 - -S1 = 2 -S2 = 4 -S3 = 11 - -IR = 12 - -Protocol --------- - -int16: bigEndian - -Motor speed: int16, range -255 .. 255 left and right - - - -Head position: int8 degree, range 0 .. 180 - -
- -Distance reading event: uint16, centimeter - -
- -Sensor change event: - - diff --git a/car/car.ino b/car/car.ino deleted file mode 100644 index c0a151a..0000000 --- a/car/car.ino +++ /dev/null @@ -1,144 +0,0 @@ -// Dimitri Sokolyuk -// 01.01.2017 - -#include -#include -#include -#include - -#include -#include - -#include "elegoo.pb.h" -#include "config.h" - -PacketSerial serial; -Servo servo; -Timer timer; -IRrecv irrecv(IR); -decode_results ir; - -void motor(int e, int a, int b, int v) { - if (v == 0) { - digitalWrite(a, LOW); - digitalWrite(b, LOW); - } else if (v > 0) { - digitalWrite(a, LOW); - digitalWrite(b, HIGH); - } else if (v < 0) { - digitalWrite(a, HIGH); - digitalWrite(b, LOW); - v = -v; - } - analogWrite(e, v); -} - -#define motorR(v) motor(ENA, IN1, IN2, v) -#define motorL(v) motor(ENB, IN3, IN4, v) - -int distance() { - digitalWrite(Trig, LOW); - delayMicroseconds(2); - digitalWrite(Trig, HIGH); - delayMicroseconds(18); - digitalWrite(Trig, LOW); - return pulseIn(Echo, HIGH, TimeOut) / ToCM; -} - -void stop() { - motorR(0); - motorL(0); -} - -void onPacket(const uint8_t* buf, size_t size) { - Command cmd = Command_init_zero; - - pb_istream_t istream = pb_istream_from_buffer(buf, size); - pb_decode_delimited(&istream, Command_fields, &cmd); - - if (cmd.has_SpeedR) { - motorR(cmd.SpeedR); - } - if (cmd.has_SpeedL) { - motorL(cmd.SpeedL); - } - if (cmd.has_Stop) { - stop(); - } - if (cmd.has_Direction) { - servo.write(cmd.Direction); - } - if (cmd.has_StopAfter) { - timer.after(cmd.StopAfter, stop); - } -} - -void events() { - uint8_t buf[64]; - - Events evt = Events_init_zero; - - evt.Distance = distance(); - evt.has_Distance = evt.Distance > 0; - - evt.SensorR = digitalRead(SR); - evt.has_SensorR = true; - - evt.SensorC = digitalRead(SC); - evt.has_SensorC = true; - - evt.SensorL = digitalRead(SL); - evt.has_SensorL = true; - - if (irrecv.decode(&ir)) { - evt.KeyPress = ir.value; - evt.has_KeyPress = ir.bits > 0; - irrecv.resume(); - } - - evt.Direction = servo.read(); - evt.has_Direction = true; - - evt.Time = millis(); - evt.has_Time = true; - - pb_ostream_t ostream = pb_ostream_from_buffer(buf, sizeof(buf)); - pb_encode_delimited(&ostream, Events_fields, &evt); - - serial.send(buf, ostream.bytes_written); -} - -void loop() { - timer.update(); - serial.update(); -} - -void setup() { - serial.begin(57600); - serial.setPacketHandler(&onPacket); - - pinMode(Echo, INPUT); - pinMode(Trig, OUTPUT); - - pinMode(IN1, OUTPUT); - pinMode(IN2, OUTPUT); - pinMode(IN3, OUTPUT); - pinMode(IN4, OUTPUT); - - pinMode(ENA, OUTPUT); - pinMode(ENB, OUTPUT); - pinMode(LED, OUTPUT); - - pinMode(SR, INPUT); - pinMode(SC, INPUT); - pinMode(SL, INPUT); - - pinMode(IR, INPUT); - irrecv.enableIRIn(); - - servo.attach(SRV); - servo.write(90); - - timer.every(100, events); - timer.oscillate(LED, 500, LOW); -} diff --git a/car/config.h b/car/config.h deleted file mode 100644 index af497b1..0000000 --- a/car/config.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -#define LED 13 - -// Settings -#define dist 20 -#define velo 130 - -// Pinout motor -#define ENA 5 // 10 pwm -#define ENB 6 // 5 pwm - -#define IN1 7 // 9 -#define IN2 8 // 8 -#define IN3 9 // 7 -#define IN4 10 // 6 - -// Pinout sensors -#define SR 2 // right -#define SC 4 // center -#define SL 11 // left - -// Servo -#define SRV 3 - -// Pinout IR -#define IR 12 - -// Pinout Ultrasonic -#define Echo A1 -#define Trig A0 - -#define ToCM 58 -#define ToInch 148 -#define TimeOut 100000 - -#define KeyUp 0x00511DBB -#define KeyDown 0xA3C8EDDB -#define KeyLeft 0x52A3D41F -#define KeyRight 0x20FE4DBB -#define KeyOk 0xD7E84B1B -#define Key0 0x1BC0157B -#define Key1 0xC101E57B -#define Key2 0x97483BFB -#define Key3 0xF0C41643 -#define Key4 0x9716BE3F -#define Key5 0x3D9AE3F7 -#define Key6 0x6182021B -#define Key7 0x8C22657B -#define Key8 0x488F3CBB -#define Key9 0x0449E79F -#define KeyStar 0x97483BFB - -#endif diff --git a/car/elegoo.pb.c b/car/elegoo.pb.c deleted file mode 100644 index 7aa3b5e..0000000 --- a/car/elegoo.pb.c +++ /dev/null @@ -1,34 +0,0 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.6 at Sat Aug 26 18:04:10 2017. */ - -#include "elegoo.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 pb_field_t Command_fields[6] = { - PB_FIELD( 1, SINT32 , OPTIONAL, STATIC , FIRST, Command, SpeedR, SpeedR, 0), - PB_FIELD( 2, SINT32 , OPTIONAL, STATIC , OTHER, Command, SpeedL, SpeedR, 0), - PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, Command, Stop, SpeedL, 0), - PB_FIELD( 4, UINT32 , OPTIONAL, STATIC , OTHER, Command, Direction, Stop, 0), - PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, Command, StopAfter, Direction, 0), - PB_LAST_FIELD -}; - -const pb_field_t Events_fields[8] = { - PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, Events, Distance, Distance, 0), - PB_FIELD( 2, SINT32 , OPTIONAL, STATIC , OTHER, Events, Direction, Distance, 0), - PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, Events, SensorR, Direction, 0), - PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, Events, SensorC, SensorR, 0), - PB_FIELD( 5, BOOL , OPTIONAL, STATIC , OTHER, Events, SensorL, SensorC, 0), - PB_FIELD( 6, UINT32 , OPTIONAL, STATIC , OTHER, Events, KeyPress, SensorL, 0), - PB_FIELD( 7, UINT32 , OPTIONAL, STATIC , OTHER, Events, Time, KeyPress, 0), - PB_LAST_FIELD -}; - - -/* @@protoc_insertion_point(eof) */ diff --git a/car/elegoo.pb.h b/car/elegoo.pb.h deleted file mode 100644 index 0f4c4e1..0000000 --- a/car/elegoo.pb.h +++ /dev/null @@ -1,93 +0,0 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.6 at Sat Aug 26 18:04:10 2017. */ - -#ifndef PB_ELEGOO_PB_H_INCLUDED -#define PB_ELEGOO_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 - -/* Struct definitions */ -typedef struct _Command { - bool has_SpeedR; - int32_t SpeedR; - bool has_SpeedL; - int32_t SpeedL; - bool has_Stop; - bool Stop; - bool has_Direction; - uint32_t Direction; - bool has_StopAfter; - uint32_t StopAfter; -/* @@protoc_insertion_point(struct:Command) */ -} Command; - -typedef struct _Events { - bool has_Distance; - uint32_t Distance; - bool has_Direction; - int32_t Direction; - bool has_SensorR; - bool SensorR; - bool has_SensorC; - bool SensorC; - bool has_SensorL; - bool SensorL; - bool has_KeyPress; - uint32_t KeyPress; - bool has_Time; - uint32_t Time; -/* @@protoc_insertion_point(struct:Events) */ -} Events; - -/* Default values for struct fields */ - -/* Initializer values for message structs */ -#define Command_init_default {false, 0, false, 0, false, 0, false, 0, false, 0} -#define Events_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -#define Command_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0} -#define Events_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} - -/* Field tags (for use in manual encoding/decoding) */ -#define Command_SpeedR_tag 1 -#define Command_SpeedL_tag 2 -#define Command_Stop_tag 3 -#define Command_Direction_tag 4 -#define Command_StopAfter_tag 5 -#define Events_Distance_tag 1 -#define Events_Direction_tag 2 -#define Events_SensorR_tag 3 -#define Events_SensorC_tag 4 -#define Events_SensorL_tag 5 -#define Events_KeyPress_tag 6 -#define Events_Time_tag 7 - -/* Struct field encoding specification for nanopb */ -extern const pb_field_t Command_fields[6]; -extern const pb_field_t Events_fields[8]; - -/* Maximum encoded size of messages (where known) */ -#define Command_size 26 -#define Events_size 30 - -/* Message IDs (where set with "msgid" option) */ -#ifdef PB_MSGID - -#define ELEGOO_MESSAGES \ - - -#endif - -#ifdef __cplusplus -} /* extern "C" */ -#endif -/* @@protoc_insertion_point(eof) */ - -#endif diff --git a/car/elegoo/elegoo.pb.go b/car/elegoo/elegoo.pb.go deleted file mode 100644 index 3a367e0..0000000 --- a/car/elegoo/elegoo.pb.go +++ /dev/null @@ -1,167 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: elegoo.proto - -/* -Package main is a generated protocol buffer package. - -It is generated from these files: - elegoo.proto - -It has these top-level messages: - Command - Events -*/ -package main - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type Command struct { - SpeedR int32 `protobuf:"zigzag32,1,opt,name=SpeedR" json:"SpeedR,omitempty"` - SpeedL int32 `protobuf:"zigzag32,2,opt,name=SpeedL" json:"SpeedL,omitempty"` - Stop bool `protobuf:"varint,3,opt,name=Stop" json:"Stop,omitempty"` - Direction uint32 `protobuf:"varint,4,opt,name=Direction" json:"Direction,omitempty"` - StopAfter uint32 `protobuf:"varint,5,opt,name=StopAfter" json:"StopAfter,omitempty"` -} - -func (m *Command) Reset() { *m = Command{} } -func (m *Command) String() string { return proto.CompactTextString(m) } -func (*Command) ProtoMessage() {} -func (*Command) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -func (m *Command) GetSpeedR() int32 { - if m != nil { - return m.SpeedR - } - return 0 -} - -func (m *Command) GetSpeedL() int32 { - if m != nil { - return m.SpeedL - } - return 0 -} - -func (m *Command) GetStop() bool { - if m != nil { - return m.Stop - } - return false -} - -func (m *Command) GetDirection() uint32 { - if m != nil { - return m.Direction - } - return 0 -} - -func (m *Command) GetStopAfter() uint32 { - if m != nil { - return m.StopAfter - } - return 0 -} - -type Events struct { - Distance uint32 `protobuf:"varint,1,opt,name=Distance" json:"Distance,omitempty"` - Direction int32 `protobuf:"zigzag32,2,opt,name=Direction" json:"Direction,omitempty"` - SensorR bool `protobuf:"varint,3,opt,name=SensorR" json:"SensorR,omitempty"` - SensorC bool `protobuf:"varint,4,opt,name=SensorC" json:"SensorC,omitempty"` - SensorL bool `protobuf:"varint,5,opt,name=SensorL" json:"SensorL,omitempty"` - KeyPress uint32 `protobuf:"varint,6,opt,name=KeyPress" json:"KeyPress,omitempty"` - Time uint32 `protobuf:"varint,7,opt,name=Time" json:"Time,omitempty"` -} - -func (m *Events) Reset() { *m = Events{} } -func (m *Events) String() string { return proto.CompactTextString(m) } -func (*Events) ProtoMessage() {} -func (*Events) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } - -func (m *Events) GetDistance() uint32 { - if m != nil { - return m.Distance - } - return 0 -} - -func (m *Events) GetDirection() int32 { - if m != nil { - return m.Direction - } - return 0 -} - -func (m *Events) GetSensorR() bool { - if m != nil { - return m.SensorR - } - return false -} - -func (m *Events) GetSensorC() bool { - if m != nil { - return m.SensorC - } - return false -} - -func (m *Events) GetSensorL() bool { - if m != nil { - return m.SensorL - } - return false -} - -func (m *Events) GetKeyPress() uint32 { - if m != nil { - return m.KeyPress - } - return 0 -} - -func (m *Events) GetTime() uint32 { - if m != nil { - return m.Time - } - return 0 -} - -func init() { - proto.RegisterType((*Command)(nil), "Command") - proto.RegisterType((*Events)(nil), "Events") -} - -func init() { proto.RegisterFile("elegoo.proto", fileDescriptor0) } - -var fileDescriptor0 = []byte{ - // 234 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0xb1, 0x4e, 0xc3, 0x30, - 0x10, 0x86, 0x65, 0x08, 0x4e, 0x39, 0xd1, 0x01, 0x0f, 0xe8, 0x84, 0x18, 0xa2, 0x4e, 0x99, 0x58, - 0x78, 0x02, 0x48, 0x99, 0xc8, 0x80, 0x1c, 0x26, 0xb6, 0xd0, 0x1e, 0xc8, 0x12, 0xf1, 0x45, 0xb6, - 0x85, 0xc4, 0x23, 0xf0, 0x56, 0x3c, 0x1a, 0xb2, 0xd3, 0x3a, 0x61, 0xbb, 0xff, 0xff, 0x2c, 0xdd, - 0xe7, 0x83, 0x0b, 0xfa, 0xa4, 0x0f, 0xe6, 0xdb, 0xd1, 0x71, 0xe0, 0xcd, 0x8f, 0x80, 0xb2, 0xe1, - 0x61, 0xe8, 0xed, 0x5e, 0x5d, 0x81, 0xec, 0x46, 0xa2, 0xbd, 0x46, 0x51, 0x89, 0xfa, 0x52, 0x1f, - 0x52, 0xee, 0x5b, 0x3c, 0x59, 0xf4, 0xad, 0x52, 0x50, 0x74, 0x81, 0x47, 0x3c, 0xad, 0x44, 0xbd, - 0xd2, 0x69, 0x56, 0x37, 0x70, 0xbe, 0x35, 0x8e, 0x76, 0xc1, 0xb0, 0xc5, 0xa2, 0x12, 0xf5, 0x5a, - 0xcf, 0x45, 0xa4, 0xf1, 0xd5, 0xfd, 0x7b, 0x20, 0x87, 0x67, 0x13, 0xcd, 0xc5, 0xe6, 0x57, 0x80, - 0x7c, 0xfc, 0x22, 0x1b, 0xbc, 0xba, 0x86, 0xd5, 0xd6, 0xf8, 0xd0, 0xdb, 0x1d, 0x25, 0x99, 0xb5, - 0xce, 0xf9, 0xff, 0x8a, 0xc9, 0x68, 0xb1, 0x02, 0xa1, 0xec, 0xc8, 0x7a, 0x76, 0xfa, 0xe0, 0x75, - 0x8c, 0x33, 0x69, 0x92, 0x58, 0x26, 0xcd, 0x4c, 0xda, 0x24, 0x95, 0x49, 0x1b, 0x3d, 0x9e, 0xe8, - 0xfb, 0xd9, 0x91, 0xf7, 0x28, 0x27, 0x8f, 0x63, 0x8e, 0xdf, 0x7f, 0x31, 0x03, 0x61, 0x99, 0xfa, - 0x34, 0x3f, 0xc8, 0xd7, 0x62, 0xe8, 0x8d, 0x7d, 0x93, 0xe9, 0xba, 0x77, 0x7f, 0x01, 0x00, 0x00, - 0xff, 0xff, 0x22, 0x73, 0x73, 0x8b, 0x6d, 0x01, 0x00, 0x00, -} diff --git a/car/elegoo/elegoo.proto b/car/elegoo/elegoo.proto deleted file mode 100644 index 7cfd826..0000000 --- a/car/elegoo/elegoo.proto +++ /dev/null @@ -1,23 +0,0 @@ -syntax = "proto3"; - - - -option go_package = "main"; - -message Command { - sint32 SpeedR = 1; // -255 .. +255 - sint32 SpeedL = 2; // -255 .. +255 - bool Stop = 3; - uint32 Direction = 4; // deg: 0 right .. 180 left - uint32 StopAfter = 5; // milliseconds -} - -message Events { - uint32 Distance = 1; // cm - sint32 Direction = 2; // deg - bool SensorR = 3; - bool SensorC = 4; - bool SensorL = 5; - uint32 KeyPress = 6; - uint32 Time = 7; // milliseconds -} diff --git a/car/elegoo/main.go b/car/elegoo/main.go deleted file mode 100644 index 7e5f6e3..0000000 --- a/car/elegoo/main.go +++ /dev/null @@ -1,143 +0,0 @@ -package main - -//go:generate sh -c "protoc --go_out=. --nanopb_out=.. *.proto" - -import ( - "bufio" - "io" - "log" - - "github.com/dim13/cobs" - "github.com/golang/protobuf/proto" - "github.com/tarm/serial" -) - -func Write(w io.Writer, pb proto.Message) error { - buf := new(proto.Buffer) - err := buf.EncodeMessage(pb) - if err != nil { - return err - } - block := cobs.Encode(buf.Bytes()) - _, err = w.Write(block) - return err -} - -func Read(buf *bufio.Reader, pb proto.Message) error { - block, err := buf.ReadBytes(0) - if err != nil { - return err - } - block = cobs.Decode(block) - return proto.NewBuffer(block).DecodeMessage(pb) -} - -// /dev/cu.Elegoo-DevB -// /dev/cu.usbmodem1421 -// /dev/cu.usbmodem1411 - -func Reader(r io.Reader) chan *Events { - c := make(chan *Events) - buf := bufio.NewReader(r) - go func() { - for { - evt := &Events{} - if err := Read(buf, evt); err != nil { - if err == io.ErrUnexpectedEOF { - continue - } - log.Println("ERR", err) - return - } - c <- evt - } - }() - return c -} - -func Writer(w io.Writer) chan *Command { - c := make(chan *Command) - go func() { - for cmd := range c { - log.Println("send", cmd) - Write(w, cmd) - } - }() - return c -} - -func main() { - c := &serial.Config{ - //Name: "/dev/tty.usbmodem1421", - //Name: "/dev/tty.usbmodem1411", - Name: "/dev/tty.Elegoo-DevB", - Baud: 57600, - } - s, err := serial.OpenPort(c) - if err != nil { - log.Fatal(err) - } - defer s.Close() - - w := Writer(s) - - w <- &Command{Direction: 80} - - for e := range Reader(s) { - log.Println("event", e) - if e.SensorC || e.Distance < 20 { - w <- &Command{Stop: true} - } - } - - /* log.Println("send -45") - time.Sleep(3 * time.Second) - Write(s, &Command{Direction: 5}) - - log.Println("send +45") - time.Sleep(3 * time.Second) - Write(s, &Command{Direction: 175}) - - log.Println("send +0") - time.Sleep(3 * time.Second) - Write(s, &Command{Direction: 90}) - */ - - /* log.Println("send motor") - Write(s, &Command{SpeedL: 200, SpeedR: 200, StopAfter: 1000}) - time.Sleep(time.Second) - - log.Println("send motor turn") - time.Sleep(time.Second) - Write(s, &Command{SpeedL: -250, SpeedR: 250, StopAfter: 500}) - - log.Println("send motor turn") - time.Sleep(time.Second) - Write(s, &Command{SpeedL: 250, SpeedR: -250, StopAfter: 500}) - */ - - /* MOTOR - cmd.SpeedL = 200 - cmd.SpeedR = 0 - cmd.Stop = false - Write(s, cmd) - time.Sleep(3 * time.Second) - - cmd.SpeedL = 0 - cmd.SpeedR = 0 - cmd.Stop = true - Write(s, cmd) - time.Sleep(3 * time.Second) - - cmd.SpeedL = 0 - cmd.SpeedR = 200 - cmd.Stop = false - Write(s, cmd) - time.Sleep(3 * time.Second) - - cmd.SpeedL = 0 - cmd.SpeedR = 0 - cmd.Stop = true - Write(s, cmd) - */ -} diff --git a/car/pb/pb.h b/car/pb/pb.h deleted file mode 100644 index c7e6bc6..0000000 --- a/car/pb/pb.h +++ /dev/null @@ -1,583 +0,0 @@ -/* 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.9-dev - -/* 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/car/pb/pb_common.c b/car/pb/pb_common.c deleted file mode 100644 index 4fb7186..0000000 --- a/car/pb/pb_common.c +++ /dev/null @@ -1,97 +0,0 @@ -/* 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/car/pb/pb_common.h b/car/pb/pb_common.h deleted file mode 100644 index 60b3d37..0000000 --- a/car/pb/pb_common.h +++ /dev/null @@ -1,42 +0,0 @@ -/* 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/car/pb/pb_decode.c b/car/pb/pb_decode.c deleted file mode 100644 index b4563cf..0000000 --- a/car/pb/pb_decode.c +++ /dev/null @@ -1,1391 +0,0 @@ -/* 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) - { - /* We memset to zero so that any callbacks are set to NULL. - * Then set any default values. */ - memset(pItem, 0, iter->pos->data_size); - 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 == NULL || 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 > PB_MAX_REQUIRED_FIELDS) - req_field_count = PB_MAX_REQUIRED_FIELDS; - - 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 any) */ - if ((req_field_count & 31) != 0) - { - 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/car/pb/pb_decode.h b/car/pb/pb_decode.h deleted file mode 100644 index a426bdd..0000000 --- a/car/pb/pb_decode.h +++ /dev/null @@ -1,153 +0,0 @@ -/* 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/car/pb/pb_encode.c b/car/pb/pb_encode.c deleted file mode 100644 index 05d691d..0000000 --- a/car/pb/pb_encode.c +++ /dev/null @@ -1,803 +0,0 @@ -/* 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) -{ - pb_type_t type = field->type; - const void *pSize = (const char*)pData + field->size_offset; - - if (PB_HTYPE(type) == PB_HTYPE_REQUIRED) - { - /* Required proto2 fields inside proto3 submessage, pretty rare case */ - return false; - } - else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - /* Repeated fields inside proto3 submessage: present if count != 0 */ - return *(const pb_size_t*)pSize == 0; - } - else if (PB_HTYPE(type) == PB_HTYPE_ONEOF) - { - /* Oneof fields */ - return *(const pb_size_t*)pSize == 0; - } - else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->size_offset) - { - /* Proto2 optional fields inside proto3 submessage */ - return *(const bool*)pSize == false; - } - - /* Rest is proto3 singular fields */ - - if (PB_ATYPE(type) == PB_ATYPE_STATIC) - { - if (PB_LTYPE(type) == PB_LTYPE_BYTES) - { - const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData; - return bytes->size == 0; - } - else if (PB_LTYPE(type) == PB_LTYPE_STRING) - { - return *(const char*)pData == '\0'; - } - else if (PB_LTYPE(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(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/car/pb/pb_encode.h b/car/pb/pb_encode.h deleted file mode 100644 index d9909fb..0000000 --- a/car/pb/pb_encode.h +++ /dev/null @@ -1,154 +0,0 @@ -/* 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/car/pb/pb_stream.cpp b/car/pb/pb_stream.cpp deleted file mode 100644 index 41100ed..0000000 --- a/car/pb/pb_stream.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// From https://github.com/amorellgarcia/arduino-nanopb - -#include "pb_stream.h" - -#define MAXSZ (size_t)-1 - -bool -os_read(pb_istream_t *stream, uint8_t *buf, size_t count) -{ - Stream *s = static_cast(stream->state); - while (s->available() > 0 && count > 0) { - count -= s->readBytes((char *)buf, count); - } - return count == 0; -} - - -void -pb_istream_from_stream(Stream &stream, pb_istream_t &istream) -{ - istream.callback = &os_read; - istream.state = &stream; - istream.bytes_left = MAXSZ; -#ifndef PB_NO_ERRMSG - istream.errmsg = NULL; -#endif -} - -bool -os_write(pb_ostream_t *stream, const uint8_t *buf, size_t count) -{ - if (stream == NULL || buf == NULL) { - return false; - } - Print *s = static_cast(stream->state); - return (s->write(buf, count) == count); -} - -void -pb_ostream_from_stream(Print &stream, pb_ostream_t &ostream) { - ostream.callback = &os_write; - ostream.state = &stream; - ostream.max_size = MAXSZ; - ostream.bytes_written = 0; -#ifndef PB_NO_ERRMSG - ostream.errmsg = NULL; -#endif -} diff --git a/car/pb/pb_stream.h b/car/pb/pb_stream.h deleted file mode 100644 index 00be77c..0000000 --- a/car/pb/pb_stream.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef PB_STREAM -#define PB_STREAM - -#include -#include -#include "pb_encode.h" -#include "pb_decode.h" - -void pb_istream_from_stream(Stream &stream, pb_istream_t &istream); -void pb_ostream_from_stream(Print &stream, pb_ostream_t &ostream); - -#endif diff --git a/elegoo.pb.go b/elegoo.pb.go new file mode 100644 index 0000000..3a367e0 --- /dev/null +++ b/elegoo.pb.go @@ -0,0 +1,167 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: elegoo.proto + +/* +Package main is a generated protocol buffer package. + +It is generated from these files: + elegoo.proto + +It has these top-level messages: + Command + Events +*/ +package main + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Command struct { + SpeedR int32 `protobuf:"zigzag32,1,opt,name=SpeedR" json:"SpeedR,omitempty"` + SpeedL int32 `protobuf:"zigzag32,2,opt,name=SpeedL" json:"SpeedL,omitempty"` + Stop bool `protobuf:"varint,3,opt,name=Stop" json:"Stop,omitempty"` + Direction uint32 `protobuf:"varint,4,opt,name=Direction" json:"Direction,omitempty"` + StopAfter uint32 `protobuf:"varint,5,opt,name=StopAfter" json:"StopAfter,omitempty"` +} + +func (m *Command) Reset() { *m = Command{} } +func (m *Command) String() string { return proto.CompactTextString(m) } +func (*Command) ProtoMessage() {} +func (*Command) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *Command) GetSpeedR() int32 { + if m != nil { + return m.SpeedR + } + return 0 +} + +func (m *Command) GetSpeedL() int32 { + if m != nil { + return m.SpeedL + } + return 0 +} + +func (m *Command) GetStop() bool { + if m != nil { + return m.Stop + } + return false +} + +func (m *Command) GetDirection() uint32 { + if m != nil { + return m.Direction + } + return 0 +} + +func (m *Command) GetStopAfter() uint32 { + if m != nil { + return m.StopAfter + } + return 0 +} + +type Events struct { + Distance uint32 `protobuf:"varint,1,opt,name=Distance" json:"Distance,omitempty"` + Direction int32 `protobuf:"zigzag32,2,opt,name=Direction" json:"Direction,omitempty"` + SensorR bool `protobuf:"varint,3,opt,name=SensorR" json:"SensorR,omitempty"` + SensorC bool `protobuf:"varint,4,opt,name=SensorC" json:"SensorC,omitempty"` + SensorL bool `protobuf:"varint,5,opt,name=SensorL" json:"SensorL,omitempty"` + KeyPress uint32 `protobuf:"varint,6,opt,name=KeyPress" json:"KeyPress,omitempty"` + Time uint32 `protobuf:"varint,7,opt,name=Time" json:"Time,omitempty"` +} + +func (m *Events) Reset() { *m = Events{} } +func (m *Events) String() string { return proto.CompactTextString(m) } +func (*Events) ProtoMessage() {} +func (*Events) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *Events) GetDistance() uint32 { + if m != nil { + return m.Distance + } + return 0 +} + +func (m *Events) GetDirection() int32 { + if m != nil { + return m.Direction + } + return 0 +} + +func (m *Events) GetSensorR() bool { + if m != nil { + return m.SensorR + } + return false +} + +func (m *Events) GetSensorC() bool { + if m != nil { + return m.SensorC + } + return false +} + +func (m *Events) GetSensorL() bool { + if m != nil { + return m.SensorL + } + return false +} + +func (m *Events) GetKeyPress() uint32 { + if m != nil { + return m.KeyPress + } + return 0 +} + +func (m *Events) GetTime() uint32 { + if m != nil { + return m.Time + } + return 0 +} + +func init() { + proto.RegisterType((*Command)(nil), "Command") + proto.RegisterType((*Events)(nil), "Events") +} + +func init() { proto.RegisterFile("elegoo.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 234 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0xb1, 0x4e, 0xc3, 0x30, + 0x10, 0x86, 0x65, 0x08, 0x4e, 0x39, 0xd1, 0x01, 0x0f, 0xe8, 0x84, 0x18, 0xa2, 0x4e, 0x99, 0x58, + 0x78, 0x02, 0x48, 0x99, 0xc8, 0x80, 0x1c, 0x26, 0xb6, 0xd0, 0x1e, 0xc8, 0x12, 0xf1, 0x45, 0xb6, + 0x85, 0xc4, 0x23, 0xf0, 0x56, 0x3c, 0x1a, 0xb2, 0xd3, 0x3a, 0x61, 0xbb, 0xff, 0xff, 0x2c, 0xdd, + 0xe7, 0x83, 0x0b, 0xfa, 0xa4, 0x0f, 0xe6, 0xdb, 0xd1, 0x71, 0xe0, 0xcd, 0x8f, 0x80, 0xb2, 0xe1, + 0x61, 0xe8, 0xed, 0x5e, 0x5d, 0x81, 0xec, 0x46, 0xa2, 0xbd, 0x46, 0x51, 0x89, 0xfa, 0x52, 0x1f, + 0x52, 0xee, 0x5b, 0x3c, 0x59, 0xf4, 0xad, 0x52, 0x50, 0x74, 0x81, 0x47, 0x3c, 0xad, 0x44, 0xbd, + 0xd2, 0x69, 0x56, 0x37, 0x70, 0xbe, 0x35, 0x8e, 0x76, 0xc1, 0xb0, 0xc5, 0xa2, 0x12, 0xf5, 0x5a, + 0xcf, 0x45, 0xa4, 0xf1, 0xd5, 0xfd, 0x7b, 0x20, 0x87, 0x67, 0x13, 0xcd, 0xc5, 0xe6, 0x57, 0x80, + 0x7c, 0xfc, 0x22, 0x1b, 0xbc, 0xba, 0x86, 0xd5, 0xd6, 0xf8, 0xd0, 0xdb, 0x1d, 0x25, 0x99, 0xb5, + 0xce, 0xf9, 0xff, 0x8a, 0xc9, 0x68, 0xb1, 0x02, 0xa1, 0xec, 0xc8, 0x7a, 0x76, 0xfa, 0xe0, 0x75, + 0x8c, 0x33, 0x69, 0x92, 0x58, 0x26, 0xcd, 0x4c, 0xda, 0x24, 0x95, 0x49, 0x1b, 0x3d, 0x9e, 0xe8, + 0xfb, 0xd9, 0x91, 0xf7, 0x28, 0x27, 0x8f, 0x63, 0x8e, 0xdf, 0x7f, 0x31, 0x03, 0x61, 0x99, 0xfa, + 0x34, 0x3f, 0xc8, 0xd7, 0x62, 0xe8, 0x8d, 0x7d, 0x93, 0xe9, 0xba, 0x77, 0x7f, 0x01, 0x00, 0x00, + 0xff, 0xff, 0x22, 0x73, 0x73, 0x8b, 0x6d, 0x01, 0x00, 0x00, +} diff --git a/elegoo.proto b/elegoo.proto new file mode 100644 index 0000000..7cfd826 --- /dev/null +++ b/elegoo.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; + + + +option go_package = "main"; + +message Command { + sint32 SpeedR = 1; // -255 .. +255 + sint32 SpeedL = 2; // -255 .. +255 + bool Stop = 3; + uint32 Direction = 4; // deg: 0 right .. 180 left + uint32 StopAfter = 5; // milliseconds +} + +message Events { + uint32 Distance = 1; // cm + sint32 Direction = 2; // deg + bool SensorR = 3; + bool SensorC = 4; + bool SensorL = 5; + uint32 KeyPress = 6; + uint32 Time = 7; // milliseconds +} diff --git a/elegoo/NOTES.md b/elegoo/NOTES.md new file mode 100644 index 0000000..99a8dd0 --- /dev/null +++ b/elegoo/NOTES.md @@ -0,0 +1,53 @@ +Pinout +------ + +Trig = A0 orange +Echo = A1 red + + +ENA = 10 green left +IN1 = 9 blue +IN2 = 8 brown + +IN3 = 7 gray right +IN4 = 6 white +ENB = 5 black + + +>>> + ENA 5 green + ENB 6 black + IN1 7 blue + IN2 8 brown + IN3 9 gray + IN4 10 white +<<< + +Servo = 3 + +S1 = 2 +S2 = 4 +S3 = 11 + +IR = 12 + +Protocol +-------- + +int16: bigEndian + +Motor speed: int16, range -255 .. 255 left and right + + + +Head position: int8 degree, range 0 .. 180 + +
+ +Distance reading event: uint16, centimeter + +
+ +Sensor change event: + + diff --git a/elegoo/car.ino b/elegoo/car.ino new file mode 100644 index 0000000..c0a151a --- /dev/null +++ b/elegoo/car.ino @@ -0,0 +1,144 @@ +// Dimitri Sokolyuk +// 01.01.2017 + +#include +#include +#include +#include + +#include +#include + +#include "elegoo.pb.h" +#include "config.h" + +PacketSerial serial; +Servo servo; +Timer timer; +IRrecv irrecv(IR); +decode_results ir; + +void motor(int e, int a, int b, int v) { + if (v == 0) { + digitalWrite(a, LOW); + digitalWrite(b, LOW); + } else if (v > 0) { + digitalWrite(a, LOW); + digitalWrite(b, HIGH); + } else if (v < 0) { + digitalWrite(a, HIGH); + digitalWrite(b, LOW); + v = -v; + } + analogWrite(e, v); +} + +#define motorR(v) motor(ENA, IN1, IN2, v) +#define motorL(v) motor(ENB, IN3, IN4, v) + +int distance() { + digitalWrite(Trig, LOW); + delayMicroseconds(2); + digitalWrite(Trig, HIGH); + delayMicroseconds(18); + digitalWrite(Trig, LOW); + return pulseIn(Echo, HIGH, TimeOut) / ToCM; +} + +void stop() { + motorR(0); + motorL(0); +} + +void onPacket(const uint8_t* buf, size_t size) { + Command cmd = Command_init_zero; + + pb_istream_t istream = pb_istream_from_buffer(buf, size); + pb_decode_delimited(&istream, Command_fields, &cmd); + + if (cmd.has_SpeedR) { + motorR(cmd.SpeedR); + } + if (cmd.has_SpeedL) { + motorL(cmd.SpeedL); + } + if (cmd.has_Stop) { + stop(); + } + if (cmd.has_Direction) { + servo.write(cmd.Direction); + } + if (cmd.has_StopAfter) { + timer.after(cmd.StopAfter, stop); + } +} + +void events() { + uint8_t buf[64]; + + Events evt = Events_init_zero; + + evt.Distance = distance(); + evt.has_Distance = evt.Distance > 0; + + evt.SensorR = digitalRead(SR); + evt.has_SensorR = true; + + evt.SensorC = digitalRead(SC); + evt.has_SensorC = true; + + evt.SensorL = digitalRead(SL); + evt.has_SensorL = true; + + if (irrecv.decode(&ir)) { + evt.KeyPress = ir.value; + evt.has_KeyPress = ir.bits > 0; + irrecv.resume(); + } + + evt.Direction = servo.read(); + evt.has_Direction = true; + + evt.Time = millis(); + evt.has_Time = true; + + pb_ostream_t ostream = pb_ostream_from_buffer(buf, sizeof(buf)); + pb_encode_delimited(&ostream, Events_fields, &evt); + + serial.send(buf, ostream.bytes_written); +} + +void loop() { + timer.update(); + serial.update(); +} + +void setup() { + serial.begin(57600); + serial.setPacketHandler(&onPacket); + + pinMode(Echo, INPUT); + pinMode(Trig, OUTPUT); + + pinMode(IN1, OUTPUT); + pinMode(IN2, OUTPUT); + pinMode(IN3, OUTPUT); + pinMode(IN4, OUTPUT); + + pinMode(ENA, OUTPUT); + pinMode(ENB, OUTPUT); + pinMode(LED, OUTPUT); + + pinMode(SR, INPUT); + pinMode(SC, INPUT); + pinMode(SL, INPUT); + + pinMode(IR, INPUT); + irrecv.enableIRIn(); + + servo.attach(SRV); + servo.write(90); + + timer.every(100, events); + timer.oscillate(LED, 500, LOW); +} diff --git a/elegoo/config.h b/elegoo/config.h new file mode 100644 index 0000000..af497b1 --- /dev/null +++ b/elegoo/config.h @@ -0,0 +1,55 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define LED 13 + +// Settings +#define dist 20 +#define velo 130 + +// Pinout motor +#define ENA 5 // 10 pwm +#define ENB 6 // 5 pwm + +#define IN1 7 // 9 +#define IN2 8 // 8 +#define IN3 9 // 7 +#define IN4 10 // 6 + +// Pinout sensors +#define SR 2 // right +#define SC 4 // center +#define SL 11 // left + +// Servo +#define SRV 3 + +// Pinout IR +#define IR 12 + +// Pinout Ultrasonic +#define Echo A1 +#define Trig A0 + +#define ToCM 58 +#define ToInch 148 +#define TimeOut 100000 + +#define KeyUp 0x00511DBB +#define KeyDown 0xA3C8EDDB +#define KeyLeft 0x52A3D41F +#define KeyRight 0x20FE4DBB +#define KeyOk 0xD7E84B1B +#define Key0 0x1BC0157B +#define Key1 0xC101E57B +#define Key2 0x97483BFB +#define Key3 0xF0C41643 +#define Key4 0x9716BE3F +#define Key5 0x3D9AE3F7 +#define Key6 0x6182021B +#define Key7 0x8C22657B +#define Key8 0x488F3CBB +#define Key9 0x0449E79F +#define KeyStar 0x97483BFB + +#endif diff --git a/elegoo/elegoo.pb.c b/elegoo/elegoo.pb.c new file mode 100644 index 0000000..5cb5e7a --- /dev/null +++ b/elegoo/elegoo.pb.c @@ -0,0 +1,34 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.6 at Sun Aug 27 00:49:15 2017. */ + +#include "elegoo.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 pb_field_t Command_fields[6] = { + PB_FIELD( 1, SINT32 , OPTIONAL, STATIC , FIRST, Command, SpeedR, SpeedR, 0), + PB_FIELD( 2, SINT32 , OPTIONAL, STATIC , OTHER, Command, SpeedL, SpeedR, 0), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, Command, Stop, SpeedL, 0), + PB_FIELD( 4, UINT32 , OPTIONAL, STATIC , OTHER, Command, Direction, Stop, 0), + PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, Command, StopAfter, Direction, 0), + PB_LAST_FIELD +}; + +const pb_field_t Events_fields[8] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, Events, Distance, Distance, 0), + PB_FIELD( 2, SINT32 , OPTIONAL, STATIC , OTHER, Events, Direction, Distance, 0), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, Events, SensorR, Direction, 0), + PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, Events, SensorC, SensorR, 0), + PB_FIELD( 5, BOOL , OPTIONAL, STATIC , OTHER, Events, SensorL, SensorC, 0), + PB_FIELD( 6, UINT32 , OPTIONAL, STATIC , OTHER, Events, KeyPress, SensorL, 0), + PB_FIELD( 7, UINT32 , OPTIONAL, STATIC , OTHER, Events, Time, KeyPress, 0), + PB_LAST_FIELD +}; + + +/* @@protoc_insertion_point(eof) */ diff --git a/elegoo/elegoo.pb.h b/elegoo/elegoo.pb.h new file mode 100644 index 0000000..3510675 --- /dev/null +++ b/elegoo/elegoo.pb.h @@ -0,0 +1,93 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.6 at Sun Aug 27 00:49:15 2017. */ + +#ifndef PB_ELEGOO_PB_H_INCLUDED +#define PB_ELEGOO_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 + +/* Struct definitions */ +typedef struct _Command { + bool has_SpeedR; + int32_t SpeedR; + bool has_SpeedL; + int32_t SpeedL; + bool has_Stop; + bool Stop; + bool has_Direction; + uint32_t Direction; + bool has_StopAfter; + uint32_t StopAfter; +/* @@protoc_insertion_point(struct:Command) */ +} Command; + +typedef struct _Events { + bool has_Distance; + uint32_t Distance; + bool has_Direction; + int32_t Direction; + bool has_SensorR; + bool SensorR; + bool has_SensorC; + bool SensorC; + bool has_SensorL; + bool SensorL; + bool has_KeyPress; + uint32_t KeyPress; + bool has_Time; + uint32_t Time; +/* @@protoc_insertion_point(struct:Events) */ +} Events; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define Command_init_default {false, 0, false, 0, false, 0, false, 0, false, 0} +#define Events_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define Command_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0} +#define Events_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define Command_SpeedR_tag 1 +#define Command_SpeedL_tag 2 +#define Command_Stop_tag 3 +#define Command_Direction_tag 4 +#define Command_StopAfter_tag 5 +#define Events_Distance_tag 1 +#define Events_Direction_tag 2 +#define Events_SensorR_tag 3 +#define Events_SensorC_tag 4 +#define Events_SensorL_tag 5 +#define Events_KeyPress_tag 6 +#define Events_Time_tag 7 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t Command_fields[6]; +extern const pb_field_t Events_fields[8]; + +/* Maximum encoded size of messages (where known) */ +#define Command_size 26 +#define Events_size 30 + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define ELEGOO_MESSAGES \ + + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/elegoo/pb/pb.h b/elegoo/pb/pb.h new file mode 100644 index 0000000..c7e6bc6 --- /dev/null +++ b/elegoo/pb/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.9-dev + +/* 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/elegoo/pb/pb_common.c b/elegoo/pb/pb_common.c new file mode 100644 index 0000000..4fb7186 --- /dev/null +++ b/elegoo/pb/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/elegoo/pb/pb_common.h b/elegoo/pb/pb_common.h new file mode 100644 index 0000000..60b3d37 --- /dev/null +++ b/elegoo/pb/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/elegoo/pb/pb_decode.c b/elegoo/pb/pb_decode.c new file mode 100644 index 0000000..b4563cf --- /dev/null +++ b/elegoo/pb/pb_decode.c @@ -0,0 +1,1391 @@ +/* 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) + { + /* We memset to zero so that any callbacks are set to NULL. + * Then set any default values. */ + memset(pItem, 0, iter->pos->data_size); + 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 == NULL || 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 > PB_MAX_REQUIRED_FIELDS) + req_field_count = PB_MAX_REQUIRED_FIELDS; + + 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 any) */ + if ((req_field_count & 31) != 0) + { + 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/elegoo/pb/pb_decode.h b/elegoo/pb/pb_decode.h new file mode 100644 index 0000000..a426bdd --- /dev/null +++ b/elegoo/pb/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/elegoo/pb/pb_encode.c b/elegoo/pb/pb_encode.c new file mode 100644 index 0000000..05d691d --- /dev/null +++ b/elegoo/pb/pb_encode.c @@ -0,0 +1,803 @@ +/* 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) +{ + pb_type_t type = field->type; + const void *pSize = (const char*)pData + field->size_offset; + + if (PB_HTYPE(type) == PB_HTYPE_REQUIRED) + { + /* Required proto2 fields inside proto3 submessage, pretty rare case */ + return false; + } + else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + /* Repeated fields inside proto3 submessage: present if count != 0 */ + return *(const pb_size_t*)pSize == 0; + } + else if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + /* Oneof fields */ + return *(const pb_size_t*)pSize == 0; + } + else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->size_offset) + { + /* Proto2 optional fields inside proto3 submessage */ + return *(const bool*)pSize == false; + } + + /* Rest is proto3 singular fields */ + + if (PB_ATYPE(type) == PB_ATYPE_STATIC) + { + if (PB_LTYPE(type) == PB_LTYPE_BYTES) + { + const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData; + return bytes->size == 0; + } + else if (PB_LTYPE(type) == PB_LTYPE_STRING) + { + return *(const char*)pData == '\0'; + } + else if (PB_LTYPE(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(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/elegoo/pb/pb_encode.h b/elegoo/pb/pb_encode.h new file mode 100644 index 0000000..d9909fb --- /dev/null +++ b/elegoo/pb/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/elegoo/pb/pb_stream.cpp b/elegoo/pb/pb_stream.cpp new file mode 100644 index 0000000..41100ed --- /dev/null +++ b/elegoo/pb/pb_stream.cpp @@ -0,0 +1,48 @@ +// From https://github.com/amorellgarcia/arduino-nanopb + +#include "pb_stream.h" + +#define MAXSZ (size_t)-1 + +bool +os_read(pb_istream_t *stream, uint8_t *buf, size_t count) +{ + Stream *s = static_cast(stream->state); + while (s->available() > 0 && count > 0) { + count -= s->readBytes((char *)buf, count); + } + return count == 0; +} + + +void +pb_istream_from_stream(Stream &stream, pb_istream_t &istream) +{ + istream.callback = &os_read; + istream.state = &stream; + istream.bytes_left = MAXSZ; +#ifndef PB_NO_ERRMSG + istream.errmsg = NULL; +#endif +} + +bool +os_write(pb_ostream_t *stream, const uint8_t *buf, size_t count) +{ + if (stream == NULL || buf == NULL) { + return false; + } + Print *s = static_cast(stream->state); + return (s->write(buf, count) == count); +} + +void +pb_ostream_from_stream(Print &stream, pb_ostream_t &ostream) { + ostream.callback = &os_write; + ostream.state = &stream; + ostream.max_size = MAXSZ; + ostream.bytes_written = 0; +#ifndef PB_NO_ERRMSG + ostream.errmsg = NULL; +#endif +} diff --git a/elegoo/pb/pb_stream.h b/elegoo/pb/pb_stream.h new file mode 100644 index 0000000..00be77c --- /dev/null +++ b/elegoo/pb/pb_stream.h @@ -0,0 +1,12 @@ +#ifndef PB_STREAM +#define PB_STREAM + +#include +#include +#include "pb_encode.h" +#include "pb_decode.h" + +void pb_istream_from_stream(Stream &stream, pb_istream_t &istream); +void pb_ostream_from_stream(Print &stream, pb_ostream_t &ostream); + +#endif diff --git a/main.go b/main.go new file mode 100644 index 0000000..837fa6a --- /dev/null +++ b/main.go @@ -0,0 +1,143 @@ +package main + +//go:generate sh -c "protoc --go_out=. --nanopb_out=elegoo/ *.proto" + +import ( + "bufio" + "io" + "log" + + "github.com/dim13/cobs" + "github.com/golang/protobuf/proto" + "github.com/tarm/serial" +) + +func Write(w io.Writer, pb proto.Message) error { + buf := new(proto.Buffer) + err := buf.EncodeMessage(pb) + if err != nil { + return err + } + block := cobs.Encode(buf.Bytes()) + _, err = w.Write(block) + return err +} + +func Read(buf *bufio.Reader, pb proto.Message) error { + block, err := buf.ReadBytes(0) + if err != nil { + return err + } + block = cobs.Decode(block) + return proto.NewBuffer(block).DecodeMessage(pb) +} + +// /dev/cu.Elegoo-DevB +// /dev/cu.usbmodem1421 +// /dev/cu.usbmodem1411 + +func Reader(r io.Reader) chan *Events { + c := make(chan *Events) + buf := bufio.NewReader(r) + go func() { + for { + evt := &Events{} + if err := Read(buf, evt); err != nil { + if err == io.ErrUnexpectedEOF { + continue + } + log.Println("ERR", err) + return + } + c <- evt + } + }() + return c +} + +func Writer(w io.Writer) chan *Command { + c := make(chan *Command) + go func() { + for cmd := range c { + log.Println("send", cmd) + Write(w, cmd) + } + }() + return c +} + +func main() { + c := &serial.Config{ + //Name: "/dev/tty.usbmodem1421", + //Name: "/dev/tty.usbmodem1411", + Name: "/dev/tty.Elegoo-DevB", + Baud: 57600, + } + s, err := serial.OpenPort(c) + if err != nil { + log.Fatal(err) + } + defer s.Close() + + w := Writer(s) + + w <- &Command{Direction: 80} + + for e := range Reader(s) { + log.Println("event", e) + if e.SensorC || e.Distance < 20 { + w <- &Command{Stop: true} + } + } + + /* log.Println("send -45") + time.Sleep(3 * time.Second) + Write(s, &Command{Direction: 5}) + + log.Println("send +45") + time.Sleep(3 * time.Second) + Write(s, &Command{Direction: 175}) + + log.Println("send +0") + time.Sleep(3 * time.Second) + Write(s, &Command{Direction: 90}) + */ + + /* log.Println("send motor") + Write(s, &Command{SpeedL: 200, SpeedR: 200, StopAfter: 1000}) + time.Sleep(time.Second) + + log.Println("send motor turn") + time.Sleep(time.Second) + Write(s, &Command{SpeedL: -250, SpeedR: 250, StopAfter: 500}) + + log.Println("send motor turn") + time.Sleep(time.Second) + Write(s, &Command{SpeedL: 250, SpeedR: -250, StopAfter: 500}) + */ + + /* MOTOR + cmd.SpeedL = 200 + cmd.SpeedR = 0 + cmd.Stop = false + Write(s, cmd) + time.Sleep(3 * time.Second) + + cmd.SpeedL = 0 + cmd.SpeedR = 0 + cmd.Stop = true + Write(s, cmd) + time.Sleep(3 * time.Second) + + cmd.SpeedL = 0 + cmd.SpeedR = 200 + cmd.Stop = false + Write(s, cmd) + time.Sleep(3 * time.Second) + + cmd.SpeedL = 0 + cmd.SpeedR = 0 + cmd.Stop = true + Write(s, cmd) + */ +} -- cgit v1.2.3