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

Committer:
ajp109
Date:
Fri Mar 12 14:33:03 2021 +0000
Revision:
2:8c341bac60b8
Parent:
1:6ff0eee2da9c
Last commit before fork - all working

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ajp109 0:a80552d32b80 1 /**************************************************************************/
ajp109 0:a80552d32b80 2 /*!
ajp109 0:a80552d32b80 3 @file Adafruit_BluefruitLE_SPI.cpp
ajp109 0:a80552d32b80 4 @author hathach, ktown (Adafruit Industries), ajp109 (University of York)
ajp109 0:a80552d32b80 5
ajp109 0:a80552d32b80 6 @section LICENSE
ajp109 0:a80552d32b80 7
ajp109 0:a80552d32b80 8 Software License Agreement (BSD License)
ajp109 0:a80552d32b80 9
ajp109 0:a80552d32b80 10 Copyright (c) 2015, Adafruit Industries (adafruit.com)
ajp109 0:a80552d32b80 11 All rights reserved.
ajp109 0:a80552d32b80 12
ajp109 0:a80552d32b80 13 Redistribution and use in source and binary forms, with or without
ajp109 0:a80552d32b80 14 modification, are permitted provided that the following conditions are met:
ajp109 0:a80552d32b80 15 1. Redistributions of source code must retain the above copyright
ajp109 0:a80552d32b80 16 notice, this list of conditions and the following disclaimer.
ajp109 0:a80552d32b80 17 2. Redistributions in binary form must reproduce the above copyright
ajp109 0:a80552d32b80 18 notice, this list of conditions and the following disclaimer in the
ajp109 0:a80552d32b80 19 documentation and/or other materials provided with the distribution.
ajp109 0:a80552d32b80 20 3. Neither the name of the copyright holders nor the
ajp109 0:a80552d32b80 21 names of its contributors may be used to endorse or promote products
ajp109 0:a80552d32b80 22 derived from this software without specific prior written permission.
ajp109 0:a80552d32b80 23
ajp109 0:a80552d32b80 24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
ajp109 0:a80552d32b80 25 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
ajp109 0:a80552d32b80 26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
ajp109 0:a80552d32b80 27 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
ajp109 0:a80552d32b80 28 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
ajp109 0:a80552d32b80 29 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
ajp109 0:a80552d32b80 30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ajp109 0:a80552d32b80 31 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
ajp109 0:a80552d32b80 32 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
ajp109 0:a80552d32b80 33 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ajp109 0:a80552d32b80 34 */
ajp109 0:a80552d32b80 35 /**************************************************************************/
ajp109 0:a80552d32b80 36 #include "mbed.h"
ajp109 0:a80552d32b80 37 #include "Adafruit_BluefruitLE_SPI.h"
ajp109 0:a80552d32b80 38 #include <stdlib.h>
ajp109 0:a80552d32b80 39
ajp109 0:a80552d32b80 40 #ifndef min
ajp109 0:a80552d32b80 41 #define min(a,b) ((a) < (b) ? (a) : (b))
ajp109 0:a80552d32b80 42 #endif
ajp109 0:a80552d32b80 43
ajp109 0:a80552d32b80 44 /******************************************************************************/
ajp109 0:a80552d32b80 45 /*!
ajp109 0:a80552d32b80 46 @brief Instantiates a new instance of the Adafruit_BluefruitLE_SPI class
ajp109 0:a80552d32b80 47
ajp109 0:a80552d32b80 48 @param[in] mosi
ajp109 0:a80552d32b80 49 The MOSI pin for the SPI interface
ajp109 0:a80552d32b80 50 @param[in] miso
ajp109 0:a80552d32b80 51 The MISO pin for the SPI interface
ajp109 0:a80552d32b80 52 @param[in] sck
ajp109 0:a80552d32b80 53 The SCK pin for the SPI interface
ajp109 0:a80552d32b80 54 @param[in] cs
ajp109 0:a80552d32b80 55 The CS pin for the SPI interface
ajp109 0:a80552d32b80 56 @param[in] irq
ajp109 0:a80552d32b80 57 The IRQ pin - this must be a HW interrupt pin
ajp109 0:a80552d32b80 58 @param[in] rstPin
ajp109 0:a80552d32b80 59 The RESET pin (optional)
ajp109 0:a80552d32b80 60 */
ajp109 0:a80552d32b80 61 /******************************************************************************/
ajp109 0:a80552d32b80 62 Adafruit_BluefruitLE_SPI::Adafruit_BluefruitLE_SPI(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName irq, PinName rst) :
ajp109 0:a80552d32b80 63 m_rx_fifo(m_rx_buffer, sizeof(m_rx_buffer), 1, true),
ajp109 2:8c341bac60b8 64 m_spi(mosi, miso, sclk),
ajp109 2:8c341bac60b8 65 m_cs(cs),
ajp109 0:a80552d32b80 66 m_irq(irq),
ajp109 0:a80552d32b80 67 m_rst(rst)
ajp109 0:a80552d32b80 68 {
ajp109 0:a80552d32b80 69 _physical_transport = BLUEFRUIT_TRANSPORT_HWSPI;
ajp109 0:a80552d32b80 70
ajp109 2:8c341bac60b8 71 m_spi.frequency(400000);
ajp109 0:a80552d32b80 72 // Mode 0, MSB-first is default
ajp109 0:a80552d32b80 73
ajp109 0:a80552d32b80 74 if (m_rst.is_connected()) {
ajp109 0:a80552d32b80 75 m_rst = true;
ajp109 0:a80552d32b80 76 }
ajp109 2:8c341bac60b8 77 m_cs = false;
ajp109 2:8c341bac60b8 78 wait_us(5);
ajp109 2:8c341bac60b8 79 m_cs = true;
ajp109 2:8c341bac60b8 80 wait_us(35);
ajp109 0:a80552d32b80 81
ajp109 0:a80552d32b80 82 m_tx_count = 0;
ajp109 0:a80552d32b80 83
ajp109 0:a80552d32b80 84 m_mode_switch_command_enabled = true;
ajp109 0:a80552d32b80 85 }
ajp109 0:a80552d32b80 86
ajp109 0:a80552d32b80 87
ajp109 0:a80552d32b80 88 /******************************************************************************/
ajp109 0:a80552d32b80 89 /*!
ajp109 0:a80552d32b80 90 @brief Initialize the HW to enable communication with the BLE module
ajp109 0:a80552d32b80 91
ajp109 0:a80552d32b80 92 @return Returns 'true' if everything initialised correctly, otherwise
ajp109 0:a80552d32b80 93 'false' if there was a problem during HW initialisation. If
ajp109 0:a80552d32b80 94 'irqPin' is not a HW interrupt pin false will be returned.
ajp109 0:a80552d32b80 95 */
ajp109 0:a80552d32b80 96 /******************************************************************************/
ajp109 0:a80552d32b80 97 bool Adafruit_BluefruitLE_SPI::begin(bool v, bool blocking)
ajp109 0:a80552d32b80 98 {
ajp109 0:a80552d32b80 99 _verbose = v;
ajp109 0:a80552d32b80 100
ajp109 0:a80552d32b80 101 bool isOK;
ajp109 0:a80552d32b80 102
ajp109 0:a80552d32b80 103 // Always try to send Initialize command to reset
ajp109 0:a80552d32b80 104 // Bluefruit since user can define but not wiring RST signal
ajp109 0:a80552d32b80 105 isOK = sendInitializePattern();
ajp109 0:a80552d32b80 106
ajp109 0:a80552d32b80 107 // use hardware reset if available
ajp109 0:a80552d32b80 108 if (m_rst.is_connected()) {
ajp109 0:a80552d32b80 109 // pull the RST to GND for 10 ms
ajp109 0:a80552d32b80 110 m_rst = false;
ajp109 0:a80552d32b80 111 thread_sleep_for(10);
ajp109 0:a80552d32b80 112 m_rst = true;
ajp109 0:a80552d32b80 113
ajp109 0:a80552d32b80 114 isOK= true;
ajp109 0:a80552d32b80 115 }
ajp109 0:a80552d32b80 116
ajp109 0:a80552d32b80 117 _reset_started_timestamp = Kernel::Clock::now();
ajp109 0:a80552d32b80 118
ajp109 0:a80552d32b80 119 // Bluefruit takes 1 second to reboot
ajp109 0:a80552d32b80 120 if (blocking) {
ajp109 0:a80552d32b80 121 thread_sleep_for(1000);
ajp109 0:a80552d32b80 122 }
ajp109 0:a80552d32b80 123
ajp109 0:a80552d32b80 124 return isOK;
ajp109 0:a80552d32b80 125 }
ajp109 0:a80552d32b80 126
ajp109 0:a80552d32b80 127 /******************************************************************************/
ajp109 0:a80552d32b80 128 /*!
ajp109 0:a80552d32b80 129 @brief Uninitializes the SPI interface
ajp109 0:a80552d32b80 130 */
ajp109 0:a80552d32b80 131 /******************************************************************************/
ajp109 0:a80552d32b80 132 void Adafruit_BluefruitLE_SPI::end(void)
ajp109 0:a80552d32b80 133 { }
ajp109 0:a80552d32b80 134
ajp109 0:a80552d32b80 135 /******************************************************************************/
ajp109 0:a80552d32b80 136 /*!
ajp109 0:a80552d32b80 137 @brief Handle direct "+++" input command from user.
ajp109 0:a80552d32b80 138 User should use setMode instead
ajp109 0:a80552d32b80 139 */
ajp109 0:a80552d32b80 140 /******************************************************************************/
ajp109 0:a80552d32b80 141 void Adafruit_BluefruitLE_SPI::simulateSwitchMode(void)
ajp109 0:a80552d32b80 142 {
ajp109 0:a80552d32b80 143 _mode = 1 - _mode;
ajp109 0:a80552d32b80 144
ajp109 0:a80552d32b80 145 char ch = '0' + _mode;
ajp109 0:a80552d32b80 146 m_rx_fifo.write(&ch);
ajp109 0:a80552d32b80 147 m_rx_fifo.write_n("\r\nOK\r\n", 6);
ajp109 0:a80552d32b80 148 }
ajp109 0:a80552d32b80 149
ajp109 0:a80552d32b80 150 /******************************************************************************/
ajp109 0:a80552d32b80 151 /*!
ajp109 0:a80552d32b80 152 @brief Simulate "+++" switch mode command
ajp109 0:a80552d32b80 153 */
ajp109 0:a80552d32b80 154 /******************************************************************************/
ajp109 0:a80552d32b80 155 bool Adafruit_BluefruitLE_SPI::setMode(uint8_t new_mode)
ajp109 0:a80552d32b80 156 {
ajp109 0:a80552d32b80 157 // invalid mode
ajp109 0:a80552d32b80 158 if ( !(new_mode == BLUEFRUIT_MODE_COMMAND || new_mode == BLUEFRUIT_MODE_DATA) ) return false;
ajp109 0:a80552d32b80 159
ajp109 0:a80552d32b80 160 // Already in the wanted mode
ajp109 0:a80552d32b80 161 if ( _mode == new_mode ) return true;
ajp109 0:a80552d32b80 162
ajp109 0:a80552d32b80 163 // SPI use different SDEP command when in DATA/COMMAND mode.
ajp109 0:a80552d32b80 164 // --> does not switch using +++ command
ajp109 0:a80552d32b80 165 _mode = new_mode;
ajp109 0:a80552d32b80 166
ajp109 0:a80552d32b80 167 // If we're entering DATA mode, flush any old response, so that it isn't
ajp109 0:a80552d32b80 168 // interpreted as incoming UART data
ajp109 0:a80552d32b80 169 if (_mode == BLUEFRUIT_MODE_DATA) sync();
ajp109 0:a80552d32b80 170
ajp109 0:a80552d32b80 171 return true;
ajp109 0:a80552d32b80 172 }
ajp109 0:a80552d32b80 173
ajp109 0:a80552d32b80 174 /******************************************************************************/
ajp109 0:a80552d32b80 175 /*!
ajp109 0:a80552d32b80 176 @brief Enable/disable recognition of "+++" switch mode command.
ajp109 0:a80552d32b80 177 Usage of setMode is not affected.
ajp109 0:a80552d32b80 178 */
ajp109 0:a80552d32b80 179 /******************************************************************************/
ajp109 0:a80552d32b80 180 void Adafruit_BluefruitLE_SPI::enableModeSwitchCommand(bool enabled)
ajp109 0:a80552d32b80 181 {
ajp109 0:a80552d32b80 182 m_mode_switch_command_enabled = enabled;
ajp109 0:a80552d32b80 183 }
ajp109 0:a80552d32b80 184
ajp109 0:a80552d32b80 185 /******************************************************************************/
ajp109 0:a80552d32b80 186 /*!
ajp109 0:a80552d32b80 187 @brief Send initialize pattern to Bluefruit LE to force a reset. This pattern
ajp109 0:a80552d32b80 188 follow the SDEP command syntax with command_id = SDEP_CMDTYPE_INITIALIZE.
ajp109 0:a80552d32b80 189 The command has NO response, and is expected to complete within 1 second
ajp109 0:a80552d32b80 190 */
ajp109 0:a80552d32b80 191 /******************************************************************************/
ajp109 0:a80552d32b80 192 bool Adafruit_BluefruitLE_SPI::sendInitializePattern(void)
ajp109 0:a80552d32b80 193 {
ajp109 0:a80552d32b80 194 return sendPacket(SDEP_CMDTYPE_INITIALIZE, NULL, 0, 0);
ajp109 0:a80552d32b80 195 }
ajp109 0:a80552d32b80 196
ajp109 0:a80552d32b80 197 /******************************************************************************/
ajp109 0:a80552d32b80 198 /*!
ajp109 0:a80552d32b80 199 @brief Send out an packet with data in m_tx_buffer
ajp109 0:a80552d32b80 200
ajp109 0:a80552d32b80 201 @param[in] more_data
ajp109 0:a80552d32b80 202 More Data bitfield, 0 indicates this is not end of transfer yet
ajp109 0:a80552d32b80 203 */
ajp109 0:a80552d32b80 204 /******************************************************************************/
ajp109 0:a80552d32b80 205 bool Adafruit_BluefruitLE_SPI::sendPacket(uint16_t command, const uint8_t* buf, uint8_t count, uint8_t more_data)
ajp109 0:a80552d32b80 206 {
ajp109 0:a80552d32b80 207 // flush old response before sending the new command, but only if we're *not*
ajp109 0:a80552d32b80 208 // in DATA mode, as the RX FIFO may containg incoming UART data that hasn't
ajp109 0:a80552d32b80 209 // been read yet
ajp109 0:a80552d32b80 210 if (more_data == 0 && _mode != BLUEFRUIT_MODE_DATA) sync();
ajp109 0:a80552d32b80 211
ajp109 0:a80552d32b80 212 sdepMsgCommand_t msgCmd;
ajp109 0:a80552d32b80 213
ajp109 0:a80552d32b80 214 msgCmd.header.msg_type = SDEP_MSGTYPE_COMMAND;
ajp109 0:a80552d32b80 215 msgCmd.header.cmd_id_high = (command >> 8) & 0xFF ;
ajp109 0:a80552d32b80 216 msgCmd.header.cmd_id_low = command & 0xFF;
ajp109 0:a80552d32b80 217 msgCmd.header.length = count;
ajp109 0:a80552d32b80 218 msgCmd.header.more_data = (count == SDEP_MAX_PACKETSIZE) ? more_data : 0;
ajp109 0:a80552d32b80 219
ajp109 0:a80552d32b80 220 // Copy payload
ajp109 0:a80552d32b80 221 if ( buf != NULL && count > 0) memcpy(msgCmd.payload, buf, count);
ajp109 0:a80552d32b80 222
ajp109 0:a80552d32b80 223 // Starting SPI transaction
ajp109 0:a80552d32b80 224 m_spi.select();
ajp109 2:8c341bac60b8 225 m_cs = false;
ajp109 0:a80552d32b80 226
ajp109 0:a80552d32b80 227 TimeoutTimer tt(_timeout);
ajp109 0:a80552d32b80 228
ajp109 0:a80552d32b80 229 // Bluefruit may not be ready
ajp109 0:a80552d32b80 230 while ( ( spixfer(msgCmd.header.msg_type) == SPI_IGNORED_BYTE ) && !tt.expired() ) {
ajp109 0:a80552d32b80 231 // Disable & Re-enable CS with a bit of delay for Bluefruit to ready itself
ajp109 2:8c341bac60b8 232 m_cs = true;
ajp109 2:8c341bac60b8 233 wait_us(SPI_DEFAULT_DELAY_US);
ajp109 2:8c341bac60b8 234 m_cs = false;
ajp109 0:a80552d32b80 235 }
ajp109 0:a80552d32b80 236
ajp109 0:a80552d32b80 237 bool result = !tt.expired();
ajp109 0:a80552d32b80 238 if ( result ) {
ajp109 0:a80552d32b80 239 // transfer the rest of the data
ajp109 0:a80552d32b80 240 spixfer((void*) (((uint8_t*)&msgCmd) +1), sizeof(sdepMsgHeader_t)+count-1);
ajp109 0:a80552d32b80 241 }
ajp109 0:a80552d32b80 242
ajp109 2:8c341bac60b8 243 m_cs = true;
ajp109 0:a80552d32b80 244 m_spi.deselect();
ajp109 0:a80552d32b80 245
ajp109 0:a80552d32b80 246 return result;
ajp109 0:a80552d32b80 247 }
ajp109 0:a80552d32b80 248
ajp109 0:a80552d32b80 249 /******************************************************************************/
ajp109 0:a80552d32b80 250 /*!
ajp109 0:a80552d32b80 251 @brief Print API. Either buffer the data internally or send it to bus
ajp109 0:a80552d32b80 252 if possible. \r and \n are command terminators and will force the
ajp109 0:a80552d32b80 253 packet to be sent to the Bluefruit LE module.
ajp109 0:a80552d32b80 254
ajp109 0:a80552d32b80 255 @param[in] c
ajp109 0:a80552d32b80 256 Character to send
ajp109 0:a80552d32b80 257 */
ajp109 0:a80552d32b80 258 /******************************************************************************/
ajp109 0:a80552d32b80 259 ssize_t Adafruit_BluefruitLE_SPI::_putc(int c_int)
ajp109 0:a80552d32b80 260 {
ajp109 0:a80552d32b80 261 uint8_t c = c_int & 0xFF;
ajp109 0:a80552d32b80 262 if (_mode == BLUEFRUIT_MODE_DATA) {
ajp109 0:a80552d32b80 263 sendPacket(SDEP_CMDTYPE_BLE_UARTTX, &c, 1, 0);
ajp109 0:a80552d32b80 264 getResponse();
ajp109 0:a80552d32b80 265 return 1;
ajp109 0:a80552d32b80 266 }
ajp109 0:a80552d32b80 267
ajp109 0:a80552d32b80 268 // Following code handle BLUEFRUIT_MODE_COMMAND
ajp109 0:a80552d32b80 269
ajp109 0:a80552d32b80 270 // Final packet due to \r or \n terminator
ajp109 0:a80552d32b80 271 if (c == '\r' || c == '\n') {
ajp109 0:a80552d32b80 272 if (m_tx_count > 0) {
ajp109 0:a80552d32b80 273 // +++ command to switch mode
ajp109 0:a80552d32b80 274 if (m_mode_switch_command_enabled && memcmp(m_tx_buffer, "+++", 3) == 0) {
ajp109 0:a80552d32b80 275 simulateSwitchMode();
ajp109 0:a80552d32b80 276 } else {
ajp109 0:a80552d32b80 277 sendPacket(SDEP_CMDTYPE_AT_WRAPPER, m_tx_buffer, m_tx_count, 0);
ajp109 0:a80552d32b80 278 }
ajp109 0:a80552d32b80 279 m_tx_count = 0;
ajp109 0:a80552d32b80 280 }
ajp109 0:a80552d32b80 281 }
ajp109 0:a80552d32b80 282 // More than max packet buffered --> send with more_data = 1
ajp109 0:a80552d32b80 283 else if (m_tx_count == SDEP_MAX_PACKETSIZE) {
ajp109 0:a80552d32b80 284 sendPacket(SDEP_CMDTYPE_AT_WRAPPER, m_tx_buffer, m_tx_count, 1);
ajp109 0:a80552d32b80 285
ajp109 0:a80552d32b80 286 m_tx_buffer[0] = c;
ajp109 0:a80552d32b80 287 m_tx_count = 1;
ajp109 0:a80552d32b80 288 }
ajp109 0:a80552d32b80 289 // Not enough data, continue to buffer
ajp109 0:a80552d32b80 290 else {
ajp109 0:a80552d32b80 291 m_tx_buffer[m_tx_count++] = c;
ajp109 0:a80552d32b80 292 }
ajp109 0:a80552d32b80 293
ajp109 0:a80552d32b80 294 if (_verbose) ::printf("%c", (char) c);
ajp109 0:a80552d32b80 295
ajp109 0:a80552d32b80 296 return 1;
ajp109 0:a80552d32b80 297 }
ajp109 0:a80552d32b80 298
ajp109 0:a80552d32b80 299 /******************************************************************************/
ajp109 0:a80552d32b80 300 /*!
ajp109 0:a80552d32b80 301
ajp109 0:a80552d32b80 302 */
ajp109 0:a80552d32b80 303 /******************************************************************************/
ajp109 0:a80552d32b80 304 ssize_t Adafruit_BluefruitLE_SPI::write(const void *v_buf, size_t size)
ajp109 0:a80552d32b80 305 {
ajp109 0:a80552d32b80 306 uint8_t *buf = (uint8_t *)v_buf;
ajp109 0:a80552d32b80 307 if ( _mode == BLUEFRUIT_MODE_DATA ) {
ajp109 0:a80552d32b80 308 if (m_mode_switch_command_enabled &&
ajp109 0:a80552d32b80 309 (size >= 3) &&
ajp109 0:a80552d32b80 310 !memcmp(buf, "+++", 3) &&
ajp109 0:a80552d32b80 311 !(size > 3 && buf[3] != '\r' && buf[3] != '\n') ) {
ajp109 0:a80552d32b80 312 simulateSwitchMode();
ajp109 0:a80552d32b80 313 } else {
ajp109 0:a80552d32b80 314 size_t remain = size;
ajp109 0:a80552d32b80 315 while(remain) {
ajp109 0:a80552d32b80 316 size_t len = min(remain, SDEP_MAX_PACKETSIZE);
ajp109 0:a80552d32b80 317 remain -= len;
ajp109 0:a80552d32b80 318
ajp109 0:a80552d32b80 319 sendPacket(SDEP_CMDTYPE_BLE_UARTTX, buf, (uint8_t) len, remain ? 1 : 0);
ajp109 0:a80552d32b80 320 buf += len;
ajp109 0:a80552d32b80 321 }
ajp109 0:a80552d32b80 322
ajp109 0:a80552d32b80 323 getResponse();
ajp109 0:a80552d32b80 324 }
ajp109 0:a80552d32b80 325
ajp109 0:a80552d32b80 326 return size;
ajp109 0:a80552d32b80 327 }
ajp109 0:a80552d32b80 328 // Command mode
ajp109 0:a80552d32b80 329 else {
ajp109 0:a80552d32b80 330 size_t n = size;
ajp109 0:a80552d32b80 331 while (size--) {
ajp109 0:a80552d32b80 332 _putc(*buf++);
ajp109 0:a80552d32b80 333 }
ajp109 0:a80552d32b80 334 return n;
ajp109 0:a80552d32b80 335 }
ajp109 0:a80552d32b80 336 }
ajp109 0:a80552d32b80 337
ajp109 0:a80552d32b80 338 /******************************************************************************/
ajp109 0:a80552d32b80 339 /*!
ajp109 0:a80552d32b80 340 @brief Check if the response from the previous command is ready
ajp109 0:a80552d32b80 341
ajp109 0:a80552d32b80 342 @return 'true' if a response is ready, otherwise 'false'
ajp109 0:a80552d32b80 343 */
ajp109 0:a80552d32b80 344 /******************************************************************************/
ajp109 0:a80552d32b80 345 int Adafruit_BluefruitLE_SPI::available(void)
ajp109 0:a80552d32b80 346 {
ajp109 0:a80552d32b80 347 if (! m_rx_fifo.empty() ) {
ajp109 0:a80552d32b80 348 return m_rx_fifo.count();
ajp109 0:a80552d32b80 349 }
ajp109 0:a80552d32b80 350
ajp109 0:a80552d32b80 351 if ( _mode == BLUEFRUIT_MODE_DATA ) {
ajp109 0:a80552d32b80 352 // DATA Mode: query for BLE UART data
ajp109 0:a80552d32b80 353 sendPacket(SDEP_CMDTYPE_BLE_UARTRX, NULL, 0, 0);
ajp109 0:a80552d32b80 354
ajp109 0:a80552d32b80 355 // Waiting to get response from Bluefruit
ajp109 0:a80552d32b80 356 getResponse();
ajp109 0:a80552d32b80 357
ajp109 0:a80552d32b80 358 return m_rx_fifo.count();
ajp109 0:a80552d32b80 359 } else {
ajp109 0:a80552d32b80 360 return (m_irq.read());
ajp109 0:a80552d32b80 361 }
ajp109 0:a80552d32b80 362 }
ajp109 0:a80552d32b80 363
ajp109 0:a80552d32b80 364 /******************************************************************************/
ajp109 0:a80552d32b80 365 /*!
ajp109 0:a80552d32b80 366 @brief Get a byte from response data, perform SPI transaction if needed
ajp109 0:a80552d32b80 367
ajp109 0:a80552d32b80 368 @return -1 if no data is available
ajp109 0:a80552d32b80 369 */
ajp109 0:a80552d32b80 370 /******************************************************************************/
ajp109 0:a80552d32b80 371 int Adafruit_BluefruitLE_SPI::_getc(void)
ajp109 0:a80552d32b80 372 {
ajp109 0:a80552d32b80 373 uint8_t ch;
ajp109 0:a80552d32b80 374
ajp109 0:a80552d32b80 375 // try to grab from buffer first...
ajp109 0:a80552d32b80 376 if (!m_rx_fifo.empty()) {
ajp109 0:a80552d32b80 377 m_rx_fifo.read(&ch);
ajp109 0:a80552d32b80 378 return (int)ch;
ajp109 0:a80552d32b80 379 }
ajp109 0:a80552d32b80 380
ajp109 0:a80552d32b80 381 if ( _mode == BLUEFRUIT_MODE_DATA ) {
ajp109 0:a80552d32b80 382 // DATA Mode: query for BLE UART data
ajp109 0:a80552d32b80 383 sendPacket(SDEP_CMDTYPE_BLE_UARTRX, NULL, 0, 0);
ajp109 0:a80552d32b80 384
ajp109 0:a80552d32b80 385 // Waiting to get response from Bluefruit
ajp109 0:a80552d32b80 386 getResponse();
ajp109 0:a80552d32b80 387 } else {
ajp109 0:a80552d32b80 388 // COMMAND Mode: Only read data from Bluefruit if IRQ is raised
ajp109 0:a80552d32b80 389 if ( m_irq.read() ) getResponse();
ajp109 0:a80552d32b80 390 }
ajp109 0:a80552d32b80 391
ajp109 0:a80552d32b80 392 return m_rx_fifo.read(&ch) ? ((int) ch) : EOF;
ajp109 0:a80552d32b80 393
ajp109 0:a80552d32b80 394 }
ajp109 0:a80552d32b80 395
ajp109 0:a80552d32b80 396 /******************************************************************************/
ajp109 0:a80552d32b80 397 /*!
ajp109 0:a80552d32b80 398 @brief Flush current response data in the internal FIFO
ajp109 0:a80552d32b80 399
ajp109 0:a80552d32b80 400 @return -1 if no data is available
ajp109 0:a80552d32b80 401 */
ajp109 0:a80552d32b80 402 /******************************************************************************/
ajp109 0:a80552d32b80 403 int Adafruit_BluefruitLE_SPI::sync(void)
ajp109 0:a80552d32b80 404 {
ajp109 0:a80552d32b80 405 m_rx_fifo.clear();
ajp109 0:a80552d32b80 406 return Adafruit_BLE::sync();
ajp109 0:a80552d32b80 407 }
ajp109 0:a80552d32b80 408
ajp109 0:a80552d32b80 409 /******************************************************************************/
ajp109 0:a80552d32b80 410 /*!
ajp109 0:a80552d32b80 411 @brief Try to perform an full AT response transfer from Bluefruit, or execute
ajp109 0:a80552d32b80 412 as many SPI transaction as internal FIFO can hold up.
ajp109 0:a80552d32b80 413
ajp109 0:a80552d32b80 414 @note If verbose is enabled, all the received data will be print to Serial
ajp109 0:a80552d32b80 415
ajp109 0:a80552d32b80 416 @return
ajp109 0:a80552d32b80 417 - true : if succeeded
ajp109 0:a80552d32b80 418 - false : if failed
ajp109 0:a80552d32b80 419 */
ajp109 0:a80552d32b80 420 /******************************************************************************/
ajp109 0:a80552d32b80 421 bool Adafruit_BluefruitLE_SPI::getResponse(void)
ajp109 0:a80552d32b80 422 {
ajp109 0:a80552d32b80 423 // Try to read data from Bluefruit if there is enough room in the fifo
ajp109 0:a80552d32b80 424 while ( m_rx_fifo.remaining() >= SDEP_MAX_PACKETSIZE ) {
ajp109 0:a80552d32b80 425 // Get a SDEP packet
ajp109 0:a80552d32b80 426 sdepMsgResponse_t msg_response;
ajp109 0:a80552d32b80 427 memclr(&msg_response, sizeof(sdepMsgResponse_t));
ajp109 0:a80552d32b80 428
ajp109 0:a80552d32b80 429 if ( !getPacket(&msg_response) ) return false;
ajp109 0:a80552d32b80 430
ajp109 0:a80552d32b80 431 // Write to fifo
ajp109 0:a80552d32b80 432 if ( msg_response.header.length > 0) {
ajp109 0:a80552d32b80 433 m_rx_fifo.write_n(msg_response.payload, msg_response.header.length);
ajp109 0:a80552d32b80 434 }
ajp109 0:a80552d32b80 435
ajp109 0:a80552d32b80 436 // No more packet data
ajp109 0:a80552d32b80 437 if ( !msg_response.header.more_data ) break;
ajp109 0:a80552d32b80 438
ajp109 0:a80552d32b80 439 // It takes a bit since all Data received to IRQ to get LOW
ajp109 0:a80552d32b80 440 // May need to delay a bit for it to be stable before the next try
ajp109 0:a80552d32b80 441 // delayMicroseconds(SPI_DEFAULT_DELAY_US);
ajp109 0:a80552d32b80 442 }
ajp109 0:a80552d32b80 443
ajp109 0:a80552d32b80 444 return true;
ajp109 0:a80552d32b80 445 }
ajp109 0:a80552d32b80 446
ajp109 0:a80552d32b80 447 /******************************************************************************/
ajp109 0:a80552d32b80 448 /*!
ajp109 0:a80552d32b80 449 @brief Perform a single SPI SDEP transaction and is used by getReponse to
ajp109 0:a80552d32b80 450 get a full response composed of multiple packets.
ajp109 0:a80552d32b80 451
ajp109 0:a80552d32b80 452 @param[in] buf
ajp109 0:a80552d32b80 453 Memory location where payload is copied to
ajp109 0:a80552d32b80 454
ajp109 0:a80552d32b80 455 @return number of bytes in SDEP payload
ajp109 0:a80552d32b80 456 */
ajp109 0:a80552d32b80 457 /******************************************************************************/
ajp109 0:a80552d32b80 458 bool Adafruit_BluefruitLE_SPI::getPacket(sdepMsgResponse_t* p_response)
ajp109 0:a80552d32b80 459 {
ajp109 0:a80552d32b80 460 // Wait until IRQ is asserted, double timeout since some commands take long time to start responding
ajp109 0:a80552d32b80 461 TimeoutTimer tt(2*_timeout);
ajp109 0:a80552d32b80 462
ajp109 0:a80552d32b80 463 while ( !m_irq.read() ) {
ajp109 0:a80552d32b80 464 if (tt.expired()) return false;
ajp109 0:a80552d32b80 465 }
ajp109 0:a80552d32b80 466
ajp109 0:a80552d32b80 467 sdepMsgHeader_t* p_header = &p_response->header;
ajp109 0:a80552d32b80 468
ajp109 0:a80552d32b80 469 tt.set(_timeout);
ajp109 0:a80552d32b80 470
Andy Pomfret 1:6ff0eee2da9c 471 m_spi.select();
ajp109 2:8c341bac60b8 472 m_cs = false;
Andy Pomfret 1:6ff0eee2da9c 473
ajp109 0:a80552d32b80 474 do {
ajp109 0:a80552d32b80 475 if ( tt.expired() ) break;
ajp109 0:a80552d32b80 476
ajp109 0:a80552d32b80 477 p_header->msg_type = spixfer(0xff);
ajp109 0:a80552d32b80 478
ajp109 0:a80552d32b80 479 if (p_header->msg_type == SPI_IGNORED_BYTE) {
ajp109 0:a80552d32b80 480 // Bluefruit may not be ready
ajp109 0:a80552d32b80 481 // Disable & Re-enable CS with a bit of delay for Bluefruit to ready itself
ajp109 2:8c341bac60b8 482 m_cs = true;
ajp109 2:8c341bac60b8 483 wait_us(SPI_DEFAULT_DELAY_US);
ajp109 2:8c341bac60b8 484 m_cs = false;
ajp109 0:a80552d32b80 485 } else if (p_header->msg_type == SPI_OVERREAD_BYTE) {
ajp109 0:a80552d32b80 486 // IRQ may not be pulled down by Bluefruit when returning all data in previous transfer.
ajp109 0:a80552d32b80 487 // This could happen when Arduino MCU is running at fast rate comparing to Bluefruit's MCU,
ajp109 0:a80552d32b80 488 // causing an SPI_OVERREAD_BYTE to be returned at stage.
ajp109 0:a80552d32b80 489 //
ajp109 0:a80552d32b80 490 // Walkaround: Disable & Re-enable CS with a bit of delay and keep waiting
ajp109 0:a80552d32b80 491 // TODO IRQ is supposed to be OFF then ON, it is better to use GPIO trigger interrupt.
ajp109 0:a80552d32b80 492
ajp109 2:8c341bac60b8 493 m_cs = true;
ajp109 0:a80552d32b80 494 // wait for the clock to be enabled..
ajp109 0:a80552d32b80 495 // while (!digitalRead(m_irq)) {
ajp109 0:a80552d32b80 496 // if ( tt.expired() ) break;
ajp109 0:a80552d32b80 497 // }
ajp109 0:a80552d32b80 498 // if (!digitalRead(m_irq)) break;
ajp109 2:8c341bac60b8 499 wait_us(SPI_DEFAULT_DELAY_US);
ajp109 2:8c341bac60b8 500 m_cs = false;
ajp109 0:a80552d32b80 501 }
ajp109 0:a80552d32b80 502 } while (p_header->msg_type == SPI_IGNORED_BYTE || p_header->msg_type == SPI_OVERREAD_BYTE);
ajp109 0:a80552d32b80 503
ajp109 0:a80552d32b80 504 bool result=false;
ajp109 0:a80552d32b80 505
ajp109 0:a80552d32b80 506 // Not a loop, just a way to avoid goto with error handling
ajp109 0:a80552d32b80 507 do {
ajp109 0:a80552d32b80 508 // Look for the header
ajp109 0:a80552d32b80 509 // note that we should always get the right header at this point, and not doing so will really mess up things.
ajp109 0:a80552d32b80 510 while ( p_header->msg_type != SDEP_MSGTYPE_RESPONSE && p_header->msg_type != SDEP_MSGTYPE_ERROR && !tt.expired() ) {
ajp109 0:a80552d32b80 511 p_header->msg_type = spixfer(0xff);
ajp109 0:a80552d32b80 512 }
ajp109 0:a80552d32b80 513
ajp109 0:a80552d32b80 514 if ( tt.expired() ) break;
ajp109 0:a80552d32b80 515
ajp109 0:a80552d32b80 516 memset( (&p_header->msg_type)+1, 0xff, sizeof(sdepMsgHeader_t) - 1);
ajp109 0:a80552d32b80 517 spixfer((&p_header->msg_type)+1, sizeof(sdepMsgHeader_t) - 1);
ajp109 0:a80552d32b80 518
ajp109 0:a80552d32b80 519 // Command is 16-bit at odd address, may have alignment issue with 32-bit chip
ajp109 0:a80552d32b80 520 uint16_t cmd_id = (p_header->cmd_id_high << 8) | p_header->cmd_id_low;
ajp109 0:a80552d32b80 521
ajp109 0:a80552d32b80 522 // Error Message Response
ajp109 0:a80552d32b80 523 if ( p_header->msg_type == SDEP_MSGTYPE_ERROR ) break;
ajp109 0:a80552d32b80 524
ajp109 0:a80552d32b80 525 // Invalid command
ajp109 0:a80552d32b80 526 if (!(cmd_id == SDEP_CMDTYPE_AT_WRAPPER ||
ajp109 0:a80552d32b80 527 cmd_id == SDEP_CMDTYPE_BLE_UARTTX ||
ajp109 0:a80552d32b80 528 cmd_id == SDEP_CMDTYPE_BLE_UARTRX) ) {
ajp109 0:a80552d32b80 529 break;
ajp109 0:a80552d32b80 530 }
ajp109 0:a80552d32b80 531
ajp109 0:a80552d32b80 532 // Invalid length
ajp109 0:a80552d32b80 533 if(p_header->length > SDEP_MAX_PACKETSIZE) break;
ajp109 0:a80552d32b80 534
ajp109 0:a80552d32b80 535 // read payload
ajp109 0:a80552d32b80 536 memset(p_response->payload, 0xff, p_header->length);
ajp109 0:a80552d32b80 537 spixfer(p_response->payload, p_header->length);
ajp109 0:a80552d32b80 538
ajp109 0:a80552d32b80 539 result = true;
ajp109 0:a80552d32b80 540 } while(0);
ajp109 0:a80552d32b80 541
ajp109 2:8c341bac60b8 542 m_cs = true;
ajp109 0:a80552d32b80 543 m_spi.deselect();
ajp109 0:a80552d32b80 544
ajp109 0:a80552d32b80 545 return result;
ajp109 0:a80552d32b80 546 }
ajp109 0:a80552d32b80 547
ajp109 0:a80552d32b80 548 /******************************************************************************/
ajp109 0:a80552d32b80 549 /*!
ajp109 0:a80552d32b80 550
ajp109 0:a80552d32b80 551 */
ajp109 0:a80552d32b80 552 /******************************************************************************/
ajp109 0:a80552d32b80 553 void Adafruit_BluefruitLE_SPI::spixfer(void *buff, size_t len)
ajp109 0:a80552d32b80 554 {
ajp109 0:a80552d32b80 555 uint8_t *p = (uint8_t *)buff;
ajp109 0:a80552d32b80 556
ajp109 0:a80552d32b80 557 while (len--) {
ajp109 2:8c341bac60b8 558 *p = spixfer(*p);
ajp109 0:a80552d32b80 559 p++;
ajp109 0:a80552d32b80 560 }
ajp109 0:a80552d32b80 561 }
ajp109 0:a80552d32b80 562
ajp109 0:a80552d32b80 563 /******************************************************************************/
ajp109 0:a80552d32b80 564 /*!
ajp109 0:a80552d32b80 565
ajp109 0:a80552d32b80 566 */
ajp109 0:a80552d32b80 567 /******************************************************************************/
ajp109 0:a80552d32b80 568 uint8_t Adafruit_BluefruitLE_SPI::spixfer(uint8_t x)
ajp109 0:a80552d32b80 569 {
ajp109 0:a80552d32b80 570 uint8_t reply = m_spi.write(x);
ajp109 2:8c341bac60b8 571 //::printf("%x -> %x\n",x,reply);
ajp109 0:a80552d32b80 572 //SerialDebug.println(reply, HEX);
ajp109 0:a80552d32b80 573 return reply;
ajp109 0:a80552d32b80 574 }