This is a copy of the community maintained fork of the open firmware which powers RNode devices. This version will have support for the hardware made by Mees Electronics.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

774 lines
19 KiB

#include <Arduino.h>
7 years ago
#include <SPI.h>
#include "Utilities.h"
7 years ago
FIFOBuffer serialFIFO;
uint8_t serialBuffer[CONFIG_UART_BUFFER_SIZE+1];
FIFOBuffer16 packet_starts;
size_t packet_starts_buf[CONFIG_QUEUE_MAX_LENGTH+1];
FIFOBuffer16 packet_lengths;
size_t packet_lengths_buf[CONFIG_QUEUE_MAX_LENGTH+1];
uint8_t packet_queue[CONFIG_QUEUE_SIZE];
volatile uint8_t queue_height = 0;
volatile size_t queued_bytes = 0;
volatile size_t queue_cursor = 0;
volatile size_t current_packet_start = 0;
volatile bool serial_buffering = false;
char sbuf[128];
7 years ago
void setup() {
#if MCU_VARIANT == MCU_ESP32
delay(1500);
EEPROM.begin(EEPROM_SIZE);
Serial.setRxBufferSize(CONFIG_UART_BUFFER_SIZE);
#endif
7 years ago
// Seed the PRNG
randomSeed(analogRead(0));
// Initialise serial communication
memset(serialBuffer, 0, sizeof(serialBuffer));
fifo_init(&serialFIFO, serialBuffer, CONFIG_UART_BUFFER_SIZE);
7 years ago
Serial.begin(serial_baudrate);
while (!Serial);
serial_interrupt_init();
7 years ago
// Configure input and output pins
pinMode(pin_led_rx, OUTPUT);
pinMode(pin_led_tx, OUTPUT);
// Initialise buffers
7 years ago
memset(pbuf, 0, sizeof(pbuf));
memset(cbuf, 0, sizeof(cbuf));
memset(packet_queue, 0, sizeof(packet_queue));
memset(packet_starts_buf, 0, sizeof(packet_starts_buf));
fifo16_init(&packet_starts, packet_starts_buf, CONFIG_QUEUE_MAX_LENGTH);
memset(packet_lengths_buf, 0, sizeof(packet_starts_buf));
fifo16_init(&packet_lengths, packet_lengths_buf, CONFIG_QUEUE_MAX_LENGTH);
7 years ago
// Set chip select, reset and interrupt
// pins for the LoRa module
LoRa.setPins(pin_cs, pin_reset, pin_dio);
#if MCU_VARIANT == MCU_ESP32
radio_locked = true;
radio_online = false;
hw_ready = false;
#endif
// Validate board health, EEPROM and config
validateStatus();
7 years ago
}
void lora_receive() {
if (!implicit) {
LoRa.receive();
} else {
LoRa.receive(implicit_l);
}
}
7 years ago
bool startRadio() {
update_radio_lock();
if (!radio_online) {
if (!radio_locked && hw_ready) {
7 years ago
if (!LoRa.begin(lora_freq)) {
// The radio could not be started.
// Indicate this failure over both the
// serial port and with the onboard LEDs
kiss_indicate_error(ERROR_INITRADIO);
led_indicate_error(0);
return false;
7 years ago
} else {
radio_online = true;
setTXPower();
setBandwidth();
setSpreadingFactor();
setCodingRate();
7 years ago
getFrequency();
LoRa.enableCrc();
#if MCU_VARIANT != MCU_ESP32
LoRa.onReceive(receive_callback);
#endif
7 years ago
lora_receive();
7 years ago
// Flash an info pattern to indicate
// that the radio is now on
led_indicate_info(3);
return true;
7 years ago
}
} else {
// Flash a warning pattern to indicate
// that the radio was locked, and thus
// not started
led_indicate_warning(3);
return false;
7 years ago
}
} else {
// If radio is already on, we silently
// ignore the request.
return true;
7 years ago
}
}
void stopRadio() {
LoRa.end();
radio_online = false;
}
void update_radio_lock() {
if (lora_freq != 0 && lora_bw != 0 && lora_txp != 0xFF && lora_sf != 0) {
radio_locked = false;
} else {
radio_locked = true;
}
}
void receive_callback(int packet_size) {
if (!promisc) {
// The standard operating mode allows large
// packets with a payload up to 500 bytes,
// by combining two raw LoRa packets.
// We read the 1-byte header and extract
// packet sequence number and split flags
uint8_t header = LoRa.read(); packet_size--;
uint8_t sequence = packetSequence(header);
bool ready = false;
if (isSplitPacket(header) && seq == SEQ_UNSET) {
// This is the first part of a split
// packet, so we set the seq variable
// and add the data to the buffer
7 years ago
read_len = 0;
seq = sequence;
last_rssi = LoRa.packetRssi();
last_snr_raw = LoRa.packetSnrRaw();
getPacketData(packet_size);
} else if (isSplitPacket(header) && seq == sequence) {
// This is the second part of a split
// packet, so we add it to the buffer
// and set the ready flag.
last_rssi = (last_rssi+LoRa.packetRssi())/2;
last_snr_raw = (last_snr_raw+LoRa.packetSnrRaw())/2;
getPacketData(packet_size);
7 years ago
seq = SEQ_UNSET;
ready = true;
} else if (isSplitPacket(header) && seq != sequence) {
// This split packet does not carry the
// same sequence id, so we must assume
// that we are seeing the first part of
// a new split packet.
read_len = 0;
seq = sequence;
last_rssi = LoRa.packetRssi();
last_snr_raw = LoRa.packetSnrRaw();
getPacketData(packet_size);
} else if (!isSplitPacket(header)) {
// This is not a split packet, so we
// just read it and set the ready
// flag to true.
if (seq != SEQ_UNSET) {
// If we already had part of a split
// packet in the buffer, we clear it.
read_len = 0;
seq = SEQ_UNSET;
}
last_rssi = LoRa.packetRssi();
last_snr_raw = LoRa.packetSnrRaw();
getPacketData(packet_size);
ready = true;
7 years ago
}
if (ready) {
// We first signal the RSSI of the
// recieved packet to the host.
kiss_indicate_stat_rssi();
kiss_indicate_stat_snr();
// And then write the entire packet
Serial.write(FEND);
Serial.write(CMD_DATA);
for (int i = 0; i < read_len; i++) {
uint8_t byte = pbuf[i];
if (byte == FEND) { Serial.write(FESC); byte = TFEND; }
if (byte == FESC) { Serial.write(FESC); byte = TFESC; }
Serial.write(byte);
}
Serial.write(FEND);
read_len = 0;
}
} else {
// In promiscuous mode, raw packets are
// output directly to the host
read_len = 0;
7 years ago
last_rssi = LoRa.packetRssi();
last_snr_raw = LoRa.packetSnrRaw();
7 years ago
getPacketData(packet_size);
// We first signal the RSSI of the
// recieved packet to the host.
kiss_indicate_stat_rssi();
kiss_indicate_stat_snr();
7 years ago
// And then write the entire packet
Serial.write(FEND);
Serial.write(CMD_DATA);
for (int i = 0; i < read_len; i++) {
uint8_t byte = pbuf[i];
if (byte == FEND) { Serial.write(FESC); byte = TFEND; }
if (byte == FESC) { Serial.write(FESC); byte = TFESC; }
Serial.write(byte);
}
Serial.write(FEND);
read_len = 0;
7 years ago
}
}
bool queueFull() {
return (queue_height >= CONFIG_QUEUE_MAX_LENGTH || queued_bytes >= CONFIG_QUEUE_SIZE);
}
volatile bool queue_flushing = false;
void flushQueue(void) {
if (!queue_flushing) {
queue_flushing = true;
size_t processed = 0;
#if MCU_VARIANT == MCU_ESP32
while (!fifo16_isempty(&packet_starts)) {
#else
while (!fifo16_isempty_locked(&packet_starts)) {
#endif
size_t start = fifo16_pop(&packet_starts);
size_t length = fifo16_pop(&packet_lengths);
if (length >= MIN_L && length <= MTU) {
for (size_t i = 0; i < length; i++) {
size_t pos = (start+i)%CONFIG_QUEUE_SIZE;
tbuf[i] = packet_queue[pos];
}
transmit(length);
processed++;
}
}
}
queue_height = 0;
queued_bytes = 0;
queue_flushing = false;
}
7 years ago
void transmit(size_t size) {
if (radio_online) {
if (!promisc) {
led_tx_on();
size_t written = 0;
uint8_t header = random(256) & 0xF0;
7 years ago
if (size > SINGLE_MTU - HEADER_L) {
header = header | FLAG_SPLIT;
}
7 years ago
LoRa.beginPacket();
LoRa.write(header); written++;
7 years ago
for (size_t i; i < size; i++) {
LoRa.write(tbuf[i]);
written++;
7 years ago
if (written == 255) {
LoRa.endPacket();
LoRa.beginPacket();
LoRa.write(header);
written = 1;
}
7 years ago
}
LoRa.endPacket();
led_tx_off();
lora_receive();
} else {
// In promiscuous mode, we only send out
// plain raw LoRa packets with a maximum
// payload of 255 bytes
led_tx_on();
size_t written = 0;
// Cap packets at 255 bytes
if (size > SINGLE_MTU) {
size = SINGLE_MTU;
}
// If implicit header mode has been set,
// set packet length to payload data length
if (!implicit) {
LoRa.beginPacket();
} else {
LoRa.beginPacket(size);
}
for (size_t i; i < size; i++) {
LoRa.write(tbuf[i]);
written++;
}
LoRa.endPacket();
led_tx_off();
lora_receive();
}
7 years ago
} else {
kiss_indicate_error(ERROR_TXFAILED);
led_indicate_error(5);
}
}
void serialCallback(uint8_t sbyte) {
if (IN_FRAME && sbyte == FEND && command == CMD_DATA) {
IN_FRAME = false;
if (!fifo16_isfull(&packet_starts) && queued_bytes < CONFIG_QUEUE_SIZE) {
size_t s = current_packet_start;
size_t e = queue_cursor-1; if (e == -1) e = CONFIG_QUEUE_SIZE-1;
size_t l;
if (s != e) {
l = (s < e) ? e - s + 1 : CONFIG_QUEUE_SIZE - s + e + 1;
} else {
l = 1;
}
if (l >= MIN_L) {
queue_height++;
fifo16_push(&packet_starts, s);
fifo16_push(&packet_lengths, l);
current_packet_start = queue_cursor;
}
}
7 years ago
} else if (sbyte == FEND) {
IN_FRAME = true;
command = CMD_UNKNOWN;
frame_len = 0;
} else if (IN_FRAME && frame_len < MTU) {
// Have a look at the command byte first
if (frame_len == 0 && command == CMD_UNKNOWN) {
command = sbyte;
} else if (command == CMD_DATA) {
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
if (queue_height < CONFIG_QUEUE_MAX_LENGTH && queued_bytes < CONFIG_QUEUE_SIZE) {
queued_bytes++;
packet_queue[queue_cursor++] = sbyte;
if (queue_cursor == CONFIG_QUEUE_SIZE) queue_cursor = 0;
}
7 years ago
}
} else if (command == CMD_FREQUENCY) {
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
cbuf[frame_len++] = sbyte;
}
if (frame_len == 4) {
uint32_t freq = (uint32_t)cbuf[0] << 24 | (uint32_t)cbuf[1] << 16 | (uint32_t)cbuf[2] << 8 | (uint32_t)cbuf[3];
if (freq == 0) {
kiss_indicate_frequency();
} else {
lora_freq = freq;
7 years ago
if (op_mode == MODE_HOST) setFrequency();
7 years ago
kiss_indicate_frequency();
}
}
} else if (command == CMD_BANDWIDTH) {
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
cbuf[frame_len++] = sbyte;
}
if (frame_len == 4) {
uint32_t bw = (uint32_t)cbuf[0] << 24 | (uint32_t)cbuf[1] << 16 | (uint32_t)cbuf[2] << 8 | (uint32_t)cbuf[3];
if (bw == 0) {
kiss_indicate_bandwidth();
} else {
lora_bw = bw;
7 years ago
if (op_mode == MODE_HOST) setBandwidth();
7 years ago
kiss_indicate_bandwidth();
}
}
} else if (command == CMD_TXPOWER) {
if (sbyte == 0xFF) {
kiss_indicate_txpower();
} else {
int txp = sbyte;
if (txp > 17) txp = 17;
lora_txp = txp;
7 years ago
if (op_mode == MODE_HOST) setTXPower();
7 years ago
kiss_indicate_txpower();
}
} else if (command == CMD_SF) {
if (sbyte == 0xFF) {
kiss_indicate_spreadingfactor();
} else {
int sf = sbyte;
if (sf < 6) sf = 6;
7 years ago
if (sf > 12) sf = 12;
lora_sf = sf;
7 years ago
if (op_mode == MODE_HOST) setSpreadingFactor();
7 years ago
kiss_indicate_spreadingfactor();
}
} else if (command == CMD_CR) {
if (sbyte == 0xFF) {
kiss_indicate_codingrate();
} else {
int cr = sbyte;
if (cr < 5) cr = 5;
if (cr > 8) cr = 8;
lora_cr = cr;
7 years ago
if (op_mode == MODE_HOST) setCodingRate();
kiss_indicate_codingrate();
}
} else if (command == CMD_IMPLICIT) {
set_implicit_length(sbyte);
kiss_indicate_implicit_length();
7 years ago
} else if (command == CMD_RADIO_STATE) {
if (sbyte == 0xFF) {
kiss_indicate_radiostate();
} else if (sbyte == 0x00) {
stopRadio();
kiss_indicate_radiostate();
} else if (sbyte == 0x01) {
startRadio();
kiss_indicate_radiostate();
}
} else if (command == CMD_STAT_RX) {
kiss_indicate_stat_rx();
} else if (command == CMD_STAT_TX) {
kiss_indicate_stat_tx();
} else if (command == CMD_STAT_RSSI) {
kiss_indicate_stat_rssi();
} else if (command == CMD_RADIO_LOCK) {
update_radio_lock();
kiss_indicate_radio_lock();
} else if (command == CMD_BLINK) {
led_indicate_info(sbyte);
} else if (command == CMD_RANDOM) {
kiss_indicate_random(getRandom());
} else if (command == CMD_DETECT) {
if (sbyte == DETECT_REQ) {
kiss_indicate_detect();
}
} else if (command == CMD_PROMISC) {
if (sbyte == 0x01) {
promisc_enable();
} else if (sbyte == 0x00) {
promisc_disable();
}
kiss_indicate_promisc();
} else if (command == CMD_READY) {
if (!queueFull()) {
kiss_indicate_ready();
} else {
kiss_indicate_not_ready();
}
} else if (command == CMD_UNLOCK_ROM) {
if (sbyte == ROM_UNLOCK_BYTE) {
unlock_rom();
}
} else if (command == CMD_RESET) {
if (sbyte == CMD_RESET_BYTE) {
hard_reset();
}
} else if (command == CMD_ROM_READ) {
kiss_dump_eeprom();
} else if (command == CMD_ROM_WRITE) {
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
cbuf[frame_len++] = sbyte;
}
if (frame_len == 2) {
eeprom_write(cbuf[0], cbuf[1]);
}
} else if (command == CMD_FW_VERSION) {
kiss_indicate_version();
} else if (command == CMD_PLATFORM) {
kiss_indicate_platform();
} else if (command == CMD_MCU) {
kiss_indicate_mcu();
} else if (command == CMD_CONF_SAVE) {
eeprom_conf_save();
} else if (command == CMD_CONF_DELETE) {
eeprom_conf_delete();
7 years ago
}
}
}
void updateModemStatus() {
uint8_t status = LoRa.modemStatus();
last_status_update = millis();
6 years ago
if (status & SIG_DETECT == SIG_DETECT) { stat_signal_detected = true; } else { stat_signal_detected = false; }
if (status & SIG_SYNCED == SIG_SYNCED) { stat_signal_synced = true; } else { stat_signal_synced = false; }
if (status & RX_ONGOING == RX_ONGOING) { stat_rx_ongoing = true; } else { stat_rx_ongoing = false; }
if (stat_signal_detected || stat_signal_synced || stat_rx_ongoing) {
if (dcd_count < dcd_threshold) {
dcd_count++;
dcd = true;
} else {
dcd = true;
dcd_led = true;
}
} else {
if (dcd_count > 0) {
dcd_count--;
} else {
dcd_led = false;
}
dcd = false;
}
if (dcd_led) {
led_rx_on();
} else {
led_rx_off();
}
}
void checkModemStatus() {
if (millis()-last_status_update >= status_interval_ms) {
updateModemStatus();
}
}
void validateStatus() {
#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
uint8_t boot_flags = OPTIBOOT_MCUSR;
uint8_t F_POR = PORF;
uint8_t F_BOR = BORF;
uint8_t F_WDR = WDRF;
#elif MCU_VARIANT == MCU_ESP32
// TODO: Get ESP32 boot flags
uint8_t boot_flags = 0x02;
uint8_t F_POR = 0x00;
uint8_t F_BOR = 0x00;
uint8_t F_WDR = 0x01;
#endif
if (boot_flags & (1<<F_POR)) {
boot_vector = START_FROM_POWERON;
} else if (boot_flags & (1<<F_BOR)) {
boot_vector = START_FROM_BROWNOUT;
} else if (boot_flags & (1<<F_WDR)) {
boot_vector = START_FROM_BOOTLOADER;
} else {
Serial.write("Error, indeterminate boot vector\r\n");
led_indicate_boot_error();
}
if (boot_vector == START_FROM_BOOTLOADER || boot_vector == START_FROM_POWERON) {
if (eeprom_lock_set()) {
if (eeprom_product_valid() && eeprom_model_valid() && eeprom_hwrev_valid()) {
if (eeprom_checksum_valid()) {
hw_ready = true;
if (eeprom_have_conf()) {
eeprom_conf_load();
op_mode = MODE_TNC;
startRadio();
}
}
} else {
hw_ready = false;
}
} else {
hw_ready = false;
}
} else {
hw_ready = false;
Serial.write("Error, incorrect boot vector\r\n");
led_indicate_boot_error();
}
}
7 years ago
void loop() {
if (radio_online) {
checkModemStatus();
#if MCU_VARIANT == MCU_ESP32
int packet_size = LoRa.parsePacket();
if (packet_size) {
receive_callback(packet_size);
}
#endif
if (queue_height > 0) {
if (!dcd_waiting) updateModemStatus();
if (!dcd && !dcd_led) {
if (dcd_waiting) delay(lora_rx_turnaround_ms);
updateModemStatus();
if (!dcd) {
dcd_waiting = false;
flushQueue();
}
} else {
dcd_waiting = true;
}
}
} else {
if (hw_ready) {
led_indicate_standby();
} else {
led_indicate_not_ready();
stopRadio();
}
}
#if MCU_VARIANT == MCU_ESP32
buffer_serial();
#endif
#if MCU_VARIANT != MCU_ESP32
if (!fifo_isempty_locked(&serialFIFO)) serial_poll();
#else
if (!fifo_isempty(&serialFIFO)) serial_poll();
#endif
}
volatile bool serial_polling = false;
void serial_poll() {
serial_polling = true;
#if MCU_VARIANT != MCU_ESP32
while (!fifo_isempty_locked(&serialFIFO)) {
#else
while (!fifo_isempty(&serialFIFO)) {
#endif
char sbyte = fifo_pop(&serialFIFO);
7 years ago
serialCallback(sbyte);
}
serial_polling = false;
}
#define MAX_CYCLES 20
void buffer_serial() {
if (!serial_buffering) {
serial_buffering = true;
uint8_t c = 0;
while (c < MAX_CYCLES && Serial.available()) {
c++;
#if MCU_VARIANT != MCU_ESP32
if (!fifo_isfull_locked(&serialFIFO)) {
fifo_push_locked(&serialFIFO, Serial.read());
}
#else
if (!fifo_isfull(&serialFIFO)) {
fifo_push(&serialFIFO, Serial.read());
}
#endif
}
serial_buffering = false;
7 years ago
}
}
void serial_interrupt_init() {
#if MCU_VARIANT == MCU_1284P
TCCR3A = 0;
TCCR3B = _BV(CS10) |
_BV(WGM33)|
_BV(WGM32);
// Buffer incoming frames every 1ms
ICR3 = 16000;
TIMSK3 = _BV(ICIE3);
#elif MCU_VARIANT == MCU_2560
// TODO: This should probably be updated for
// atmega2560 support. Might be source of
// reported issues from snh.
TCCR3A = 0;
TCCR3B = _BV(CS10) |
_BV(WGM33)|
_BV(WGM32);
// Buffer incoming frames every 1ms
ICR3 = 16000;
TIMSK3 = _BV(ICIE3);
#elif MCU_VARIANT == MCU_ESP32
// No interrupt-based polling on ESP32
#endif
}
#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
ISR(TIMER3_CAPT_vect) {
buffer_serial();
}
#endif