google protocol buffers for embedded€¦ · nanopbboilerplate: • dsl proto idl nanopbstructs+...

41
© Zühlke 2018 Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018 Google Protocol Buffers for Embedded Integration in a medical device project

Upload: others

Post on 21-May-2020

6 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Google Protocol Buffers for Embedded

Integration in a medical device project

Page 2: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Quick look

1: Overview• What is it and why is useful

• Peers and alternatives

• Wire format and language syntax

• Libraries for Embedded

• Statistics

2: Project integration• Why did we choose it

• How it was used and integrated

• Custom communications stack

• Lessons learned

Page 3: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

And this is about testing…?

Well ok maybe not directly…

Open source:

• Has lots of eyes on stability and security

• Often comes with decent test coverage

• And yes it usually costs nothing

… yet it isn’t always the first choice

for embedded systems.

Page 4: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

The what?

§ Portable data interchange format for serialization across machine boundaries

§ Used in producer/consumer scenarios like:• Data blobs storage• Networks• PC to embedded devices• Multi-processor/controller

§ Specified wire exchange format

§ Implementation not mandated

§ Official implementations available

§ Google tools under BSD

Page 5: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

The why?

• Language and platform portable

• Full scalar data type coverage

• Wire size efficient (but not optimal)

• Fast runtime performance (but not optimal)

• Basis for a “Remote Procedure Protocol”

• Backbone of an OSI stack (Layers 2-5)

• Excellent documentation

• No magic tricks, straightforward spec

Page 6: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

What is it not?

• No encryption/decryption features

• Character encoding only: UTF-8, ASCII 7-bit

• No compression beyond encoding

• No RPC framework built in

• … but these things can be added

• It’s not self describing, the contract must be available!

Page 7: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Serialization has been around the block…

What could it replace?

• Tried and “true” methods include:• Soap, Corba, COM/DCOM

ü Flexible and comprehensive

X Heavy weight integration/use

X Not necessarily language/platform neutral

• JSON, XML, Raw Textü Highly portable

ü Human readable (kind of)

X Not cheap to parse

X Not cheap to encode

X Not cheap to store

X Not cheap to send

Page 8: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Apache Thrift

What are it’s peers?

• From an ex-googler (2007)… similarities

• was internal at Facebook, now open source

• Similar to PB in performance

• Similar feature set to PB and even more languages

• Full built in RPC layer

• Less documentation

• Still slightly less efficient

Page 9: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Apache Avro

The latest craze

• JSON Schema always available

• Payload can be binary or JSON

• Schema robust to changes (alias’s, defaults)

• Can read/write PB and Thrift!

• Similar speed/space to PB

• Comparatively limited language support

• Only recently stable (2016)

Page 10: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

We need to go faster…

But wait… there’s more!

• “Protocol Buffers” spawned streamlined “zero copy” serialization formats.

• Why do we even need to encode/decode?! Hell let’s mmap the data!

• April 2013: Cap’n Proto from author of “Protocol Buffers” v2

• December 2013: SBE (Simple Binary Encoder) for financial trading

• June 2014: Flat Buffers from Google for game development

• By nature faster than Google’s PB implementation, but beware the gotchas…

Page 11: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Roll your own

You could…

ü Specify only what you need

ü Can be faster

ü Can be smaller

X But …. lions, tigers, and bears… oh my!

Page 12: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

It’s been awhile!

Short history

• Developed internally at Google circa 2001

• Used as core glue for google services

• Released open source (2008) to public as stable and well tested

• Google’s implementation’s security has been verified

• Reward for finding XSS exploit in Google maps w/ Protobuf

Page 13: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Two options

Format Versions

• Proto2:• Full featured.

• C++, Java, Python, Javascript in official tools

• Other third party library options

• Version we choose

• Proto3:• Interface definition language (IDL) was streamlined

• A handful of new features

