diff --git a/avrrfm.c b/avrrfm.c index cb4bd5e..55943b3 100644 --- a/avrrfm.c +++ b/avrrfm.c @@ -35,9 +35,9 @@ #include "dejavu.h" #include "unifont.h" -#define TRANSMIT_FAST 5 // 15 ~ 30 seconds -#define TRANSMIT_SLOW 30 // 150 ~ 5 minutes -#define MAX_TIMEOUTS 9 // slow down tx attempts after so many timeouts +#define TRANSMIT_FAST 15 // 15 ~ 30 seconds +#define TRANSMIT_SLOW 150 // 150 ~ 5 minutes +#define MAX_TIMEOUTS 9 // slow down tx attempts after so many timeouts #define LABEL_OFFSET 10 #define BLACK 0x0000 @@ -45,17 +45,22 @@ #define WHITE 0xffff /* Node addresses */ -#define NODE0 0x12 -#define NODE1 0x24 -#define NODE2 0x42 +#define NODE0 0x12 +#define NODE1 0x24 +#define NODE2 0x42 /* Carrier frequency in kHz */ -#define FREQ 868600 +#define FREQ 868600 + +/* Limit to FSK max size for now */ +#define MSG_SIZE RFM_FSK_MSG_SIZE #ifndef RECEIVER #define RECEIVER 1 #endif +#define LORA 1 + static volatile uint8_t watchdogInts = 0; static uint8_t measureInts = TRANSMIT_FAST; static uint8_t timeoutCount = 0; @@ -68,7 +73,7 @@ static width_t width = 0; /* Averaged output power requested from transmitter */ -static int8_t power = DBM_MAX; +static int8_t power = RFM_DBM_MAX; /** * Wakes up the controller and increments the watchdog bark counter. @@ -86,7 +91,8 @@ } /** - * Wakes up the controller and notifies of an interrupt on DIO4. + * Wakes up the controller and notifies of an interrupt on DIO4 (FSK)/ + * DIO1 (LoRa). */ ISR(INT1_vect) { rfmIrq(); @@ -134,8 +140,10 @@ // default fOSC/4 SPCR |= (1 << MSTR); SPCR |= (1 << SPE); - // slow down for the breadboard wiring - spiMid(); + if (!RECEIVER) { + // slow down for the breadboard wiring + spiMid(); + } } /** @@ -155,12 +163,9 @@ // interrupt on rising edge EICRA |= (1 << ISC01) | (1 << ISC00); - // irq from DIO4 only used for transmitter (timeout waiting for response) - if (!RECEIVER) { - EIMSK |= (1 << INT1); - // interrupt on rising edge - EICRA |= (1 << ISC11) | (1 << ISC10); - } + EIMSK |= (1 << INT1); + // interrupt on rising edge + EICRA |= (1 << ISC11) | (1 << ISC10); } /** @@ -191,17 +196,6 @@ } /** - * Reads the temperature from the sensor and transmits it with the given - * node address. - */ -static void transmitTemp(uint8_t node) { - uint16_t temp = readTSens(); - uint8_t power = rfmGetOutputPower(); - uint8_t payload[] = {(temp >> 8), temp & 0x00ff, power}; - rfmTransmitPayload(payload, sizeof (payload), node); -} - -/** * Converts the raw temperature to °C and lets it float around the display. * * @param rssi RSSI value @@ -209,7 +203,6 @@ * @param temp temperature + info */ static void displayTemp(uint8_t rssi, bool crc, Temperature *temp) { - uint8_t _rssi = divRoundNearest(rssi, 2); int16_t tempx10 = convertTSens(temp->raw); div_t tdiv = div(tempx10, 10); @@ -218,7 +211,7 @@ char buf[42]; snprintf(paf, sizeof (paf), "%+3d", temp->power); snprintf(buf, sizeof (buf), "RSSI: %4d dBm, CRC: %d, PA: %s dBm", - -_rssi, crc, crc ? paf : "---"); + -rssi, crc, crc ? paf : "---"); const __flash Font *unifont = &unifontFont; writeString(0, 0, unifont, buf, BLACK, WHITE); @@ -238,13 +231,12 @@ } /** - * Reads and returns the raw temperature + other info. + * Reads the temperature from the given payload and returns it. * - * @return temperature + info + * @param payload + * @return raw temperature + tx power in dBm */ -static Temperature readTemp(void) { - uint8_t payload[3]; - rfmReadPayload(payload, sizeof (payload)); +static Temperature readTemp(uint8_t *payload) { Temperature temp = {0}; temp.raw |= payload[0] << 8; temp.raw |= payload[1]; @@ -254,19 +246,54 @@ } /** - * Handles the payload received from the transmitter. - * - * @param flags + * Receives the temperature and responds with the RSSI. */ -static void handlePayload(PayloadFlags flags) { - Temperature temp = readTemp(); +static void receiveTemp(void) { + if (LORA) { + RxFlags flags = rfmLoRaRxDone(); + if (flags.ready) { + uint8_t response[] = {flags.rssi}; + rfmLoRaTx(response, sizeof (response)); - // communicate RSSI back to transmitter - uint8_t payload[] = {flags.rssi}; - rfmTransmitPayload(payload, sizeof (payload), NODE2); + uint8_t payload[3]; + rfmLoRaRxRead(payload, sizeof (payload)); + Temperature temp = readTemp(payload); - displayTemp(flags.rssi, flags.crc, &temp); - rfmStartReceive(false); + displayTemp(flags.rssi, flags.crc, &temp); + + rfmLoRaStartRx(); + } + } else { + RxFlags flags = rfmPayloadReady(); + if (flags.ready) { + uint8_t response[] = {flags.rssi}; + rfmTransmitPayload(response, sizeof (response), NODE2); + + uint8_t payload[3]; + rfmReadPayload(payload, sizeof (payload)); + Temperature temp = readTemp(payload); + displayTemp(flags.rssi, flags.crc, &temp); + + rfmStartReceive(false); + } + } +} + +/** + * Reads the temperature from the sensor and transmits it with the given + * node address. + * + * @param node node address + */ +static void transmitTemp(uint8_t node) { + uint16_t temp = readTSens(); + uint8_t power = rfmGetOutputPower(); + uint8_t payload[] = {(temp >> 8), temp & 0x00ff, power}; + if (LORA) { + rfmLoRaTx(payload, sizeof (payload)); + } else { + rfmTransmitPayload(payload, sizeof (payload), node); + } } /** @@ -276,12 +303,17 @@ */ static bool waitResponse(void) { uint8_t response[1]; - int8_t len = rfmReceivePayload(response, sizeof (response), true); + int8_t len = 0; + if (LORA) { + len = rfmLoRaRx(response, sizeof (response)); + } else { + len = rfmReceivePayload(response, sizeof (response), true); + } if (len > 0) { - // set more output power starting from -95 dBm + // set more output power starting from -100 dBm int8_t rssi = divRoundNearest(response[0], 2); - power = divRoundNearest(power + rssi - 97, 2); - rfmSetOutputPower(min(max(power, DBM_MIN), DBM_MAX)); + power = divRoundNearest(power + rssi - 98, 2); + rfmSetOutputPower(min(max(power, RFM_DBM_MIN), RFM_DBM_MAX)); return false; } @@ -289,65 +321,26 @@ return true; } -/** - * Receives data read from SD card. - * - * @param flags - */ -static void receiveData(PayloadFlags flags) { - uint8_t payload[MESSAGE_SIZE + 1]; // + address byte - uint8_t len = rfmReadPayload(payload, sizeof (payload)); - - char buf[MESSAGE_SIZE + 1]; - snprintf(buf, len, "%s", payload); - printString(buf); - _delay_ms(10); - - rfmStartReceive(false); -} - -/** - * Transmits data read from SD card. - */ -static void transmitData(void) { - uint8_t block[SD_BLOCK_SIZE]; - bool read = sdcReadSingleBlock(0, block); - if (read) { - void *start = █ - div_t packets = div(SD_BLOCK_SIZE, MESSAGE_SIZE); - for (size_t i = 0; i < packets.quot; i++) { - rfmTransmitPayload(start, MESSAGE_SIZE, NODE0); - start += MESSAGE_SIZE; - // a little break in between packets for now - _delay_ms(100); - } - if (packets.rem > 0) { - rfmTransmitPayload(start, packets.rem, NODE0); - } - } -} - int main(void) { initUSART(); initPins(); initSPI(); initI2C(); initRadioInt(); - bool sdcard = false; - - printString("Hello Radio!\r\n"); + // bool sdcard = sdcInit(); if (!RECEIVER) { // used only for tx initWatchdog(); - sdcard = sdcInit(); } // enable global interrupts sei(); + printString("Hello Radio!\r\n"); + uint8_t node = RECEIVER ? NODE1 : NODE2; - bool radio = rfmInit(FREQ, node); + bool radio = rfmInit(FREQ, node, LORA); if (!radio) { printString("Radio init failed!\r\n"); } @@ -357,7 +350,13 @@ setFrame(WHITE); fillArea(0, 0, DISPLAY_WIDTH, 16, BLACK); // initial rx mode - if (radio) rfmStartReceive(false); + if (radio) { + if (LORA) { + rfmLoRaStartRx(); + } else { + rfmStartReceive(false); + } + } } while (true) { @@ -373,31 +372,27 @@ enableSPI(); wakeTSens(); rfmWake(); - if (sdcard) { - transmitData(); - } else { - transmitTemp(NODE1); - bool timeout = waitResponse(); - if (timeout) { - if (++timeoutCount > MAX_TIMEOUTS) { - measureInts = TRANSMIT_SLOW; - timeoutCount = 0; - } - } else { + // transmit temperature + transmitTemp(NODE1); + // wait for response from receiver + bool timeout = waitResponse(); + if (timeout) { + if (++timeoutCount > MAX_TIMEOUTS) { + measureInts = TRANSMIT_SLOW; timeoutCount = 0; - measureInts = TRANSMIT_FAST; } + rfmSetOutputPower(RFM_DBM_MAX); + } else { + timeoutCount = 0; + measureInts = TRANSMIT_FAST; } sleepTSens(); rfmSleep(); disableSPI(); } } else { - PayloadFlags flags = rfmPayloadReady(); - if (flags.ready) { - handlePayload(flags); - // receiveData(flags); - } + // receive and display temperature, respond back to transmitter + receiveTemp(); } } diff --git a/librfm.a b/librfm.a index c00f9e1..e51b95d 100644 --- a/librfm.a +++ b/librfm.a Binary files differ diff --git a/librfm.h b/librfm.h index 5d80df9..1e4913b 100644 --- a/librfm.h +++ b/librfm.h @@ -12,86 +12,125 @@ #include #include -#define FIFO 0x00 -#define OP_MODE 0x01 -#define BITRATE_MSB 0x02 -#define BITRATE_LSB 0x03 -#define FDEV_MSB 0x04 -#define FDEV_LSB 0x05 -#define FRF_MSB 0x06 -#define FRF_MID 0x07 -#define FRF_LSB 0x08 -#define PA_CONFIG 0x09 -#define PA_RAMP 0x0a -#define OCP 0x0b -#define LNA 0x0c -#define RX_CONFIG 0x0d -#define RSSI_CONFIG 0x0e -#define RSSI_COLLIS 0x0f -#define RSSI_THRESH 0x10 -#define RSSI_VALUE 0x11 -#define RX_BW 0x12 -#define AFC_BW 0x13 -#define AFC_FEI 0x1a -#define PREA_DETECT 0x1f -#define RX_TO_RSSI 0x20 -#define RX_TO_PREA 0x21 -#define RX_TO_SYNC 0x22 -#define RX_DELAY 0x23 -#define OSC 0x24 -#define PREA_MSB 0x25 -#define PREA_LSB 0x26 -#define SYNC_CONFIG 0x27 -#define SYNC_VAL1 0x28 -#define SYNC_VAL2 0x29 -#define SYNC_VAL3 0x2a -#define SYNC_VAL4 0x2b -#define SYNC_VAL5 0x2c -#define SYNC_VAL6 0x2d -#define SYNC_VAL7 0x2e -#define SYNC_VAL8 0x2f -#define PCK_CONFIG1 0x30 -#define PCK_CONFIG2 0x31 -#define PAYLOAD_LEN 0x32 -#define NODE_ADDR 0x33 -#define CAST_ADDR 0x34 -#define FIFO_THRESH 0x35 -#define IMAGE_CAL 0x3b -#define TEMP 0x3c -#define LOW_BAT 0x3d -#define IRQ_FLAGS1 0x3e -#define IRQ_FLAGS2 0x3f -#define DIO_MAP1 0x40 -#define DIO_MAP2 0x41 -#define VERSION 0x42 +/* Registers shared by FSK and LoRa mode */ +#define RFM_FIFO 0x00 +#define RFM_OP_MODE 0x01 +#define RFM_FRF_MSB 0x06 +#define RFM_FRF_MID 0x07 +#define RFM_FRF_LSB 0x08 +#define RFM_PA_CONFIG 0x09 +#define RFM_PA_RAMP 0x0a +#define RFM_OCP 0x0b +#define RFM_LNA 0x0c +#define RFM_DIO_MAP1 0x40 +#define RFM_DIO_MAP2 0x41 +#define RFM_VERSION 0x42 -#define MASK_MODE 0x07 +/* FSK mode registers */ +#define RFM_FSK_BITRATE_MSB 0x02 +#define RFM_FSK_BITRATE_LSB 0x03 +#define RFM_FSK_FDEV_MSB 0x04 +#define RFM_FSK_FDEV_LSB 0x05 +#define RFM_FSK_RX_CONFIG 0x0d +#define RFM_FSK_RSSI_CONFIG 0x0e +#define RFM_FSK_RSSI_COLLIS 0x0f +#define RFM_FSK_RSSI_THRESH 0x10 +#define RFM_FSK_RSSI_VALUE 0x11 +#define RFM_FSK_RX_BW 0x12 +#define RFM_FSK_AFC_BW 0x13 +#define RFM_FSK_AFC_FEI 0x1a +#define RFM_FSK_PREA_DETECT 0x1f +#define RFM_FSK_RX_TO_RSSI 0x20 +#define RFM_FSK_RX_TO_PREA 0x21 +#define RFM_FSK_RX_TO_SYNC 0x22 +#define RFM_FSK_RX_DELAY 0x23 +#define RFM_FSK_OSC 0x24 +#define RFM_FSK_PREA_MSB 0x25 +#define RFM_FSK_PREA_LSB 0x26 +#define RFM_FSK_SYNC_CONFIG 0x27 +#define RFM_FSK_SYNC_VAL1 0x28 +#define RFM_FSK_SYNC_VAL2 0x29 +#define RFM_FSK_SYNC_VAL3 0x2a +#define RFM_FSK_SYNC_VAL4 0x2b +#define RFM_FSK_SYNC_VAL5 0x2c +#define RFM_FSK_SYNC_VAL6 0x2d +#define RFM_FSK_SYNC_VAL7 0x2e +#define RFM_FSK_SYNC_VAL8 0x2f +#define RFM_FSK_PCK_CONFIG1 0x30 +#define RFM_FSK_PCK_CONFIG2 0x31 +#define RFM_FSK_PAYLOAD_LEN 0x32 +#define RFM_FSK_NODE_ADDR 0x33 +#define RFM_FSK_CAST_ADDR 0x34 +#define RFM_FSK_FIFO_THRESH 0x35 +#define RFM_FSK_IMAGE_CAL 0x3b +#define RFM_FSK_TEMP 0x3c +#define RFM_FSK_LOW_BAT 0x3d +#define RFM_FSK_IRQ_FLAGS1 0x3e +#define RFM_FSK_IRQ_FLAGS2 0x3f -#define MODE_SLEEP 0x00 -#define MODE_STDBY 0x01 -#define MODE_FS_TX 0x02 -#define MODE_TX 0x03 -#define MODE_FS_RX 0x04 -#define MODE_RX 0x05 +/* LoRa mode registers */ +#define RFM_LORA_FIFO_ADDR_PTR 0x0d +#define RFM_LORA_FIFO_TX_ADDR 0x0e +#define RFM_LORA_FIFO_RX_ADDR 0x0f +#define RFM_LORA_FIFO_CURR_ADDR 0x10 +#define RFM_LORA_IRQ_FLAGS_MASK 0x11 +#define RFM_LORA_IRQ_FLAGS 0x12 +#define RFM_LORA_RX_BYTES_NB 0x13 +#define RFM_LORA_RX_HDR_CNT_MSB 0x14 +#define RFM_LORA_RX_HDR_CNT_LSB 0x15 +#define RFM_LORA_RX_PCK_CNT_MSB 0x16 +#define RFM_LORA_RX_PCK_CNT_LSB 0x17 +#define RFM_LORA_MODEM_STAT 0x18 +#define RFM_LORA_PCK_SNR 0x19 +#define RFM_LORA_PCK_RSSI 0x1a +#define RFM_LORA_RSSI 0x1b +#define RFM_LORA_HOP_CHANNEL 0x1c +#define RFM_LORA_MODEM_CONFIG1 0x1d +#define RFM_LORA_MODEM_CONFIG2 0x1e +#define RFM_LORA_SYMB_TIMEO_LSB 0x1f +#define RFM_LORA_PREA_LEN_MSB 0x20 +#define RFM_LORA_PREA_LEN_LSB 0x21 +#define RFM_LORA_PAYLD_LEN 0x22 +#define RFM_LORA_PAYLD_MAX_LEN 0x23 +#define RFM_LORA_HOP_PERIOD 0x24 +#define RFM_LORA_FIFO_RX_B_ADDR 0x25 +#define RFM_LORA_MODEM_CONFIG3 0x26 -#define DBM_MIN 2 -#define DBM_MAX 17 -#define PA_MIN 0 -#define PA_MAX 15 -#define PA_OFF 2 +/* Values shared by FSK and LoRa mode */ +#define RFM_MODE_SLEEP 0x00 +#define RFM_MODE_STDBY 0x01 +#define RFM_MODE_FS_TX 0x02 +#define RFM_MODE_TX 0x03 +#define RFM_MODE_FS_RX 0x04 +#define RFM_MODE_RX 0x05 // LoRa RXCONTINUOUS +#define RFM_MODE_RXSINGLE 0x06 // LoRa only +#define RFM_MODE_CAD 0x07 // LoRa only +#define RFM_MASK_MODE 0x07 -#define MESSAGE_SIZE 63 -#define F_STEP 61035 -#define CAST_ADDRESS 0x84 +#define RFM_F_STEP 61035 +#define RFM_CAST_ADDRESS 0x84 + +#define RFM_DBM_MIN 2 +#define RFM_DBM_MAX 17 +#define RFM_PA_MIN 0 +#define RFM_PA_MAX 15 +#define RFM_PA_OFF 2 + +/* FSK mode values */ +#define RFM_FSK_MSG_SIZE 63 + +/* LoRa mode values */ +// assuming 50/50 for Tx/Rx for now +#define RFM_LORA_MSG_SIZE 128 /** - * Flags for "payload ready" event. + * Flags for 'PayloadReady'/'RxDone' event. */ typedef struct { bool ready; bool crc; uint8_t rssi; -} PayloadFlags; +} RxFlags; /** * F_CPU dependent delay of 5 milliseconds. @@ -128,12 +167,13 @@ uint8_t _rfmTx(uint8_t data); /** - * Initializes the radio module with the given carrier frequency in kilohertz - * and node address. Returns true on success, false otherwise. + * Initializes the radio module in FSK or LoRa mode with the given carrier + * frequency in kilohertz and node address. Returns true on success, + * false otherwise. * * @return success */ -bool rfmInit(uint64_t freq, uint8_t node); +bool rfmInit(uint64_t freq, uint8_t node, bool lora); /** * Reads interrupt flags. Should be called when any interrupt occurs @@ -143,7 +183,8 @@ /** * Sets the "Timeout" interrupt flag, allowing to "unlock" a possibly hanging - * wait for either "PayloadReady" or "Timeout" by the radio. + * wait for either "PayloadReady" or "Timeout" by the radio in FSK mode, + * ignored in LoRa mode. */ void rfmTimeout(void); @@ -182,22 +223,25 @@ /** * Sets the radio to receive mode and maps "PayloadReady" to DIO0 and enables * or disables timeout. + * For FSK mode. * * @param timeout enable timeout */ void rfmStartReceive(bool timeout); /** - * Returns true if a "PayloadReady" interrupt arrived and clears the - * interrupt state. + * Returns true and puts the radio in standby mode if a "PayloadReady" + * interrupt arrived. + * For FSK mode. * - * @return true if "PayloadReady" + * @return flags */ -PayloadFlags rfmPayloadReady(void); +RxFlags rfmPayloadReady(void); /** * Sets the radio in standby mode, puts the payload into the given array * with the given size, and returns the length of the payload. + * For FSK mode. * * @param payload buffer for payload * @param size of payload buffer @@ -209,6 +253,7 @@ * Waits for "PayloadReady", puts the payload into the given array with the * given size, enables or disables timeout, and returns the length of the * payload, or 0 if a timeout occurred. + * For FSK mode. * * @param payload buffer for payload * @param size of payload buffer @@ -218,7 +263,8 @@ size_t rfmReceivePayload(uint8_t *payload, size_t size, bool timeout); /** - * Transmits up to 64 bytes of the given payload with the given node address. + * Transmits up to 63 bytes of the given payload with the given node address. + * For FSK mode. * * @param payload to be sent * @param size of payload @@ -227,5 +273,46 @@ */ size_t rfmTransmitPayload(uint8_t *payload, size_t size, uint8_t node); -#endif /* LIBRFM_H */ +/** + * Sets the radio in continous receive mode and maps "RxDone" to DIO0. + */ +void rfmLoRaStartRx(void); +/** + * Returns true if a "RxDone" interrupt arrived. + * + * @return flags + */ +RxFlags rfmLoRaRxDone(void); + +/** + * Puts the received payload into the given array with the given size, + * and returns the length of the payload. + * + * @param payload buffer for payload + * @param size of payload buffer + * @return payload bytes actually received + */ +size_t rfmLoRaRxRead(uint8_t *payload, size_t size); + +/** + * Sets the radio in single receive mode, waits for "RxDone" with timeout, + * puts the payload into the given array with the given size, and returns + * the length of the payload, or 0 if a timeout occurred. + * + * @param payload buffer for payload + * @param size of payload buffer + * @return payload bytes actually received + */ +size_t rfmLoRaRx(uint8_t *payload, size_t size); + +/** + * Transmits up to 128 bytes of the given payload. + * + * @param payload to be sent + * @param size of payload + * @return payload bytes actually sent + */ +size_t rfmLoRaTx(uint8_t *payload, size_t size); + +#endif /* LIBRFM_H */