Skip to content

Commit

Permalink
Clarify protocol. Disruptive changes: see below
Browse files Browse the repository at this point in the history
This huge commit tries to enhance several things related to the fw/cli protocol.
Generally, the idea is to be verbose, explicit and reuse conventions, in order to enhance code maintainability and understandability for the other contributors.

docs/protocol.md got heavily updated

Guidelines, also written in docs/protocol.md "New data payloads: guidelines for developers":
- Now protocol data exchanged over USB or BLE are defined in netdata.h as packed structs and values are stored in Network byte order (=Big Endian)
- Command-specific payloads are defined in their respective cmd_processor handler in app_cmd.c and chameleon_cmd.py
- Define C `struct` for cmd/resp data greater than a single byte, use and abuse of `struct.pack`/`struct.unpack` in Python. So one can understand the payload format at a simple glimpse.
- If single byte of data to return, still use a 1-byte `data`, not `status`.
- Use unambiguous types such as `uint16_t`, not `int` or `enum`. Cast explicitly `int` and `enum` to `uint_t` of proper size
- Use Network byte order for 16b and 32b integers
  - Macros `U16NTOHS`, `U32NTOHL` must be used on reception of a command payload.
  - Macros `U16HTONS`, `U32HTONL` must be used on creation of a response payload.
  - In Python, use the modifier `!` with all `struct.pack`/`struct.unpack`
- Concentrate payload parsing in the handlers, avoid further parsing in their callers. This is true for the firmware and the client.
- In cmd_processor handlers: don't reuse input `length`/`data` parameters for creating the response content
- Avoid hardcoding offsets, use `sizeof()`, `offsetof(struct, field)` in C and `struct.calcsize()` in Python
- Use the exact same command and fields names in firmware and in client, use function names matching the command names for their handlers unless there is a very good reason not to do so. This helps grepping around. Names must start with a letter, not a number, because some languages require it (e.g. `14a_scan` not possible in Python)
- Respect commands order in `m_data_cmd_map`, `data_cmd.h` and `chameleon_cmd.py` definitions
- Even if a command is not yet implemented in firmware or in client but a command number is allocated, add it to `data_cmd.h` and `chameleon_cmd.py` with some `FIXME: to be implemented` comment
- Validate data before using it, both when receiving command data in the firmware and when receiving response data in the client.
- Validate response status in client.

Disruptive changes:
- GET_DEVICE_CAPABILITIES: list of cmds in data are now really Big Endian
  Note: the initial attempt to use macros PP_HTONS were actually considering wrongly that the platform was Big Endian (BYTE_ORDER was actually undefined) while it is actually Little Endian.
- GET_APP_VERSION: response is now a tuple of bytes: major|minor (previously it was in reversed order as a single uint16_t in Little Endian)
- SET_SLOT_TAG_TYPE: tag_type now on 2 bytes, to prepare remapping of its enum
- SET_SLOT_DATA_DEFAULT: tag_type now on 2 bytes, to prepare remapping of its enum
- GET_SLOT_INFO: tag_type now on 2 bytes, to prepare remapping of its enum
- GET_DEVICE_CHIP_ID: now returns its 64b ID following Network byte order (previously, bytes were in the reverse order)
- GET_DEVICE_ADDRESS: now returns its 56b address following Network byte order (previously, bytes were in the reverse order). CLI does not reverse the response anymore so it displays the same value as before.
- GET_GIT_VERSION response status is now STATUS_DEVICE_SUCCESS
- GET_DEVICE_MODEL response status is now STATUS_DEVICE_SUCCESS
- MF1_READ_EMU_BLOCK_DATA response status is now STATUS_DEVICE_SUCCESS
- GET_DEVICE_CAPABILITIES response status is now STATUS_DEVICE_SUCCESS
- HF14A_SCAN: entirely new response format, room for ATS and multiple tags
- MF1_DETECT_SUPPORT response status is now HF_TAG_OK and support is indicated as bool in 1 byte of data
- MF1_DETECT_PRNG response status is now HF_TAG_OK and prng_type is returned in 1 byte of data with a new enum mf1_prng_type_t == MifareClassicPrngType
- MF1_DETECT_DARKSIDE response status is now HF_TAG_OK and darkside_status is returned in 1 byte of data with a new enum mf1_darkside_status_t == MifareClassicDarksideStatus
- MF1_DARKSIDE_ACQUIRE response status is now HF_TAG_OK and darkside_status is returned in 1 byte of data. If OK, followed by 24 bytes as previously
- not breaking but many commands have been renamed for consistency. you are invited to adapt your client for easier maintenance

