Home | History | Annotate | Download | only in nrf8001
      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