Загрузить исходник nrf24.c

/*
* ----------------------------------------------------------------------------
* “THE COFFEEWARE LICENSE” (Revision 1):
* <[email protected]> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a coffee in return.
* -----------------------------------------------------------------------------
* This library is based on this library: 
*   https://github.com/aaronds/arduino-nrf24l01
* Which is based on this library: 
*   http://www.tinkerer.eu/AVRLib/nRF24L01
* -----------------------------------------------------------------------------
*/
#include "nrf24.h"

uint8_t payload_len;

void nrf24_setupPins() {
    nrf24_set_bit(NRF24_IO_DDR, NRF24_CE_PIN); // CE output
    nrf24_set_bit(NRF24_IO_DDR, NRF24_CSN_PIN); // CSN output
    nrf24_set_bit(NRF24_IO_DDR, NRF24_SCK_PIN); // SCK output
    nrf24_set_bit(NRF24_IO_DDR, NRF24_MOSI_PIN); // MOSI output
    nrf24_clr_bit(NRF24_IO_DDR, NRF24_MISO_PIN); // MISO input
}

void nrf24_ce_digitalWrite(uint8_t state) {
    if (state) {
        nrf24_set_bit(NRF24_IO_PORT, NRF24_CE_PIN);
    }
    else {
        nrf24_clr_bit(NRF24_IO_PORT, NRF24_CE_PIN);
    }
}

void nrf24_csn_digitalWrite(uint8_t state) {
    if (state) {
        nrf24_set_bit(NRF24_IO_PORT, NRF24_CSN_PIN);
    }
    else {
        nrf24_clr_bit(NRF24_IO_PORT, NRF24_CSN_PIN);
    }
}


void nrf24_sck_digitalWrite(uint8_t state) {
    if (state) {
        nrf24_set_bit(NRF24_IO_PORT, NRF24_SCK_PIN);
    }
    else {
        nrf24_clr_bit(NRF24_IO_PORT, NRF24_SCK_PIN);
    }
}

void nrf24_mosi_digitalWrite(uint8_t state) {
    if (state) {
        nrf24_set_bit(NRF24_IO_PORT, NRF24_MOSI_PIN);
    }
    else {
        nrf24_clr_bit(NRF24_IO_PORT, NRF24_MOSI_PIN);
    }
}

uint8_t nrf24_miso_digitalRead() {
    return nrf24_check_bit(NRF24_IO_PINREG, NRF24_MISO_PIN);
}


/* init the hardware pins */
void nrf24_init() {
    nrf24_setupPins();
    nrf24_ce_digitalWrite(LOW);
    nrf24_csn_digitalWrite(HIGH);
}

/* configure the module */
void nrf24_config(uint8_t channel, uint8_t pay_length) {
    /* Use static payload length ... */
    payload_len = pay_length;

    // Set RF channel
    nrf24_configRegister(RF_CH, channel);

    // Set length of incoming payload 
    nrf24_configRegister(RX_PW_P0, 0x00); // Auto-ACK pipe ...
    nrf24_configRegister(RX_PW_P1, payload_len); // Data payload pipe
    nrf24_configRegister(RX_PW_P2, 0x00); // Pipe not used 
    nrf24_configRegister(RX_PW_P3, 0x00); // Pipe not used 
    nrf24_configRegister(RX_PW_P4, 0x00); // Pipe not used 
    nrf24_configRegister(RX_PW_P5, 0x00); // Pipe not used 

    // 1 Mbps, TX gain: 0dbm
    nrf24_configRegister(RF_SETUP, (0 << RF_DR) | ((0x03) << RF_PWR));

    // CRC enable, 1 byte CRC length
    nrf24_configRegister(CONFIG, nrf24_CONFIG);

    // Auto Acknowledgment
    nrf24_configRegister(EN_AA, (1 << ENAA_P0) | (1 << ENAA_P1) | (0 << ENAA_P2) | (0 << ENAA_P3) | (0 << ENAA_P4) |
                                (0 << ENAA_P5));

    // Enable RX addresses
    nrf24_configRegister(EN_RXADDR,
                         (1 << ERX_P0) | (1 << ERX_P1) | (0 << ERX_P2) | (0 << ERX_P3) | (0 << ERX_P4) | (0 << ERX_P5));

    // Auto retransmit delay: 1000 us and Up to 15 retransmit trials
    nrf24_configRegister(SETUP_RETR, (0x04 << ARD) | (0x0F << ARC));

    // Dynamic length configurations: No dynamic length
    nrf24_configRegister(DYNPD,
                         (0 << DPL_P0) | (0 << DPL_P1) | (0 << DPL_P2) | (0 << DPL_P3) | (0 << DPL_P4) | (0 << DPL_P5));

    // Start listening
    nrf24_powerUpRx();
}

