A LoRa APRS node with KISS interface based on a Raspberry Pi Pico
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.
 
 
 
 
 
 

244 lines
4.8 KiB

#include <SPI.h>
#include "LoRa.h"
#include "Config.h"
#include "KISS.h"
void setup() {
// put your setup code here, to run once:
Serial.begin(serialBaudRate);
while (!Serial); // Waiting until LoRa32u4 is ready
// Buffers
memset(rxBuffer, 0, sizeof(rxBuffer));
memset(txBuffer, 0, sizeof(txBuffer));
LoRa.setPins(pinNSS, pinNRST, pinDIO0);
startRadio();
}
bool startRadio() {
if (!LoRa.begin(loraFrequency)) {
kissIndicateError(ERROR_INITRADIO);
Serial.println("FAIL");
while(1);
}
else {
Serial.println("SUCCESS");
LoRa.setSpreadingFactor(loraSpreadingFactor);
LoRa.setCodingRate4(loraCodingRate);
LoRa.enableCrc();
LoRa.onReceive(receiveCallback);
LoRa.receive();
}
}
void transmit(size_t size) {
size_t written = 0;
if (size > MTU) {
size = MTU;
}
LoRa.beginPacket();
for (size_t i; i < size; i++) {
LoRa.write(txBuffer[i]);
written++;
}
LoRa.endPacket();
LoRa.receive();
}
void serialCallback(uint8_t txByte) {
if (inFrame && txByte == FEND && command == CMD_DATA) {
inFrame = false;
//Serial.println("FULL_KISS");
if (outboundReady) {
kissIndicateError(ERROR_QUEUE_FULL);
}
else {
outboundReady = true;
//Serial.println("RDY_OUT");
}
}
else if (txByte == FEND) {
//Serial.println("KISS_FLAG");
inFrame = true;
command = CMD_UNKNOWN;
frameLength = 0;
}
else if (inFrame && frameLength < MTU) {
// Get command byte
if (frameLength == 0 && command == CMD_UNKNOWN) {
//Serial.println("ACQ_CMD");
command = txByte;
}
else if (command == CMD_DATA) {
if (txByte == FESC) {
escape = true;
}
else {
if (escape) {
if (txByte == TFEND) {
txByte = FEND;
}
if (txByte == TFESC) {
txByte = FESC;
}
escape = false;
}
else {
txBuffer[frameLength++] = txByte;
}
}
}
}
}
void updateModemStatus() {
uint8_t status = LoRa.modemStatus();
lastStatusUpdate = millis();
if (status & SIG_DETECT == 0x01) {
statSignalDetected = true;
}
else {
statSignalDetected = false;
}
if (status & SIG_SYNCED == 0x01) {
statSignalSynced = true;
}
else {
statSignalSynced = false;
}
if (status & RX_ONGOING == 0x01) {
statRxOngoing = true;
}
else {
statRxOngoing = false;
}
if (statSignalDetected || statSignalSynced || statRxOngoing) {
if (dcdCount < dcdThreshold) {
dcdCount++;
dcd = true;
}
else {
dcd = true;
dcdLed = true;
}
}
else {
if (dcdCount > 0) {
dcdCount--;
}
else {
dcdLed = false;
}
dcd = false;
}
}
bool isOutboundReady() {
return outboundReady;
}
void checkModemStatus() {
if (millis() - lastStatusUpdate >= statusIntervalms) {
updateModemStatus();
}
}
void receiveCallback(int packetSize) {
readLength = 0;
lastRssi = LoRa.packetRssi();
getPacketData(packetSize);
// Send RSSI
Serial.write(FEND);
Serial.write(HW_RSSI);
Serial.write((uint8_t)(lastRssi-rssiOffset));
Serial.write(FEND);
// And then write the entire packet
Serial.write(FEND);
Serial.write((uint8_t)CMD_DATA);
for (int i = 0; i < readLength; i++) {
uint8_t temp = rxBuffer[i];
if (temp == FEND) {
Serial.write(FESC);
temp = TFEND;
}
if (temp == FESC) {
Serial.write(FESC);
temp = TFESC;
}
Serial.write(temp);
}
Serial.write(FEND);
readLength = 0;
}
void escapedSerialWrite (uint8_t bufferByte) {
switch(bufferByte) {
case FEND:
Serial.write(FESC);
Serial.write(TFEND);
break;
case FESC:
Serial.write(FESC);
Serial.write(TFESC);
break;
default:
Serial.write(bufferByte);
}
}
void kissIndicateError(uint8_t errorCode) {
Serial.write(FEND);
Serial.write(CMD_ERROR);
Serial.write(errorCode);
Serial.write(FEND);
}
void getPacketData(int packetLength) {
while (packetLength--) {
rxBuffer[readLength++] = LoRa.read();
}
}
void loop() {
// put your main code here, to run repeatedly:
checkModemStatus();
if (isOutboundReady() && !SERIAL_READING) {
if (!dcdWaiting) {
updateModemStatus();
}
if (!dcd && !dcdLed) {
if (dcdWaiting)
delay(loraRxTurnaround);
updateModemStatus();
if (!dcd) {
dcdWaiting = false;
outboundReady = false;
//Serial.println("CLR_TRANSMIT");
transmit(frameLength);
}
else {
dcdWaiting = true;
}
}
}
if (Serial.available()) {
SERIAL_READING = true;
char txByte = Serial.read();
serialCallback(txByte);
lastSerialRead = millis();
}
else {
if (SERIAL_READING && millis() - lastSerialRead >= serialReadTimeout) {
SERIAL_READING = false;
}
}
}