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