/* Set the RX address */
void nrf24_rx_address(uint8_t *adr) {
    nrf24_ce_digitalWrite(LOW);
    nrf24_writeRegister(RX_ADDR_P1, adr, nrf24_ADDR_LEN);
    nrf24_ce_digitalWrite(HIGH);
}

/* Returns the payload length */
uint8_t nrf24_payload_length() {
    return payload_len;
}

/* Set the TX address */
void nrf24_tx_address(uint8_t *adr) {
    /* RX_ADDR_P0 must be set to the sending addr for auto ack to work. */
    nrf24_writeRegister(RX_ADDR_P0, adr, nrf24_ADDR_LEN);
    nrf24_writeRegister(TX_ADDR, adr, nrf24_ADDR_LEN);
}

/* Checks if data is available for reading */
/* Returns 1 if data is ready ... */
uint8_t nrf24_dataReady() {
    // See note in getData() function - just checking RX_DR isn't good enough
    uint8_t status = nrf24_getStatus();

    // We can short circuit on RX_DR, but if it's not set, we still need
    // to check the FIFO for any pending packets
    if (status & (1 << RX_DR)) {
        return 1;
    }

    return !nrf24_rxFifoEmpty();;
}

/* Checks if receive FIFO is empty or not */
uint8_t nrf24_rxFifoEmpty() {
    uint8_t fifoStatus;

    nrf24_readRegister(FIFO_STATUS, &fifoStatus, 1);

    return (fifoStatus & (1 << RX_EMPTY));
}

/* Returns the length of data waiting in the RX fifo */
uint8_t nrf24_payloadLength() {
    uint8_t status;
    nrf24_csn_digitalWrite(LOW);
    spi_transfer(R_RX_PL_WID);
    status = spi_transfer(0x00);
    return status;
}

/* Reads payload bytes into data array */
void nrf24_getData(uint8_t *data) {
    /* Pull down chip select */
    nrf24_csn_digitalWrite(LOW);

    /* Send cmd to read rx payload */
    spi_transfer(R_RX_PAYLOAD);

    /* Read payload */
    nrf24_transferSync(data, data, payload_len);

    /* Pull up chip select */
    nrf24_csn_digitalWrite(HIGH);

    /* Reset status register */
    nrf24_configRegister(STATUS, (1 << RX_DR));
}

/* Returns the number of retransmissions occured for the last message */
uint8_t nrf24_retransmissionCount() {
    uint8_t rv;
    nrf24_readRegister(OBSERVE_TX, &rv, 1);
    rv = rv & 0x0F;
    return rv;
}

// Sends a data package to the default address. Be sure to send the correct
// amount of bytes as configured as payload on the receiver.
void nrf24_send(uint8_t *value) {
    /* Go to Standby-I first */
    nrf24_ce_digitalWrite(LOW);

    /* Set to transmitter mode , Power up if needed */
    nrf24_powerUpTx();

    /* Do we really need to flush TX fifo each time ? */
#if 1
    /* Pull down chip select */
    nrf24_csn_digitalWrite(LOW);

    /* Write cmd to flush transmit FIFO */
    spi_transfer(FLUSH_TX);

    /* Pull up chip select */
    nrf24_csn_digitalWrite(HIGH);
#endif

    /* Pull down chip select */
    nrf24_csn_digitalWrite(LOW);

    /* Write cmd to write payload */
    spi_transfer(W_TX_PAYLOAD);

    /* Write payload */
    nrf24_transmitSync(value, payload_len);

    /* Pull up chip select */
    nrf24_csn_digitalWrite(HIGH);

    /* Start the transmission */
    nrf24_ce_digitalWrite(HIGH);
}

