Proof of concept for a radio transmitter
This commit is contained in:
parent
3ec18f464e
commit
576ad4089e
|
@ -14,6 +14,7 @@ You should have received a copy of the GNU General Public License along with Lum
|
||||||
#include <display.h>
|
#include <display.h>
|
||||||
#include <util/delay.h>
|
#include <util/delay.h>
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#define ENABLE _BV(5)
|
#define ENABLE _BV(5)
|
||||||
#define CHARCODE _BV(4)
|
#define CHARCODE _BV(4)
|
||||||
|
@ -111,3 +112,15 @@ void display_write_message(display_t *disp, const char *msg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void display_write_bit_pattern(display_t *disp, const uint8_t pattern) {
|
||||||
|
char msg[16];
|
||||||
|
sprintf(msg, "* ");
|
||||||
|
for (int i = 7; i >= 0; i--) {
|
||||||
|
if (pattern & _BV(i)) {
|
||||||
|
display_write_message(disp, "1");
|
||||||
|
} else {
|
||||||
|
display_write_message(disp, "0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ Lumeto. If not, see <https://www.gnu.org/licenses/>.
|
||||||
#define __DISPLAY_H__
|
#define __DISPLAY_H__
|
||||||
|
|
||||||
#include <shift_register.h>
|
#include <shift_register.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
typedef struct DISPLAY {
|
typedef struct DISPLAY {
|
||||||
shift_register_t reg;
|
shift_register_t reg;
|
||||||
|
@ -64,5 +65,7 @@ void display_set_location(display_t *, size_t, size_t);
|
||||||
|
|
||||||
void display_write_message(display_t *, const char *);
|
void display_write_message(display_t *, const char *);
|
||||||
|
|
||||||
|
void display_write_bit_pattern(display_t *, const uint8_t);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
13
flake.nix
13
flake.nix
|
@ -37,16 +37,16 @@
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
packages."x86_64-linux"."morse-tx" =
|
packages."x86_64-linux"."prime-tx" =
|
||||||
let
|
let
|
||||||
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
||||||
lib = pkgs.lib;
|
lib = pkgs.lib;
|
||||||
avr = pkgs.pkgsCross.avr.buildPackages;
|
avr = pkgs.pkgsCross.avr.buildPackages;
|
||||||
in pkgs.stdenv.mkDerivation rec {
|
in pkgs.stdenv.mkDerivation rec {
|
||||||
name = "morse-tx";
|
name = "prime-tx";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
|
|
||||||
includes = [ "base" "spi" "morse" "rfm69hcw" ];
|
includes = [ "base" "spi" "shift_register" "rfm69hcw" "display" ];
|
||||||
|
|
||||||
MCU = "atmega32u4";
|
MCU = "atmega32u4";
|
||||||
CHIP_SELECT = "AVR_ATmega32u4";
|
CHIP_SELECT = "AVR_ATmega32u4";
|
||||||
|
@ -57,9 +57,10 @@
|
||||||
buildPhase = ''
|
buildPhase = ''
|
||||||
${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o rfm.o -c ${src}/rfm69hcw/rfm.c
|
${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o rfm.o -c ${src}/rfm69hcw/rfm.c
|
||||||
${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o spi.o -c ${src}/spi/spi.c
|
${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o spi.o -c ${src}/spi/spi.c
|
||||||
${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o morse.o -c ${src}/morse/morse.c
|
${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o reg.o -c ${src}/shift_register/shift_register.c
|
||||||
${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o main.o -c ${src}/morse_tx/main.c
|
${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o display.o -c ${src}/display/display.c
|
||||||
${avr.gcc}/bin/avr-gcc ${CFLAGS} -o main.elf main.o morse.o spi.o rfm.o
|
${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o main.o -c ${src}/prime-tx/main.c
|
||||||
|
${avr.gcc}/bin/avr-gcc ${CFLAGS} -o main.elf main.o display.o spi.o rfm.o reg.o
|
||||||
$OBJCOPY -O ihex main.elf main.hex
|
$OBJCOPY -O ihex main.elf main.hex
|
||||||
'';
|
'';
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
|
|
139
morse_tx/main.c
139
morse_tx/main.c
|
@ -1,139 +0,0 @@
|
||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include <base.h>
|
|
||||||
#include <spi.h>
|
|
||||||
#include <rfm.h>
|
|
||||||
|
|
||||||
// typedef struct RFM {
|
|
||||||
// spi_t spi;
|
|
||||||
// gpio_t irq;
|
|
||||||
// gpio_t reset;
|
|
||||||
// } rfm_t;
|
|
||||||
//
|
|
||||||
// void rfm_initialize(rfm_t *rfm) {
|
|
||||||
// spi_initialize(&rfm->spi);
|
|
||||||
//
|
|
||||||
// spi_acquire(&rfm->spi);
|
|
||||||
// spi_transfer_byte(&rfm->spi, 0x37 | _BV(7));
|
|
||||||
// spi_transfer_byte(&rfm->spi, 0);
|
|
||||||
// spi_release(&rfm->spi);
|
|
||||||
//
|
|
||||||
// spi_acquire(&rfm->spi);
|
|
||||||
// spi_transfer_byte(&rfm->spi, 0x38 | _BV(7));
|
|
||||||
// spi_transfer_byte(&rfm->spi, 1);
|
|
||||||
// spi_release(&rfm->spi);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// void rfm_power_off(rfm_t *rfm) {
|
|
||||||
// spi_acquire(&rfm->spi);
|
|
||||||
// spi_transfer_byte(&rfm->spi, 0x11);
|
|
||||||
// spi_transfer_byte(&rfm->spi, 0x00);
|
|
||||||
// spi_release(&rfm->spi);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// void rfm_send_data(rfm_t *rfm, uint8_t *data, size_t length) {
|
|
||||||
// /* Go into standby mode */
|
|
||||||
// spi_acquire(&rfm->spi);
|
|
||||||
// spi_transfer_byte(&rfm->spi, 0x11);
|
|
||||||
// spi_transfer_byte(&rfm->spi, 0x01);
|
|
||||||
// spi_release(&rfm->spi);
|
|
||||||
//
|
|
||||||
// /* Write data to FIFO */
|
|
||||||
// spi_acquire(&rfm->spi);
|
|
||||||
// spi_transfer_byte(&rfm->spi, 0x10);
|
|
||||||
// for (size_t i = 0; i < length; i++) {
|
|
||||||
// spi_transfer_byte(&rfm->spi, data[i]);
|
|
||||||
// }
|
|
||||||
// spi_release(&rfm->spi);
|
|
||||||
//
|
|
||||||
// /* Go into transmit mode */
|
|
||||||
// spi_acquire(&rfm->spi);
|
|
||||||
// spi_transfer_byte(&rfm->spi, 0x11);
|
|
||||||
// spi_transfer_byte(&rfm->spi, 0x03);
|
|
||||||
// spi_release(&rfm->spi);
|
|
||||||
//
|
|
||||||
// /* Return to standby mode */
|
|
||||||
// spi_acquire(&rfm->spi);
|
|
||||||
// spi_transfer_byte(&rfm->spi, 0x11);
|
|
||||||
// spi_transfer_byte(&rfm->spi, 0x01);
|
|
||||||
// spi_release(&rfm->spi);
|
|
||||||
// }
|
|
||||||
|
|
||||||
void flash(gpio_t *light, size_t count) {
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
|
||||||
set_line(light);
|
|
||||||
_delay_ms(50);
|
|
||||||
clear_line(light);
|
|
||||||
_delay_ms(50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
spi_t spi = (spi_t){
|
|
||||||
.clock = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 1 },
|
|
||||||
.data_out = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 2 },
|
|
||||||
.data_in = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 3 },
|
|
||||||
.chip_select = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 4 },
|
|
||||||
};
|
|
||||||
|
|
||||||
rfm_t rfm = (rfm_t){
|
|
||||||
.spi = spi,
|
|
||||||
.irq = { .ddr = &DDRE, .port = &PORTE, .pin = &PINE, .addr = 6 },
|
|
||||||
.reset = { .ddr = &DDRD, .port = &PORTD, .pin = &PIND, .addr = 4 },
|
|
||||||
};
|
|
||||||
|
|
||||||
gpio_t light = { .ddr = &DDRC, .port = &PORTC, .addr = 7 };
|
|
||||||
gpio_t fifo_full = { .ddr = &DDRB, .port = &PORTB, .addr = 7 };
|
|
||||||
gpio_t fifo_empty = { .ddr = &DDRB, .port = &PORTB, .addr = 6 };
|
|
||||||
|
|
||||||
set_line_direction(&light, LINE_OUT);
|
|
||||||
set_line_direction(&fifo_full, LINE_OUT);
|
|
||||||
set_line_direction(&fifo_empty, LINE_OUT);
|
|
||||||
|
|
||||||
|
|
||||||
flash(&light, 3);
|
|
||||||
|
|
||||||
rfm_initialize(&rfm);
|
|
||||||
set_line(&light);
|
|
||||||
uint8_t status = rfm_status(&rfm);
|
|
||||||
status & _BV(7) ? set_line(&fifo_full) : clear_line(&fifo_full);
|
|
||||||
status & _BV(6) ? set_line(&fifo_empty) : clear_line(&fifo_empty);
|
|
||||||
|
|
||||||
/*
|
|
||||||
spi_acquire(&rfm.spi);
|
|
||||||
spi_transfer_byte(&rfm.spi, 0x11);
|
|
||||||
spi_transfer_byte(&rfm.spi, 0x01);
|
|
||||||
spi_release(&rfm.spi);
|
|
||||||
|
|
||||||
spi_acquire(&rfm.spi);
|
|
||||||
spi_transfer_byte(&rfm.spi, 0x10);
|
|
||||||
spi_transfer_byte(&rfm.spi, 1);
|
|
||||||
spi_transfer_byte(&rfm.spi, 2);
|
|
||||||
spi_transfer_byte(&rfm.spi, 3);
|
|
||||||
spi_transfer_byte(&rfm.spi, 5);
|
|
||||||
spi_transfer_byte(&rfm.spi, 7);
|
|
||||||
spi_transfer_byte(&rfm.spi, 11);
|
|
||||||
spi_transfer_byte(&rfm.spi, 13);
|
|
||||||
spi_release(&rfm.spi);
|
|
||||||
|
|
||||||
status = rfm_status(&rfm);
|
|
||||||
if (status & _BV(7)) {
|
|
||||||
clear_line(&light);
|
|
||||||
} else {
|
|
||||||
set_line(&light);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
uint8_t count[1] = { 0 };
|
|
||||||
while(1) {
|
|
||||||
rfm_send_data(&rfm, count, 1);
|
|
||||||
count[0]++;
|
|
||||||
set_line(&light);
|
|
||||||
_delay_ms(50);
|
|
||||||
clear_line(&light);
|
|
||||||
_delay_ms(50);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -0,0 +1,188 @@
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <base.h>
|
||||||
|
#include <display.h>
|
||||||
|
#include <rfm.h>
|
||||||
|
#include <spi.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
void status(display_t *display, rfm_t *radio) {
|
||||||
|
op_mode_t mode = rfm_mode(radio);
|
||||||
|
interrupt_flags_t flags = rfm_interrupts(radio);
|
||||||
|
|
||||||
|
display_clear(display);
|
||||||
|
|
||||||
|
if (mode.listen_on) display_write_message(display, "Listen ");
|
||||||
|
if (mode.mode == sleep) display_write_message(display, "Sleep");
|
||||||
|
if (mode.mode == standby) display_write_message(display, "Standby");
|
||||||
|
if (mode.mode == fs) display_write_message(display, "FS");
|
||||||
|
if (mode.mode == tx) display_write_message(display, "TX");
|
||||||
|
if (mode.mode == rx) display_write_message(display, "RX");
|
||||||
|
|
||||||
|
display_set_location(display, 1, 0);
|
||||||
|
if (flags.mode_ready) display_write_message(display, "R ");
|
||||||
|
if (flags.rx_ready) display_write_message(display, "RX ");
|
||||||
|
if (flags.tx_ready) display_write_message(display, "TX ");
|
||||||
|
if (flags.timeout) display_write_message(display, "TO ");
|
||||||
|
if (flags.auto_mode) display_write_message(display, "AM ");
|
||||||
|
if (flags.sync_addr_match) display_write_message(display, "SM ");
|
||||||
|
if (flags.fifo_full) display_write_message(display, "F ");
|
||||||
|
if (flags.fifo_not_empty) display_write_message(display, "NE ");
|
||||||
|
if (flags.fifo_level) display_write_message(display, "LE ");
|
||||||
|
if (flags.fifo_overrun) display_write_message(display, "OR ");
|
||||||
|
if (flags.packet_sent) display_write_message(display, "PS ");
|
||||||
|
if (flags.payload_ready) display_write_message(display, "PR");
|
||||||
|
if (flags.crc_ok) display_write_message(display, "CRC");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
display_t display = {
|
||||||
|
.reg = {
|
||||||
|
.output = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 7 },
|
||||||
|
.shift_clock = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 6 },
|
||||||
|
.latch_clock = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 5 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
rfm_t radio = (rfm_t){
|
||||||
|
.spi = {
|
||||||
|
.clock = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 1 },
|
||||||
|
.data_out = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 2 },
|
||||||
|
.data_in = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 3 },
|
||||||
|
.chip_select = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 4 },
|
||||||
|
},
|
||||||
|
.irq = { .ddr = &DDRE, .port = &PORTE, .pin = &PINE, .addr = 6 },
|
||||||
|
.reset = { .ddr = &DDRD, .port = &PORTD, .pin = &PIND, .addr = 4 },
|
||||||
|
};
|
||||||
|
|
||||||
|
_delay_ms(15);
|
||||||
|
display_init(&display);
|
||||||
|
|
||||||
|
rfm_error_e error;
|
||||||
|
|
||||||
|
rfm_init(&radio, (uint8_t [4]){ 0xde, 0xca, 0xfb, 0xad }, 4, &error);
|
||||||
|
|
||||||
|
status(&display, &radio);
|
||||||
|
_delay_ms(1000);
|
||||||
|
|
||||||
|
rfm_transmit(&radio, (uint8_t [7]){ 1, 2, 3, 5, 7, 11, 13 }, 7);
|
||||||
|
status(&display, &radio);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
_delay_ms(1000);
|
||||||
|
status(&display, &radio);
|
||||||
|
interrupt_flags_t flags = rfm_interrupts(&radio);
|
||||||
|
|
||||||
|
if (flags.packet_sent) {
|
||||||
|
rfm_standby(&radio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (!error) {
|
||||||
|
display_clear(&display);
|
||||||
|
display_write_message(&display, "Error detected");
|
||||||
|
} else {
|
||||||
|
while (1) {
|
||||||
|
status(&display, &radio);
|
||||||
|
_delay_ms(1000);
|
||||||
|
|
||||||
|
rfm_receive_mode(&radio);
|
||||||
|
status(&display, &radio);
|
||||||
|
_delay_ms(1000);
|
||||||
|
rfm_standby(&radio);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
status(&display, &radio);
|
||||||
|
_delay_ms(1000);
|
||||||
|
|
||||||
|
rfm_set_mode(&display, &radio, (op_mode_t){ .listen_on = true, .mode = standby });
|
||||||
|
_delay_ms(1000);
|
||||||
|
rfm_set_mode(&display, &radio, (op_mode_t){ .listen_on = true, .mode = standby });
|
||||||
|
_delay_ms(1000);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
rfm_packet_format(&radio, fixed, 8);
|
||||||
|
|
||||||
|
rfm_set_mode(&display, &radio, (op_mode_t){ .listen_on = false, .mode = rx });
|
||||||
|
_delay_ms(1000);
|
||||||
|
status(&display, &radio);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
while (1) {
|
||||||
|
status(&display, &radio);
|
||||||
|
_delay_ms(1000);
|
||||||
|
|
||||||
|
uint8_t data;
|
||||||
|
rfm_receive(rfm, &data, 1);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
uint8_t b[8];
|
||||||
|
char msg[32];
|
||||||
|
status(&display, &radio);
|
||||||
|
_delay_ms(1000);
|
||||||
|
|
||||||
|
interrupt_flags_t flags = rfm_interrupts(&radio);
|
||||||
|
|
||||||
|
if (flags.fifo_not_empty) {
|
||||||
|
rfm_receive(&radio, b, 8);
|
||||||
|
|
||||||
|
display_clear(&display);
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
sprintf(msg, "%x", b[i]);
|
||||||
|
}
|
||||||
|
display_write_message(&display, msg);
|
||||||
|
_delay_ms(1000);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// }
|
||||||
|
|
||||||
|
/*
|
||||||
|
spi_acquire(&rfm.spi);
|
||||||
|
spi_transfer_byte(&rfm.spi, 0x11);
|
||||||
|
spi_transfer_byte(&rfm.spi, 0x01);
|
||||||
|
spi_release(&rfm.spi);
|
||||||
|
|
||||||
|
spi_acquire(&rfm.spi);
|
||||||
|
spi_transfer_byte(&rfm.spi, 0x10);
|
||||||
|
spi_transfer_byte(&rfm.spi, 1);
|
||||||
|
spi_transfer_byte(&rfm.spi, 2);
|
||||||
|
spi_transfer_byte(&rfm.spi, 3);
|
||||||
|
spi_transfer_byte(&rfm.spi, 5);
|
||||||
|
spi_transfer_byte(&rfm.spi, 7);
|
||||||
|
spi_transfer_byte(&rfm.spi, 11);
|
||||||
|
spi_transfer_byte(&rfm.spi, 13);
|
||||||
|
spi_release(&rfm.spi);
|
||||||
|
|
||||||
|
status = rfm_status(&rfm);
|
||||||
|
if (status & _BV(7)) {
|
||||||
|
clear_line(&light);
|
||||||
|
} else {
|
||||||
|
set_line(&light);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
uint8_t count[1] = { 0 };
|
||||||
|
while(1) {
|
||||||
|
rfm_send_data(&rfm, count, 1);
|
||||||
|
count[0]++;
|
||||||
|
set_line(&light);
|
||||||
|
_delay_ms(50);
|
||||||
|
clear_line(&light);
|
||||||
|
_delay_ms(50);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
217
rfm69hcw/rfm.c
217
rfm69hcw/rfm.c
|
@ -13,86 +13,193 @@ You should have received a copy of the GNU General Public License along with Lum
|
||||||
|
|
||||||
#include <rfm.h>
|
#include <rfm.h>
|
||||||
|
|
||||||
void rfm_write(rfm_t *rfm, uint8_t reg, uint8_t *data, size_t length) {
|
#define REG_FIFO 0x00
|
||||||
|
#define REG_OP_MODE 0x01
|
||||||
|
#define REG_DATA_MODULE 0x02
|
||||||
|
#define REG_VERSION 0x10
|
||||||
|
#define REG_RSSI_VALUE 0x24
|
||||||
|
#define REG_DIO_MAPPING1 0x25
|
||||||
|
#define REG_IRQ_FLAGS1 0x27
|
||||||
|
#define REG_IRQ_FLAGS2 0x28
|
||||||
|
#define REG_SYNC_CONFIG 0x2e
|
||||||
|
#define REG_SYNC_VALUE1 0x2f
|
||||||
|
#define REG_PACKET_CONFIG1 0x37
|
||||||
|
#define REG_FIFO_THRESH 0x3c
|
||||||
|
#define REG_TEST_PA1 0x5a
|
||||||
|
#define REG_TEST_PA2 0x5c
|
||||||
|
|
||||||
|
#define PA1_LOW_POWER 0x55
|
||||||
|
#define PA2_LOW_POWER 0x70
|
||||||
|
|
||||||
|
void _rfm_write(rfm_t *rfm, uint8_t reg, uint8_t *data, size_t length) {
|
||||||
spi_acquire(&rfm->spi);
|
spi_acquire(&rfm->spi);
|
||||||
spi_transfer_byte(&rfm->spi, _BV(7) | reg);
|
spi_transceive(&rfm->spi, _BV(7) | reg);
|
||||||
for (size_t i = 0; i < length; i++) {
|
for (size_t i = 0; i < length; i++) {
|
||||||
spi_transfer_byte(&rfm->spi, data[i]);
|
spi_transceive(&rfm->spi, data[i]);
|
||||||
}
|
}
|
||||||
spi_release(&rfm->spi);
|
spi_release(&rfm->spi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rfm_read(rfm_t *rfm, uint8_t reg, uint8_t *data, size_t length) {
|
void _rfm_read(rfm_t *rfm, uint8_t reg, uint8_t *data, size_t length) {
|
||||||
spi_acquire(&rfm->spi);
|
spi_acquire(&rfm->spi);
|
||||||
spi_transfer_byte(&rfm->spi, reg);
|
spi_transceive(&rfm->spi, reg);
|
||||||
for (size_t i = 0; i < length; i++) {
|
for (size_t i = 0; i < length; i++) {
|
||||||
data[i] = spi_transfer_byte(&rfm->spi, 0);
|
data[i] = spi_transceive(&rfm->spi, 0);
|
||||||
}
|
}
|
||||||
spi_release(&rfm->spi);
|
spi_release(&rfm->spi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rfm_initialize(rfm_t *rfm) {
|
void _rfm_set_low_power(rfm_t *rfm) {
|
||||||
|
_rfm_write(rfm, REG_TEST_PA1, (uint8_t [1]){ PA1_LOW_POWER }, 1);
|
||||||
|
_rfm_write(rfm, REG_TEST_PA2, (uint8_t [1]){ PA2_LOW_POWER }, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rfm_init(rfm_t *rfm, uint8_t *sync_word, size_t length, rfm_error_e *error) {
|
||||||
|
if (!error) return;
|
||||||
|
|
||||||
spi_initialize(&rfm->spi);
|
spi_initialize(&rfm->spi);
|
||||||
|
set_line_direction(&rfm->irq, LINE_IN);
|
||||||
|
set_line_direction(&rfm->reset, LINE_OUT);
|
||||||
|
|
||||||
|
rfm_reset(rfm);
|
||||||
|
rfm_sleep(rfm);
|
||||||
|
|
||||||
|
uint8_t version;
|
||||||
|
_rfm_read(rfm, REG_VERSION, &version, 1);
|
||||||
|
if (version != 0x24) {
|
||||||
|
*error = radio_not_found;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rfm_set_mode(rfm, (op_mode_t){ .listen_on = false, .mode = standby });
|
||||||
|
_rfm_write(rfm, REG_FIFO_THRESH, (uint8_t [1]){ 0x8f }, 1);
|
||||||
|
_rfm_set_low_power(rfm);
|
||||||
|
|
||||||
|
_rfm_write(rfm, REG_PACKET_CONFIG1,
|
||||||
|
(uint8_t [1]){
|
||||||
|
_BV(7) /* variable length packets */
|
||||||
|
| _BV(6) /* DC whitening */
|
||||||
|
| _BV(4) /* CRC on */
|
||||||
|
| _BV(1) /* packet filtering requires nodeaddress */
|
||||||
|
}, 1);
|
||||||
|
|
||||||
|
_rfm_write(rfm, REG_SYNC_CONFIG, (uint8_t [1]){ _BV(7) | (length << 3) }, 1);
|
||||||
|
uint8_t word_base = REG_SYNC_VALUE1;
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
_rfm_write(rfm, word_base + i, &sync_word[i], length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rfm_reset(rfm_t *rfm) {
|
||||||
|
set_line(&rfm->reset);
|
||||||
|
_delay_us(100);
|
||||||
|
clear_line(&rfm->reset);
|
||||||
|
_delay_us(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rfm_packet_format(rfm_t *rfm, packet_format_e format, size_t length) {
|
void rfm_packet_format(rfm_t *rfm, packet_format_e format, size_t length) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case unlimited:
|
case unlimited:
|
||||||
rfm_write(rfm, 0x37, (uint8_t [1]){ 0 }, 1);
|
_rfm_write(rfm, 0x37, (uint8_t [1]){ 0 }, 1);
|
||||||
rfm_write(rfm, 0x38, (uint8_t [1]){ 0 }, 1);
|
_rfm_write(rfm, 0x38, (uint8_t [1]){ 0 }, 1);
|
||||||
break;
|
break;
|
||||||
case fixed:
|
case fixed:
|
||||||
rfm_write(rfm, 0x37, (uint8_t [1]){ 0 }, 1);
|
_rfm_write(rfm, 0x37, (uint8_t [1]){ 0 }, 1);
|
||||||
rfm_write(rfm, 0x38, (uint8_t [1]){ length }, 1);
|
_rfm_write(rfm, 0x38, (uint8_t [1]){ length }, 1);
|
||||||
break;
|
break;
|
||||||
case variable:
|
case variable:
|
||||||
rfm_write(rfm, 0x37, (uint8_t [1]){ _BV(7) }, 1);
|
_rfm_write(rfm, 0x37, (uint8_t [1]){ _BV(7) }, 1);
|
||||||
rfm_write(rfm, 0x38, (uint8_t [1]){ 0 }, 1);
|
_rfm_write(rfm, 0x38, (uint8_t [1]){ 0 }, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rfm_sleep(rfm_t *rfm) {
|
||||||
|
rfm_set_mode(rfm, (op_mode_t){ .listen_on = false, .mode = sleep });
|
||||||
|
}
|
||||||
|
|
||||||
|
void rfm_standby(rfm_t *rfm) {
|
||||||
|
rfm_set_mode(rfm, (op_mode_t){ .listen_on = false, .mode = standby });
|
||||||
|
}
|
||||||
|
|
||||||
|
void rfm_transmit(rfm_t *rfm, uint8_t *data, size_t length) {
|
||||||
|
rfm_set_mode(rfm, (op_mode_t){ .listen_on = false, .mode = standby });
|
||||||
|
_rfm_write(rfm, REG_FIFO, data, length);
|
||||||
|
_rfm_write(rfm, REG_DIO_MAPPING1, (uint8_t [1]){ 0x00 }, 1);
|
||||||
|
rfm_set_mode(rfm, (op_mode_t){ .listen_on = false, .mode = tx });
|
||||||
|
}
|
||||||
|
|
||||||
|
void rfm_receive_mode(rfm_t *rfm) {
|
||||||
|
_rfm_write(rfm, REG_DIO_MAPPING1, (uint8_t [1]){ _BV(6) }, 1);
|
||||||
|
rfm_set_mode(rfm, (op_mode_t){ .listen_on = false, .mode = rx });
|
||||||
|
}
|
||||||
|
|
||||||
|
void rfm_receive(rfm_t *rfm, uint8_t *data, size_t length) {
|
||||||
|
_rfm_write(rfm, REG_DIO_MAPPING1, (uint8_t [1]){ _BV(6) }, 1);
|
||||||
|
rfm_set_mode(rfm, (op_mode_t){ .listen_on = false, .mode = rx });
|
||||||
|
_rfm_read(rfm, 0x00, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t rfm_temperature(rfm_t *rfm) {
|
uint8_t rfm_temperature(rfm_t *rfm) {
|
||||||
uint8_t ready = 0;
|
uint8_t ready = 0;
|
||||||
uint8_t temp;
|
uint8_t temp;
|
||||||
rfm_write(rfm, 0x4e, (uint8_t [1]){ _BV(3) }, 1);
|
_rfm_write(rfm, 0x4e, (uint8_t [1]){ _BV(3) }, 1);
|
||||||
_delay_ms(1);
|
_delay_ms(1);
|
||||||
|
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
while (!(ready & _BV(2)) && i < 10) {
|
while (!(ready & _BV(2)) && i < 10) {
|
||||||
rfm_read(rfm, 0x4e, &ready, 1);
|
_rfm_read(rfm, 0x4e, &ready, 1);
|
||||||
i++;
|
i++;
|
||||||
_delay_us(100);
|
_delay_us(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
rfm_read(rfm, 0x4f, &temp, 1);
|
_rfm_read(rfm, 0x4f, &temp, 1);
|
||||||
|
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t rfm_mode(rfm_t *rfm) {
|
op_mode_t rfm_mode(rfm_t *rfm) {
|
||||||
uint8_t mode_flag;
|
op_mode_t op_mode = {
|
||||||
rfm_read(rfm, 0x01, &mode_flag, 1);
|
.listen_on = false,
|
||||||
return mode_flag;
|
.mode = sleep,
|
||||||
|
};
|
||||||
|
uint8_t flags;
|
||||||
|
|
||||||
|
_rfm_read(rfm, 0x01, &flags, 1);
|
||||||
|
if (flags & _BV(6)) op_mode.listen_on = 1;
|
||||||
|
op_mode.mode = (flags & 0b00011100) >> 2;
|
||||||
|
|
||||||
|
return op_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rfm_set_mode(rfm_t *rfm, op_mode_t mode) {
|
||||||
|
op_mode_t current = rfm_mode(rfm);
|
||||||
|
uint8_t flags = mode.mode << 2;
|
||||||
|
|
||||||
|
if (mode.listen_on) {
|
||||||
|
flags |= _BV(6);
|
||||||
|
} else if (current.listen_on) {
|
||||||
|
flags |= _BV(5);
|
||||||
|
_rfm_write(rfm, REG_OP_MODE, (uint8_t [1]){ flags }, 1);
|
||||||
|
|
||||||
|
flags = flags & ~_BV(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
_rfm_write(rfm, REG_OP_MODE, (uint8_t [1]){ flags }, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t rfm_status(rfm_t *rfm) {
|
uint8_t rfm_status(rfm_t *rfm) {
|
||||||
uint8_t status_flag;
|
uint8_t status_flag;
|
||||||
rfm_read(rfm, 0x28, &status_flag, 1);
|
_rfm_read(rfm, 0x28, &status_flag, 1);
|
||||||
return status_flag;
|
return status_flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rfm_listen(rfm_t *rfm) {
|
|
||||||
rfm_write(rfm, 0x01, (uint8_t [1]){ _BV(6) }, 1);
|
|
||||||
_delay_ms(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t rfm_frequency(rfm_t *rfm) {
|
uint32_t rfm_frequency(rfm_t *rfm) {
|
||||||
uint8_t frequency_bytes[3];
|
uint8_t frequency_bytes[3];
|
||||||
uint32_t frequency;
|
uint32_t frequency;
|
||||||
rfm_read(rfm, 0x07, &frequency_bytes[2], 1);
|
_rfm_read(rfm, 0x07, &frequency_bytes[2], 1);
|
||||||
rfm_read(rfm, 0x08, &frequency_bytes[1], 1);
|
_rfm_read(rfm, 0x08, &frequency_bytes[1], 1);
|
||||||
rfm_read(rfm, 0x09, &frequency_bytes[0], 1);
|
_rfm_read(rfm, 0x09, &frequency_bytes[0], 1);
|
||||||
|
|
||||||
frequency = frequency_bytes[2];
|
frequency = frequency_bytes[2];
|
||||||
frequency = frequency << 8;
|
frequency = frequency << 8;
|
||||||
|
@ -102,19 +209,43 @@ uint32_t rfm_frequency(rfm_t *rfm) {
|
||||||
return frequency * 61;
|
return frequency * 61;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t rfm_set_mode(rfm_t *rfm, mode_e mode) {
|
interrupt_flags_t rfm_interrupts(rfm_t *rfm) {
|
||||||
uint8_t mode_flags;
|
uint8_t irq_1;
|
||||||
rfm_read(rfm, 0x01, &mode_flags, 1);
|
uint8_t irq_2;
|
||||||
mode_flags = mode_flags & 0b11100011;
|
interrupt_flags_t flags = {
|
||||||
/*
|
.mode_ready = false,
|
||||||
mode_flags += (mode << 2);
|
.rx_ready = false,
|
||||||
rfm_write(rfm, 0x01, &mode_flags, 1);
|
.tx_ready = false,
|
||||||
*/
|
.timeout = false,
|
||||||
return mode_flags;
|
.auto_mode = false,
|
||||||
}
|
.sync_addr_match = false,
|
||||||
|
|
||||||
uint8_t rfm_irq_1(rfm_t *rfm) {
|
.fifo_full = false,
|
||||||
uint8_t irq;
|
.fifo_not_empty = false,
|
||||||
rfm_read(rfm, 0x27, &irq, 1);
|
.fifo_level = false,
|
||||||
return irq;
|
.fifo_overrun = false,
|
||||||
|
.packet_sent = false,
|
||||||
|
.payload_ready = false,
|
||||||
|
.crc_ok = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
_rfm_read(rfm, REG_IRQ_FLAGS1, &irq_1, 1);
|
||||||
|
_rfm_read(rfm, REG_IRQ_FLAGS2, &irq_2, 1);
|
||||||
|
|
||||||
|
if (irq_1 & _BV(7)) flags.mode_ready = true;
|
||||||
|
if (irq_1 & _BV(6)) flags.rx_ready = true;
|
||||||
|
if (irq_1 & _BV(5)) flags.tx_ready = true;
|
||||||
|
if (irq_1 & _BV(2)) flags.timeout = true;
|
||||||
|
if (irq_1 & _BV(1)) flags.auto_mode = true;
|
||||||
|
if (irq_1 & _BV(0)) flags.sync_addr_match = true;
|
||||||
|
|
||||||
|
if (irq_2 & _BV(7)) flags.fifo_full = true;
|
||||||
|
if (irq_2 & _BV(6)) flags.fifo_not_empty = true;
|
||||||
|
if (irq_2 & _BV(5)) flags.fifo_level = true;
|
||||||
|
if (irq_2 & _BV(4)) flags.fifo_overrun = true;
|
||||||
|
if (irq_2 & _BV(3)) flags.packet_sent = true;
|
||||||
|
if (irq_2 & _BV(2)) flags.payload_ready = true;
|
||||||
|
if (irq_2 & _BV(1)) flags.crc_ok = true;
|
||||||
|
|
||||||
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,12 @@ You should have received a copy of the GNU General Public License along with Lum
|
||||||
|
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
#include <spi.h>
|
#include <spi.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef enum RFM_ERROR_TYPES {
|
||||||
|
Ok,
|
||||||
|
radio_not_found,
|
||||||
|
} rfm_error_e;
|
||||||
|
|
||||||
typedef struct RFM {
|
typedef struct RFM {
|
||||||
spi_t spi;
|
spi_t spi;
|
||||||
|
@ -33,22 +39,53 @@ typedef enum MODE {
|
||||||
standby,
|
standby,
|
||||||
fs,
|
fs,
|
||||||
tx,
|
tx,
|
||||||
rx
|
rx,
|
||||||
|
listen
|
||||||
} mode_e;
|
} mode_e;
|
||||||
|
|
||||||
void rfm_initialize(rfm_t *rfm);
|
/* make mode more of a state machine. define the transitions between those machines. */
|
||||||
|
typedef struct MODE_FLAGS {
|
||||||
|
bool listen_on;
|
||||||
|
mode_e mode;
|
||||||
|
} op_mode_t;
|
||||||
|
|
||||||
|
typedef struct INTERRUPT_FLAGS {
|
||||||
|
bool mode_ready;
|
||||||
|
bool rx_ready;
|
||||||
|
bool tx_ready;
|
||||||
|
bool timeout;
|
||||||
|
bool auto_mode;
|
||||||
|
bool sync_addr_match;
|
||||||
|
|
||||||
|
bool fifo_full;
|
||||||
|
bool fifo_not_empty;
|
||||||
|
bool fifo_level;
|
||||||
|
bool fifo_overrun;
|
||||||
|
bool packet_sent;
|
||||||
|
bool payload_ready;
|
||||||
|
bool crc_ok;
|
||||||
|
} interrupt_flags_t;
|
||||||
|
|
||||||
|
void rfm_init(rfm_t *, uint8_t *, size_t, rfm_error_e *);
|
||||||
|
void rfm_reset(rfm_t *);
|
||||||
|
|
||||||
|
|
||||||
void rfm_packet_format(rfm_t *rfm, packet_format_e format, size_t length);
|
void rfm_packet_format(rfm_t *rfm, packet_format_e format, size_t length);
|
||||||
|
|
||||||
void rfm_send_data(rfm_t *rfm, uint8_t *data, size_t length);
|
void rfm_sleep(rfm_t *);
|
||||||
void rfm_receive_data(rfm_t *rfm, uint8_t *data, size_t length);
|
void rfm_standby(rfm_t *);
|
||||||
|
void rfm_receive_mode(rfm_t *);
|
||||||
|
void rfm_transmit(rfm_t *rfm, uint8_t *data, size_t length);
|
||||||
|
void rfm_receive(rfm_t *rfm, uint8_t *data, size_t length);
|
||||||
|
|
||||||
|
op_mode_t rfm_mode(rfm_t *rfm);
|
||||||
|
void rfm_set_mode(rfm_t *rfm, op_mode_t mode);
|
||||||
|
|
||||||
uint8_t rfm_mode(rfm_t *rfm);
|
|
||||||
uint8_t rfm_status(rfm_t *rfm);
|
uint8_t rfm_status(rfm_t *rfm);
|
||||||
uint8_t rfm_temperature(rfm_t *rfm);
|
uint8_t rfm_temperature(rfm_t *rfm);
|
||||||
uint32_t rfm_frequency(rfm_t *rfm);
|
uint32_t rfm_frequency(rfm_t *rfm);
|
||||||
|
|
||||||
void rfm_listen(rfm_t *rfm);
|
void rfm_listen(rfm_t *rfm);
|
||||||
uint8_t rfm_set_mode(rfm_t *rfm, mode_e mode);
|
interrupt_flags_t rfm_interrupts(rfm_t *rfm);
|
||||||
uint8_t rfm_irq_1(rfm_t *rfm);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,7 +31,7 @@ void spi_release(spi_t *spi) {
|
||||||
set_line(&spi->chip_select);
|
set_line(&spi->chip_select);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t spi_transfer_byte(spi_t *spi, uint8_t output) {
|
uint8_t spi_transceive(spi_t *spi, uint8_t output) {
|
||||||
uint8_t input = 0;
|
uint8_t input = 0;
|
||||||
int input_bit;
|
int input_bit;
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,6 @@ typedef struct SPI {
|
||||||
void spi_initialize(spi_t *spi);
|
void spi_initialize(spi_t *spi);
|
||||||
void spi_acquire(spi_t *spi);
|
void spi_acquire(spi_t *spi);
|
||||||
void spi_release(spi_t *spi);
|
void spi_release(spi_t *spi);
|
||||||
uint8_t spi_transfer_byte(spi_t *spi, uint8_t output);
|
uint8_t spi_transceive(spi_t *spi, uint8_t output);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue