Englebert
4 years ago
commit
b5ab8bdceb
1 changed files with 423 additions and 0 deletions
-
423OpenFlightRX.ino
@ -0,0 +1,423 @@ |
|||||
|
/*
|
||||
|
* Filename: OpenFlightRX.ino |
||||
|
* Description: |
||||
|
* To receive signals from LoRA module and configurable over WiFi |
||||
|
* Author: Englebert |
||||
|
* Date: Fri 25 Sep 2020 04:22:40 PM +08 |
||||
|
* |
||||
|
* TODO/Wish Lists: |
||||
|
* 1. BT Serial Relay - For INAV |
||||
|
* 2. WiFi Configuration - NOT going to work because going to cause issue on LoRA speed. Demolish the idea. |
||||
|
* 3. Status Display - |
||||
|
* 4. Sending SBUS over ESP32 |
||||
|
* 5. Serial Configuration for the 1st time or debugging |
||||
|
* 6. Configuration over LoRA signals using the last byte. |
||||
|
* |
||||
|
* |
||||
|
* REF: |
||||
|
* WiFi AP - https://randomnerdtutorials.com/esp32-access-point-ap-web-server/
|
||||
|
* |
||||
|
* Frequency for RFM95W: |
||||
|
* 900MHz ~ 930MHz (900000000Hz - 930000000Hz) |
||||
|
* |
||||
|
* EEPROM Format: |
||||
|
* |
||||
|
* HFFFFS |
||||
|
* |
||||
|
* H: Header. Must be equal to 0x70. Else this will be consider not valid |
||||
|
* FFFF: 4 bytes Frequency Channel Number |
||||
|
* S: Sync word. Key to prevent other LoRA channels listened. Valid Range: 0x00 ~ 0xFF |
||||
|
* |
||||
|
* Signal Format: |
||||
|
* TTYYPPRRS |
||||
|
* TYPRS---- |
||||
|
* Hell0 012 |
||||
|
*/ |
||||
|
|
||||
|
// LoRA Module Needed
|
||||
|
#include <SPI.h>
|
||||
|
#include <LoRa.h>
|
||||
|
|
||||
|
// Display
|
||||
|
#include <Adafruit_GFX.h>
|
||||
|
#include <Adafruit_SSD1306.h>
|
||||
|
|
||||
|
// For storing configurations and settings
|
||||
|
#include <EEPROM.h>
|
||||
|
|
||||
|
//define the pins used by the transceiver module
|
||||
|
#define SS 5
|
||||
|
#define RST 14
|
||||
|
#define DIO0 2
|
||||
|
|
||||
|
#define SCREEN_WIDTH 128 // OLED display width, in pixels
|
||||
|
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
|
||||
|
|
||||
|
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
|
||||
|
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
|
||||
|
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); |
||||
|
|
||||
|
uint64_t last_received_lora = 0; |
||||
|
uint64_t last_display = 0; |
||||
|
uint32_t uptime = 0; |
||||
|
uint32_t lora_packets = 0; |
||||
|
uint32_t lora_packets_per_second = 0; |
||||
|
uint32_t delayed = 0; |
||||
|
uint32_t frequency = 900000000; |
||||
|
uint8_t syncword = 0x00; |
||||
|
bool stop_delay = false; |
||||
|
bool tx_mode = false; |
||||
|
bool oled = true; |
||||
|
uint8_t counter = 0; |
||||
|
|
||||
|
String LoRaData; |
||||
|
|
||||
|
// Example:
|
||||
|
// String a = explode("Data|Raw1|Raw2", "|", 4);
|
||||
|
String explode(String data, char separator, int index) { |
||||
|
int found = 0; |
||||
|
int strIndex[] = {0, -1}; |
||||
|
int maxIndex = data.length() - 1; |
||||
|
|
||||
|
for(int i = 0; i <= maxIndex && found<=index; i++) { |
||||
|
if(data.charAt(i) == separator || i == maxIndex) { |
||||
|
found++; |
||||
|
strIndex[0] = strIndex[1]+1; |
||||
|
strIndex[1] = (i == maxIndex) ? i+1 : i; |
||||
|
} |
||||
|
} |
||||
|
return found>index ? data.substring(strIndex[0], strIndex[1]) : ""; |
||||
|
} |
||||
|
|
||||
|
void showFreeMem() { |
||||
|
Serial.println(F("")); |
||||
|
Serial.print(F("FREE Memory: ")); |
||||
|
Serial.println(ESP.getFreeHeap()); |
||||
|
} |
||||
|
|
||||
|
void showHelp() { |
||||
|
Serial.println(F("*** Help ***")); |
||||
|
Serial.print(F("free - Show FREE memory\nhelp - this page\nreboot - restart the device\nsetfreq - change frequency and syncword\ngetfreq - retrive current settings\ntx - TX Mode\nrx - RX Mode\n")); |
||||
|
} |
||||
|
|
||||
|
void resetFunc(void) { |
||||
|
ESP.restart(); |
||||
|
} |
||||
|
|
||||
|
void getOpenFlightRXSettings(void) { |
||||
|
uint16_t addr = 0x00; |
||||
|
|
||||
|
// If heder not the same then use the default settings
|
||||
|
if(EEPROM.read(addr) != 0x70) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Retriving data
|
||||
|
frequency = (EEPROM.read(0x01) << 24) | (EEPROM.read(0x02) << 16) | (EEPROM.read(0x03) << 8) | (EEPROM.read(0x04)); |
||||
|
|
||||
|
/*
|
||||
|
Serial.println(frequency); |
||||
|
Serial.println(EEPROM.read(0x01), HEX); |
||||
|
Serial.println(EEPROM.read(0x02), HEX); |
||||
|
Serial.println(EEPROM.read(0x03), HEX); |
||||
|
Serial.println(EEPROM.read(0x04), HEX); |
||||
|
*/ |
||||
|
|
||||
|
// Default to minimum if less then 900MHz
|
||||
|
if(frequency < 900000000) frequency = 900000000; |
||||
|
|
||||
|
// Default to maximum if more than 930MHz
|
||||
|
if(frequency > 930000000) frequency = 930000000; |
||||
|
|
||||
|
// Sync Word
|
||||
|
syncword = EEPROM.read(0x05); |
||||
|
|
||||
|
// Receiver or TX mode
|
||||
|
tx_mode = EEPROM.read(0x06) & 0x01; |
||||
|
|
||||
|
// Debug...
|
||||
|
Serial.print(F("Freq:")); |
||||
|
Serial.print(frequency); |
||||
|
Serial.println(F("Hz")); |
||||
|
|
||||
|
Serial.print(F("Sync:")); |
||||
|
Serial.println(syncword, HEX); |
||||
|
|
||||
|
Serial.print(F("Mode:")); |
||||
|
Serial.println(tx_mode, DEC); |
||||
|
} |
||||
|
|
||||
|
void setOpenFlightRXSettings(void) { |
||||
|
uint8_t addr = 0x00; |
||||
|
|
||||
|
// Header
|
||||
|
write_data(addr++, 0x70); |
||||
|
|
||||
|
// Frequency
|
||||
|
write_data(addr++, ((frequency & 0xFF000000) >> 24 )); |
||||
|
Serial.println(EEPROM.read(addr - 1), HEX); |
||||
|
|
||||
|
write_data(addr++, ((frequency & 0x00FF0000) >> 16 )); |
||||
|
Serial.println(EEPROM.read(addr - 1), HEX); |
||||
|
write_data(addr++, ((frequency & 0x0000FF00) >> 8)); |
||||
|
Serial.println(EEPROM.read(addr - 1), HEX); |
||||
|
write_data(addr++, ((frequency & 0x000000FF))); |
||||
|
Serial.println(EEPROM.read(addr - 1), HEX); |
||||
|
// Sync Word
|
||||
|
write_data(addr++, syncword); |
||||
|
Serial.println(EEPROM.read(addr - 1), HEX); |
||||
|
// TX Mode/RX Mode
|
||||
|
write_data(addr++, (tx_mode)); |
||||
|
Serial.println(EEPROM.read(addr - 1), HEX); |
||||
|
|
||||
|
|
||||
|
Serial.println(F("**** New Settings Saved *****")); |
||||
|
Serial.print(F("FREQ:")); |
||||
|
Serial.println(frequency); |
||||
|
Serial.print(F("SYNC:")); |
||||
|
Serial.println(syncword, HEX); |
||||
|
Serial.print(F("MODE:")); |
||||
|
Serial.println(tx_mode, DEC); |
||||
|
} |
||||
|
|
||||
|
void resetConfig(void) { |
||||
|
// Erase 1st byte will do.
|
||||
|
EEPROM.write(0x00, 0x00); |
||||
|
EEPROM.commit(); |
||||
|
} |
||||
|
|
||||
|
void write_data(uint16_t addr, uint8_t val) { |
||||
|
// Only enabel the timerAlarmDisable if crash in future....
|
||||
|
// timerAlarmDisable(timer);
|
||||
|
EEPROM.write(addr, val); |
||||
|
EEPROM.commit(); |
||||
|
// timerAlarmEnable(timer);
|
||||
|
} |
||||
|
|
||||
|
/* create a hardware timer */ |
||||
|
hw_timer_t * timer = NULL; |
||||
|
|
||||
|
void IRAM_ATTR onTimer(){ |
||||
|
uptime++; |
||||
|
if(!stop_delay) delayed++; |
||||
|
lora_packets_per_second = lora_packets; |
||||
|
lora_packets = 0; |
||||
|
} |
||||
|
|
||||
|
void setup() { |
||||
|
//initialize Serial Monitor
|
||||
|
Serial.begin(115200); |
||||
|
|
||||
|
while (!Serial); |
||||
|
Serial.println(F("OpenFlightRX v1.0 @ 2020")); |
||||
|
|
||||
|
// Define a range for the EEPROM (512 bytes). May be can be lesser
|
||||
|
EEPROM.begin(512); |
||||
|
|
||||
|
// Getting settings and starts the system
|
||||
|
getOpenFlightRXSettings(); |
||||
|
|
||||
|
// Setup LoRa transceiver module
|
||||
|
LoRa.setPins(SS, RST, DIO0); |
||||
|
|
||||
|
|
||||
|
// while (!LoRa.begin(914990000)) {
|
||||
|
Serial.print(F("Starting up LoRA")); |
||||
|
while(!LoRa.begin(frequency)) { |
||||
|
Serial.print(F(".")); |
||||
|
delay(500); |
||||
|
} |
||||
|
Serial.println(F("OK")); |
||||
|
|
||||
|
// The sync word assures you don't get LoRa messages from other LoRa transceivers
|
||||
|
// ranges from 0-0xFF
|
||||
|
LoRa.setSyncWord(syncword); |
||||
|
LoRa.setPreambleLength(8); |
||||
|
// LoRa.setSpreadingFactor(6);
|
||||
|
// LoRa.setSpreadingFactor(7);
|
||||
|
//7.8E3, 10.4E3, 15.6E3, 20.8E3, 31.25E3, 41.7E3, 62.5E3, 125E3, and 250E3.
|
||||
|
// LoRa.setSignalBandwidth(250E3);
|
||||
|
// LoRa.setCodingRate4(5);
|
||||
|
// LoRa.setSpreadingFactor(9);
|
||||
|
// LoRa.setSignalBandwidth(62.5E3);
|
||||
|
// LoRa.setCodingRate4(8);
|
||||
|
|
||||
|
/* Use 1st timer of 4 */ |
||||
|
/* 1 tick take 1/(80MHZ/80) = 1us so we set divider 80 and count up */ |
||||
|
timer = timerBegin(0, 80, true); |
||||
|
|
||||
|
/* Attach onTimer function to our timer */ |
||||
|
timerAttachInterrupt(timer, &onTimer, true); |
||||
|
|
||||
|
/* Set alarm to call onTimer function every second 1 tick is 1us => 1 second is 1000000us */ |
||||
|
/* Repeat the alarm (third parameter) */ |
||||
|
timerAlarmWrite(timer, 1000000, true); |
||||
|
|
||||
|
/* Start an alarm */ |
||||
|
timerAlarmEnable(timer); |
||||
|
|
||||
|
/**** TO BE COMMENTED OUT ****/ |
||||
|
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
|
||||
|
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { |
||||
|
Serial.println(F("SSD1306 not found")); |
||||
|
oled = false; |
||||
|
} |
||||
|
|
||||
|
if(oled) { |
||||
|
// Clear the buffer
|
||||
|
display.clearDisplay(); |
||||
|
|
||||
|
display.setTextSize(2); |
||||
|
display.setTextColor(SSD1306_WHITE); |
||||
|
display.setCursor(0, 0); |
||||
|
|
||||
|
display.print("START RX LORA..."); |
||||
|
display.display(); |
||||
|
|
||||
|
display.clearDisplay(); |
||||
|
display.setTextColor(SSD1306_WHITE); |
||||
|
display.setCursor(0, 0); |
||||
|
|
||||
|
display.print("DONE!"); |
||||
|
display.display(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void loop() { |
||||
|
if(!tx_mode) { |
||||
|
// try to parse packet
|
||||
|
int packetSize = LoRa.parsePacket(); |
||||
|
if (packetSize) { |
||||
|
// received a packet
|
||||
|
// Serial.print("Received packet '");
|
||||
|
if(!stop_delay) { |
||||
|
stop_delay = true; |
||||
|
} |
||||
|
|
||||
|
// read packet
|
||||
|
while (LoRa.available()) { |
||||
|
LoRaData = LoRa.readString(); |
||||
|
// Serial.print(LoRaData);
|
||||
|
} |
||||
|
lora_packets++; |
||||
|
|
||||
|
last_received_lora = millis(); |
||||
|
|
||||
|
// print RSSI of packet
|
||||
|
// Serial.print("' with RSSI ");
|
||||
|
// Serial.println(LoRa.packetRssi());
|
||||
|
// if(millis() - last_display > 1000) {
|
||||
|
if(oled) { |
||||
|
display.clearDisplay(); |
||||
|
display.setTextSize(2); |
||||
|
display.setTextColor(SSD1306_WHITE); |
||||
|
display.setCursor(0, 0); |
||||
|
|
||||
|
display.print("RSSI:"); |
||||
|
display.print(LoRa.packetRssi()); |
||||
|
display.setCursor(0, 16); |
||||
|
display.print("SNR:"); |
||||
|
display.print(LoRa.packetSnr()); |
||||
|
display.setTextSize(1); |
||||
|
display.setCursor(0, 32); |
||||
|
display.print("Data:"); |
||||
|
display.print(LoRaData); |
||||
|
display.setCursor(0, 48); |
||||
|
display.print("Packet/s:"); |
||||
|
display.print(lora_packets_per_second); |
||||
|
display.setCursor(0, 40); |
||||
|
display.print("Delayed:"); |
||||
|
display.print(delayed); |
||||
|
display.setCursor(0, 56); |
||||
|
display.print("Up:"); |
||||
|
display.print(uptime); |
||||
|
display.setCursor(64, 56); |
||||
|
display.print("Band: "); |
||||
|
display.print(LoRa.packetFrequencyError()); |
||||
|
display.display(); |
||||
|
} |
||||
|
/*
|
||||
|
Serial.print(F("RSSI:")); |
||||
|
Serial.println(LoRa.packetRssi()); |
||||
|
Serial.print(F("SNR:")); |
||||
|
Serial.println(LoRa.packetSnr()); |
||||
|
Serial.print(F("Data:")); |
||||
|
Serial.println(LoRaData); |
||||
|
Serial.print(F("Packet/s:")); |
||||
|
Serial.println(lora_packets_per_second); |
||||
|
*/ |
||||
|
|
||||
|
last_display = millis(); |
||||
|
} else { |
||||
|
if(millis() - last_received_lora > 1000) { |
||||
|
if(oled) { |
||||
|
display.clearDisplay(); |
||||
|
display.setCursor(0, 0); |
||||
|
display.setTextColor(SSD1306_WHITE); |
||||
|
display.print("SIGNAL LOST"); |
||||
|
display.display(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
// TX mode. For distance checking via remote ;)
|
||||
|
LoRa.beginPacket(); |
||||
|
LoRa.print("HELLO "); |
||||
|
LoRa.print(counter); |
||||
|
LoRa.endPacket(); |
||||
|
|
||||
|
if(oled) { |
||||
|
display.clearDisplay(); |
||||
|
display.setTextSize(2); |
||||
|
display.setTextColor(SSD1306_WHITE); |
||||
|
display.setCursor(0, 0); |
||||
|
|
||||
|
display.print("TX MODE"); |
||||
|
display.display(); |
||||
|
} |
||||
|
counter++; |
||||
|
delay(25); |
||||
|
} |
||||
|
|
||||
|
// Processing CLI
|
||||
|
if(Serial.available() > 0){ |
||||
|
String serial_commands_string = Serial.readStringUntil('\n'); |
||||
|
serial_commands_string.trim(); |
||||
|
|
||||
|
String serial_command = explode(serial_commands_string, ' ', 0); |
||||
|
|
||||
|
if(serial_command == "reset") { |
||||
|
Serial.println(F("Clearing EEPROM settings...")); |
||||
|
resetConfig(); |
||||
|
resetFunc(); |
||||
|
} else if(serial_command == "free") { |
||||
|
showFreeMem(); |
||||
|
} else if(serial_command == "help") { |
||||
|
showHelp(); |
||||
|
} else if(serial_command == "reboot") { |
||||
|
resetFunc(); |
||||
|
} else if(serial_command == "setfreq") { |
||||
|
String frequency_raw = explode(serial_commands_string, ' ', 1); |
||||
|
String syncword_raw = explode(serial_commands_string, ' ', 2); |
||||
|
if( |
||||
|
frequency_raw.length() > 0 && |
||||
|
syncword_raw.length() > 0) { |
||||
|
frequency = frequency_raw.toInt(); |
||||
|
syncword = (uint8_t) (syncword_raw.toInt() & 0xFF); |
||||
|
setOpenFlightRXSettings(); |
||||
|
} |
||||
|
} else if(serial_command == "getfreq") { |
||||
|
Serial.print(F("FREQ:")); |
||||
|
Serial.println(frequency); |
||||
|
|
||||
|
Serial.print(F("SYNC:")); |
||||
|
Serial.println(syncword, HEX); |
||||
|
} else if(serial_command == "tx") { |
||||
|
tx_mode = true; |
||||
|
setOpenFlightRXSettings(); |
||||
|
} else if(serial_command == "rx") { |
||||
|
tx_mode = false; |
||||
|
setOpenFlightRXSettings(); |
||||
|
} |
||||
|
} |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue