P364 is a lightweight, Firmata-inspired, bi-directional serial protocol for Arduino that supports command execution, request–response data exchange, and periodic data synchronization with a host computer. It enables up to 4,096 commands, multi-argument execution, and efficient syncing of up to 64 variables.
Off-load the bloat of serial communication without having to sacrifice the usage of libraries or custom code on your Arduino!
Some Host Protocols are available here.
- Processing: WIP
Otherwise, you can create your own protocol implementation based on the specifications mentioned under Usage.
Simply upload the entire Repo to an Arduino. You can then code the rest of your project at the bottom of the .ino file, after the protocol code. (This is to ensure that all of the methods connected to the protocol are accessible from your own code).
By checking the Serial Monitor for any $<ind><data> formatted string
By sending !13 to turn the on-board LED on/off
By sending ?PP1 and getting ?1PONG as a reply on the Serial Monitor
The host can send to the Arduino 2 types of requests. Command requests imply that the Arduino will execute an internal method, while a Data Request will return a specific value/state at a specific moment.
| Request Type | Prefix | Format | Use Case |
|---|---|---|---|
| Command | ! |
!<req>/<arg1>/.../<arg4> |
Run functions on the Arduino |
| Data Request | ? |
?<req><index> |
One-off data request for a specific state/value |
Keep in mind that this Repo only provides the Arduino Protocol. It's up to individual users to create a Host Protocol.
Commands are straight forward. The bare-bones implementation would be sending a correctly formatted string.
Requests are a bit more complex. While the bare-bones is quite straight-forward (listen for a reply of format ?<index><data>), multiple requests at once would require the implementation of a host-sided buffer.
Each type of request has a 2 character identifier. Both types of Host -> Arduino Requests utilize a switch in order to determine what logic needs to be executed.
For performance, this protocol uses Integer Packing to handle 2-character identifiers within the switch statement. This avoids the overhead of string comparisons. The syntax for a new case is ('A' << 8 | 'B') where you can replace A and B with the 2 characters you want.
For Command Requests, you can add another condition to the switch found under the processCommand() function
case ('A' << 8 | 'B'): // AB (Alpha Beta)
COMMAND_CommandNameHere(); // Name of the method you want to run whenever this command is received
break;For Data Requests, you need to update the processDataRequest() function.
It's recommended to use the included returnData(data) method, which automatically formats and writes to Serial a string or int bit of data.
case ('P' << 8 | 'P'): // PP (Ping Pong)
returnData("PONG");
break;
| Type | Prefix | Format | Use Case |
|---|---|---|---|
| Data Sync | $ |
$<ind><data> |
Continuously update the host about a specific value or state of the Arduino |
Keep in mind that, while this protocol supports up to 64 simultanious syncs, this amount can seriously slow down your Arduino. There is a trade-off between variable amount and frequency of data syncing. An Arduino that does nothing but periodically check multiple sensors and update their state every couple of minutes can very well utilize all 64 slots, but more frequent updates require less data to be periodically sent.
To continously sync data between the Arduino and your Host, update the dataSyncLoop() function.
processDataSyncing(<ind>, <data>)
You can tell the protocol to sync a specific value by running processDataSyncing(<ind>, <data>) from within the Arduino.
You can either execute this within the dataSyncLoop(), which will periodically update multiple variables multiple times per second (default is every 250ms), or execute that command from anywhere in your code in order to force a sync at a specific moment.


