Skip to content

Commit

Permalink
Finish radio driver & task
Browse files Browse the repository at this point in the history
  • Loading branch information
shetaye committed Jan 11, 2025
1 parent 3a8f4a1 commit b2cf5e4
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 34 deletions.
64 changes: 61 additions & 3 deletions src/drivers/rfm9x.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
#include <string.h>

rfm9x_t rfm9x_mk(spi_inst_t *spi, uint reset_pin, uint cs_pin, uint spi_tx_pin,
uint spi_rx_pin, uint spi_clk_pin)
uint spi_rx_pin, uint spi_clk_pin, uint d0_pin, rfm9x_interrupt_func interrupt_func)
{
rfm9x_t r = {.reset_pin = reset_pin,
.spi_cs_pin = cs_pin,
.spi_tx_pin = spi_tx_pin,
.spi_rx_pin = spi_rx_pin,
.spi_clk_pin = spi_clk_pin,
.d0_pin = d0_pin,
.interrupt_func = interrupt_func,
.spi = spi,
/*
* Default values
Expand Down Expand Up @@ -583,6 +585,7 @@ uint8_t rfm9x_get_lna_boost(rfm9x_t *r)
return c;
}


void rfm9x_init(rfm9x_t *r)
{
// Setup reset line
Expand All @@ -600,7 +603,12 @@ void rfm9x_init(rfm9x_t *r)
gpio_set_function(r->spi_clk_pin, GPIO_FUNC_SPI);
gpio_set_function(r->spi_tx_pin, GPIO_FUNC_SPI);
gpio_set_function(r->spi_rx_pin, GPIO_FUNC_SPI);
gpio_set_function(17, GPIO_FUNC_SPI);
gpio_set_function(17, GPIO_FUNC_SPI); // ???

// Setup interrupt line
gpio_init(r->d0_pin);
gpio_set_dir(r->d0_pin, GPIO_IN);
gpio_pull_down(r->d0_pin);

// Initialize SPI for the RFM9X

Expand Down Expand Up @@ -675,6 +683,13 @@ void rfm9x_init(rfm9x_t *r)

rfm9x_set_lna_boost(r, 0b11);
ASSERT(rfm9x_get_lna_boost(r) == 0b11);

// Setup interrupt
if(r->interrupt_func != NULL)
{
gpio_set_irq_enabled_with_callback(r->d0_pin, GPIO_IRQ_EDGE_RISE,
true, r->interrupt_func);
}
}

/*
Expand Down Expand Up @@ -745,14 +760,57 @@ uint8_t rfm9x_rx_done(rfm9x_t *r)
}
}

uint8_t rfm9x_await_rx(rfm9x_t *r)
int rfm9x_await_rx(rfm9x_t *r)
{
rfm9x_listen(r);
while (!rfm9x_rx_done(r))
; // spin until RX done
return 1;
}

uint8_t rfm9x_packet_to_fifo(rfm9x_t *r, uint8_t *buf, uint8_t n) {
uint8_t old_mode = rfm9x_get_mode(r);
rfm9x_set_mode(r, STANDBY_MODE);

rfm9x_put8(r, _RH_RF95_REG_0D_FIFO_ADDR_PTR, 0x00);

rfm9x_put_buf(r, _RH_RF95_REG_00_FIFO, buf, n);
rfm9x_put8(r, _RH_RF95_REG_22_PAYLOAD_LENGTH, n);

rfm9x_set_mode(r, old_mode);
return 0;
}


uint8_t rfm9x_packet_from_fifo(rfm9x_t *r, uint8_t *buf) {
uint8_t n_read = 0;
uint8_t old_mode = rfm9x_get_mode(r);
rfm9x_set_mode(r, STANDBY_MODE);

// Check for CRC error
if(rfm9x_is_crc_enabled(r) && rfm9x_crc_error(r)) {
// TODO report somehow
} else {
uint8_t fifo_length = rfm9x_get8(r, _RH_RF95_REG_13_RX_NB_BYTES);
if(fifo_length > 0) {
uint8_t current_addr =
rfm9x_get8(r, _RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR);
rfm9x_put8(r, _RH_RF95_REG_0D_FIFO_ADDR_PTR, current_addr);

// read the packet
rfm9x_get_buf(r, _RH_RF95_REG_00_FIFO, buf,
fifo_length);
}
n_read = fifo_length;
}
rfm9x_set_mode(r, old_mode);
return n_read;
}

void rfm9x_clear_interrupts(rfm9x_t *r) {
rfm9x_put8(r, _RH_RF95_REG_12_IRQ_FLAGS, 0xFF);
}

uint8_t rfm9x_receive_packet(rfm9x_t *r, uint8_t node, char *buf)
{
while (1)
Expand Down
19 changes: 18 additions & 1 deletion src/drivers/rfm9x.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,19 @@ typedef enum
RX_MODE = 5,
} rfm9x_mode_t;

typedef void (*rfm9x_interrupt_func)(uint, uint32_t);

typedef struct _rfm9x
{
uint reset_pin;
uint spi_cs_pin;
uint spi_rx_pin;
uint spi_tx_pin;
uint spi_clk_pin;
uint d0_pin;

rfm9x_interrupt_func interrupt_func;

spi_inst_t *spi;
uint8_t seq; /* current sequence number */
uint32_t high_power : 1, max_power : 1, debug : 1;
Expand All @@ -36,7 +42,7 @@ typedef struct _rfm9x
* Creates an RFM9X helper struct. Uninitialized.
*/
rfm9x_t rfm9x_mk(spi_inst_t *spi, uint reset_pin, uint cs_pin, uint spi_tx_pin,
uint spi_rx_pin, uint spi_clk_pin);
uint spi_rx_pin, uint spi_clk_pin, uint d0_pin, rfm9x_interrupt_func interrupt_func);

/*
* Initializes an RFM9X radio.
Expand Down Expand Up @@ -83,6 +89,17 @@ uint8_t rfm9x_send_ack(rfm9x_t *r, char *data, uint32_t l, uint8_t destination,
uint8_t rfm9x_receive(rfm9x_t *r, char *packet, uint8_t node,
uint8_t keep_listening, uint8_t with_ack, bool blocking_wait_for_packet);


void rfm9x_listen(rfm9x_t *r);
void rfm9x_transmit(rfm9x_t *r);

uint8_t rfm9x_tx_done(rfm9x_t *r);
uint8_t rfm9x_rx_done(rfm9x_t *r);

uint8_t rfm9x_packet_to_fifo(rfm9x_t *r, uint8_t *buf, uint8_t n);
uint8_t rfm9x_packet_from_fifo(rfm9x_t *r, uint8_t *buf);
void rfm9x_clear_interrupts(rfm9x_t *r);

typedef enum
{
_RH_RF95_REG_00_FIFO = 0x00,
Expand Down
1 change: 1 addition & 0 deletions src/pins.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
#define RFM9X_RX (SPI0_RX)
#define RFM9X_RESET (21)
#define RFM9X_CS (20)
#define RFM9X_D0 (28)
1 change: 0 additions & 1 deletion src/scheduler/scheduler.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ void sched_dispatch(slate_t *slate)
task->next_dispatch =
make_timeout_time_ms(task->dispatch_period_ms);

LOG_DEBUG("sched: Dispatching task %s", task->name);
task->task_dispatch(slate);
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/slate.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ typedef struct samwise_slate
* Radio
*/
rfm9x_t radio;
uint8_t radio_node;
queue_t tx_queue;
queue_t rx_queue;
uint32_t rx_bytes;
uint32_t rx_packets;
uint32_t rx_backpressure_drops;
uint32_t rx_bad_packet_drops;
uint32_t tx_bytes;
uint32_t tx_packets;
} slate_t;
120 changes: 91 additions & 29 deletions src/state_machine/tasks/radio_task.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,90 @@
#include "slate.h"
#include "pins.h"

