libmup
Reference implementation library of the M.A.R-T>Y. Micro Protocol for small-ish networked systems.
Functionality Status: Iterative
Download for your language(s) at bottom of the page.
libmup is an endpoint-based RPC framework for small-ish interlinked systems providing serialization, request/response, variadic payloads, heartbeat messages and optional CRC32 routines in various languages.
For compatibility and portability this library does not use any dynamically allocated memory.
M.A.R-T>Y. Micro Protocol (MuP) shares similarities to its bigger brother UNIX host-based RPC protocol but with a more basic and rigid structure. There are a variety of message types, but the request type 'SEND' still allows hitting endpoints with a variable payload count. To learn more about the M.A.R-T>Y. Micro Protocol read the definition document here.
This library does not do everything for you. It handles the boring stuff (putting bytes in a line and taking them out, error detection, definitions for endpoints and request/response, emitting events, etc.) but your application actually has to make use of them. In this way you can pick and choose the level of functionality; you don't have to use/handle everything if it's unecessary.
libmup provides:
- definitions for every type and argument in MuP
- structs representing packets, endpoints and state
- enums representing errors and protocol-level events
- internal crc32 table & routines enabled/disabled with a #define
- serialize & deserialize functions for converting between structs and buffers
- payload addition/yield functions for handling variadic payloads
- event processing which emits protocol-level events based on the last message
- #define modifiers to enable/disable functionality
libmup does NOT provide (i.e. left to the application designer):
- receive and transmit functions
- event handler functions or callbacks
- automatic timed 'SONAR' pings (heartbeat) or transmission of pongs*
- automatic transmission of 'API' type responses
- automatic transmission of 'BAD' type messages**
- automatic retransmission of corrupted messages***
- an automated 'INIT' handshake
- implementation of endpoints or parameter bound checking
*if a sonar ping is received the event processor will automatically serialize a reply, but your event handler must transmit it.
**the event processor will automatically serialize these, but your event handler must transmit if you desire.
***the event processor will emit a corruption event, and a 'BAD' type message will be automatically serialized. Your event handler must transmit it, then the connection partner must handle and re-transmit.
Usage Notes
- structs provided should be initialised with the mup_struct_factory functions. These can also be used to reset them for a fresh use after transmission for example.
- mup_add_payload will take in an external buffer and map its contents to the packet buffer at the next payload position.
- mup_register_payload will register a payload you have pre-filled in the packet buffer at the next payload position.
- Payloads should be terminated correctly before they are added/registered.
- Payloads should be added/registered in the correct order, then serialized and transmit before any other library calls on that packet. Other functions may modify the internal payload register of a packet if called before transmission, which could lead to undefined behaviour.
- mup_process_events is in charge of emitting events based on the received message, and it can deserialize it for you too. Typically you'd call it after a full packet is received (e.g. you get the packet terminator character), then check the event and handle accordingly.
- A complete list and description of #define modifiers can be found in libmup.h.
- If you want to use your own CRC routine (e.g. you have hardware accel) see the MUP_CFG_BYOC define notes in libmup.h and make sure to register a calculation function!
Pro Tips
- Define your endpoints as an array of MUEndpoint structs, and you can have the first payload in your messages be the index that represents that endpoint. Then your application knows what to do :)
- Check the MUPEvent enum in libmup.h for all the events mup_process_events exposes. They should be pretty self explanatory.
- mup_yield_payload is fastest if the payloads you asked for are called in ascending order starting from 0 due to the internal counter caching sizes. If you yield them out of order it will do a full packet scan.
- You can use CRC16 instead by enabling MUP_CFG_BYOC and have your calculation function return a uint32_t with the highest 2 bytes empty. Tables not included.
- You can completely disable CRC by enabling MUP_CFG_BYOC and define a calculation function that always return a constant like 0x00000000.
- In 'bring your own buffer' mode (MUP_CFG_BYOB) you only need to give the buffer to the mup_packet_factory the first time you call it. Subsequent calls can pass in NULL instead.
Download the libraries for the language(s) you want to use: