1 /* Copyright (c) 2014, Nordic Semiconductor ASA 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to deal 5 * in the Software without restriction, including without limitation the rights 6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 * copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in all 11 * copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 * SOFTWARE. 20 */ 21 22 /** @file 23 @brief Implementation of the ACI transport layer module 24 */ 25 26 #include <string> 27 #include <stdexcept> 28 #include <stdio.h> 29 30 #include "hal_platform.h" 31 #include "hal_aci_tl.h" 32 #include "aci_queue.h" 33 34 #define HIGH 1 35 #define LOW 0 36 37 #define REVERSE_BITS(byte) (((reverse_lookup[(byte & 0x0F)]) << 4) + reverse_lookup[((byte & 0xF0) >> 4)]) 38 static const uint8_t reverse_lookup[] = { 0, 8, 4, 12, 2, 10, 6, 14,1, 9, 5, 13,3, 11, 7, 15 }; 39 40 static void m_aci_data_print(hal_aci_data_t *p_data); 41 static void m_aci_event_check(void); 42 static void m_aci_isr(void); 43 static void m_aci_pins_set(aci_pins_t *a_pins_ptr); 44 static inline void m_aci_reqn_disable (void); 45 static inline void m_aci_reqn_enable (void); 46 static void m_aci_q_flush(void); 47 static bool m_aci_spi_transfer(hal_aci_data_t * data_to_send, hal_aci_data_t * received_data); 48 49 static uint8_t spi_readwrite(uint8_t aci_byte); 50 51 static bool aci_debug_print = false; 52 53 aci_queue_t aci_tx_q; 54 aci_queue_t aci_rx_q; 55 56 static aci_pins_t *a_pins_local_ptr; 57 58 void m_aci_data_print(hal_aci_data_t *p_data) 59 { 60 const uint8_t length = p_data->buffer[0]; 61 uint8_t i; 62 printf("%d\n", length); 63 printf(" :\n"); 64 for (i=0; i<=length; i++) 65 { 66 printf("%x", p_data->buffer[i]); 67 printf(", "); 68 } 69 printf("\n"); 70 } 71 72 /* 73 Interrupt service routine called when the RDYN line goes low. Runs the SPI transfer. 74 */ 75 static void m_aci_isr(void) 76 { 77 hal_aci_data_t data_to_send; 78 hal_aci_data_t received_data; 79 80 // Receive from queue 81 if (!aci_queue_dequeue_from_isr(&aci_tx_q, &data_to_send)) 82 { 83 /* queue was empty, nothing to send */ 84 data_to_send.status_byte = 0; 85 data_to_send.buffer[0] = 0; 86 } 87 88 // Receive and/or transmit data 89 m_aci_spi_transfer(&data_to_send, &received_data); 90 91 if (!aci_queue_is_full_from_isr(&aci_rx_q) && !aci_queue_is_empty_from_isr(&aci_tx_q)) 92 { 93 m_aci_reqn_enable(); 94 } 95 96 // Check if we received data 97 if (received_data.buffer[0] > 0) 98 { 99 if (!aci_queue_enqueue_from_isr(&aci_rx_q, &received_data)) 100 { 101 /* Receive Buffer full. 102 Should never happen. 103 Spin in a while loop. 104 */ 105 while(1); 106 } 107 108 // Disable ready line interrupt until we have room to store incoming messages 109 if (aci_queue_is_full_from_isr(&aci_rx_q)) 110 { 111 // detachInterrupt(a_pins_local_ptr->interrupt_number); 112 } 113 } 114 115 return; 116 } 117 118 /* 119 Checks the RDYN line and runs the SPI transfer if required. 120 */ 121 static void m_aci_event_check(void) 122 { 123 hal_aci_data_t data_to_send; 124 hal_aci_data_t received_data; 125 126 // No room to store incoming messages 127 if (aci_queue_is_full(&aci_rx_q)) 128 { 129 return; 130 } 131 132 // If the ready line is disabled and we have pending messages outgoing we enable the request line 133 if (HIGH == mraa_gpio_read (a_pins_local_ptr->m_rdy_ctx)) 134 // if (HIGH == digitalRead(a_pins_local_ptr->rdyn_pin)) 135 { 136 if (!aci_queue_is_empty(&aci_tx_q)) 137 { 138 m_aci_reqn_enable(); 139 } 140 141 return; 142 } 143 144 // Receive from queue 145 if (!aci_queue_dequeue(&aci_tx_q, &data_to_send)) 146 { 147 /* queue was empty, nothing to send */ 148 data_to_send.status_byte = 0; 149 data_to_send.buffer[0] = 0; 150 } 151 152 // Receive and/or transmit data 153 m_aci_spi_transfer(&data_to_send, &received_data); 154 155 /* If there are messages to transmit, and we can store the reply, we request a new transfer */ 156 if (!aci_queue_is_full(&aci_rx_q) && !aci_queue_is_empty(&aci_tx_q)) 157 { 158 m_aci_reqn_enable(); 159 } 160 161 // Check if we received data 162 if (received_data.buffer[0] > 0) 163 { 164 if (!aci_queue_enqueue(&aci_rx_q, &received_data)) 165 { 166 /* Receive Buffer full. 167 Should never happen. 168 Spin in a while loop. 169 */ 170 while(1); 171 } 172 } 173 174 return; 175 } 176 177 /** @brief Point the low level library at the ACI pins specified 178 * @details 179 * The ACI pins are specified in the application and a pointer is made available for 180 * the low level library to use 181 */ 182 static void m_aci_pins_set(aci_pins_t *a_pins_ptr) 183 { 184 a_pins_local_ptr = a_pins_ptr; 185 } 186 187 static inline void m_aci_reqn_disable (void) 188 { 189 mraa_gpio_write (a_pins_local_ptr->m_req_ctx, HIGH); 190 } 191 192 static inline void m_aci_reqn_enable (void) 193 { 194 mraa_gpio_write (a_pins_local_ptr->m_req_ctx, LOW); 195 } 196 197 static void m_aci_q_flush(void) 198 { 199 // noInterrupts(); 200 /* re-initialize aci cmd queue and aci event queue to flush them*/ 201 aci_queue_init(&aci_tx_q); 202 aci_queue_init(&aci_rx_q); 203 // interrupts(); 204 } 205 206 static bool m_aci_spi_transfer(hal_aci_data_t * data_to_send, hal_aci_data_t * received_data) 207 { 208 uint8_t byte_cnt; 209 uint8_t byte_sent_cnt; 210 uint8_t max_bytes; 211 212 m_aci_reqn_enable(); 213 214 // Send length, receive header 215 byte_sent_cnt = 0; 216 received_data->status_byte = spi_readwrite(data_to_send->buffer[byte_sent_cnt++]); 217 // Send first byte, receive length from slave 218 received_data->buffer[0] = spi_readwrite(data_to_send->buffer[byte_sent_cnt++]); 219 if (0 == data_to_send->buffer[0]) 220 { 221 max_bytes = received_data->buffer[0]; 222 } 223 else 224 { 225 // Set the maximum to the biggest size. One command byte is already sent 226 max_bytes = (received_data->buffer[0] > (data_to_send->buffer[0] - 1)) 227 ? received_data->buffer[0] 228 : (data_to_send->buffer[0] - 1); 229 } 230 231 if (max_bytes > HAL_ACI_MAX_LENGTH) 232 { 233 max_bytes = HAL_ACI_MAX_LENGTH; 234 } 235 236 // Transmit/receive the rest of the packet 237 for (byte_cnt = 0; byte_cnt < max_bytes; byte_cnt++) 238 { 239 received_data->buffer[byte_cnt+1] = spi_readwrite(data_to_send->buffer[byte_sent_cnt++]); 240 } 241 242 // RDYN should follow the REQN line in approx 100ns 243 m_aci_reqn_disable(); 244 245 return (max_bytes > 0); 246 } 247 248 void hal_aci_tl_debug_print(bool enable) 249 { 250 aci_debug_print = enable; 251 } 252 253 void hal_aci_tl_pin_reset(void) 254 { 255 if (UNUSED != a_pins_local_ptr->reset_pin) 256 { 257 // pinMode(a_pins_local_ptr->reset_pin, OUTPUT); 258 259 if ((REDBEARLAB_SHIELD_V1_1 == a_pins_local_ptr->board_name) || 260 (REDBEARLAB_SHIELD_V2012_07 == a_pins_local_ptr->board_name)) 261 { 262 //The reset for the Redbearlab v1.1 and v2012.07 boards are inverted and has a Power On Reset 263 //circuit that takes about 100ms to trigger the reset 264 mraa_gpio_write (a_pins_local_ptr->m_rst_ctx, HIGH); 265 usleep (100000); 266 mraa_gpio_write (a_pins_local_ptr->m_rst_ctx, LOW); 267 } 268 else 269 { 270 mraa_gpio_write (a_pins_local_ptr->m_rst_ctx, HIGH); 271 mraa_gpio_write (a_pins_local_ptr->m_rst_ctx, LOW); 272 mraa_gpio_write (a_pins_local_ptr->m_rst_ctx, HIGH); 273 } 274 } 275 } 276 277 bool hal_aci_tl_event_peek(hal_aci_data_t *p_aci_data) 278 { 279 if (!a_pins_local_ptr->interface_is_interrupt) 280 { 281 m_aci_event_check(); 282 } 283 284 if (aci_queue_peek(&aci_rx_q, p_aci_data)) 285 { 286 return true; 287 } 288 289 return false; 290 } 291 292 bool hal_aci_tl_event_get(hal_aci_data_t *p_aci_data) 293 { 294 bool was_full; 295 296 if (!a_pins_local_ptr->interface_is_interrupt && !aci_queue_is_full(&aci_rx_q)) 297 { 298 m_aci_event_check(); 299 } 300 301 was_full = aci_queue_is_full(&aci_rx_q); 302 303 if (aci_queue_dequeue(&aci_rx_q, p_aci_data)) 304 { 305 if (aci_debug_print) 306 { 307 printf(" E"); 308 m_aci_data_print(p_aci_data); 309 } 310 311 if (was_full && a_pins_local_ptr->interface_is_interrupt) 312 { 313 /* Enable RDY line interrupt again */ 314 // attachInterrupt(a_pins_local_ptr->interrupt_number, m_aci_isr, LOW); 315 } 316 317 /* Attempt to pull REQN LOW since we've made room for new messages */ 318 if (!aci_queue_is_full(&aci_rx_q) && !aci_queue_is_empty(&aci_tx_q)) 319 { 320 m_aci_reqn_enable(); 321 } 322 323 return true; 324 } 325 326 return false; 327 } 328 329 void hal_aci_tl_init(aci_pins_t *a_pins, bool debug) 330 { 331 mraa_result_t error = MRAA_SUCCESS; 332 aci_debug_print = debug; 333 334 /* Needs to be called as the first thing for proper intialization*/ 335 m_aci_pins_set(a_pins); 336 337 /* 338 * Init SPI 339 */ 340 a_pins->m_spi = mraa_spi_init (0); 341 if (a_pins->m_spi == NULL) { 342 throw std::invalid_argument(std::string(__FUNCTION__) + 343 ": mraa_spi_init() failed"); 344 } 345 346 mraa_spi_frequency (a_pins->m_spi, 2000000); 347 mraa_spi_mode (a_pins->m_spi, MRAA_SPI_MODE0); 348 349 /* Initialize the ACI Command queue. This must be called after the delay above. */ 350 aci_queue_init(&aci_tx_q); 351 aci_queue_init(&aci_rx_q); 352 353 // Configure the IO lines 354 a_pins->m_rdy_ctx = mraa_gpio_init (a_pins->rdyn_pin); 355 if (a_pins->m_rdy_ctx == NULL) { 356 throw std::invalid_argument(std::string(__FUNCTION__) + 357 ": mraa_gpio_init(rdyn) failed, invalid pin?"); 358 } 359 360 a_pins->m_req_ctx = mraa_gpio_init (a_pins->reqn_pin); 361 if (a_pins->m_req_ctx == NULL) { 362 throw std::invalid_argument(std::string(__FUNCTION__) + 363 ": mraa_gpio_init(reqn) failed, invalid pin?"); 364 } 365 366 a_pins->m_rst_ctx = mraa_gpio_init (a_pins->reset_pin); 367 if (a_pins->m_rst_ctx == NULL) { 368 throw std::invalid_argument(std::string(__FUNCTION__) + 369 ": mraa_gpio_init(reset) failed, invalid pin?"); 370 } 371 372 error = mraa_gpio_dir (a_pins->m_rdy_ctx, MRAA_GPIO_IN); 373 if (error != MRAA_SUCCESS) { 374 printf ("[ERROR] GPIO failed to initilize \n"); 375 } 376 377 error = mraa_gpio_dir (a_pins->m_req_ctx, MRAA_GPIO_OUT); 378 if (error != MRAA_SUCCESS) { 379 printf ("[ERROR] GPIO failed to initilize \n"); 380 } 381 382 error = mraa_gpio_dir (a_pins->m_rst_ctx, MRAA_GPIO_OUT); 383 if (error != MRAA_SUCCESS) { 384 printf ("[ERROR] GPIO failed to initilize \n"); 385 } 386 387 if (UNUSED != a_pins->active_pin) { 388 } 389 390 /* Pin reset the nRF8001, required when the nRF8001 setup is being changed */ 391 hal_aci_tl_pin_reset(); 392 393 /* Set the nRF8001 to a known state as required by the datasheet*/ 394 mraa_gpio_write (a_pins->m_req_ctx, LOW); 395 396 usleep(30000); //Wait for the nRF8001 to get hold of its lines - the lines float for a few ms after the reset 397 398 /* Attach the interrupt to the RDYN line as requested by the caller */ 399 if (a_pins->interface_is_interrupt) { 400 // We use the LOW level of the RDYN line as the atmega328 can wakeup from sleep only on LOW 401 // attachInterrupt(a_pins->interrupt_number, m_aci_isr, LOW); 402 } 403 } 404 405 bool hal_aci_tl_send(hal_aci_data_t *p_aci_cmd) 406 { 407 const uint8_t length = p_aci_cmd->buffer[0]; 408 bool ret_val = false; 409 410 if (length > HAL_ACI_MAX_LENGTH) 411 { 412 return false; 413 } 414 415 ret_val = aci_queue_enqueue(&aci_tx_q, p_aci_cmd); 416 if (ret_val) 417 { 418 if(!aci_queue_is_full(&aci_rx_q)) 419 { 420 // Lower the REQN only when successfully enqueued 421 m_aci_reqn_enable(); 422 } 423 } 424 425 return ret_val; 426 } 427 428 static uint8_t spi_readwrite(const uint8_t aci_byte) 429 { 430 uint8_t reversed, ret; 431 reversed = mraa_spi_write (a_pins_local_ptr->m_spi, REVERSE_BITS (aci_byte)); 432 ret = REVERSE_BITS (reversed); 433 return ret; 434 } 435 436 bool hal_aci_tl_rx_q_empty (void) 437 { 438 return aci_queue_is_empty(&aci_rx_q); 439 } 440 441 bool hal_aci_tl_rx_q_full (void) 442 { 443 return aci_queue_is_full(&aci_rx_q); 444 } 445 446 bool hal_aci_tl_tx_q_empty (void) 447 { 448 return aci_queue_is_empty(&aci_tx_q); 449 } 450 451 bool hal_aci_tl_tx_q_full (void) 452 { 453 return aci_queue_is_full(&aci_tx_q); 454 } 455 456 void hal_aci_tl_q_flush (void) 457 { 458 m_aci_q_flush(); 459 } 460