/* Checks the RDYN line and runs the SPI transfer if required. */ static void m_aci_event_check(void) { hal_aci_data_t data_to_send; hal_aci_data_t received_data; // No room to store incoming messages if (aci_queue_is_full(&aci_rx_q)) { return; } // If the ready line is disabled and we have pending messages outgoing we enable the request line if (HIGH == mraa_gpio_read (a_pins_local_ptr->m_rdy_ctx)) // if (HIGH == digitalRead(a_pins_local_ptr->rdyn_pin)) { if (!aci_queue_is_empty(&aci_tx_q)) { m_aci_reqn_enable(); } return; } // Receive from queue if (!aci_queue_dequeue(&aci_tx_q, &data_to_send)) { /* queue was empty, nothing to send */ data_to_send.status_byte = 0; data_to_send.buffer[0] = 0; } // Receive and/or transmit data m_aci_spi_transfer(&data_to_send, &received_data); /* If there are messages to transmit, and we can store the reply, we request a new transfer */ if (!aci_queue_is_full(&aci_rx_q) && !aci_queue_is_empty(&aci_tx_q)) { m_aci_reqn_enable(); } // Check if we received data if (received_data.buffer[0] > 0) { if (!aci_queue_enqueue(&aci_rx_q, &received_data)) { /* Receive Buffer full. Should never happen. Spin in a while loop. */ while(1); } } return; }
bool aci_queue_peek(aci_queue_t *aci_q, hal_aci_data_t *p_data) { ble_assert(NULL != aci_q); ble_assert(NULL != p_data); if (aci_queue_is_empty(aci_q)) { return false; } memcpy((uint8_t *)p_data, (uint8_t *)&(aci_q->aci_data[aci_q->head % ACI_QUEUE_SIZE]), sizeof(hal_aci_data_t)); return true; }
bool aci_queue_dequeue(aci_queue_t *aci_q, hal_aci_data_t *p_data) { // ble_assert(NULL != aci_q); // ble_assert(NULL != p_data); if (aci_queue_is_empty(aci_q)) { return false; } memcpy((uint8_t *)p_data, (uint8_t *)&(aci_q->aci_data[aci_q->head]), sizeof(hal_aci_data_t)); aci_q->head = (aci_q->head + 1) % ACI_QUEUE_SIZE; return true; }
bool hal_aci_tl_event_get(hal_aci_data_t *p_aci_data) { bool was_full; #ifdef HAL_ACI_TL_INTERRUPT if (!a_pins_local_ptr->interface_is_interrupt && !aci_queue_is_full(&aci_rx_q)) #else if (!aci_queue_is_full(&aci_rx_q)) #endif { m_aci_event_check(); } was_full = aci_queue_is_full(&aci_rx_q); if (aci_queue_dequeue(&aci_rx_q, p_aci_data)) { #ifdef HAL_ACI_TL_DEBUG if (aci_debug_print) { Serial.print(" E"); m_aci_data_print(p_aci_data); } #endif #ifdef HAL_ACI_TL_INTERRUPT if (was_full && a_pins_local_ptr->interface_is_interrupt) { /* Enable RDY line interrupt again */ attachInterrupt(a_pins_local_ptr->interrupt_number, m_aci_isr, LOW); #if defined(SPI_HAS_TRANSACTION) && defined(__SAMD21G18A__) SPI.usingInterrupt(a_pins->interrupt_number); #endif } #endif /* Attempt to pull REQN LOW since we've made room for new messages */ if (!aci_queue_is_full(&aci_rx_q) && !aci_queue_is_empty(&aci_tx_q)) { m_aci_reqn_enable(); } return true; } return false; }
bool hal_aci_tl_event_get(hal_aci_data_t *p_aci_data) { bool was_full; if (!a_pins_local_ptr->interface_is_interrupt && !aci_queue_is_full(&aci_rx_q)) { m_aci_event_check(); } was_full = aci_queue_is_full(&aci_rx_q); if (aci_queue_dequeue(&aci_rx_q, p_aci_data)) { if (aci_debug_print) { Serial.print(" E"); m_aci_data_print(p_aci_data); } if (was_full && a_pins_local_ptr->interface_is_interrupt) { /* Enable RDY line interrupt again */ attachInterrupt(a_pins_local_ptr->interrupt_number, m_aci_isr, LOW); } /* Attempt to pull REQN LOW since we've made room for new messages */ if (!aci_queue_is_full(&aci_rx_q) && !aci_queue_is_empty(&aci_tx_q)) { m_aci_reqn_enable(); } return true; } return false; }
bool hal_aci_tl_tx_q_empty (void) { return aci_queue_is_empty(&aci_tx_q); }
void hal_aci_tl_init(aci_pins_t *a_pins, bool debug) { aci_debug_print = debug; /* Needs to be called as the first thing for proper intialization*/ m_aci_pins_set(a_pins); /* The SPI lines used are mapped directly to the hardware SPI MISO MOSI and SCK Change here if the pins are mapped differently The SPI library assumes that the hardware pins are used */ spi_master_init(a_pins->spi); struct spi_device spi_device_conf = { .id = a_pins->reqn_pin }; spi_master_setup_device(a_pins->spi, &spi_device_conf, SPI_MODE_0, BLUETOOTH_DATA_RATE, 0); //Board dependent defines #if defined (__AVR__) //For Arduino use the LSB first a_pins->spi->CTRL |= SPI_DORD_bm; #elif defined(__PIC32MX__) //For ChipKit use MSBFIRST and REVERSE the bits on the SPI as LSBFIRST is not supported SPI.setBitOrder(MSBFIRST); #endif /* Initialize the ACI Command queue. This must be called after the delay above. */ aci_queue_init(&aci_tx_q); aci_queue_init(&aci_rx_q); //Configure the IO lines //pinMode(a_pins->rdyn_pin, INPUT_PULLUP); //pinMode(a_pins->reqn_pin, OUTPUT); spi_enable(a_pins->spi); if (UNUSED != a_pins->active_pin) { pinMode(a_pins->active_pin, INPUT); } /* Pin reset the nRF8001, required when the nRF8001 setup is being changed */ hal_aci_tl_pin_reset(); /* Set the nRF8001 to a known state as required by the datasheet*/ digitalWrite(a_pins->miso_pin, 0); digitalWrite(a_pins->mosi_pin, 0); digitalWrite(a_pins->reqn_pin, 1); digitalWrite(a_pins->sck_pin, 0); delay(30); //Wait for the nRF8001 to get hold of its lines - the lines float for a few ms after the reset /* Attach the interrupt to the RDYN line as requested by the caller */ if (a_pins->interface_is_interrupt) { // We use the LOW level of the RDYN line as the atmega328 can wakeup from sleep only on LOW attachInterrupt(a_pins->interrupt_number, m_aci_isr, LOW); } } bool hal_aci_tl_send(hal_aci_data_t *p_aci_cmd) { const uint8_t length = p_aci_cmd->buffer[0]; bool ret_val = false; if (length > HAL_ACI_MAX_LENGTH) { return false; } ret_val = aci_queue_enqueue(&aci_tx_q, p_aci_cmd); if (ret_val) { if(!aci_queue_is_full(&aci_rx_q)) { // Lower the REQN only when successfully enqueued m_aci_reqn_enable(); } if (aci_debug_print) { //Serial.print("C"); //ACI Command m_aci_data_print(p_aci_cmd); } } return ret_val; } static uint8_t spi_readwrite(const uint8_t aci_byte) { //Board dependent defines #if defined (__AVR__) //For Arduino the transmission does not have to be reversed return spi_readwrite_xmega(aci_byte); #elif defined(__PIC32MX__) //For ChipKit the transmission has to be reversed uint8_t tmp_bits; tmp_bits = SPI.transfer(REVERSE_BITS(aci_byte)); return REVERSE_BITS(tmp_bits); #endif } bool hal_aci_tl_rx_q_empty (void) { return aci_queue_is_empty(&aci_rx_q); } bool hal_aci_tl_rx_q_full (void) { return aci_queue_is_full(&aci_rx_q); } bool hal_aci_tl_tx_q_empty (void) { return aci_queue_is_empty(&aci_tx_q); } bool hal_aci_tl_tx_q_full (void) { return aci_queue_is_full(&aci_tx_q); } void hal_aci_tl_q_flush (void) { m_aci_q_flush(); }