#include "drivers/rfm9x.h"

#include "hardware/spi.h"
#include "hardware/gpio.h"

const uint RADIO_INTERRUPT_PIN = 28;
const bool ENABLE_IRQ = true;
#include <string.h>

static slate_t* s;

int receive(rfm9x_t radio_module);

void interrupt_recieved(uint gpio, uint32_t events)
static void tx_done() {
packet_t p;
if(queue_try_remove(&s->tx_queue, &p)) {
uint8_t p_buf[p.len + 4];
p_buf[0] = p.dst;
p_buf[1] = p.src;
p_buf[2] = p.seq;
p_buf[3] = p.flags;
memcpy(p_buf + 4, &p.data[0], p.len);

rfm9x_packet_to_fifo(&s->radio, p_buf, sizeof(p_buf));
rfm9x_clear_interrupts(&s->radio);

s->tx_packets++;
s->tx_bytes += sizeof(p_buf);
} else {
// No more TX packets, switch to receive mode
rfm9x_clear_interrupts(&s->radio);
rfm9x_listen(&s->radio);
}
}

static void rx_done() {
// Copy packet into receive queue and unset interrupt
// TODO: Can we do this faster?
uint8_t p_buf[256];
packet_t p;

uint8_t n = rfm9x_packet_from_fifo(&s->radio, &p_buf[0]);
s->rx_bytes += n;

if(n > 0) {
if(n < 4) {
s->rx_bad_packet_drops++;
} else {
p.dst = p_buf[0];
p.src = p_buf[1];
p.seq = p_buf[2];
p.flags = p_buf[3];
p.len = n - 4;
memcpy(&p.data[0], p_buf + 4, n - 4);

if((p.dst == _RH_BROADCAST_ADDRESS || p.dst == s->radio_node)) {
s->rx_packets++;

if(!queue_try_add(&s->rx_queue, &p)) s->rx_backpressure_drops++;
}
}
}
rfm9x_clear_interrupts(&s->radio);
}