uint8_t nrf24_isSending() {
    uint8_t status;

    /* read the current status */
    status = nrf24_getStatus();

    /* if sending successful (TX_DS) or max retries exceded (MAX_RT). */
    if ((status & ((1 << TX_DS) | (1 << MAX_RT)))) {
        return 0; /* false */
    }

    return 1; /* true */

}

uint8_t nrf24_getStatus() {
    uint8_t rv;
    nrf24_csn_digitalWrite(LOW);
    rv = spi_transfer(NOP);
    nrf24_csn_digitalWrite(HIGH);
    return rv;
}

uint8_t nrf24_lastMessageStatus() {
    uint8_t rv;

    rv = nrf24_getStatus();

    /* Transmission went OK */
    if ((rv & ((1 << TX_DS)))) {
        return NRF24_TRANSMISSON_OK;
    }
        /* Maximum retransmission count is reached */
        /* Last message probably went missing ... */
    else if ((rv & ((1 << MAX_RT)))) {
        return NRF24_MESSAGE_LOST;
    }
        /* Probably still sending ... */
    else {
        return 0xFF;
    }
}

void nrf24_powerUpRx() {
    nrf24_csn_digitalWrite(LOW);
    spi_transfer(FLUSH_RX);
    nrf24_csn_digitalWrite(HIGH);

    nrf24_configRegister(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT));

    nrf24_ce_digitalWrite(LOW);
    nrf24_configRegister(CONFIG, nrf24_CONFIG | ((1 << PWR_UP) | (1 << PRIM_RX)));
    nrf24_ce_digitalWrite(HIGH);
}

void nrf24_powerUpTx() {
    nrf24_configRegister(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT));

    nrf24_configRegister(CONFIG, nrf24_CONFIG | ((1 << PWR_UP) | (0 << PRIM_RX)));
}

void nrf24_powerDown() {
    nrf24_ce_digitalWrite(LOW);
    nrf24_configRegister(CONFIG, nrf24_CONFIG);
}

/* software spi routine */
uint8_t spi_transfer(uint8_t tx) {
    uint8_t i = 0;
    uint8_t rx = 0;

    nrf24_sck_digitalWrite(LOW);

    for (i = 0; i < 8; i++) {

        if (tx & (1 << (7 - i))) {
            nrf24_mosi_digitalWrite(HIGH);
        }
        else {
            nrf24_mosi_digitalWrite(LOW);
        }

        nrf24_sck_digitalWrite(HIGH);

        rx = rx << 1;
        if (nrf24_miso_digitalRead()) {
            rx |= 0x01;
        }

        nrf24_sck_digitalWrite(LOW);

    }

    return rx;
}

/* send and receive multiple bytes over SPI */
void nrf24_transferSync(uint8_t *dataout, uint8_t *datain, uint8_t len) {
    uint8_t i;

    for (i = 0; i < len; i++) {
        datain[i] = spi_transfer(dataout[i]);
    }

}

/* send multiple bytes over SPI */
void nrf24_transmitSync(uint8_t *dataout, uint8_t len) {
    uint8_t i;

    for (i = 0; i < len; i++) {
        spi_transfer(dataout[i]);
    }

}

/* Clocks only one byte into the given nrf24 register */
void nrf24_configRegister(uint8_t reg, uint8_t value) {
    nrf24_csn_digitalWrite(LOW);
    spi_transfer(W_REGISTER | (REGISTER_MASK & reg));
    spi_transfer(value);
    nrf24_csn_digitalWrite(HIGH);
}

/* Read single register from nrf24 */
void nrf24_readRegister(uint8_t reg, uint8_t *value, uint8_t len) {
    nrf24_csn_digitalWrite(LOW);
    spi_transfer(R_REGISTER | (REGISTER_MASK & reg));
    nrf24_transferSync(value, value, len);
    nrf24_csn_digitalWrite(HIGH);
}

/* Write to a single register of nrf24 */
void nrf24_writeRegister(uint8_t reg, uint8_t *value, uint8_t len) {
    nrf24_csn_digitalWrite(LOW);
    spi_transfer(W_REGISTER | (REGISTER_MASK & reg));
    nrf24_transmitSync(value, len);
    nrf24_csn_digitalWrite(HIGH);
}