|
rcbench
Servo and ESC test bench: panel, IOmcu and shared C
|
The OpenYGE ESC (electronic speed controller) protocol: framing, telemetry, status and parameters. More...
#include <stdbool.h>#include <stddef.h>#include <stdint.h>Go to the source code of this file.
Data Structures | |
| struct | openyge_header_t |
| struct | openyge_frame_t |
| One decoded frame: header and payload. More... | |
| struct | openyge_decoder_t |
| Byte buffer and counters of the resynchronising decoder. More... | |
| struct | openyge_telemetry_t |
| struct | openyge_status_t |
| Decoded status byte. More... | |
| struct | openyge_params_t |
Macros | |
| #define | OPENYGE_SYNC 0xA5u |
| #define | OPENYGE_VERSION 3u |
| #define | OPENYGE_HDR_V3 6u |
| #define | OPENYGE_HDR_LEGACY 4u |
| #define | OPENYGE_CRC_BYTES 2u |
| #define | OPENYGE_TELEMETRY_BYTES 26u |
| #define | OPENYGE_CONTROL_BYTES 4u |
| #define | OPENYGE_MIN_FRAME (OPENYGE_HDR_LEGACY + OPENYGE_CRC_BYTES) |
| The shortest possible frame: legacy header plus CRC (cyclic redundancy check). | |
| #define | OPENYGE_MAX_FRAME 140u |
| #define | OPENYGE_CRC_INIT 0x0000u |
| CRC-16/XMODEM: polynomial 0x1021, no reflection, no final XOR, seed 0x0000. | |
| #define | OPENYGE_CRC_CHECK 0x31C3u |
| #define | OPENYGE_DEV_MASTER 0x80u |
| Address byte: bit 7 set means the sender is the master. | |
| #define | OPENYGE_DEV_ADDR_MASK 0x7Fu |
| #define | OPENYGE_DEV_BROADCAST 0x00u |
| #define | OPENYGE_TEMP_OFFSET 40 |
| Temperatures travel as °C + 40, so −40 is representable in a uint8. | |
| #define | OPENYGE_MAX_PARAMS 64 |
| The bitmap that tracks which indices have been seen is 64 bits wide. | |
| #define | OPENYGE_P_COUNT 0 |
| Indices this project relies on. | |
| #define | OPENYGE_P_MOTOR_POLES 20 |
| #define | OPENYGE_P_PINION_TEETH 21 |
| #define | OPENYGE_P_MAIN_TEETH 22 |
Enumerations | |
| enum | openyge_frame_type_t { OPENYGE_FT_TELE_AUTO = 0x00 , OPENYGE_FT_TELE_RESP = 0x02 , OPENYGE_FT_TELE_REQ = 0x03 , OPENYGE_FT_WRITE_PARAM_RESP = 0x04 , OPENYGE_FT_WRITE_PARAM_REQ = 0x05 } |
| Frame type codes, the type byte of the header. More... | |
| enum | openyge_subject_t { OPENYGE_SUBJECT_ESC = 0 , OPENYGE_SUBJECT_BEC } |
| Which device the warning bits are talking about. | |
| enum | openyge_state_t { OPENYGE_ST_DISARMED = 0x0 , OPENYGE_ST_POWER_CUT = 0x1 , OPENYGE_ST_FAST_START = 0x2 , OPENYGE_ST_ALIGN_FOR_POS = 0x4 , OPENYGE_ST_BRAKING_NORM_FINI = 0x6 , OPENYGE_ST_BRAKING_SYNC_FINI = 0x7 , OPENYGE_ST_STARTING = 0x8 , OPENYGE_ST_BRAKING_NORM = 0x9 , OPENYGE_ST_BRAKING_SYNC = 0xA , OPENYGE_ST_WINDMILLING = 0xC , OPENYGE_ST_RUNNING_NORM = 0xE } |
| The motor states. More... | |
Functions | |
| uint16_t | openyge_crc (uint16_t crc, const void *data, size_t len) |
Fold len bytes at data into crc and return the new accumulator. | |
| void | openyge_decoder_reset (openyge_decoder_t *d) |
| Clear a decoder, buffer and counters. | |
| bool | openyge_decode_byte (openyge_decoder_t *d, uint8_t byte, openyge_frame_t *out) |
Feed one received byte; returns true when out holds a whole good frame. | |
| bool | openyge_frame_has_telemetry (const openyge_frame_t *f) |
| True if this frame is one an ESC sends, i.e. one carrying telemetry. | |
| bool | openyge_telemetry_parse (const openyge_frame_t *f, openyge_telemetry_t *out) |
| Parse the telemetry payload. | |
| bool | openyge_control_parse (const openyge_frame_t *f, uint16_t *index, uint16_t *param) |
| Parse the 4-byte control payload of a request. | |
| size_t | openyge_encode (uint8_t *out, size_t cap, uint8_t type, uint8_t device, uint8_t seq, const void *payload, size_t payload_len) |
| Build a frame. | |
| size_t | openyge_build_telemetry_request (uint8_t *out, size_t cap, uint8_t device, uint8_t seq) |
| A telemetry request: the control payload, both words zero. | |
| size_t | openyge_build_param_write (uint8_t *out, size_t cap, uint8_t device, uint8_t seq, uint16_t index, uint16_t value) |
| A single parameter write. | |
| void | openyge_status_decode (uint8_t status1, openyge_status_t *out) |
| Decode the status byte of a telemetry frame. | |
| const char * | openyge_state_name (uint8_t state) |
| A short name for a motor state, or "?" for a reserved value. | |
| void | openyge_params_reset (openyge_params_t *p) |
| Clear the parameter cache. | |
| void | openyge_params_observe (openyge_params_t *p, uint16_t index, uint16_t value) |
| Record one (index, value) pair from a telemetry frame. | |
| void | openyge_params_begin_writes (openyge_params_t *p) |
| Mark writes outstanding, which withdraws the table until it is re-read. | |
| void | openyge_params_end_writes (openyge_params_t *p) |
| Clear the outstanding-writes mark. | |
| bool | openyge_params_complete (const openyge_params_t *p) |
| True once every index 0..count-1 has been seen and no write is pending. | |
| bool | openyge_params_get (const openyge_params_t *p, uint16_t index, uint16_t *out) |
| Read one. | |
| float | openyge_params_progress (const openyge_params_t *p) |
| 0..1, for a progress bar. | |
| bool | openyge_motor_rpm (const openyge_params_t *p, uint32_t erpm, float *motor_rpm) |
| Mechanical and head RPM (revolutions per minute) from eRPM (electrical RPM) and the gear train. | |
| bool | openyge_head_rpm (const openyge_params_t *p, uint32_t erpm, float *head_rpm) |
| Head rpm from eRPM and the gear train. | |
The OpenYGE ESC (electronic speed controller) protocol: framing, telemetry, status and parameters.
Implements the OpenYGE telemetry and parameter protocol of YGE ESCs. YGE and OpenYGE are names or trademarks of their respective owners; they are used here only to say which ESCs this module works with (NOTICE, "Trademarks").
Written from docs/OpenYGE.md, the specification of record. Anything that page marks as inferred is inferred here too, and each such place carries a comment.
Boundaries of this module:
SPDX-License-Identifier: MIT
| #define OPENYGE_CONTROL_BYTES 4u |
control payload length
| #define OPENYGE_CRC_BYTES 2u |
CRC trailer, little-endian
| #define OPENYGE_CRC_INIT 0x0000u |
CRC-16/XMODEM: polynomial 0x1021, no reflection, no final XOR, seed 0x0000.
The check value is over the 9 bytes of the ASCII string "123456789"; an implementation at the far end is verified against it before it is trusted.
| #define OPENYGE_HDR_LEGACY 4u |
pre-v3: no seq, no device
| #define OPENYGE_HDR_V3 6u |
header bytes, version 3 and up
| #define OPENYGE_MAX_FRAME 140u |
largest frame, in bytes
| #define OPENYGE_P_COUNT 0 |
Indices this project relies on.
Every other index is carried, not used. These are unconfirmed too; confirm them before anything is written.
| #define OPENYGE_SYNC 0xA5u |
first byte of every frame
| #define OPENYGE_TELEMETRY_BYTES 26u |
telemetry payload length
| #define OPENYGE_VERSION 3u |
the version this speaks; a frame of version 3 or above is read with the 6-byte header
| enum openyge_frame_type_t |
| enum openyge_state_t |
The motor states.
Reserved values are not listed and must not be mapped onto a neighbour; show the number.
| size_t openyge_build_param_write | ( | uint8_t * | out, |
| size_t | cap, | ||
| uint8_t | device, | ||
| uint8_t | seq, | ||
| uint16_t | index, | ||
| uint16_t | value ) |
A single parameter write.
One parameter per frame; there is no page write.
| out | Buffer to write the frame into. |
| cap | Size of out in bytes. |
| device | Device address, without the master bit. |
| seq | Sequence number. |
| index | Parameter index. |
| value | Value to write. |
| size_t openyge_build_telemetry_request | ( | uint8_t * | out, |
| size_t | cap, | ||
| uint8_t | device, | ||
| uint8_t | seq ) |
A telemetry request: the control payload, both words zero.
| out | Buffer to write the frame into. |
| cap | Size of out in bytes. |
| device | Device address, without the master bit. |
| seq | Sequence number. |
| bool openyge_control_parse | ( | const openyge_frame_t * | f, |
| uint16_t * | index, | ||
| uint16_t * | param ) |
Parse the 4-byte control payload of a request.
| f | Decoded frame. |
| index | Receives the parameter index; NULL to skip. |
| param | Receives the parameter value; NULL to skip. |
| uint16_t openyge_crc | ( | uint16_t | crc, |
| const void * | data, | ||
| size_t | len ) |
Fold len bytes at data into crc and return the new accumulator.
A frame's CRC is openyge_crc(OPENYGE_CRC_INIT, frame, total - 2), stored little-endian in the frame's last 2 bytes. Incremental: folding a buffer in pieces gives what folding it whole gives. A len of 0 returns crc and reads nothing.
| crc | Accumulator from an earlier call, or OPENYGE_CRC_INIT. |
| data | Bytes to fold. |
| len | Number of bytes in data. |
| bool openyge_decode_byte | ( | openyge_decoder_t * | d, |
| uint8_t | byte, | ||
| openyge_frame_t * | out ) |
Feed one received byte; returns true when out holds a whole good frame.
Resynchronising: noise carrying a plausible sync byte in front of a real frame must not swallow the real one. Every sync byte in the buffer is a candidate and the earliest complete candidate wins.
| d | Decoder state. |
| byte | Received byte. |
| out | Receives the frame when true is returned. |
| void openyge_decoder_reset | ( | openyge_decoder_t * | d | ) |
Clear a decoder, buffer and counters.
| d | Decoder to clear; NULL does nothing. |
| size_t openyge_encode | ( | uint8_t * | out, |
| size_t | cap, | ||
| uint8_t | type, | ||
| uint8_t | device, | ||
| uint8_t | seq, | ||
| const void * | payload, | ||
| size_t | payload_len ) |
Build a frame.
Returns its length, or 0 if it would not fit or the type is not one this speaks.
The length byte is written from what was assembled, after the bounds check, so a frame that does not fit leaves the buffer untouched.
| out | Buffer to write the frame into. |
| cap | Size of out in bytes. |
| type | One of openyge_frame_type_t. |
| device | Device address, without the master bit. |
| seq | Sequence number. |
| payload | Payload bytes. |
| payload_len | Payload length; must match the type's payload size. |
| bool openyge_frame_has_telemetry | ( | const openyge_frame_t * | f | ) |
True if this frame is one an ESC sends, i.e. one carrying telemetry.
| f | Decoded frame. |
| bool openyge_head_rpm | ( | const openyge_params_t * | p, |
| uint32_t | erpm, | ||
| float * | head_rpm ) |
Head rpm from eRPM and the gear train.
| p | Cache with the pole count and both gear teeth counts. |
| erpm | Electrical rpm. |
| head_rpm | Receives the head rpm. |
| bool openyge_motor_rpm | ( | const openyge_params_t * | p, |
| uint32_t | erpm, | ||
| float * | motor_rpm ) |
Mechanical and head RPM (revolutions per minute) from eRPM (electrical RPM) and the gear train.
False unless the table is complete and the pole count is at least 2. Head speed needs the pinion and main gear teeth too; when either is zero the head figure is not written.
| p | Cache with the pole count. |
| erpm | Electrical rpm. |
| motor_rpm | Receives the motor rpm. |
| void openyge_params_begin_writes | ( | openyge_params_t * | p | ) |
Mark writes outstanding, which withdraws the table until it is re-read.
| p | Cache to update; NULL does nothing. |
| bool openyge_params_complete | ( | const openyge_params_t * | p | ) |
True once every index 0..count-1 has been seen and no write is pending.
| p | Cache to test. |
| void openyge_params_end_writes | ( | openyge_params_t * | p | ) |
Clear the outstanding-writes mark.
| p | Cache to update; NULL does nothing. |
| bool openyge_params_get | ( | const openyge_params_t * | p, |
| uint16_t | index, | ||
| uint16_t * | out ) |
Read one.
False unless the whole table is complete: a half-read table is not the ESC's settings.
| p | Cache to read. |
| index | Parameter index, below the table count. |
| out | Receives the value. |
| void openyge_params_observe | ( | openyge_params_t * | p, |
| uint16_t | index, | ||
| uint16_t | value ) |
Record one (index, value) pair from a telemetry frame.
Ignored while writes are outstanding: a frame already in flight from before a write carries the old value and would overwrite the new one.
| p | Cache to update. |
| index | Parameter index, below OPENYGE_MAX_PARAMS; other values are ignored. |
| value | Parameter value. |
| float openyge_params_progress | ( | const openyge_params_t * | p | ) |
0..1, for a progress bar.
The table fills in about 1.6s at 20Hz and 32 parameters.
| p | Cache to read. |
| void openyge_params_reset | ( | openyge_params_t * | p | ) |
Clear the parameter cache.
| p | Cache to clear; NULL does nothing. |
| const char * openyge_state_name | ( | uint8_t | state | ) |
A short name for a motor state, or "?" for a reserved value.
| state | State value; only the low nibble is used. |
| void openyge_status_decode | ( | uint8_t | status1, |
| openyge_status_t * | out ) |
Decode the status byte of a telemetry frame.
| status1 | The status byte. |
| out | Receives the decoded status; NULL does nothing. |
| bool openyge_telemetry_parse | ( | const openyge_frame_t * | f, |
| openyge_telemetry_t * | out ) |
Parse the telemetry payload.
False if the frame does not carry one.
| f | Decoded frame. |
| out | Receives the telemetry. |
out is NULL.