added more documentation
This commit is contained in:
-80
@@ -1,80 +0,0 @@
|
||||
# GEX core protocol
|
||||
|
||||
## Framing layer
|
||||
|
||||
GEX uses [TinyFrame](https://github.com/MightyPork/TinyFrame) to form and parse data frames.
|
||||
|
||||
- Frames are sent and received using two USB bulk endpoints (VCOM or raw access) or through UART.
|
||||
- Transmitted frame length is virtually unlimited
|
||||
- Received frame length is limited by the Rx buffer size.
|
||||
|
||||
### Frame structure
|
||||
|
||||
```none
|
||||
,------+----------+---------+------+------------+- - - - -+------------,
|
||||
| SOF | frame_id | pld_len | type | head_cksum | payload | pld_cksum |
|
||||
| 1 | 2 | 2 | 1 | 1 | ... | 1 | <- size (bytes)
|
||||
'------+----------+---------+------+------------+- - - - -+------------'
|
||||
```
|
||||
|
||||
- SOF byte is `0x01`
|
||||
- Checksum = inverted XOR of all bytes
|
||||
|
||||
The checksum is used to catch implementation mistakes (such as mistaken CR-LF transformations).
|
||||
USB bulk transfers have CRC error checking built-in.
|
||||
|
||||
*Frame ID* is incremented with each transaction (message, request-response or longer).
|
||||
The highest ID bit identifies the peer who started the transaction.
|
||||
|
||||
*Type* defines the meaning of the frame. A list is attached below.
|
||||
|
||||
## Message types
|
||||
|
||||
### General messages
|
||||
- `0x00` ... `SUCCESS` - Generic success response; used by default in all responses; payload is transaction-specific
|
||||
- `0x01` ... `PING` - Ping request, used to test connection
|
||||
- Response: ASCII string with the version and platform name
|
||||
- `0x02` ... `ERROR` - Generic failure response (when a request fails to execute)
|
||||
- Response: ASCII string with the error message
|
||||
|
||||
### Bulk transfer (large multi-frame transfer)
|
||||
Bulk transfer is used for reading / writing large files that exceed the TinyFrame buffer sizes.
|
||||
|
||||
- `0x03` ... `BULK_READ_OFFER` - Offer of data to read.
|
||||
- Payload: u32 total len
|
||||
- `0x04` ... `BULK_READ_POLL` - Request to read a previously announced chunk (`BULK_READ_OFFER`)
|
||||
- Payload: u32 max chunk size to read
|
||||
- Response: a `BULK_DATA` frame
|
||||
- `0x05` ... `BULK_WRITE_OFFER` - Offer to receive data in a write transaction.
|
||||
- This is an affirmation to some other frame that introduced a request to write bulk data.
|
||||
- Payload: u32 max total size, u32 max chunk size
|
||||
- `0x06` ... `BULK_DATA` - Writing a chunk, or sending a chunk to master.
|
||||
- `0x07` ... `BULK_END` - Bulk transfer is done, no more data to read or write. Recipient shall check total len and discard the received data on mismatch.
|
||||
- `0x08` ... `BULK_ABORT` - Discard the ongoing transfer (sent by either peer)
|
||||
|
||||
### Unit messages
|
||||
Units are instances of a particular unit driver. A unit driver is e.g. Digital Output or SPI.
|
||||
Each unit has a TYPE (which driver to use), NAME (for user convenience) and CALLSIGN (for messages)
|
||||
|
||||
In the INI file, all three are shown in the unit section: `[type:name@callsign]`
|
||||
|
||||
Units can accept commands and generate events. Both are identified by 1-byte codes.
|
||||
|
||||
- `0x10` ... `UNIT_REQUEST` - Command addressed to a particular unit
|
||||
- Payload: u8 callsign, u8 command, rest - data for a unit driver
|
||||
- `0x11` ... `UNIT_REPORT` - Spontaneous report from a unit
|
||||
- Payload: u8 callsign, u8 type, u64 usec timestamp, rest: data from unit driver
|
||||
|
||||
### System messages
|
||||
Settings management etc.
|
||||
|
||||
- `0x20` ... `LIST_UNITS` - Get all active unit call-signs, types and names
|
||||
- Response: u8 count, { u8 callsign, cstring type, cstring name }
|
||||
- `0x21` ... `INI_READ` - Read the ini file via bulk
|
||||
- starts a bulk read transfer
|
||||
- Response: a `BULK_READ_OFFER` frame
|
||||
- `0x22` ... `INI_WRITE` - Write the ini file via bulk
|
||||
- starts a bulk write transfer
|
||||
- Response: a `BULK_WRITE_OFFER` frame
|
||||
- `0x23` ... `PERSIST_CFG` - Write current settings to Flash (the equivalent of replacing the lock jumper / pushing the button if VFS is active)
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
# GEX's low-level communication protocol
|
||||
|
||||
## Framing layer
|
||||
|
||||
GEX uses [TinyFrame](https://github.com/MightyPork/TinyFrame) to form and parse data frames.
|
||||
|
||||
- Frames are normally sent and received using two USB bulk endpoints (VCOM or raw access) or through UART.
|
||||
- Transmitted frame length is virtually unlimited
|
||||
- Received frame length is limited by the Rx buffer size. This is overcome using a Bulk Write function.
|
||||
|
||||
### Frame structure
|
||||
|
||||
See the TinyFrame documentation for detailed description of the frame structure and protocol functions.
|
||||
|
||||
Here's the configuration used by GEX:
|
||||
|
||||
```none
|
||||
,------+----------+---------+------+------------+- - - - -+------------,
|
||||
| SOF | frame_id | pld_len | type | head_cksum | payload | pld_cksum |
|
||||
| 1 | 2 | 2 | 1 | 1 | ... | 1 | <- size (bytes)
|
||||
'------+----------+---------+------+------------+- - - - -+------------'
|
||||
```
|
||||
|
||||
- SOF byte is `0x01`
|
||||
- Checksum = inverted XOR of all bytes
|
||||
|
||||
USB bulk transfers have CRC error checking built-in. The checksum field is mainly used to catch
|
||||
implementation mistakes, such as a CR-LF transformation.
|
||||
|
||||
*Frame ID* is incremented with each transaction (message, request/response, or longer).
|
||||
The highest ID bit identifies the peer who started the transaction ("master", "slave").
|
||||
|
||||
*Type* defines the meaning of the frame within a higher level protocol. A list of all types is attached below.
|
||||
|
||||
## Message types
|
||||
|
||||
### General messages
|
||||
- `0x00` ... `SUCCESS` - Generic success response; used by default in all responses;
|
||||
- *Payload:*
|
||||
- optional, differs based on the request
|
||||
- `0x01` ... `PING` - Ping request, used to test connection
|
||||
- *Response:*
|
||||
- `SUCCESS` frame with an ASCII string containing the GEX version and the hardware platform name
|
||||
- `0x02` ... `ERROR` - Generic failure response, used when a request fails to execute
|
||||
- *Payload:*
|
||||
- ASCII string with the error message
|
||||
|
||||
### Bulk transfer (large multi-frame transfer)
|
||||
Bulk transfer is used for reading / writing large files that exceed the TinyFrame buffer sizes.
|
||||
|
||||
- `0x03` ... `BULK_READ_OFFER` - Offer of data to read.
|
||||
- *Payload:*
|
||||
- u32 - total len
|
||||
- `0x04` ... `BULK_READ_POLL` - Request to read a previously announced chunk (`BULK_READ_OFFER`)
|
||||
- *Payload:*
|
||||
- u32 - max chunk size to read
|
||||
- Response: a `BULK_DATA` frame (see below)
|
||||
- `0x05` ... `BULK_WRITE_OFFER` - Offer to receive data in a write transaction.
|
||||
- This is a report of readiness after some other frame introduced a request to write bulk data
|
||||
(e.g. writing a config file)
|
||||
- *Payload:*
|
||||
- u32 - max total size
|
||||
- u32 - max chunk size
|
||||
- `0x06` ... `BULK_DATA` - Writing a chunk, or sending a chunk to master.
|
||||
- *Payload:*
|
||||
- a block of data
|
||||
- `0x07` ... `BULK_END` - Bulk transfer is done, no more data to read or write. Recipient shall check total length and discard the received data on mismatch.
|
||||
- `0x08` ... `BULK_ABORT` - Abort and discard the ongoing transfer (sent by either peer)
|
||||
|
||||
### Unit messages
|
||||
Units are instances of a particular unit driver. A unit driver is e.g. Digital Output or SPI.
|
||||
Each unit has a TYPE (which driver to use), NAME (for user convenience) and CALLSIGN (for messages)
|
||||
|
||||
In the INI file, all three are shown in the unit section: `[type:name@callsign]`
|
||||
|
||||
Units can accept commands and generate events. Both are identified by 1-byte codes.
|
||||
|
||||
- `0x10` ... `UNIT_REQUEST` - Command addressed to a particular unit
|
||||
- *Payload:*
|
||||
- u8 callsign
|
||||
- u8 command
|
||||
- rest - data for a unit driver
|
||||
- `0x11` ... `UNIT_REPORT` - Spontaneous report from a unit
|
||||
- *Payload:*
|
||||
- u8 callsign
|
||||
- u8 report type
|
||||
- u64 usec timestamp
|
||||
- rest - data from unit driver
|
||||
|
||||
### System messages
|
||||
Settings management etc.
|
||||
|
||||
- `0x20` ... `LIST_UNITS` - Get all active unit call-signs, types and names
|
||||
- *Response:*
|
||||
- u8 number of units
|
||||
- repeat for each unit:
|
||||
- u8 callsign
|
||||
- cstring type
|
||||
- cstring name
|
||||
- `0x21` ... `INI_READ` - Read the ini file via bulk
|
||||
- starts a bulk read transfer
|
||||
- *Response:*
|
||||
- a `BULK_READ_OFFER` frame (see above)
|
||||
- `0x22` ... `INI_WRITE` - Write the ini file via bulk
|
||||
- starts a bulk write transfer
|
||||
- *Response:*
|
||||
- a `BULK_WRITE_OFFER` frame (see above)
|
||||
- `0x23` ... `PERSIST_CFG` - Write current settings to Flash
|
||||
- This is the equivalent of replacing the lock jumper / pushing the button when the virtual filesystem is enabled.
|
||||
- If the virtual filesystem is enabled, this also closes it.
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
# GEX's config files
|
||||
|
||||
GEX's configuration is stored in the internal flash memory in a packed binary form.
|
||||
To make its editing easier for the user, the configuration is accessible as INI files
|
||||
annotated by numerous comments explaining the individual config options.
|
||||
|
||||
## Filesystem access
|
||||
|
||||
There are two config files: `UNITS.INI` and `SYSTEM.INI`.
|
||||
|
||||
To access those files, the user presses the LOCK button (or removes the LOCK jumper),
|
||||
which enables an emulated FAT16 storage that will appear on the host computer as a USB disk.
|
||||
Some hardware platforms require that the jumper be removed before plugging in the USB cable,
|
||||
as it can't trigger re-enumeration without external circuitry, which is missing on those
|
||||
evaluation boards.
|
||||
|
||||
It's recommended to copy the INI files to a real disk before editing, as some editors create
|
||||
temporary back-up files that can confuse the filesystem emulator. However, in-place editing
|
||||
is also possible with some editors.
|
||||
|
||||
*This method is the only way of accessing the `SYSTEM.INI` file, which can reconfigure
|
||||
the main communication port.*
|
||||
|
||||
After writing the changed files back to the virtual disk, it will briefly disappear
|
||||
and an updated version of the files will become available for review.
|
||||
This is when you can check for error messages.
|
||||
|
||||
To confirm the config modifications (they take effect imemdiately, but are not written to flash yet),
|
||||
push the LOCK button again (or replace the LOCK jumper).
|
||||
|
||||
## API access
|
||||
|
||||
The `UNITS.INI` file may be accessed through the communication port.
|
||||
|
||||
The file is read using Bulk Read (see [FRAME_FORMAT.md](FRAME_FORMAT.md)) after sending a `INI_READ` request.
|
||||
|
||||
The modified file is written back using Bulk Write after sending a `INI_WRITE` request.
|
||||
|
||||
After writing the changed configuration, it may be persisted to flash using a `PERSIST_CFG` command.
|
||||
This is not required if the new configuration will be used only temporarily; the original settings
|
||||
will be restored after a restart.
|
||||
|
||||
## UNITS.INI file structure
|
||||
|
||||
The `UNITS.INI` file is interactive. The general layout is as follows:
|
||||
|
||||
```ini
|
||||
## UNITS.INI
|
||||
## GEX v0.0.1 on STM32F072-HUB
|
||||
## built Mar 17 2018 at 17:53:15
|
||||
|
||||
# Overwrite this file to change settings.
|
||||
# Press the LOCK button to save them to Flash.
|
||||
|
||||
[UNITS]
|
||||
# Create units by adding their names next to a type (e.g. DO=A,B),
|
||||
# remove the same way. Reload to update the unit sections below.
|
||||
|
||||
# Digital output
|
||||
DO=
|
||||
# Digital input with triggers
|
||||
DI=btn,btn2
|
||||
# (... more unit types here)
|
||||
|
||||
[DO:btn@1]
|
||||
# Port name
|
||||
port=B
|
||||
# Pins (comma separated, supports ranges)
|
||||
pins=2
|
||||
# Initially high pins
|
||||
initial=2
|
||||
# Open-drain pins
|
||||
open-drain=
|
||||
```
|
||||
|
||||
- The keys in the `[UNITS]` section are lists of instances for each unit type.
|
||||
After adding a name to the list and saving the file, a new unit section will appear below, offering to configure
|
||||
the new unit as needed.
|
||||
- Each unit section starts with `[type:name@callsign]`.The name must match the name used in the unit lists above.
|
||||
The callsign can be freely changed, as long as there is no conflict. Callsign 0 is forbidden and will be changed
|
||||
to a new unique callsign on save.
|
||||
- If an error occurs during unit initialization, an error message will appear under the unit's section header.
|
||||
|
||||
## GEX reconfiguration workflow
|
||||
|
||||
1. Enable the mass storage using the LOCK button or jumper (or use the API for reading and writing the file)
|
||||
2. Open the `UNITS.INI` file in a text editor
|
||||
3. If adding or removing unit instances, add their names to the right type (eg. `DO=LED`), save and reload the file.
|
||||
On some systems, it's necessary to close the editor right after saving and then reopen it again after the disk
|
||||
refreshes.
|
||||
4. Configure the units as needed; adjust callsigns if desired. Save and reload the file.
|
||||
5. Check for error messages under unit headers. Correct any problems. Save and reload to apply any changes.
|
||||
6. Push the LOCK button or replace the jumper to persist all changes to flash. If using the API, issue
|
||||
the `PERSIST_CFG` command for the same effect.
|
||||
|
||||
This is much easier when done through the API, perhaps using the PyQt GEX configuration utility included as an
|
||||
example in the Python client repository.
|
||||
@@ -0,0 +1,44 @@
|
||||
# GEX's internal structure
|
||||
|
||||
GEX is modular, composed of functional blocks called *units*. A unit can be e.g. SPI or a digital output.
|
||||
|
||||
There can be more than one instance of a given unit, based on the microcontroller's hardware resources.
|
||||
Some units use hardware peripherals, others are implemented in software. Those "soft" units (typically
|
||||
bit-banged protocols) are limited only by the available GPIO pins.
|
||||
|
||||
## Resources
|
||||
|
||||
A system of resource claiming is implemented to avoid units conflicting with each other and interfering with
|
||||
peripherals used internally by the system (such as the LED pin). Each unit claims the resources it uses during
|
||||
initialization. If the resource needed is not available, it may try to claim an alternate resource or fail to
|
||||
initialize.
|
||||
|
||||
A init failure is reported in the config file as an error message under the unit's header.
|
||||
|
||||
An example of defined resources:
|
||||
|
||||
- all GPIO pins
|
||||
- timers/counters
|
||||
- SPI, I2C, USART peripherals
|
||||
- DMA channels
|
||||
|
||||
## Unit identification
|
||||
|
||||
Each unit has a *name* and a *callsign* (1-255) used for message addressing. Both are defined in the config file.
|
||||
|
||||
There can be up to 255 units, in practice fewer due to storage limitations.
|
||||
|
||||
## Unit commands and events
|
||||
|
||||
Units can receive command messages (`UNIT_REQUEST`) and report asynchronous events using `UNIT_REPORT` frames.
|
||||
|
||||
A command is identified by a number 0-127. The highest bit (0x80) of the command number is reserved to request
|
||||
confirmation (a `SUCCESS` frame) if the command doesn't normally generate a response. This is used by the client
|
||||
library to check that an operation was completed correctly (as opposed to e.g. the firmware crashing and rebooting
|
||||
through the watchdog).
|
||||
|
||||
Unit events include the unit's callsign, a number 0-255 identifying the event type, and a 64-bit microsecond
|
||||
timestamp.
|
||||
|
||||
See [FRAME_FORMAT.md](FRAME_FORMAT.md) for the payloads structure.
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# GEX protocol documentation
|
||||
|
||||
This repository specifies the control protocol implemented by [gex-core](https://github.com/gexpander/gex-core).
|
||||
|
||||
- [FRAME_FORMAT.md](FRAME_FORMAT.md) - Low level frame format, message types
|
||||
- [INTERNAL_STRUCTURE.md](INTERNAL_STRUCTURE.md) - GEX's internal structure, units, requests and events
|
||||
- [INI_FILES.md](INI_FILES.md) - INI config files, filesystem and API access
|
||||
|
||||
- [UNIT_DO.md](UNIT_DO.md) - Digital Output unit
|
||||
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
# Digital Output
|
||||
|
||||
- Direct output access to one or more pins of a port.
|
||||
- All selected pins are written simultaneously.
|
||||
- Supports generating output pulses of precise length.
|
||||
|
||||
Pins are ordered in a descending order (DOWNTO) and accessed in a packed format,
|
||||
e.g. if pins 1 and 4 are selected (0b10010 on the port), the control word has
|
||||
two bits (4)(1) and e.g. 0b10 means pin 4, 0b11 both. This makes accessing the
|
||||
block of pins easier, e.g. when using them to drive a parallel bus.
|
||||
|
||||
## Commands
|
||||
|
||||
### WRITE
|
||||
Write a value to all defined pins.
|
||||
|
||||
*Payload:*
|
||||
- u16 - new value (packed)
|
||||
|
||||
### SET
|
||||
Set pins high
|
||||
|
||||
*Payload:*
|
||||
- u16 - pins to set high (packed)
|
||||
|
||||
### CLEAR
|
||||
Set pins low
|
||||
|
||||
*Payload:*
|
||||
- u16 - pins to set low (packed)
|
||||
|
||||
### TOGGLE
|
||||
Toggle selected pins (high - low)
|
||||
|
||||
*Payload:*
|
||||
- u16 - pins to toggle (packed)
|
||||
|
||||
### PULSE
|
||||
Send a pulse. The start will be aligned to 1 us or 1 ms (based on pulse length) of the internal timebase to ensure the highest length precision. (This alignment reduces time jitter.)
|
||||
|
||||
*Payload:*
|
||||
- u16 - pins to generate the pulse on (packed)
|
||||
- u8 - pulse active level (0, 1)
|
||||
- u8 - range (0 - milliseconds, 1 - microseconds)
|
||||
- u16 - duration in the selected range
|
||||
|
||||
*NOTE:* The microsecond range supports durations only up to 999 (1 ms), higher
|
||||
numbers will be divided by 1000 and use the millisecond range instead.
|
||||
|
||||
## Events
|
||||
|
||||
*No events defined for this unit type.*
|
||||
Reference in New Issue
Block a user