Other changes:
- FW/CLI: changes to match the aforementioned guidelines
- CLI: does not instanciate ChameleonCMD on every single command
- CLI: query capabilities on connect, not on every single command if device does not support the get_device_capabilities command
- CLI: hw raw: detail status messages
- CLI: merge #143 manually
- CLI: HF14AInfo logic moved inside HF14AScan
- FW: replace dynamic cmd_map_init() by static cmd_map initialization
- probably many little ones I forgot about...

TODO:
- remap `tag_specific_type_t` enum to allow future tags (e.g. LF tags) without reshuffling enum and affecting users stored cards
- continue cmd list review, cf protocol.md
  - document cmd in protocol.md
  - apply recommendations given in "New data payloads: guidelines for developers"
  - use @expect_response_ng, temporary name as it should replace @expect_response once done everywhere
  - rewrite cmd pack if needed
  - rewrite cmd unpack if needed
  - rewrite resp pack if needed, replace num_to_bytes
  - rewrite resp unpack if needed, limit data parsing to cmd handlers, revise chameleon_cstruct
  - TEST!
  • Loading branch information
doegox committed Sep 14, 2023
1 parent 98605be commit b61657e
Show file tree
Hide file tree
Showing 30 changed files with 1,548 additions and 1,134 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...

## [unreleased][unreleased]
- Added guessed type information for NXP tags, and reorganization of HF information part. (@FlUxIuS)
- Added `hf settings blepair` command to get and set ble pairing enable state, and default disable ble pair. (@xianglin1998)
- Added `hf mf info` command to get UID/SAK/ATQA from slot (@Foxushka)
- Added `hw raw` to send raw command to Chameleon (@Foxushka)
Expand Down
4 changes: 4 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,7 @@ Limitations:
* SWO pin is shared with... SWO so when e.g. reflashing the device, garbage may appear on the monitoring terminal.
* SWO pin is also shared with the blue channel of the RGB slot LEDs, so faint blue may appear briefly when logs are sent and LED might not work properly when supposed to be blue.
# Resources
* [nRF52840 Objective Product Specification v0.5.1](https://infocenter.nordicsemi.com/pdf/nRF52840_OPS_v0.5.1.pdf)
5 changes: 5 additions & 0 deletions docs/images/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
all:
pdflatex --shell-escape protocol-packet.tex

clean:
rm *.aux *.log *.pdf
Binary file modified docs/images/protocol-packet.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions docs/images/protocol-packet.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
\documentclass[border=10pt,png]{standalone}
\usepackage{bytefield}
\usepackage{xcolor}

\begin{document}

\definecolor{lightcyan}{rgb}{0.85,1,1}
\definecolor{lightgreen}{rgb}{0.85,1,0.85}
\definecolor{lightred}{rgb}{1,0.85,0.85}
\begin{bytefield}[bitwidth=1.1em]{32}
\bitbox{8}[bgcolor=lightcyan]{SOF} &
\bitbox{8}[bgcolor=lightcyan]{LRC1} &
\bitbox{16}[bgcolor=lightgreen]{CMD} \\
\bitbox{16}[bgcolor=lightgreen]{STATUS} &
\bitbox{16}[bgcolor=lightgreen]{LEN} \\
\bitbox{8}[bgcolor=lightgreen]{LRC2} &
\bitbox[tlr]{24}[bgcolor=lightred]{} \\
\wordbox[lr]{1}[bgcolor=lightred]{DATA} \\
\wordbox[lr]{1}[bgcolor=lightred]{$\cdots$} \\
\bitbox[blr]{24}[bgcolor=lightred]{} &
\bitbox{8}[bgcolor=lightred]{LRC3}
\end{bytefield}

\end{document}
260 changes: 245 additions & 15 deletions docs/protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,258 @@

**WIP**

## Packets format
## Frame format

The communication with the application is not the easiest but is structured as follows:
The communication between the firmware and the client is made of frames structured as follows:

![](images/protocol-packet.png)

- **SOF**: `1 Byte`, the "Magic Byte" represent the start of a packet, must be `0x11`.
- **LRC1**: `1 Byte`, the LRC ([**L**ongitudinal **R**edundancy **C**heck](https://en.wikipedia.org/wiki/Longitudinal_redundancy_check)) of the `SOF`, must be `0xEF`.
- **CMD**: `2 Bytes` in unsigned [Big Endian](https://en.wikipedia.org/wiki/Endianness) format, each command have been assigned a unique number (e.g. `factoryReset(1020)`), this is what you are sending to the device.
- **STATUS**: `2 Bytes` in unsigned [Big Endian](https://en.wikipedia.org/wiki/Endianness) format. If the direction is from APP to hardware, the status is always `0x0000`. If the direction is from hardware to APP, the status is the result of the command.
- **LEN**: `2 Bytes` in unsigned [Big Endian](https://en.wikipedia.org/wiki/Endianness) format, the length of the data, maximum is `512`.
- **LRC2**: `1 Byte`, the LRC ([**L**ongitudinal **R**edundancy **C**heck](https://en.wikipedia.org/wiki/Longitudinal_redundancy_check)) of the `CMD`, `STATUS` and `LEN`.
- **DATA**: `LEN Bytes`, the data to send or receive, maximum is `512 Bytes`. This could be anything, for example you should sending key type, block number, and the card keys when reading a block.
- **LRC3**: `1 Byte`, the LRC ([**L**ongitudinal **R**edundancy **C**heck](https://en.wikipedia.org/wiki/Longitudinal_redundancy_check)) of the `DATA`.
- **SOF**: `1 byte`, "**S**tart-**O**f-**F**rame byte" represents the start of a packet, and must be equal to `0x11`.
- **LRC1**: `1 byte`, LRC over `SOF` byte, therefore must be equal to `0xEF`.
- **CMD**: `2 bytes`, each command have been assigned a unique number (e.g. `DATA_CMD_SET_SLOT_TAG_NICK` = `1007`).
- **STATUS**: `2 bytes`.
- From client to firmware, the status is always `0x0000`.
- From firmware to client, the status is the result of the command.
- **LEN**: `2 bytes`, length of the `DATA` field, maximum is `512`.
- **LRC2**: `1 byte`, LRC over `CMD|STATUS|LEN` bytes.
- **DATA**: `LEN bytes`, data to be sent or received, maximum is `512 bytes`. This payload depends on the exact command or response to command being used. See [Packet payloads](#packet-payloads) below.
- **LRC3**: `1 byte`, LRC over `DATA` bytes.

The total length of the packet is `LEN + 10` Bytes. For receiving, it is the exact same format.

Note: LRC2 and LRC3 can be computed equally as covering either the frame from its first byte or from the byte following the previous LRC, because previous LRC nullifies previous bytes LRC computation.
Notes:
* The same frame format is used for commands and for responses.
* All values are **unsigned** values, and if more than one byte, in **network byte order**, aka [Big Endian](https://en.wikipedia.org/wiki/Endianness) byte order.
* The total length of the packet is `LEN + 10` bytes, therefore it is between `10` and `522` bytes.
* The LRC ([**L**ongitudinal **R**edundancy **C**heck](https://en.wikipedia.org/wiki/Longitudinal_redundancy_check)) is the 8-bit two's-complement value of the sum of all bytes modulo $2^8$.
* LRC2 and LRC3 can be computed equally as covering either the frame from its first byte or from the byte following the previous LRC, because previous LRC nullifies previous bytes LRC computation.
E.g. LRC3(DATA) == LRC3(whole frame)

## Packet payloads
## Data payloads

Each command and response have their own payload formats.

TODO:
Standard response status is `STATUS_DEVICE_SUCCESS` for general commands, `HF_TAG_OK` for HF commands and `LF_TAG_OK` for LF commands.
See [Guidelines](#new-data-payloads-guidelines-for-developers) for more info.

**TODO:** check all status responses in all commands with `hw raw`

Beware, slots in protocol count from 0 to 7.

### 1000: GET_APP_VERSION
* Command: no data
* Response: 2 bytes: `version_major|version_minor`
### 1001: CHANGE_DEVICE_MODE
* Command: 1 byte. `0x00`=emulator mode, `0x01`=reader mode
* Response: no data
### 1002: GET_DEVICE_MODE
* Command: no data
* Response: data: 1 byte. `0x00`=emulator mode, `0x01`=reader mode
### 1003: SET_ACTIVE_SLOT
* Command: 1 byte. `slot_number` between 0 and 7
* Response: no data
### 1004: SET_SLOT_TAG_TYPE
* Command: 3 bytes. `slot_number|tag_type[2]` with `slot_number` between 0 and 7 and `tag_type` according to `tag_specific_type_t` enum.
* Response: no data

**TODO:** remap `tag_specific_type_t` enum. Maybe dissociate LF & HF types in 2 enums
### 1005: SET_SLOT_DATA_DEFAULT
* Command: 3 bytes. `slot_number|tag_type[2]` with `slot_number` between 0 and 7 and `tag_type` according to `tag_specific_type_t` enum.
* Response: no data

**TODO:** remap `tag_specific_type_t` enum. Maybe dissociate LF & HF types in 2 enums
### 1006: SET_SLOT_ENABLE
* Command: 2 bytes. `slot_number|enable` with `slot_number` between 0 and 7 and `enable` = `0x01` to enable, `0x00` to disable
* Response: no data
### 1007: SET_SLOT_TAG_NICK
* Command: 2+n bytes. `slot_number|sense_type|name[n]` with `slot_number` between 0 and 7, `sense_type` according to `tag_sense_type_t` enum and `name` a UTF-8 encoded string of max 32 bytes, no null terminator.
* Response: no data

**TODO:** rewrite cmd unpack
### 1008: GET_SLOT_TAG_NICK
* Command: 2 bytes. `slot_number|sense_type` with `slot_number` between 0 and 7 and `sense_type` according to `tag_sense_type_t` enum.
* Response: a UTF-8 encoded string of max 32 bytes, no null terminator. If no nick name has been recorded in Flash, response status is `STATUS_FLASH_READ_FAIL`.

**TODO:** rewrite cmd unpack
### 1009: SLOT_DATA_CONFIG_SAVE
* Command: no data
* Response: no data
### 1010: ENTER_BOOTLOADER
* Command: no data
* Response: this special command does not return and will interrupt the communication link while rebooting in bootloader mode, needed for DFU.
### 1011: GET_DEVICE_CHIP_ID
* Command: no data
* Response: 8 bytes. nRF `DEVICEID[8]` in Network byte order.
### 1012: GET_DEVICE_ADDRESS
* Command: no data
* Response: 6 bytes. nRF `DEVICEADDR[6]` in Network byte order. First 2 MSBits forced to `0b11` to match BLE static address.
### 1013: SAVE_SETTINGS
* Command: no data
* Response: no data
### 1014: RESET_SETTINGS
* Command: no data
* Response: no data
### 1015: SET_ANIMATION_MODE
* Command: 1 byte, according to `settings_animation_mode_t` enum.
* Response: no data
### 1016: GET_ANIMATION_MODE
* Command: no data
* Response: 1 byte, according to `settings_animation_mode_t` enum.
### 1017: GET_GIT_VERSION
* Command: no data
* Response: n bytes, a UTF-8 encoded string, no null terminator.
### 1018: GET_ACTIVE_SLOT
* Command: no data
* Response: 1 byte
### 1019: GET_SLOT_INFO
* Command: no data
* Response: 32 bytes, 8 tuples `hf_tag_type[2]|lf_tag_type[2]` according to `tag_specific_type_t` enum, for slots from 0 to 7

**TODO:** remap `tag_specific_type_t` enum. Maybe dissociate LF & HF types in 2 enums
### 1020: WIPE_FDS
* Command: no data
* Response: no data. Status is `STATUS_DEVICE_SUCCESS` or `STATUS_FLASH_WRITE_FAIL`. The device will reboot shortly after this command.
### 1023: GET_ENABLED_SLOTS
* Command: no data
* Response: 8 bytes, 8 bools = `0x00` or `0x01`, for slots from 0 to 7
### 1024: DELETE_SLOT_SENSE_TYPE
* Command: 2 bytes. `slot_number|sense_type` with `slot_number` between 0 and 7 and `sense_type` according to `tag_sense_type_t` enum.
* Response: no data
### 1025: GET_BATTERY_INFO
* Command: no data
* Response: 3 bytes, `voltage[2]|percentage`
### 1026: GET_BUTTON_PRESS_CONFIG
* Command: 1 byte. Char `A` or `B` (`a`/`b` tolerated too)
* Response: 1 byte, `button_function` according to `settings_button_function_t` enum.
### 1027: SET_BUTTON_PRESS_CONFIG
* Command: 2 bytes. `button|button_function` with `button` char `A` or `B` (`a`/`b` tolerated too) and `button_function` according to `settings_button_function_t` enum.
* Response: no data
### 1028: GET_LONG_BUTTON_PRESS_CONFIG
* Command: 1 byte. Char `A` or `B` (`a`/`b` tolerated too)
* Response: 1 byte, `button_function` according to `settings_button_function_t` enum.
### 1029: SET_LONG_BUTTON_PRESS_CONFIG
* Command: 2 bytes. `button|button_function` with `button` char `A` or `B` (`a`/`b` tolerated too) and `button_function` according to `settings_button_function_t` enum.
* Response: no data
### 1030: SET_BLE_PAIRING_KEY
* Command: 6 bytes. 6 ASCII-encoded digits.
* Response: no data
### 1031: GET_BLE_PAIRING_KEY
* Command: no data
* Response: 6 bytes. 6 ASCII-encoded digits.
### 1032: DELETE_ALL_BLE_BONDS
* Command: no data
* Response: no data
### 1033: GET_DEVICE_MODEL
* Command: no data
* Response: 1 byte. `hw_version` aka `NRF_DFU_HW_VERSION` (0=Ultra, 1=Lite)
### 1034: GET_DEVICE_SETTINGS
* Command: no data
* Response: 14 bytes
* `settings_current_version` = `5`
* `animation_mode`, cf [GET_ANIMATION_MODE](#1016-get_animation_mode)
* `btn_press_A`, cf [GET_BUTTON_PRESS_CONFIG](#1026-get_button_press_config)
* `btn_press_B`, cf [GET_BUTTON_PRESS_CONFIG](#1026-get_button_press_config)
* `btn_long_press_A`, cf [GET_LONG_BUTTON_PRESS_CONFIG](#1028-get_long_button_press_config)
* `btn_long_press_B`, cf [GET_LONG_BUTTON_PRESS_CONFIG](#1028-get_long_button_press_config)
* `ble_pairing_enable`, cf [GET_BLE_PAIRING_ENABLE](#1036-get_ble_pairing_enable)
* `ble_pairing_key[6]`, cf [GET_BLE_PAIRING_KEY](#1031-get_ble_pairing_key)

### 1035: GET_DEVICE_CAPABILITIES
* Command: no data
* Response: 2*n bytes, a list of supported commands IDs.
### 1036: GET_BLE_PAIRING_ENABLE
* Command: no data
* Response: 1 byte, bool = `0x00` or `0x01`
### 1037: SET_BLE_PAIRING_ENABLE
* Command: 1 byte, bool = `0x00` or `0x01`
* Response: no data
### 2000: HF14A_SCAN
* Command: no data
* Response: N bytes: `tag1_data|tag2_data|...` with each tag: `uidlen|uid[uidlen]|atqa[2]|sak|atslen|ats[atslen]`

Notes:
* remind that if no tag is present, status will be `HF_TAG_NO` and Response empty.
* at the moment, the firmware supports only one tag, but get your client ready for more!
* `atslen` must not be confused with `ats[0]`==`TL`. So `atslen|ats` = `00` means no ATS while `0100` would be an empty ATS.
### 2001: MF1_DETECT_SUPPORT
* Command: no data
* Response: 1 byte, bool = `0x00` or `0x01`
### 2002: MF1_DETECT_PRNG
* Command: no data
* Response: 1 byte, according to `mf1_nested_type_t` enum
### 2003: MF1_DETECT_DARKSIDE
* Command: no data
* Response: 1 byte, according to `mf1_darkside_status_t` enum
### 2004: MF1_DARKSIDE_ACQUIRE
* Command: 4 bytes: `type_target|block_target|first_recover|sync_max`
* Response: 1 byte if Darkside failed, according to `mf1_darkside_status_t` enum,
else 25 bytes `darkside_status|uid[4]|nt1[4]|par[4]|ks1[4]|nr[4]|ar[4]`
### 2005: MF1_DETECT_NT_DIST
* Command: 8 bytes: `type_known|block_known|key_known[6]`
* Response: 8 bytes: `uid[4]|dist[4]`
### 2006: MF1_NESTED_ACQUIRE
* Command: 10 bytes: `type_known|block_known|key_known[6]|type_target|block_target`
* Response: N*9 bytes: N tuples of `nt[4]|nt_enc[4]|par`
### 2007: MF1_AUTH_ONE_KEY_BLOCK
* Command: 8 bytes: `type|block|key[6]`
* Response: no data
* Status will be `HF_TAG_OK` if auth succeeded, else `MF_ERR_AUTH`
### 2008: MF1_READ_ONE_BLOCK
* Command: 8 bytes: `type|block|key[6]`
* Response: 16 bytes: `block_data[16]`
### 2009: MF1_WRITE_ONE_BLOCK
* Command: 24 bytes: `type|block|key[6]|block_data[16]`
* Response: no data
### 3000: EM410X_SCAN
### 3001: EM410X_WRITE_TO_T55XX
### 4000: MF1_WRITE_EMU_BLOCK_DATA
### 4001: MF1_SET_ANTI_COLLISION_RES
* FIXME: rename as MF1_SET_ANTI_COLL_DATA ?
### 4002: MF1_SET_ANTI_COLLISION_INFO
* FIXME: not implemented, delete?
### 4003: MF1_SET_ATS_RESOURCE
* FIXME: not implemented
### 4004: MF1_SET_DETECTION_ENABLE
### 4005: MF1_GET_DETECTION_COUNT
### 4006: MF1_GET_DETECTION_LOG
### 4007: MF1_GET_DETECTION_STATUS
### 4008: MF1_READ_EMU_BLOCK_DATA
### 4009: MF1_GET_EMULATOR_CONFIG
### 4010: MF1_GET_GEN1A_MODE
### 4011: MF1_SET_GEN1A_MODE
### 4012: MF1_GET_GEN2_MODE
### 4013: MF1_SET_GEN2_MODE
### 4014: MF1_GET_BLOCK_ANTI_COLL_MODE
### 4015: MF1_SET_BLOCK_ANTI_COLL_MODE
### 4016: MF1_GET_WRITE_MODE
### 4017: MF1_SET_WRITE_MODE
### 4018: MF1_GET_ANTI_COLL_DATA
### 5000: EM410X_SET_EMU_ID
### 5001: EM410X_GET_EMU_ID


## New data payloads: guidelines for developers

If you need to define new payloads for new commands, try to follow these guidelines.

### Guideline: Verbose and explicit
Be verbose, explicit and reuse conventions, in order to enhance code maintainability and understandability for the other contributors
### Guideline: Structs
- Define C `struct` for cmd/resp data greater than a single byte, use and abuse of `struct.pack`/`struct.unpack` in Python. So one can understand the payload format at a simple glimpse.
- Avoid hardcoding offsets, use `sizeof()`, `offsetof(struct, field)` in C and `struct.calcsize()` in Python
### Guideline: Status
If single byte of data to return, still use a 1-byte `data`, not `status`. Standard response status is `STATUS_DEVICE_SUCCESS` for general commands, `HF_TAG_OK` for HF commands and `LF_TAG_OK` for LF commands. If the response status is different than those, the response data is empty. Response status are generic and cover things like tag disappearance or tag non-conformities with the ISO standard. If a command needs more specific response status, it is added in the first byte of the data, to avoid cluttering the 1-byte general status enum with command-specific statuses. See e.g. [MF1_DARKSIDE_ACQUIRE](#2004-mf1-darkside-acquire).
### Guideline: unambiguous types
- Use unambiguous types such as `uint16_t`, not `int` or `enum`. Cast explicitly `int` and `enum` to `uint_t` of proper size
- Use Network byte order for 16b and 32b integers
- Macros `U16NTOHS`, `U32NTOHL` must be used on reception of a command payload.
- Macros `U16HTONS`, `U32HTONL` must be used on creation of a response payload.
- In Python, use the modifier `!` with all `struct.pack`/`struct.unpack`
### Guideline: payload parsing in handlers
- Concentrate payload parsing in the handlers, avoid further parsing in their callers. This is true for the firmware and the client.
- In cmd_processor handlers: don't reuse input `length`/`data` parameters for creating the response content
### Guideline: Naming conventions
- Use the exact same command and fields names in firmware and in client, use function names matching the command names for their handlers unless there is a very good reason not to do so. This helps grepping around. Names must start with a letter, not a number, because some languages require it (e.g. `14a_scan` not possible in Python)
- Respect commands order in `m_data_cmd_map`, `data_cmd.h` and `chameleon_cmd.py` definitions
- Even if a command is not yet implemented in firmware or in client but a command number is allocated, add it to `data_cmd.h` and `chameleon_cmd.py` with some `FIXME: to be implemented` comment
### Guideline: Validate status and data
- Validate data before using it, both when receiving command data in the firmware and when receiving response data in the client.
- Validate response status in client.
Loading

0 comments on commit b61657e

Please sign in to comment.