commit
f2762af576
7 changed files with 1312 additions and 0 deletions
@ -0,0 +1,4 @@ |
|||||||
|
.DS_Store |
||||||
|
*.hex |
||||||
|
TODO |
||||||
|
|
@ -0,0 +1,63 @@ |
|||||||
|
#ifndef CONFIG_H |
||||||
|
#define CONFIG_H |
||||||
|
|
||||||
|
#define MCU_328P 0x90 |
||||||
|
#define MCU_1284P 0x91 |
||||||
|
|
||||||
|
#if defined(__AVR_ATmega328P__) |
||||||
|
#define MCU_VARIANT MCU_328P |
||||||
|
#warning "Firmware is being compiled for atmega328p based boards" |
||||||
|
#elif defined(__AVR_ATmega1284P__) |
||||||
|
#define MCU_VARIANT MCU_1284P |
||||||
|
#warning "Firmware is being compiled for atmega1284p based boards" |
||||||
|
#else |
||||||
|
#error "The firmware cannot be compiled for the selected MCU variant" |
||||||
|
#endif |
||||||
|
|
||||||
|
#define MTU 500 |
||||||
|
#define SINGLE_MTU 255 |
||||||
|
#define HEADER_L 1 |
||||||
|
#define CMD_L 4 |
||||||
|
|
||||||
|
// MCU dependent configuration parameters
|
||||||
|
#if MCU_VARIANT == MCU_328P |
||||||
|
const int pin_cs = 7; |
||||||
|
const int pin_reset = 6; |
||||||
|
const int pin_dio = 2; |
||||||
|
const int pin_led_rx = 5; |
||||||
|
const int pin_led_tx = 4; |
||||||
|
#endif |
||||||
|
|
||||||
|
#if MCU_VARIANT == MCU_1284P |
||||||
|
const int pin_cs = 4; |
||||||
|
const int pin_reset = 3; |
||||||
|
const int pin_dio = 2; |
||||||
|
const int pin_led_rx = 12; |
||||||
|
const int pin_led_tx = 13; |
||||||
|
#endif |
||||||
|
|
||||||
|
// MCU independent configuration parameters
|
||||||
|
const long serial_baudrate = 115200; |
||||||
|
const int rssi_offset = 164; |
||||||
|
|
||||||
|
// Default LoRa settings
|
||||||
|
int lora_sf = 0; |
||||||
|
int lora_txp = 0xFF; |
||||||
|
uint32_t lora_bw = 0; |
||||||
|
uint32_t lora_freq = 0; |
||||||
|
|
||||||
|
// Operational variables
|
||||||
|
bool radio_locked = true; |
||||||
|
bool radio_online = false; |
||||||
|
|
||||||
|
int last_rssi = -164; |
||||||
|
size_t read_len = 0; |
||||||
|
uint8_t seq = 0xFF; |
||||||
|
uint8_t pbuf[MTU]; |
||||||
|
uint8_t sbuf[MTU]; |
||||||
|
uint8_t cbuf[CMD_L]; |
||||||
|
|
||||||
|
uint32_t stat_rx = 0; |
||||||
|
uint32_t stat_tx = 0; |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,55 @@ |
|||||||
|
#ifndef FRAMING_H |
||||||
|
#define FRAMING_H |
||||||
|
|
||||||
|
#define FEND 0xC0 |
||||||
|
#define FESC 0xDB |
||||||
|
#define TFEND 0xDC |
||||||
|
#define TFESC 0xDD |
||||||
|
|
||||||
|
#define CMD_UNKNOWN 0xFE |
||||||
|
#define CMD_DATA 0x00 |
||||||
|
#define CMD_FREQUENCY 0x01 |
||||||
|
#define CMD_BANDWIDTH 0x02 |
||||||
|
#define CMD_TXPOWER 0x03 |
||||||
|
#define CMD_SF 0x04 |
||||||
|
#define CMD_RADIO_STATE 0x05 |
||||||
|
#define CMD_RADIO_LOCK 0x06 |
||||||
|
|
||||||
|
#define CMD_STAT_RX 0x21 |
||||||
|
#define CMD_STAT_TX 0x22 |
||||||
|
#define CMD_STAT_RSSI 0x23 |
||||||
|
#define CMD_BLINK 0x30 |
||||||
|
#define CMD_RANDOM 0x40 |
||||||
|
|
||||||
|
#define RADIO_STATE_OFF 0x00 |
||||||
|
#define RADIO_STATE_ON 0x01 |
||||||
|
|
||||||
|
#define CMD_ERROR 0x90 |
||||||
|
#define ERROR_INITRADIO 0x01 |
||||||
|
#define ERROR_TXFAILED 0x02 |
||||||
|
|
||||||
|
#define NIBBLE_SEQ 0xF0 |
||||||
|
#define NIBBLE_FLAGS 0x0F |
||||||
|
#define FLAG_SPLIT 0x01 |
||||||
|
#define SEQ_UNSET 0xFF |
||||||
|
|
||||||
|
// Serial framing variables
|
||||||
|
size_t frame_len; |
||||||
|
bool IN_FRAME = false; |
||||||
|
bool ESCAPE = false; |
||||||
|
uint8_t command = CMD_UNKNOWN; |
||||||
|
|
||||||
|
#endif |
||||||
|
|
||||||
|
/*
|
||||||
|
Frequency 433.200 0xc00119d21b80c0 |
||||||
|
Bandwidth 20.800 0xc00200005140c0 |
||||||
|
TX Power 8dbm 0xc00308c0 |
||||||
|
SF 7 0xc00407c0 |
||||||
|
|
||||||
|
All: 0xc00119d21b80c00200005140c00308c00407c0 |
||||||
|
|
||||||
|
Radio on 0xc00501c0 |
||||||
|
|
||||||
|
Config+on 0xc00119d21b80c00200005140c00308c00407c00501c0 |
||||||
|
*/ |
@ -0,0 +1,584 @@ |
|||||||
|
// Copyright (c) Sandeep Mistry. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
#include <LoRa.h> |
||||||
|
|
||||||
|
// registers
|
||||||
|
#define REG_FIFO 0x00 |
||||||
|
#define REG_OP_MODE 0x01 |
||||||
|
#define REG_FRF_MSB 0x06 |
||||||
|
#define REG_FRF_MID 0x07 |
||||||
|
#define REG_FRF_LSB 0x08 |
||||||
|
#define REG_PA_CONFIG 0x09 |
||||||
|
#define REG_LNA 0x0c |
||||||
|
#define REG_FIFO_ADDR_PTR 0x0d |
||||||
|
#define REG_FIFO_TX_BASE_ADDR 0x0e |
||||||
|
#define REG_FIFO_RX_BASE_ADDR 0x0f |
||||||
|
#define REG_FIFO_RX_CURRENT_ADDR 0x10 |
||||||
|
#define REG_IRQ_FLAGS 0x12 |
||||||
|
#define REG_RX_NB_BYTES 0x13 |
||||||
|
#define REG_PKT_SNR_VALUE 0x19 |
||||||
|
#define REG_PKT_RSSI_VALUE 0x1a |
||||||
|
#define REG_MODEM_CONFIG_1 0x1d |
||||||
|
#define REG_MODEM_CONFIG_2 0x1e |
||||||
|
#define REG_PREAMBLE_MSB 0x20 |
||||||
|
#define REG_PREAMBLE_LSB 0x21 |
||||||
|
#define REG_PAYLOAD_LENGTH 0x22 |
||||||
|
#define REG_MODEM_CONFIG_3 0x26 |
||||||
|
#define REG_FREQ_ERROR_MSB 0x28 |
||||||
|
#define REG_FREQ_ERROR_MID 0x29 |
||||||
|
#define REG_FREQ_ERROR_LSB 0x2a |
||||||
|
#define REG_RSSI_WIDEBAND 0x2c |
||||||
|
#define REG_DETECTION_OPTIMIZE 0x31 |
||||||
|
#define REG_DETECTION_THRESHOLD 0x37 |
||||||
|
#define REG_SYNC_WORD 0x39 |
||||||
|
#define REG_DIO_MAPPING_1 0x40 |
||||||
|
#define REG_VERSION 0x42 |
||||||
|
|
||||||
|
// modes
|
||||||
|
#define MODE_LONG_RANGE_MODE 0x80 |
||||||
|
#define MODE_SLEEP 0x00 |
||||||
|
#define MODE_STDBY 0x01 |
||||||
|
#define MODE_TX 0x03 |
||||||
|
#define MODE_RX_CONTINUOUS 0x05 |
||||||
|
#define MODE_RX_SINGLE 0x06 |
||||||
|
|
||||||
|
// PA config
|
||||||
|
#define PA_BOOST 0x80 |
||||||
|
|
||||||
|
// IRQ masks
|
||||||
|
#define IRQ_TX_DONE_MASK 0x08 |
||||||
|
#define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20 |
||||||
|
#define IRQ_RX_DONE_MASK 0x40 |
||||||
|
|
||||||
|
#define MAX_PKT_LENGTH 255 |
||||||
|
|
||||||
|
LoRaClass::LoRaClass() : |
||||||
|
_spiSettings(8E6, MSBFIRST, SPI_MODE0), |
||||||
|
_ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), |
||||||
|
_frequency(0), |
||||||
|
_packetIndex(0), |
||||||
|
_implicitHeaderMode(0), |
||||||
|
_onReceive(NULL) |
||||||
|
{ |
||||||
|
// overide Stream timeout value
|
||||||
|
setTimeout(0); |
||||||
|
} |
||||||
|
|
||||||
|
int LoRaClass::begin(long frequency) |
||||||
|
{ |
||||||
|
// setup pins
|
||||||
|
pinMode(_ss, OUTPUT); |
||||||
|
// set SS high
|
||||||
|
digitalWrite(_ss, HIGH); |
||||||
|
|
||||||
|
if (_reset != -1) { |
||||||
|
pinMode(_reset, OUTPUT); |
||||||
|
|
||||||
|
// perform reset
|
||||||
|
digitalWrite(_reset, LOW); |
||||||
|
delay(10); |
||||||
|
digitalWrite(_reset, HIGH); |
||||||
|
delay(10); |
||||||
|
} |
||||||
|
|
||||||
|
// start SPI
|
||||||
|
SPI.begin(); |
||||||
|
|
||||||
|
// check version
|
||||||
|
uint8_t version = readRegister(REG_VERSION); |
||||||
|
if (version != 0x12) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
// put in sleep mode
|
||||||
|
sleep(); |
||||||
|
|
||||||
|
// set frequency
|
||||||
|
setFrequency(frequency); |
||||||
|
|
||||||
|
// set base addresses
|
||||||
|
writeRegister(REG_FIFO_TX_BASE_ADDR, 0); |
||||||
|
writeRegister(REG_FIFO_RX_BASE_ADDR, 0); |
||||||
|
|
||||||
|
// set LNA boost
|
||||||
|
writeRegister(REG_LNA, readRegister(REG_LNA) | 0x03); |
||||||
|
|
||||||
|
// set auto AGC
|
||||||
|
writeRegister(REG_MODEM_CONFIG_3, 0x04); |
||||||
|
|
||||||
|
// set output power to 17 dBm
|
||||||
|
setTxPower(17); |
||||||
|
|
||||||
|
// put in standby mode
|
||||||
|
idle(); |
||||||
|
|
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::end() |
||||||
|
{ |
||||||
|
// put in sleep mode
|
||||||
|
sleep(); |
||||||
|
|
||||||
|
// stop SPI
|
||||||
|
SPI.end(); |
||||||
|
} |
||||||
|
|
||||||
|
int LoRaClass::beginPacket(int implicitHeader) |
||||||
|
{ |
||||||
|
// put in standby mode
|
||||||
|
idle(); |
||||||
|
|
||||||
|
if (implicitHeader) { |
||||||
|
implicitHeaderMode(); |
||||||
|
} else { |
||||||
|
explicitHeaderMode(); |
||||||
|
} |
||||||
|
|
||||||
|
// reset FIFO address and paload length
|
||||||
|
writeRegister(REG_FIFO_ADDR_PTR, 0); |
||||||
|
writeRegister(REG_PAYLOAD_LENGTH, 0); |
||||||
|
|
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
int LoRaClass::endPacket() |
||||||
|
{ |
||||||
|
// put in TX mode
|
||||||
|
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); |
||||||
|
|
||||||
|
// wait for TX done
|
||||||
|
while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { |
||||||
|
yield(); |
||||||
|
} |
||||||
|
|
||||||
|
// clear IRQ's
|
||||||
|
writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); |
||||||
|
|
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
int LoRaClass::parsePacket(int size) |
||||||
|
{ |
||||||
|
int packetLength = 0; |
||||||
|
int irqFlags = readRegister(REG_IRQ_FLAGS); |
||||||
|
|
||||||
|
if (size > 0) { |
||||||
|
implicitHeaderMode(); |
||||||
|
|
||||||
|
writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); |
||||||
|
} else { |
||||||
|
explicitHeaderMode(); |
||||||
|
} |
||||||
|
|
||||||
|
// clear IRQ's
|
||||||
|
writeRegister(REG_IRQ_FLAGS, irqFlags); |
||||||
|
|
||||||
|
if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { |
||||||
|
// received a packet
|
||||||
|
_packetIndex = 0; |
||||||
|
|
||||||
|
// read packet length
|
||||||
|
if (_implicitHeaderMode) { |
||||||
|
packetLength = readRegister(REG_PAYLOAD_LENGTH); |
||||||
|
} else { |
||||||
|
packetLength = readRegister(REG_RX_NB_BYTES); |
||||||
|
} |
||||||
|
|
||||||
|
// set FIFO address to current RX address
|
||||||
|
writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); |
||||||
|
|
||||||
|
// put in standby mode
|
||||||
|
idle(); |
||||||
|
} else if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) { |
||||||
|
// not currently in RX mode
|
||||||
|
|
||||||
|
// reset FIFO address
|
||||||
|
writeRegister(REG_FIFO_ADDR_PTR, 0); |
||||||
|
|
||||||
|
// put in single RX mode
|
||||||
|
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE); |
||||||
|
} |
||||||
|
|
||||||
|
return packetLength; |
||||||
|
} |
||||||
|
|
||||||
|
int LoRaClass::packetRssi() |
||||||
|
{ |
||||||
|
return (readRegister(REG_PKT_RSSI_VALUE) - (_frequency < 868E6 ? 164 : 157)); |
||||||
|
} |
||||||
|
|
||||||
|
float LoRaClass::packetSnr() |
||||||
|
{ |
||||||
|
return ((int8_t)readRegister(REG_PKT_SNR_VALUE)) * 0.25; |
||||||
|
} |
||||||
|
|
||||||
|
long LoRaClass::packetFrequencyError() |
||||||
|
{ |
||||||
|
int32_t freqError = 0; |
||||||
|
freqError = static_cast<int32_t>(readRegister(REG_FREQ_ERROR_MSB) & B111); |
||||||
|
freqError <<= 8L; |
||||||
|
freqError += static_cast<int32_t>(readRegister(REG_FREQ_ERROR_MID)); |
||||||
|
freqError <<= 8L; |
||||||
|
freqError += static_cast<int32_t>(readRegister(REG_FREQ_ERROR_LSB)); |
||||||
|
|
||||||
|
if (readRegister(REG_FREQ_ERROR_MSB) & B1000) { // Sign bit is on
|
||||||
|
freqError -= 524288; // B1000'0000'0000'0000'0000
|
||||||
|
} |
||||||
|
|
||||||
|
const float fXtal = 32E6; // FXOSC: crystal oscillator (XTAL) frequency (2.5. Chip Specification, p. 14)
|
||||||
|
const float fError = ((static_cast<float>(freqError) * (1L << 24)) / fXtal) * (getSignalBandwidth() / 500000.0f); // p. 37
|
||||||
|
|
||||||
|
return static_cast<long>(fError); |
||||||
|
} |
||||||
|
|
||||||
|
size_t LoRaClass::write(uint8_t byte) |
||||||
|
{ |
||||||
|
return write(&byte, sizeof(byte)); |
||||||
|
} |
||||||
|
|
||||||
|
size_t LoRaClass::write(const uint8_t *buffer, size_t size) |
||||||
|
{ |
||||||
|
int currentLength = readRegister(REG_PAYLOAD_LENGTH); |
||||||
|
|
||||||
|
// check size
|
||||||
|
if ((currentLength + size) > MAX_PKT_LENGTH) { |
||||||
|
size = MAX_PKT_LENGTH - currentLength; |
||||||
|
} |
||||||
|
|
||||||
|
// write data
|
||||||
|
for (size_t i = 0; i < size; i++) { |
||||||
|
writeRegister(REG_FIFO, buffer[i]); |
||||||
|
} |
||||||
|
|
||||||
|
// update length
|
||||||
|
writeRegister(REG_PAYLOAD_LENGTH, currentLength + size); |
||||||
|
|
||||||
|
return size; |
||||||
|
} |
||||||
|
|
||||||
|
int LoRaClass::available() |
||||||
|
{ |
||||||
|
return (readRegister(REG_RX_NB_BYTES) - _packetIndex); |
||||||
|
} |
||||||
|
|
||||||
|
int LoRaClass::read() |
||||||
|
{ |
||||||
|
if (!available()) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
_packetIndex++; |
||||||
|
|
||||||
|
return readRegister(REG_FIFO); |
||||||
|
} |
||||||
|
|
||||||
|
int LoRaClass::peek() |
||||||
|
{ |
||||||
|
if (!available()) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
// store current FIFO address
|
||||||
|
int currentAddress = readRegister(REG_FIFO_ADDR_PTR); |
||||||
|
|
||||||
|
// read
|
||||||
|
uint8_t b = readRegister(REG_FIFO); |
||||||
|
|
||||||
|
// restore FIFO address
|
||||||
|
writeRegister(REG_FIFO_ADDR_PTR, currentAddress); |
||||||
|
|
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::flush() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::onReceive(void(*callback)(int)) |
||||||
|
{ |
||||||
|
_onReceive = callback; |
||||||
|
|
||||||
|
if (callback) { |
||||||
|
pinMode(_dio0, INPUT); |
||||||
|
|
||||||
|
writeRegister(REG_DIO_MAPPING_1, 0x00); |
||||||
|
#ifdef SPI_HAS_NOTUSINGINTERRUPT |
||||||
|
SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); |
||||||
|
#endif |
||||||
|
attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); |
||||||
|
} else { |
||||||
|
detachInterrupt(digitalPinToInterrupt(_dio0)); |
||||||
|
#ifdef SPI_HAS_NOTUSINGINTERRUPT |
||||||
|
SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0)); |
||||||
|
#endif |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::receive(int size) |
||||||
|
{ |
||||||
|
if (size > 0) { |
||||||
|
implicitHeaderMode(); |
||||||
|
|
||||||
|
writeRegister(REG_PAYLOAD_LENGTH, size & 0xff); |
||||||
|
} else { |
||||||
|
explicitHeaderMode(); |
||||||
|
} |
||||||
|
|
||||||
|
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::idle() |
||||||
|
{ |
||||||
|
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::sleep() |
||||||
|
{ |
||||||
|
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::setTxPower(int level, int outputPin) |
||||||
|
{ |
||||||
|
if (PA_OUTPUT_RFO_PIN == outputPin) { |
||||||
|
// RFO
|
||||||
|
if (level < 0) { |
||||||
|
level = 0; |
||||||
|
} else if (level > 14) { |
||||||
|
level = 14; |
||||||
|
} |
||||||
|
|
||||||
|
writeRegister(REG_PA_CONFIG, 0x70 | level); |
||||||
|
} else { |
||||||
|
// PA BOOST
|
||||||
|
if (level < 2) { |
||||||
|
level = 2; |
||||||
|
} else if (level > 17) { |
||||||
|
level = 17; |
||||||
|
} |
||||||
|
|
||||||
|
writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::setFrequency(long frequency) |
||||||
|
{ |
||||||
|
_frequency = frequency; |
||||||
|
|
||||||
|
uint64_t frf = ((uint64_t)frequency << 19) / 32000000; |
||||||
|
|
||||||
|
writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16)); |
||||||
|
writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8)); |
||||||
|
writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0)); |
||||||
|
} |
||||||
|
|
||||||
|
long LoRaClass::getFrequency() { |
||||||
|
uint8_t msb = readRegister(REG_FRF_MSB); |
||||||
|
uint8_t mid = readRegister(REG_FRF_MID); |
||||||
|
uint8_t lsb = readRegister(REG_FRF_LSB); |
||||||
|
|
||||||
|
uint64_t frf = msb << 16 | mid << 8 | lsb; |
||||||
|
long frequency = (uint64_t)(frf*32000000) >> 19; |
||||||
|
|
||||||
|
return frequency; |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::setSpreadingFactor(int sf) |
||||||
|
{ |
||||||
|
if (sf < 6) { |
||||||
|
sf = 6; |
||||||
|
} else if (sf > 12) { |
||||||
|
sf = 12; |
||||||
|
} |
||||||
|
|
||||||
|
if (sf == 6) { |
||||||
|
writeRegister(REG_DETECTION_OPTIMIZE, 0xc5); |
||||||
|
writeRegister(REG_DETECTION_THRESHOLD, 0x0c); |
||||||
|
} else { |
||||||
|
writeRegister(REG_DETECTION_OPTIMIZE, 0xc3); |
||||||
|
writeRegister(REG_DETECTION_THRESHOLD, 0x0a); |
||||||
|
} |
||||||
|
|
||||||
|
writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)); |
||||||
|
} |
||||||
|
|
||||||
|
long LoRaClass::getSignalBandwidth() |
||||||
|
{ |
||||||
|
byte bw = (readRegister(REG_MODEM_CONFIG_1) >> 4); |
||||||
|
switch (bw) { |
||||||
|
case 0: return 7.8E3; |
||||||
|
case 1: return 10.4E3;
|
||||||
|
case 2: return 15.6E3;
|
||||||
|
case 3: return 20.8E3;
|
||||||
|
case 4: return 31.25E3;
|
||||||
|
case 5: return 41.7E3;
|
||||||
|
case 6: return 62.5E3;
|
||||||
|
case 7: return 125E3;
|
||||||
|
case 8: return 250E3;
|
||||||
|
case 9: return 500E3;
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::setSignalBandwidth(long sbw) |
||||||
|
{ |
||||||
|
int bw; |
||||||
|
|
||||||
|
if (sbw <= 7.8E3) { |
||||||
|
bw = 0; |
||||||
|
} else if (sbw <= 10.4E3) { |
||||||
|
bw = 1; |
||||||
|
} else if (sbw <= 15.6E3) { |
||||||
|
bw = 2; |
||||||
|
} else if (sbw <= 20.8E3) { |
||||||
|
bw = 3; |
||||||
|
} else if (sbw <= 31.25E3) { |
||||||
|
bw = 4; |
||||||
|
} else if (sbw <= 41.7E3) { |
||||||
|
bw = 5; |
||||||
|
} else if (sbw <= 62.5E3) { |
||||||
|
bw = 6; |
||||||
|
} else if (sbw <= 125E3) { |
||||||
|
bw = 7; |
||||||
|
} else if (sbw <= 250E3) { |
||||||
|
bw = 8; |
||||||
|
} else /*if (sbw <= 250E3)*/ { |
||||||
|
bw = 9; |
||||||
|
} |
||||||
|
|
||||||
|
writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4)); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::setCodingRate4(int denominator) |
||||||
|
{ |
||||||
|
if (denominator < 5) { |
||||||
|
denominator = 5; |
||||||
|
} else if (denominator > 8) { |
||||||
|
denominator = 8; |
||||||
|
} |
||||||
|
|
||||||
|
int cr = denominator - 4; |
||||||
|
|
||||||
|
writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1)); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::setPreambleLength(long length) |
||||||
|
{ |
||||||
|
writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8)); |
||||||
|
writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0)); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::setSyncWord(int sw) |
||||||
|
{ |
||||||
|
writeRegister(REG_SYNC_WORD, sw); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::enableCrc() |
||||||
|
{ |
||||||
|
writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) | 0x04); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::disableCrc() |
||||||
|
{ |
||||||
|
writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb); |
||||||
|
} |
||||||
|
|
||||||
|
byte LoRaClass::random() |
||||||
|
{ |
||||||
|
return readRegister(REG_RSSI_WIDEBAND); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::setPins(int ss, int reset, int dio0) |
||||||
|
{ |
||||||
|
_ss = ss; |
||||||
|
_reset = reset; |
||||||
|
_dio0 = dio0; |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::setSPIFrequency(uint32_t frequency) |
||||||
|
{ |
||||||
|
_spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::dumpRegisters(Stream& out) |
||||||
|
{ |
||||||
|
for (int i = 0; i < 128; i++) { |
||||||
|
out.print("0x"); |
||||||
|
out.print(i, HEX); |
||||||
|
out.print(": 0x"); |
||||||
|
out.println(readRegister(i), HEX); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::explicitHeaderMode() |
||||||
|
{ |
||||||
|
_implicitHeaderMode = 0; |
||||||
|
|
||||||
|
writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) & 0xfe); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::implicitHeaderMode() |
||||||
|
{ |
||||||
|
_implicitHeaderMode = 1; |
||||||
|
|
||||||
|
writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) | 0x01); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::handleDio0Rise() |
||||||
|
{ |
||||||
|
int irqFlags = readRegister(REG_IRQ_FLAGS); |
||||||
|
|
||||||
|
// clear IRQ's
|
||||||
|
writeRegister(REG_IRQ_FLAGS, irqFlags); |
||||||
|
|
||||||
|
if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { |
||||||
|
// received a packet
|
||||||
|
_packetIndex = 0; |
||||||
|
|
||||||
|
// read packet length
|
||||||
|
int packetLength = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH) : readRegister(REG_RX_NB_BYTES); |
||||||
|
|
||||||
|
// set FIFO address to current RX address
|
||||||
|
writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR)); |
||||||
|
|
||||||
|
if (_onReceive) { |
||||||
|
_onReceive(packetLength); |
||||||
|
} |
||||||
|
|
||||||
|
// reset FIFO address
|
||||||
|
writeRegister(REG_FIFO_ADDR_PTR, 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
uint8_t LoRaClass::readRegister(uint8_t address) |
||||||
|
{ |
||||||
|
return singleTransfer(address & 0x7f, 0x00); |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::writeRegister(uint8_t address, uint8_t value) |
||||||
|
{ |
||||||
|
singleTransfer(address | 0x80, value); |
||||||
|
} |
||||||
|
|
||||||
|
uint8_t LoRaClass::singleTransfer(uint8_t address, uint8_t value) |
||||||
|
{ |
||||||
|
uint8_t response; |
||||||
|
|
||||||
|
digitalWrite(_ss, LOW); |
||||||
|
|
||||||
|
SPI.beginTransaction(_spiSettings); |
||||||
|
SPI.transfer(address); |
||||||
|
response = SPI.transfer(value); |
||||||
|
SPI.endTransaction(); |
||||||
|
|
||||||
|
digitalWrite(_ss, HIGH); |
||||||
|
|
||||||
|
return response; |
||||||
|
} |
||||||
|
|
||||||
|
void LoRaClass::onDio0Rise() |
||||||
|
{ |
||||||
|
LoRa.handleDio0Rise(); |
||||||
|
} |
||||||
|
|
||||||
|
LoRaClass LoRa; |
@ -0,0 +1,96 @@ |
|||||||
|
// Copyright (c) Sandeep Mistry. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
#ifndef LORA_H |
||||||
|
#define LORA_H |
||||||
|
|
||||||
|
#include <Arduino.h> |
||||||
|
#include <SPI.h> |
||||||
|
|
||||||
|
#define LORA_DEFAULT_SS_PIN 10 |
||||||
|
#define LORA_DEFAULT_RESET_PIN 9 |
||||||
|
#define LORA_DEFAULT_DIO0_PIN 2 |
||||||
|
|
||||||
|
#define PA_OUTPUT_RFO_PIN 0 |
||||||
|
#define PA_OUTPUT_PA_BOOST_PIN 1 |
||||||
|
|
||||||
|
class LoRaClass : public Stream { |
||||||
|
public: |
||||||
|
LoRaClass(); |
||||||
|
|
||||||
|
int begin(long frequency); |
||||||
|
void end(); |
||||||
|
|
||||||
|
int beginPacket(int implicitHeader = false); |
||||||
|
int endPacket(); |
||||||
|
|
||||||
|
int parsePacket(int size = 0); |
||||||
|
int packetRssi(); |
||||||
|
float packetSnr(); |
||||||
|
long packetFrequencyError(); |
||||||
|
|
||||||
|
// from Print
|
||||||
|
virtual size_t write(uint8_t byte); |
||||||
|
virtual size_t write(const uint8_t *buffer, size_t size); |
||||||
|
|
||||||
|
// from Stream
|
||||||
|
virtual int available(); |
||||||
|
virtual int read(); |
||||||
|
virtual int peek(); |
||||||
|
virtual void flush(); |
||||||
|
|
||||||
|
void onReceive(void(*callback)(int)); |
||||||
|
|
||||||
|
void receive(int size = 0); |
||||||
|
void idle(); |
||||||
|
void sleep(); |
||||||
|
|
||||||
|
void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN); |
||||||
|
long getFrequency(); |
||||||
|
void setFrequency(long frequency); |
||||||
|
void setSpreadingFactor(int sf); |
||||||
|
long getSignalBandwidth(); |
||||||
|
void setSignalBandwidth(long sbw); |
||||||
|
void setCodingRate4(int denominator); |
||||||
|
void setPreambleLength(long length); |
||||||
|
void setSyncWord(int sw); |
||||||
|
void enableCrc(); |
||||||
|
void disableCrc(); |
||||||
|
|
||||||
|
// deprecated
|
||||||
|
void crc() { enableCrc(); } |
||||||
|
void noCrc() { disableCrc(); } |
||||||
|
|
||||||
|
byte random(); |
||||||
|
|
||||||
|
void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN); |
||||||
|
void setSPIFrequency(uint32_t frequency); |
||||||
|
|
||||||
|
void dumpRegisters(Stream& out); |
||||||
|
|
||||||
|
private: |
||||||
|
void explicitHeaderMode(); |
||||||
|
void implicitHeaderMode(); |
||||||
|
|
||||||
|
void handleDio0Rise(); |
||||||
|
|
||||||
|
uint8_t readRegister(uint8_t address); |
||||||
|
void writeRegister(uint8_t address, uint8_t value); |
||||||
|
uint8_t singleTransfer(uint8_t address, uint8_t value); |
||||||
|
|
||||||
|
static void onDio0Rise(); |
||||||
|
|
||||||
|
private: |
||||||
|
SPISettings _spiSettings; |
||||||
|
int _ss; |
||||||
|
int _reset; |
||||||
|
int _dio0; |
||||||
|
long _frequency; |
||||||
|
int _packetIndex; |
||||||
|
int _implicitHeaderMode; |
||||||
|
void (*_onReceive)(int); |
||||||
|
}; |
||||||
|
|
||||||
|
extern LoRaClass LoRa; |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,311 @@ |
|||||||
|
#include <SPI.h> |
||||||
|
#include <LoRa.h> |
||||||
|
#include "Config.h" |
||||||
|
#include "Framing.h" |
||||||
|
#include "Utilities.cpp" |
||||||
|
|
||||||
|
void setup() { |
||||||
|
// Seed the PRNG
|
||||||
|
randomSeed(analogRead(0)); |
||||||
|
|
||||||
|
// Initialise serial communication
|
||||||
|
Serial.begin(serial_baudrate); |
||||||
|
while (!Serial); |
||||||
|
|
||||||
|
// Configure input and output pins
|
||||||
|
pinMode(pin_led_rx, OUTPUT); |
||||||
|
pinMode(pin_led_tx, OUTPUT); |
||||||
|
|
||||||
|
// Set up buffers
|
||||||
|
memset(pbuf, 0, sizeof(pbuf)); |
||||||
|
memset(sbuf, 0, sizeof(sbuf)); |
||||||
|
memset(cbuf, 0, sizeof(cbuf)); |
||||||
|
|
||||||
|
// Set chip select, reset and interrupt
|
||||||
|
// pins for the LoRa module
|
||||||
|
LoRa.setPins(pin_cs, pin_reset, pin_dio); |
||||||
|
} |
||||||
|
|
||||||
|
bool startRadio() { |
||||||
|
update_radio_lock(); |
||||||
|
if (!radio_online) { |
||||||
|
if (!radio_locked) { |
||||||
|
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); |
||||||
|
} else { |
||||||
|
radio_online = true; |
||||||
|
|
||||||
|
setTXPower(); |
||||||
|
setBandwidth(); |
||||||
|
setSpreadingFactor(); |
||||||
|
getFrequency(); |
||||||
|
|
||||||
|
LoRa.enableCrc(); |
||||||
|
LoRa.onReceive(receiveCallback); |
||||||
|
|
||||||
|
LoRa.receive(); |
||||||
|
|
||||||
|
// Flash an info pattern to indicate
|
||||||
|
// that the radio is now on
|
||||||
|
led_indicate_info(3); |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
// Flash a warning pattern to indicate
|
||||||
|
// that the radio was locked, and thus
|
||||||
|
// not started
|
||||||
|
led_indicate_warning(3); |
||||||
|
} |
||||||
|
} else { |
||||||
|
// If radio is already on, we silently
|
||||||
|
// ignore the request.
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
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 receiveCallback(int packet_size) { |
||||||
|
led_rx_on(); |
||||||
|
|
||||||
|
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
|
||||||
|
read_len = 0; |
||||||
|
seq = sequence; |
||||||
|
last_rssi = LoRa.packetRssi(); |
||||||
|
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; |
||||||
|
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.
|
||||||
|
read_len = 0; |
||||||
|
seq = sequence; |
||||||
|
last_rssi = LoRa.packetRssi(); |
||||||
|
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(); |
||||||
|
getPacketData(packet_size); |
||||||
|
ready = true; |
||||||
|
} |
||||||
|
|
||||||
|
if (ready) { |
||||||
|
// We first signal the RSSI of the
|
||||||
|
// recieved packet to the host.
|
||||||
|
Serial.write(FEND); |
||||||
|
Serial.write(CMD_STAT_RSSI); |
||||||
|
Serial.write((uint8_t)(last_rssi-rssi_offset)); |
||||||
|
|
||||||
|
// 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; |
||||||
|
} |
||||||
|
led_rx_off(); |
||||||
|
} |
||||||
|
|
||||||
|
void transmit(size_t size) { |
||||||
|
if (radio_online) { |
||||||
|
led_tx_on(); |
||||||
|
size_t written = 0; |
||||||
|
uint8_t header = random(256) & 0xF0; |
||||||
|
|
||||||
|
if (size > SINGLE_MTU - HEADER_L) { |
||||||
|
header = header | FLAG_SPLIT; |
||||||
|
} |
||||||
|
|
||||||
|
LoRa.beginPacket(); |
||||||
|
LoRa.write(header); written++; |
||||||
|
|
||||||
|
for (size_t i; i < size; i++) { |
||||||
|
LoRa.write(sbuf[i]); |
||||||
|
written++; |
||||||
|
|
||||||
|
if (written == 255) { |
||||||
|
LoRa.endPacket(); |
||||||
|
LoRa.beginPacket(); |
||||||
|
LoRa.write(header); |
||||||
|
written = 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
LoRa.endPacket(); |
||||||
|
led_tx_off(); |
||||||
|
LoRa.receive(); |
||||||
|
} 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; |
||||||
|
transmit(frame_len); |
||||||
|
} 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; |
||||||
|
} |
||||||
|
sbuf[frame_len++] = sbyte; |
||||||
|
} |
||||||
|
} 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; |
||||||
|
setFrequency(); |
||||||
|
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; |
||||||
|
setBandwidth(); |
||||||
|
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; |
||||||
|
setTXPower(); |
||||||
|
kiss_indicate_txpower(); |
||||||
|
} |
||||||
|
} else if (command == CMD_SF) { |
||||||
|
if (sbyte == 0xFF) { |
||||||
|
kiss_indicate_spreadingfactor(); |
||||||
|
} else { |
||||||
|
int sf = sbyte; |
||||||
|
if (sf < 7) sf = 7; |
||||||
|
if (sf > 12) sf = 12; |
||||||
|
|
||||||
|
lora_sf = sf; |
||||||
|
setSpreadingFactor(); |
||||||
|
kiss_indicate_spreadingfactor(); |
||||||
|
} |
||||||
|
} 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()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void loop() { |
||||||
|
if (Serial.available()) { |
||||||
|
char sbyte = Serial.read(); |
||||||
|
serialCallback(sbyte); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,199 @@ |
|||||||
|
#include <Arduino.h> |
||||||
|
#include <LoRa.h> |
||||||
|
#include "Config.h" |
||||||
|
#include "Framing.h" |
||||||
|
|
||||||
|
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); } |
||||||
|
void led_rx_off() { digitalWrite(pin_led_rx, LOW); } |
||||||
|
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); } |
||||||
|
void led_tx_off() { digitalWrite(pin_led_tx, LOW); } |
||||||
|
|
||||||
|
void led_indicate_error(int cycles) { |
||||||
|
bool forever = (cycles == 0) ? true : false; |
||||||
|
cycles = forever ? 1 : cycles; |
||||||
|
while(cycles > 0) { |
||||||
|
digitalWrite(pin_led_rx, HIGH); |
||||||
|
digitalWrite(pin_led_tx, LOW); |
||||||
|
delay(100); |
||||||
|
digitalWrite(pin_led_rx, LOW); |
||||||
|
digitalWrite(pin_led_tx, HIGH); |
||||||
|
delay(100); |
||||||
|
if (!forever) cycles--; |
||||||
|
} |
||||||
|
digitalWrite(pin_led_rx, LOW); |
||||||
|
digitalWrite(pin_led_tx, LOW); |
||||||
|
} |
||||||
|
|
||||||
|
void led_indicate_warning(int cycles) { |
||||||
|
bool forever = (cycles == 0) ? true : false; |
||||||
|
cycles = forever ? 1 : cycles; |
||||||
|
digitalWrite(pin_led_tx, HIGH); |
||||||
|
while(cycles > 0) { |
||||||
|
digitalWrite(pin_led_tx, LOW); |
||||||
|
delay(100); |
||||||
|
digitalWrite(pin_led_tx, HIGH); |
||||||
|
delay(100); |
||||||
|
if (!forever) cycles--; |
||||||
|
} |
||||||
|
digitalWrite(pin_led_tx, LOW); |
||||||
|
} |
||||||
|
|
||||||
|
void led_indicate_info(int cycles) { |
||||||
|
bool forever = (cycles == 0) ? true : false; |
||||||
|
cycles = forever ? 1 : cycles; |
||||||
|
while(cycles > 0) { |
||||||
|
digitalWrite(pin_led_rx, LOW); |
||||||
|
delay(100); |
||||||
|
digitalWrite(pin_led_rx, HIGH); |
||||||
|
delay(100); |
||||||
|
if (!forever) cycles--; |
||||||
|
} |
||||||
|
digitalWrite(pin_led_rx, LOW); |
||||||
|
} |
||||||
|
|
||||||
|
void kiss_indicate_error(uint8_t error_code) { |
||||||
|
Serial.write(FEND); |
||||||
|
Serial.write(CMD_ERROR); |
||||||
|
Serial.write(error_code); |
||||||
|
Serial.write(FEND); |
||||||
|
} |
||||||
|
|
||||||
|
void kiss_indicate_radiostate() { |
||||||
|
Serial.write(FEND); |
||||||
|
Serial.write(CMD_RADIO_STATE); |
||||||
|
Serial.write(radio_online); |
||||||
|
Serial.write(FEND); |
||||||
|
} |
||||||
|
|
||||||
|
void kiss_indicate_stat_rx() { |
||||||
|
Serial.write(FEND); |
||||||
|
Serial.write(CMD_STAT_RX); |
||||||
|
Serial.write(stat_rx>>24); |
||||||
|
Serial.write(stat_rx>>16); |
||||||
|
Serial.write(stat_rx>>8); |
||||||
|
Serial.write(stat_rx); |
||||||
|
Serial.write(FEND); |
||||||
|
} |
||||||
|
|
||||||
|
void kiss_indicate_stat_tx() { |
||||||
|
Serial.write(FEND); |
||||||
|
Serial.write(CMD_STAT_TX); |
||||||
|
Serial.write(stat_tx>>24); |
||||||
|
Serial.write(stat_tx>>16); |
||||||
|
Serial.write(stat_tx>>8); |
||||||
|
Serial.write(stat_tx); |
||||||
|
Serial.write(FEND); |
||||||
|
} |
||||||
|
|
||||||
|
void kiss_indicate_stat_rssi() { |
||||||
|
Serial.write(FEND); |
||||||
|
Serial.write(CMD_STAT_RSSI); |
||||||
|
Serial.write((uint8_t)last_rssi+rssi_offset); |
||||||
|
Serial.write(FEND); |
||||||
|
} |
||||||
|
|
||||||
|
void kiss_indicate_radio_lock() { |
||||||
|
Serial.write(FEND); |
||||||
|
Serial.write(CMD_RADIO_LOCK); |
||||||
|
Serial.write(radio_locked); |
||||||
|
Serial.write(FEND); |
||||||
|
} |
||||||
|
|
||||||
|
void kiss_indicate_spreadingfactor() { |
||||||
|
Serial.write(FEND); |
||||||
|
Serial.write(CMD_SF); |
||||||
|
Serial.write((uint8_t)lora_sf); |
||||||
|
Serial.write(FEND); |
||||||
|
} |
||||||
|
|
||||||
|
void kiss_indicate_txpower() { |
||||||
|
Serial.write(FEND); |
||||||
|
Serial.write(CMD_TXPOWER); |
||||||
|
Serial.write((uint8_t)lora_txp); |
||||||
|
Serial.write(FEND); |
||||||
|
} |
||||||
|
|
||||||
|
void kiss_indicate_bandwidth() { |
||||||
|
Serial.write(FEND); |
||||||
|
Serial.write(CMD_BANDWIDTH); |
||||||
|
Serial.write(lora_bw>>24); |
||||||
|
Serial.write(lora_bw>>16); |
||||||
|
Serial.write(lora_bw>>8); |
||||||
|
Serial.write(lora_bw); |
||||||
|
Serial.write(FEND); |
||||||
|
} |
||||||
|
|
||||||
|
void kiss_indicate_frequency() { |
||||||
|
Serial.write(FEND); |
||||||
|
Serial.write(CMD_FREQUENCY); |
||||||
|
Serial.write(lora_freq>>24); |
||||||
|
Serial.write(lora_freq>>16); |
||||||
|
Serial.write(lora_freq>>8); |
||||||
|
Serial.write(lora_freq); |
||||||
|
Serial.write(FEND); |
||||||
|
} |
||||||
|
|
||||||
|
void kiss_indicate_random(uint8_t byte) { |
||||||
|
Serial.write(FEND); |
||||||
|
Serial.write(CMD_RANDOM); |
||||||
|
Serial.write(byte); |
||||||
|
Serial.write(FEND); |
||||||
|
} |
||||||
|
|
||||||
|
bool isSplitPacket(uint8_t header) { |
||||||
|
return (header & FLAG_SPLIT); |
||||||
|
} |
||||||
|
|
||||||
|
uint8_t packetSequence(uint8_t header) { |
||||||
|
return header >> 4; |
||||||
|
} |
||||||
|
|
||||||
|
void getPacketData(int len) { |
||||||
|
while (len--) { |
||||||
|
pbuf[read_len++] = LoRa.read(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void setSpreadingFactor() { |
||||||
|
if (radio_online) LoRa.setSpreadingFactor(lora_sf); |
||||||
|
} |
||||||
|
|
||||||
|
void setTXPower() { |
||||||
|
if (radio_online) LoRa.setTxPower(lora_txp); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void getBandwidth() { |
||||||
|
if (radio_online) { |
||||||
|
lora_bw = LoRa.getSignalBandwidth(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void setBandwidth() { |
||||||
|
if (radio_online) { |
||||||
|
LoRa.setSignalBandwidth(lora_bw); |
||||||
|
getBandwidth(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void getFrequency() { |
||||||
|
if (radio_online) { |
||||||
|
lora_freq = LoRa.getFrequency(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void setFrequency() { |
||||||
|
if (radio_online) { |
||||||
|
LoRa.setFrequency(lora_freq); |
||||||
|
getFrequency(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
uint8_t getRandom() { |
||||||
|
if (radio_online) { |
||||||
|
return LoRa.random(); |
||||||
|
} else { |
||||||
|
return 0x00; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue