/* * Copyright (C) 2014 Hamburg University of Applied Sciences * * This file is subject to the terms and conditions of the GNU Lesser General * Public License v2.1. See the file LICENSE in the top level directory for more * details. */ /** * @ingroup drivers_nrf24l01p * @{ * @author Peter Kietzmann * @author Joakim Nohlgård * @author Marc Poulhiès * @} */ #include "nrf24l01p.h" #include "nrf24l01p_settings.h" #include "mutex.h" #include "periph/gpio.h" #include "periph/spi.h" #include "xtimer.h" #include "thread.h" #include "msg.h" #define ENABLE_DEBUG (0) #include "debug.h" #define DELAY_CS_TOGGLE_TICKS (xtimer_ticks_from_usec(DELAY_CS_TOGGLE_US)) #define DELAY_AFTER_FUNC_TICKS (xtimer_ticks_from_usec(DELAY_AFTER_FUNC_US)) #define DELAY_CHANGE_TXRX_TICKS (xtimer_ticks_from_usec(DELAY_CHANGE_TXRX_US)) int nrf24l01p_read_reg(nrf24l01p_t *dev, char reg, char *answer) { int status; /* Acquire exclusive access to the bus. */ spi_acquire(dev->spi); gpio_clear(dev->cs); xtimer_spin(DELAY_CS_TOGGLE_TICKS); status = spi_transfer_reg(dev->spi, (CMD_R_REGISTER | (REGISTER_MASK & reg)), CMD_NOP, answer); xtimer_spin(DELAY_CS_TOGGLE_TICKS); gpio_set(dev->cs); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); return (status < 0) ? status : 0; } int nrf24l01p_write_reg(nrf24l01p_t *dev, char reg, char write) { int status; char reg_content; /* Acquire exclusive access to the bus. */ spi_acquire(dev->spi); gpio_clear(dev->cs); xtimer_spin(DELAY_CS_TOGGLE_TICKS); status = spi_transfer_reg(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & reg)), write, ®_content); xtimer_spin(DELAY_CS_TOGGLE_TICKS); gpio_set(dev->cs); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); return (status < 0) ? status : 0; } int nrf24l01p_init(nrf24l01p_t *dev, spi_t spi, gpio_t ce, gpio_t cs, gpio_t irq) { int status; char INITIAL_TX_ADDRESS[] = {0xe7, 0xe7, 0xe7, 0xe7, 0xe7,}; char INITIAL_RX_ADDRESS[] = {0xe7, 0xe7, 0xe7, 0xe7, 0xe7,}; dev->spi = spi; dev->ce = ce; dev->cs = cs; dev->irq = irq; dev->listener = KERNEL_PID_UNDEF; /* Init CE pin */ gpio_init(dev->ce, GPIO_OUT); /* Init CS pin */ gpio_init(dev->cs, GPIO_OUT); gpio_set(dev->cs); /* Init IRQ pin */ gpio_init_int(dev->irq, GPIO_IN_PU, GPIO_FALLING, nrf24l01p_rx_cb, dev); /* Init SPI */ spi_poweron(dev->spi); spi_acquire(dev->spi); status = spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, SPI_SPEED_400KHZ); spi_release(dev->spi); if (status < 0) { return status; } xtimer_spin(DELAY_AFTER_FUNC_TICKS); /* Flush TX FIFIO */ status = nrf24l01p_flush_tx_fifo(dev); if (status < 0) { return status; } /* Flush RX FIFIO */ status = nrf24l01p_flush_rx_fifo(dev); if (status < 0) { return status; } /* Setup adress width */ status = nrf24l01p_set_address_width(dev, NRF24L01P_AW_5BYTE); if (status < 0) { return status; } /* Setup payload width */ status = nrf24l01p_set_payload_width(dev, NRF24L01P_PIPE0, NRF24L01P_MAX_DATA_LENGTH); if (status < 0) { return status; } /* Set RF channel */ status = nrf24l01p_set_channel(dev, INITIAL_RF_CHANNEL); if (status < 0) { return status; } /* Set RF power */ status = nrf24l01p_set_power(dev, INITIAL_RX_POWER_0dB); if (status < 0) { return status; } /* Set RF datarate */ status = nrf24l01p_set_datarate(dev, NRF24L01P_DR_250KBS); if (status < 0) { return status; } /* Set TX Address */ status = nrf24l01p_set_tx_address(dev, INITIAL_TX_ADDRESS, INITIAL_ADDRESS_WIDTH); if (status < 0) { return status; } /* Set RX Adress */ status = nrf24l01p_set_rx_address(dev, NRF24L01P_PIPE0, INITIAL_RX_ADDRESS, INITIAL_ADDRESS_WIDTH); if (status < 0) { return status; } /* Reset auto ack for all pipes */ status = nrf24l01p_disable_all_auto_ack(dev); if (status < 0) { return status; } /* Setup Auto ACK and retransmission */ status = nrf24l01p_setup_auto_ack(dev, NRF24L01P_PIPE0, NRF24L01P_RETR_750US, 15); if (status < 0) { return status; } /* Setup CRC */ status = nrf24l01p_enable_crc(dev, NRF24L01P_CRC_2BYTE); if (status < 0) { return status; } /* Reset all interrupt flags */ status = nrf24l01p_reset_all_interrupts(dev); if (status < 0) { return status; } return nrf24l01p_on(dev); } int nrf24l01p_on(nrf24l01p_t *dev) { char read; int status; nrf24l01p_read_reg(dev, REG_CONFIG, &read); status = nrf24l01p_write_reg(dev, REG_CONFIG, (read | PWR_UP)); xtimer_usleep(DELAY_CHANGE_PWR_MODE_US); return status; } int nrf24l01p_off(nrf24l01p_t *dev) { char read; int status; nrf24l01p_read_reg(dev, REG_CONFIG, &read); status = nrf24l01p_write_reg(dev, REG_CONFIG, (read & ~PWR_UP)); xtimer_usleep(DELAY_CHANGE_PWR_MODE_US); return status; } void nrf24l01p_transmit(nrf24l01p_t *dev) { gpio_set(dev->ce); xtimer_usleep(DELAY_CE_HIGH_US); /* at least 10 us high */ gpio_clear(dev->ce); xtimer_spin(DELAY_CHANGE_TXRX_TICKS); } int nrf24l01p_read_payload(nrf24l01p_t *dev, char *answer, unsigned int size) { int status; /* Acquire exclusive access to the bus. */ spi_acquire(dev->spi); gpio_clear(dev->cs); xtimer_spin(DELAY_CS_TOGGLE_TICKS); status = spi_transfer_regs(dev->spi, CMD_R_RX_PAYLOAD, 0, answer, size); xtimer_spin(DELAY_CS_TOGGLE_TICKS); gpio_set(dev->cs); xtimer_spin(DELAY_AFTER_FUNC_TICKS); /* Release the bus for other threads. */ spi_release(dev->spi); return status; } void nrf24l01p_register(nrf24l01p_t *dev, unsigned int *pid) { dev->listener = *pid; } int nrf24l01p_unregister(nrf24l01p_t *dev, unsigned int pid) { if (dev != NULL && dev->listener == pid) { dev->listener = 0; return 0; } else { return -1; } } void nrf24l01p_get_id(nrf24l01p_t *dev, unsigned int *pid) { *((int *)pid) = dev->listener; } void nrf24l01p_start(nrf24l01p_t *dev) { gpio_set(dev->ce); xtimer_usleep(DELAY_CE_START_US); } void nrf24l01p_stop(nrf24l01p_t *dev) { xtimer_spin(DELAY_CS_TOGGLE_TICKS); gpio_clear(dev->ce); } int nrf24l01p_preload(nrf24l01p_t *dev, char *data, unsigned int size) { int status; size = (size <= 32) ? size : 32; /* Acquire exclusive access to the bus. */ spi_acquire(dev->spi); gpio_clear(dev->cs); xtimer_spin(DELAY_CS_TOGGLE_TICKS); status = spi_transfer_regs(dev->spi, CMD_W_TX_PAYLOAD, data, NULL, size); xtimer_spin(DELAY_CS_TOGGLE_TICKS); gpio_set(dev->cs); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); return status; } int nrf24l01p_set_channel(nrf24l01p_t *dev, uint8_t chan) { if (chan > 125) { chan = 125; } return nrf24l01p_write_reg(dev, REG_RF_CH, chan); } int nrf24l01p_set_address_width(nrf24l01p_t *dev, nrf24l01p_aw_t aw) { char aw_setup; nrf24l01p_read_reg(dev, REG_SETUP_AW, &aw_setup); xtimer_spin(DELAY_AFTER_FUNC_TICKS); switch (aw) { case NRF24L01P_AW_3BYTE: aw_setup &= ~(3); aw_setup |= 1; break; case NRF24L01P_AW_4BYTE: aw_setup &= ~(3); aw_setup |= 2; break; case NRF24L01P_AW_5BYTE: aw_setup &= ~(3); aw_setup |= 3; break; default: return -1; } return nrf24l01p_write_reg(dev, REG_SETUP_AW, aw_setup); } int nrf24l01p_set_payload_width(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char width) { char pipe_pw_address; switch (pipe) { case NRF24L01P_PIPE0: pipe_pw_address = REG_RX_PW_P0; break; case NRF24L01P_PIPE1: pipe_pw_address = REG_RX_PW_P1; break; case NRF24L01P_PIPE2: pipe_pw_address = REG_RX_PW_P2; break; case NRF24L01P_PIPE3: pipe_pw_address = REG_RX_PW_P3; break; case NRF24L01P_PIPE4: pipe_pw_address = REG_RX_PW_P4; break; case NRF24L01P_PIPE5: pipe_pw_address = REG_RX_PW_P5; break; default: return -1; } if (width < 0) { return -1; } if (width > 32) { width = 32; } return nrf24l01p_write_reg(dev, pipe_pw_address, width); } int nrf24l01p_set_tx_address(nrf24l01p_t *dev, char *saddr, unsigned int length) { int status; /* Acquire exclusive access to the bus. */ spi_acquire(dev->spi); gpio_clear(dev->cs); xtimer_spin(DELAY_CS_TOGGLE_TICKS); status = spi_transfer_regs(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), saddr, NULL, length); /* address width is 5 byte */ xtimer_spin(DELAY_CS_TOGGLE_TICKS); gpio_set(dev->cs); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); return (status < 0) ? status : length; } int nrf24l01p_set_tx_address_long(nrf24l01p_t *dev, uint64_t saddr, unsigned int length) { int status; char buf[length]; if (length <= INITIAL_ADDRESS_WIDTH) { for (int i = 0; i < length; i++) { buf[i] = (uint8_t)(saddr >> (((length - 1) - i) * sizeof(uint64_t))); } } else { return -1; } /* Acquire exclusive access to the bus. */ spi_acquire(dev->spi); gpio_clear(dev->cs); xtimer_spin(DELAY_CS_TOGGLE_TICKS); status = spi_transfer_regs(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), buf, NULL, length); /* address width is 5 byte */ xtimer_spin(DELAY_CS_TOGGLE_TICKS); gpio_set(dev->cs); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); return (status < 0) ? status : length; } uint64_t nrf24l01p_get_tx_address_long(nrf24l01p_t *dev) { int status; uint64_t saddr_64 = 0; char addr_array[INITIAL_ADDRESS_WIDTH]; /* Acquire exclusive access to the bus. */ spi_acquire(dev->spi); gpio_clear(dev->cs); xtimer_spin(DELAY_CS_TOGGLE_TICKS); status = spi_transfer_regs(dev->spi, (CMD_R_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), 0, addr_array, INITIAL_ADDRESS_WIDTH); /* address width is 5 byte */ xtimer_spin(DELAY_CS_TOGGLE_TICKS); gpio_set(dev->cs); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); if (status < 0) { return -1; } xtimer_spin(DELAY_AFTER_FUNC_TICKS); for (int i = 0; i < INITIAL_ADDRESS_WIDTH; i++) { saddr_64 |= (((uint64_t) addr_array[i]) << (8 * (INITIAL_ADDRESS_WIDTH - i - 1))); } return saddr_64; } int nrf24l01p_set_rx_address(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char *saddr, unsigned int length) { int status; char pipe_addr; switch (pipe) { case NRF24L01P_PIPE0: pipe_addr = REG_RX_ADDR_P0; break; case NRF24L01P_PIPE1: pipe_addr = REG_RX_ADDR_P1; break; case NRF24L01P_PIPE2: pipe_addr = REG_RX_ADDR_P2; break; case NRF24L01P_PIPE3: pipe_addr = REG_RX_ADDR_P3; break; case NRF24L01P_PIPE4: pipe_addr = REG_RX_ADDR_P4; break; case NRF24L01P_PIPE5: pipe_addr = REG_RX_ADDR_P5; break; default: return -1; } /* Acquire exclusive access to the bus. */ spi_acquire(dev->spi); gpio_clear(dev->cs); xtimer_spin(DELAY_CS_TOGGLE_TICKS); status = spi_transfer_regs(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & pipe_addr)), saddr, NULL, length); /* address width is 5 byte */ xtimer_spin(DELAY_CS_TOGGLE_TICKS); gpio_set(dev->cs); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); /* Enable this pipe */ nrf24l01p_enable_pipe(dev, pipe); return (status < 0) ? status : length; } int nrf24l01p_set_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, uint64_t saddr, unsigned int length) { char buf[length]; if (length <= INITIAL_ADDRESS_WIDTH) { for (int i = 0; i < length; i++) { buf[i] = (uint8_t)(saddr >> (((length - 1) - i) * 8)); } } else { return -1; } return nrf24l01p_set_rx_address(dev, pipe, buf, length); } uint64_t nrf24l01p_get_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe) { int status; char pipe_addr; uint64_t saddr_64 = 0; char addr_array[INITIAL_ADDRESS_WIDTH]; switch (pipe) { case NRF24L01P_PIPE0: pipe_addr = REG_RX_ADDR_P0; break; case NRF24L01P_PIPE1: pipe_addr = REG_RX_ADDR_P1; break; case NRF24L01P_PIPE2: pipe_addr = REG_RX_ADDR_P2; break; case NRF24L01P_PIPE3: pipe_addr = REG_RX_ADDR_P3; break; case NRF24L01P_PIPE4: pipe_addr = REG_RX_ADDR_P4; break; case NRF24L01P_PIPE5: pipe_addr = REG_RX_ADDR_P5; break; default: return -1; } /* Acquire exclusive access to the bus. */ spi_acquire(dev->spi); gpio_clear(dev->cs); xtimer_spin(DELAY_CS_TOGGLE_TICKS); status = spi_transfer_regs(dev->spi, (CMD_R_REGISTER | (REGISTER_MASK & pipe_addr)), 0, addr_array, INITIAL_ADDRESS_WIDTH); /* address width is 5 byte */ xtimer_spin(DELAY_CS_TOGGLE_TICKS); gpio_set(dev->cs); /* Release the bus for other threads. */ spi_release(dev->spi); if (status < 0) { return -1; } xtimer_spin(DELAY_AFTER_FUNC_TICKS); for (int i = 0; i < INITIAL_ADDRESS_WIDTH; i++) { saddr_64 |= (((uint64_t) addr_array[i]) << (8 * (INITIAL_ADDRESS_WIDTH - i - 1))); } return saddr_64; } int nrf24l01p_set_datarate(nrf24l01p_t *dev, nrf24l01p_dr_t dr) { char rf_setup; nrf24l01p_read_reg(dev, REG_RF_SETUP, &rf_setup); switch (dr) { case NRF24L01P_DR_250KBS: rf_setup |= RF_SETUP_RF_DR_LOW; rf_setup &= ~(RF_SETUP_RF_DR_HIGH); break; case NRF24L01P_DR_1MBS: rf_setup &= ~(RF_SETUP_RF_DR_LOW | RF_SETUP_RF_DR_HIGH); break; case NRF24L01P_DR_2MBS: rf_setup &= ~RF_SETUP_RF_DR_LOW; rf_setup |= RF_SETUP_RF_DR_HIGH; break; default: return -1; } return nrf24l01p_write_reg(dev, REG_RF_SETUP, rf_setup); } int nrf24l01p_get_status(nrf24l01p_t *dev) { char status; /* Acquire exclusive access to the bus. */ spi_acquire(dev->spi); gpio_clear(dev->cs); xtimer_spin(DELAY_CS_TOGGLE_TICKS); spi_transfer_byte(dev->spi, CMD_NOP, &status); xtimer_spin(DELAY_CS_TOGGLE_TICKS); gpio_set(dev->cs); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); return (int)status; } int nrf24l01p_set_power(nrf24l01p_t *dev, int pwr) { char rf_setup; nrf24l01p_read_reg(dev, REG_RF_SETUP, &rf_setup); if (pwr >= -3) { rf_setup &= ~(3 << 1); rf_setup |= (NRF24L01P_PWR_0DBM << 1); } if (pwr < -3) { rf_setup &= ~(3 << 1); rf_setup |= (NRF24L01P_PWR_N6DBM << 1); } if (pwr < -9) { rf_setup &= ~(3 << 1); rf_setup |= (NRF24L01P_PWR_N12DBM << 1); } if (pwr < -15) { rf_setup &= ~(3 << 1); } return nrf24l01p_write_reg(dev, REG_RF_SETUP, rf_setup); } int nrf24l01p_get_power(nrf24l01p_t *dev) { char rf_setup; int pwr; nrf24l01p_read_reg(dev, REG_RF_SETUP, &rf_setup); if ((rf_setup & 0x6) == 0) { pwr = -18; } if ((rf_setup & 0x6) == 2) { pwr = -12; } if ((rf_setup & 0x6) == 4) { pwr = -6; } if ((rf_setup & 0x6) == 6) { pwr = 0; } return pwr; } int nrf24l01p_set_txmode(nrf24l01p_t *dev) { char conf; int status; nrf24l01p_stop(dev); nrf24l01p_mask_interrupt(dev, (MASK_RX_DR | MASK_TX_DS | MASK_MAX_RT)); nrf24l01p_flush_tx_fifo(dev); nrf24l01p_read_reg(dev, REG_CONFIG, &conf); conf &= ~(PRIM_RX); status = nrf24l01p_write_reg(dev, REG_CONFIG, conf); xtimer_usleep(DELAY_CHANGE_TXRX_US); return status; } int nrf24l01p_set_rxmode(nrf24l01p_t *dev) { char conf; int status; nrf24l01p_unmask_interrupt(dev, MASK_RX_DR); nrf24l01p_mask_interrupt(dev, (MASK_TX_DS | MASK_MAX_RT)); nrf24l01p_flush_rx_fifo(dev); nrf24l01p_read_reg(dev, REG_CONFIG, &conf); conf |= PRIM_RX; status = nrf24l01p_write_reg(dev, REG_CONFIG, conf); nrf24l01p_start(dev); xtimer_usleep(DELAY_CHANGE_TXRX_US); return status; } int nrf24l01p_reset_interrupts(nrf24l01p_t *dev, char intrs) { return nrf24l01p_write_reg(dev, REG_STATUS, intrs); } int nrf24l01p_reset_all_interrupts(nrf24l01p_t *dev) { return nrf24l01p_write_reg(dev, REG_STATUS, ALL_INT_MASK); } int nrf24l01p_mask_interrupt(nrf24l01p_t *dev, char intr) { char conf; nrf24l01p_read_reg(dev, REG_CONFIG, &conf); conf |= intr; return nrf24l01p_write_reg(dev, REG_CONFIG, conf); } int nrf24l01p_unmask_interrupt(nrf24l01p_t *dev, char intr) { char conf; nrf24l01p_read_reg(dev, REG_CONFIG, &conf); conf &= ~intr; return nrf24l01p_write_reg(dev, REG_CONFIG, conf); } int nrf24l01p_enable_dynamic_payload(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe) { char feature_val; char en_aa_val; char dynpd_val; int pipe_mask = 0; int dpl_mask = 0; if (nrf24l01p_read_reg(dev, REG_FEATURE, &feature_val) < 0) { DEBUG("Can't read REG_FEATURE\n"); return -1; } if (!(feature_val & FEATURE_EN_DPL)){ feature_val |= FEATURE_EN_DPL; if (nrf24l01p_write_reg(dev, REG_FEATURE, feature_val) < 0){ DEBUG("Can't write REG_FEATURE\n"); return -1; } } if (nrf24l01p_read_reg(dev, REG_EN_AA, &en_aa_val) < 0){ DEBUG("Can't read REG_EN_AA\n"); return -1; } switch (pipe){ case NRF24L01P_PIPE0: pipe_mask = ENAA_P0; dpl_mask = DYNPD_DPL_P0; break; case NRF24L01P_PIPE1: pipe_mask = ENAA_P1; dpl_mask = DYNPD_DPL_P1; break; case NRF24L01P_PIPE2: pipe_mask = ENAA_P2; dpl_mask = DYNPD_DPL_P2; break; case NRF24L01P_PIPE3: pipe_mask = ENAA_P3; dpl_mask = DYNPD_DPL_P3; break; case NRF24L01P_PIPE4: pipe_mask = ENAA_P4; dpl_mask = DYNPD_DPL_P4; break; case NRF24L01P_PIPE5: pipe_mask = ENAA_P5; dpl_mask = DYNPD_DPL_P5; break; } if (!(en_aa_val & pipe_mask)){ en_aa_val |= pipe_mask; if (nrf24l01p_write_reg(dev, REG_EN_AA, en_aa_val) < 0){ DEBUG("Can't write REG_EN_AA\n"); return -1; } } if (nrf24l01p_read_reg(dev, REG_DYNPD, &dynpd_val) < 0){ DEBUG("Can't read REG_DYNPD\n"); return -1; } if (!(dynpd_val & dpl_mask)){ dynpd_val |= dpl_mask; if (nrf24l01p_write_reg(dev, REG_DYNPD, dynpd_val) < 0){ DEBUG("Can't write REG_DYNPD\n"); return -1; } } return 0; } int nrf24l01p_enable_pipe(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe) { char pipe_conf; nrf24l01p_read_reg(dev, REG_EN_RXADDR, &pipe_conf); pipe_conf |= (1 << pipe); return nrf24l01p_write_reg(dev, REG_EN_RXADDR, pipe_conf); } int nrf24l01p_disable_pipe(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe) { char pipe_conf; nrf24l01p_read_reg(dev, REG_EN_RXADDR, &pipe_conf); pipe_conf &= ~(1 << pipe); return nrf24l01p_write_reg(dev, REG_EN_RXADDR, pipe_conf); } int nrf24l01p_enable_crc(nrf24l01p_t *dev, nrf24l01p_crc_t crc) { char conf; nrf24l01p_read_reg(dev, REG_CONFIG, &conf); switch (crc) { case NRF24L01P_CRC_1BYTE: conf &= ~(CRCO); break; case NRF24L01P_CRC_2BYTE: conf |= CRCO; break; default: return -1; } return nrf24l01p_write_reg(dev, REG_CONFIG, (conf | EN_CRC)); } int nrf24l01p_setup_auto_ack(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, nrf24l01p_retransmit_delay_t delay_retrans, char count_retrans) { char en_aa; int status; nrf24l01p_read_reg(dev, REG_EN_AA, &en_aa); switch (pipe) { case NRF24L01P_PIPE0: en_aa |= (1 << 0); break; case NRF24L01P_PIPE1: en_aa |= (1 << 1); break; case NRF24L01P_PIPE2: en_aa |= (1 << 2); break; case NRF24L01P_PIPE3: en_aa |= (1 << 3); break; case NRF24L01P_PIPE4: en_aa |= (1 << 4); break; case NRF24L01P_PIPE5: en_aa |= (1 << 5); break; default: return -1; } /* Enable Auto Ack */ status = nrf24l01p_write_reg(dev, REG_EN_AA, en_aa); if (status < 0) { return status; } count_retrans = (count_retrans < 16) ? count_retrans : 15; /* setup auto retransmit delay and count */ return nrf24l01p_write_reg(dev, REG_SETUP_RETR, ((delay_retrans << 4) | count_retrans)); } int nrf24l01p_enable_dynamic_ack(nrf24l01p_t *dev) { char feature; if (nrf24l01p_read_reg(dev, REG_FEATURE, &feature) < 0){ DEBUG("Can't read FEATURE reg\n"); return -1; } if (!(feature & FEATURE_EN_DYN_ACK)){ feature |= FEATURE_EN_DYN_ACK; if (nrf24l01p_write_reg(dev, REG_FEATURE, feature) < 0){ DEBUG("Can't write FEATURE reg\n"); return -1; } } return 0; } int nrf24l01p_disable_all_auto_ack(nrf24l01p_t *dev) { return nrf24l01p_write_reg(dev, REG_EN_AA, 0x00); } int nrf24l01p_flush_tx_fifo(nrf24l01p_t *dev) { int status; char reg_content; /* Acquire exclusive access to the bus. */ spi_acquire(dev->spi); gpio_clear(dev->cs); xtimer_spin(DELAY_CS_TOGGLE_TICKS); status = spi_transfer_byte(dev->spi, CMD_FLUSH_TX, ®_content); xtimer_spin(DELAY_CS_TOGGLE_TICKS); gpio_set(dev->cs); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); return (status < 0) ? status : 0; } int nrf24l01p_flush_rx_fifo(nrf24l01p_t *dev) { int status; char reg_content; /* Acquire exclusive access to the bus. */ spi_acquire(dev->spi); gpio_clear(dev->cs); xtimer_spin(DELAY_CS_TOGGLE_TICKS); status = spi_transfer_byte(dev->spi, CMD_FLUSH_RX, ®_content); xtimer_spin(DELAY_CS_TOGGLE_TICKS); gpio_set(dev->cs); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); return (status < 0) ? status : 0; } void nrf24l01p_rx_cb(void *arg) { DEBUG("In HW cb\n"); nrf24l01p_t *dev = (nrf24l01p_t *)arg; /* clear interrupt */ nrf24l01p_reset_all_interrupts(dev); /* informs thread about available rx data*/ if (dev->listener != KERNEL_PID_UNDEF) { msg_t m; m.type = RCV_PKT_NRF24L01P; m.content.ptr = dev; /* transmit more things here ? */ msg_send_int(&m, dev->listener); } }