added debugging

Fork of BLE_nRF8001 by RedBearLab

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers hal_aci_tl.cpp Source File

hal_aci_tl.cpp

Go to the documentation of this file.
00001 /* Copyright (c) 2014, Nordic Semiconductor ASA
00002  *
00003  * Permission is hereby granted, free of charge, to any person obtaining a copy
00004  * of this software and associated documentation files (the "Software"), to deal
00005  * in the Software without restriction, including without limitation the rights
00006  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00007  * copies of the Software, and to permit persons to whom the Software is
00008  * furnished to do so, subject to the following conditions:
00009  *
00010  * The above copyright notice and this permission notice shall be included in all
00011  * copies or substantial portions of the Software.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00014  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00015  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00016  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00017  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00018  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00019  * SOFTWARE.
00020  */
00021 
00022 /** @file
00023 @brief Implementation of the ACI transport layer module
00024 */
00025 
00026 #include "hal_platform.h "
00027 #include "hal_aci_tl.h"
00028 #include "aci_queue.h"
00029 
00030 /*
00031 PIC32 supports only MSbit transfer on SPI and the nRF8001 uses LSBit
00032 Use the REVERSE_BITS macro to convert from MSBit to LSBit
00033 The outgoing command and the incoming event needs to be converted
00034 */
00035 //For mbed as the transmission has to be reversed, the next definitions have to be added
00036 #define REVERSE_BITS(byte) (((reverse_lookup[(byte & 0x0F)]) << 4) + reverse_lookup[((byte & 0xF0) >> 4)])
00037 static const uint8_t reverse_lookup[] = { 0, 8,  4, 12, 2, 10, 6, 14,1, 9, 5, 13,3, 11, 7, 15 };
00038 
00039 static void m_aci_data_print(hal_aci_data_t *p_data);
00040 static void m_aci_event_check(void);
00041 static void m_aci_isr(void);
00042 static void m_aci_pins_set(aci_pins_t *a_pins_ptr);
00043 static inline void m_aci_reqn_disable (void);
00044 static inline void m_aci_reqn_enable (void);
00045 static void m_aci_q_flush(void);
00046 static bool m_aci_spi_transfer(hal_aci_data_t * data_to_send, hal_aci_data_t * received_data);
00047 
00048 static uint8_t        spi_readwrite(uint8_t aci_byte);
00049 
00050 static bool           aci_debug_print = false;
00051 
00052 aci_queue_t    aci_tx_q;
00053 aci_queue_t    aci_rx_q;
00054 
00055 static aci_pins_t    *a_pins_local_ptr;
00056 
00057 void m_aci_data_print(hal_aci_data_t *p_data)
00058 {
00059   const uint8_t length = p_data->buffer[0];
00060   uint8_t i;
00061   serial.printf("%d", length);
00062   serial.printf(" :");
00063   for (i=0; i<=length; i++)
00064   {
00065     serial.printf("%02X", p_data->buffer[i]);
00066     serial.printf(", ");
00067   }
00068   serial.printf("");
00069 }
00070 
00071 /*
00072   Interrupt service routine called when the RDYN line goes low. Runs the SPI transfer.
00073 */
00074 static void m_aci_isr(void)
00075 {
00076   hal_aci_data_t data_to_send;
00077   hal_aci_data_t received_data;
00078 
00079   // Receive from queue
00080   if (!aci_queue_dequeue_from_isr(&aci_tx_q, &data_to_send))
00081   {
00082     /* queue was empty, nothing to send */
00083     data_to_send.status_byte = 0;
00084     data_to_send.buffer[0] = 0;
00085   }
00086 
00087   // Receive and/or transmit data
00088   m_aci_spi_transfer(&data_to_send, &received_data);
00089 
00090   if (!aci_queue_is_full_from_isr(&aci_rx_q) && !aci_queue_is_empty_from_isr(&aci_tx_q))
00091   {
00092     m_aci_reqn_enable();
00093   }
00094 
00095   // Check if we received data
00096   if (received_data.buffer[0] > 0)
00097   {
00098     if (!aci_queue_enqueue_from_isr(&aci_rx_q, &received_data))
00099     {
00100       /* Receive Buffer full.
00101          Should never happen.
00102          Spin in a while loop.
00103       */
00104       while(1);
00105     }
00106 
00107     // Disable ready line interrupt until we have room to store incoming messages
00108     if (aci_queue_is_full_from_isr(&aci_rx_q))
00109     {
00110       //detachInterrupt(a_pins_local_ptr->interrupt_number);
00111     }
00112   }
00113 
00114   return;
00115 }
00116 
00117 /*
00118   Checks the RDYN line and runs the SPI transfer if required.
00119 */
00120 static void m_aci_event_check(void)
00121 {
00122   hal_aci_data_t data_to_send;
00123   hal_aci_data_t received_data;
00124 
00125   // No room to store incoming messages
00126   if (aci_queue_is_full(&aci_rx_q))
00127   {
00128     return;
00129   }
00130 
00131   // If the ready line is disabled and we have pending messages outgoing we enable the request line
00132   if (HIGH == digitalRead(a_pins_local_ptr->rdyn_pin))
00133   {
00134     if (!aci_queue_is_empty(&aci_tx_q))
00135     {
00136       m_aci_reqn_enable();
00137     }
00138 
00139     return;
00140   }
00141 
00142   // Receive from queue
00143   if (!aci_queue_dequeue(&aci_tx_q, &data_to_send))
00144   {
00145     /* queue was empty, nothing to send */
00146     data_to_send.status_byte = 0;
00147     data_to_send.buffer[0] = 0;
00148   }
00149 
00150   // Receive and/or transmit data
00151   m_aci_spi_transfer(&data_to_send, &received_data);
00152 
00153   /* If there are messages to transmit, and we can store the reply, we request a new transfer */
00154   if (!aci_queue_is_full(&aci_rx_q) && !aci_queue_is_empty(&aci_tx_q))
00155   {
00156     m_aci_reqn_enable();
00157   }
00158 
00159   // Check if we received data
00160   if (received_data.buffer[0] > 0)
00161   {
00162     if (!aci_queue_enqueue(&aci_rx_q, &received_data))
00163     {
00164       /* Receive Buffer full.
00165          Should never happen.
00166          Spin in a while loop.
00167       */
00168       while(1);
00169     }
00170   }
00171 
00172   return;
00173 }
00174 
00175 /** @brief Point the low level library at the ACI pins specified
00176  *  @details
00177  *  The ACI pins are specified in the application and a pointer is made available for
00178  *  the low level library to use
00179  */
00180 static void m_aci_pins_set(aci_pins_t *a_pins_ptr)
00181 {
00182   a_pins_local_ptr = a_pins_ptr;
00183 }
00184 
00185 static inline void m_aci_reqn_disable (void)
00186 {
00187   digitalWrite(a_pins_local_ptr->reqn_pin, 1);
00188 }
00189 
00190 static inline void m_aci_reqn_enable (void)
00191 {
00192   digitalWrite(a_pins_local_ptr->reqn_pin, 0);
00193 }
00194 
00195 static void m_aci_q_flush(void)
00196 {
00197   //noInterrupts();
00198   /* re-initialize aci cmd queue and aci event queue to flush them*/
00199   aci_queue_init(&aci_tx_q);
00200   aci_queue_init(&aci_rx_q);
00201   //interrupts();
00202 }
00203 
00204 static bool m_aci_spi_transfer(hal_aci_data_t * data_to_send, hal_aci_data_t * received_data)
00205 {
00206   uint8_t byte_cnt;
00207   uint8_t byte_sent_cnt;
00208   uint8_t max_bytes;
00209 
00210   m_aci_reqn_enable();
00211 
00212   // Send length, receive header
00213   byte_sent_cnt = 0;
00214   received_data->status_byte = spi_readwrite(data_to_send->buffer[byte_sent_cnt++]);
00215   // Send first byte, receive length from slave
00216   received_data->buffer[0] = spi_readwrite(data_to_send->buffer[byte_sent_cnt++]);
00217   if (0 == data_to_send->buffer[0])
00218   {
00219     max_bytes = received_data->buffer[0];
00220   }
00221   else
00222   {
00223     // Set the maximum to the biggest size. One command byte is already sent
00224     max_bytes = (received_data->buffer[0] > (data_to_send->buffer[0] - 1))
00225                                           ? received_data->buffer[0]
00226                                           : (data_to_send->buffer[0] - 1);
00227   }
00228 
00229   if (max_bytes > HAL_ACI_MAX_LENGTH)
00230   {
00231     max_bytes = HAL_ACI_MAX_LENGTH;
00232   }
00233 
00234   // Transmit/receive the rest of the packet
00235   for (byte_cnt = 0; byte_cnt < max_bytes; byte_cnt++)
00236   {
00237     received_data->buffer[byte_cnt+1] =  spi_readwrite(data_to_send->buffer[byte_sent_cnt++]);
00238   }
00239 
00240   // RDYN should follow the REQN line in approx 100ns
00241   m_aci_reqn_disable();
00242 
00243   return (max_bytes > 0);
00244 }
00245 
00246 void hal_aci_tl_debug_print(bool enable)
00247 {
00248     aci_debug_print = enable;
00249 }
00250 
00251 void hal_aci_tl_pin_reset(void)
00252 {
00253     if (NULL != a_pins_local_ptr->reset_pin)
00254     {
00255         pinMode(a_pins_local_ptr->reset_pin, OUTPUT);
00256 
00257         if ((REDBEARLAB_SHIELD_V1_1     == a_pins_local_ptr->board_name) ||
00258             (REDBEARLAB_SHIELD_V2012_07 == a_pins_local_ptr->board_name))
00259         {
00260             //The reset for the Redbearlab v1.1 and v2012.07 boards are inverted and has a Power On Reset
00261             //circuit that takes about 100ms to trigger the reset
00262             digitalWrite(a_pins_local_ptr->reset_pin, 1);
00263             delay(100);
00264             digitalWrite(a_pins_local_ptr->reset_pin, 0);
00265         }
00266         else
00267         {
00268             digitalWrite(a_pins_local_ptr->reset_pin, 1);
00269             digitalWrite(a_pins_local_ptr->reset_pin, 0);
00270             digitalWrite(a_pins_local_ptr->reset_pin, 1);
00271         }
00272     }
00273 }
00274 
00275 bool hal_aci_tl_event_peek(hal_aci_data_t *p_aci_data)
00276 {
00277   if (!a_pins_local_ptr->interface_is_interrupt)
00278   {
00279     m_aci_event_check();
00280   }
00281 
00282   if (aci_queue_peek(&aci_rx_q, p_aci_data))
00283   {
00284     return true;
00285   }
00286 
00287   return false;
00288 }
00289 
00290 bool hal_aci_tl_event_get(hal_aci_data_t *p_aci_data)
00291 {
00292   bool was_full;
00293 
00294   if (!a_pins_local_ptr->interface_is_interrupt && !aci_queue_is_full(&aci_rx_q))
00295   {
00296     m_aci_event_check();
00297   }
00298 
00299   was_full = aci_queue_is_full(&aci_rx_q);
00300 
00301   if (aci_queue_dequeue(&aci_rx_q, p_aci_data))
00302   {
00303     if (aci_debug_print)
00304     {
00305       serial.printf(" E");
00306       m_aci_data_print(p_aci_data);
00307     }
00308 
00309     if (was_full && a_pins_local_ptr->interface_is_interrupt)
00310       {
00311       /* Enable RDY line interrupt again */
00312       //attachInterrupt(a_pins_local_ptr->interrupt_number, m_aci_isr, LOW);
00313     }
00314 
00315     /* Attempt to pull REQN LOW since we've made room for new messages */
00316     if (!aci_queue_is_full(&aci_rx_q) && !aci_queue_is_empty(&aci_tx_q))
00317     {
00318       m_aci_reqn_enable();
00319     }
00320 
00321     return true;
00322   }
00323 
00324   return false;
00325 }
00326 
00327 void hal_aci_tl_init(aci_pins_t *a_pins, bool debug)
00328 {
00329   aci_debug_print = debug;
00330 
00331   /* Needs to be called as the first thing for proper intialization*/
00332   m_aci_pins_set(a_pins);
00333 
00334   /*
00335   The SPI lines used are mapped directly to the hardware SPI
00336   MISO MOSI and SCK
00337   Change here if the pins are mapped differently
00338 
00339   The SPI library assumes that the hardware pins are used
00340   */
00341   spi.format(8,0);
00342   spi.frequency(2000000);
00343 
00344   /* Initialize the ACI Command queue. This must be called after the delay above. */
00345   aci_queue_init(&aci_tx_q);
00346   aci_queue_init(&aci_rx_q);
00347 
00348   //Configure the IO lines
00349   pinMode(a_pins->rdyn_pin,     INPUT_PULLUP);
00350   pinMode(a_pins->reqn_pin,     OUTPUT);
00351 
00352   if (NULL != a_pins->active_pin)
00353   {
00354     pinMode(a_pins->active_pin, INPUT);
00355   }
00356   /* Pin reset the nRF8001, required when the nRF8001 setup is being changed */
00357   hal_aci_tl_pin_reset();
00358 
00359   /* Set the nRF8001 to a known state as required by the datasheet*/
00360   digitalWrite(a_pins->reqn_pin, 1);
00361 
00362   delay(30); //Wait for the nRF8001 to get hold of its lines - the lines float for a few ms after the reset
00363 
00364   /* Attach the interrupt to the RDYN line as requested by the caller */
00365   if (a_pins->interface_is_interrupt)
00366   {
00367     // We use the LOW level of the RDYN line as the atmega328 can wakeup from sleep only on LOW
00368     //attachInterrupt(a_pins->interrupt_number, m_aci_isr, LOW);
00369   }
00370 }
00371 
00372 bool hal_aci_tl_send(hal_aci_data_t *p_aci_cmd)
00373 {
00374   const uint8_t length = p_aci_cmd->buffer[0];
00375   bool ret_val = false;
00376 
00377   if (length > HAL_ACI_MAX_LENGTH)
00378   {
00379     return false;
00380   }
00381 
00382   ret_val = aci_queue_enqueue(&aci_tx_q, p_aci_cmd);
00383   if (ret_val)
00384   {
00385     if(!aci_queue_is_full(&aci_rx_q))
00386     {
00387       // Lower the REQN only when successfully enqueued
00388       m_aci_reqn_enable();
00389     }
00390 
00391     if (aci_debug_print)
00392     {
00393       serial.printf("C"); //ACI Command
00394       m_aci_data_print(p_aci_cmd);
00395     }
00396   }
00397 
00398   return ret_val;
00399 }
00400 
00401 static uint8_t spi_readwrite(const uint8_t aci_byte)
00402 {
00403     uint8_t tmp_byte;
00404     tmp_byte = REVERSE_BITS(aci_byte);
00405     tmp_byte = spi.write(tmp_byte);
00406     return REVERSE_BITS(tmp_byte);
00407 }
00408 
00409 bool hal_aci_tl_rx_q_empty (void)
00410 {
00411   return aci_queue_is_empty(&aci_rx_q);
00412 }
00413 
00414 bool hal_aci_tl_rx_q_full (void)
00415 {
00416   return aci_queue_is_full(&aci_rx_q);
00417 }
00418 
00419 bool hal_aci_tl_tx_q_empty (void)
00420 {
00421   return aci_queue_is_empty(&aci_tx_q);
00422 }
00423 
00424 bool hal_aci_tl_tx_q_full (void)
00425 {
00426   return aci_queue_is_full(&aci_tx_q);
00427 }
00428 
00429 void hal_aci_tl_q_flush (void)
00430 {
00431   m_aci_q_flush();
00432 }