diff --git a/flake.nix b/flake.nix index 840b7e2..f4dd1a3 100644 --- a/flake.nix +++ b/flake.nix @@ -69,6 +69,38 @@ ''; }; + packages."x86_64-linux"."radio-rx" = + let + pkgs = import nixpkgs { system = "x86_64-linux"; }; + lib = pkgs.lib; + avr = pkgs.pkgsCross.avr.buildPackages; + in pkgs.stdenv.mkDerivation rec { + name = "prime-tx"; + src = ./.; + + includes = [ "base" "spi" "shift_register" "rfm69hcw" "display" ]; + + MCU = "atmega32u4"; + CHIP_SELECT = "AVR_ATmega32u4"; + F_CPU = "8000000"; + CFLAGS = ''-O -finline-functions -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Werror -Wstrict-prototypes -DF_CPU=${F_CPU} -std=gnu99 -D__${CHIP_SELECT}__=1 -mmcu=${MCU} -DAVR=1''; + INCLUDE_DIRS = lib.concatStringsSep " " (map (dir: "-I${src}/${dir}") includes); + + 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 spi.o -c ${src}/spi/spi.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 display.o -c ${src}/display/display.c + ${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o main.o -c ${src}/radio-rx/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 + ''; + installPhase = '' + mkdir $out + cp main.elf main.hex $out + ''; + }; + packages."x86_64-linux"."spi_test" = let pkgs = import nixpkgs { system = "x86_64-linux"; }; diff --git a/prime-tx/main.c b/prime-tx/main.c index 68ea4c1..76d921c 100644 --- a/prime-tx/main.c +++ b/prime-tx/main.c @@ -71,29 +71,23 @@ int main(void) { status(&display, &radio, clock); - int next_transmit = 0; int prime = 0; while (1) { - if (clock >= next_transmit) { - display_clear(&display); - char msg[16]; - sprintf(msg, "sending %d", primes[prime]); - display_write_message(&display, msg); + status(&display, &radio, clock); + + op_mode_t mode = rfm_mode(&radio); + interrupt_flags_t flags = rfm_interrupts(&radio); + if (mode.mode == standby) { rfm_transmit(&radio, &primes[prime], 1); if (primes[prime] == 0) { prime = 0; } else { prime++; } - next_transmit = clock + 10; - _delay_ms(1000); - } - status(&display, &radio, clock); - interrupt_flags_t flags = rfm_interrupts(&radio); - - if (flags.packet_sent) { + } else if (mode.mode == tx && flags.packet_sent) { rfm_standby(&radio); } + clock++; _delay_ms(1000); } diff --git a/radio-rx/main.c b/radio-rx/main.c new file mode 100644 index 0000000..dacf5fa --- /dev/null +++ b/radio-rx/main.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include + +void status(display_t *display, rfm_t *radio, int clock) { + op_mode_t mode = rfm_mode(radio); + interrupt_flags_t flags = rfm_interrupts(radio); + uint8_t rssi = rfm_rssi(radio); + + display_clear(display); + + /* + char clock_str[16]; + sprintf(clock_str, "%4d ", clock); + display_write_message(display, clock_str); + */ + + 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); + + char msg[16]; + snprintf(msg, 15, "[-%d] ", rssi / 2); + display_write_message(display, msg); + + 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); + display_clear(&display); + + rfm_error_e error; + + rfm_init(&radio, (uint8_t [4]){ 0xde, 0xca, 0xfb, 0xad }, 4, &error); + rfm_listen(&radio); + + if (!error) { + display_write_message(&display, "error detected"); + return 0; + } + + /* + uint8_t word[8]; + uint8_t sync_length = sync_word(&radio, word); + char msg[16]; + snprintf(msg, 15, "sync: %d", sync_length); + display_write_message(&display, msg); + display_set_location(&display, 1, 0); + + if (sync_length == 4) { + snprintf(msg, 15, ": %x %x %x %x", word[0], word[1], word[2], word[3]); + } else { + snprintf(msg, 15, "word err"); + } + + display_write_message(&display, msg); + _delay_ms(5000); + */ + + char msg[16]; + uint32_t frequency = rfm_frequency(&radio); + snprintf(msg, 15, "F: %ld", frequency); + display_write_message(&display, msg); + _delay_ms(5000); + + while(1) { + // char msg[16]; + // uint8_t packet[66]; + // uint8_t length; + // display_clear(&display); + + // if (length > 0) { + // snprintf(msg, 15, "%d ", packet[0]); + // display_write_message(&display, msg); + // _delay_ms(1000); + // } + status(&display, &radio, 0); + _delay_ms(1000); + } +} diff --git a/rfm69hcw/rfm.c b/rfm69hcw/rfm.c index 622ffca..42f79d4 100644 --- a/rfm69hcw/rfm.c +++ b/rfm69hcw/rfm.c @@ -12,15 +12,18 @@ You should have received a copy of the GNU General Public License along with Lum #include +#include #define REG_FIFO 0x00 #define REG_OP_MODE 0x01 -#define REG_DATA_MODULE 0x02 +#define REG_DATA_MODUL 0x02 #define REG_VERSION 0x10 +#define REG_RSSI_CONFIG 0x23 #define REG_RSSI_VALUE 0x24 #define REG_DIO_MAPPING1 0x25 #define REG_IRQ_FLAGS1 0x27 #define REG_IRQ_FLAGS2 0x28 +#define REG_RSSI_THRESH 0x29 #define REG_SYNC_CONFIG 0x2e #define REG_SYNC_VALUE1 0x2f #define REG_PACKET_CONFIG1 0x37 @@ -29,7 +32,9 @@ You should have received a copy of the GNU General Public License along with Lum #define REG_TEST_PA2 0x5c #define PA1_LOW_POWER 0x55 +#define PA1_HIGH_POWER 0x5D #define PA2_LOW_POWER 0x70 +#define PA2_HIGH_POWER 0x7C void _rfm_write(rfm_t *rfm, uint8_t reg, uint8_t *data, size_t length) { spi_acquire(&rfm->spi); @@ -54,6 +59,11 @@ void _rfm_set_low_power(rfm_t *rfm) { _rfm_write(rfm, REG_TEST_PA2, (uint8_t [1]){ PA2_LOW_POWER }, 1); } +void _rfm_set_high_power(rfm_t *rfm) { + _rfm_write(rfm, REG_TEST_PA1, (uint8_t [1]){ PA1_HIGH_POWER }, 1); + _rfm_write(rfm, REG_TEST_PA2, (uint8_t [1]){ PA2_HIGH_POWER }, 1); +} + void rfm_init(rfm_t *rfm, uint8_t *sync_word, size_t length, rfm_error_e *error) { if (!error) return; @@ -72,7 +82,11 @@ void rfm_init(rfm_t *rfm, uint8_t *sync_word, size_t length, rfm_error_e *error) } rfm_set_mode(rfm, (op_mode_t){ .listen_on = false, .mode = standby }); + + _rfm_write(rfm, REG_DATA_MODUL, (uint8_t [1]){ _BV(3) }, 1); + _rfm_write(rfm, REG_FIFO_THRESH, (uint8_t [1]){ 0x8f }, 1); + _rfm_write(rfm, REG_RSSI_THRESH, (uint8_t [1]){ 0xe4 }, 1); _rfm_set_low_power(rfm); _rfm_write(rfm, REG_PACKET_CONFIG1, @@ -80,16 +94,29 @@ void rfm_init(rfm_t *rfm, uint8_t *sync_word, size_t length, rfm_error_e *error) _BV(7) /* variable length packets */ | _BV(6) /* DC whitening */ | _BV(4) /* CRC on */ - | _BV(1) /* packet filtering requires nodeaddress */ + | _BV(0) /* packet filtering does not require node address */ }, 1); - _rfm_write(rfm, REG_SYNC_CONFIG, (uint8_t [1]){ _BV(7) | (length << 3) }, 1); + _rfm_write(rfm, REG_SYNC_CONFIG, (uint8_t [1]){ _BV(7) | (length << 2) }, 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); + _rfm_write(rfm, word_base + i, &sync_word[i], 1); } } +uint8_t sync_word(rfm_t *rfm, uint8_t sync_word[8]) { + uint8_t length; + + _rfm_read(rfm, REG_SYNC_CONFIG, &length, 1); + length = (length >> 2) & 0b00000111; + uint8_t word_base = REG_SYNC_VALUE1; + for (int i = 0; i < length; i++) { + _rfm_read(rfm, word_base + i, &sync_word[i], 1); + } + + return length; +} + void rfm_reset(rfm_t *rfm) { set_line(&rfm->reset); _delay_us(100); @@ -122,8 +149,13 @@ void rfm_standby(rfm_t *rfm) { rfm_set_mode(rfm, (op_mode_t){ .listen_on = false, .mode = standby }); } +void rfm_listen(rfm_t *rfm) { + rfm_set_mode(rfm, (op_mode_t){ .listen_on = true, .mode = standby }); +} + void rfm_transmit(rfm_t *rfm, uint8_t *data, uint8_t length) { rfm_set_mode(rfm, (op_mode_t){ .listen_on = false, .mode = standby }); + _rfm_set_low_power(rfm); _rfm_write(rfm, REG_FIFO, &length, 1); _rfm_write(rfm, REG_FIFO, data, length); _rfm_write(rfm, REG_DIO_MAPPING1, (uint8_t [1]){ 0x00 }, 1); @@ -135,10 +167,21 @@ void rfm_receive_mode(rfm_t *rfm) { rfm_set_mode(rfm, (op_mode_t){ .listen_on = false, .mode = rx }); } -void rfm_receive(rfm_t *rfm, uint8_t *data, size_t length) { +void rfm_receive(display_t *display, rfm_t *rfm, uint8_t data[66], uint8_t *length) { + display_clear(display); + _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); + _rfm_read(rfm, REG_FIFO, length, 1); + + char msg[16]; + sprintf(msg, "length: %d", *length); + display_write_message(display, msg); + _delay_ms(1000); + + if (*length > 0) { + _rfm_read(rfm, 0x00, data, *length); + } } uint8_t rfm_temperature(rfm_t *rfm) { @@ -250,3 +293,20 @@ interrupt_flags_t rfm_interrupts(rfm_t *rfm) { return flags; } + +uint8_t rfm_rssi(rfm_t *rfm) { + uint8_t rssi_reg; + uint8_t rssi_value; + + _rfm_write(rfm, REG_RSSI_CONFIG, (uint8_t [1]){ _BV(0) }, 1); + + while(!(rssi_reg & _BV(1))) { + _rfm_read(rfm, REG_RSSI_CONFIG, &rssi_reg, 1); + } + + _rfm_read(rfm, REG_RSSI_VALUE, &rssi_value, 1); + + return rssi_value; +} + + diff --git a/rfm69hcw/rfm.h b/rfm69hcw/rfm.h index 0c4e661..9bed95f 100644 --- a/rfm69hcw/rfm.h +++ b/rfm69hcw/rfm.h @@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with Lum #include #include #include +#include typedef enum RFM_ERROR_TYPES { Ok, @@ -67,16 +68,16 @@ typedef struct INTERRUPT_FLAGS { } interrupt_flags_t; void rfm_init(rfm_t *, uint8_t *, size_t, rfm_error_e *); +uint8_t sync_word(rfm_t *rfm, uint8_t sync_word[8]); void rfm_reset(rfm_t *); - void rfm_packet_format(rfm_t *rfm, packet_format_e format, size_t length); void rfm_sleep(rfm_t *); void rfm_standby(rfm_t *); void rfm_receive_mode(rfm_t *); void rfm_transmit(rfm_t *rfm, uint8_t *data, uint8_t length); -void rfm_receive(rfm_t *rfm, uint8_t *data, size_t length); +void rfm_receive(display_t *display, rfm_t *rfm, uint8_t data[66], uint8_t *length); op_mode_t rfm_mode(rfm_t *rfm); void rfm_set_mode(rfm_t *rfm, op_mode_t mode); @@ -88,4 +89,6 @@ uint32_t rfm_frequency(rfm_t *rfm); void rfm_listen(rfm_t *rfm); interrupt_flags_t rfm_interrupts(rfm_t *rfm); +uint8_t rfm_rssi(rfm_t *rfm); + #endif