• More language support (ex. formal C#).

• Most features of wire format backwards compatible (beware the exceptions….)

Page 14: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Overview and integration

IDL

• Interface definition language specified by Google

• Files have .proto suffix

• Google compiler converts IDL to boilerplate

• Runtime libraries decode and encode streams

• Simple to read and write

Page 15: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Details

IDL syntax

• Versioning through unique IDs on fields.

• Fields can be required or optional (proto2 exclusively)

• Default values (proto3 type specific only)

• Messages are nestable

• Files are composable

• Most numerical values are efficient VARINTs

Page 16: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Proto2 example

IDL syntax

//Generic definitions in other protoimport “base.proto”

enum OperationType{

IDLE = 0;SLEEP = 1;DOWORK = 2;

}

message OperationRequest{

required OperationType requestType = 1;optional uint32 timeout = 2;optional bool sleepOnFinish = 3;

}

message Result{

required string resultString=1;optional uint32 timestamp=2;

}

message OperationResponse{

repeated Result result=1;}

Page 17: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Wire format

Above covers signed numbers (two possible encodings) and floats (@fixed32).Separate type for 64-bit fixed sized numbers

Page 18: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

A bit on the heavy side

But we didn’t use Google’s tools

Google C++ implementation under BSD• But it depends on STL…

• Dynamic allocation

• … code space starts around 100KB or more

You could strip it down,

… but Embedded was not the target market!

Page 19: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Alternatives

PB for embedded

• Various C libraries from third parties over the years:• … lwpb, Protobuf-embedded-c, empb

• The actives ones:• Protobuf-c

o New BSD licenseo Feature complete to google specificationo Dynamic allocations, but customizable with allocatorso > 20 KB rom

Page 20: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Nanopb

The winner is…

• Z-lib license

• Fully static by default

• Smallest @: ~2-10 rom KB and ~300 bytes ram

• Favors small size over serialization speed

• Strings/Byte Arrays use custom field options to specify size

• Precompile flags to tailor fit (ex. Field-tag size)

• For dynamic sized fields there are callbacks

• IDL processing: Google PB compiler + python plugin

• Complete documentation Unit tests included!

Page 21: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

You still have a spec!

May sound crazy…

• Optimize for your use case

• Example: Custom PB Serializer

• But still…

Page 22: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Comparison

Some statistics

NanoPB

vs ProtoBuf-C

vs Protobuf-Emb-C

Decoding on

QEMU-Simulator with

gcc and “All types message”

Page 23: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Sizes

Statistics

Page 24: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Enough overview and comparisons

Page 25: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Why NanoPB was our choice?

• No custom serialization spec, no XML/JSON

• Portability: C#, C/C++, and Java

• Size: Must run on mid-range microcontrollers

• License: Sell it on the customer

Page 26: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Scenarios

• Remote procedures:• Device operation through Host App(s) in C# and Java

• Services on Master controller <-> Services on hard real time controller

• Secondary cases:§ Data streaming to host

§ Portable data blobsMain Real time

Calculations

PC/Host

USBUART

UART

Page 27: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Use cases

State transitionsStatus updates

File transfers

Service operations

Module initialization Data queries

Log streaming

Page 28: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Constraints

• Main controller:q Plenty of ROM (> 1MB)

q RAM 256KB

q Middleware Embedded OS

• Real time controller:q 256 KB RAM + ROM

q Tight real time requirements

q No OS

It fits!

Page 29: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Diesel and Gaudi are the glue

• No RPC in Protocol Buffers but easy to add!

• Diesel DSL approach with ruby, rake, and Gaudi

• Our DSL target:• System - Shared definitions (types, enums, defines)

• Services – remote API for on device functional modules

Page 30: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Example%% Provides an interface to control LEDs on the device.service LED=15 {namespace = LEDversion = 2.0.0platform = device

%% Defines the types of LEDs.enum LEDType {prefix = eLDT

mapping {Red = 0Green = 1

}}

%% Turns on and off LEDs on the controller.command SetSteadyState=1 {encodable_from = host

fields {%% The type of LED to updateLEDType led_id = 1%% Desired status of the LEDbool enabled = 2

}}

Page 31: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Generate whatever you can!

NanoPB boilerplate:

• DSL Proto IDL NanoPB structs+

C++ boilerplate classes per service:• Decoders: byte streams NanoPB C-structs service API calls

• Encoders: API Calls NanoPB C-structs PB streams

Diesel PB compiler

Page 32: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

First attempt RPC

Packet structure

• Enveloping :

• Outer envelope(s) to address packet• Sequence ID

• Service ID

• Enum defining the actual payload

• Potential payloads as optional fields

• … it worked but was a bit of a headache and overhead

Page 33: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Custom meta format

Packet structure

• Two PB based packets back to back for each RPC.

1) Shared Header: Manually serialized using library.

2)Payload: Full PB message serialized using generated code.

