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