Bluetooth UART support for the Adafruit BluefruitLE SPI, for the University of York Engineering Stage 1 project

Committer:
ajp109
Date:
Sat Feb 06 20:58:22 2021 +0000
Revision:
0:a80552d32b80
Initial commit (not working)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ajp109 0:a80552d32b80 1 # SPI AT Command Transport Layer (SDEP)
ajp109 0:a80552d32b80 2
ajp109 0:a80552d32b80 3 This library transmits AT-style commands to the Bluefruit LE module over SPI using a custom protocol we've defined called SDEP, which stands for the **_Simple Data Exchange Protocol_**.
ajp109 0:a80552d32b80 4
ajp109 0:a80552d32b80 5 SDEP is used to handle messages and responses, including error responses, and was designed to be _bus neutral_, meaning that we can use SDEP regardless of the transport mechanism (USB HID, SPI, I2C, Wireless data over the air, etc.).
ajp109 0:a80552d32b80 6
ajp109 0:a80552d32b80 7 SDEP messages have a four byte header, and up to a 16 byte payload, and larger messages are broken into several message chunks which are rebuilt at either end of the transport bus. The 20 byte limit (4 byte header + 16 byte payload) was chosen to take into account the size limitations present in some transport layers.
ajp109 0:a80552d32b80 8
ajp109 0:a80552d32b80 9 # SPI Setup
ajp109 0:a80552d32b80 10
ajp109 0:a80552d32b80 11 The SPI interface uses the standard four SPI pins (MISO, MOSI, SCK and CS/SSEL), as well as an additional **IRQ** line (output from the nRF51822 to the SPI Master MCU).
ajp109 0:a80552d32b80 12
ajp109 0:a80552d32b80 13 ## IRQ Pin
ajp109 0:a80552d32b80 14
ajp109 0:a80552d32b80 15 The IRQ line is asserted as long as an entire SDEP packet is available in the buffer on the nRF51822, at which point you should read the packet, keeping the CS line asserted for the entire transaction (as detailed below).
ajp109 0:a80552d32b80 16
ajp109 0:a80552d32b80 17 The IRQ line will remain asserted as long as one or more packets are available, so the line may stay high after reading a packet, meaning that more packets are still available in the FIFO on the SPI slave side.
ajp109 0:a80552d32b80 18
ajp109 0:a80552d32b80 19 ## SPI Bus Hardware Requirements
ajp109 0:a80552d32b80 20
ajp109 0:a80552d32b80 21 The SPI peripheral block on the nRF51822 MCU has some specific limitations that need to be taken into account when communicating with it as an SPI slave:
ajp109 0:a80552d32b80 22
ajp109 0:a80552d32b80 23 * The SPI clock should run <=2MHz
ajp109 0:a80552d32b80 24 * A 100us delay should be added between the moment that the CS line is asserted, and before any data is transmitted on the SPI bus
ajp109 0:a80552d32b80 25 * The CS line should remain asserted for the entire packet, rather than toggling CS every byte
ajp109 0:a80552d32b80 26
ajp109 0:a80552d32b80 27 ## SDEP Packet and SPI Error Identifier
ajp109 0:a80552d32b80 28
ajp109 0:a80552d32b80 29 Once CS has been asserted and the mandatory 100us delay has passed, a single byte should be read from the SPI bus which will indicate the type of payload available on the nRF51822 (see **Message Type Indicator** below for more information on SDEP message types). Keep CS asserted after this byte has been read in case you need to continue reading the rest of the frame.
ajp109 0:a80552d32b80 30
ajp109 0:a80552d32b80 31 If a standard SDEP message type indicators (0x10, 0x20, 0x40 or 0x80) is encountered, keep reading as normal. There are two other indicators that should be taken into account, though, which indicate a problem on the nRF51822 SPI slave side:
ajp109 0:a80552d32b80 32
ajp109 0:a80552d32b80 33 * **0xFE**: Slave device not ready (wait a bit and try again)
ajp109 0:a80552d32b80 34 * **0xFF**: Slave device read overflow indicator (you've read more data than is available)
ajp109 0:a80552d32b80 35
ajp109 0:a80552d32b80 36 ## Sample Transaction
ajp109 0:a80552d32b80 37
ajp109 0:a80552d32b80 38 The following image shows a sample SDEP response that is spread over two packets (since the response is > 20 bytes in size). Notice that the IRQ line stays asserted between the packets since more than one was available in the FIFO on the nRF51822 side:
ajp109 0:a80552d32b80 39
ajp109 0:a80552d32b80 40 ![sdepexample_twopackets](https://cloud.githubusercontent.com/assets/181073/8234310/646b7498-15db-11e5-9c69-6366c5dd433a.png)
ajp109 0:a80552d32b80 41
ajp109 0:a80552d32b80 42 # SDEP (Simple Data Exchange Protocol)
ajp109 0:a80552d32b80 43
ajp109 0:a80552d32b80 44 The Simple Data Exchange Protocol (SDEP) can be used to send and receive binary messages between two connected devices using any binary serial bus (USB HID, USB Bulk, SPI, I2C, Wireless, etc.), exchanging data using one of four distinct message types (Command, Response, Alert and Error messages).
ajp109 0:a80552d32b80 45
ajp109 0:a80552d32b80 46 The protocol is designed to be flexible and extensible, with the only requirement being that **individual messages are 20 bytes or smaller**, and that the first byte of every message is a one byte (U8) identifier that indicates the message type, which defines the format for the remainder of the payload.
ajp109 0:a80552d32b80 47
ajp109 0:a80552d32b80 48 ## Endianness
ajp109 0:a80552d32b80 49
ajp109 0:a80552d32b80 50 All values larger than 8-bits are encoded in little endian format. Any deviation from this rule should be clearly documented.
ajp109 0:a80552d32b80 51
ajp109 0:a80552d32b80 52 ## Message Type Indicator
ajp109 0:a80552d32b80 53
ajp109 0:a80552d32b80 54 The first byte of every message is an 8-bit identifier called the **Message Type Indicator**. This value indicates the type of message being sent, and allows us to determine the format for the remainder of the message.
ajp109 0:a80552d32b80 55
ajp109 0:a80552d32b80 56 | Message Type | ID (U8) | Description |
ajp109 0:a80552d32b80 57 | ------------ | ------- | ----------- |
ajp109 0:a80552d32b80 58 | Command | 0x10 | |
ajp109 0:a80552d32b80 59 | Response | 0x20 | |
ajp109 0:a80552d32b80 60 | Alert | 0x40 | |
ajp109 0:a80552d32b80 61 | Error | 0x80 | |
ajp109 0:a80552d32b80 62
ajp109 0:a80552d32b80 63 ## SDEP Data Transactions
ajp109 0:a80552d32b80 64
ajp109 0:a80552d32b80 65 Either connected device can initiate SDEP transactions, though certain transport protocols imposes restrictions on who can initiate a transfer. The _master_ device, for example, always initiates transactions with Bluetooth Low Energy or USB, meaning that _slave_ devices can only reply to incoming commands.
ajp109 0:a80552d32b80 66
ajp109 0:a80552d32b80 67 Every device that receives a _Command Message_ must reply with a _Response Message_, _Error Message_ or _Alert message_.
ajp109 0:a80552d32b80 68
ajp109 0:a80552d32b80 69 The following diagram illustrates how an SDEP exchange typically takes place. A Command Message is sent, and a reply will be generated based on whether the command was accepted (in which case a Response Message will be sent in reply), if the command was invalid or rejected (in which case an Error Message reply will be sent), or if the command was valid but some specific condition occurred that should be indicated to the master device (in which case an Alert Message will be sent):
ajp109 0:a80552d32b80 70
ajp109 0:a80552d32b80 71 **ToDo: Insert two line master/slave chart showing message flow in different scenarios**
ajp109 0:a80552d32b80 72
ajp109 0:a80552d32b80 73 ## Message Types
ajp109 0:a80552d32b80 74
ajp109 0:a80552d32b80 75 ### Command Messages
ajp109 0:a80552d32b80 76
ajp109 0:a80552d32b80 77 Command messages (Message Type = 0x10) have the following structure:
ajp109 0:a80552d32b80 78
ajp109 0:a80552d32b80 79 | Name | Type | Meaning |
ajp109 0:a80552d32b80 80 | --------------- | ---- | ------------------------------------------------- |
ajp109 0:a80552d32b80 81 | Message Type | U8 | Always '0x10' |
ajp109 0:a80552d32b80 82 | Command ID | U16 | Unique command identifier |
ajp109 0:a80552d32b80 83 | Payload Length | U8 | [7] More data <br> [6-5] Reserved <br> [4-0] Payload length (0..16) |
ajp109 0:a80552d32b80 84 | Payload | ... | Optional command payload (parameters, etc.) |
ajp109 0:a80552d32b80 85
ajp109 0:a80552d32b80 86 **Command ID** (bytes 1-2) and **Payload Length** (byte 3) are mandatory in any command message. The message payload is optional, and will be ignored if Payload Length is set to 0 bytes. When a message payload is present, it’s length can be anywhere from 1..16 bytes, to stay within the 20-byte maximum message length.
ajp109 0:a80552d32b80 87
ajp109 0:a80552d32b80 88 A long command (>16 bytes payload) must be divided into multiple packets. To facilitate this, the **More data** field (bit 7 of byte 3) is used to indicate whether additional packets are available for the same command. The SDEP receiver must continue to reads packets until it finds a packet with **More data == 0**, then assemble all sub-packets into one command if necessary.
ajp109 0:a80552d32b80 89
ajp109 0:a80552d32b80 90 The contents of the payload are user defined, and can change from one command to another.
ajp109 0:a80552d32b80 91
ajp109 0:a80552d32b80 92 A sample command message would be:
ajp109 0:a80552d32b80 93
ajp109 0:a80552d32b80 94 | 0: Message Type (U8) | 1+2: Command ID (U16) | 3: Payload Len (U8) | 4: Payload (...) |
ajp109 0:a80552d32b80 95 | -------------------- | --------------------- | ------------------- | ---------------- |
ajp109 0:a80552d32b80 96 | 10 | 34 12 | 01 | FF |
ajp109 0:a80552d32b80 97
ajp109 0:a80552d32b80 98 - The first byte is the Message Type (0x10), which identifies this as a command message.
ajp109 0:a80552d32b80 99 - The second and third bytes are 0x1234 (34 12 in little-endian notation), which is the unique command ID. This value will be compared against the command lookup table and redirected to an appropriate command handler function if a matching entry was found.
ajp109 0:a80552d32b80 100 - The fourth byte indicates that we have a message payload of 1 byte
ajp109 0:a80552d32b80 101 - The fifth byte is the 1 byte payload: 0xFF
ajp109 0:a80552d32b80 102
ajp109 0:a80552d32b80 103 ### Response Messages
ajp109 0:a80552d32b80 104
ajp109 0:a80552d32b80 105 Response messages (Message Type = 0x20) are generated in response to an incoming command, and have the following structure:
ajp109 0:a80552d32b80 106
ajp109 0:a80552d32b80 107 | Name | Type | Meaning |
ajp109 0:a80552d32b80 108 | --------------- | ---- | ------------------------------------------------- |
ajp109 0:a80552d32b80 109 | Message Type | U8 | Always '0x20' |
ajp109 0:a80552d32b80 110 | Command ID | U16 | Command ID of the command this message is a response to, to correlated responses and commands |
ajp109 0:a80552d32b80 111 | Payload Length | U8 | [7] More data <br> [6-5] Reserved <br> [4-0] Payload length (0..16) |
ajp109 0:a80552d32b80 112 | Payload | ... | Optional response payload (parameters, etc.) |
ajp109 0:a80552d32b80 113
ajp109 0:a80552d32b80 114 By including the **Command ID** that this response message is related to, the recipient can more easily correlate responses and commands. This is useful in situations where multiple commands are sent, and some commands may take a longer period of time to execute than subsequent commands with a different command ID.
ajp109 0:a80552d32b80 115
ajp109 0:a80552d32b80 116 Response messages can only be generate in response to a command message, so the Command ID field should always be present.
ajp109 0:a80552d32b80 117
ajp109 0:a80552d32b80 118 A long response (>16 bytes payload) must be divided into multiple packets. Similar to long commands, the **More data** field (bit 7 of byte 3) is used to indicate whether additional packets are available for the same response. On responses that span more than one packet, the **More data** bit on the final packet will be set to `0` to indicate that this is the last packet in the sequence. The SDEP receiver must re-assemble all sub-packets in into one payload when necessary.
ajp109 0:a80552d32b80 119
ajp109 0:a80552d32b80 120 If more precise command/response correlation is required a custom protocol should be developed, where a unique message identifier is included in the payload of each command/response, but this is beyond the scope of this high-level protocol definition.
ajp109 0:a80552d32b80 121
ajp109 0:a80552d32b80 122 A sample response message would be:
ajp109 0:a80552d32b80 123
ajp109 0:a80552d32b80 124 | 0: Message Type (U8) | 1+2: Command ID (U16) | 3: Payload Len (U8) | 4: Payload (...) |
ajp109 0:a80552d32b80 125 | -------------------- | --------------------- | ------------------- | ---------------- |
ajp109 0:a80552d32b80 126 | 20 | 34 12 | 01 | FF |
ajp109 0:a80552d32b80 127
ajp109 0:a80552d32b80 128 - The first byte is the Message Type (0x20), which identifies this as a response message.
ajp109 0:a80552d32b80 129 - The second and third bytes are 0x1234, which is the unique command ID that this response is related to.
ajp109 0:a80552d32b80 130 - The fourth byte indicates that we have a message payload of 1 byte.
ajp109 0:a80552d32b80 131 - The fifth byte is the 1 byte payload: 0xFF
ajp109 0:a80552d32b80 132
ajp109 0:a80552d32b80 133 ### Alert Messages
ajp109 0:a80552d32b80 134
ajp109 0:a80552d32b80 135 Alert messages (Message Type = 0x40) are sent whenever an alert condition is present on the system (low battery, etc.), and have the following structure:
ajp109 0:a80552d32b80 136
ajp109 0:a80552d32b80 137 | Name | Type | Meaning |
ajp109 0:a80552d32b80 138 | --------------- | ---- | ------------------------------------------------- |
ajp109 0:a80552d32b80 139 | Message Type | U8 | Always '0x40' |
ajp109 0:a80552d32b80 140 | Alert ID | U16 | Unique ID for the alert condition |
ajp109 0:a80552d32b80 141 | Payload Length | U8 | Payload length (0..16) |
ajp109 0:a80552d32b80 142 | Payload | ... | Optional response payload (parameters, etc.) |
ajp109 0:a80552d32b80 143
ajp109 0:a80552d32b80 144 A sample alert message would be:
ajp109 0:a80552d32b80 145
ajp109 0:a80552d32b80 146 | 0: Message Type (U8) | 1+2: Alert ID (U16) | 3: Payload Len (U8) | 4+5+6+7: Payload |
ajp109 0:a80552d32b80 147 | -------------------- | --------------------- | ------------------- | ----------------- |
ajp109 0:a80552d32b80 148 | 40 | CD AB | 04 | 42 07 00 10 |
ajp109 0:a80552d32b80 149
ajp109 0:a80552d32b80 150 - The first byte is the Message Type (0x40), which identifies this as an alert message.
ajp109 0:a80552d32b80 151 - The second and third bytes are 0xABCD, which is the unique alert ID.
ajp109 0:a80552d32b80 152 - The fourth byte indicates that we have a message payload of 4 bytes.
ajp109 0:a80552d32b80 153 - The last four bytes are the actual payload: `0x10000742` in this case, assuming we were transmitting a 32-bit value in little-endian format.
ajp109 0:a80552d32b80 154
ajp109 0:a80552d32b80 155 #### Standard Alert IDs
ajp109 0:a80552d32b80 156
ajp109 0:a80552d32b80 157 Alert IDs in the range of 0x0000 to 0x00FF are reserved for standard SDEP alerts, and may not be used by custom alerts.
ajp109 0:a80552d32b80 158
ajp109 0:a80552d32b80 159 The following alerts have been defined as a standard part of the protocol:
ajp109 0:a80552d32b80 160
ajp109 0:a80552d32b80 161 | ID | Alert Description | Description |
ajp109 0:a80552d32b80 162 | ------ | ----------------- | ------------------------------------ |
ajp109 0:a80552d32b80 163 | 0x0000 | Reserved | Reserved for future use |
ajp109 0:a80552d32b80 164 | 0x0001 | System Reset | The system is about the reset |
ajp109 0:a80552d32b80 165 | 0x0002 | Battery Low | The battery level is low |
ajp109 0:a80552d32b80 166 | 0x0003 | Battery Critical | The battery level is critically low |
ajp109 0:a80552d32b80 167
ajp109 0:a80552d32b80 168 ### Error Messages
ajp109 0:a80552d32b80 169
ajp109 0:a80552d32b80 170 Error messages (Message Type = 0x80) are returned whenever an error condition is present on the system, and have the following structure:
ajp109 0:a80552d32b80 171
ajp109 0:a80552d32b80 172 | Name | Type | Meaning |
ajp109 0:a80552d32b80 173 | --------------- | ---- | ------------------------------------------------- |
ajp109 0:a80552d32b80 174 | Message Type | U8 | Always '0x80' |
ajp109 0:a80552d32b80 175 | Error ID | U16 | Unique ID for the error condition |
ajp109 0:a80552d32b80 176 | Reserved | U8 | Reserved for future use |
ajp109 0:a80552d32b80 177
ajp109 0:a80552d32b80 178 Whenever an error condition is present and the system needs to be alerted (such as a failed request, an attempt to access a non-existing resource, etc.) the system can return a specific error message with an appropriate Error ID.
ajp109 0:a80552d32b80 179
ajp109 0:a80552d32b80 180 A sample error message would be:
ajp109 0:a80552d32b80 181
ajp109 0:a80552d32b80 182 | 0: Message Type (U8) | 1+2: Error ID (U16) | 3: Reserved (U8) |
ajp109 0:a80552d32b80 183 | -------------------- | --------------------- | ---------------- |
ajp109 0:a80552d32b80 184 | 80 | 01 00 | 00 |
ajp109 0:a80552d32b80 185
ajp109 0:a80552d32b80 186 - The first byte is the Message Type (0x80), which identifies this as an error message.
ajp109 0:a80552d32b80 187 - The second and third bytes are 0x0001 (01 00 in little-endian notation), which indicates that the supplied Command ID was invalid (see Standard Error IDs below).
ajp109 0:a80552d32b80 188 - The last byte is reserved and should be 0x00 and ignored.
ajp109 0:a80552d32b80 189
ajp109 0:a80552d32b80 190 #### Standard Error IDs
ajp109 0:a80552d32b80 191
ajp109 0:a80552d32b80 192 Error IDs in the range of 0x0000 to 0x00FF are reserved for standard SDEP errors, and may not be used by custom errors.
ajp109 0:a80552d32b80 193
ajp109 0:a80552d32b80 194 The following errors have been defined as a standard part of the protocol:
ajp109 0:a80552d32b80 195
ajp109 0:a80552d32b80 196 | ID | Error Description | Description |
ajp109 0:a80552d32b80 197 | ------ | ----------------- | ----------------------------------------------- |
ajp109 0:a80552d32b80 198 | 0x0000 | Reserved | Reserved for future use |
ajp109 0:a80552d32b80 199 | 0x0001 | Invalid Cmd ID | The command ID wasn't found in the lookup table |
ajp109 0:a80552d32b80 200 | 0x0003 | Invalid Payload | The message payload was invalid |