static void interrupt_received(uint gpio, uint32_t events)
{
LOG_INFO("Interrupt received on pin %d\n", gpio);
if (gpio == RADIO_INTERRUPT_PIN)
if (gpio == RFM9X_D0)
{
LOG_INFO("Radio interrupt received\n");
//receive(radio_module);

receive(s->radio);

if(rfm9x_tx_done(&s->radio)) tx_done();
else if(rfm9x_rx_done(&s->radio)) rx_done();
}
}

void radio_task_init(slate_t *slate)
{
s = slate;
gpio_init(RADIO_INTERRUPT_PIN);
gpio_set_dir(RADIO_INTERRUPT_PIN, GPIO_IN);
gpio_pull_down(RADIO_INTERRUPT_PIN);

slate->rx_bytes = 0;
slate->rx_packets = 0;
slate->rx_backpressure_drops = 0;
slate->rx_bad_packet_drops = 0;

slate->tx_bytes = 0;
slate->tx_packets = 0;

// transmit queue
queue_init(&slate->tx_queue, sizeof(packet_t), TX_QUEUE_SIZE);
Expand All @@ -49,39 +105,45 @@ void radio_task_init(slate_t *slate)
queue_init(&slate->rx_queue, sizeof(packet_t), RX_QUEUE_SIZE);

// create the radio here
slate->radio = rfm9x_mk(RFM9X_SPI, RFM9X_RESET, RFM9X_CS, RFM9X_TX, RFM9X_RX, RFM9X_CLK);
slate->radio = rfm9x_mk(
RFM9X_SPI,
RFM9X_RESET,
RFM9X_CS,
RFM9X_TX,
RFM9X_RX,
RFM9X_CLK,
RFM9X_D0,
&interrupt_received
);

// initialize the radio here
rfm9x_init(&slate->radio);

gpio_set_irq_enabled_with_callback(RADIO_INTERRUPT_PIN, GPIO_IRQ_EDGE_RISE,
ENABLE_IRQ, &interrupt_recieved);
// Switch to receive mode
rfm9x_listen(&slate->radio);

LOG_INFO("Brought up RFM9X v%d", rfm9x_version(&slate->radio));
}


// When it sees something in the transmit queue, switches into recieve mode and
// When it sees something in the transmit queue, switches into transmit mode and
// send a packet. Otherwise, be in recieve mode. When it recieves a packet, it
// inturrupts the CPU to immediately recieve.
void radio_task_dispatch(slate_t *slate)
{

}

// screen /dev/tty.usbmodem1101
int receive(rfm9x_t radio_module)
{
char data[256];
uint8_t n = rfm9x_receive(&radio_module, &data[0], 1, 0, 0, 1);
printf("Received %d\n", n);

bool interruptPin = gpio_get(RADIO_INTERRUPT_PIN);
printf("Interrupt pin: %d\n", interruptPin);
// Switch to transmit mode if queue is not empty
if(!queue_is_empty(&slate->tx_queue)) {
rfm9x_transmit(&slate->radio);
// Since the interrupt only fires when done transmitting the last packet, we need
// to get it started manually
tx_done();
} else {
rfm9x_receive(&slate->radio);
}
}

sched_task_t radio_task = {.name = "radio",
.dispatch_period_ms = 1000,
.dispatch_period_ms = 100,
.task_init = &radio_task_init,
.task_dispatch = &radio_task_dispatch,

Expand Down

0 comments on commit b2cf5e4

Please sign in to comment.