@@ 0,0 1,427 @@
+#include <debugio.h>
+#include <string.h>
+#include <ctl_api.h>
+#include <ctl_spi.h>
+#include <stdbool.h>
+#include <sam.h>
+
+#include "d2x_gpio.h"
+#include "d2x_eic.h"
+#include "d2x_common.h"
+
+#include "nrf24.h"
+
+#define RF24_CONFIG_ADDR 0x00
+#define RF24_EN_RXADDR 0x02
+#define RF24_SETUP_ADDR_LEN_ADDR 0x03
+#define RF24_RF_CH_ADDR 0x05
+#define RF24_STATUS_ADDR 0x07
+#define RF24_RX_ADDR_P0_ADDR 0x0A // location of pipe 0 rx address
+#define RF24_RX_ADDR_P1_ADDR 0x0B // location of pipe 1 rx address
+#define RF24_RX_PW_P0_ADDR 0x11 // Payload len of (rx) pipe 0
+
+
+
+#define RF24_TX_ADDR_ADDR 0x10 // location of tx address
+
+#define RF24_R_REGISTER 0x00
+#define RF24_W_REGISTER 0x20
+#define RF24_REGISTER_MASK 0x1F
+#define RF24_ACTIVATE 0x50
+#define R_RX_PL_WID 0x60
+#define R_RX_PAYLOAD 0x61
+#define W_TX_PAYLOAD 0xA0
+#define W_ACK_PAYLOAD 0xA8
+#define FLUSH_TX 0xE1
+#define FLUSH_RX 0xE2
+#define REUSE_TX_PL 0xE3
+#define RF24_NOP 0xFF
+
+#define MAX_PIPE_AMOUNT 6 // pipes 0..5
+
+// -- config register --
+#define MASK_RX_DR (1 << 6)
+#define MASK_TX_DS (1 << 5)
+#define MASK_MAX_RT (1 << 4)
+#define EN_CRC (1 << 3)
+#define CRC0 (1 << 2)
+#define PWR_UP (1 << 1)
+#define PRIM_RX (1 << 0)
+
+#define RF24_SERCOM 0
+
+const struct rf24_settings rf24_defaults =
+ {
+ .data_received_interrupt = false,
+ .data_sent_interrupt = false,
+ .max_retransmission_interrupt = false,
+ .enable_crc = true,
+ .use_2_bit_crc = false,
+ .power_up = false,
+ .rx_mode = false
+ };
+
+static CTL_SPI_DEVICE_t nrf24_device;
+
+static uint8_t rf24_addr_len = 0;
+
+static void rf24_cs(bool state)
+{
+ gpio_set_state(D2X_PORT_A, 5, state);
+}
+
+void rf24_select(struct CTL_SPI_DEVICE_s *self, int state)
+{
+ gpio_set_state(D2X_PORT_A, 5, state);
+}
+
+static void rf24_ce(bool state)
+{
+ gpio_set_state(D2X_PORT_A, 17, state);
+}
+
+uint8_t rf24_read_register_array(uint8_t reg, uint8_t *buf, uint32_t len)
+{
+ CTL_STATUS_t transfer_status, read_status;
+ uint32_t i;
+ uint8_t data;
+ uint8_t command = RF24_R_REGISTER | ( RF24_REGISTER_MASK & reg );
+
+ ctl_spi_select_device(&nrf24_device);
+ transfer_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+ if (transfer_status != CTL_NO_ERROR) {
+ debug_printf("read_register_array, transfer error: %d\n", transfer_status);
+ }
+
+ read_status = ctl_spi_read(&nrf24_device, buf, len);
+ if (read_status != CTL_NO_ERROR) {
+ debug_printf("read_register_array, read error: %d\n", read_status);
+ }
+
+ ctl_spi_deselect_device(&nrf24_device);
+
+ return transfer_status;
+}
+
+uint8_t rf24_read_register(uint8_t reg)
+{
+ CTL_STATUS_t transfer_status, read_status;
+ uint32_t i;
+ uint8_t data;
+ uint8_t command = RF24_R_REGISTER | ( RF24_REGISTER_MASK & reg );
+
+ ctl_spi_select_device(&nrf24_device);
+ transfer_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+ if (transfer_status != CTL_NO_ERROR) {
+ debug_printf("read_register, transfer error: %d\n", transfer_status);
+ }
+
+ command = 0xFF;
+ read_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+ if (read_status != CTL_NO_ERROR) {
+ debug_printf("rf24_read_register, read error: %d\n", read_status);
+ }
+ ctl_spi_deselect_device(&nrf24_device);
+
+ return data;
+
+}
+
+uint8_t rf24_write_register_array(uint8_t reg, const uint8_t *buf, uint32_t len)
+{
+ CTL_STATUS_t transfer_status, send_status;
+ uint32_t i;
+ uint8_t data;
+ uint8_t command = RF24_R_REGISTER | ( RF24_REGISTER_MASK & reg );
+
+ ctl_spi_select_device(&nrf24_device);
+ transfer_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+ if (transfer_status != CTL_NO_ERROR) {
+ debug_printf("write_register_array, transfer error: %d\n", transfer_status);
+ }
+
+ send_status = ctl_spi_write(&nrf24_device, buf, len);
+ if (send_status != CTL_NO_ERROR) {
+ debug_printf("write_register_array, send error: %d\n", send_status);
+ }
+ ctl_spi_deselect_device(&nrf24_device);
+
+ return data;
+
+}
+
+uint8_t rf24_write_register(uint8_t reg, uint8_t val)
+{
+ int transfer_status, write_status;
+ uint32_t i;
+ uint8_t data;
+ uint8_t command = RF24_R_REGISTER | ( RF24_REGISTER_MASK & reg );
+
+
+ ctl_spi_select_device(&nrf24_device);
+ transfer_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+ if (transfer_status != CTL_NO_ERROR) {
+ debug_printf("write_register, transfer error: %d\n", transfer_status);
+ }
+
+ command = val;
+ write_status = ctl_spi_write(&nrf24_device, &command, 1);
+ if (write_status != CTL_NO_ERROR) {
+ debug_printf("write_register, write error: %d\n", write_status);
+ }
+
+ ctl_spi_deselect_device(&nrf24_device);
+ debug_printf("rf24_write_register ok\n");
+
+ return data;
+}
+
+uint8_t rf24_status(void)
+{
+ CTL_STATUS_t spi_status;
+ uint8_t rf_status;
+ uint8_t command = RF24_NOP;
+
+ ctl_spi_select_device(&nrf24_device);
+ spi_status = ctl_spi_exchange(&nrf24_device, &command, &rf_status, 1);
+ ctl_spi_deselect_device(&nrf24_device);
+
+ if (spi_status != CTL_NO_ERROR) {
+ debug_printf("ERROR: spi_transfer(NOP) failed\n");
+ return 0xFF;
+ }
+
+ return rf_status;
+}
+
+void rf24_set_channel(uint8_t ch)
+{
+ uint8_t s;
+ (void)rf24_write_register(RF24_RF_CH_ADDR, ch);
+ /* ignore return value */
+}
+
+void rf24_set_address_len(uint8_t addr_len)
+{
+ uint8_t len = addr_len;
+ if (len < 3) {
+ debug_printf("WARNING: Len %d too small, setting it to 3\n", len);
+ len = 3;
+ } else if (len > 5) {
+ debug_printf("WARNING: Len %d too big, setting it to 5\n", len);
+ len = 5;
+ }
+ (void)rf24_write_register(RF24_SETUP_ADDR_LEN_ADDR, len);
+ rf24_addr_len = len;
+}
+
+void rf24_set_rx_addr(uint8_t pipe_no, const uint8_t *addr, uint8_t addr_len)
+{
+ if (addr_len != rf24_addr_len) {
+ rf24_set_address_len(addr_len);
+ }
+
+ if (pipe_no > 1) {
+ debug_printf("ERROR: rf24_set_rx_addr: pipe number %d too big, doing nothing\n", pipe_no);
+ return;
+ }
+
+ if (addr == NULL) {
+ debug_printf("ERROR: rf24_set_rx_addr: addr NULL!\n");
+ return;
+ }
+
+ if (pipe_no == 0) {
+ (void)rf24_write_register_array(RF24_RX_ADDR_P0_ADDR, addr, rf24_addr_len);
+ } else {
+ (void)rf24_write_register_array(RF24_RX_ADDR_P1_ADDR, addr, rf24_addr_len);
+ }
+}
+
+void rf24_set_rx_payload_len(uint8_t pipe_no, uint8_t payload_len)
+{
+ uint8_t len = payload_len;
+
+ if (pipe_no >= MAX_PIPE_AMOUNT) {
+ debug_printf("ERROR: rf24_set_rx_payload_len: invalid pipe number %d\n", pipe_no);
+ return;
+ }
+
+ if (len > 32) {
+ len = 32;
+ }
+
+ (void)rf24_write_register(RF24_RX_PW_P0_ADDR + pipe_no, len);
+}
+
+int rf24_get_rx_payload_len(uint8_t pipe_no, uint8_t* payload_len)
+{
+ if (pipe_no >= MAX_PIPE_AMOUNT) {
+ debug_printf("ERROR: rf24_get_rx_payload_len: invalid pipe number %d\n", pipe_no);
+ return -1;
+ }
+ if (payload_len == NULL) {
+ debug_printf("ERROR: rf24_get_rx_payload_len: pointer NULL\n");
+ return -1;
+ }
+
+ *payload_len = rf24_read_register(RF24_RX_PW_P0_ADDR + pipe_no) & 0b00011111;
+
+ return 0;
+}
+
+int rf24_get_rx_payload(char *payload, uint8_t payload_max_len, uint8_t *len)
+{
+ CTL_STATUS_t transfer_status, read_status;
+ uint8_t data, command;
+ uint8_t payload_len = payload_max_len;
+
+ if (payload_len > 32) {
+ payload_len = 32;
+ }
+
+ command = R_RX_PAYLOAD;
+ ctl_spi_select_device(&nrf24_device);
+ transfer_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+
+ if (transfer_status != CTL_NO_ERROR) {
+ debug_printf("rf24_get_rx_payload, transfer error: %d\n", transfer_status);
+ return RF24_ERROR;
+ }
+
+ read_status = ctl_spi_read(&nrf24_device, payload, payload_len);
+ if (read_status != CTL_NO_ERROR) {
+ debug_printf("rf24_get_rx_payload, read error: %d\n", read_status);
+ return RF24_ERROR;
+ }
+ ctl_spi_deselect_device(&nrf24_device);
+
+ *len = payload_len;
+
+ return RF24_OK;
+}
+
+int rf24_set_tx_payload(const char *payload, uint8_t payload_len)
+{
+ CTL_STATUS_t transfer_status, send_status;
+ uint8_t data, command;
+
+ if (payload_len > 32) {
+ payload_len = 32;
+ }
+
+ command = W_TX_PAYLOAD;
+
+ ctl_spi_select_device(&nrf24_device);
+ transfer_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+ if (transfer_status != CTL_NO_ERROR) {
+ debug_printf("rf24_set_tx_payload, transfer error: %d\n", transfer_status);
+ rf24_cs(false);
+ return RF24_ERROR;
+ }
+
+ send_status = ctl_spi_write(&nrf24_device, payload, payload_len);
+ ctl_spi_deselect_device(&nrf24_device);
+
+ if (send_status != CTL_NO_ERROR) {
+ debug_printf("rf24_set_tx_payload, send error: %d\n", send_status);
+ return RF24_ERROR;
+ }
+
+ return RF24_OK;
+}
+
+void rf24_enable_pipes(uint8_t pipe_mask)
+{
+ (void)rf24_write_register(RF24_EN_RXADDR, pipe_mask & 0b00111111);
+}
+
+void rf24_set_tx_addr(const uint8_t *addr, uint8_t addr_len)
+{
+ if (addr_len != rf24_addr_len) {
+ rf24_set_address_len(addr_len);
+ }
+
+ (void)rf24_write_register_array(RF24_TX_ADDR_ADDR, addr, rf24_addr_len);
+}
+
+void rf24_get_config(struct rf24_settings* config)
+{
+ uint8_t conf;
+
+ conf = rf24_read_register(RF24_CONFIG_ADDR);
+
+ config->data_received_interrupt = (conf & MASK_RX_DR) == MASK_RX_DR;
+ config->data_sent_interrupt = (conf & MASK_TX_DS) == MASK_TX_DS;
+ config->max_retransmission_interrupt = (conf & MASK_MAX_RT) == MASK_MAX_RT;
+ config->enable_crc = (conf & EN_CRC) == EN_CRC;
+ config->use_2_bit_crc = (conf & CRC0) == CRC0;
+ config->power_up = (conf & PWR_UP) == PWR_UP;
+ config->rx_mode = (conf & PRIM_RX) == PRIM_RX;
+}
+
+void rf24_set_config(const struct rf24_settings *config)
+{
+ uint8_t conf;
+
+ if (config->data_received_interrupt) conf |= MASK_RX_DR;
+ if (config->data_sent_interrupt) conf |= MASK_TX_DS;
+ if (config->max_retransmission_interrupt) conf |= MASK_MAX_RT;
+ if (config->enable_crc) conf |= EN_CRC;
+ if (config->use_2_bit_crc) conf |= CRC0;
+ if (config->power_up) conf |= PWR_UP;
+ if (config->rx_mode) conf |= PRIM_RX;
+
+ (void)rf24_write_register(RF24_CONFIG_ADDR, conf);
+}
+
+void rf24_send_payload(void)
+{
+ rf24_ce(true);
+ ctl_timeout_wait(ctl_get_current_time() + ctl_get_ticks_per_second()/333); // ~3ms
+ rf24_ce(false);
+}
+
+void rf24_init(const struct rf24_settings *config, CTL_SPI_BUS_t *spi_bus)
+{
+ int status;
+ uint8_t s;
+ uint8_t addr[5] = { 0 };
+
+ rf24_addr_len = 5;
+
+
+ ctl_spi_attach_device(spi_bus, &nrf24_device);
+ nrf24_device.select = rf24_select;
+ ctl_spi_set_protocol(&nrf24_device, CTL_SPI_MODE0, 8, 100000, 0xFF);
+
+ // status = spi_enable(0, SPI_EDGE_FIRST_RISING);
+
+ // debug_printf("spi_enable: %d\n", status);
+
+ /* CE pin as output */
+ status = gpio_set_output(D2X_PORT_A, 17);
+ status = gpio_set_output(D2X_PORT_A, 5);
+
+ rf24_ce(false);
+ rf24_cs(false);
+
+ ctl_sleep(10);
+
+ rf24_set_config(config);
+ if (config->rx_mode) {
+ debug_printf("RX mode\n");
+ } else {
+ debug_printf("TX mode\n");
+ }
+
+ s = rf24_read_register_array(0x0A, addr, 5);
+ debug_printf("rf24 default address: %02x %02x %02x %02x %02x\n", addr[0], addr[1], addr[2], addr[3], addr[4]);
+
+ s = rf24_write_register(0x05, 76);
+ debug_printf("channel write status: %d\n", s);
+
+ s = rf24_read_register(0x05);
+ debug_printf("rf24 channel: %d\n", s);
+}
+