No separator!

HeaderCRC,ID,Address

PayloadParameters

00

Page 34: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Packet streams

• Zero byte terminators

• Bytes reencoded with Consistent Overhead Byte Stuffing

• No “reserved” zero bytes in payload

ü Packets can be defined of unlimited size

ü Overhead minimum of 1 byte and maximum of n/254

x Errors require full resend

1 11 22 00 33 03 11 22 02 33 00

2 11 22 33 44 05 11 22 33 44 00

3 11 00 00 00 02 11 01 01 01 00

Page 35: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

So many types of bytes!

Example stream

• 04-0D-3F-02-01-20-10-03-18-05-20-01-28-21-

0A-15-46-4C-41-53-48-2F-43-4F-4E-46-49-47-2F-45-46-45-32-2E-49-4E-49-00

• Green = Zero byte overhead bytes

• Blue = Header field tag bytes

• Orange = Header field values

• Red = Payload bytes

Page 36: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Did we get the right message

Packet integrity

1. First field is CRC

2. CRC uses Fixed32 type

3. Initialize CRC to zero

4. Encode header and payload

5. Calculate CRC over encoded stream

6. Encode CRC value in zero’d bytes

7. Reverse the steps to verify

Page 37: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Sequence numbers

Stream integrity

• Initial version• Status ack/nack as normal message with status details

• Sequence number along with status field

• Too heavy weight and better suited with logging

• Light weight alternative• Just CRC header and sequence number payload

• Can be distinguished easily by field tags

• Lower bandwidth and faster performance

Page 38: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Made easy

Packet reception

• Wait on next zero byte in the stream

• Iterate the header fields

• Check integrity/validity

• Determine target service

• Switch statement to jump to destination function

Page 39: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

Lessons learned

ü Reliability from mature predefined protocol saves a lot of time

ü NanoPB implementation solid and efficient

ü Custom light weight RPC more than enough

ü Zlib license is low stress

ü Docs from Google and Nanopb comprehensive

ü Rarely needed to peek in the box

ü … and when we did it wasn’t scary

– More flexibility and features than needed

– Efficient but not optimal (4 byte minimum fixed size)

Page 40: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

It’s perfect right?

Open source…

• Advantages are clear when the project is popular!

• But free is not always appropriate:• Consider the licensing model … Is what’s free today free tomorrow?

• Verification doesn’t come for free, is the choice temporary or will it go the distance?

• https://blog.marcgravell.com/2018/04/having-serious-conversation-about-open.html

Page 41: Google Protocol Buffers for Embedded€¦ · NanoPBboilerplate: • DSL Proto IDL NanoPBstructs+ C++ boilerplate classes per service: • Decoders: byte streams NanoPBC-structs service

© Zühlke 2018Leveraging open source in embedded software projects for more efficient testing | Morgan Kita 14. June 2018

That’s all folks!

Morgan KitaExpert Software Engineer+49 174 302 [email protected]://de.linkedin.com/in/morgan-kita-6513a343https://www.zuehlke.com