#pragma once #include "tiring.h" #include "softspi.h" #include "mspdebugconsole.h" enum NRFSendStatus { NRF_SENDING = 0, NRF_SUCCESS = 1, NRF_FAILURE = 2, }; template class NRF24L01 { private: enum Command { CMD_R_REGISTER = 0x00, CMD_W_REGISTER = 0x20, CMD_R_RX_PAYLOAD = 0x61, CMD_W_TX_PAYLOAD = 0xA0, CMD_FLUSH_TX = 0xE1, CMD_FLUSH_RX = 0xE2, CMD_REUSE_RX_PL = 0xE3, CMD_ACTIVATE = 0x50, CMD_R_RX_PL_WID = 0x60, CMD_W_ACK_PAYLOAD = 0xA8, CMD_WX_PAYLOAD_NOACK = 0xB0, CMD_NOP = 0xFF, }; enum Register { REG_CONFIG = 0x00, REG_EN_AA = 0x01, REG_EN_RXADDR = 0x02, REG_SETUP_AW = 0x03, REG_SETUP_RETR = 0x04, REG_RF_CH = 0x05, REG_RF_SETUP = 0x06, REG_STATUS = 0x07, REG_OBSERVE_TX = 0x08, REG_CD = 0x09, REG_RX_ADDR_P0 = 0x0A, REG_RX_ADDR_P1 = 0x0B, REG_RX_ADDR_P2 = 0x0C, REG_RX_ADDR_P3 = 0x0D, REG_RX_ADDR_P4 = 0x0E, REG_RX_ADDR_P5 = 0x0F, REG_TX_ADDR = 0x10, REG_RX_PW_P0 = 0x11, REG_RX_PW_P1 = 0x12, REG_RX_PW_P2 = 0x13, REG_RX_PW_P3 = 0x14, REG_RX_PW_P4 = 0x15, REG_RX_PW_P5 = 0x16, REG_FIFO_STATUS = 0x17, REG_DYNPD = 0x1C, REG_FEATURE = 0x1D, }; SoftSPI spi; Output ce; void command(Command cmd) { spi.enable(); status = spi.transfer(cmd); spi.disable(); } uint8_t read_reg(Register reg) { spi.enable(); status = spi.transfer(CMD_R_REGISTER | reg); uint8_t value = spi.transfer(0); spi.disable(); return value; } void write_reg(Register reg, uint8_t val) { spi.enable(); status = spi.transfer(CMD_W_REGISTER | reg); spi.transfer(val); spi.disable(); } void bis_reg(Register reg, uint8_t bits) { write_reg(reg, read_reg(reg) | bits); } void bic_reg(Register reg, uint8_t bits) { write_reg(reg, read_reg(reg) & ~bits); } void write_reg_address(Register reg, uint8_t *val) { spi.enable(); status = spi.transfer(CMD_W_REGISTER | reg); uint16_t i; for (i = 6; i > 0; i--) spi.transfer(*val++); spi.disable(); } uint8_t packet_length; uint8_t status; public: NRF24L01() : packet_length(0) { reset(); } void reset() { ce = false; command(CMD_FLUSH_TX); command(CMD_FLUSH_RX); write_reg(REG_CONFIG, 0x08 | 0x04); // EN_CRC | CRCO write_reg(REG_STATUS, 0x30); // clear all interrupts } void set_channel(uint8_t channel) { write_reg(REG_RF_CH, channel & 0x7F); } void set_packet_length(uint8_t length) { if (length > 32) length = 32; write_reg(REG_RX_PW_P1, length); packet_length = length; } void set_tx_address(const char *address) { set_tx_address((uint8_t *)address); } void set_tx_address(uint8_t *address) { write_reg_address(REG_TX_ADDR, address); write_reg_address(REG_RX_ADDR_P0, address); } void set_rx_address(const char *address) { set_rx_address((uint8_t *)address); } void set_rx_address(uint8_t *address) { write_reg_address(REG_RX_ADDR_P1, address); } // delay_us = (delay + 1) * 250us, max 15 // count = count of retries, max 15 void set_retransmit(uint8_t delay, uint8_t count) { uint8_t value = ((delay & 0xF) << 4) | (count & 0xF); write_reg(REG_SETUP_RETR, value); } void receive() { bis_reg(REG_CONFIG, 0x01); // PRIM_RX ce = true; __delay_cycles(T_MHZ * 4); } void transmit() { ce = false; bic_reg(REG_CONFIG, 0x01); // PRIM_RX } void standby() { ce = false; } void power_on() { bis_reg(REG_CONFIG, 0x02); // PWR_UP Time::sleep_ms(2); } void power_off() { bic_reg(REG_CONFIG, 0x02); // PWR_UP } bool data_ready() { command(CMD_NOP); return (status & 0x40) > 0; // RX_DR } void recv(uint8_t *buffer) { ce = false; spi.enable(); status = spi.transfer(CMD_R_RX_PAYLOAD); uint16_t i; for (i = packet_length; i > 0; i--) *buffer++ = spi.transfer(0); spi.disable(); write_reg(REG_STATUS, 0x40); // ack RX_DR ce = true; __delay_cycles(T_MHZ * 4); } void send(uint8_t *buffer) { spi.enable(); status = spi.transfer(CMD_W_TX_PAYLOAD); uint16_t i; for (i = packet_length; i > 0; i--) spi.transfer(*buffer++); spi.disable(); __delay_cycles(T_MHZ); ce = true; __delay_cycles(T_MHZ * 12); ce = false; } NRFSendStatus send_status() { command(CMD_NOP); if ((status & 0x30) == 0) return NRF_SENDING; else if (status & 0x20) return NRF_SUCCESS; else return NRF_FAILURE; } void ack_send_status() { write_reg(REG_STATUS, 0x70); // ack all interrupts } bool sending() { command(CMD_NOP); return (status & 0x30) == 0; } NRFSendStatus send_block(uint8_t *buffer) { send(buffer); NRFSendStatus result; while ((result = send_status()) == NRF_SENDING) ; ack_send_status(); if (status == NRF_FAILURE) command(CMD_FLUSH_TX); return result; } };