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.

1651 lines
45 KiB

5 months ago
// Copyright (C) 2024, Mark Qvist
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#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;
uint16_t packet_starts_buf[CONFIG_QUEUE_MAX_LENGTH+1];
FIFOBuffer16 packet_lengths;
uint16_t packet_lengths_buf[CONFIG_QUEUE_MAX_LENGTH+1];
uint8_t packet_queue[CONFIG_QUEUE_SIZE];
volatile uint8_t queue_height = 0;
volatile uint16_t queued_bytes = 0;
volatile uint16_t queue_cursor = 0;
volatile uint16_t current_packet_start = 0;
volatile bool serial_buffering = false;
#if HAS_BLUETOOTH || HAS_BLE == true
bool bt_init_ran = false;
#endif
#if HAS_CONSOLE
#include "Console.h"
#endif
#if PLATFORM == PLATFORM_ESP32 || PLATFORM == PLATFORM_NRF52
#define MODEM_QUEUE_SIZE 4
typedef struct {
size_t len;
int rssi;
int snr_raw;
uint8_t data[];
} modem_packet_t;
static xQueueHandle modem_packet_queue = NULL;
#endif
char sbuf[128];
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
bool packet_ready = false;
#endif
7 years ago
void setup() {
#if MCU_VARIANT == MCU_ESP32
boot_seq();
EEPROM.begin(EEPROM_SIZE);
Serial.setRxBufferSize(CONFIG_UART_BUFFER_SIZE);
#if BOARD_MODEL == BOARD_TDECK
pinMode(pin_poweron, OUTPUT);
digitalWrite(pin_poweron, HIGH);
pinMode(SD_CS, OUTPUT);
pinMode(DISPLAY_CS, OUTPUT);
digitalWrite(SD_CS, HIGH);
digitalWrite(DISPLAY_CS, HIGH);
pinMode(DISPLAY_BL_PIN, OUTPUT);
#endif
#endif
#if MCU_VARIANT == MCU_NRF52
if (!eeprom_begin()) {
Serial.write("EEPROM initialisation failed.\r\n");
}
#endif
// Seed the PRNG for CSMA R-value selection
# if MCU_VARIANT == MCU_ESP32
// On ESP32, get the seed value from the
// hardware RNG
int seed_val = (int)esp_random();
#else
// Otherwise, get a pseudo-random seed
// value from an unconnected analog pin
int seed_val = analogRead(0);
#endif
randomSeed(seed_val);
7 years ago
// Initialise serial communication
memset(serialBuffer, 0, sizeof(serialBuffer));
fifo_init(&serialFIFO, serialBuffer, CONFIG_UART_BUFFER_SIZE);
7 years ago
Serial.begin(serial_baudrate);
#if HAS_NP
led_init();
#endif
#if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_RNODE_NG_22 && BOARD_MODEL != BOARD_TBEAM_S_V1
// Some boards need to wait until the hardware UART is set up before booting
// the full firmware. In the case of the RAK4631, the line below will wait
// until a serial connection is actually established with a master. Thus, it
// is disabled on this platform.
while (!Serial);
#endif
7 years ago
serial_interrupt_init();
7 years ago
// Configure input and output pins
#if HAS_INPUT
input_init();
#endif
#if HAS_NP == false
pinMode(pin_led_rx, OUTPUT);
pinMode(pin_led_tx, OUTPUT);
#endif
7 years ago
#if HAS_TCXO == true
if (pin_tcxo_enable != -1) {
pinMode(pin_tcxo_enable, OUTPUT);
digitalWrite(pin_tcxo_enable, HIGH);
}
#endif
// Initialise buffers
7 years ago
memset(pbuf, 0, sizeof(pbuf));
memset(cmdbuf, 0, sizeof(cmdbuf));
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
#if PLATFORM == PLATFORM_ESP32 || PLATFORM == PLATFORM_NRF52
modem_packet_queue = xQueueCreate(MODEM_QUEUE_SIZE, sizeof(modem_packet_t*));
#endif
7 years ago
// Set chip select, reset and interrupt
// pins for the LoRa module
#if MODEM == SX1276 || MODEM == SX1278
LoRa->setPins(pin_cs, pin_reset, pin_dio, pin_busy);
#elif MODEM == SX1262
LoRa->setPins(pin_cs, pin_reset, pin_dio, pin_busy, pin_rxen);
#elif MODEM == SX1280
LoRa->setPins(pin_cs, pin_reset, pin_dio, pin_busy, pin_rxen, pin_txen);
#endif
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
init_channel_stats();
// Check installed transceiver chip and
// probe boot parameters.
if (LoRa->preInit()) {
modem_installed = true;
#if HAS_INPUT
// Skip quick-reset console activation
#else
uint32_t lfr = LoRa->getFrequency();
if (lfr == 0) {
// Normal boot
} else if (lfr == M_FRQ_R) {
// Quick reboot
#if HAS_CONSOLE
if (rtc_get_reset_reason(0) == POWERON_RESET) {
console_active = true;
}
#endif
} else {
// Unknown boot
}
LoRa->setFrequency(M_FRQ_S);
#endif
} else {
modem_installed = false;
}
#else
// Older variants only came with SX1276/78 chips,
// so assume that to be the case for now.
modem_installed = true;
#endif
#if HAS_DISPLAY
#if HAS_EEPROM
if (EEPROM.read(eeprom_addr(ADDR_CONF_DSET)) != CONF_OK_BYTE) {
#elif MCU_VARIANT == MCU_NRF52
if (eeprom_read(eeprom_addr(ADDR_CONF_DSET)) != CONF_OK_BYTE) {
#endif
eeprom_update(eeprom_addr(ADDR_CONF_DSET), CONF_OK_BYTE);
eeprom_update(eeprom_addr(ADDR_CONF_DINT), 0xFF);
}
display_unblank();
disp_ready = display_init();
update_display();
#endif
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
#if HAS_PMU == true
pmu_ready = init_pmu();
#endif
#if HAS_BLUETOOTH || HAS_BLE == true
bt_init();
bt_init_ran = true;
#endif
if (console_active) {
2 years ago
#if HAS_CONSOLE
console_start();
#else
kiss_indicate_reset();
#endif
} else {
kiss_indicate_reset();
}
#endif
// Validate board health, EEPROM and config
validate_status();
if (op_mode != MODE_TNC) LoRa->setFrequency(0);
7 years ago
}
void lora_receive() {
if (!implicit) {
LoRa->receive();
} else {
LoRa->receive(implicit_l);
}
}
inline void kiss_write_packet() {
serial_write(FEND);
serial_write(CMD_DATA);
for (uint16_t i = 0; i < read_len; i++) {
#if MCU_VARIANT == MCU_NRF52
portENTER_CRITICAL();
uint8_t byte = pbuf[i];
portEXIT_CRITICAL();
#else
uint8_t byte = pbuf[i];
#endif
if (byte == FEND) { serial_write(FESC); byte = TFEND; }
if (byte == FESC) { serial_write(FESC); byte = TFESC; }
serial_write(byte);
7 years ago
}
serial_write(FEND);
read_len = 0;
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
packet_ready = false;
#endif
5 months ago
#if MCU_VARIANT == MCU_ESP32
#if HAS_BLE
bt_flush();
#endif
#endif
7 years ago
}
inline void getPacketData(uint16_t len) {
#if MCU_VARIANT != MCU_NRF52
while (len-- && read_len < MTU) {
pbuf[read_len++] = LoRa->read();
}
#else
BaseType_t int_mask = taskENTER_CRITICAL_FROM_ISR();
while (len-- && read_len < MTU) {
pbuf[read_len++] = LoRa->read();
}
taskEXIT_CRITICAL_FROM_ISR(int_mask);
#endif
}
void ISR_VECT receive_callback(int packet_size) {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
BaseType_t int_mask;
#endif
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
#if MCU_VARIANT == MCU_NRF52
int_mask = taskENTER_CRITICAL_FROM_ISR(); read_len = 0; taskEXIT_CRITICAL_FROM_ISR(int_mask);
#else
read_len = 0;
#endif
seq = sequence;
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
last_rssi = LoRa->packetRssi();
last_snr_raw = LoRa->packetSnrRaw();
#endif
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.
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
last_rssi = (last_rssi+LoRa->packetRssi())/2;
last_snr_raw = (last_snr_raw+LoRa->packetSnrRaw())/2;
#endif
getPacketData(packet_size);
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.
#if MCU_VARIANT == MCU_NRF52
int_mask = taskENTER_CRITICAL_FROM_ISR(); read_len = 0; taskEXIT_CRITICAL_FROM_ISR(int_mask);
#else
read_len = 0;
#endif
seq = sequence;
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
last_rssi = LoRa->packetRssi();
last_snr_raw = LoRa->packetSnrRaw();
#endif
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.
#if MCU_VARIANT == MCU_NRF52
int_mask = taskENTER_CRITICAL_FROM_ISR(); read_len = 0; taskEXIT_CRITICAL_FROM_ISR(int_mask);
#else
read_len = 0;
#endif
seq = SEQ_UNSET;
}
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
last_rssi = LoRa->packetRssi();
last_snr_raw = LoRa->packetSnrRaw();
#endif
getPacketData(packet_size);
ready = true;
}
7 years ago
if (ready) {
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
// 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
kiss_write_packet();
#else
// Allocate packet struct, but abort if there
// is not enough memory available.
modem_packet_t *modem_packet = (modem_packet_t*)malloc(sizeof(modem_packet_t) + read_len);
if(!modem_packet) { memory_low = true; return; }
// Get packet RSSI and SNR
#if MCU_VARIANT == MCU_ESP32
modem_packet->snr_raw = LoRa->packetSnrRaw();
modem_packet->rssi = LoRa->packetRssi(modem_packet->snr_raw);
#endif
// Send packet to event queue, but free the
// allocated memory again if the queue is
// unable to receive the packet.
modem_packet->len = read_len;
memcpy(modem_packet->data, pbuf, read_len);
if (!modem_packet_queue || xQueueSendFromISR(modem_packet_queue, &modem_packet, NULL) != pdPASS) {
free(modem_packet);
}
#endif
}
} else {
// In promiscuous mode, raw packets are
// output directly to the host
read_len = 0;
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
last_rssi = LoRa->packetRssi();
last_snr_raw = LoRa->packetSnrRaw();
getPacketData(packet_size);
// 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
kiss_write_packet();
#else
getPacketData(packet_size);
packet_ready = true;
#endif
}
}
bool startRadio() {
update_radio_lock();
2 years ago
if (!radio_online && !console_active) {
if (!radio_locked && hw_ready) {
if (!LoRa->begin(lora_freq)) {
// The radio could not be started.
// Indicate this failure over both the
// serial port and with the onboard LEDs
radio_error = true;
kiss_indicate_error(ERROR_INITRADIO);
led_indicate_error(0);
return false;
} else {
radio_online = true;
init_channel_stats();
setTXPower();
setBandwidth();
setSpreadingFactor();
setCodingRate();
getFrequency();
LoRa->enableCrc();
LoRa->onReceive(receive_callback);
lora_receive();
// Flash an info pattern to indicate
// that the radio is now on
kiss_indicate_radiostate();
led_indicate_info(3);
return true;
}
} else {
// Flash a warning pattern to indicate
// that the radio was locked, and thus
// not started
radio_online = false;
kiss_indicate_radiostate();
led_indicate_warning(3);
return false;
7 years ago
}
} else {
// If radio is already on, we silently
// ignore the request.
kiss_indicate_radiostate();
return true;
}
}
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;
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;
led_tx_on();
uint16_t processed = 0;
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
while (!fifo16_isempty(&packet_starts)) {
#else
while (!fifo16_isempty_locked(&packet_starts)) {
#endif
uint16_t start = fifo16_pop(&packet_starts);
uint16_t length = fifo16_pop(&packet_lengths);
if (length >= MIN_L && length <= MTU) {
for (uint16_t i = 0; i < length; i++) {
uint16_t pos = (start+i)%CONFIG_QUEUE_SIZE;
tbuf[i] = packet_queue[pos];
}
transmit(length);
processed++;
}
}
lora_receive();
led_tx_off();
post_tx_yield_timeout = millis()+(lora_post_tx_yield_slots*csma_slot_ms);
}
queue_height = 0;
queued_bytes = 0;
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
update_airtime();
#endif
queue_flushing = false;
#if HAS_DISPLAY
display_tx = true;
#endif
}
#define PHY_HEADER_LORA_SYMBOLS 8
void add_airtime(uint16_t written) {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
float packet_cost_ms = 0.0;
float payload_cost_ms = ((float)written * lora_us_per_byte)/1000.0;
packet_cost_ms += payload_cost_ms;
packet_cost_ms += (lora_preamble_symbols+4.25)*lora_symbol_time_ms;
packet_cost_ms += PHY_HEADER_LORA_SYMBOLS * lora_symbol_time_ms;
uint16_t cb = current_airtime_bin();
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
airtime_bins[cb] += packet_cost_ms;
airtime_bins[nb] = 0;
#endif
}
void update_airtime() {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
uint16_t cb = current_airtime_bin();
uint16_t pb = cb-1; if (cb-1 < 0) { pb = AIRTIME_BINS-1; }
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
airtime_bins[nb] = 0;
airtime = (float)(airtime_bins[cb]+airtime_bins[pb])/(2.0*AIRTIME_BINLEN_MS);
uint32_t longterm_airtime_sum = 0;
for (uint16_t bin = 0; bin < AIRTIME_BINS; bin++) {
longterm_airtime_sum += airtime_bins[bin];
}
longterm_airtime = (float)longterm_airtime_sum/(float)AIRTIME_LONGTERM_MS;
float longterm_channel_util_sum = 0.0;
for (uint16_t bin = 0; bin < AIRTIME_BINS; bin++) {
longterm_channel_util_sum += longterm_bins[bin];
}
longterm_channel_util = (float)longterm_channel_util_sum/(float)AIRTIME_BINS;
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
1 year ago
update_csma_p();
#endif
kiss_indicate_channel_stats();
#endif
}
void transmit(uint16_t size) {
7 years ago
if (radio_online) {
if (!promisc) {
uint16_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
3 years ago
for (uint16_t i=0; i < size; i++) {
LoRa->write(tbuf[i]);
written++;
7 years ago
if (written == 255 && isSplitPacket(header)) {
if (!LoRa->endPacket()) {
kiss_indicate_error(ERROR_MODEM_TIMEOUT);
kiss_indicate_error(ERROR_TXFAILED);
led_indicate_error(5);
hard_reset();
}
add_airtime(written);
LoRa->beginPacket();
LoRa->write(header);
written = 1;
}
7 years ago
}
if (!LoRa->endPacket()) {
kiss_indicate_error(ERROR_MODEM_TIMEOUT);
kiss_indicate_error(ERROR_TXFAILED);
led_indicate_error(5);
hard_reset();
}
add_airtime(written);
} else {
// In promiscuous mode, we only send out
// plain raw LoRa packets with a maximum
// payload of 255 bytes
led_tx_on();
uint16_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);
}
3 years ago
for (uint16_t i=0; i < size; i++) {
LoRa->write(tbuf[i]);
written++;
}
LoRa->endPacket(); add_airtime(written);
}
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) {
uint16_t s = current_packet_start;
3 years ago
int16_t e = queue_cursor-1; if (e == -1) e = CONFIG_QUEUE_SIZE-1;
uint16_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 (bt_state != BT_STATE_CONNECTED) {
cable_state = CABLE_STATE_CONNECTED;
}
7 years ago
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;
}
if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte;
7 years ago
}
if (frame_len == 4) {
uint32_t freq = (uint32_t)cmdbuf[0] << 24 | (uint32_t)cmdbuf[1] << 16 | (uint32_t)cmdbuf[2] << 8 | (uint32_t)cmdbuf[3];
7 years ago
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;
}
if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte;
7 years ago
}
if (frame_len == 4) {
uint32_t bw = (uint32_t)cmdbuf[0] << 24 | (uint32_t)cmdbuf[1] << 16 | (uint32_t)cmdbuf[2] << 8 | (uint32_t)cmdbuf[3];
7 years ago
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 MODEM == SX1262
if (txp > 22) txp = 22;
#else
if (txp > 17) txp = 17;
#endif
7 years ago
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 < 5) sf = 5;
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();
} else if (command == CMD_LEAVE) {
if (sbyte == 0xFF) {
display_unblank();
cable_state = CABLE_STATE_DISCONNECTED;
current_rssi = -292;
last_rssi = -292;
last_rssi_raw = 0x00;
last_snr_raw = 0x80;
}
7 years ago
} else if (command == CMD_RADIO_STATE) {
if (bt_state != BT_STATE_CONNECTED) {
cable_state = CABLE_STATE_CONNECTED;
display_unblank();
}
7 years ago
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_ST_ALOCK) {
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte;
}
if (frame_len == 2) {
uint16_t at = (uint16_t)cmdbuf[0] << 8 | (uint16_t)cmdbuf[1];
if (at == 0) {
st_airtime_limit = 0.0;
} else {
st_airtime_limit = (float)at/(100.0*100.0);
if (st_airtime_limit >= 1.0) { st_airtime_limit = 0.0; }
}
kiss_indicate_st_alock();
}
} else if (command == CMD_LT_ALOCK) {
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte;
}
if (frame_len == 2) {
uint16_t at = (uint16_t)cmdbuf[0] << 8 | (uint16_t)cmdbuf[1];
if (at == 0) {
lt_airtime_limit = 0.0;
} else {
lt_airtime_limit = (float)at/(100.0*100.0);
if (lt_airtime_limit >= 1.0) { lt_airtime_limit = 0.0; }
}
kiss_indicate_lt_alock();
}
7 years ago
} 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) {
if (bt_state != BT_STATE_CONNECTED) cable_state = CABLE_STATE_CONNECTED;
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;
}
if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte;
}
if (frame_len == 2) {
eeprom_write(cmdbuf[0], cmdbuf[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_BOARD) {
kiss_indicate_board();
} else if (command == CMD_CONF_SAVE) {
eeprom_conf_save();
} else if (command == CMD_CONF_DELETE) {
eeprom_conf_delete();
} else if (command == CMD_FB_EXT) {
#if HAS_DISPLAY == true
if (sbyte == 0xFF) {
kiss_indicate_fbstate();
} else if (sbyte == 0x00) {
ext_fb_disable();
kiss_indicate_fbstate();
} else if (sbyte == 0x01) {
ext_fb_enable();
kiss_indicate_fbstate();
}
#endif
} else if (command == CMD_FB_WRITE) {
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte;
}
#if HAS_DISPLAY
if (frame_len == 9) {
uint8_t line = cmdbuf[0];
if (line > 63) line = 63;
int fb_o = line*8;
memcpy(fb+fb_o, cmdbuf+1, 8);
}
#endif
} else if (command == CMD_FB_READ) {
if (sbyte != 0x00) {
kiss_indicate_fb();
}
} else if (command == CMD_DEV_HASH) {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (sbyte != 0x00) {
kiss_indicate_device_hash();
}
#endif
} else if (command == CMD_DEV_SIG) {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte;
}
if (frame_len == DEV_SIG_LEN) {
memcpy(dev_sig, cmdbuf, DEV_SIG_LEN);
device_save_signature();
}
#endif
} else if (command == CMD_FW_UPD) {
if (sbyte == 0x01) {
firmware_update_mode = true;
} else {
firmware_update_mode = false;
}
} else if (command == CMD_HASHES) {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (sbyte == 0x01) {
kiss_indicate_target_fw_hash();
} else if (sbyte == 0x02) {
kiss_indicate_fw_hash();
} else if (sbyte == 0x03) {
kiss_indicate_bootloader_hash();
} else if (sbyte == 0x04) {
kiss_indicate_partition_table_hash();
}
#endif
} else if (command == CMD_FW_HASH) {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte;
}
if (frame_len == DEV_HASH_LEN) {
memcpy(dev_firmware_hash_target, cmdbuf, DEV_HASH_LEN);
device_save_firmware_hash();
}
#endif
} else if (command == CMD_BT_CTRL) {
#if HAS_BLUETOOTH || HAS_BLE
if (sbyte == 0x00) {
bt_stop();
bt_conf_save(false);
} else if (sbyte == 0x01) {
bt_start();
bt_conf_save(true);
} else if (sbyte == 0x02) {
if (bt_state == BT_STATE_OFF) {
bt_start();
bt_conf_save(true);
}
if (bt_state != BT_STATE_CONNECTED) {
bt_enable_pairing();
}
}
#endif
} else if (command == CMD_DISP_INT) {
#if HAS_DISPLAY
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
display_intensity = sbyte;
di_conf_save(display_intensity);
display_unblank();
}
#endif
} else if (command == CMD_DISP_ADDR) {
#if HAS_DISPLAY
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
display_addr = sbyte;
da_conf_save(display_addr);
}
#endif
} else if (command == CMD_DISP_BLNK) {
#if HAS_DISPLAY
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
db_conf_save(sbyte);
display_unblank();
}
#endif
} else if (command == CMD_NP_INT) {
#if HAS_NP
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
5 months ago
sbyte;
led_set_intensity(sbyte);
np_int_conf_save(sbyte);
}
#endif
7 years ago
}
}
}
#if MCU_VARIANT == MCU_ESP32
portMUX_TYPE update_lock = portMUX_INITIALIZER_UNLOCKED;
#endif
void updateModemStatus() {
#if MCU_VARIANT == MCU_ESP32
portENTER_CRITICAL(&update_lock);
#elif MCU_VARIANT == MCU_NRF52
portENTER_CRITICAL();
#endif
uint8_t status = LoRa->modemStatus();
current_rssi = LoRa->currentRssi();
last_status_update = millis();
#if MCU_VARIANT == MCU_ESP32
portEXIT_CRITICAL(&update_lock);
#elif MCU_VARIANT == MCU_NRF52
portEXIT_CRITICAL();
#endif
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 (stat_signal_detected || stat_signal_synced) {
if (stat_rx_ongoing) {
if (dcd_count < dcd_threshold) {
dcd_count++;
} else {
last_dcd = last_status_update;
dcd_led = true;
dcd = true;
}
}
} else {
#define DCD_LED_STEP_D 3
if (dcd_count == 0) {
dcd_led = false;
} else if (dcd_count > DCD_LED_STEP_D) {
dcd_count -= DCD_LED_STEP_D;
} else {
dcd_count = 0;
}
if (last_status_update > last_dcd+csma_slot_ms) {
dcd = false;
dcd_led = false;
dcd_count = 0;
}
}
if (dcd_led) {
led_rx_on();
} else {
if (airtime_lock) {
led_indicate_airtime_lock();
} else {
led_rx_off();
}
}
}
void checkModemStatus() {
if (millis()-last_status_update >= status_interval_ms) {
updateModemStatus();
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
util_samples[dcd_sample] = dcd;
dcd_sample = (dcd_sample+1)%DCD_SAMPLES;
if (dcd_sample % UTIL_UPDATE_INTERVAL == 0) {
int util_count = 0;
for (int ui = 0; ui < DCD_SAMPLES; ui++) {
if (util_samples[ui]) util_count++;
}
local_channel_util = (float)util_count / (float)DCD_SAMPLES;
total_channel_util = local_channel_util + airtime;
if (total_channel_util > 1.0) total_channel_util = 1.0;
int16_t cb = current_airtime_bin();
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
if (total_channel_util > longterm_bins[cb]) longterm_bins[cb] = total_channel_util;
longterm_bins[nb] = 0.0;
update_airtime();
}
#endif
}
}
void validate_status() {
#if MCU_VARIANT == MCU_1284P
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_2560
uint8_t boot_flags = OPTIBOOT_MCUSR;
if (boot_flags == 0x00) boot_flags = 0x03;
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;
#elif MCU_VARIANT == MCU_NRF52
// TODO: Get NRF52 boot flags
uint8_t boot_flags = 0x02;
uint8_t F_POR = 0x00;
uint8_t F_BOR = 0x00;
uint8_t F_WDR = 0x01;
#endif
if (hw_ready || device_init_done) {
hw_ready = false;
Serial.write("Error, invalid hardware check state\r\n");
#if HAS_DISPLAY
if (disp_ready) {
device_init_done = true;
update_display();
}
#endif
led_indicate_boot_error();
}
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");
#if HAS_DISPLAY
if (disp_ready) {
device_init_done = true;
update_display();
}
#endif
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()) {
eeprom_ok = true;
if (modem_installed) {
#if PLATFORM == PLATFORM_ESP32 || PLATFORM == PLATFORM_NRF52
if (device_init()) {
hw_ready = true;
} else {
hw_ready = false;
}
#else
hw_ready = true;
#endif
} else {
hw_ready = false;
Serial.write("No radio module found\r\n");
#if HAS_DISPLAY
if (disp_ready) {
device_init_done = true;
update_display();
}
#endif
}
if (hw_ready && eeprom_have_conf()) {
eeprom_conf_load();
op_mode = MODE_TNC;
startRadio();
}
} else {
hw_ready = false;
Serial.write("Invalid EEPROM checksum\r\n");
#if HAS_DISPLAY
if (disp_ready) {
device_init_done = true;
update_display();
}
#endif
}
} else {
hw_ready = false;
Serial.write("Invalid EEPROM configuration\r\n");
#if HAS_DISPLAY
if (disp_ready) {
device_init_done = true;
update_display();
}
#endif
}
} else {
hw_ready = false;
Serial.write("Device unprovisioned, no device configuration found in EEPROM\r\n");
#if HAS_DISPLAY
if (disp_ready) {
device_init_done = true;
update_display();
}
#endif
}
} else {
hw_ready = false;
Serial.write("Error, incorrect boot vector\r\n");
#if HAS_DISPLAY
if (disp_ready) {
device_init_done = true;
update_display();
}
#endif
led_indicate_boot_error();
}
}
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
1 year ago
#define _e 2.71828183
#define _S 12.5
1 year ago
float csma_slope(float u) { return (pow(_e,_S*u-_S/2.0))/(pow(_e,_S*u-_S/2.0)+1.0); }
void update_csma_p() {
csma_p = (uint8_t)((1.0-(csma_p_min+(csma_p_max-csma_p_min)*csma_slope(airtime+csma_b_speed)))*255.0);
}
1 year ago
#endif
7 years ago
void loop() {
if (radio_online) {
#if MCU_VARIANT == MCU_ESP32
modem_packet_t *modem_packet = NULL;
if(modem_packet_queue && xQueueReceive(modem_packet_queue, &modem_packet, 0) == pdTRUE && modem_packet) {
read_len = modem_packet->len;
last_rssi = modem_packet->rssi;
last_snr_raw = modem_packet->snr_raw;
memcpy(&pbuf, modem_packet->data, modem_packet->len);
free(modem_packet);
modem_packet = NULL;
kiss_indicate_stat_rssi();
kiss_indicate_stat_snr();
kiss_write_packet();
}
airtime_lock = false;
if (st_airtime_limit != 0.0 && airtime >= st_airtime_limit) airtime_lock = true;
if (lt_airtime_limit != 0.0 && longterm_airtime >= lt_airtime_limit) airtime_lock = true;
#elif MCU_VARIANT == MCU_NRF52
modem_packet_t *modem_packet = NULL;
if(modem_packet_queue && xQueueReceive(modem_packet_queue, &modem_packet, 0) == pdTRUE && modem_packet) {
memcpy(&pbuf, modem_packet->data, modem_packet->len);
read_len = modem_packet->len;
free(modem_packet);
modem_packet = NULL;
portENTER_CRITICAL();
last_rssi = LoRa->packetRssi();
last_snr_raw = LoRa->packetSnrRaw();
portEXIT_CRITICAL();
kiss_indicate_stat_rssi();
kiss_indicate_stat_snr();
kiss_write_packet();
}
airtime_lock = false;
if (st_airtime_limit != 0.0 && airtime >= st_airtime_limit) airtime_lock = true;
if (lt_airtime_limit != 0.0 && longterm_airtime >= lt_airtime_limit) airtime_lock = true;
#endif
checkModemStatus();
if (!airtime_lock) {
if (queue_height > 0) {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
long check_time = millis();
if (check_time > post_tx_yield_timeout) {
if (dcd_waiting && (check_time >= dcd_wait_until)) { dcd_waiting = false; }
if (!dcd_waiting) {
for (uint8_t dcd_i = 0; dcd_i < dcd_threshold*2; dcd_i++) {
delay(STATUS_INTERVAL_MS); updateModemStatus();
}
if (!dcd) {
uint8_t csma_r = (uint8_t)random(256);
if (csma_p >= csma_r) {
flushQueue();
} else {
dcd_waiting = true;
dcd_wait_until = millis()+csma_slot_ms;
}
}
}
}
#else
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;
}
#endif
}
}
} else {
if (hw_ready) {
if (console_active) {
2 years ago
#if HAS_CONSOLE
console_loop();
#endif
} else {
led_indicate_standby();
}
} else {
led_indicate_not_ready();
stopRadio();
}
}
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
buffer_serial();
if (!fifo_isempty(&serialFIFO)) serial_poll();
#else
if (!fifo_isempty_locked(&serialFIFO)) serial_poll();
#endif
#if HAS_DISPLAY
if (disp_ready) update_display();
#endif
#if HAS_PMU
if (pmu_ready) update_pmu();
#endif
#if HAS_BLUETOOTH || HAS_BLE == true
if (!console_active && bt_ready) update_bt();
#endif
#if HAS_INPUT
input_read();
#endif
if (memory_low) {
#if PLATFORM == PLATFORM_ESP32
if (esp_get_free_heap_size() < 8192) {
kiss_indicate_error(ERROR_MEMORY_LOW); memory_low = false;
} else {
memory_low = false;
}
#else
kiss_indicate_error(ERROR_MEMORY_LOW); memory_low = false;
#endif
}
}
void sleep_now() {
#if HAS_SLEEP == true
#if BOARD_MODEL == BOARD_RNODE_NG_22
display_intensity = 0;
update_display(true);
#endif
#if PIN_DISP_SLEEP >= 0
pinMode(PIN_DISP_SLEEP, OUTPUT);
digitalWrite(PIN_DISP_SLEEP, DISP_SLEEP_LEVEL);
#endif
#if HAS_BLUETOOTH
if (bt_state == BT_STATE_CONNECTED) {
bt_stop();
delay(100);
}
#endif
esp_sleep_enable_ext0_wakeup(PIN_WAKEUP, WAKEUP_LEVEL);
esp_deep_sleep_start();
#endif
}
void button_event(uint8_t event, unsigned long duration) {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (display_blanked) {
display_unblank();
} else {
if (duration > 10000) {
#if HAS_CONSOLE
#if HAS_BLUETOOTH || HAS_BLE
bt_stop();
#endif
console_active = true;
console_start();
#endif
} else if (duration > 5000) {
#if HAS_BLUETOOTH || HAS_BLE
if (bt_state != BT_STATE_CONNECTED) { bt_enable_pairing(); }
#endif
} else if (duration > 700) {
#if HAS_SLEEP
sleep_now();
#endif
} else {
#if HAS_BLUETOOTH || HAS_BLE
if (bt_state != BT_STATE_CONNECTED) {
if (bt_state == BT_STATE_OFF) {
bt_start();
bt_conf_save(true);
} else {
bt_stop();
bt_conf_save(false);
}
}
#endif
}
}
5 months ago
#endif
}
volatile bool serial_polling = false;
void serial_poll() {
serial_polling = true;
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
while (!fifo_isempty_locked(&serialFIFO)) {
#else
while (!fifo_isempty(&serialFIFO)) {
#endif
char sbyte = fifo_pop(&serialFIFO);
7 years ago
serialCallback(sbyte);
}
serial_polling = false;
}
#if MCU_VARIANT != MCU_ESP32
#define MAX_CYCLES 20
#else
#define MAX_CYCLES 10
#endif
void buffer_serial() {
if (!serial_buffering) {
serial_buffering = true;
uint8_t c = 0;
#if HAS_BLUETOOTH || HAS_BLE == true
while (
c < MAX_CYCLES &&
( (bt_state != BT_STATE_CONNECTED && Serial.available()) || (bt_state == BT_STATE_CONNECTED && SerialBT.available()) )
)
#else
while (c < MAX_CYCLES && Serial.available())
#endif
{
c++;
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
if (!fifo_isfull_locked(&serialFIFO)) {
fifo_push_locked(&serialFIFO, Serial.read());
}
#elif HAS_BLUETOOTH || HAS_BLE == true
if (bt_state == BT_STATE_CONNECTED) {
if (!fifo_isfull(&serialFIFO)) {
fifo_push(&serialFIFO, SerialBT.read());
}
} else {
if (!fifo_isfull(&serialFIFO)) {
fifo_push(&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