From b96cbcc0604c404c1fed175a7b5a8e600e14bcf0 Mon Sep 17 00:00:00 2001 From: roema Date: Sun, 7 Mar 2021 21:59:21 +0100 Subject: [PATCH] json config file / multi ssid / oled improvements --- ognbase/APRS.cpp | 924 +++---- ognbase/APRS.h | 225 +- ognbase/D1090.cpp | 3 +- ognbase/EEPROM.cpp | 44 +- ognbase/EEPROM.h | 26 +- ognbase/GNSS.cpp | 2077 ++++++++-------- ognbase/GNSS.h | 138 +- ognbase/JSON.cpp | 6 +- ognbase/JSON.h | 194 +- ognbase/Log.cpp | 203 +- ognbase/MAVLink.cpp | 3 +- ognbase/MONIT.cpp | 47 +- ognbase/OLED.cpp | 490 ++-- ognbase/OLED.h | 72 +- ognbase/Platform_ESP32.cpp | 2653 ++++++++++---------- ognbase/Protocol_FANET.cpp | 863 ++++--- ognbase/Protocol_FANET.h | 281 ++- ognbase/Protocol_Legacy.cpp | 670 ++--- ognbase/RF.cpp | 4652 ++++++++++++++++++----------------- ognbase/RF.h | 238 +- ognbase/RSM.cpp | 20 +- ognbase/SoftRF.h | 442 ++-- ognbase/Time.cpp | 318 +-- ognbase/Traffic.cpp | 467 ++-- ognbase/Web.cpp | 962 ++++---- ognbase/WiFi.cpp | 581 ++--- ognbase/config.cpp | 357 ++- ognbase/config.h | 60 +- ognbase/data/config.json | 54 + ognbase/data/config.xml | 27 - ognbase/data/zabbix.txt | 3 - ognbase/global.h | 35 +- ognbase/logos.h | 167 ++ ognbase/ogn_service.pb.c | 46 +- ognbase/ogn_service.pb.h | 437 ++-- ognbase/ognbase.ino | 54 +- ognbase/version.h | 22 +- 37 files changed, 9141 insertions(+), 8720 deletions(-) create mode 100644 ognbase/data/config.json delete mode 100644 ognbase/data/config.xml delete mode 100644 ognbase/data/zabbix.txt create mode 100644 ognbase/logos.h diff --git a/ognbase/APRS.cpp b/ognbase/APRS.cpp index 075882b..9dc15d4 100644 --- a/ognbase/APRS.cpp +++ b/ognbase/APRS.cpp @@ -1,461 +1,463 @@ -/* - OGN.cpp - Copyright (C) 2020 Manuel Rösel - - 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 . -*/ - -#include "APRS.h" -#include "SoftRF.h" -#include "Battery.h" -#include "Traffic.h" -#include "RF.h" -#include "EEPROM.h" -#include "global.h" -#include "Log.h" -#include "OLED.h" - - -#include - -#define kKey 0x73e2 - -int MIN_SPEED = 0; - -const char aprsServer[] = "aprs.glidernet.org"; - -int aprsPort = 14580; -int aprs_registred = 0; -bool aprs_connected = false; -int last_packet_time = 0; // seconds -int ap_uptime = 0; - -#define seconds() (millis() / 1000) - -static String zeroPadding(String data, int len) -{ - if (data.charAt(2) == '.') { - data.remove(len, data.length()); - } - - if (data.charAt(1) == '.') { - data.remove(len - 1, data.length()); - } - String tmp = ""; - for (int i = data.length(); i < len; i++) - tmp += "0"; - tmp += data; - return tmp; -} - -static String getWW(String data) -{ - String tmp = data; - int len = tmp.length(); - tmp.remove(0, len - 1); - return tmp; -} - -static float SnrCalc(float rssi) -{ - float noise = -108.0; - return rssi - (noise); -} - -static short AprsPasscode(const char* theCall) -{ - char rootCall[10]; - char* p1 = rootCall; - - while ((*theCall != '-') && (*theCall != 0) && (p1 < rootCall + 9)) { - *p1++ = toupper(*theCall++); - } - - *p1 = 0; - - short hash = kKey; - short i = 0; - short len = strlen(rootCall); - char* ptr = rootCall; - - while (i < len) { - hash ^= (*ptr++) << 8; - hash ^= (*ptr++); - i += 2; - } - - return hash & 0x7fff; -} - -static long double toRadians(const long double degree) -{ - long double one_deg = (M_PI) / 180; - return one_deg * degree; -} - -static long double distance(long double lat1, long double long1, long double lat2, long double long2) -{ - lat1 = toRadians(lat1); - long1 = toRadians(long1); - lat2 = toRadians(lat2); - long2 = toRadians(long2); - - long double dlong = long2 - long1; - long double dlat = lat2 - lat1; - - long double ans = pow(sin(dlat / 2), 2) + - cos(lat1) * cos(lat2) * - pow(sin(dlong / 2), 2); - - ans = 2 * asin(sqrt(ans)); - - long double R = 6371; - ans = ans * R; - - return ans * 1000; -} - -static bool OGN_APRS_Connect() -{ - if (SoC->WiFi_connect_TCP(aprsServer, aprsPort)) - return true; - else - return false; -} - -static bool OGN_APRS_DisConnect() -{ - if (!SoC->WiFi_disconnect_TCP()) - return true; - return false; -} - -static int OGN_APRS_check_reg(String* msg) // 0 = unverified // 1 = verified // -1 = wrong message -{ - int len = msg->length(); - - if (msg->indexOf("verified") > -1) - return 1; - if (msg->indexOf("unverified") > -1) - return 0; - if (msg->indexOf("invalid") > -1) - return 2; - - return -1; -} - -bool OGN_APRS_check_Wifi() -{ - if (WiFi.status() != WL_CONNECTED && WiFi.getMode() == WIFI_STA) - { - WiFi.disconnect(); - WiFi.mode(WIFI_OFF); - WiFi.mode(WIFI_STA); - WiFi.begin(ogn_ssid.c_str(), ogn_wpass.c_str()); - delay(100); - } - if (WiFi.status() == WL_CONNECTED){ - return true; - } - else{ - Serial.println("more then 3 minutes in AP mode reset"); - SoC->reset(); - } - return false; -} - -int OGN_APRS_check_messages() -{ - char* RXbuffer = (char *) malloc(512); - int recStatus = SoC->WiFi_receive_TCP(RXbuffer, 512); - String msg; - - for (int i = 0; i < recStatus; i++) - msg += RXbuffer[i]; - - - if (recStatus > 0) - { - - if (OGN_APRS_check_reg(&msg) == 0) - msg = "login unsuccessful"; - - if (OGN_APRS_check_reg(&msg) == 1) - msg = "login successful"; - - last_packet_time = seconds(); - } - - Logger_send_udp(&msg); - - if (seconds() - last_packet_time > 60) - { - msg = "no packet since > 60 seconds...reconnecting"; - Logger_send_udp(&msg); - SoC->WiFi_disconnect_TCP(); - aprs_registred = 0; - } - - - free(RXbuffer); - return aprs_registred; -} - -void OGN_APRS_Export() -{ - struct aprs_airc_packet APRS_AIRC; - time_t this_moment = now(); - - String symbol_table[16] = {"/", "/", "\\", "/", "\\", "\\", "/", "/", "\\", "J", "/", "/", "M", "/", "\\", "\\"}; // 0x79 -> aircraft type 1110 dec 14 & 0x51 -> aircraft type 4 - String symbol[16] = {"z", "^", "^", "X", "", "^", "g", "g", "^", "^", "^", "O", "^", "\'", "", "n", }; - - - for (int i = 0; i < MAX_TRACKING_OBJECTS; i++) - if (Container[i].addr && (this_moment - Container[i].timestamp) <= EXPORT_EXPIRATION_TIME && Container[i].distance < settings->range * 1000) - { - if (Container[i].distance / 1000 > largest_range) - largest_range = Container[i].distance / 1000; - - float LAT = fabs(Container[i].latitude); - float LON = fabs(Container[i].longitude); - - - APRS_AIRC.callsign = zeroPadding(String(Container[i].addr, HEX),6); - APRS_AIRC.callsign.toUpperCase(); - APRS_AIRC.rec_callsign = ogn_callsign; - - - // TBD need to use Container[i].timestamp instead of hour(), minute(), second() - // actually, need to make sure Container[i].timestamp is based on SlotTime not current time due slot-2 time extension - //converting Container[i].timestamp to hour minutes seconds - - time_t receive_time = Container[i].timestamp; - APRS_AIRC.timestamp = zeroPadding(String(hour(receive_time)), 2) + zeroPadding(String(minute(receive_time)), 2) + zeroPadding(String(second(receive_time)), 2) + "h"; - - /*Latitude*/ - APRS_AIRC.lat_deg = String(int(LAT)); - APRS_AIRC.lat_min = zeroPadding(String((LAT - int(LAT)) * 60, 3), 5); - - /*Longitude*/ - APRS_AIRC.lon_deg = zeroPadding(String(int(LON)), 3); - APRS_AIRC.lon_min = zeroPadding(String((LON - int(LON)) * 60, 3), 5); - - /*Altitude*/ - APRS_AIRC.alt = zeroPadding(String(int(Container[i].altitude * 3.28084)), 6); - - APRS_AIRC.heading = zeroPadding(String(int(Container[i].course)), 3); - APRS_AIRC.ground_speed = zeroPadding(String(int(Container[i].speed)), 3); - - - APRS_AIRC.sender_details = zeroPadding(String(Container[i].aircraft_type << 2 | (Container[i].stealth << 7) | (Container[i].no_track << 6) | Container[i].addr_type, HEX), 2); - - APRS_AIRC.symbol_table = symbol_table[Container[i].aircraft_type]; - APRS_AIRC.symbol = symbol[Container[i].aircraft_type]; - - APRS_AIRC.snr = String(SnrCalc( Container[i].rssi), 1); - - - String W_lat = String((LAT - int(LAT)) * 60, 3); - String W_lon = String((LON - int(LON)) * 60, 3); - - - APRS_AIRC.pos_precision = getWW(W_lat) + getWW(W_lon); - - if (Container[i].vs >= 0) - APRS_AIRC.climbrate = "+" + zeroPadding(String(int(Container[i].vs)), 3); - else - APRS_AIRC.climbrate = zeroPadding(String(int(Container[i].vs)), 3); - - String AircraftPacket = ""; - - if (Container[i].addr_type == 1) - AircraftPacket = "ICA"; - if (Container[i].addr_type == 2) - AircraftPacket += "FLR"; - if (Container[i].addr_type == 3) - AircraftPacket += "OGN"; - if (Container[i].addr_type == 4) - AircraftPacket += "P3I"; - if (Container[i].addr_type == 5) - AircraftPacket += "FNT"; - if (Container[i].addr_type == 0 || Container[i].addr_type > 5) - AircraftPacket += "RANDOM"; - - AircraftPacket += APRS_AIRC.callsign; - APRS_AIRC.sender_details.toUpperCase(); - - AircraftPacket += ">APRS,qAS,"; - AircraftPacket += APRS_AIRC.rec_callsign; - AircraftPacket += ":/"; - AircraftPacket += APRS_AIRC.timestamp; - AircraftPacket += APRS_AIRC.lat_deg; - AircraftPacket += APRS_AIRC.lat_min; - if (Container[i].latitude < 0) - AircraftPacket += "S"; - else - AircraftPacket += "N"; - AircraftPacket += APRS_AIRC.symbol_table; - AircraftPacket += APRS_AIRC.lon_deg; - AircraftPacket += APRS_AIRC.lon_min; - if (Container[i].longitude < 0) - AircraftPacket += "W"; - else - AircraftPacket += "E"; - AircraftPacket += APRS_AIRC.symbol; - AircraftPacket += APRS_AIRC.heading; - AircraftPacket += "/"; - AircraftPacket += APRS_AIRC.ground_speed; - AircraftPacket += "/A="; - AircraftPacket += APRS_AIRC.alt; - AircraftPacket += " !W"; - AircraftPacket += APRS_AIRC.pos_precision; - AircraftPacket += "! id"; - AircraftPacket += APRS_AIRC.sender_details; - AircraftPacket += APRS_AIRC.callsign; - AircraftPacket += " "; - AircraftPacket += APRS_AIRC.climbrate; - AircraftPacket += "fpm +0.0rot "; - AircraftPacket += APRS_AIRC.snr; - AircraftPacket += "dB 0e -0.0kHz"; - AircraftPacket += "\r\n"; - - Logger_send_udp(&AircraftPacket); - Logger_send_udp(&APRS_AIRC.pos_precision); - - if (!Container[i].stealth && !Container[i].no_track || settings->ignore_no_track && settings->ignore_stealth) - SoC->WiFi_transmit_TCP(AircraftPacket); - } - - for (int i = 0; i < MAX_TRACKING_OBJECTS; i++) // cleaning up containers - Container[i] = EmptyFO; -} - -int OGN_APRS_Register(ufo_t* this_aircraft) -{ - if (OGN_APRS_Connect()) - { - struct aprs_login_packet APRS_LOGIN; - - APRS_LOGIN.user = String(this_aircraft->addr, HEX); - APRS_LOGIN.pass = String(AprsPasscode(APRS_LOGIN.user.c_str())); - APRS_LOGIN.appname = "ESP32"; - APRS_LOGIN.version = SOFTRF_FIRMWARE_VERSION; - - String LoginPacket = "user "; - LoginPacket += APRS_LOGIN.user; - LoginPacket += " pass "; - LoginPacket += APRS_LOGIN.pass; - LoginPacket += " vers "; - LoginPacket += APRS_LOGIN.appname; - LoginPacket += " "; - LoginPacket += APRS_LOGIN.version; - LoginPacket += " "; - LoginPacket += "m/"; - LoginPacket += String(settings->range); - LoginPacket += "\n"; - - Logger_send_udp(&LoginPacket); - SoC->WiFi_transmit_TCP(LoginPacket); - - aprs_registred = 1; - } - - if (aprs_registred == 1) - { - /* RUSSIA>APRS,TCPIP*,qAC,248280:/220757h626.56NI09353.92E&/A=000446 */ - - struct aprs_reg_packet APRS_REG; - float LAT = fabs(this_aircraft->latitude); - float LON = fabs(this_aircraft->longitude); - - APRS_REG.origin = ogn_callsign; - APRS_REG.callsign = String(this_aircraft->addr, HEX); - APRS_REG.callsign.toUpperCase(); - APRS_REG.alt = zeroPadding(String(int(this_aircraft->altitude * 3.28084)), 6); - APRS_REG.timestamp = zeroPadding(String(hour()), 2) + zeroPadding(String(minute()), 2) + zeroPadding(String(second()), 2) + "h"; - - APRS_REG.lat_deg = zeroPadding(String(int(LAT)), 2); - APRS_REG.lat_min = zeroPadding(String((LAT - int(LAT)) * 60, 3), 5); - - APRS_REG.lon_deg = zeroPadding(String(int(LON)), 3); - APRS_REG.lon_min = zeroPadding(String((LON - int(LON)) * 60, 3), 5); - - String RegisterPacket = ""; - RegisterPacket += APRS_REG.origin; - RegisterPacket += ">APRS,TCPIP*,qAC,"; - RegisterPacket += APRS_REG.callsign; - RegisterPacket += ":/"; - RegisterPacket += APRS_REG.timestamp; - RegisterPacket += APRS_REG.lat_deg + APRS_REG.lat_min; - - if (this_aircraft->latitude < 0) - RegisterPacket += "S"; - else - RegisterPacket += "N"; - RegisterPacket += "I"; - RegisterPacket += APRS_REG.lon_deg + APRS_REG.lon_min; - if (this_aircraft->longitude < 0) - RegisterPacket += "W"; - else - RegisterPacket += "E"; - RegisterPacket += "&/A="; - RegisterPacket += APRS_REG.alt; - RegisterPacket += "\r\n"; - - SoC->WiFi_transmit_TCP(RegisterPacket); - Logger_send_udp(&RegisterPacket); - } - return aprs_registred; -} - -void OGN_APRS_KeepAlive() -{ - String KeepAlivePacket = "#keepalive\n\n"; - Logger_send_udp(&KeepAlivePacket); - SoC->WiFi_transmit_TCP(KeepAlivePacket); -} - -// LKHS>APRS,TCPIP*,qAC,GLIDERN2:>211635h v0.2.6.ARM CPU:0.2 RAM:777.7/972.2MB NTP:3.1ms/-3.8ppm 4.902V 0.583A +33.6C - -void OGN_APRS_Status(ufo_t* this_aircraft) -{ - struct aprs_stat_packet APRS_STAT; - APRS_STAT.origin = ogn_callsign; - APRS_STAT.callsign = String(this_aircraft->addr, HEX); - APRS_STAT.callsign.toUpperCase(); - APRS_STAT.timestamp = zeroPadding(String(hour()), 2) + zeroPadding(String(minute()), 2) + zeroPadding(String(second()), 2) + "h"; - APRS_STAT.platform = SOFTRF_FIRMWARE_VERSION; - APRS_STAT.platform += "_ESP32"; - APRS_STAT.realtime_clock = String(0.0); - APRS_STAT.board_voltage = String(Battery_voltage()) + "V"; - - // 14/16Acfts[1h] - - String StatusPacket = ""; - StatusPacket += APRS_STAT.origin; - StatusPacket += ">APRS,TCPIP*,qAC,"; - StatusPacket += APRS_STAT.callsign; - StatusPacket += ":>"; - StatusPacket += APRS_STAT.timestamp; - StatusPacket += " "; - StatusPacket += APRS_STAT.platform; - StatusPacket += " "; - StatusPacket += APRS_STAT.board_voltage; - //StatusPacket += " "; - //StatusPacket += ThisAircraft.timestamp; - StatusPacket += "\r\n"; - SoC->WiFi_transmit_TCP(StatusPacket); - Logger_send_udp(&StatusPacket); - return; -} +/* + OGN.cpp + Copyright (C) 2020 Manuel Rösel + + 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 . + */ + +#include "APRS.h" +#include "SoftRF.h" +#include "Battery.h" +#include "Traffic.h" +#include "RF.h" +#include "EEPROM.h" +#include "global.h" +#include "Log.h" +#include "OLED.h" +#include "global.h" + + +#include + +#define kKey 0x73e2 + +int MIN_SPEED = 0; + +int aprs_registred = 0; +bool aprs_connected = false; +int last_packet_time = 0; // seconds +int ap_uptime = 0; + +#define seconds() (millis() / 1000) + +static String zeroPadding(String data, int len) +{ + if (data.charAt(2) == '.') + data.remove(len, data.length()); + + if (data.charAt(1) == '.') + data.remove(len - 1, data.length()); + String tmp = ""; + for (int i = data.length(); i < len; i++) + tmp += "0"; + tmp += data; + return tmp; +} + +static String getWW(String data) +{ + String tmp = data; + int len = tmp.length(); + tmp.remove(0, len - 1); + return tmp; +} + +static float SnrCalc(float rssi) +{ + float noise = -108.0; + return rssi - (noise); +} + +static short AprsPasscode(const char* theCall) +{ + char rootCall[10]; + char* p1 = rootCall; + + while ((*theCall != '-') && (*theCall != 0) && (p1 < rootCall + 9)) { + *p1++ = toupper(*theCall++); + } + + *p1 = 0; + + short hash = kKey; + short i = 0; + short len = strlen(rootCall); + char* ptr = rootCall; + + while (i < len) { + hash ^= (*ptr++) << 8; + hash ^= (*ptr++); + i += 2; + } + + return hash & 0x7fff; +} + +static long double toRadians(const long double degree) +{ + long double one_deg = (M_PI) / 180; + return one_deg * degree; +} + +static long double distance(long double lat1, long double long1, long double lat2, long double long2) +{ + lat1 = toRadians(lat1); + long1 = toRadians(long1); + lat2 = toRadians(lat2); + long2 = toRadians(long2); + + long double dlong = long2 - long1; + long double dlat = lat2 - lat1; + + long double ans = pow(sin(dlat / 2), 2) + + cos(lat1) * cos(lat2) * + pow(sin(dlong / 2), 2); + + ans = 2 * asin(sqrt(ans)); + + long double R = 6371; + ans = ans * R; + + return ans * 1000; +} + +static bool OGN_APRS_Connect() +{ + if (SoC->WiFi_connect_TCP(ogn_server.c_str(), ogn_port)) + return true; + else + return false; +} + +static bool OGN_APRS_DisConnect() +{ + if (!SoC->WiFi_disconnect_TCP()) + return true; + return false; +} + +static int OGN_APRS_check_reg(String* msg) // 0 = unverified // 1 = verified // -1 = wrong message +{ + int len = msg->length(); + + if (msg->indexOf("verified") > -1) + return 1; + if (msg->indexOf("unverified") > -1) + return 0; + if (msg->indexOf("invalid") > -1) + return 2; + + return -1; +} + +bool OGN_APRS_check_Wifi() +{ + if (WiFi.status() != WL_CONNECTED && WiFi.getMode() == WIFI_STA) + { + WiFi.disconnect(); + WiFi.mode(WIFI_OFF); + WiFi.mode(WIFI_STA); + //WiFi.begin(ogn_ssid_1.c_str(), ogn_wpass_1.c_str()); + delay(100); + } + if (WiFi.status() == WL_CONNECTED) + return true; + else + { + Serial.println("more then 10 minutes in AP mode reset"); + SoC->reset(); + } + return false; +} + +int OGN_APRS_check_messages() +{ + char* RXbuffer = (char *) malloc(512); + int recStatus = SoC->WiFi_receive_TCP(RXbuffer, 512); + String msg; + + for (int i = 0; i < recStatus; i++) + msg += RXbuffer[i]; + + + if (recStatus > 0) + { + if (OGN_APRS_check_reg(&msg) == 0) + msg = "login unsuccessful"; + + if (OGN_APRS_check_reg(&msg) == 1) + msg = "login successful"; + + last_packet_time = seconds(); + } + + Logger_send_udp(&msg); + + if (seconds() - last_packet_time > 60) + { + msg = "no packet since > 60 seconds...reconnecting"; + Logger_send_udp(&msg); + SoC->WiFi_disconnect_TCP(); + aprs_registred = 0; + } + + + free(RXbuffer); + return aprs_registred; +} + +void OGN_APRS_Export() +{ + struct aprs_airc_packet APRS_AIRC; + time_t this_moment = now(); + + String symbol_table[16] = {"/", "/", "\\", "/", "\\", "\\", "/", "/", "\\", "J", "/", "/", "M", "/", "\\", "\\"}; // 0x79 -> aircraft type 1110 dec 14 & 0x51 -> aircraft type 4 + String symbol[16] = {"z", "^", "^", "X", "", "^", "g", "g", "^", "^", "^", "O", "^", "\'", "", "n", }; + + + for (int i = 0; i < MAX_TRACKING_OBJECTS; i++) + if (Container[i].addr && (this_moment - Container[i].timestamp) <= EXPORT_EXPIRATION_TIME && Container[i].distance < ogn_range * 1000) + { + if (Container[i].distance / 1000 > largest_range) + largest_range = Container[i].distance / 1000; + + float LAT = fabs(Container[i].latitude); + float LON = fabs(Container[i].longitude); + + + APRS_AIRC.callsign = zeroPadding(String(Container[i].addr, HEX), 6); + APRS_AIRC.callsign.toUpperCase(); + APRS_AIRC.rec_callsign = ogn_callsign; + + + // TBD need to use Container[i].timestamp instead of hour(), minute(), second() + // actually, need to make sure Container[i].timestamp is based on SlotTime not current time due slot-2 time extension + //converting Container[i].timestamp to hour minutes seconds + + time_t receive_time = Container[i].timestamp; + APRS_AIRC.timestamp = zeroPadding(String(hour(receive_time)), 2) + zeroPadding(String(minute(receive_time)), 2) + zeroPadding(String(second(receive_time)), 2) + "h"; + + /*Latitude*/ + APRS_AIRC.lat_deg = String(int(LAT)); + APRS_AIRC.lat_min = zeroPadding(String((LAT - int(LAT)) * 60, 3), 5); + + /*Longitude*/ + APRS_AIRC.lon_deg = zeroPadding(String(int(LON)), 3); + APRS_AIRC.lon_min = zeroPadding(String((LON - int(LON)) * 60, 3), 5); + + /*Altitude*/ + APRS_AIRC.alt = zeroPadding(String(int(Container[i].altitude * 3.28084)), 6); + + APRS_AIRC.heading = zeroPadding(String(int(Container[i].course)), 3); + APRS_AIRC.ground_speed = zeroPadding(String(int(Container[i].speed)), 3); + + + APRS_AIRC.sender_details = zeroPadding(String(Container[i].aircraft_type << 2 | (Container[i].stealth << 7) | (Container[i].no_track << 6) | Container[i].addr_type, HEX), 2); + + APRS_AIRC.symbol_table = symbol_table[Container[i].aircraft_type]; + APRS_AIRC.symbol = symbol[Container[i].aircraft_type]; + + APRS_AIRC.snr = String(SnrCalc(Container[i].rssi), 1); + + + String W_lat = String((LAT - int(LAT)) * 60, 3); + String W_lon = String((LON - int(LON)) * 60, 3); + + + APRS_AIRC.pos_precision = getWW(W_lat) + getWW(W_lon); + + if (Container[i].vs >= 0) + APRS_AIRC.climbrate = "+" + zeroPadding(String(int(Container[i].vs)), 3); + else + APRS_AIRC.climbrate = zeroPadding(String(int(Container[i].vs)), 3); + + String AircraftPacket = ""; + + if (Container[i].addr_type == 1) + AircraftPacket = "ICA"; + if (Container[i].addr_type == 2) + AircraftPacket += "FLR"; + if (Container[i].addr_type == 3) + AircraftPacket += "OGN"; + if (Container[i].addr_type == 4) + AircraftPacket += "P3I"; + if (Container[i].addr_type == 5) + AircraftPacket += "FNT"; + if (Container[i].addr_type == 0 || Container[i].addr_type > 5) + AircraftPacket += "RANDOM"; + + AircraftPacket += APRS_AIRC.callsign; + APRS_AIRC.sender_details.toUpperCase(); + + AircraftPacket += ">APRS,qAS,"; + AircraftPacket += APRS_AIRC.rec_callsign; + AircraftPacket += ":/"; + AircraftPacket += APRS_AIRC.timestamp; + AircraftPacket += APRS_AIRC.lat_deg; + AircraftPacket += APRS_AIRC.lat_min; + if (Container[i].latitude < 0) + AircraftPacket += "S"; + else + AircraftPacket += "N"; + AircraftPacket += APRS_AIRC.symbol_table; + AircraftPacket += APRS_AIRC.lon_deg; + AircraftPacket += APRS_AIRC.lon_min; + if (Container[i].longitude < 0) + AircraftPacket += "W"; + else + AircraftPacket += "E"; + AircraftPacket += APRS_AIRC.symbol; + AircraftPacket += APRS_AIRC.heading; + AircraftPacket += "/"; + AircraftPacket += APRS_AIRC.ground_speed; + AircraftPacket += "/A="; + AircraftPacket += APRS_AIRC.alt; + AircraftPacket += " !W"; + AircraftPacket += APRS_AIRC.pos_precision; + AircraftPacket += "! id"; + AircraftPacket += APRS_AIRC.sender_details; + AircraftPacket += APRS_AIRC.callsign; + AircraftPacket += " "; + AircraftPacket += APRS_AIRC.climbrate; + AircraftPacket += "fpm +0.0rot "; + AircraftPacket += APRS_AIRC.snr; + AircraftPacket += "dB 0e -0.0kHz"; + AircraftPacket += "\r\n"; + + Logger_send_udp(&AircraftPacket); + Logger_send_udp(&APRS_AIRC.pos_precision); + + if (!Container[i].stealth && !Container[i].no_track || ogn_itrackbit && ogn_istealthbit) + SoC->WiFi_transmit_TCP(AircraftPacket); + } + + for (int i = 0; i < MAX_TRACKING_OBJECTS; i++) // cleaning up containers + Container[i] = EmptyFO; +} + +int OGN_APRS_Register(ufo_t* this_aircraft) +{ + if (OGN_APRS_Connect()) + { + struct aprs_login_packet APRS_LOGIN; + + APRS_LOGIN.user = String(this_aircraft->addr, HEX); + APRS_LOGIN.pass = String(AprsPasscode(APRS_LOGIN.user.c_str())); + APRS_LOGIN.appname = "ESP32"; + APRS_LOGIN.version = SOFTRF_FIRMWARE_VERSION; + + String LoginPacket = "user "; + LoginPacket += APRS_LOGIN.user; + LoginPacket += " pass "; + LoginPacket += APRS_LOGIN.pass; + LoginPacket += " vers "; + LoginPacket += APRS_LOGIN.appname; + LoginPacket += " "; + LoginPacket += APRS_LOGIN.version; + LoginPacket += " "; + LoginPacket += "m/"; + LoginPacket += String(ogn_range); + LoginPacket += "\n"; + + Logger_send_udp(&LoginPacket); + SoC->WiFi_transmit_TCP(LoginPacket); + + aprs_registred = 1; + } + + else + { + Serial.println("OGN connection failed"); + aprs_registred = 0; + return -1; + } + + if (aprs_registred == 1) + { + /* RUSSIA>APRS,TCPIP*,qAC,248280:/220757h626.56NI09353.92E&/A=000446 */ + + struct aprs_reg_packet APRS_REG; + float LAT = fabs(this_aircraft->latitude); + float LON = fabs(this_aircraft->longitude); + + APRS_REG.origin = ogn_callsign; + APRS_REG.callsign = String(this_aircraft->addr, HEX); + APRS_REG.callsign.toUpperCase(); + APRS_REG.alt = zeroPadding(String(int(this_aircraft->altitude * 3.28084)), 6); + APRS_REG.timestamp = zeroPadding(String(hour()), 2) + zeroPadding(String(minute()), 2) + zeroPadding(String(second()), 2) + "h"; + + APRS_REG.lat_deg = zeroPadding(String(int(LAT)), 2); + APRS_REG.lat_min = zeroPadding(String((LAT - int(LAT)) * 60, 3), 5); + + APRS_REG.lon_deg = zeroPadding(String(int(LON)), 3); + APRS_REG.lon_min = zeroPadding(String((LON - int(LON)) * 60, 3), 5); + + String RegisterPacket = ""; + RegisterPacket += APRS_REG.origin; + RegisterPacket += ">APRS,TCPIP*,qAC,"; + RegisterPacket += APRS_REG.callsign; + RegisterPacket += ":/"; + RegisterPacket += APRS_REG.timestamp; + RegisterPacket += APRS_REG.lat_deg + APRS_REG.lat_min; + + if (this_aircraft->latitude < 0) + RegisterPacket += "S"; + else + RegisterPacket += "N"; + RegisterPacket += "I"; + RegisterPacket += APRS_REG.lon_deg + APRS_REG.lon_min; + if (this_aircraft->longitude < 0) + RegisterPacket += "W"; + else + RegisterPacket += "E"; + RegisterPacket += "&/A="; + RegisterPacket += APRS_REG.alt; + RegisterPacket += "\r\n"; + + SoC->WiFi_transmit_TCP(RegisterPacket); + Logger_send_udp(&RegisterPacket); + } + return aprs_registred; +} + +void OGN_APRS_KeepAlive() +{ + String KeepAlivePacket = "#keepalive\n\n"; + Logger_send_udp(&KeepAlivePacket); + SoC->WiFi_transmit_TCP(KeepAlivePacket); +} + +// LKHS>APRS,TCPIP*,qAC,GLIDERN2:>211635h v0.2.6.ARM CPU:0.2 RAM:777.7/972.2MB NTP:3.1ms/-3.8ppm 4.902V 0.583A +33.6C + +void OGN_APRS_Status(ufo_t* this_aircraft) +{ + struct aprs_stat_packet APRS_STAT; + APRS_STAT.origin = ogn_callsign; + APRS_STAT.callsign = String(this_aircraft->addr, HEX); + APRS_STAT.callsign.toUpperCase(); + APRS_STAT.timestamp = zeroPadding(String(hour()), 2) + zeroPadding(String(minute()), 2) + zeroPadding(String(second()), 2) + "h"; + APRS_STAT.platform = SOFTRF_FIRMWARE_VERSION; + APRS_STAT.platform += "_ESP32"; + APRS_STAT.realtime_clock = String(0.0); + APRS_STAT.board_voltage = String(Battery_voltage()) + "V"; + + // 14/16Acfts[1h] + + String StatusPacket = ""; + StatusPacket += APRS_STAT.origin; + StatusPacket += ">APRS,TCPIP*,qAC,"; + StatusPacket += APRS_STAT.callsign; + StatusPacket += ":>"; + StatusPacket += APRS_STAT.timestamp; + StatusPacket += " "; + StatusPacket += APRS_STAT.platform; + StatusPacket += " "; + StatusPacket += APRS_STAT.board_voltage; + //StatusPacket += " "; + //StatusPacket += ThisAircraft.timestamp; + StatusPacket += "\r\n"; + SoC->WiFi_transmit_TCP(StatusPacket); + Logger_send_udp(&StatusPacket); + return; +} diff --git a/ognbase/APRS.h b/ognbase/APRS.h index 8d96982..19941f1 100644 --- a/ognbase/APRS.h +++ b/ognbase/APRS.h @@ -1,113 +1,112 @@ -/* - * OGN.h - * Copyright (C) 2020 Manuel Rösel - * - * 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 . - */ - -#include -#include "SoC.h" - - -#ifndef OGNHELPER_H -#define OGNHELPER_H - -//LKHS>APRS,TCPIP*,qAC,GLIDERN2:/211635h4902.45NI01429.51E&000/000/A=001689 - -struct aprs_reg_packet -{ - String origin; - String callsign; - String timestamp; - String lat_deg; - String lat_min; - String lon_deg; - String lon_min; - String alt; -}; - -struct aprs_login_packet // user OGN123456 pass 12345 vers DemoApp 0.0.0 filter m/10 -{ - String user; - String pass; - String appname; - String version; -}; - -// LKHS>APRS,TCPIP*,qAC,GLIDERN2:>211635h v0.2.6.ARM CPU:0.2 RAM:777.7/972.2MB NTP:3.1ms/-3.8ppm 4.902V 0.583A +33.6C -struct aprs_stat_packet -{ - String origin; - String callsign; - String timestamp; - String platform; - String cpu_usage; - String ram_max; - String ram_usage; - String realtime_clock; - String board_voltage; - String board_amperage; - String cpu_temperature; -}; - -// FLRDF0A52>APRS,qAS,LSTB:/220132h4658.70N/00707.72Ez090/054/A=001424 !W37! id06DF0A52 +020fpm +0.0rot 55.2dB 0e -6.2kHz gps4x6 s6.01 h03 rDDACC4 +5.0dBm hearD7EA hearDA95 -struct aprs_airc_packet -{ - String callsign; - String rec_callsign; - String timestamp; - String lat_deg; - String lat_min; - String lon_deg; - String lon_min; - String alt; - String heading; - String ground_speed; - String pos_precision; - String symbol_table; - String symbol; - String climbrate; - String sender_details; - String snr; -}; - -enum -{ - OGN_OFF, - OGN_ON, -}; - -static bool OGN_APRS_Connect(); - -static bool OGN_APRS_DisConnect(); - - -void OGN_APRS_Export(); - -void OGN_APRS_Weather(); - -int OGN_APRS_Register(ufo_t* this_aircraft); - -void OGN_APRS_KeepAlive(); - -bool OGN_APRS_check_Wifi(); - -void OGN_APRS_Status(ufo_t* this_aircraft); - -static int OGN_APRS_check_reg(String *); - -int OGN_APRS_check_messages(); - -extern String ogn_callsign; -#endif /* OGNHELPER_H */ +/* + * OGN.h + * Copyright (C) 2020 Manuel Rösel + * + * 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 . + */ + +#include +#include "SoC.h" + + +#ifndef OGNHELPER_H +#define OGNHELPER_H + +//LKHS>APRS,TCPIP*,qAC,GLIDERN2:/211635h4902.45NI01429.51E&000/000/A=001689 + +struct aprs_reg_packet +{ + String origin; + String callsign; + String timestamp; + String lat_deg; + String lat_min; + String lon_deg; + String lon_min; + String alt; +}; + +struct aprs_login_packet // user OGN123456 pass 12345 vers DemoApp 0.0.0 filter m/10 +{ + String user; + String pass; + String appname; + String version; +}; + +// LKHS>APRS,TCPIP*,qAC,GLIDERN2:>211635h v0.2.6.ARM CPU:0.2 RAM:777.7/972.2MB NTP:3.1ms/-3.8ppm 4.902V 0.583A +33.6C +struct aprs_stat_packet +{ + String origin; + String callsign; + String timestamp; + String platform; + String cpu_usage; + String ram_max; + String ram_usage; + String realtime_clock; + String board_voltage; + String board_amperage; + String cpu_temperature; +}; + +// FLRDF0A52>APRS,qAS,LSTB:/220132h4658.70N/00707.72Ez090/054/A=001424 !W37! id06DF0A52 +020fpm +0.0rot 55.2dB 0e -6.2kHz gps4x6 s6.01 h03 rDDACC4 +5.0dBm hearD7EA hearDA95 +struct aprs_airc_packet +{ + String callsign; + String rec_callsign; + String timestamp; + String lat_deg; + String lat_min; + String lon_deg; + String lon_min; + String alt; + String heading; + String ground_speed; + String pos_precision; + String symbol_table; + String symbol; + String climbrate; + String sender_details; + String snr; +}; + +enum +{ + OGN_OFF, + OGN_ON, +}; + +static bool OGN_APRS_Connect(); + +static bool OGN_APRS_DisConnect(); + + +void OGN_APRS_Export(); + +void OGN_APRS_Weather(); + +int OGN_APRS_Register(ufo_t* this_aircraft); + +void OGN_APRS_KeepAlive(); + +bool OGN_APRS_check_Wifi(); + +void OGN_APRS_Status(ufo_t* this_aircraft); + +static int OGN_APRS_check_reg(String *); + +int OGN_APRS_check_messages(); + +#endif /* OGNHELPER_H */ diff --git a/ognbase/D1090.cpp b/ognbase/D1090.cpp index b44a345..28519bd 100644 --- a/ognbase/D1090.cpp +++ b/ognbase/D1090.cpp @@ -25,6 +25,7 @@ #include "GDL90.h" #include "EEPROM.h" #include "Traffic.h" +#include "global.h" #define ADDR_TO_HEX_STR(s, c) (s += ((c) < 0x10 ? "0" : "") + String((c), HEX)) @@ -75,7 +76,7 @@ void D1090_Export() { distance = Container[i].distance; - if (distance < settings->range) + if (distance < ogn_range) { double altitude; /* If the aircraft's data has standard pressure altitude - make use it */ diff --git a/ognbase/EEPROM.cpp b/ognbase/EEPROM.cpp index d3e86a1..c581a8b 100644 --- a/ognbase/EEPROM.cpp +++ b/ognbase/EEPROM.cpp @@ -79,12 +79,12 @@ void EEPROM_setup() void EEPROM_defaults() { - eeprom_block.field.magic = SOFTRF_EEPROM_MAGIC; - eeprom_block.field.version = SOFTRF_EEPROM_VERSION; - eeprom_block.field.settings.mode = SOFTRF_MODE_GROUND; - eeprom_block.field.settings.rf_protocol = RF_PROTOCOL_OGNTP; - eeprom_block.field.settings.rf_protocol2 = RF_PROTOCOL_LEGACY; - eeprom_block.field.settings.band = RF_BAND_EU; + eeprom_block.field.magic = SOFTRF_EEPROM_MAGIC; + eeprom_block.field.version = SOFTRF_EEPROM_VERSION; + eeprom_block.field.settings.mode = SOFTRF_MODE_GROUND; + //eeprom_block.field.settings.rf_protocol = RF_PROTOCOL_OGNTP; + //eeprom_block.field.settings.rf_protocol2 = RF_PROTOCOL_LEGACY; + //eeprom_block.field.settings.band = RF_BAND_EU; eeprom_block.field.settings.aircraft_type = AIRCRAFT_TYPE_GLIDER; eeprom_block.field.settings.txpower = RF_TX_POWER_FULL; eeprom_block.field.settings.bluetooth = BLUETOOTH_OFF; @@ -110,22 +110,22 @@ void EEPROM_defaults() eeprom_block.field.settings.nmea_out = NMEA_OFF; #endif - eeprom_block.field.settings.gdl90 = GDL90_OFF; - eeprom_block.field.settings.d1090 = D1090_OFF; - eeprom_block.field.settings.json = JSON_OFF; - eeprom_block.field.settings.stealth = false; - eeprom_block.field.settings.no_track = false; - eeprom_block.field.settings.power_save = POWER_SAVE_NONE; - eeprom_block.field.settings.freq_corr = 0; - eeprom_block.field.settings.range = 10; - eeprom_block.field.settings.sxlna = true; - eeprom_block.field.settings.ogndebug = false; - eeprom_block.field.settings.ogndebugp = 12000; - eeprom_block.field.settings.ignore_stealth = false; - eeprom_block.field.settings.ignore_no_track = false; - eeprom_block.field.settings.sleep_mode = 0; - eeprom_block.field.settings.sleep_after_rx_idle = 3600; - eeprom_block.field.settings.wake_up_timer = 3600; + eeprom_block.field.settings.gdl90 = GDL90_OFF; + eeprom_block.field.settings.d1090 = D1090_OFF; + eeprom_block.field.settings.json = JSON_OFF; + eeprom_block.field.settings.stealth = false; + eeprom_block.field.settings.no_track = false; + eeprom_block.field.settings.power_save = POWER_SAVE_NONE; + eeprom_block.field.settings.freq_corr = 0; + //eeprom_block.field.settings.range = 10; + //eeprom_block.field.settings.sxlna = true; + //eeprom_block.field.settings.ogndebug = false; + //eeprom_block.field.settings.ogndebugp = 12000; + //eeprom_block.field.settings.ignore_stealth = false; + //eeprom_block.field.settings.ignore_no_track = false; + //eeprom_block.field.settings.sleep_mode = 0; + //eeprom_block.field.settings.sleep_after_rx_idle = 3600; + //eeprom_block.field.settings.wake_up_timer = 3600; } void EEPROM_store() diff --git a/ognbase/EEPROM.h b/ognbase/EEPROM.h index 03bbe0f..c2d07e5 100644 --- a/ognbase/EEPROM.h +++ b/ognbase/EEPROM.h @@ -31,8 +31,8 @@ typedef struct Settings { uint8_t mode; - uint8_t rf_protocol; - uint8_t band; + //uint8_t rf_protocol; + //uint8_t band; uint8_t aircraft_type; uint8_t txpower; uint8_t volume; @@ -57,17 +57,17 @@ typedef struct Settings uint8_t power_save; int8_t freq_corr; /* +/-, kHz */ - int16_t range; /*OGN Basestation max Range*/ - bool sxlna; /*SX1276 agcref settings*/ - bool ogndebug; /*debug on*/ - uint16_t ogndebugp; /*debug port*/ - bool ignore_stealth; - bool ignore_no_track; - uint8_t rf_protocol2; - uint8_t sleep_mode; - uint16_t sleep_after_rx_idle; - uint16_t wake_up_timer; - bool zabbix_en; + //int16_t range; /*OGN Basestation max Range*/ + //bool sxlna; /*SX1276 agcref settings*/ + //bool ogndebug; /*debug on*/ + //uint16_t ogndebugp; /*debug port*/ + //bool ignore_stealth; + //bool ignore_no_track; + //uint8_t rf_protocol2; + //uint8_t sleep_mode; + //uint16_t sleep_after_rx_idle; + //uint16_t wake_up_timer; + //bool zabbix_en; } settings_t; typedef struct EEPROM_S diff --git a/ognbase/GNSS.cpp b/ognbase/GNSS.cpp index cc58752..e4643ac 100644 --- a/ognbase/GNSS.cpp +++ b/ognbase/GNSS.cpp @@ -1,1039 +1,1038 @@ -/* - * GNSS.cpp - * Copyright (C) 2019-2020 Linar Yusupov - * - * 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 . - */ - -#if defined(ARDUINO) -#include -#endif -#include - -#include "GNSS.h" -#include "EEPROM.h" -#include "NMEA.h" -#include "SoC.h" -#include "WiFi.h" -#include "RF.h" -#include "Battery.h" - -#if !defined(EXCLUDE_EGM96) -#include -#endif /* EXCLUDE_EGM96 */ - -#if !defined(DO_GNSS_DEBUG) -#define GNSS_DEBUG_PRINT -#define GNSS_DEBUG_PRINTLN -#else -#define GNSS_DEBUG_PRINT Serial.print -#define GNSS_DEBUG_PRINTLN Serial.println -#endif - -unsigned long GNSSTimeSyncMarker = 0; -volatile unsigned long PPS_TimeMarker = 0; - -#if 0 -unsigned long GGA_Start_Time_Marker = 0; -unsigned long GGA_Stop_Time_Marker = 0; -#endif - -boolean gnss_set_sucess = false; -TinyGPSPlus gnss; // Create an Instance of the TinyGPS++ object called gnss - -uint8_t GNSSbuf[250]; // at least 3 lines of 80 characters each - // and 40+30*N bytes for "UBX-MON-VER" payload -int GNSS_cnt = 0; - -/* CFG-MSG */ -const uint8_t setGLL[] PROGMEM = {0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; -const uint8_t setGSV[] PROGMEM = {0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; -const uint8_t setVTG[] PROGMEM = {0xF0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; -#if !defined(NMEA_TCP_SERVICE) -const uint8_t setGSA[] PROGMEM = {0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; -#endif -/* CFG-PRT */ -uint8_t setBR[] = {0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x00, 0x96, - 0x00, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}; - -const uint8_t setNav5[] PROGMEM = {0xFF, 0xFF, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x27, 0x00, 0x00, 0x05, 0x00, 0xFA, 0x00, - 0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; - -const uint8_t CFG_RST[12] PROGMEM = {0xb5, 0x62, 0x06, 0x04, 0x04, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x0F, 0x66}; - -const uint8_t RXM_PMREQ_OFF[16] PROGMEM = {0xb5, 0x62, 0x02, 0x41, 0x08, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x00, 0x4d, 0x3b}; - -const byte RXM_PMREQ[16] = {0xb5, 0x62, 0x02, 0x41, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4d, 0x3b}; //power off until wakeup call -uint8_t GPSon[16] = {0xB5, 0x62, 0x02, 0x41, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4C, 0x37}; - -#if defined(USE_GNSS_PSM) -static bool gnss_psm_active = false; - -/* Max Performance Mode (default) */ -const uint8_t RXM_MAXP[] PROGMEM = {0xB5, 0x62, 0x06, 0x11, 0x02, 0x00, 0x08, 0x00, 0x21, 0x91}; - -/* Power Save Mode */ -const uint8_t RXM_PSM[] PROGMEM = {0xB5, 0x62, 0x06, 0x11, 0x02, 0x00, 0x08, 0x01, 0x22, 0x92}; -#endif /* USE_GNSS_PSM */ - -const char* GNSS_name[] = { - [GNSS_MODULE_NONE] = "NONE", - [GNSS_MODULE_NMEA] = "NMEA", - [GNSS_MODULE_U6] = "U6", - [GNSS_MODULE_U7] = "U7", - [GNSS_MODULE_U8] = "U8", - [GNSS_MODULE_U9] = "U9", - [GNSS_MODULE_MAV] = "MAV", - [GNSS_MODULE_S7XG] = "S7XG" -}; - -#if defined(USE_NMEA_CFG) - -#include "RF.h" /* RF_Shutdown() */ - - -#include "GDL90.h" -#include "D1090.h" - -TinyGPSCustom C_Version(gnss, "PSRFC", 1); -TinyGPSCustom C_Mode(gnss, "PSRFC", 2); -TinyGPSCustom C_Protocol(gnss, "PSRFC", 3); -TinyGPSCustom C_Band(gnss, "PSRFC", 4); -TinyGPSCustom C_AcftType(gnss, "PSRFC", 5); -TinyGPSCustom C_Alarm(gnss, "PSRFC", 6); -TinyGPSCustom C_TxPower(gnss, "PSRFC", 7); -TinyGPSCustom C_Volume(gnss, "PSRFC", 8); -TinyGPSCustom C_Pointer(gnss, "PSRFC", 9); -TinyGPSCustom C_NMEA_gnss(gnss, "PSRFC", 10); -TinyGPSCustom C_NMEA_private(gnss, "PSRFC", 11); -TinyGPSCustom C_NMEA_legacy(gnss, "PSRFC", 12); -TinyGPSCustom C_NMEA_sensors(gnss, "PSRFC", 13); -TinyGPSCustom C_NMEA_Output(gnss, "PSRFC", 14); -TinyGPSCustom C_GDL90_Output(gnss, "PSRFC", 15); -TinyGPSCustom C_D1090_Output(gnss, "PSRFC", 16); -TinyGPSCustom C_Stealth(gnss, "PSRFC", 17); -TinyGPSCustom C_noTrack(gnss, "PSRFC", 18); -TinyGPSCustom C_PowerSave(gnss, "PSRFC", 19); - -#endif /* USE_NMEA_CFG */ - -static uint8_t makeUBXCFG(uint8_t cl, uint8_t id, uint8_t msglen, const uint8_t* msg) -{ - if (msglen > (sizeof(GNSSbuf) - 8)) - msglen = sizeof(GNSSbuf) - 8; - - // Construct the UBX packet - GNSSbuf[0] = 0xB5; // header - GNSSbuf[1] = 0x62; // header - GNSSbuf[2] = cl; // class - GNSSbuf[3] = id; // id - GNSSbuf[4] = msglen; // length - GNSSbuf[5] = 0x00; - - GNSSbuf[6 + msglen] = 0x00; // CK_A - GNSSbuf[7 + msglen] = 0x00; // CK_B - - for (int i = 2; i < 6; i++) { - GNSSbuf[6 + msglen] += GNSSbuf[i]; - GNSSbuf[7 + msglen] += GNSSbuf[6 + msglen]; - } - - for (int i = 0; i < msglen; i++) { - GNSSbuf[6 + i] = pgm_read_byte(&msg[i]); - GNSSbuf[6 + msglen] += GNSSbuf[6 + i]; - GNSSbuf[7 + msglen] += GNSSbuf[6 + msglen]; - } - return msglen + 8; -} - -// Send a byte array of UBX protocol to the GPS -static void sendUBX(const uint8_t* MSG, uint8_t len) -{ - for (int i = 0; i < len; i++) { - swSer.write(MSG[i]); - GNSS_DEBUG_PRINT(MSG[i], HEX); - } -// swSer.println(); -} - -// Calculate expected UBX ACK packet and parse UBX response from GPS -static boolean getUBX_ACK(uint8_t cl, uint8_t id) -{ - uint8_t b; - uint8_t ackByteID = 0; - uint8_t ackPacket[2] = {cl, id}; - unsigned long startTime = millis(); - GNSS_DEBUG_PRINT(F(" * Reading ACK response: ")); - - // Construct the expected ACK packet - makeUBXCFG(0x05, 0x01, 2, ackPacket); - - while (1) { - // Test for success - if (ackByteID > 9) - { - // All packets in order! - GNSS_DEBUG_PRINTLN(F(" (SUCCESS!)")); - return true; - } - - // Timeout if no valid response in 2 seconds - if (millis() - startTime > 2000) - { - GNSS_DEBUG_PRINTLN(F(" (FAILED!)")); - return false; - } - - // Make sure data is available to read - if (swSer.available()) - { - b = swSer.read(); - - // Check that bytes arrive in sequence as per expected ACK packet - if (b == GNSSbuf[ackByteID]) - { - ackByteID++; - GNSS_DEBUG_PRINT(b, HEX); - } - else - { - ackByteID = 0; // Reset and look again, invalid order - } - } - yield(); - } -} - -static void setup_UBX() -{ - uint8_t msglen; - -#if 0 - unsigned int baudrate =; - - setBR[ 8] = (baudrate) & 0xFF; - setBR[ 9] = (baudrate >> 8) & 0xFF; - setBR[10] = (baudrate >> 16) & 0xFF; - - SoC->swSer_begin(9600); - - Serial.print(F("Switching baud rate onto ")); - Serial.println(baudrate); - - msglen = makeUBXCFG(0x06, 0x00, sizeof(setBR), setBR); - sendUBX(GNSSbuf, msglen); - gnss_set_sucess = getUBX_ACK(0x06, 0x00); - - if (!gnss_set_sucess) - { - Serial.print(F("WARNING: Unable to set baud rate onto ")); - Serial.println(baudrate); - } - swSer.flush(); - SoC->swSer_begin(baudrate); -#endif - - GNSS_DEBUG_PRINTLN(F("Airborne <2g navigation mode: ")); - - // Set the navigation mode (Airborne, < 2g) - msglen = makeUBXCFG(0x06, 0x24, sizeof(setNav5), setNav5); - sendUBX(GNSSbuf, msglen); - gnss_set_sucess = getUBX_ACK(0x06, 0x24); - - if (!gnss_set_sucess) - GNSS_DEBUG_PRINTLN(F("WARNING: Unable to set airborne <2g navigation mode.")); - - GNSS_DEBUG_PRINTLN(F("Switching off NMEA GLL: ")); - - msglen = makeUBXCFG(0x06, 0x01, sizeof(setGLL), setGLL); - sendUBX(GNSSbuf, msglen); - gnss_set_sucess = getUBX_ACK(0x06, 0x01); - - if (!gnss_set_sucess) - GNSS_DEBUG_PRINTLN(F("WARNING: Unable to disable NMEA GLL.")); - - GNSS_DEBUG_PRINTLN(F("Switching off NMEA GSV: ")); - - msglen = makeUBXCFG(0x06, 0x01, sizeof(setGSV), setGSV); - sendUBX(GNSSbuf, msglen); - gnss_set_sucess = getUBX_ACK(0x06, 0x01); - - if (!gnss_set_sucess) - GNSS_DEBUG_PRINTLN(F("WARNING: Unable to disable NMEA GSV.")); - - GNSS_DEBUG_PRINTLN(F("Switching off NMEA VTG: ")); - - msglen = makeUBXCFG(0x06, 0x01, sizeof(setVTG), setVTG); - sendUBX(GNSSbuf, msglen); - gnss_set_sucess = getUBX_ACK(0x06, 0x01); - - if (!gnss_set_sucess) - GNSS_DEBUG_PRINTLN(F("WARNING: Unable to disable NMEA VTG.")); - -#if !defined(NMEA_TCP_SERVICE) - - GNSS_DEBUG_PRINTLN(F("Switching off NMEA GSA: ")); - - msglen = makeUBXCFG(0x06, 0x01, sizeof(setGSA), setGSA); - sendUBX(GNSSbuf, msglen); - gnss_set_sucess = getUBX_ACK(0x06, 0x01); - - if (!gnss_set_sucess) - GNSS_DEBUG_PRINTLN(F("WARNING: Unable to disable NMEA GSA.")); - -#endif -} - -static void setup_NMEA() -{ -#if 0 - //swSer.write("$PUBX,41,1,0007,0003,9600,0*10\r\n"); - swSer.write("$PUBX,41,1,0007,0003,38400,0*20\r\n"); - - swSer.flush(); - SoC->swSer_begin(38400); - - // Turning off some GPS NMEA strings on the uBlox modules - swSer.write("$PUBX,40,GLL,0,0,0,0*5C\r\n"); - delay(250); - swSer.write("$PUBX,40,GSV,0,0,0,0*59\r\n"); - delay(250); - swSer.write("$PUBX,40,VTG,0,0,0,0*5E\r\n"); - delay(250); -#if !defined(NMEA_TCP_SERVICE) - swSer.write("$PUBX,40,GSA,0,0,0,0*4E\r\n"); - delay(250); -#endif -#endif - -#if defined(USE_AT6558_SETUP) - /* Assume that we deal with fake NEO module (AT6558 based) */ - swSer.write("$PCAS04,5*1C\r\n"); /* GPS + GLONASS */ delay(250); -#if defined(NMEA_TCP_SERVICE) - /* GGA,RMC and GSA */ - swSer.write("$PCAS03,1,0,1,0,1,0,0,0,0,0,,,0,0*03\r\n"); - delay(250); -#else - /* GGA and RMC */ - swSer.write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n"); - delay(250); -#endif - swSer.write("$PCAS11,6*1B\r\n"); /* Aviation < 2g */ delay(250); -#endif /* USE_AT6558_SETUP */ -} - -/* ------ BEGIN ----------- https://github.com/Black-Thunder/FPV-Tracker */ - -enum ubloxState -{ - WAIT_SYNC1, WAIT_SYNC2, GET_CLASS, GET_ID, GET_LL, GET_LH, GET_DATA, GET_CKA, GET_CKB -}; - -ubloxState ubloxProcessDataState = WAIT_SYNC1; - -unsigned short ubloxExpectedDataLength; -unsigned short ubloxClass, ubloxId; -unsigned char ubloxCKA, ubloxCKB; - -// process serial data -// data is stored inside #GNSSbuf, data size inside #GNSS_cnt -// warning : if #GNSSbuf is too short, data is truncated. -static int ubloxProcessData(unsigned char data) -{ - int parsed = 0; - - switch (ubloxProcessDataState) - { - case WAIT_SYNC1: - if (data == 0xb5) - ubloxProcessDataState = WAIT_SYNC2; - break; - - case WAIT_SYNC2: - if (data == 0x62) - ubloxProcessDataState = GET_CLASS; - else if (data == 0xb5) - { - // ubloxProcessDataState = GET_SYNC2; - } - else - ubloxProcessDataState = WAIT_SYNC1; - break; - case GET_CLASS: - ubloxClass = data; - ubloxCKA = data; - ubloxCKB = data; - ubloxProcessDataState = GET_ID; - break; - - case GET_ID: - ubloxId = data; - ubloxCKA += data; - ubloxCKB += ubloxCKA; - ubloxProcessDataState = GET_LL; - break; - - case GET_LL: - ubloxExpectedDataLength = data; - ubloxCKA += data; - ubloxCKB += ubloxCKA; - ubloxProcessDataState = GET_LH; - break; - - case GET_LH: - ubloxExpectedDataLength += data << 8; - GNSS_cnt = 0; - ubloxCKA += data; - ubloxCKB += ubloxCKA; - ubloxProcessDataState = GET_DATA; - break; - - case GET_DATA: - ubloxCKA += data; - ubloxCKB += ubloxCKA; - if (GNSS_cnt < sizeof(GNSSbuf)) - GNSSbuf[GNSS_cnt++] = data; - if ((--ubloxExpectedDataLength) == 0) - ubloxProcessDataState = GET_CKA; - break; - - case GET_CKA: - if (ubloxCKA != data) - ubloxProcessDataState = WAIT_SYNC1; - else - ubloxProcessDataState = GET_CKB; - break; - - case GET_CKB: - if (ubloxCKB == data) - parsed = 1; - ubloxProcessDataState = WAIT_SYNC1; - break; - } - - return parsed; -} - -/* ------ END ----------- https://github.com/Black-Thunder/FPV-Tracker */ - -static boolean GNSS_probe() -{ - unsigned long startTime = millis(); - char c1, c2; - c1 = c2 = 0; - - // clean any leftovers - swSer.flush(); - - // Serial.println(F("INFO: Waiting for NMEA data from GNSS module...")); - - // Timeout if no valid response in 3 seconds - while (millis() - startTime < 3000) { - if (swSer.available() > 0) - { - c1 = swSer.read(); - if ((c1 == '$') && (c2 == 0)) - { - c2 = c1; - continue; - } - if ((c2 == '$') && (c1 == 'G')) - /* got $G */ - - /* leave the function with GNSS port opened */ - return true; - else - c2 = 0; - } - - delay(1); - } - - return false; -} - -static byte GNSS_version() -{ - byte rval = GNSS_MODULE_NMEA; - unsigned long startTime = millis(); - - uint8_t msglen = makeUBXCFG(0x0A, 0x04, 0, NULL); // MON-VER - sendUBX(GNSSbuf, msglen); - - // Get the message back from the GPS - GNSS_DEBUG_PRINT(F(" * Reading response: ")); - - while ((millis() - startTime) < 2000) { - if (swSer.available()) - { - unsigned char c = swSer.read(); - int ret = 0; - - GNSS_DEBUG_PRINT(c, HEX); - ret = ubloxProcessData(c); - - // Upon a successfully parsed sentence, do the version detection - if (ret) - { - if (ubloxClass == 0x0A) // MON - { - if (ubloxId == 0x04) // VER - - // UBX-MON-VER data description - // uBlox 6 - page 166 : https://www.u-blox.com/sites/default/files/products/documents/u-blox6_ReceiverDescrProtSpec_%28GPS.G6-SW-10018%29_Public.pdf - // uBlox 7 - page 153 : https://www.u-blox.com/sites/default/files/products/documents/u-blox7-V14_ReceiverDescriptionProtocolSpec_%28GPS.G7-SW-12001%29_Public.pdf - // uBlox M8 - page 300 : https://www.u-blox.com/sites/default/files/products/documents/u-blox8-M8_ReceiverDescrProtSpec_%28UBX-13003221%29_Public.pdf - - { - Serial.print(F("INFO: GNSS module HW version: ")); - Serial.println((char *) &GNSSbuf[30]); - - Serial.print(F("INFO: GNSS module FW version: ")); - Serial.println((char *) &GNSSbuf[0]); - -#ifdef DO_GNSS_DEBUG - for (unsigned i = 30 + 10; i < GNSS_cnt; i+=30) { - Serial.print(F("INFO: GNSS module extension: ")); - Serial.println((char *) &GNSSbuf[i]); - } -#endif - - if (GNSSbuf[33] == '4') - rval = GNSS_MODULE_U6; - else if (GNSSbuf[33] == '7') - rval = GNSS_MODULE_U7; - else if (GNSSbuf[33] == '8') - rval = GNSS_MODULE_U8; - - break; - } - } - } - } - } - - return rval; -} - -byte GNSS_setup() -{ - byte rval = GNSS_MODULE_NONE; - - SoC->swSer_begin(SERIAL_IN_BR); - - if (hw_info.model == SOFTRF_MODEL_PRIME_MK2 || - hw_info.model == SOFTRF_MODEL_UNI) - { - // power on by wakeup call - swSer.write((uint8_t) 0); - swSer.flush(); - delay(500); - } - - if (!GNSS_probe()) - return rval; - - rval = GNSS_MODULE_NMEA; - - if (hw_info.model == SOFTRF_MODEL_PRIME_MK2 || - hw_info.model == SOFTRF_MODEL_RASPBERRY || - hw_info.model == SOFTRF_MODEL_UNI) - { - rval = GNSS_version(); - - if (rval == GNSS_MODULE_U6 || - rval == GNSS_MODULE_U7 || - rval == GNSS_MODULE_U8) - - // Set the navigation mode (Airborne, 1G) - // Turning off some GPS NMEA sentences on the uBlox modules - setup_UBX(); - else - setup_NMEA(); - } - - if (SOC_GPIO_PIN_GNSS_PPS != SOC_UNUSED_PIN) - { - pinMode(SOC_GPIO_PIN_GNSS_PPS, SOC_GPIO_PIN_MODE_PULLDOWN); - attachInterrupt(digitalPinToInterrupt(SOC_GPIO_PIN_GNSS_PPS), - SoC->GNSS_PPS_handler, RISING); - } - - return rval; -} - -void GNSS_sleep() -{ - for (int i = 0; i < sizeof(CFG_RST); i++) - swSer.write(pgm_read_byte(&CFG_RST[i])); - delay(600); - - for (int i = 0; i < sizeof(RXM_PMREQ); i++) - swSer.write(pgm_read_byte(&RXM_PMREQ[i])); -} - -void GNSS_wakeup() -{ - for (int i = 0; i < 20; i++) //send random to trigger respose - swSer.write(0xFF); -} - -void GNSS_loop(bool TimeSync) -{ - PickGNSSFix(); - - if(!TimeSync){ - GNSSTimeSync(); - } - -#if defined(USE_GNSS_PSM) - if (settings->power_save & POWER_SAVE_GNSS) - if (hw_info.model == SOFTRF_MODEL_UNI) - if (hw_info.gnss == GNSS_MODULE_U6 || - hw_info.gnss == GNSS_MODULE_U7 || - hw_info.gnss == GNSS_MODULE_U8) - { - if (!gnss_psm_active && isValidGNSSFix() && gnss.satellites.value() > 5) - { - // Setup for Power Save Mode (Default Cyclic 1s) - for (int i = 0; i < sizeof(RXM_PSM); i++) - swSer.write(pgm_read_byte(&RXM_PSM[i])); - - GNSS_DEBUG_PRINTLN(F("INFO: GNSS Power Save Mode")); - gnss_psm_active = true; - } - else if (gnss_psm_active && - ((gnss.satellites.isValid() && gnss.satellites.value() <= 5) || - gnss.satellites.age() > NMEA_EXP_TIME)) - { - // Setup for Continuous Mode - for (int i = 0; i < sizeof(RXM_MAXP); i++) - swSer.write(pgm_read_byte(&RXM_MAXP[i])); - - GNSS_DEBUG_PRINTLN(F("INFO: GNSS Continuous Mode")); - gnss_psm_active = false; - } - } - -#endif /* USE_GNSS_PSM */ -} - -void GNSS_fini() -{ - if (hw_info.model == SOFTRF_MODEL_PRIME_MK2 || - hw_info.model == SOFTRF_MODEL_UNI) - if (hw_info.gnss == GNSS_MODULE_U6 || - hw_info.gnss == GNSS_MODULE_U7 || - hw_info.gnss == GNSS_MODULE_U8) - { - // Controlled Software reset - for (int i = 0; i < sizeof(CFG_RST); i++) - swSer.write(pgm_read_byte(&CFG_RST[i])); - - delay(hw_info.gnss == GNSS_MODULE_U8 ? 1000 : 600); - - // power off until wakeup call - for (int i = 0; i < sizeof(RXM_PMREQ_OFF); i++) - swSer.write(pgm_read_byte(&RXM_PMREQ_OFF[i])); - } -} - -void GNSSTimeSync() -{ - if (GNSSTimeSyncMarker == 0 && gnss.time.isValid() && gnss.time.isUpdated()) - { - setTime(gnss.time.hour(), gnss.time.minute(), gnss.time.second(), gnss.date.day(), gnss.date.month(), gnss.date.year()); - GNSSTimeSyncMarker = millis(); - } - else - { - if ((millis() - GNSSTimeSyncMarker > 60000) /* 1m */ && gnss.time.isValid() && - gnss.time.isUpdated() && (gnss.time.age() <= 1000) /* 1s */) - { - #if 0 - Serial.print("Valid: "); - Serial.println(gnss.time.isValid()); - Serial.print("isUpdated: "); - Serial.println(gnss.time.isUpdated()); - Serial.print("age: "); - Serial.println(gnss.time.age()); - #endif - setTime(gnss.time.hour(), gnss.time.minute(), gnss.time.second(), gnss.date.day(), gnss.date.month(), gnss.date.year()); - GNSSTimeSyncMarker = millis(); - } - } -} - -void PickGNSSFix() -{ - bool isValidSentence = false; - int ndx; - int c = -1; - - /* - * Check SW, HW and BT UARTs for data - * WARNING! Make use only one input source at a time. - */ - while (true) { -#if !defined(USE_NMEA_CFG) - if (swSer.available() > 0) - c = swSer.read(); - else if (Serial.available() > 0) - c = Serial.read(); - else if (SoC->Bluetooth && SoC->Bluetooth->available() > 0) - { - c = SoC->Bluetooth->read(); - - /* - * Don't forget to disable echo: - * - * stty raw -echo -F /dev/rfcomm0 - * - * GNSS input becomes garbled otherwise - */ - - // Serial.write((char) c); - /* Ignore Bluetooth input for a while */ - // break; -#else - /* - * Give priority to control channels on STM32-based - * 'Dongle' and 'Retro' Editions - */ - - /* USB input is first */ - if (SoC->Bluetooth && SoC->Bluetooth->available() > 0) - { - c = SoC->Bluetooth->read(); - -#if 0 - /* This makes possible to configure S76x's built-in SONY GNSS from aside */ - if (hw_info.model == SOFTRF_MODEL_DONGLE) - swSer.write(c); - -#endif - - /* Serial input is second */ - } - else if (SerialOutput.available() > 0) - { - c = SerialOutput.read(); - - /* Built-in GNSS input */ - } - else if (swSer.available() > 0) - { - c = swSer.read(); -#endif /* USE_NMEA_CFG */ - } - else - /* return back if no input data */ - break; - - if (c == -1) - /* retry */ - continue; - - if (isPrintable(c) || c == '\r' || c == '\n') - GNSSbuf[GNSS_cnt] = c; - else - /* ignore */ - continue; - -#if 0 - if ((GNSS_cnt >= 5) && - (GNSSbuf[GNSS_cnt - 5] == '$') && - (GNSSbuf[GNSS_cnt - 4] == 'G') && - ((GNSSbuf[GNSS_cnt - 3] == 'P') || (GNSSbuf[GNSS_cnt - 3] == 'N')) && - (GNSSbuf[GNSS_cnt - 2] == 'G') && - (GNSSbuf[GNSS_cnt - 1] == 'G') && - (GNSSbuf[GNSS_cnt - 0] == 'A') - ) - GGA_Start_Time_Marker = millis(); - -#endif - - isValidSentence = gnss.encode(GNSSbuf[GNSS_cnt]); - if (settings->nmea_g && GNSSbuf[GNSS_cnt] == '\r' && isValidSentence) - { - for (ndx = GNSS_cnt - 4; ndx >= 0; ndx--) { // skip CS and * - if ((GNSSbuf[ndx] == '$') && (GNSSbuf[ndx + 1] == 'G')) - { - size_t write_size = GNSS_cnt - ndx + 1; - -#if 0 - if (!strncmp((char *) &GNSSbuf[ndx + 3], "GGA,", strlen("GGA,"))) - { - GGA_Stop_Time_Marker = millis(); - - Serial.print("GGA Start: "); - Serial.print(GGA_Start_Time_Marker); - Serial.print(" Stop: "); - Serial.print(GGA_Stop_Time_Marker); - Serial.print(" gnss.time.age: "); - Serial.println(gnss.time.age()); - } -#endif - - /* - * Work around issue with "always 0.0,M" GGA geoid separation value - * given by some Chinese GNSS chipsets - */ -#if defined(USE_NMEALIB) - if (hw_info.model == SOFTRF_MODEL_PRIME_MK2 && - !strncmp((char *) &GNSSbuf[ndx + 3], "GGA,", strlen("GGA,")) && - gnss.separation.meters() == 0.0) - NMEA_GGA(); - else -#endif - { - NMEA_Out(&GNSSbuf[ndx], write_size, true); - } - - break; - } - } -#if defined(USE_NMEA_CFG) - if (C_Version.isUpdated()) - { - if (strncmp(C_Version.value(), "RST", 3) == 0) - { - SoC->WDT_fini(); - Serial.println(); - Serial.println(F("Restart is in progress. Please, wait...")); - Serial.println(); - Serial.flush(); - RF_Shutdown(); - SoC->reset(); - } - else if (strncmp(C_Version.value(), "OFF", 3) == 0) - shutdown(" OFF "); - else if (strncmp(C_Version.value(), "?", 1) == 0) - { - char psrfc_buf[MAX_PSRFC_LEN]; - - snprintf_P(psrfc_buf, sizeof(psrfc_buf), - PSTR("$PSRFC,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d*"), - PSRFC_VERSION, settings->mode, settings->rf_protocol, - settings->band, settings->aircraft_type, settings->alarm, - settings->txpower, settings->volume, settings->pointer, - settings->nmea_g, settings->nmea_p, settings->nmea_l, - settings->nmea_s, settings->nmea_out, settings->gdl90, - settings->d1090, settings->stealth, settings->no_track, - settings->power_save); - - NMEA_add_checksum(psrfc_buf, sizeof(psrfc_buf) - strlen(psrfc_buf)); - NMEA_Out((byte *) psrfc_buf, strlen(psrfc_buf), false); - } - else if (atoi(C_Version.value()) == PSRFC_VERSION) - { - bool cfg_is_updated = false; - - if (C_Mode.isUpdated()) - { - settings->mode = atoi(C_Mode.value()); - Serial.print(F("Mode = ")); - Serial.println(settings->mode); - cfg_is_updated = true; - } - if (C_Protocol.isUpdated()) - { - settings->rf_protocol = atoi(C_Protocol.value()); - Serial.print(F("Protocol = ")); - Serial.println(settings->rf_protocol); - cfg_is_updated = true; - } - if (C_Band.isUpdated()) - { - settings->band = atoi(C_Band.value()); - Serial.print(F("Region = ")); - Serial.println(settings->band); - cfg_is_updated = true; - } - if (C_AcftType.isUpdated()) - { - settings->aircraft_type = atoi(C_AcftType.value()); - Serial.print(F("AcftType = ")); - Serial.println(settings->aircraft_type); - cfg_is_updated = true; - } - if (C_Alarm.isUpdated()) - { - settings->alarm = atoi(C_Alarm.value()); - Serial.print(F("Alarm = ")); - Serial.println(settings->alarm); - cfg_is_updated = true; - } - if (C_TxPower.isUpdated()) - { - settings->txpower = atoi(C_TxPower.value()); - Serial.print(F("TxPower = ")); - Serial.println(settings->txpower); - cfg_is_updated = true; - } - if (C_Volume.isUpdated()) - { - settings->volume = atoi(C_Volume.value()); - Serial.print(F("Volume = ")); - Serial.println(settings->volume); - cfg_is_updated = true; - } - if (C_Pointer.isUpdated()) - { - settings->pointer = atoi(C_Pointer.value()); - Serial.print(F("Pointer = ")); - Serial.println(settings->pointer); - cfg_is_updated = true; - } - if (C_NMEA_gnss.isUpdated()) - { - settings->nmea_g = atoi(C_NMEA_gnss.value()); - Serial.print(F("NMEA_gnss = ")); - Serial.println(settings->nmea_g); - cfg_is_updated = true; - } - if (C_NMEA_private.isUpdated()) - { - settings->nmea_p = atoi(C_NMEA_private.value()); - Serial.print(F("NMEA_private = ")); - Serial.println(settings->nmea_p); - cfg_is_updated = true; - } - if (C_NMEA_legacy.isUpdated()) - { - settings->nmea_l = atoi(C_NMEA_legacy.value()); - Serial.print(F("NMEA_legacy = ")); - Serial.println(settings->nmea_l); - cfg_is_updated = true; - } - if (C_NMEA_sensors.isUpdated()) - { - settings->nmea_s = atoi(C_NMEA_sensors.value()); - Serial.print(F("NMEA_sensors = ")); - Serial.println(settings->nmea_s); - cfg_is_updated = true; - } - if (C_NMEA_Output.isUpdated()) - { - settings->nmea_out = atoi(C_NMEA_Output.value()); - Serial.print(F("NMEA_Output = ")); - Serial.println(settings->nmea_out); - cfg_is_updated = true; - } - if (C_GDL90_Output.isUpdated()) - { - settings->gdl90 = atoi(C_GDL90_Output.value()); - Serial.print(F("GDL90_Output = ")); - Serial.println(settings->gdl90); - cfg_is_updated = true; - } - if (C_D1090_Output.isUpdated()) - { - settings->d1090 = atoi(C_D1090_Output.value()); - Serial.print(F("D1090_Output = ")); - Serial.println(settings->d1090); - cfg_is_updated = true; - } - if (C_Stealth.isUpdated()) - { - settings->stealth = atoi(C_Stealth.value()); - Serial.print(F("Stealth = ")); - Serial.println(settings->stealth); - cfg_is_updated = true; - } - if (C_noTrack.isUpdated()) - { - settings->no_track = atoi(C_noTrack.value()); - Serial.print(F("noTrack = ")); - Serial.println(settings->no_track); - cfg_is_updated = true; - } - if (C_PowerSave.isUpdated()) - { - settings->power_save = atoi(C_PowerSave.value()); - Serial.print(F("PowerSave = ")); - Serial.println(settings->power_save); - cfg_is_updated = true; - } - - if (cfg_is_updated) - { - SoC->WDT_fini(); - Serial.println(); - Serial.println(F("Restart is in progress. Please, wait...")); - Serial.println(); - Serial.flush(); - EEPROM_store(); - RF_Shutdown(); - SoC->reset(); - } - } - } -#endif /* USE_NMEA_CFG */ - } - if (GNSSbuf[GNSS_cnt] == '\n' || GNSS_cnt == sizeof(GNSSbuf) - 1) - GNSS_cnt = 0; - else - { - GNSS_cnt++; - yield(); - } - } -} - -#if !defined(EXCLUDE_EGM96) -/* - * Algorithm of EGM96 geoid offset approximation was taken from XCSoar - */ - -static float AsBearing(float angle) -{ - float retval = angle; - - while (retval < 0) { - retval += 360.0; - } - - while (retval >= 360.0) { - retval -= 360.0; - } - - return retval; -} - -int LookupSeparation(float lat, float lon) -{ - int ilat, ilon; - - ilat = round((90.0 - lat) / 2.0); - ilon = round(AsBearing(lon) / 2.0); - - int offset = ilat * 180 + ilon; - - if (offset >= egm96s_dem_len) - return 0; - - if (offset < 0) - return 0; - - return (int) pgm_read_byte(&egm96s_dem[offset]) - 127; -} - -#endif /* EXCLUDE_EGM96 */ +/* + * GNSS.cpp + * Copyright (C) 2019-2020 Linar Yusupov + * + * 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 . + */ + +#if defined(ARDUINO) +#include +#endif +#include + +#include "GNSS.h" +#include "EEPROM.h" +#include "NMEA.h" +#include "SoC.h" +#include "WiFi.h" +#include "RF.h" +#include "Battery.h" + +#if !defined(EXCLUDE_EGM96) +#include +#endif /* EXCLUDE_EGM96 */ + +#if !defined(DO_GNSS_DEBUG) +#define GNSS_DEBUG_PRINT +#define GNSS_DEBUG_PRINTLN +#else +#define GNSS_DEBUG_PRINT Serial.print +#define GNSS_DEBUG_PRINTLN Serial.println +#endif + +unsigned long GNSSTimeSyncMarker = 0; +volatile unsigned long PPS_TimeMarker = 0; + +#if 0 +unsigned long GGA_Start_Time_Marker = 0; +unsigned long GGA_Stop_Time_Marker = 0; +#endif + +boolean gnss_set_sucess = false; +TinyGPSPlus gnss; // Create an Instance of the TinyGPS++ object called gnss + +uint8_t GNSSbuf[250]; // at least 3 lines of 80 characters each + // and 40+30*N bytes for "UBX-MON-VER" payload +int GNSS_cnt = 0; + +/* CFG-MSG */ +const uint8_t setGLL[] PROGMEM = {0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; +const uint8_t setGSV[] PROGMEM = {0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; +const uint8_t setVTG[] PROGMEM = {0xF0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; +#if !defined(NMEA_TCP_SERVICE) +const uint8_t setGSA[] PROGMEM = {0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; +#endif +/* CFG-PRT */ +uint8_t setBR[] = {0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x00, 0x96, + 0x00, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const uint8_t setNav5[] PROGMEM = {0xFF, 0xFF, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x27, 0x00, 0x00, 0x05, 0x00, 0xFA, 0x00, + 0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + +const uint8_t CFG_RST[12] PROGMEM = {0xb5, 0x62, 0x06, 0x04, 0x04, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x0F, 0x66}; + +const uint8_t RXM_PMREQ_OFF[16] PROGMEM = {0xb5, 0x62, 0x02, 0x41, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x4d, 0x3b}; + +const byte RXM_PMREQ[16] = {0xb5, 0x62, 0x02, 0x41, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4d, 0x3b}; //power off until wakeup call +uint8_t GPSon[16] = {0xB5, 0x62, 0x02, 0x41, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4C, 0x37}; + +#if defined(USE_GNSS_PSM) +static bool gnss_psm_active = false; + +/* Max Performance Mode (default) */ +const uint8_t RXM_MAXP[] PROGMEM = {0xB5, 0x62, 0x06, 0x11, 0x02, 0x00, 0x08, 0x00, 0x21, 0x91}; + +/* Power Save Mode */ +const uint8_t RXM_PSM[] PROGMEM = {0xB5, 0x62, 0x06, 0x11, 0x02, 0x00, 0x08, 0x01, 0x22, 0x92}; +#endif /* USE_GNSS_PSM */ + +const char* GNSS_name[] = { + [GNSS_MODULE_NONE] = "NONE", + [GNSS_MODULE_NMEA] = "NMEA", + [GNSS_MODULE_U6] = "U6", + [GNSS_MODULE_U7] = "U7", + [GNSS_MODULE_U8] = "U8", + [GNSS_MODULE_U9] = "U9", + [GNSS_MODULE_MAV] = "MAV", + [GNSS_MODULE_S7XG] = "S7XG" +}; + +#if defined(USE_NMEA_CFG) + +#include "RF.h" /* RF_Shutdown() */ + + +#include "GDL90.h" +#include "D1090.h" + +TinyGPSCustom C_Version(gnss, "PSRFC", 1); +TinyGPSCustom C_Mode(gnss, "PSRFC", 2); +TinyGPSCustom C_Protocol(gnss, "PSRFC", 3); +TinyGPSCustom C_Band(gnss, "PSRFC", 4); +TinyGPSCustom C_AcftType(gnss, "PSRFC", 5); +TinyGPSCustom C_Alarm(gnss, "PSRFC", 6); +TinyGPSCustom C_TxPower(gnss, "PSRFC", 7); +TinyGPSCustom C_Volume(gnss, "PSRFC", 8); +TinyGPSCustom C_Pointer(gnss, "PSRFC", 9); +TinyGPSCustom C_NMEA_gnss(gnss, "PSRFC", 10); +TinyGPSCustom C_NMEA_private(gnss, "PSRFC", 11); +TinyGPSCustom C_NMEA_legacy(gnss, "PSRFC", 12); +TinyGPSCustom C_NMEA_sensors(gnss, "PSRFC", 13); +TinyGPSCustom C_NMEA_Output(gnss, "PSRFC", 14); +TinyGPSCustom C_GDL90_Output(gnss, "PSRFC", 15); +TinyGPSCustom C_D1090_Output(gnss, "PSRFC", 16); +TinyGPSCustom C_Stealth(gnss, "PSRFC", 17); +TinyGPSCustom C_noTrack(gnss, "PSRFC", 18); +TinyGPSCustom C_PowerSave(gnss, "PSRFC", 19); + +#endif /* USE_NMEA_CFG */ + +static uint8_t makeUBXCFG(uint8_t cl, uint8_t id, uint8_t msglen, const uint8_t* msg) +{ + if (msglen > (sizeof(GNSSbuf) - 8)) + msglen = sizeof(GNSSbuf) - 8; + + // Construct the UBX packet + GNSSbuf[0] = 0xB5; // header + GNSSbuf[1] = 0x62; // header + GNSSbuf[2] = cl; // class + GNSSbuf[3] = id; // id + GNSSbuf[4] = msglen; // length + GNSSbuf[5] = 0x00; + + GNSSbuf[6 + msglen] = 0x00; // CK_A + GNSSbuf[7 + msglen] = 0x00; // CK_B + + for (int i = 2; i < 6; i++) { + GNSSbuf[6 + msglen] += GNSSbuf[i]; + GNSSbuf[7 + msglen] += GNSSbuf[6 + msglen]; + } + + for (int i = 0; i < msglen; i++) { + GNSSbuf[6 + i] = pgm_read_byte(&msg[i]); + GNSSbuf[6 + msglen] += GNSSbuf[6 + i]; + GNSSbuf[7 + msglen] += GNSSbuf[6 + msglen]; + } + return msglen + 8; +} + +// Send a byte array of UBX protocol to the GPS +static void sendUBX(const uint8_t* MSG, uint8_t len) +{ + for (int i = 0; i < len; i++) { + swSer.write(MSG[i]); + GNSS_DEBUG_PRINT(MSG[i], HEX); + } +// swSer.println(); +} + +// Calculate expected UBX ACK packet and parse UBX response from GPS +static boolean getUBX_ACK(uint8_t cl, uint8_t id) +{ + uint8_t b; + uint8_t ackByteID = 0; + uint8_t ackPacket[2] = {cl, id}; + unsigned long startTime = millis(); + GNSS_DEBUG_PRINT(F(" * Reading ACK response: ")); + + // Construct the expected ACK packet + makeUBXCFG(0x05, 0x01, 2, ackPacket); + + while (1) { + // Test for success + if (ackByteID > 9) + { + // All packets in order! + GNSS_DEBUG_PRINTLN(F(" (SUCCESS!)")); + return true; + } + + // Timeout if no valid response in 2 seconds + if (millis() - startTime > 2000) + { + GNSS_DEBUG_PRINTLN(F(" (FAILED!)")); + return false; + } + + // Make sure data is available to read + if (swSer.available()) + { + b = swSer.read(); + + // Check that bytes arrive in sequence as per expected ACK packet + if (b == GNSSbuf[ackByteID]) + { + ackByteID++; + GNSS_DEBUG_PRINT(b, HEX); + } + else + { + ackByteID = 0; // Reset and look again, invalid order + } + } + yield(); + } +} + +static void setup_UBX() +{ + uint8_t msglen; + +#if 0 + unsigned int baudrate =; + + setBR[ 8] = (baudrate) & 0xFF; + setBR[ 9] = (baudrate >> 8) & 0xFF; + setBR[10] = (baudrate >> 16) & 0xFF; + + SoC->swSer_begin(9600); + + Serial.print(F("Switching baud rate onto ")); + Serial.println(baudrate); + + msglen = makeUBXCFG(0x06, 0x00, sizeof(setBR), setBR); + sendUBX(GNSSbuf, msglen); + gnss_set_sucess = getUBX_ACK(0x06, 0x00); + + if (!gnss_set_sucess) + { + Serial.print(F("WARNING: Unable to set baud rate onto ")); + Serial.println(baudrate); + } + swSer.flush(); + SoC->swSer_begin(baudrate); +#endif + + GNSS_DEBUG_PRINTLN(F("Airborne <2g navigation mode: ")); + + // Set the navigation mode (Airborne, < 2g) + msglen = makeUBXCFG(0x06, 0x24, sizeof(setNav5), setNav5); + sendUBX(GNSSbuf, msglen); + gnss_set_sucess = getUBX_ACK(0x06, 0x24); + + if (!gnss_set_sucess) + GNSS_DEBUG_PRINTLN(F("WARNING: Unable to set airborne <2g navigation mode.")); + + GNSS_DEBUG_PRINTLN(F("Switching off NMEA GLL: ")); + + msglen = makeUBXCFG(0x06, 0x01, sizeof(setGLL), setGLL); + sendUBX(GNSSbuf, msglen); + gnss_set_sucess = getUBX_ACK(0x06, 0x01); + + if (!gnss_set_sucess) + GNSS_DEBUG_PRINTLN(F("WARNING: Unable to disable NMEA GLL.")); + + GNSS_DEBUG_PRINTLN(F("Switching off NMEA GSV: ")); + + msglen = makeUBXCFG(0x06, 0x01, sizeof(setGSV), setGSV); + sendUBX(GNSSbuf, msglen); + gnss_set_sucess = getUBX_ACK(0x06, 0x01); + + if (!gnss_set_sucess) + GNSS_DEBUG_PRINTLN(F("WARNING: Unable to disable NMEA GSV.")); + + GNSS_DEBUG_PRINTLN(F("Switching off NMEA VTG: ")); + + msglen = makeUBXCFG(0x06, 0x01, sizeof(setVTG), setVTG); + sendUBX(GNSSbuf, msglen); + gnss_set_sucess = getUBX_ACK(0x06, 0x01); + + if (!gnss_set_sucess) + GNSS_DEBUG_PRINTLN(F("WARNING: Unable to disable NMEA VTG.")); + +#if !defined(NMEA_TCP_SERVICE) + + GNSS_DEBUG_PRINTLN(F("Switching off NMEA GSA: ")); + + msglen = makeUBXCFG(0x06, 0x01, sizeof(setGSA), setGSA); + sendUBX(GNSSbuf, msglen); + gnss_set_sucess = getUBX_ACK(0x06, 0x01); + + if (!gnss_set_sucess) + GNSS_DEBUG_PRINTLN(F("WARNING: Unable to disable NMEA GSA.")); + +#endif +} + +static void setup_NMEA() +{ +#if 0 + //swSer.write("$PUBX,41,1,0007,0003,9600,0*10\r\n"); + swSer.write("$PUBX,41,1,0007,0003,38400,0*20\r\n"); + + swSer.flush(); + SoC->swSer_begin(38400); + + // Turning off some GPS NMEA strings on the uBlox modules + swSer.write("$PUBX,40,GLL,0,0,0,0*5C\r\n"); + delay(250); + swSer.write("$PUBX,40,GSV,0,0,0,0*59\r\n"); + delay(250); + swSer.write("$PUBX,40,VTG,0,0,0,0*5E\r\n"); + delay(250); +#if !defined(NMEA_TCP_SERVICE) + swSer.write("$PUBX,40,GSA,0,0,0,0*4E\r\n"); + delay(250); +#endif +#endif + +#if defined(USE_AT6558_SETUP) + /* Assume that we deal with fake NEO module (AT6558 based) */ + swSer.write("$PCAS04,5*1C\r\n"); /* GPS + GLONASS */ delay(250); +#if defined(NMEA_TCP_SERVICE) + /* GGA,RMC and GSA */ + swSer.write("$PCAS03,1,0,1,0,1,0,0,0,0,0,,,0,0*03\r\n"); + delay(250); +#else + /* GGA and RMC */ + swSer.write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n"); + delay(250); +#endif + swSer.write("$PCAS11,6*1B\r\n"); /* Aviation < 2g */ delay(250); +#endif /* USE_AT6558_SETUP */ +} + +/* ------ BEGIN ----------- https://github.com/Black-Thunder/FPV-Tracker */ + +enum ubloxState +{ + WAIT_SYNC1, WAIT_SYNC2, GET_CLASS, GET_ID, GET_LL, GET_LH, GET_DATA, GET_CKA, GET_CKB +}; + +ubloxState ubloxProcessDataState = WAIT_SYNC1; + +unsigned short ubloxExpectedDataLength; +unsigned short ubloxClass, ubloxId; +unsigned char ubloxCKA, ubloxCKB; + +// process serial data +// data is stored inside #GNSSbuf, data size inside #GNSS_cnt +// warning : if #GNSSbuf is too short, data is truncated. +static int ubloxProcessData(unsigned char data) +{ + int parsed = 0; + + switch (ubloxProcessDataState) + { + case WAIT_SYNC1: + if (data == 0xb5) + ubloxProcessDataState = WAIT_SYNC2; + break; + + case WAIT_SYNC2: + if (data == 0x62) + ubloxProcessDataState = GET_CLASS; + else if (data == 0xb5) + { + // ubloxProcessDataState = GET_SYNC2; + } + else + ubloxProcessDataState = WAIT_SYNC1; + break; + case GET_CLASS: + ubloxClass = data; + ubloxCKA = data; + ubloxCKB = data; + ubloxProcessDataState = GET_ID; + break; + + case GET_ID: + ubloxId = data; + ubloxCKA += data; + ubloxCKB += ubloxCKA; + ubloxProcessDataState = GET_LL; + break; + + case GET_LL: + ubloxExpectedDataLength = data; + ubloxCKA += data; + ubloxCKB += ubloxCKA; + ubloxProcessDataState = GET_LH; + break; + + case GET_LH: + ubloxExpectedDataLength += data << 8; + GNSS_cnt = 0; + ubloxCKA += data; + ubloxCKB += ubloxCKA; + ubloxProcessDataState = GET_DATA; + break; + + case GET_DATA: + ubloxCKA += data; + ubloxCKB += ubloxCKA; + if (GNSS_cnt < sizeof(GNSSbuf)) + GNSSbuf[GNSS_cnt++] = data; + if ((--ubloxExpectedDataLength) == 0) + ubloxProcessDataState = GET_CKA; + break; + + case GET_CKA: + if (ubloxCKA != data) + ubloxProcessDataState = WAIT_SYNC1; + else + ubloxProcessDataState = GET_CKB; + break; + + case GET_CKB: + if (ubloxCKB == data) + parsed = 1; + ubloxProcessDataState = WAIT_SYNC1; + break; + } + + return parsed; +} + +/* ------ END ----------- https://github.com/Black-Thunder/FPV-Tracker */ + +static boolean GNSS_probe() +{ + unsigned long startTime = millis(); + char c1, c2; + c1 = c2 = 0; + + // clean any leftovers + swSer.flush(); + + // Serial.println(F("INFO: Waiting for NMEA data from GNSS module...")); + + // Timeout if no valid response in 3 seconds + while (millis() - startTime < 3000) { + if (swSer.available() > 0) + { + c1 = swSer.read(); + if ((c1 == '$') && (c2 == 0)) + { + c2 = c1; + continue; + } + if ((c2 == '$') && (c1 == 'G')) + /* got $G */ + + /* leave the function with GNSS port opened */ + return true; + else + c2 = 0; + } + + delay(1); + } + + return false; +} + +static byte GNSS_version() +{ + byte rval = GNSS_MODULE_NMEA; + unsigned long startTime = millis(); + + uint8_t msglen = makeUBXCFG(0x0A, 0x04, 0, NULL); // MON-VER + sendUBX(GNSSbuf, msglen); + + // Get the message back from the GPS + GNSS_DEBUG_PRINT(F(" * Reading response: ")); + + while ((millis() - startTime) < 2000) { + if (swSer.available()) + { + unsigned char c = swSer.read(); + int ret = 0; + + GNSS_DEBUG_PRINT(c, HEX); + ret = ubloxProcessData(c); + + // Upon a successfully parsed sentence, do the version detection + if (ret) + { + if (ubloxClass == 0x0A) // MON + { + if (ubloxId == 0x04) // VER + + // UBX-MON-VER data description + // uBlox 6 - page 166 : https://www.u-blox.com/sites/default/files/products/documents/u-blox6_ReceiverDescrProtSpec_%28GPS.G6-SW-10018%29_Public.pdf + // uBlox 7 - page 153 : https://www.u-blox.com/sites/default/files/products/documents/u-blox7-V14_ReceiverDescriptionProtocolSpec_%28GPS.G7-SW-12001%29_Public.pdf + // uBlox M8 - page 300 : https://www.u-blox.com/sites/default/files/products/documents/u-blox8-M8_ReceiverDescrProtSpec_%28UBX-13003221%29_Public.pdf + + { + Serial.print(F("INFO: GNSS module HW version: ")); + Serial.println((char *) &GNSSbuf[30]); + + Serial.print(F("INFO: GNSS module FW version: ")); + Serial.println((char *) &GNSSbuf[0]); + +#ifdef DO_GNSS_DEBUG + for (unsigned i = 30 + 10; i < GNSS_cnt; i+=30) { + Serial.print(F("INFO: GNSS module extension: ")); + Serial.println((char *) &GNSSbuf[i]); + } +#endif + + if (GNSSbuf[33] == '4') + rval = GNSS_MODULE_U6; + else if (GNSSbuf[33] == '7') + rval = GNSS_MODULE_U7; + else if (GNSSbuf[33] == '8') + rval = GNSS_MODULE_U8; + + break; + } + } + } + } + } + + return rval; +} + +byte GNSS_setup() +{ + byte rval = GNSS_MODULE_NONE; + + SoC->swSer_begin(SERIAL_IN_BR); + + if (hw_info.model == SOFTRF_MODEL_PRIME_MK2 || + hw_info.model == SOFTRF_MODEL_UNI) + { + // power on by wakeup call + swSer.write((uint8_t) 0); + swSer.flush(); + delay(500); + } + + if (!GNSS_probe()) + return rval; + + rval = GNSS_MODULE_NMEA; + + if (hw_info.model == SOFTRF_MODEL_PRIME_MK2 || + hw_info.model == SOFTRF_MODEL_RASPBERRY || + hw_info.model == SOFTRF_MODEL_UNI) + { + rval = GNSS_version(); + + if (rval == GNSS_MODULE_U6 || + rval == GNSS_MODULE_U7 || + rval == GNSS_MODULE_U8) + + // Set the navigation mode (Airborne, 1G) + // Turning off some GPS NMEA sentences on the uBlox modules + setup_UBX(); + else + setup_NMEA(); + } + + if (SOC_GPIO_PIN_GNSS_PPS != SOC_UNUSED_PIN) + { + pinMode(SOC_GPIO_PIN_GNSS_PPS, SOC_GPIO_PIN_MODE_PULLDOWN); + attachInterrupt(digitalPinToInterrupt(SOC_GPIO_PIN_GNSS_PPS), + SoC->GNSS_PPS_handler, RISING); + } + + return rval; +} + +void GNSS_sleep() +{ + for (int i = 0; i < sizeof(CFG_RST); i++) + swSer.write(pgm_read_byte(&CFG_RST[i])); + delay(600); + + for (int i = 0; i < sizeof(RXM_PMREQ); i++) + swSer.write(pgm_read_byte(&RXM_PMREQ[i])); +} + +void GNSS_wakeup() +{ + for (int i = 0; i < 20; i++) //send random to trigger respose + swSer.write(0xFF); +} + +void GNSS_loop(bool TimeSync) +{ + PickGNSSFix(); + + if (!TimeSync) + GNSSTimeSync(); + +#if defined(USE_GNSS_PSM) + if (settings->power_save & POWER_SAVE_GNSS) + if (hw_info.model == SOFTRF_MODEL_UNI) + if (hw_info.gnss == GNSS_MODULE_U6 || + hw_info.gnss == GNSS_MODULE_U7 || + hw_info.gnss == GNSS_MODULE_U8) + { + if (!gnss_psm_active && isValidGNSSFix() && gnss.satellites.value() > 5) + { + // Setup for Power Save Mode (Default Cyclic 1s) + for (int i = 0; i < sizeof(RXM_PSM); i++) + swSer.write(pgm_read_byte(&RXM_PSM[i])); + + GNSS_DEBUG_PRINTLN(F("INFO: GNSS Power Save Mode")); + gnss_psm_active = true; + } + else if (gnss_psm_active && + ((gnss.satellites.isValid() && gnss.satellites.value() <= 5) || + gnss.satellites.age() > NMEA_EXP_TIME)) + { + // Setup for Continuous Mode + for (int i = 0; i < sizeof(RXM_MAXP); i++) + swSer.write(pgm_read_byte(&RXM_MAXP[i])); + + GNSS_DEBUG_PRINTLN(F("INFO: GNSS Continuous Mode")); + gnss_psm_active = false; + } + } + +#endif /* USE_GNSS_PSM */ +} + +void GNSS_fini() +{ + if (hw_info.model == SOFTRF_MODEL_PRIME_MK2 || + hw_info.model == SOFTRF_MODEL_UNI) + if (hw_info.gnss == GNSS_MODULE_U6 || + hw_info.gnss == GNSS_MODULE_U7 || + hw_info.gnss == GNSS_MODULE_U8) + { + // Controlled Software reset + for (int i = 0; i < sizeof(CFG_RST); i++) + swSer.write(pgm_read_byte(&CFG_RST[i])); + + delay(hw_info.gnss == GNSS_MODULE_U8 ? 1000 : 600); + + // power off until wakeup call + for (int i = 0; i < sizeof(RXM_PMREQ_OFF); i++) + swSer.write(pgm_read_byte(&RXM_PMREQ_OFF[i])); + } +} + +void GNSSTimeSync() +{ + if (GNSSTimeSyncMarker == 0 && gnss.time.isValid() && gnss.time.isUpdated()) + { + setTime(gnss.time.hour(), gnss.time.minute(), gnss.time.second(), gnss.date.day(), gnss.date.month(), gnss.date.year()); + GNSSTimeSyncMarker = millis(); + } + else + { + if ((millis() - GNSSTimeSyncMarker > 60000) /* 1m */ && gnss.time.isValid() && + gnss.time.isUpdated() && (gnss.time.age() <= 1000) /* 1s */) + { + #if 0 + Serial.print("Valid: "); + Serial.println(gnss.time.isValid()); + Serial.print("isUpdated: "); + Serial.println(gnss.time.isUpdated()); + Serial.print("age: "); + Serial.println(gnss.time.age()); + #endif + setTime(gnss.time.hour(), gnss.time.minute(), gnss.time.second(), gnss.date.day(), gnss.date.month(), gnss.date.year()); + GNSSTimeSyncMarker = millis(); + } + } +} + +void PickGNSSFix() +{ + bool isValidSentence = false; + int ndx; + int c = -1; + + /* + * Check SW, HW and BT UARTs for data + * WARNING! Make use only one input source at a time. + */ + while (true) { +#if !defined(USE_NMEA_CFG) + if (swSer.available() > 0) + c = swSer.read(); + else if (Serial.available() > 0) + c = Serial.read(); + else if (SoC->Bluetooth && SoC->Bluetooth->available() > 0) + { + c = SoC->Bluetooth->read(); + + /* + * Don't forget to disable echo: + * + * stty raw -echo -F /dev/rfcomm0 + * + * GNSS input becomes garbled otherwise + */ + + // Serial.write((char) c); + /* Ignore Bluetooth input for a while */ + // break; +#else + /* + * Give priority to control channels on STM32-based + * 'Dongle' and 'Retro' Editions + */ + + /* USB input is first */ + if (SoC->Bluetooth && SoC->Bluetooth->available() > 0) + { + c = SoC->Bluetooth->read(); + +#if 0 + /* This makes possible to configure S76x's built-in SONY GNSS from aside */ + if (hw_info.model == SOFTRF_MODEL_DONGLE) + swSer.write(c); + +#endif + + /* Serial input is second */ + } + else if (SerialOutput.available() > 0) + { + c = SerialOutput.read(); + + /* Built-in GNSS input */ + } + else if (swSer.available() > 0) + { + c = swSer.read(); +#endif /* USE_NMEA_CFG */ + } + else + /* return back if no input data */ + break; + + if (c == -1) + /* retry */ + continue; + + if (isPrintable(c) || c == '\r' || c == '\n') + GNSSbuf[GNSS_cnt] = c; + else + /* ignore */ + continue; + +#if 0 + if ((GNSS_cnt >= 5) && + (GNSSbuf[GNSS_cnt - 5] == '$') && + (GNSSbuf[GNSS_cnt - 4] == 'G') && + ((GNSSbuf[GNSS_cnt - 3] == 'P') || (GNSSbuf[GNSS_cnt - 3] == 'N')) && + (GNSSbuf[GNSS_cnt - 2] == 'G') && + (GNSSbuf[GNSS_cnt - 1] == 'G') && + (GNSSbuf[GNSS_cnt - 0] == 'A') + ) + GGA_Start_Time_Marker = millis(); + +#endif + + isValidSentence = gnss.encode(GNSSbuf[GNSS_cnt]); + if (settings->nmea_g && GNSSbuf[GNSS_cnt] == '\r' && isValidSentence) + { + for (ndx = GNSS_cnt - 4; ndx >= 0; ndx--) { // skip CS and * + if ((GNSSbuf[ndx] == '$') && (GNSSbuf[ndx + 1] == 'G')) + { + size_t write_size = GNSS_cnt - ndx + 1; + +#if 0 + if (!strncmp((char *) &GNSSbuf[ndx + 3], "GGA,", strlen("GGA,"))) + { + GGA_Stop_Time_Marker = millis(); + + Serial.print("GGA Start: "); + Serial.print(GGA_Start_Time_Marker); + Serial.print(" Stop: "); + Serial.print(GGA_Stop_Time_Marker); + Serial.print(" gnss.time.age: "); + Serial.println(gnss.time.age()); + } +#endif + + /* + * Work around issue with "always 0.0,M" GGA geoid separation value + * given by some Chinese GNSS chipsets + */ +#if defined(USE_NMEALIB) + if (hw_info.model == SOFTRF_MODEL_PRIME_MK2 && + !strncmp((char *) &GNSSbuf[ndx + 3], "GGA,", strlen("GGA,")) && + gnss.separation.meters() == 0.0) + NMEA_GGA(); + else +#endif + { + NMEA_Out(&GNSSbuf[ndx], write_size, true); + } + + break; + } + } +#if defined(USE_NMEA_CFG) + if (C_Version.isUpdated()) + { + if (strncmp(C_Version.value(), "RST", 3) == 0) + { + SoC->WDT_fini(); + Serial.println(); + Serial.println(F("Restart is in progress. Please, wait...")); + Serial.println(); + Serial.flush(); + RF_Shutdown(); + SoC->reset(); + } + else if (strncmp(C_Version.value(), "OFF", 3) == 0) + shutdown(" OFF "); + else if (strncmp(C_Version.value(), "?", 1) == 0) + { + char psrfc_buf[MAX_PSRFC_LEN]; + + snprintf_P(psrfc_buf, sizeof(psrfc_buf), + PSTR("$PSRFC,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d*"), + PSRFC_VERSION, settings->mode, ogn_protocol_1, + ogn_band, settings->aircraft_type, settings->alarm, + settings->txpower, settings->volume, settings->pointer, + settings->nmea_g, settings->nmea_p, settings->nmea_l, + settings->nmea_s, settings->nmea_out, settings->gdl90, + settings->d1090, settings->stealth, settings->no_track, + settings->power_save); + + NMEA_add_checksum(psrfc_buf, sizeof(psrfc_buf) - strlen(psrfc_buf)); + NMEA_Out((byte *) psrfc_buf, strlen(psrfc_buf), false); + } + else if (atoi(C_Version.value()) == PSRFC_VERSION) + { + bool cfg_is_updated = false; + + if (C_Mode.isUpdated()) + { + settings->mode = atoi(C_Mode.value()); + Serial.print(F("Mode = ")); + Serial.println(settings->mode); + cfg_is_updated = true; + } + if (C_Protocol.isUpdated()) + { + ogn_protocol_1 = atoi(C_Protocol.value()); + Serial.print(F("Protocol = ")); + Serial.println(ogn_protocol_1); + cfg_is_updated = true; + } + if (C_Band.isUpdated()) + { + ogn_band = atoi(C_Band.value()); + Serial.print(F("Region = ")); + Serial.println(ogn_band); + cfg_is_updated = true; + } + if (C_AcftType.isUpdated()) + { + settings->aircraft_type = atoi(C_AcftType.value()); + Serial.print(F("AcftType = ")); + Serial.println(settings->aircraft_type); + cfg_is_updated = true; + } + if (C_Alarm.isUpdated()) + { + settings->alarm = atoi(C_Alarm.value()); + Serial.print(F("Alarm = ")); + Serial.println(settings->alarm); + cfg_is_updated = true; + } + if (C_TxPower.isUpdated()) + { + settings->txpower = atoi(C_TxPower.value()); + Serial.print(F("TxPower = ")); + Serial.println(settings->txpower); + cfg_is_updated = true; + } + if (C_Volume.isUpdated()) + { + settings->volume = atoi(C_Volume.value()); + Serial.print(F("Volume = ")); + Serial.println(settings->volume); + cfg_is_updated = true; + } + if (C_Pointer.isUpdated()) + { + settings->pointer = atoi(C_Pointer.value()); + Serial.print(F("Pointer = ")); + Serial.println(settings->pointer); + cfg_is_updated = true; + } + if (C_NMEA_gnss.isUpdated()) + { + settings->nmea_g = atoi(C_NMEA_gnss.value()); + Serial.print(F("NMEA_gnss = ")); + Serial.println(settings->nmea_g); + cfg_is_updated = true; + } + if (C_NMEA_private.isUpdated()) + { + settings->nmea_p = atoi(C_NMEA_private.value()); + Serial.print(F("NMEA_private = ")); + Serial.println(settings->nmea_p); + cfg_is_updated = true; + } + if (C_NMEA_legacy.isUpdated()) + { + settings->nmea_l = atoi(C_NMEA_legacy.value()); + Serial.print(F("NMEA_legacy = ")); + Serial.println(settings->nmea_l); + cfg_is_updated = true; + } + if (C_NMEA_sensors.isUpdated()) + { + settings->nmea_s = atoi(C_NMEA_sensors.value()); + Serial.print(F("NMEA_sensors = ")); + Serial.println(settings->nmea_s); + cfg_is_updated = true; + } + if (C_NMEA_Output.isUpdated()) + { + settings->nmea_out = atoi(C_NMEA_Output.value()); + Serial.print(F("NMEA_Output = ")); + Serial.println(settings->nmea_out); + cfg_is_updated = true; + } + if (C_GDL90_Output.isUpdated()) + { + settings->gdl90 = atoi(C_GDL90_Output.value()); + Serial.print(F("GDL90_Output = ")); + Serial.println(settings->gdl90); + cfg_is_updated = true; + } + if (C_D1090_Output.isUpdated()) + { + settings->d1090 = atoi(C_D1090_Output.value()); + Serial.print(F("D1090_Output = ")); + Serial.println(settings->d1090); + cfg_is_updated = true; + } + if (C_Stealth.isUpdated()) + { + settings->stealth = atoi(C_Stealth.value()); + Serial.print(F("Stealth = ")); + Serial.println(settings->stealth); + cfg_is_updated = true; + } + if (C_noTrack.isUpdated()) + { + settings->no_track = atoi(C_noTrack.value()); + Serial.print(F("noTrack = ")); + Serial.println(settings->no_track); + cfg_is_updated = true; + } + if (C_PowerSave.isUpdated()) + { + settings->power_save = atoi(C_PowerSave.value()); + Serial.print(F("PowerSave = ")); + Serial.println(settings->power_save); + cfg_is_updated = true; + } + + if (cfg_is_updated) + { + SoC->WDT_fini(); + Serial.println(); + Serial.println(F("Restart is in progress. Please, wait...")); + Serial.println(); + Serial.flush(); + EEPROM_store(); + RF_Shutdown(); + SoC->reset(); + } + } + } +#endif /* USE_NMEA_CFG */ + } + if (GNSSbuf[GNSS_cnt] == '\n' || GNSS_cnt == sizeof(GNSSbuf) - 1) + GNSS_cnt = 0; + else + { + GNSS_cnt++; + yield(); + } + } +} + +#if !defined(EXCLUDE_EGM96) +/* + * Algorithm of EGM96 geoid offset approximation was taken from XCSoar + */ + +static float AsBearing(float angle) +{ + float retval = angle; + + while (retval < 0) { + retval += 360.0; + } + + while (retval >= 360.0) { + retval -= 360.0; + } + + return retval; +} + +int LookupSeparation(float lat, float lon) +{ + int ilat, ilon; + + ilat = round((90.0 - lat) / 2.0); + ilon = round(AsBearing(lon) / 2.0); + + int offset = ilat * 180 + ilon; + + if (offset >= egm96s_dem_len) + return 0; + + if (offset < 0) + return 0; + + return (int) pgm_read_byte(&egm96s_dem[offset]) - 127; +} + +#endif /* EXCLUDE_EGM96 */ diff --git a/ognbase/GNSS.h b/ognbase/GNSS.h index a9c3634..ebe8b4e 100644 --- a/ognbase/GNSS.h +++ b/ognbase/GNSS.h @@ -1,69 +1,69 @@ -/* - * GNSS.h - * Copyright (C) 2019-2020 Linar Yusupov - * - * 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 . - */ - -#ifndef GNSSHELPER_H -#define GNSSHELPER_H - -#include - -enum -{ - GNSS_MODULE_NONE, - GNSS_MODULE_NMEA, /* generic NMEA */ - GNSS_MODULE_U6, /* Ublox 6 */ - GNSS_MODULE_U7, /* Ublox 7 */ - GNSS_MODULE_U8, /* Ublox 8 */ - GNSS_MODULE_U9, /* reserved for Ublox 9 */ - GNSS_MODULE_MAV, /* MAVLink */ - GNSS_MODULE_S7XG /* S7XG */ -}; - -/* - * Both GGA and RMC NMEA sentences are required. - * No fix when any of them is missing or lost. - * Valid date is critical for legacy protocol (only). - */ -#define NMEA_EXP_TIME 3500 /* 3.5 seconds */ -#define isValidGNSSFix() (gnss.location.isValid() && \ - gnss.altitude.isValid() && \ - gnss.date.isValid() && \ - (gnss.location.age() <= NMEA_EXP_TIME) && \ - (gnss.altitude.age() <= NMEA_EXP_TIME) && \ - (gnss.date.age() <= NMEA_EXP_TIME)) - -byte GNSS_setup(void); - -void GNSS_loop(bool); - -void GNSS_fini(void); - -void GNSSTimeSync(void); - -void PickGNSSFix(void); - -int LookupSeparation(float, float); - -void GNSS_sleep(void); - -void GNSS_weakup(void); - -extern TinyGPSPlus gnss; -extern volatile unsigned long PPS_TimeMarker; -extern const char* GNSS_name[]; - -#endif /* GNSSHELPER_H */ +/* + * GNSS.h + * Copyright (C) 2019-2020 Linar Yusupov + * + * 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 . + */ + +#ifndef GNSSHELPER_H +#define GNSSHELPER_H + +#include + +enum +{ + GNSS_MODULE_NONE, + GNSS_MODULE_NMEA, /* generic NMEA */ + GNSS_MODULE_U6, /* Ublox 6 */ + GNSS_MODULE_U7, /* Ublox 7 */ + GNSS_MODULE_U8, /* Ublox 8 */ + GNSS_MODULE_U9, /* reserved for Ublox 9 */ + GNSS_MODULE_MAV, /* MAVLink */ + GNSS_MODULE_S7XG /* S7XG */ +}; + +/* + * Both GGA and RMC NMEA sentences are required. + * No fix when any of them is missing or lost. + * Valid date is critical for legacy protocol (only). + */ +#define NMEA_EXP_TIME 3500 /* 3.5 seconds */ +#define isValidGNSSFix() (gnss.location.isValid() && \ + gnss.altitude.isValid() && \ + gnss.date.isValid() && \ + (gnss.location.age() <= NMEA_EXP_TIME) && \ + (gnss.altitude.age() <= NMEA_EXP_TIME) && \ + (gnss.date.age() <= NMEA_EXP_TIME)) + +byte GNSS_setup(void); + +void GNSS_loop(bool); + +void GNSS_fini(void); + +void GNSSTimeSync(void); + +void PickGNSSFix(void); + +int LookupSeparation(float, float); + +void GNSS_sleep(void); + +void GNSS_weakup(void); + +extern TinyGPSPlus gnss; +extern volatile unsigned long PPS_TimeMarker; +extern const char* GNSS_name[]; + +#endif /* GNSSHELPER_H */ diff --git a/ognbase/JSON.cpp b/ognbase/JSON.cpp index 5eb84dc..63091dc 100644 --- a/ognbase/JSON.cpp +++ b/ognbase/JSON.cpp @@ -94,8 +94,8 @@ void JSON_Export() aircraft["horVelocityCMS"] = (unsigned long) (Container[i].speed * _GPS_MPS_PER_KNOT * 100); /* Vertical velocity in centimeters/sec with positive being up */ aircraft["verVelocityCMS"] = (long) (Container[i].vs * 100 / (_GPS_FEET_PER_METER * 60.0)); - aircraft["squawk"] = (settings->band == RF_BAND_US ? 1200 : 7000); // VFR Squawk code - aircraft["altitudeType"] = 1; // Altitude Source: 0 = Pressure 1 = Geometric + aircraft["squawk"] = (ogn_band == RF_BAND_US ? 1200 : 7000); // VFR Squawk code + aircraft["altitudeType"] = 1; // Altitude Source: 0 = Pressure 1 = Geometric memcpy(callsign, GDL90_CallSign_Prefix[Container[i].protocol], strlen(GDL90_CallSign_Prefix[Container[i].protocol])); memcpy(callsign + strlen(GDL90_CallSign_Prefix[Container[i].protocol]), @@ -739,7 +739,7 @@ void parseSettings(JsonObject& root) for (int i=0; i < MAX_TRACKING_OBJECTS; i++) if (memcmp(Container[i].raw, EmptyFO.raw, sizeof(EmptyFO.raw)) != 0) { - size_t size = RF_Payload_Size(settings->rf_protocol); + size_t size = RF_Payload_Size(ogn_protocol_1); size = size > sizeof(Container[i].raw) ? sizeof(Container[i].raw) : size; String str = Bin2Hex(Container[i].raw, size); printf("%s\n", str.c_str()); diff --git a/ognbase/JSON.h b/ognbase/JSON.h index ef48755..0bae94f 100644 --- a/ognbase/JSON.h +++ b/ognbase/JSON.h @@ -1,97 +1,97 @@ -/* - * JSON.h - * Copyright (C) 2018-2020 Linar Yusupov - * - * 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 . - */ - -#ifndef JSONHELPER_H -#define JSONHELPER_H - -#include - -#if defined(ARDUINO) -#include -#endif /* ARDUINO */ - -#if defined(RASPBERRY_PI) -#include -#endif /* RASPBERRY_PI */ - -#define JSON_BUFFER_SIZE 65536 -#define isValidGPSDFix() (hasValidGPSDFix) - -enum -{ - JSON_OFF, - JSON_PING -}; - -struct dump1090_aircraft_struct -{ - const char* hex; - const char* squawk; - const char* flight; - float lat; - float lon; - int nucp; - float seen_pos; - int altitude; // in feet - int vert_rate; // in feet/minute - int track; // degrees, 0-360 - int speed; // in knots - int messages; - float seen; - float rssi; -}; - -struct ping_aircraft_struct -{ - const char* icaoAddress; - int trafficSource; - float latDD; - float lonDD; - long altitudeMM; - int headingDE2; - int horVelocityCMS; - int verVelocityCMS; - int squawk; - int altitudeType; - const char* Callsign; - int emitterType; - int utcSync; - const char* timeStamp; -}; - -typedef struct dump1090_aircraft_struct dump1090_aircraft_t; -typedef struct ping_aircraft_struct ping_aircraft_t; - -extern StaticJsonDocument jsonBuffer; -extern bool hasValidGPSDFix; - -extern void JSON_Export(); - -extern void parseTPV(JsonObject&); - -extern void parseSettings(JsonObject&); - -extern void parseD1090(JsonObject&); - -extern void parsePING(JsonObject&); - -extern void parseRAW(JsonObject&); - -extern byte getVal(char); - -#endif /* JSONHELPER_H */ +/* + * JSON.h + * Copyright (C) 2018-2020 Linar Yusupov + * + * 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 . + */ + +#ifndef JSONHELPER_H +#define JSONHELPER_H + +#include + +#if defined(ARDUINO) +#include +#endif /* ARDUINO */ + +#if defined(RASPBERRY_PI) +#include +#endif /* RASPBERRY_PI */ + +#define JSON_BUFFER_SIZE 65536 +#define isValidGPSDFix() (hasValidGPSDFix) + +enum +{ + JSON_OFF, + JSON_PING +}; + +struct dump1090_aircraft_struct +{ + const char* hex; + const char* squawk; + const char* flight; + float lat; + float lon; + int nucp; + float seen_pos; + int altitude; // in feet + int vert_rate; // in feet/minute + int track; // degrees, 0-360 + int speed; // in knots + int messages; + float seen; + float rssi; +}; + +struct ping_aircraft_struct +{ + const char* icaoAddress; + int trafficSource; + float latDD; + float lonDD; + long altitudeMM; + int headingDE2; + int horVelocityCMS; + int verVelocityCMS; + int squawk; + int altitudeType; + const char* Callsign; + int emitterType; + int utcSync; + const char* timeStamp; +}; + +typedef struct dump1090_aircraft_struct dump1090_aircraft_t; +typedef struct ping_aircraft_struct ping_aircraft_t; + +extern StaticJsonDocument jsonBuffer; +extern bool hasValidGPSDFix; + +extern void JSON_Export(); + +extern void parseTPV(JsonObject&); + +extern void parseSettings(JsonObject&); + +extern void parseD1090(JsonObject&); + +extern void parsePING(JsonObject&); + +extern void parseRAW(JsonObject&); + +extern byte getVal(char); + +#endif /* JSONHELPER_H */ diff --git a/ognbase/Log.cpp b/ognbase/Log.cpp index 1b4a47a..bc5574b 100644 --- a/ognbase/Log.cpp +++ b/ognbase/Log.cpp @@ -1,101 +1,102 @@ -/* - * Log.cpp - * Copyright (C) 2019-2020 Linar Yusupov - * - * 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 . - */ - -#include "SoC.h" -#include "Log.h" -#include "EEPROM.h" - - -void Logger_send_udp(String* buf) -{ - if (settings->ogndebug) - { - int debug_len = buf->length() + 1; - byte debug_msg[debug_len]; - buf->getBytes(debug_msg, debug_len); - SoC->WiFi_transmit_UDP_debug(settings->ogndebugp, debug_msg, debug_len); - } -} - -#if LOGGER_IS_ENABLED - -#define LOGFILE "/Logfile.txt" - -File LogFile; -FSInfo fs_info; -FtpServer ftpSrv; //set #define FTP_DEBUG in ESP8266FtpServer.h to see ftp verbose on serial - -void Logger_setup() -{ - char LogFilename[] = LOGFILE; - - - if (SPIFFS.begin()) - { - Serial.println(F("SPIFFS volume is mounted successfully.")); - - SPIFFS.info(fs_info); - - Serial.println(); - Serial.print(F("Total bytes: ")); - Serial.println(fs_info.totalBytes); - Serial.print(F("Used bytes: ")); - Serial.println(fs_info.usedBytes); - Serial.print(F("Block size: ")); - Serial.println(fs_info.blockSize); - Serial.print(F("Page size: ")); - Serial.println(fs_info.pageSize); - - //if (SPIFFS.exists(LogFilename)) SPIFFS.remove(LogFilename); - - LogFile = SPIFFS.open(LogFilename, "a+"); - - if (!LogFile) - { - Serial.print(F("Unable to open log file: ")); - Serial.println(LogFilename); - } - else - { - LogFile.println(); - LogFile.println(F("******* Logging is restarted *******")); - LogFile.print(F("*** Storage free space: ")); - LogFile.print(fs_info.totalBytes - fs_info.usedBytes); - LogFile.println(F(" bytes ***")); - - //username, password for ftp. set ports in ESP8266FtpServer.h (default 21, 50009 for PASV) - ftpSrv.begin("softrf", "softrf"); - }; - } - else - Serial.println(F("ERROR: Unable to mount SPIFFS volume.")); - ; -} - -void Logger_loop() -{ - ftpSrv.handleFTP(); -} - -void Logger_fini() -{ - LogFile.close(); - SPIFFS.end(); -} - -#endif /* LOGGER_IS_ENABLED */ +/* + * Log.cpp + * Copyright (C) 2019-2020 Linar Yusupov + * + * 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 . + */ + +#include "SoC.h" +#include "Log.h" +#include "EEPROM.h" +#include "global.h" + + +void Logger_send_udp(String* buf) +{ + if (ogn_debug) + { + int debug_len = buf->length() + 1; + byte debug_msg[debug_len]; + buf->getBytes(debug_msg, debug_len); + SoC->WiFi_transmit_UDP_debug(ogn_debugport, debug_msg, debug_len); + } +} + +#if LOGGER_IS_ENABLED + +#define LOGFILE "/Logfile.txt" + +File LogFile; +FSInfo fs_info; +FtpServer ftpSrv; //set #define FTP_DEBUG in ESP8266FtpServer.h to see ftp verbose on serial + +void Logger_setup() +{ + char LogFilename[] = LOGFILE; + + + if (SPIFFS.begin()) + { + Serial.println(F("SPIFFS volume is mounted successfully.")); + + SPIFFS.info(fs_info); + + Serial.println(); + Serial.print(F("Total bytes: ")); + Serial.println(fs_info.totalBytes); + Serial.print(F("Used bytes: ")); + Serial.println(fs_info.usedBytes); + Serial.print(F("Block size: ")); + Serial.println(fs_info.blockSize); + Serial.print(F("Page size: ")); + Serial.println(fs_info.pageSize); + + //if (SPIFFS.exists(LogFilename)) SPIFFS.remove(LogFilename); + + LogFile = SPIFFS.open(LogFilename, "a+"); + + if (!LogFile) + { + Serial.print(F("Unable to open log file: ")); + Serial.println(LogFilename); + } + else + { + LogFile.println(); + LogFile.println(F("******* Logging is restarted *******")); + LogFile.print(F("*** Storage free space: ")); + LogFile.print(fs_info.totalBytes - fs_info.usedBytes); + LogFile.println(F(" bytes ***")); + + //username, password for ftp. set ports in ESP8266FtpServer.h (default 21, 50009 for PASV) + ftpSrv.begin("softrf", "softrf"); + }; + } + else + Serial.println(F("ERROR: Unable to mount SPIFFS volume.")); + ; +} + +void Logger_loop() +{ + ftpSrv.handleFTP(); +} + +void Logger_fini() +{ + LogFile.close(); + SPIFFS.end(); +} + +#endif /* LOGGER_IS_ENABLED */ diff --git a/ognbase/MAVLink.cpp b/ognbase/MAVLink.cpp index 8286154..d4d46bd 100644 --- a/ognbase/MAVLink.cpp +++ b/ognbase/MAVLink.cpp @@ -26,6 +26,7 @@ #include "Traffic.h" #include "EEPROM.h" #include "RF.h" +#include "global.h" static unsigned long MAVLinkTimeSyncMarker = 0; static bool MAVLinkAPisArmed = false; @@ -77,7 +78,7 @@ void MAVLinkShareTraffic() Container[i].course, Container[i].speed * _GPS_MPS_PER_KNOT, /* m/s */ Container[i].vs / (_GPS_FEET_PER_METER * 60.0), /* m/s */ - (settings->band == RF_BAND_US ? 1200 : 7000), + (ogn_band == RF_BAND_US ? 1200 : 7000), callsign, AT_TO_GDL90(Container[i].aircraft_type)); } diff --git a/ognbase/MONIT.cpp b/ognbase/MONIT.cpp index 5dd0bf2..daff4a5 100644 --- a/ognbase/MONIT.cpp +++ b/ognbase/MONIT.cpp @@ -29,58 +29,17 @@ WiFiClient zclient; -String zabbix_server; -int zabbix_port; -String zabbix_host; -bool config_status; - -static bool loadConfig() -{ - int line = 0; - - if (!SPIFFS.begin(true)) - return false; - - File configFile = SPIFFS.open("/zabbix.txt", "r"); - if (!configFile) - return false; - - while (configFile.available() && line < 7) - { - if (line == 0) - zabbix_server = configFile.readStringUntil('\n').c_str(); - if (line == 1) - zabbix_port = configFile.readStringUntil('\n').toInt(); - if (line == 2) - zabbix_host = configFile.readStringUntil('\n').c_str(); - line++; - } - - configFile.close(); - - if (line < 2) - return false; - - zabbix_server.trim(); - return true; -} - -static bool MONIT_setup() -{ - if (!config_status) - config_status = loadConfig(); - return config_status; -} +bool config_status; void MONIT_send_trap() { int timeout = 5; - if (MONIT_setup()) + if (zabbix_enable) { ZabbixSender zs; String jsonPayload; - jsonPayload = zs.createPayload(zabbix_host.c_str(), Battery_voltage(), RF_last_rssi, int(hours()), gnss.satellites.value(), ThisAircraft.timestamp, largest_range); + jsonPayload = zs.createPayload(zabbix_server.c_str(), Battery_voltage(), RF_last_rssi, int(hours()), gnss.satellites.value(), ThisAircraft.timestamp, largest_range); String msg = zs.createMessage(jsonPayload); diff --git a/ognbase/OLED.cpp b/ognbase/OLED.cpp index ea9e65a..5093a18 100644 --- a/ognbase/OLED.cpp +++ b/ognbase/OLED.cpp @@ -1,198 +1,292 @@ -/* - * OLED.cpp - * Copyright (C) 2019-2021 Linar Yusupov - * - * 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 . - */ - -#include "SoC.h" - -#include - -#include "OLED.h" -#include "EEPROM.h" -#include "RF.h" -#include "GNSS.h" -#include "Battery.h" -#include "Traffic.h" -#include "global.h" -#include "Web.h" -#include "version.h" - -SSD1306Wire display(SSD1306_OLED_I2C_ADDR, SDA, SCL); // ADDRESS, SDA, SCL -bool display_init = false; - -int rssi = 0; -int oled_site = 0; - -enum -{ - OLED_PAGE_RADIO, - OLED_PAGE_OTHER, - OLED_PAGE_COUNT -}; - -const char *OLED_Protocol_ID[] = { - [RF_PROTOCOL_LEGACY] = "L", - [RF_PROTOCOL_OGNTP] = "O", - [RF_PROTOCOL_P3I] = "P", - [RF_PROTOCOL_ADSB_1090] = "A", - [RF_PROTOCOL_ADSB_UAT] = "U", - [RF_PROTOCOL_FANET] = "F" -}; - -const char *ISO3166_CC[] = { - [RF_BAND_AUTO] = "--", - [RF_BAND_EU] = "EU", - [RF_BAND_US] = "US", - [RF_BAND_AU] = "AU", - [RF_BAND_NZ] = "NZ", - [RF_BAND_RU] = "RU", - [RF_BAND_CN] = "CN", - [RF_BAND_UK] = "UK", - [RF_BAND_IN] = "IN", - //[RF_BAND_IL] = "IL", - //[RF_BAND_KR] = "KR" -}; - -byte OLED_setup() { - display_init = display.init(); -} - -void OLED_write(char* text, short x, short y, bool clear) -{ - if(display_init){ - display.displayOn(); - if(clear){ - display.clear(); - } - display.drawString(x, y, text); - display.display(); - } - -} - -void OLED_clear() -{ - if(display_init){ - display.clear(); - } -} - -void OLED_info(bool ntp) -{ - char buf[20]; - uint32_t disp_value; - - - if (display_init) { - - display.displayOff(); - display.clear(); - - display.setFont(ArialMT_Plain_24); - display.drawString(85, 0, "RX"); - display.setFont(ArialMT_Plain_16); - snprintf (buf, sizeof(buf), "%d", rx_packets_counter); - display.drawString(85, 30, buf); - display.setFont(ArialMT_Plain_10); - - if(!oled_site){ - snprintf (buf, sizeof(buf), "ID: %06X", ThisAircraft.addr); - display.drawString(0, 0, buf); - - snprintf (buf, sizeof(buf), "SSID: %s", ogn_ssid); - display.drawString(0, 9, buf); - - snprintf (buf, sizeof(buf), "CS: %s", ogn_callsign); - display.drawString(0, 18, buf); - - snprintf (buf, sizeof(buf), "Band: %s", ISO3166_CC[settings->band]); - display.drawString(0, 27, buf); - - //OLED_Protocol_ID[ThisAircraft.protocol] - snprintf (buf, sizeof(buf), "Prot: %s", OLED_Protocol_ID[ThisAircraft.protocol]); - display.drawString(0, 36, buf); - - snprintf (buf, sizeof(buf), "UTC: %02d:%02d", hour(now()), minute(now())); - display.drawString(0, 45, buf); - - if(ntp){ - display.drawString(0, 54, "NTP: True"); - } - else{ - disp_value = gnss.satellites.value(); - itoa(disp_value, buf, 10); - snprintf (buf, sizeof(buf), "GNSS: %s", buf); - display.drawString(0, 54, buf); - } - - disp_value = settings->range; - itoa(disp_value, buf, 10); - snprintf (buf, sizeof(buf), "Range: %s", buf); - display.drawString(0, 63, buf); - oled_site = 1; - display.display(); - display.displayOn(); - return; - } - if(oled_site == 1){ - - disp_value = RF_last_rssi; - snprintf (buf, sizeof(buf), "RSSI: %d", disp_value); - display.drawString(0, 0, buf); - - //ogndebug - disp_value = settings->ogndebug; - snprintf (buf, sizeof(buf), "Debug: %d", disp_value); - display.drawString(0, 9, buf); - - //ogndebugp - disp_value = settings->ogndebugp; - snprintf (buf, sizeof(buf), "DebugP: %d", disp_value); - display.drawString(0, 18, buf); - - //bool ignore_stealth; - disp_value = settings->ignore_stealth; - snprintf (buf, sizeof(buf), "IStealth: %d", disp_value); - display.drawString(0, 27, buf); - - - //bool ignore_no_track; - disp_value = settings->ignore_no_track; - snprintf (buf, sizeof(buf), "ITrack: %d", disp_value); - display.drawString(0, 36, buf); - - - //zabbix_en - disp_value = settings->zabbix_en; - snprintf (buf, sizeof(buf), "Zabbix: %d", disp_value); - display.drawString(0, 45, buf); - - //version - snprintf (buf, sizeof(buf), "Version: %s", _VERSION); - display.drawString(0, 54, buf); - - - display.display(); - oled_site = 0; - display.displayOn(); - return; - } - } -} - -void OLED_status(){ - -} +/* + * OLED.cpp + * Copyright (C) 2019-2021 Linar Yusupov + * + * 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 . + */ + +#include "SoC.h" + +#include + +#include "OLED.h" +#include "EEPROM.h" +#include "RF.h" +#include "GNSS.h" +#include "Battery.h" +#include "Traffic.h" +#include "global.h" +#include "Web.h" +#include "version.h" +#include "logos.h" + +SSD1306Wire display(SSD1306_OLED_I2C_ADDR, SDA, SCL); // ADDRESS, SDA, SCL +bool display_init = false; + +int rssi = 0; +int oled_site = 0; + +enum +{ + OLED_PAGE_RADIO, + OLED_PAGE_OTHER, + OLED_PAGE_COUNT +}; + +const char* OLED_Protocol_ID[] = { + [RF_PROTOCOL_LEGACY] = "L", + [RF_PROTOCOL_OGNTP] = "O", + [RF_PROTOCOL_P3I] = "P", + [RF_PROTOCOL_ADSB_1090] = "A", + [RF_PROTOCOL_ADSB_UAT] = "U", + [RF_PROTOCOL_FANET] = "F" +}; + +const char* ISO3166_CC[] = { + [RF_BAND_AUTO] = "--", + [RF_BAND_EU] = "EU", + [RF_BAND_US] = "US", + [RF_BAND_AU] = "AU", + [RF_BAND_NZ] = "NZ", + [RF_BAND_RU] = "RU", + [RF_BAND_CN] = "CN", + [RF_BAND_UK] = "UK", + [RF_BAND_IN] = "IN", + //[RF_BAND_IL] = "IL", + //[RF_BAND_KR] = "KR" +}; + +byte OLED_setup() +{ + display_init = display.init(); + display.flipScreenVertically(); +} + +void OLED_write(char* text, short x, short y, bool clear) +{ + if (display_init) + { + display.displayOn(); + if (clear) + display.clear(); + display.drawString(x, y, text); + display.display(); + } +} + +void OLED_clear() +{ + if (display_init) + display.clear(); +} + +void OLED_draw_Bitmap(int16_t x, int16_t y, uint8_t bm, bool clear) +{ + display.displayOn(); + if (clear) + display.clear(); + if (bm == 1) + display.drawXbm(x, y, 50, 28, wifi_50_28); + if (bm == 2) + // fanet_export_75_75 + display.drawXbm(x, y, 100, 63, fanet_export_100_63); + if (bm == 3) //network network_50_44 + display.drawXbm(x, y, 50, 44, network_50_44); + if (bm == 100) + // supporter_50_64 + display.drawXbm(x, y, 50, 64, supporter_50_64); + display.display(); +} + +void OLED_info(bool ntp) +{ + char buf[64]; + uint32_t disp_value; + + int bars = 0; + int32_t RSSI; + + RSSI = WiFi.RSSI(); + + if (RSSI > -55) + bars = 5; + else if (RSSI < -55 & RSSI > -65) + bars = 4; + else if (RSSI < -65 & RSSI > -70) + bars = 3; + else if (RSSI < -70 & RSSI > -78) + bars = 2; + else if (RSSI < -78 & RSSI > -82) + bars = 1; + else + bars = 0; + + + if (display_init) + { + display.displayOff(); + display.clear(); + + + for (int b=0; b <= bars; b++) + display.fillRect(100 + (b * 5), 65 - (b * 3), 3, b * 3); + + display.setFont(ArialMT_Plain_24); + display.drawString(95, 0, "RX"); + display.setFont(ArialMT_Plain_16); + snprintf(buf, sizeof(buf), "%d", rx_packets_counter); + display.drawString(100, 28, buf); + display.setFont(ArialMT_Plain_10); + + + if (!oled_site) + { + snprintf(buf, sizeof(buf), "ID: %06X", ThisAircraft.addr); + display.drawString(0, 0, buf); + + snprintf(buf, sizeof(buf), "SSID: %s", WiFi.SSID()); + display.drawString(0, 9, buf); + + snprintf(buf, sizeof(buf), "CS: %s", ogn_callsign); + display.drawString(0, 18, buf); + + snprintf(buf, sizeof(buf), "Band: %s", ISO3166_CC[ogn_band]); + display.drawString(0, 27, buf); + + //OLED_Protocol_ID[ThisAircraft.protocol] + snprintf(buf, sizeof(buf), "Prot: %s", OLED_Protocol_ID[ThisAircraft.protocol]); + display.drawString(0, 36, buf); + + snprintf(buf, sizeof(buf), "UTC: %02d:%02d", hour(now()), minute(now())); + display.drawString(0, 45, buf); + + if (ntp) + display.drawString(0, 54, "NTP: True"); + else + { + disp_value = gnss.satellites.value(); + itoa(disp_value, buf, 10); + snprintf(buf, sizeof(buf), "GNSS: %s", buf); + display.drawString(0, 54, buf); + } + /* + disp_value = settings->range; + itoa(disp_value, buf, 10); + snprintf (buf, sizeof(buf), "Range: %s", buf); + display.drawString(0, 63, buf); + */ + oled_site = 1; + display.display(); + display.displayOn(); + return; + } + if (oled_site == 1) + { + disp_value = RF_last_rssi; + snprintf(buf, sizeof(buf), "RSSI: %d", disp_value); + display.drawString(0, 0, buf); + + //ogndebug + disp_value = ogn_debug; + snprintf(buf, sizeof(buf), "Debug: %d", disp_value); + display.drawString(0, 9, buf); + + //ogndebugp + disp_value = ogn_debug; + snprintf(buf, sizeof(buf), "DebugP: %d", disp_value); + display.drawString(0, 18, buf); + + //bool ignore_stealth; + disp_value = ogn_istealthbit; + snprintf(buf, sizeof(buf), "IStealth: %d", disp_value); + display.drawString(0, 27, buf); + + + //bool ignore_no_track; + disp_value = ogn_itrackbit; + snprintf(buf, sizeof(buf), "ITrack: %d", disp_value); + display.drawString(0, 36, buf); + + + //zabbix_en + disp_value = zabbix_enable; + snprintf(buf, sizeof(buf), "Zabbix: %d", disp_value); + display.drawString(0, 45, buf); + + //version + snprintf(buf, sizeof(buf), "Version: %s", _VERSION); + display.drawString(0, 54, buf); + + + display.display(); + oled_site = 2; + display.displayOn(); + return; + } + + if (oled_site == 2) + { + display.clear(); + snprintf(buf, sizeof(buf), "SSID List"); + display.drawString(0, 0, buf); + + for (int i=0; i < 5; i++) + if (ogn_ssid[i] != "") + { + snprintf(buf, sizeof(buf), "%s", ogn_ssid[i].c_str()); + Serial.println(buf); + display.drawString(0, (i + 1) * 9, buf); + } + + for (int b=0; b <= bars; b++) + display.fillRect(100 + (b * 5), 40 - (b * 6), 3, b * 6); + + snprintf(buf, sizeof(buf), "connected to %s", WiFi.SSID()); + display.drawString(0, 54, buf); + + display.display(); + if (beers_show) + oled_site = 3; + else + oled_site = 0; + display.displayOn(); + return; + } + + + if (oled_site == 3) + { + String beer_supporters[] = {"guy", "jozef", "camille"}; + display.clear(); + snprintf(buf, sizeof(buf), "Bier supporters"); + display.drawString(0, 0, buf); + for (int i=0; i < sizeof(beer_supporters); i++) { + snprintf(buf, sizeof(buf), "%s", beer_supporters[i]); + display.drawString(0, (i + 1) * 9, buf); + } + + snprintf(buf, sizeof(buf), "many thanks !!"); + display.drawString(0, 52, buf); + + OLED_draw_Bitmap(75, 0, 100, false); + display.display(); + oled_site = 0; + display.displayOn(); + return; + } + } +} + +void OLED_status() +{} diff --git a/ognbase/OLED.h b/ognbase/OLED.h index 7f38db9..57fc7ce 100644 --- a/ognbase/OLED.h +++ b/ognbase/OLED.h @@ -1,33 +1,39 @@ -/* - * OLEDHelper.h - * Copyright (C) 2019-2021 Linar Yusupov - * - * 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 . - */ - -#ifndef OLEDHELPER_H -#define OLEDHELPER_H - -#include "SSD1306Wire.h" - -#define SSD1306_OLED_I2C_ADDR 0x3C - -byte OLED_setup(void); -void OLED_write(char*, short, short, bool); -void OLED_clear(void); -void OLED_bar(uint8_t, uint8_t); -void OLED_info(bool); -void OLED_update(void); - -#endif /* OLEDHELPER_H */ +/* + * OLEDHelper.h + * Copyright (C) 2019-2021 Linar Yusupov + * + * 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 . + */ + +#ifndef OLEDHELPER_H +#define OLEDHELPER_H + +#include "SSD1306Wire.h" + +#define SSD1306_OLED_I2C_ADDR 0x3C + +byte OLED_setup(void); + +void OLED_write(char *, short, short, bool); + +void OLED_clear(void); + +void OLED_bar(uint8_t, uint8_t); +void OLED_info(bool); + +void OLED_update(void); + +void OLED_draw_Bitmap(int16_t, int16_t, uint8_t, bool); + +#endif /* OLEDHELPER_H */ diff --git a/ognbase/Platform_ESP32.cpp b/ognbase/Platform_ESP32.cpp index 3aa4be6..45eff49 100644 --- a/ognbase/Platform_ESP32.cpp +++ b/ognbase/Platform_ESP32.cpp @@ -1,1326 +1,1327 @@ -/* - * Platform_ESP32.cpp - * Copyright (C) 2018-2020 Linar Yusupov - * - * 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 . - */ -#if defined(ESP32) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Platform_ESP32.h" -#include "SoC.h" - -#include "EEPROM.h" -#include "RF.h" -#include "WiFi.h" -#include "Bluetooth.h" - -#include "Log.h" -#include - -#include "Battery.h" - -#include -#include - -// RFM95W pin mapping -lmic_pinmap lmic_pins = { - .nss = SOC_GPIO_PIN_SS, - .txe = LMIC_UNUSED_PIN, - .rxe = LMIC_UNUSED_PIN, - .rst = SOC_GPIO_PIN_RST, - .dio = {LMIC_UNUSED_PIN, LMIC_UNUSED_PIN, LMIC_UNUSED_PIN}, - .busy = SOC_GPIO_PIN_TXE, - .tcxo = LMIC_UNUSED_PIN, -}; - -WebServer server(80); - -U8X8_SSD1306_128X64_NONAME_2ND_HW_I2C u8x8_ttgo(TTGO_V2_OLED_PIN_RST, - TTGO_V2_OLED_PIN_SCL, - TTGO_V2_OLED_PIN_SDA); - -U8X8_SSD1306_128X64_NONAME_2ND_HW_I2C u8x8_heltec(HELTEC_OLED_PIN_RST, - HELTEC_OLED_PIN_SCL, - HELTEC_OLED_PIN_SDA); - -AXP20X_Class axp; -WiFiClient client; - -static U8X8_SSD1306_128X64_NONAME_2ND_HW_I2C* u8x8 = NULL; -static TFT_eSPI* tft = NULL; - -static int esp32_board = ESP32_DEVKIT; /* default */ - -static portMUX_TYPE GNSS_PPS_mutex = portMUX_INITIALIZER_UNLOCKED; -static portMUX_TYPE PMU_mutex = portMUX_INITIALIZER_UNLOCKED; -volatile bool PMU_Irq = false; - -static bool GPIO_21_22_are_busy = false; - -static union -{ - uint8_t efuse_mac[6]; - uint64_t chipmacid; -}; - -static bool OLED_display_probe_status = false; -static bool OLED_display_frontpage = false; -static uint32_t prev_tx_packets_counter = 0; -static uint32_t prev_rx_packets_counter = 0; -extern uint32_t tx_packets_counter, rx_packets_counter; -extern bool loopTaskWDTEnabled; - -/*const char* OLED_Protocol_ID[] = { - [RF_PROTOCOL_LEGACY] = "L", - [RF_PROTOCOL_OGNTP] = "O", - [RF_PROTOCOL_P3I] = "P", - [RF_PROTOCOL_ADSB_1090] = "A", - [RF_PROTOCOL_ADSB_UAT] = "U", - [RF_PROTOCOL_FANET] = "F" -};*/ - -const char SoftRF_text[] = "SoftRF"; -const char ID_text[] = "ID"; -const char PROTOCOL_text[] = "PROTOCOL"; -const char RX_text[] = "RX"; -const char TX_text[] = "TX"; - -static void IRAM_ATTR ESP32_PMU_Interrupt_handler() -{ - portENTER_CRITICAL_ISR(&PMU_mutex); - PMU_Irq = true; - portEXIT_CRITICAL_ISR(&PMU_mutex); -} - -static uint32_t ESP32_getFlashId() -{ - return g_rom_flashchip.device_id; -} - -static void ESP32_setup() -{ -#if !defined(SOFTRF_ADDRESS) - - esp_err_t ret = ESP_OK; - uint8_t null_mac[6] = {0}; - - ret = esp_efuse_mac_get_custom(efuse_mac); - if (ret != ESP_OK) - { - ESP_LOGE(TAG, "Get base MAC address from BLK3 of EFUSE error (%s)", esp_err_to_name(ret)); - /* If get custom base MAC address error, the application developer can decide what to do: - * abort or use the default base MAC address which is stored in BLK0 of EFUSE by doing - * nothing. - */ - - ESP_LOGI(TAG, "Use base MAC address which is stored in BLK0 of EFUSE"); - chipmacid = ESP.getEfuseMac(); - } - else if (memcmp(efuse_mac, null_mac, 6) == 0) - { - ESP_LOGI(TAG, "Use base MAC address which is stored in BLK0 of EFUSE"); - chipmacid = ESP.getEfuseMac(); - } -#endif /* SOFTRF_ADDRESS */ - -#if ESP32_DISABLE_BROWNOUT_DETECTOR - WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); -#endif - - if (psramFound()) - { - uint32_t flash_id = ESP32_getFlashId(); - - /* - * Board | Module | Flash memory IC - * ----------------+------------+-------------------- - * DoIt ESP32 | WROOM | GIGADEVICE_GD25Q32 - * TTGO T3 V2.0 | PICO-D4 IC | GIGADEVICE_GD25Q32 - * TTGO T3 V2.1.6 | PICO-D4 IC | GIGADEVICE_GD25Q32 - * TTGO T22 V06 | | WINBOND_NEX_W25Q32_V - * TTGO T22 V08 | | WINBOND_NEX_W25Q32_V - * TTGO T22 V11 | | BOYA_BY25Q32AL - * TTGO T8 V1.8 | WROVER | GIGADEVICE_GD25LQ32 - * TTGO T5S V1.9 | | WINBOND_NEX_W25Q32_V - * TTGO T5S V2.8 | | BOYA_BY25Q32AL - * TTGO T-Watch | | WINBOND_NEX_W25Q128_V - */ - - switch (flash_id) - { - case MakeFlashId(GIGADEVICE_ID, GIGADEVICE_GD25LQ32): - /* ESP32-WROVER module with ESP32-NODEMCU-ADAPTER */ - hw_info.model = SOFTRF_MODEL_STANDALONE; - break; - case MakeFlashId(WINBOND_NEX_ID, WINBOND_NEX_W25Q128_V): - hw_info.model = SOFTRF_MODEL_SKYWATCH; - break; - case MakeFlashId(WINBOND_NEX_ID, WINBOND_NEX_W25Q32_V): - case MakeFlashId(BOYA_ID, BOYA_BY25Q32AL): - default: - hw_info.model = SOFTRF_MODEL_PRIME_MK2; - break; - } - } - else - { - uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG); - uint32_t pkg_ver = chip_ver & 0x7; - if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) - { - esp32_board = ESP32_TTGO_V2_OLED; - lmic_pins.rst = SOC_GPIO_PIN_TBEAM_RF_RST_V05; - lmic_pins.busy = SOC_GPIO_PIN_TBEAM_RF_BUSY_V08; - } - } - - ledcSetup(LEDC_CHANNEL_BUZZER, 0, LEDC_RESOLUTION_BUZZER); - - if (hw_info.model == SOFTRF_MODEL_SKYWATCH) - { - esp32_board = ESP32_TTGO_T_WATCH; - - Wire1.begin(SOC_GPIO_PIN_TWATCH_SEN_SDA, SOC_GPIO_PIN_TWATCH_SEN_SCL); - Wire1.beginTransmission(AXP202_SLAVE_ADDRESS); - if (Wire1.endTransmission() == 0) - { - axp.begin(Wire1, AXP202_SLAVE_ADDRESS); - - axp.enableIRQ(AXP202_ALL_IRQ, AXP202_OFF); - axp.adc1Enable(0xFF, AXP202_OFF); - - axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL); - - axp.setPowerOutPut(AXP202_LDO2, AXP202_ON); // BL - axp.setPowerOutPut(AXP202_LDO3, AXP202_ON); // S76G (MCU + LoRa) - axp.setLDO4Voltage(AXP202_LDO4_1800MV); - axp.setPowerOutPut(AXP202_LDO4, AXP202_ON); // S76G (Sony GNSS) - - pinMode(SOC_GPIO_PIN_TWATCH_PMU_IRQ, INPUT_PULLUP); - - attachInterrupt(digitalPinToInterrupt(SOC_GPIO_PIN_TWATCH_PMU_IRQ), - ESP32_PMU_Interrupt_handler, FALLING); - - axp.adc1Enable(AXP202_BATT_VOL_ADC1, AXP202_ON); - axp.enableIRQ(AXP202_PEK_LONGPRESS_IRQ | AXP202_PEK_SHORTPRESS_IRQ, true); - axp.clearIRQ(); - } - } - else if (hw_info.model == SOFTRF_MODEL_PRIME_MK2) - { - esp32_board = ESP32_TTGO_T_BEAM; - - Wire1.begin(TTGO_V2_OLED_PIN_SDA, TTGO_V2_OLED_PIN_SCL); - Wire1.beginTransmission(AXP192_SLAVE_ADDRESS); - if (Wire1.endTransmission() == 0) - { - hw_info.revision = 8; - - axp.begin(Wire1, AXP192_SLAVE_ADDRESS); - - axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL); - - axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); - axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); - axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON); - axp.setPowerOutPut(AXP192_DCDC2, AXP202_ON); // NC - axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON); - - axp.setDCDC1Voltage(3300); // AXP192 power-on value: 3300 - axp.setLDO2Voltage(3300); // LoRa, AXP192 power-on value: 3300 - axp.setLDO3Voltage(3000); // GPS, AXP192 power-on value: 2800 - - pinMode(SOC_GPIO_PIN_TBEAM_V08_PMU_IRQ, INPUT_PULLUP); - - attachInterrupt(digitalPinToInterrupt(SOC_GPIO_PIN_TBEAM_V08_PMU_IRQ), - ESP32_PMU_Interrupt_handler, FALLING); - - axp.enableIRQ(AXP202_PEK_LONGPRESS_IRQ | AXP202_PEK_SHORTPRESS_IRQ, true); - axp.clearIRQ(); - } - else - hw_info.revision = 2; - lmic_pins.rst = SOC_GPIO_PIN_TBEAM_RF_RST_V05; - lmic_pins.busy = SOC_GPIO_PIN_TBEAM_RF_BUSY_V08; - } -} - -static void ESP32_loop() -{ - if ((hw_info.model == SOFTRF_MODEL_PRIME_MK2 && - hw_info.revision == 8) || - hw_info.model == SOFTRF_MODEL_SKYWATCH) - { - bool is_irq = false; - bool down = false; - - portENTER_CRITICAL_ISR(&PMU_mutex); - is_irq = PMU_Irq; - portEXIT_CRITICAL_ISR(&PMU_mutex); - - if (is_irq) - { - if (axp.readIRQ() == AXP_PASS) - { - if (axp.isPEKLongtPressIRQ()) - { - down = true; -#if 0 - Serial.println(F("Longt Press IRQ")); - Serial.flush(); -#endif - } - if (axp.isPEKShortPressIRQ()) - { -#if 0 - Serial.println(F("Short Press IRQ")); - Serial.flush(); -#endif - } - - axp.clearIRQ(); - } - - portENTER_CRITICAL_ISR(&PMU_mutex); - PMU_Irq = false; - portEXIT_CRITICAL_ISR(&PMU_mutex); - - if (down) - shutdown(" OFF "); - } - - if (isTimeToBattery()) - { - if (Battery_voltage() > Battery_threshold()) - axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL); - else - axp.setChgLEDMode(AXP20X_LED_BLINK_1HZ); - } - } -} - -static void ESP32_fini() -{ - SPI.end(); - - esp_wifi_stop(); - esp_bt_controller_disable(); - - if (hw_info.model == SOFTRF_MODEL_SKYWATCH) - { - axp.setChgLEDMode(AXP20X_LED_OFF); - - axp.setPowerOutPut(AXP202_LDO2, AXP202_OFF); // BL - axp.setPowerOutPut(AXP202_LDO4, AXP202_OFF); // S76G (Sony GNSS) - axp.setPowerOutPut(AXP202_LDO3, AXP202_OFF); // S76G (MCU + LoRa) - - delay(20); - - esp_sleep_enable_ext0_wakeup((gpio_num_t) SOC_GPIO_PIN_TWATCH_PMU_IRQ, 0); // 1 = High, 0 = Low - } - else if (hw_info.model == SOFTRF_MODEL_PRIME_MK2 && - hw_info.revision == 8) - { - axp.setChgLEDMode(AXP20X_LED_OFF); - - delay(2000); /* Keep 'OFF' message on OLED for 2 seconds */ - - axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); - axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF); - axp.setPowerOutPut(AXP192_DCDC2, AXP202_OFF); - axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); - axp.setPowerOutPut(AXP192_EXTEN, AXP202_OFF); - - delay(20); - - esp_sleep_enable_ext0_wakeup((gpio_num_t) SOC_GPIO_PIN_TBEAM_V08_PMU_IRQ, 0); // 1 = High, 0 = Low - } - - esp_deep_sleep_start(); -} - -static void ESP32_reset() -{ - ESP.restart(); -} - -static uint32_t ESP32_getChipId() -{ -#if !defined(SOFTRF_ADDRESS) - uint32_t id = (uint32_t) efuse_mac[5] | ((uint32_t) efuse_mac[4] << 8) | \ - ((uint32_t) efuse_mac[3] << 16) | ((uint32_t) efuse_mac[2] << 24); - - /* remap address to avoid overlapping with congested FLARM range */ - if (((id & 0x00FFFFFF) >= 0xDD0000) && ((id & 0x00FFFFFF) <= 0xDFFFFF)) - id += 0x100000; - - return id; -#else - return SOFTRF_ADDRESS & 0xFFFFFFFFU; -#endif /* SOFTRF_ADDRESS */ -} - -static struct rst_info reset_info = { - .reason = REASON_DEFAULT_RST, -}; - -static void * ESP32_getResetInfoPtr() -{ - switch (rtc_get_reset_reason(0)) - { - case POWERON_RESET: - reset_info.reason = REASON_DEFAULT_RST; - break; - case SW_RESET: - reset_info.reason = REASON_SOFT_RESTART; - break; - case OWDT_RESET: - reset_info.reason = REASON_WDT_RST; - break; - case DEEPSLEEP_RESET: - reset_info.reason = REASON_DEEP_SLEEP_AWAKE; - break; - case SDIO_RESET: - reset_info.reason = REASON_EXCEPTION_RST; - break; - case TG0WDT_SYS_RESET: - reset_info.reason = REASON_WDT_RST; - break; - case TG1WDT_SYS_RESET: - reset_info.reason = REASON_WDT_RST; - break; - case RTCWDT_SYS_RESET: - reset_info.reason = REASON_WDT_RST; - break; - case INTRUSION_RESET: - reset_info.reason = REASON_EXCEPTION_RST; - break; - case TGWDT_CPU_RESET: - reset_info.reason = REASON_WDT_RST; - break; - case SW_CPU_RESET: - reset_info.reason = REASON_SOFT_RESTART; - break; - case RTCWDT_CPU_RESET: - reset_info.reason = REASON_WDT_RST; - break; - case EXT_CPU_RESET: - reset_info.reason = REASON_EXT_SYS_RST; - break; - case RTCWDT_BROWN_OUT_RESET: - reset_info.reason = REASON_EXT_SYS_RST; - break; - case RTCWDT_RTC_RESET: - /* Slow start of GD25LQ32 causes one read fault at boot time with current ESP-IDF */ - if (ESP32_getFlashId() == MakeFlashId(GIGADEVICE_ID, GIGADEVICE_GD25LQ32)) - reset_info.reason = REASON_DEFAULT_RST; - else - reset_info.reason = REASON_WDT_RST; - break; - default: - reset_info.reason = REASON_DEFAULT_RST; - } - - return (void *) &reset_info; -} - -static String ESP32_getResetInfo() -{ - switch (rtc_get_reset_reason(0)) - { - case POWERON_RESET: - return F("Vbat power on reset"); - case SW_RESET: - return F("Software reset digital core"); - case OWDT_RESET: - return F("Legacy watch dog reset digital core"); - case DEEPSLEEP_RESET: - return F("Deep Sleep reset digital core"); - case SDIO_RESET: - return F("Reset by SLC module, reset digital core"); - case TG0WDT_SYS_RESET: - return F("Timer Group0 Watch dog reset digital core"); - case TG1WDT_SYS_RESET: - return F("Timer Group1 Watch dog reset digital core"); - case RTCWDT_SYS_RESET: - return F("RTC Watch dog Reset digital core"); - case INTRUSION_RESET: - return F("Instrusion tested to reset CPU"); - case TGWDT_CPU_RESET: - return F("Time Group reset CPU"); - case SW_CPU_RESET: - return F("Software reset CPU"); - case RTCWDT_CPU_RESET: - return F("RTC Watch dog Reset CPU"); - case EXT_CPU_RESET: - return F("for APP CPU, reseted by PRO CPU"); - case RTCWDT_BROWN_OUT_RESET: - return F("Reset when the vdd voltage is not stable"); - case RTCWDT_RTC_RESET: - return F("RTC Watch dog reset digital core and rtc module"); - default: - return F("No reset information available"); - } -} - -static String ESP32_getResetReason() -{ - switch (rtc_get_reset_reason(0)) - { - case POWERON_RESET: - return F("POWERON_RESET"); - case SW_RESET: - return F("SW_RESET"); - case OWDT_RESET: - return F("OWDT_RESET"); - case DEEPSLEEP_RESET: - return F("DEEPSLEEP_RESET"); - case SDIO_RESET: - return F("SDIO_RESET"); - case TG0WDT_SYS_RESET: - return F("TG0WDT_SYS_RESET"); - case TG1WDT_SYS_RESET: - return F("TG1WDT_SYS_RESET"); - case RTCWDT_SYS_RESET: - return F("RTCWDT_SYS_RESET"); - case INTRUSION_RESET: - return F("INTRUSION_RESET"); - case TGWDT_CPU_RESET: - return F("TGWDT_CPU_RESET"); - case SW_CPU_RESET: - return F("SW_CPU_RESET"); - case RTCWDT_CPU_RESET: - return F("RTCWDT_CPU_RESET"); - case EXT_CPU_RESET: - return F("EXT_CPU_RESET"); - case RTCWDT_BROWN_OUT_RESET: - return F("RTCWDT_BROWN_OUT_RESET"); - case RTCWDT_RTC_RESET: - return F("RTCWDT_RTC_RESET"); - default: - return F("NO_MEAN"); - } -} - -static uint32_t ESP32_getFreeHeap() -{ - return ESP.getFreeHeap(); -} - -static long ESP32_random(long howsmall, long howBig) -{ - return random(howsmall, howBig); -} - -/*static void ESP32_Sound_test(int var) - { - if (settings->volume != BUZZER_OFF) { - - ledcAttachPin(SOC_GPIO_PIN_BUZZER, LEDC_CHANNEL_BUZZER); - - ledcWrite(LEDC_CHANNEL_BUZZER, 125); // high volume - - if (var == REASON_DEFAULT_RST || - var == REASON_EXT_SYS_RST || - var == REASON_SOFT_RESTART) { - ledcWriteTone(LEDC_CHANNEL_BUZZER, 440);delay(500); - ledcWriteTone(LEDC_CHANNEL_BUZZER, 640);delay(500); - ledcWriteTone(LEDC_CHANNEL_BUZZER, 840);delay(500); - ledcWriteTone(LEDC_CHANNEL_BUZZER, 1040); - } else if (var == REASON_WDT_RST) { - ledcWriteTone(LEDC_CHANNEL_BUZZER, 440);delay(500); - ledcWriteTone(LEDC_CHANNEL_BUZZER, 1040);delay(500); - ledcWriteTone(LEDC_CHANNEL_BUZZER, 440);delay(500); - ledcWriteTone(LEDC_CHANNEL_BUZZER, 1040); - } else { - ledcWriteTone(LEDC_CHANNEL_BUZZER, 1040);delay(500); - ledcWriteTone(LEDC_CHANNEL_BUZZER, 840);delay(500); - ledcWriteTone(LEDC_CHANNEL_BUZZER, 640);delay(500); - ledcWriteTone(LEDC_CHANNEL_BUZZER, 440); - } - delay(600); - - ledcWriteTone(LEDC_CHANNEL_BUZZER, 0); // off - - ledcDetachPin(SOC_GPIO_PIN_BUZZER); - pinMode(SOC_GPIO_PIN_BUZZER, INPUT_PULLDOWN); - } - }*/ - -static uint32_t ESP32_maxSketchSpace() -{ - return 0x1E0000; -} - -static const int8_t ESP32_dB_to_power_level[21] = { - 8, /* 2 dB, #0 */ - 8, /* 2 dB, #1 */ - 8, /* 2 dB, #2 */ - 8, /* 2 dB, #3 */ - 8, /* 2 dB, #4 */ - 20, /* 5 dB, #5 */ - 20, /* 5 dB, #6 */ - 28, /* 7 dB, #7 */ - 28, /* 7 dB, #8 */ - 34, /* 8.5 dB, #9 */ - 34, /* 8.5 dB, #10 */ - 44, /* 11 dB, #11 */ - 44, /* 11 dB, #12 */ - 52, /* 13 dB, #13 */ - 52, /* 13 dB, #14 */ - 60, /* 15 dB, #15 */ - 60, /* 15 dB, #16 */ - 68, /* 17 dB, #17 */ - 74, /* 18.5 dB, #18 */ - 76, /* 19 dB, #19 */ - 78 /* 19.5 dB, #20 */ -}; - -static void ESP32_WiFi_setOutputPower(int dB) -{ - if (dB > 20) - dB = 20; - - if (dB < 0) - dB = 0; - - ESP_ERROR_CHECK(esp_wifi_set_max_tx_power(ESP32_dB_to_power_level[dB])); -} - -static IPAddress ESP32_WiFi_get_broadcast() -{ - tcpip_adapter_ip_info_t info; - IPAddress broadcastIp; - - if (WiFi.getMode() == WIFI_STA) - tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &info); - else - tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &info); - broadcastIp = ~info.netmask.addr | info.ip.addr; - - return broadcastIp; -} - -static void ESP32_WiFi_transmit_UDP_debug(int port, byte* buf, size_t size) -{ - IPAddress ClientIP; - unsigned int localPort = 8888; - - WiFiMode_t mode = WiFi.getMode(); - int i = 0; - - switch (mode) - { - case WIFI_STA: - ClientIP = WiFi.gatewayIP(); - ClientIP[3] = 200; - Uni_Udp.begin(localPort); - Uni_Udp.beginPacket(ClientIP, port); - Uni_Udp.write(buf, size); - Uni_Udp.endPacket(); - - ClientIP[3] = 199; - Uni_Udp.begin(localPort); - Uni_Udp.beginPacket(ClientIP, port); - Uni_Udp.write(buf, size); - Uni_Udp.endPacket(); - - break; - case WIFI_AP: - break; - case WIFI_OFF: - default: - break; - } -} - -static void ESP32_WiFi_transmit_UDP(int port, byte* buf, size_t size) -{ - IPAddress ClientIP; - WiFiMode_t mode = WiFi.getMode(); - int i = 0; - - switch (mode) - { - case WIFI_STA: - ClientIP = ESP32_WiFi_get_broadcast(); - - Uni_Udp.beginPacket(ClientIP, port); - Uni_Udp.write(buf, size); - Uni_Udp.endPacket(); - - break; - case WIFI_AP: - wifi_sta_list_t stations; - ESP_ERROR_CHECK(esp_wifi_ap_get_sta_list(&stations)); - - tcpip_adapter_sta_list_t infoList; - ESP_ERROR_CHECK(tcpip_adapter_get_sta_list(&stations, &infoList)); - - while (i < infoList.num) { - ClientIP = infoList.sta[i++].ip.addr; - - Uni_Udp.beginPacket(ClientIP, port); - Uni_Udp.write(buf, size); - Uni_Udp.endPacket(); - } - break; - case WIFI_OFF: - default: - break; - } -} - -static int ESP32_WiFi_connect_TCP(const char* host, int port) -{ - bool ret = Ping.ping(host, 2); - - if (ret) - { - if (!client.connect(host, port)) - return 0; - return 1; - } -} - -static int ESP32_WiFi_disconnect_TCP() -{ - client.stop(); -} - -static int ESP32_WiFi_transmit_TCP(String message) -{ - if (client.connected()) - { - client.print(message); - return 0; - } - return 0; -} - -static int ESP32_WiFi_receive_TCP(char* RXbuffer, int RXbuffer_size) -{ - int i = 0; - - if (client.connected()) - { - while (client.available() && i < RXbuffer_size - 1) { - RXbuffer[i] = client.read(); - i++; - RXbuffer[i] = '\0'; - } - return i; - } - client.stop(); - return -1; -} - -static int ESP32_WiFi_isconnected_TCP() -{ - return client.connected(); -} - -static void ESP32_WiFiUDP_stopAll() -{ -/* not implemented yet */ -} - -static bool ESP32_WiFi_hostname(String aHostname) -{ - return WiFi.setHostname(aHostname.c_str()); -} - -static int ESP32_WiFi_clients_count() -{ - WiFiMode_t mode = WiFi.getMode(); - - switch (mode) - { - case WIFI_AP: - wifi_sta_list_t stations; - ESP_ERROR_CHECK(esp_wifi_ap_get_sta_list(&stations)); - - tcpip_adapter_sta_list_t infoList; - ESP_ERROR_CHECK(tcpip_adapter_get_sta_list(&stations, &infoList)); - - return infoList.num; - case WIFI_STA: - default: - return -1; /* error */ - } -} - -static bool ESP32_EEPROM_begin(size_t size) -{ - return EEPROM.begin(size); -} - -static void ESP32_SPI_begin() -{ - if (esp32_board != ESP32_TTGO_T_WATCH) - SPI.begin(SOC_GPIO_PIN_SCK, SOC_GPIO_PIN_MISO, SOC_GPIO_PIN_MOSI, SOC_GPIO_PIN_SS); - else - SPI.begin(SOC_GPIO_PIN_TWATCH_TFT_SCK, SOC_GPIO_PIN_TWATCH_TFT_MISO, - SOC_GPIO_PIN_TWATCH_TFT_MOSI, -1); -} - -static void ESP32_swSer_begin(unsigned long baud) -{ - if (hw_info.model == SOFTRF_MODEL_PRIME_MK2) - { - Serial.print(F("INFO: TTGO T-Beam rev. 0")); - Serial.print(hw_info.revision); - Serial.println(F(" is detected.")); - - if (hw_info.revision == 8) - swSer.begin(baud, SERIAL_IN_BITS, SOC_GPIO_PIN_TBEAM_V08_RX, SOC_GPIO_PIN_TBEAM_V08_TX); - else - swSer.begin(baud, SERIAL_IN_BITS, SOC_GPIO_PIN_TBEAM_V05_RX, SOC_GPIO_PIN_TBEAM_V05_TX); - } - else - { - if (esp32_board == ESP32_TTGO_T_WATCH) - { - Serial.println(F("INFO: TTGO T-Watch is detected.")); - swSer.begin(baud, SERIAL_IN_BITS, SOC_GPIO_PIN_TWATCH_RX, SOC_GPIO_PIN_TWATCH_TX); - } - else if (esp32_board == ESP32_TTGO_V2_OLED) - { - /* 'Mini' (TTGO T3 + GNSS) */ - Serial.print(F("INFO: TTGO T3 rev. ")); - Serial.print(hw_info.revision); - Serial.println(F(" is detected.")); - swSer.begin(baud, SERIAL_IN_BITS, TTGO_V2_PIN_GNSS_RX, TTGO_V2_PIN_GNSS_TX); - } - else - /* open Standalone's GNSS port */ - swSer.begin(baud, SERIAL_IN_BITS, SOC_GPIO_PIN_GNSS_RX, SOC_GPIO_PIN_GNSS_TX); - } - - /* Default Rx buffer size (256 bytes) is sometimes not big enough */ - // swSer.setRxBufferSize(512); - - /* Need to gather some statistics on variety of flash IC usage */ - Serial.print(F("Flash memory ID: ")); - Serial.println(ESP32_getFlashId(), HEX); -} - -static void ESP32_swSer_enableRx(boolean arg) -{} - -/*static byte ESP32_Display_setup() - { - byte rval = DISPLAY_NONE; - - if (esp32_board != ESP32_TTGO_T_WATCH) { - - if (GPIO_21_22_are_busy) { - Wire1.begin(HELTEC_OLED_PIN_SDA , HELTEC_OLED_PIN_SCL); - Wire1.beginTransmission(SSD1306_OLED_I2C_ADDR); - if (Wire1.endTransmission() == 0) { - u8x8 = &u8x8_heltec; - esp32_board = ESP32_HELTEC_OLED; - rval = DISPLAY_OLED_HELTEC; - } - } else { - Wire1.begin(TTGO_V2_OLED_PIN_SDA , TTGO_V2_OLED_PIN_SCL); - Wire1.beginTransmission(SSD1306_OLED_I2C_ADDR); - if (Wire1.endTransmission() == 0) { - u8x8 = &u8x8_ttgo; - esp32_board = ESP32_TTGO_V2_OLED; - - if (hw_info.model == SOFTRF_MODEL_STANDALONE) { - if (RF_SX12XX_RST_is_connected) { - hw_info.revision = 16; - } else { - hw_info.revision = 11; - } - } - - rval = DISPLAY_OLED_TTGO; - } else { - if (!(hw_info.model == SOFTRF_MODEL_PRIME_MK2 && - hw_info.revision == 8)) { - Wire1.begin(HELTEC_OLED_PIN_SDA , HELTEC_OLED_PIN_SCL); - Wire1.beginTransmission(SSD1306_OLED_I2C_ADDR); - if (Wire1.endTransmission() == 0) { - u8x8 = &u8x8_heltec; - esp32_board = ESP32_HELTEC_OLED; - rval = DISPLAY_OLED_HELTEC; - } - } - } - } - - if (u8x8) { - u8x8->begin(); - u8x8->setFont(u8x8_font_chroma48medium8_r); - u8x8->clear(); - u8x8->draw2x2String(2, 3, SoftRF_text); - } - - } else { - - ESP32_SPI_begin(); - - tft = new TFT_eSPI(LV_HOR_RES, LV_VER_RES); - tft->init(); - tft->setRotation(0); - tft->fillScreen(TFT_NAVY); - - ledcAttachPin(SOC_GPIO_PIN_TWATCH_TFT_BL, 1); - ledcSetup(BACKLIGHT_CHANNEL, 12000, 8); - - for (int level = 0; level < 255; level += 25) { - ledcWrite(BACKLIGHT_CHANNEL, level); - delay(100); - } - - tft->setTextFont(4); - tft->setTextSize(2); - tft->setTextColor(TFT_WHITE, TFT_NAVY); - - uint16_t tbw = tft->textWidth(SoftRF_text); - uint16_t tbh = tft->fontHeight(); - tft->setCursor((tft->width() - tbw)/2, (tft->height() - tbh)/2); - tft->println(SoftRF_text); - - rval = DISPLAY_TFT_TTGO; - } - - return rval; - }*/ - -/*static void ESP32_Display_loop() - { - char buf[16]; - uint32_t disp_value; - - uint16_t tbw; - uint16_t tbh; - - switch (hw_info.display) - { - case DISPLAY_TFT_TTGO: - if (tft) { - if (!OLED_display_frontpage) { - tft->fillScreen(TFT_NAVY); - - tft->setTextFont(2); - tft->setTextSize(2); - tft->setTextColor(TFT_WHITE, TFT_NAVY); - - tbw = tft->textWidth(ID_text); - tbh = tft->fontHeight(); - - tft->setCursor(tft->textWidth(" "), tft->height()/6 - tbh); - tft->print(ID_text); - - tbw = tft->textWidth(PROTOCOL_text); - - tft->setCursor(tft->width() - tbw - tft->textWidth(" "), - tft->height()/6 - tbh); - tft->print(PROTOCOL_text); - - tbw = tft->textWidth(RX_text); - tbh = tft->fontHeight(); - - tft->setCursor(tft->textWidth(" "), tft->height()/2 - tbh); - tft->print(RX_text); - - tbw = tft->textWidth(TX_text); - - tft->setCursor(tft->width()/2 + tft->textWidth(" "), - tft->height()/2 - tbh); - tft->print(TX_text); - - tft->setTextFont(4); - tft->setTextSize(2); - - itoa(ThisAircraft.addr & 0xFFFFFF, buf, 16); - - tbw = tft->textWidth(buf); - tbh = tft->fontHeight(); - - tft->setCursor(tft->textWidth(" "), tft->height()/6); - tft->print(buf); - - tbw = tft->textWidth(OLED_Protocol_ID[ThisAircraft.protocol]); - - tft->setCursor(tft->width() - tbw - tft->textWidth(" "), - tft->height()/6); - tft->print(OLED_Protocol_ID[ThisAircraft.protocol]); - - itoa(rx_packets_counter % 1000, buf, 10); - tft->setCursor(tft->textWidth(" "), tft->height()/2); - tft->print(buf); - - itoa(tx_packets_counter % 1000, buf, 10); - tft->setCursor(tft->width()/2 + tft->textWidth(" "), tft->height()/2); - tft->print(buf); - - OLED_display_frontpage = true; - - } else { - - if (rx_packets_counter > prev_rx_packets_counter) { - disp_value = rx_packets_counter % 1000; - itoa(disp_value, buf, 10); - - if (disp_value < 10) { - strcat_P(buf,PSTR(" ")); - } else { - if (disp_value < 100) { - strcat_P(buf,PSTR(" ")); - }; - } - - tft->setTextFont(4); - tft->setTextSize(2); - - tft->setCursor(tft->textWidth(" "), tft->height()/2); - tft->print(buf); - - prev_rx_packets_counter = rx_packets_counter; - } - if (tx_packets_counter > prev_tx_packets_counter) { - disp_value = tx_packets_counter % 1000; - itoa(disp_value, buf, 10); - - if (disp_value < 10) { - strcat_P(buf,PSTR(" ")); - } else { - if (disp_value < 100) { - strcat_P(buf,PSTR(" ")); - }; - } - - tft->setTextFont(4); - tft->setTextSize(2); - - tft->setCursor(tft->width()/2 + tft->textWidth(" "), tft->height()/2); - tft->print(buf); - - prev_tx_packets_counter = tx_packets_counter; - } - } - } - - break; - - case DISPLAY_OLED_TTGO: - case DISPLAY_OLED_HELTEC: - if (u8x8) { - if (!OLED_display_probe_status) { - u8x8->clear(); - - u8x8->draw2x2String(0, 0, "RADIO"); - u8x8->draw2x2String(14, 0, hw_info.rf != RF_IC_NONE ? "+" : "-"); - u8x8->draw2x2String(0, 2, "GNSS"); - u8x8->draw2x2String(14, 2, hw_info.gnss != GNSS_MODULE_NONE ? "+" : "-"); - u8x8->draw2x2String(0, 4, "OLED"); - u8x8->draw2x2String(0, 6, "BARO"); - u8x8->draw2x2String(14, 6, hw_info.baro != BARO_MODULE_NONE ? "+" : "-"); - - delay(3000); - - if (loopTaskWDTEnabled) { - feedLoopWDT(); - } - - OLED_display_probe_status = true; - } else if (!OLED_display_frontpage) { - - u8x8->clear(); - - u8x8->drawString(1, 1, ID_text); - - itoa(ThisAircraft.addr & 0xFFFFFF, buf, 16); - u8x8->draw2x2String(0, 2, buf); - - u8x8->drawString(8, 1, PROTOCOL_text); - - u8x8->draw2x2String(14, 2, OLED_Protocol_ID[ThisAircraft.protocol]); - - u8x8->drawString(1, 5, RX_text); - - itoa(rx_packets_counter % 1000, buf, 10); - u8x8->draw2x2String(0, 6, buf); - - u8x8->drawString(9, 5, TX_text); - - if (settings->txpower == RF_TX_POWER_OFF ) { - strcpy(buf, "OFF"); - } else { - itoa(tx_packets_counter % 1000, buf, 10); - } - u8x8->draw2x2String(8, 6, buf); - - OLED_display_frontpage = true; - - } else { - - if (rx_packets_counter > prev_rx_packets_counter) { - disp_value = rx_packets_counter % 1000; - itoa(disp_value, buf, 10); - - if (disp_value < 10) { - strcat_P(buf,PSTR(" ")); - } else { - if (disp_value < 100) { - strcat_P(buf,PSTR(" ")); - }; - } - - u8x8->draw2x2String(0, 6, buf); - prev_rx_packets_counter = rx_packets_counter; - } - if (tx_packets_counter > prev_tx_packets_counter) { - disp_value = tx_packets_counter % 1000; - itoa(disp_value, buf, 10); - - if (disp_value < 10) { - strcat_P(buf,PSTR(" ")); - } else { - if (disp_value < 100) { - strcat_P(buf,PSTR(" ")); - }; - } - - u8x8->draw2x2String(8, 6, buf); - prev_tx_packets_counter = tx_packets_counter; - } - } - } - - break; - } - }*/ - -static void ESP32_Display_fini(const char* msg) -{ - if (u8x8) - { - u8x8->setFont(u8x8_font_chroma48medium8_r); - u8x8->clear(); - u8x8->draw2x2String(1, 3, msg); -// u8x8->noDisplay(); - } -} - -static void ESP32_Battery_setup() -{ - if ((hw_info.model == SOFTRF_MODEL_PRIME_MK2 && - hw_info.revision == 8) || - hw_info.model == SOFTRF_MODEL_SKYWATCH) - { - /* T-Beam v08 and T-Watch have PMU */ - - /* TBD */ - } - else - calibrate_voltage(hw_info.model == SOFTRF_MODEL_PRIME_MK2 || - (esp32_board == ESP32_TTGO_V2_OLED && hw_info.revision == 16) ? - ADC1_GPIO35_CHANNEL : ADC1_GPIO36_CHANNEL); -} - -static float ESP32_Battery_voltage() -{ - float voltage = 0.0; - - if ((hw_info.model == SOFTRF_MODEL_PRIME_MK2 && - hw_info.revision == 8) || - hw_info.model == SOFTRF_MODEL_SKYWATCH) - { - /* T-Beam v08 and T-Watch have PMU */ - if (axp.isBatteryConnect()) - voltage = axp.getBattVoltage(); - } - else - { - voltage = (float) read_voltage(); - - /* T-Beam v02-v07 and T3 V2.1.6 have voltage divider 100k/100k on board */ - if (hw_info.model == SOFTRF_MODEL_PRIME_MK2 || - (esp32_board == ESP32_TTGO_V2_OLED && hw_info.revision == 16)) - voltage += voltage; - } - - return voltage * 0.001; -} - -static void IRAM_ATTR ESP32_GNSS_PPS_Interrupt_handler() -{ - portENTER_CRITICAL_ISR(&GNSS_PPS_mutex); - PPS_TimeMarker = millis(); /* millis() has IRAM_ATTR */ - portEXIT_CRITICAL_ISR(&GNSS_PPS_mutex); -} - -static unsigned long ESP32_get_PPS_TimeMarker() -{ - unsigned long rval; - portENTER_CRITICAL_ISR(&GNSS_PPS_mutex); - rval = PPS_TimeMarker; - portEXIT_CRITICAL_ISR(&GNSS_PPS_mutex); - return rval; -} - -/*static bool ESP32_Baro_setup() - { - if (hw_info.model == SOFTRF_MODEL_SKYWATCH) { - - return false; - - } else if (hw_info.model != SOFTRF_MODEL_PRIME_MK2) { - - if ((hw_info.rf != RF_IC_SX1276 && hw_info.rf != RF_IC_SX1262) || - RF_SX12XX_RST_is_connected) { - return false; - } - - #if DEBUG - Serial.println(F("INFO: RESET pin of SX12xx radio is not connected to MCU.")); - #endif - - - Wire.begin(SOC_GPIO_PIN_SDA, SOC_GPIO_PIN_SCL); - - } else { - - - Wire.begin(SOC_GPIO_PIN_TBEAM_SDA, SOC_GPIO_PIN_TBEAM_SCL); - - if (hw_info.revision == 2) - return false; - - #if !defined(ENABLE_AHRS) - - Wire.begin(TTGO_V2_OLED_PIN_SDA, TTGO_V2_OLED_PIN_SCL); - - GPIO_21_22_are_busy = true; - #else - return false; - #endif - } - - return true; - }*/ - -static void ESP32_UATSerial_begin(unsigned long baud) -{ - /* open Standalone's I2C/UATSerial port */ - UATSerial.begin(baud, SERIAL_IN_BITS, SOC_GPIO_PIN_CE, SOC_GPIO_PIN_PWR); -} - -static void ESP32_UATSerial_updateBaudRate(unsigned long baud) -{ - UATSerial.updateBaudRate(baud); -} - -static void ESP32_UATModule_restart() -{ - digitalWrite(SOC_GPIO_PIN_TXE, LOW); - pinMode(SOC_GPIO_PIN_TXE, OUTPUT); - - delay(100); - - digitalWrite(SOC_GPIO_PIN_TXE, HIGH); - - delay(100); - - pinMode(SOC_GPIO_PIN_TXE, INPUT); -} - -static void ESP32_WDT_setup() -{ - enableLoopWDT(); -} - -static void ESP32_WDT_fini() -{ - disableLoopWDT(); -} - -static void ESP32_Button_setup() -{ - /* TODO */ -} - -static void ESP32_Button_loop() -{ - /* TODO */ -} - -static void ESP32_Button_fini() -{ - /* TODO */ -} - -const SoC_ops_t ESP32_ops = { - SOC_ESP32, - "ESP32", - ESP32_setup, - ESP32_loop, - ESP32_fini, - ESP32_reset, - ESP32_getChipId, - ESP32_getResetInfoPtr, - ESP32_getResetInfo, - ESP32_getResetReason, - ESP32_getFreeHeap, - ESP32_random, - ESP32_maxSketchSpace, - ESP32_WiFi_setOutputPower, - ESP32_WiFi_transmit_UDP, - ESP32_WiFi_transmit_UDP_debug, - ESP32_WiFi_connect_TCP, - ESP32_WiFi_disconnect_TCP, - ESP32_WiFi_transmit_TCP, - ESP32_WiFi_receive_TCP, - ESP32_WiFi_isconnected_TCP, - ESP32_WiFiUDP_stopAll, - ESP32_WiFi_hostname, - ESP32_WiFi_clients_count, - ESP32_EEPROM_begin, - ESP32_SPI_begin, - ESP32_swSer_begin, - ESP32_swSer_enableRx, - &ESP32_Bluetooth_ops, - ESP32_Battery_setup, - ESP32_Battery_voltage, - ESP32_GNSS_PPS_Interrupt_handler, - ESP32_get_PPS_TimeMarker, - ESP32_UATSerial_begin, - ESP32_UATModule_restart, - ESP32_WDT_setup, - ESP32_WDT_fini, - ESP32_Button_setup, - ESP32_Button_loop, - ESP32_Button_fini -}; - -#endif /* ESP32 */ +/* + * Platform_ESP32.cpp + * Copyright (C) 2018-2020 Linar Yusupov + * + * 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 . + */ +#if defined(ESP32) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Platform_ESP32.h" +#include "SoC.h" + +#include "EEPROM.h" +#include "RF.h" +#include "WiFi.h" +#include "Bluetooth.h" + +#include "Log.h" +#include + +#include "Battery.h" + +#include +#include + +// RFM95W pin mapping +lmic_pinmap lmic_pins = { + .nss = SOC_GPIO_PIN_SS, + .txe = LMIC_UNUSED_PIN, + .rxe = LMIC_UNUSED_PIN, + .rst = SOC_GPIO_PIN_RST, + .dio = {LMIC_UNUSED_PIN, LMIC_UNUSED_PIN, LMIC_UNUSED_PIN}, + .busy = SOC_GPIO_PIN_TXE, + .tcxo = LMIC_UNUSED_PIN, +}; + +WebServer server(80); + +U8X8_SSD1306_128X64_NONAME_2ND_HW_I2C u8x8_ttgo(TTGO_V2_OLED_PIN_RST, + TTGO_V2_OLED_PIN_SCL, + TTGO_V2_OLED_PIN_SDA); + +U8X8_SSD1306_128X64_NONAME_2ND_HW_I2C u8x8_heltec(HELTEC_OLED_PIN_RST, + HELTEC_OLED_PIN_SCL, + HELTEC_OLED_PIN_SDA); + +AXP20X_Class axp; +WiFiClient client; + +static U8X8_SSD1306_128X64_NONAME_2ND_HW_I2C* u8x8 = NULL; +static TFT_eSPI* tft = NULL; + +static int esp32_board = ESP32_DEVKIT; /* default */ + +static portMUX_TYPE GNSS_PPS_mutex = portMUX_INITIALIZER_UNLOCKED; +static portMUX_TYPE PMU_mutex = portMUX_INITIALIZER_UNLOCKED; +volatile bool PMU_Irq = false; + +static bool GPIO_21_22_are_busy = false; + +static union +{ + uint8_t efuse_mac[6]; + uint64_t chipmacid; +}; + +static bool OLED_display_probe_status = false; +static bool OLED_display_frontpage = false; +static uint32_t prev_tx_packets_counter = 0; +static uint32_t prev_rx_packets_counter = 0; +extern uint32_t tx_packets_counter, rx_packets_counter; +extern bool loopTaskWDTEnabled; + +/*const char* OLED_Protocol_ID[] = { + [RF_PROTOCOL_LEGACY] = "L", + [RF_PROTOCOL_OGNTP] = "O", + [RF_PROTOCOL_P3I] = "P", + [RF_PROTOCOL_ADSB_1090] = "A", + [RF_PROTOCOL_ADSB_UAT] = "U", + [RF_PROTOCOL_FANET] = "F" + };*/ + +const char SoftRF_text[] = "SoftRF"; +const char ID_text[] = "ID"; +const char PROTOCOL_text[] = "PROTOCOL"; +const char RX_text[] = "RX"; +const char TX_text[] = "TX"; + +static void IRAM_ATTR ESP32_PMU_Interrupt_handler() +{ + portENTER_CRITICAL_ISR(&PMU_mutex); + PMU_Irq = true; + portEXIT_CRITICAL_ISR(&PMU_mutex); +} + +static uint32_t ESP32_getFlashId() +{ + return g_rom_flashchip.device_id; +} + +static void ESP32_setup() +{ +#if !defined(SOFTRF_ADDRESS) + + esp_err_t ret = ESP_OK; + uint8_t null_mac[6] = {0}; + + ret = esp_efuse_mac_get_custom(efuse_mac); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "Get base MAC address from BLK3 of EFUSE error (%s)", esp_err_to_name(ret)); + /* If get custom base MAC address error, the application developer can decide what to do: + * abort or use the default base MAC address which is stored in BLK0 of EFUSE by doing + * nothing. + */ + + ESP_LOGI(TAG, "Use base MAC address which is stored in BLK0 of EFUSE"); + chipmacid = ESP.getEfuseMac(); + } + else if (memcmp(efuse_mac, null_mac, 6) == 0) + { + ESP_LOGI(TAG, "Use base MAC address which is stored in BLK0 of EFUSE"); + chipmacid = ESP.getEfuseMac(); + } +#endif /* SOFTRF_ADDRESS */ + +#if ESP32_DISABLE_BROWNOUT_DETECTOR + WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); +#endif + + if (psramFound()) + { + uint32_t flash_id = ESP32_getFlashId(); + + /* + * Board | Module | Flash memory IC + * ----------------+------------+-------------------- + * DoIt ESP32 | WROOM | GIGADEVICE_GD25Q32 + * TTGO T3 V2.0 | PICO-D4 IC | GIGADEVICE_GD25Q32 + * TTGO T3 V2.1.6 | PICO-D4 IC | GIGADEVICE_GD25Q32 + * TTGO T22 V06 | | WINBOND_NEX_W25Q32_V + * TTGO T22 V08 | | WINBOND_NEX_W25Q32_V + * TTGO T22 V11 | | BOYA_BY25Q32AL + * TTGO T8 V1.8 | WROVER | GIGADEVICE_GD25LQ32 + * TTGO T5S V1.9 | | WINBOND_NEX_W25Q32_V + * TTGO T5S V2.8 | | BOYA_BY25Q32AL + * TTGO T-Watch | | WINBOND_NEX_W25Q128_V + */ + + switch (flash_id) + { + case MakeFlashId(GIGADEVICE_ID, GIGADEVICE_GD25LQ32): + /* ESP32-WROVER module with ESP32-NODEMCU-ADAPTER */ + hw_info.model = SOFTRF_MODEL_STANDALONE; + break; + case MakeFlashId(WINBOND_NEX_ID, WINBOND_NEX_W25Q128_V): + hw_info.model = SOFTRF_MODEL_SKYWATCH; + break; + case MakeFlashId(WINBOND_NEX_ID, WINBOND_NEX_W25Q32_V): + case MakeFlashId(BOYA_ID, BOYA_BY25Q32AL): + default: + hw_info.model = SOFTRF_MODEL_PRIME_MK2; + break; + } + } + else + { + uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG); + uint32_t pkg_ver = chip_ver & 0x7; + if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) + { + esp32_board = ESP32_TTGO_V2_OLED; + lmic_pins.rst = SOC_GPIO_PIN_TBEAM_RF_RST_V05; + lmic_pins.busy = SOC_GPIO_PIN_TBEAM_RF_BUSY_V08; + } + } + + ledcSetup(LEDC_CHANNEL_BUZZER, 0, LEDC_RESOLUTION_BUZZER); + + if (hw_info.model == SOFTRF_MODEL_SKYWATCH) + { + esp32_board = ESP32_TTGO_T_WATCH; + + Wire1.begin(SOC_GPIO_PIN_TWATCH_SEN_SDA, SOC_GPIO_PIN_TWATCH_SEN_SCL); + Wire1.beginTransmission(AXP202_SLAVE_ADDRESS); + if (Wire1.endTransmission() == 0) + { + axp.begin(Wire1, AXP202_SLAVE_ADDRESS); + + axp.enableIRQ(AXP202_ALL_IRQ, AXP202_OFF); + axp.adc1Enable(0xFF, AXP202_OFF); + + axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL); + + axp.setPowerOutPut(AXP202_LDO2, AXP202_ON); // BL + axp.setPowerOutPut(AXP202_LDO3, AXP202_ON); // S76G (MCU + LoRa) + axp.setLDO4Voltage(AXP202_LDO4_1800MV); + axp.setPowerOutPut(AXP202_LDO4, AXP202_ON); // S76G (Sony GNSS) + + pinMode(SOC_GPIO_PIN_TWATCH_PMU_IRQ, INPUT_PULLUP); + + attachInterrupt(digitalPinToInterrupt(SOC_GPIO_PIN_TWATCH_PMU_IRQ), + ESP32_PMU_Interrupt_handler, FALLING); + + axp.adc1Enable(AXP202_BATT_VOL_ADC1, AXP202_ON); + axp.enableIRQ(AXP202_PEK_LONGPRESS_IRQ | AXP202_PEK_SHORTPRESS_IRQ, true); + axp.clearIRQ(); + } + } + else if (hw_info.model == SOFTRF_MODEL_PRIME_MK2) + { + esp32_board = ESP32_TTGO_T_BEAM; + + Wire1.begin(TTGO_V2_OLED_PIN_SDA, TTGO_V2_OLED_PIN_SCL); + Wire1.beginTransmission(AXP192_SLAVE_ADDRESS); + if (Wire1.endTransmission() == 0) + { + hw_info.revision = 8; + + axp.begin(Wire1, AXP192_SLAVE_ADDRESS); + + axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL); + + axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); + axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); + axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON); + axp.setPowerOutPut(AXP192_DCDC2, AXP202_ON); // NC + axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON); + + axp.setDCDC1Voltage(3300); // AXP192 power-on value: 3300 + axp.setLDO2Voltage(3300); // LoRa, AXP192 power-on value: 3300 + axp.setLDO3Voltage(3000); // GPS, AXP192 power-on value: 2800 + + pinMode(SOC_GPIO_PIN_TBEAM_V08_PMU_IRQ, INPUT_PULLUP); + + attachInterrupt(digitalPinToInterrupt(SOC_GPIO_PIN_TBEAM_V08_PMU_IRQ), + ESP32_PMU_Interrupt_handler, FALLING); + + axp.enableIRQ(AXP202_PEK_LONGPRESS_IRQ | AXP202_PEK_SHORTPRESS_IRQ, true); + axp.clearIRQ(); + } + else + hw_info.revision = 2; + lmic_pins.rst = SOC_GPIO_PIN_TBEAM_RF_RST_V05; + lmic_pins.busy = SOC_GPIO_PIN_TBEAM_RF_BUSY_V08; + } +} + +static void ESP32_loop() +{ + if ((hw_info.model == SOFTRF_MODEL_PRIME_MK2 && + hw_info.revision == 8) || + hw_info.model == SOFTRF_MODEL_SKYWATCH) + { + bool is_irq = false; + bool down = false; + + portENTER_CRITICAL_ISR(&PMU_mutex); + is_irq = PMU_Irq; + portEXIT_CRITICAL_ISR(&PMU_mutex); + + if (is_irq) + { + if (axp.readIRQ() == AXP_PASS) + { + if (axp.isPEKLongtPressIRQ()) + { + down = true; +#if 0 + Serial.println(F("Longt Press IRQ")); + Serial.flush(); +#endif + } + if (axp.isPEKShortPressIRQ()) + { +#if 0 + Serial.println(F("Short Press IRQ")); + Serial.flush(); +#endif + } + + axp.clearIRQ(); + } + + portENTER_CRITICAL_ISR(&PMU_mutex); + PMU_Irq = false; + portEXIT_CRITICAL_ISR(&PMU_mutex); + + if (down) + shutdown(" OFF "); + } + + if (isTimeToBattery()) + { + if (Battery_voltage() > Battery_threshold()) + axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL); + else + axp.setChgLEDMode(AXP20X_LED_BLINK_1HZ); + } + } +} + +static void ESP32_fini() +{ + SPI.end(); + + esp_wifi_stop(); + esp_bt_controller_disable(); + + if (hw_info.model == SOFTRF_MODEL_SKYWATCH) + { + axp.setChgLEDMode(AXP20X_LED_OFF); + + axp.setPowerOutPut(AXP202_LDO2, AXP202_OFF); // BL + axp.setPowerOutPut(AXP202_LDO4, AXP202_OFF); // S76G (Sony GNSS) + axp.setPowerOutPut(AXP202_LDO3, AXP202_OFF); // S76G (MCU + LoRa) + + delay(20); + + esp_sleep_enable_ext0_wakeup((gpio_num_t) SOC_GPIO_PIN_TWATCH_PMU_IRQ, 0); // 1 = High, 0 = Low + } + else if (hw_info.model == SOFTRF_MODEL_PRIME_MK2 && + hw_info.revision == 8) + { + axp.setChgLEDMode(AXP20X_LED_OFF); + + delay(2000); /* Keep 'OFF' message on OLED for 2 seconds */ + + axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); + axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF); + axp.setPowerOutPut(AXP192_DCDC2, AXP202_OFF); + axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); + axp.setPowerOutPut(AXP192_EXTEN, AXP202_OFF); + + delay(20); + + esp_sleep_enable_ext0_wakeup((gpio_num_t) SOC_GPIO_PIN_TBEAM_V08_PMU_IRQ, 0); // 1 = High, 0 = Low + } + + esp_deep_sleep_start(); +} + +static void ESP32_reset() +{ + ESP.restart(); +} + +static uint32_t ESP32_getChipId() +{ +#if !defined(SOFTRF_ADDRESS) + uint32_t id = (uint32_t) efuse_mac[5] | ((uint32_t) efuse_mac[4] << 8) | \ + ((uint32_t) efuse_mac[3] << 16) | ((uint32_t) efuse_mac[2] << 24); + + /* remap address to avoid overlapping with congested FLARM range */ + if (((id & 0x00FFFFFF) >= 0xDD0000) && ((id & 0x00FFFFFF) <= 0xDFFFFF)) + id += 0x100000; + + return id; +#else + return SOFTRF_ADDRESS & 0xFFFFFFFFU; +#endif /* SOFTRF_ADDRESS */ +} + +static struct rst_info reset_info = { + .reason = REASON_DEFAULT_RST, +}; + +static void * ESP32_getResetInfoPtr() +{ + switch (rtc_get_reset_reason(0)) + { + case POWERON_RESET: + reset_info.reason = REASON_DEFAULT_RST; + break; + case SW_RESET: + reset_info.reason = REASON_SOFT_RESTART; + break; + case OWDT_RESET: + reset_info.reason = REASON_WDT_RST; + break; + case DEEPSLEEP_RESET: + reset_info.reason = REASON_DEEP_SLEEP_AWAKE; + break; + case SDIO_RESET: + reset_info.reason = REASON_EXCEPTION_RST; + break; + case TG0WDT_SYS_RESET: + reset_info.reason = REASON_WDT_RST; + break; + case TG1WDT_SYS_RESET: + reset_info.reason = REASON_WDT_RST; + break; + case RTCWDT_SYS_RESET: + reset_info.reason = REASON_WDT_RST; + break; + case INTRUSION_RESET: + reset_info.reason = REASON_EXCEPTION_RST; + break; + case TGWDT_CPU_RESET: + reset_info.reason = REASON_WDT_RST; + break; + case SW_CPU_RESET: + reset_info.reason = REASON_SOFT_RESTART; + break; + case RTCWDT_CPU_RESET: + reset_info.reason = REASON_WDT_RST; + break; + case EXT_CPU_RESET: + reset_info.reason = REASON_EXT_SYS_RST; + break; + case RTCWDT_BROWN_OUT_RESET: + reset_info.reason = REASON_EXT_SYS_RST; + break; + case RTCWDT_RTC_RESET: + /* Slow start of GD25LQ32 causes one read fault at boot time with current ESP-IDF */ + if (ESP32_getFlashId() == MakeFlashId(GIGADEVICE_ID, GIGADEVICE_GD25LQ32)) + reset_info.reason = REASON_DEFAULT_RST; + else + reset_info.reason = REASON_WDT_RST; + break; + default: + reset_info.reason = REASON_DEFAULT_RST; + } + + return (void *) &reset_info; +} + +static String ESP32_getResetInfo() +{ + switch (rtc_get_reset_reason(0)) + { + case POWERON_RESET: + return F("Vbat power on reset"); + case SW_RESET: + return F("Software reset digital core"); + case OWDT_RESET: + return F("Legacy watch dog reset digital core"); + case DEEPSLEEP_RESET: + return F("Deep Sleep reset digital core"); + case SDIO_RESET: + return F("Reset by SLC module, reset digital core"); + case TG0WDT_SYS_RESET: + return F("Timer Group0 Watch dog reset digital core"); + case TG1WDT_SYS_RESET: + return F("Timer Group1 Watch dog reset digital core"); + case RTCWDT_SYS_RESET: + return F("RTC Watch dog Reset digital core"); + case INTRUSION_RESET: + return F("Instrusion tested to reset CPU"); + case TGWDT_CPU_RESET: + return F("Time Group reset CPU"); + case SW_CPU_RESET: + return F("Software reset CPU"); + case RTCWDT_CPU_RESET: + return F("RTC Watch dog Reset CPU"); + case EXT_CPU_RESET: + return F("for APP CPU, reseted by PRO CPU"); + case RTCWDT_BROWN_OUT_RESET: + return F("Reset when the vdd voltage is not stable"); + case RTCWDT_RTC_RESET: + return F("RTC Watch dog reset digital core and rtc module"); + default: + return F("No reset information available"); + } +} + +static String ESP32_getResetReason() +{ + switch (rtc_get_reset_reason(0)) + { + case POWERON_RESET: + return F("POWERON_RESET"); + case SW_RESET: + return F("SW_RESET"); + case OWDT_RESET: + return F("OWDT_RESET"); + case DEEPSLEEP_RESET: + return F("DEEPSLEEP_RESET"); + case SDIO_RESET: + return F("SDIO_RESET"); + case TG0WDT_SYS_RESET: + return F("TG0WDT_SYS_RESET"); + case TG1WDT_SYS_RESET: + return F("TG1WDT_SYS_RESET"); + case RTCWDT_SYS_RESET: + return F("RTCWDT_SYS_RESET"); + case INTRUSION_RESET: + return F("INTRUSION_RESET"); + case TGWDT_CPU_RESET: + return F("TGWDT_CPU_RESET"); + case SW_CPU_RESET: + return F("SW_CPU_RESET"); + case RTCWDT_CPU_RESET: + return F("RTCWDT_CPU_RESET"); + case EXT_CPU_RESET: + return F("EXT_CPU_RESET"); + case RTCWDT_BROWN_OUT_RESET: + return F("RTCWDT_BROWN_OUT_RESET"); + case RTCWDT_RTC_RESET: + return F("RTCWDT_RTC_RESET"); + default: + return F("NO_MEAN"); + } +} + +static uint32_t ESP32_getFreeHeap() +{ + return ESP.getFreeHeap(); +} + +static long ESP32_random(long howsmall, long howBig) +{ + return random(howsmall, howBig); +} + +/*static void ESP32_Sound_test(int var) + { + if (settings->volume != BUZZER_OFF) { + + ledcAttachPin(SOC_GPIO_PIN_BUZZER, LEDC_CHANNEL_BUZZER); + + ledcWrite(LEDC_CHANNEL_BUZZER, 125); // high volume + + if (var == REASON_DEFAULT_RST || + var == REASON_EXT_SYS_RST || + var == REASON_SOFT_RESTART) { + ledcWriteTone(LEDC_CHANNEL_BUZZER, 440);delay(500); + ledcWriteTone(LEDC_CHANNEL_BUZZER, 640);delay(500); + ledcWriteTone(LEDC_CHANNEL_BUZZER, 840);delay(500); + ledcWriteTone(LEDC_CHANNEL_BUZZER, 1040); + } else if (var == REASON_WDT_RST) { + ledcWriteTone(LEDC_CHANNEL_BUZZER, 440);delay(500); + ledcWriteTone(LEDC_CHANNEL_BUZZER, 1040);delay(500); + ledcWriteTone(LEDC_CHANNEL_BUZZER, 440);delay(500); + ledcWriteTone(LEDC_CHANNEL_BUZZER, 1040); + } else { + ledcWriteTone(LEDC_CHANNEL_BUZZER, 1040);delay(500); + ledcWriteTone(LEDC_CHANNEL_BUZZER, 840);delay(500); + ledcWriteTone(LEDC_CHANNEL_BUZZER, 640);delay(500); + ledcWriteTone(LEDC_CHANNEL_BUZZER, 440); + } + delay(600); + + ledcWriteTone(LEDC_CHANNEL_BUZZER, 0); // off + + ledcDetachPin(SOC_GPIO_PIN_BUZZER); + pinMode(SOC_GPIO_PIN_BUZZER, INPUT_PULLDOWN); + } + }*/ + +static uint32_t ESP32_maxSketchSpace() +{ + return 0x1E0000; +} + +static const int8_t ESP32_dB_to_power_level[21] = { + 8, /* 2 dB, #0 */ + 8, /* 2 dB, #1 */ + 8, /* 2 dB, #2 */ + 8, /* 2 dB, #3 */ + 8, /* 2 dB, #4 */ + 20, /* 5 dB, #5 */ + 20, /* 5 dB, #6 */ + 28, /* 7 dB, #7 */ + 28, /* 7 dB, #8 */ + 34, /* 8.5 dB, #9 */ + 34, /* 8.5 dB, #10 */ + 44, /* 11 dB, #11 */ + 44, /* 11 dB, #12 */ + 52, /* 13 dB, #13 */ + 52, /* 13 dB, #14 */ + 60, /* 15 dB, #15 */ + 60, /* 15 dB, #16 */ + 68, /* 17 dB, #17 */ + 74, /* 18.5 dB, #18 */ + 76, /* 19 dB, #19 */ + 78 /* 19.5 dB, #20 */ +}; + +static void ESP32_WiFi_setOutputPower(int dB) +{ + if (dB > 20) + dB = 20; + + if (dB < 0) + dB = 0; + + ESP_ERROR_CHECK(esp_wifi_set_max_tx_power(ESP32_dB_to_power_level[dB])); +} + +static IPAddress ESP32_WiFi_get_broadcast() +{ + tcpip_adapter_ip_info_t info; + IPAddress broadcastIp; + + if (WiFi.getMode() == WIFI_STA) + tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &info); + else + tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &info); + broadcastIp = ~info.netmask.addr | info.ip.addr; + + return broadcastIp; +} + +static void ESP32_WiFi_transmit_UDP_debug(int port, byte* buf, size_t size) +{ + IPAddress ClientIP; + unsigned int localPort = 8888; + + WiFiMode_t mode = WiFi.getMode(); + int i = 0; + + switch (mode) + { + case WIFI_STA: + ClientIP = WiFi.gatewayIP(); + ClientIP[3] = 200; + Uni_Udp.begin(localPort); + Uni_Udp.beginPacket(ClientIP, port); + Uni_Udp.write(buf, size); + Uni_Udp.endPacket(); + + ClientIP[3] = 199; + Uni_Udp.begin(localPort); + Uni_Udp.beginPacket(ClientIP, port); + Uni_Udp.write(buf, size); + Uni_Udp.endPacket(); + + break; + case WIFI_AP: + break; + case WIFI_OFF: + default: + break; + } +} + +static void ESP32_WiFi_transmit_UDP(int port, byte* buf, size_t size) +{ + IPAddress ClientIP; + WiFiMode_t mode = WiFi.getMode(); + int i = 0; + + switch (mode) + { + case WIFI_STA: + ClientIP = ESP32_WiFi_get_broadcast(); + + Uni_Udp.beginPacket(ClientIP, port); + Uni_Udp.write(buf, size); + Uni_Udp.endPacket(); + + break; + case WIFI_AP: + wifi_sta_list_t stations; + ESP_ERROR_CHECK(esp_wifi_ap_get_sta_list(&stations)); + + tcpip_adapter_sta_list_t infoList; + ESP_ERROR_CHECK(tcpip_adapter_get_sta_list(&stations, &infoList)); + + while (i < infoList.num) { + ClientIP = infoList.sta[i++].ip.addr; + + Uni_Udp.beginPacket(ClientIP, port); + Uni_Udp.write(buf, size); + Uni_Udp.endPacket(); + } + break; + case WIFI_OFF: + default: + break; + } +} + +static int ESP32_WiFi_connect_TCP(const char* host, int port) +{ + bool ret = Ping.ping(host, 2); + + if (ret) + { + if (!client.connect(host, port, 5000)) + return 0; + return 1; + } + return 0; +} + +static int ESP32_WiFi_disconnect_TCP() +{ + client.stop(); +} + +static int ESP32_WiFi_transmit_TCP(String message) +{ + if (client.connected()) + { + client.print(message); + return 0; + } + return 0; +} + +static int ESP32_WiFi_receive_TCP(char* RXbuffer, int RXbuffer_size) +{ + int i = 0; + + if (client.connected()) + { + while (client.available() && i < RXbuffer_size - 1) { + RXbuffer[i] = client.read(); + i++; + RXbuffer[i] = '\0'; + } + return i; + } + client.stop(); + return -1; +} + +static int ESP32_WiFi_isconnected_TCP() +{ + return client.connected(); +} + +static void ESP32_WiFiUDP_stopAll() +{ +/* not implemented yet */ +} + +static bool ESP32_WiFi_hostname(String aHostname) +{ + return WiFi.setHostname(aHostname.c_str()); +} + +static int ESP32_WiFi_clients_count() +{ + WiFiMode_t mode = WiFi.getMode(); + + switch (mode) + { + case WIFI_AP: + wifi_sta_list_t stations; + ESP_ERROR_CHECK(esp_wifi_ap_get_sta_list(&stations)); + + tcpip_adapter_sta_list_t infoList; + ESP_ERROR_CHECK(tcpip_adapter_get_sta_list(&stations, &infoList)); + + return infoList.num; + case WIFI_STA: + default: + return -1; /* error */ + } +} + +static bool ESP32_EEPROM_begin(size_t size) +{ + return EEPROM.begin(size); +} + +static void ESP32_SPI_begin() +{ + if (esp32_board != ESP32_TTGO_T_WATCH) + SPI.begin(SOC_GPIO_PIN_SCK, SOC_GPIO_PIN_MISO, SOC_GPIO_PIN_MOSI, SOC_GPIO_PIN_SS); + else + SPI.begin(SOC_GPIO_PIN_TWATCH_TFT_SCK, SOC_GPIO_PIN_TWATCH_TFT_MISO, + SOC_GPIO_PIN_TWATCH_TFT_MOSI, -1); +} + +static void ESP32_swSer_begin(unsigned long baud) +{ + if (hw_info.model == SOFTRF_MODEL_PRIME_MK2) + { + Serial.print(F("INFO: TTGO T-Beam rev. 0")); + Serial.print(hw_info.revision); + Serial.println(F(" is detected.")); + + if (hw_info.revision == 8) + swSer.begin(baud, SERIAL_IN_BITS, SOC_GPIO_PIN_TBEAM_V08_RX, SOC_GPIO_PIN_TBEAM_V08_TX); + else + swSer.begin(baud, SERIAL_IN_BITS, SOC_GPIO_PIN_TBEAM_V05_RX, SOC_GPIO_PIN_TBEAM_V05_TX); + } + else + { + if (esp32_board == ESP32_TTGO_T_WATCH) + { + Serial.println(F("INFO: TTGO T-Watch is detected.")); + swSer.begin(baud, SERIAL_IN_BITS, SOC_GPIO_PIN_TWATCH_RX, SOC_GPIO_PIN_TWATCH_TX); + } + else if (esp32_board == ESP32_TTGO_V2_OLED) + { + /* 'Mini' (TTGO T3 + GNSS) */ + Serial.print(F("INFO: TTGO T3 rev. ")); + Serial.print(hw_info.revision); + Serial.println(F(" is detected.")); + swSer.begin(baud, SERIAL_IN_BITS, TTGO_V2_PIN_GNSS_RX, TTGO_V2_PIN_GNSS_TX); + } + else + /* open Standalone's GNSS port */ + swSer.begin(baud, SERIAL_IN_BITS, SOC_GPIO_PIN_GNSS_RX, SOC_GPIO_PIN_GNSS_TX); + } + + /* Default Rx buffer size (256 bytes) is sometimes not big enough */ + // swSer.setRxBufferSize(512); + + /* Need to gather some statistics on variety of flash IC usage */ + Serial.print(F("Flash memory ID: ")); + Serial.println(ESP32_getFlashId(), HEX); +} + +static void ESP32_swSer_enableRx(boolean arg) +{} + +/*static byte ESP32_Display_setup() + { + byte rval = DISPLAY_NONE; + + if (esp32_board != ESP32_TTGO_T_WATCH) { + + if (GPIO_21_22_are_busy) { + Wire1.begin(HELTEC_OLED_PIN_SDA , HELTEC_OLED_PIN_SCL); + Wire1.beginTransmission(SSD1306_OLED_I2C_ADDR); + if (Wire1.endTransmission() == 0) { + u8x8 = &u8x8_heltec; + esp32_board = ESP32_HELTEC_OLED; + rval = DISPLAY_OLED_HELTEC; + } + } else { + Wire1.begin(TTGO_V2_OLED_PIN_SDA , TTGO_V2_OLED_PIN_SCL); + Wire1.beginTransmission(SSD1306_OLED_I2C_ADDR); + if (Wire1.endTransmission() == 0) { + u8x8 = &u8x8_ttgo; + esp32_board = ESP32_TTGO_V2_OLED; + + if (hw_info.model == SOFTRF_MODEL_STANDALONE) { + if (RF_SX12XX_RST_is_connected) { + hw_info.revision = 16; + } else { + hw_info.revision = 11; + } + } + + rval = DISPLAY_OLED_TTGO; + } else { + if (!(hw_info.model == SOFTRF_MODEL_PRIME_MK2 && + hw_info.revision == 8)) { + Wire1.begin(HELTEC_OLED_PIN_SDA , HELTEC_OLED_PIN_SCL); + Wire1.beginTransmission(SSD1306_OLED_I2C_ADDR); + if (Wire1.endTransmission() == 0) { + u8x8 = &u8x8_heltec; + esp32_board = ESP32_HELTEC_OLED; + rval = DISPLAY_OLED_HELTEC; + } + } + } + } + + if (u8x8) { + u8x8->begin(); + u8x8->setFont(u8x8_font_chroma48medium8_r); + u8x8->clear(); + u8x8->draw2x2String(2, 3, SoftRF_text); + } + + } else { + + ESP32_SPI_begin(); + + tft = new TFT_eSPI(LV_HOR_RES, LV_VER_RES); + tft->init(); + tft->setRotation(0); + tft->fillScreen(TFT_NAVY); + + ledcAttachPin(SOC_GPIO_PIN_TWATCH_TFT_BL, 1); + ledcSetup(BACKLIGHT_CHANNEL, 12000, 8); + + for (int level = 0; level < 255; level += 25) { + ledcWrite(BACKLIGHT_CHANNEL, level); + delay(100); + } + + tft->setTextFont(4); + tft->setTextSize(2); + tft->setTextColor(TFT_WHITE, TFT_NAVY); + + uint16_t tbw = tft->textWidth(SoftRF_text); + uint16_t tbh = tft->fontHeight(); + tft->setCursor((tft->width() - tbw)/2, (tft->height() - tbh)/2); + tft->println(SoftRF_text); + + rval = DISPLAY_TFT_TTGO; + } + + return rval; + }*/ + +/*static void ESP32_Display_loop() + { + char buf[16]; + uint32_t disp_value; + + uint16_t tbw; + uint16_t tbh; + + switch (hw_info.display) + { + case DISPLAY_TFT_TTGO: + if (tft) { + if (!OLED_display_frontpage) { + tft->fillScreen(TFT_NAVY); + + tft->setTextFont(2); + tft->setTextSize(2); + tft->setTextColor(TFT_WHITE, TFT_NAVY); + + tbw = tft->textWidth(ID_text); + tbh = tft->fontHeight(); + + tft->setCursor(tft->textWidth(" "), tft->height()/6 - tbh); + tft->print(ID_text); + + tbw = tft->textWidth(PROTOCOL_text); + + tft->setCursor(tft->width() - tbw - tft->textWidth(" "), + tft->height()/6 - tbh); + tft->print(PROTOCOL_text); + + tbw = tft->textWidth(RX_text); + tbh = tft->fontHeight(); + + tft->setCursor(tft->textWidth(" "), tft->height()/2 - tbh); + tft->print(RX_text); + + tbw = tft->textWidth(TX_text); + + tft->setCursor(tft->width()/2 + tft->textWidth(" "), + tft->height()/2 - tbh); + tft->print(TX_text); + + tft->setTextFont(4); + tft->setTextSize(2); + + itoa(ThisAircraft.addr & 0xFFFFFF, buf, 16); + + tbw = tft->textWidth(buf); + tbh = tft->fontHeight(); + + tft->setCursor(tft->textWidth(" "), tft->height()/6); + tft->print(buf); + + tbw = tft->textWidth(OLED_Protocol_ID[ThisAircraft.protocol]); + + tft->setCursor(tft->width() - tbw - tft->textWidth(" "), + tft->height()/6); + tft->print(OLED_Protocol_ID[ThisAircraft.protocol]); + + itoa(rx_packets_counter % 1000, buf, 10); + tft->setCursor(tft->textWidth(" "), tft->height()/2); + tft->print(buf); + + itoa(tx_packets_counter % 1000, buf, 10); + tft->setCursor(tft->width()/2 + tft->textWidth(" "), tft->height()/2); + tft->print(buf); + + OLED_display_frontpage = true; + + } else { + + if (rx_packets_counter > prev_rx_packets_counter) { + disp_value = rx_packets_counter % 1000; + itoa(disp_value, buf, 10); + + if (disp_value < 10) { + strcat_P(buf,PSTR(" ")); + } else { + if (disp_value < 100) { + strcat_P(buf,PSTR(" ")); + }; + } + + tft->setTextFont(4); + tft->setTextSize(2); + + tft->setCursor(tft->textWidth(" "), tft->height()/2); + tft->print(buf); + + prev_rx_packets_counter = rx_packets_counter; + } + if (tx_packets_counter > prev_tx_packets_counter) { + disp_value = tx_packets_counter % 1000; + itoa(disp_value, buf, 10); + + if (disp_value < 10) { + strcat_P(buf,PSTR(" ")); + } else { + if (disp_value < 100) { + strcat_P(buf,PSTR(" ")); + }; + } + + tft->setTextFont(4); + tft->setTextSize(2); + + tft->setCursor(tft->width()/2 + tft->textWidth(" "), tft->height()/2); + tft->print(buf); + + prev_tx_packets_counter = tx_packets_counter; + } + } + } + + break; + + case DISPLAY_OLED_TTGO: + case DISPLAY_OLED_HELTEC: + if (u8x8) { + if (!OLED_display_probe_status) { + u8x8->clear(); + + u8x8->draw2x2String(0, 0, "RADIO"); + u8x8->draw2x2String(14, 0, hw_info.rf != RF_IC_NONE ? "+" : "-"); + u8x8->draw2x2String(0, 2, "GNSS"); + u8x8->draw2x2String(14, 2, hw_info.gnss != GNSS_MODULE_NONE ? "+" : "-"); + u8x8->draw2x2String(0, 4, "OLED"); + u8x8->draw2x2String(0, 6, "BARO"); + u8x8->draw2x2String(14, 6, hw_info.baro != BARO_MODULE_NONE ? "+" : "-"); + + delay(3000); + + if (loopTaskWDTEnabled) { + feedLoopWDT(); + } + + OLED_display_probe_status = true; + } else if (!OLED_display_frontpage) { + + u8x8->clear(); + + u8x8->drawString(1, 1, ID_text); + + itoa(ThisAircraft.addr & 0xFFFFFF, buf, 16); + u8x8->draw2x2String(0, 2, buf); + + u8x8->drawString(8, 1, PROTOCOL_text); + + u8x8->draw2x2String(14, 2, OLED_Protocol_ID[ThisAircraft.protocol]); + + u8x8->drawString(1, 5, RX_text); + + itoa(rx_packets_counter % 1000, buf, 10); + u8x8->draw2x2String(0, 6, buf); + + u8x8->drawString(9, 5, TX_text); + + if (settings->txpower == RF_TX_POWER_OFF ) { + strcpy(buf, "OFF"); + } else { + itoa(tx_packets_counter % 1000, buf, 10); + } + u8x8->draw2x2String(8, 6, buf); + + OLED_display_frontpage = true; + + } else { + + if (rx_packets_counter > prev_rx_packets_counter) { + disp_value = rx_packets_counter % 1000; + itoa(disp_value, buf, 10); + + if (disp_value < 10) { + strcat_P(buf,PSTR(" ")); + } else { + if (disp_value < 100) { + strcat_P(buf,PSTR(" ")); + }; + } + + u8x8->draw2x2String(0, 6, buf); + prev_rx_packets_counter = rx_packets_counter; + } + if (tx_packets_counter > prev_tx_packets_counter) { + disp_value = tx_packets_counter % 1000; + itoa(disp_value, buf, 10); + + if (disp_value < 10) { + strcat_P(buf,PSTR(" ")); + } else { + if (disp_value < 100) { + strcat_P(buf,PSTR(" ")); + }; + } + + u8x8->draw2x2String(8, 6, buf); + prev_tx_packets_counter = tx_packets_counter; + } + } + } + + break; + } + }*/ + +static void ESP32_Display_fini(const char* msg) +{ + if (u8x8) + { + u8x8->setFont(u8x8_font_chroma48medium8_r); + u8x8->clear(); + u8x8->draw2x2String(1, 3, msg); +// u8x8->noDisplay(); + } +} + +static void ESP32_Battery_setup() +{ + if ((hw_info.model == SOFTRF_MODEL_PRIME_MK2 && + hw_info.revision == 8) || + hw_info.model == SOFTRF_MODEL_SKYWATCH) + { + /* T-Beam v08 and T-Watch have PMU */ + + /* TBD */ + } + else + calibrate_voltage(hw_info.model == SOFTRF_MODEL_PRIME_MK2 || + (esp32_board == ESP32_TTGO_V2_OLED && hw_info.revision == 16) ? + ADC1_GPIO35_CHANNEL : ADC1_GPIO36_CHANNEL); +} + +static float ESP32_Battery_voltage() +{ + float voltage = 0.0; + + if ((hw_info.model == SOFTRF_MODEL_PRIME_MK2 && + hw_info.revision == 8) || + hw_info.model == SOFTRF_MODEL_SKYWATCH) + { + /* T-Beam v08 and T-Watch have PMU */ + if (axp.isBatteryConnect()) + voltage = axp.getBattVoltage(); + } + else + { + voltage = (float) read_voltage(); + + /* T-Beam v02-v07 and T3 V2.1.6 have voltage divider 100k/100k on board */ + if (hw_info.model == SOFTRF_MODEL_PRIME_MK2 || + (esp32_board == ESP32_TTGO_V2_OLED && hw_info.revision == 16)) + voltage += voltage; + } + + return voltage * 0.001; +} + +static void IRAM_ATTR ESP32_GNSS_PPS_Interrupt_handler() +{ + portENTER_CRITICAL_ISR(&GNSS_PPS_mutex); + PPS_TimeMarker = millis(); /* millis() has IRAM_ATTR */ + portEXIT_CRITICAL_ISR(&GNSS_PPS_mutex); +} + +static unsigned long ESP32_get_PPS_TimeMarker() +{ + unsigned long rval; + portENTER_CRITICAL_ISR(&GNSS_PPS_mutex); + rval = PPS_TimeMarker; + portEXIT_CRITICAL_ISR(&GNSS_PPS_mutex); + return rval; +} + +/*static bool ESP32_Baro_setup() + { + if (hw_info.model == SOFTRF_MODEL_SKYWATCH) { + + return false; + + } else if (hw_info.model != SOFTRF_MODEL_PRIME_MK2) { + + if ((hw_info.rf != RF_IC_SX1276 && hw_info.rf != RF_IC_SX1262) || + RF_SX12XX_RST_is_connected) { + return false; + } + + #if DEBUG + Serial.println(F("INFO: RESET pin of SX12xx radio is not connected to MCU.")); + #endif + + + Wire.begin(SOC_GPIO_PIN_SDA, SOC_GPIO_PIN_SCL); + + } else { + + + Wire.begin(SOC_GPIO_PIN_TBEAM_SDA, SOC_GPIO_PIN_TBEAM_SCL); + + if (hw_info.revision == 2) + return false; + + #if !defined(ENABLE_AHRS) + + Wire.begin(TTGO_V2_OLED_PIN_SDA, TTGO_V2_OLED_PIN_SCL); + + GPIO_21_22_are_busy = true; + #else + return false; + #endif + } + + return true; + }*/ + +static void ESP32_UATSerial_begin(unsigned long baud) +{ + /* open Standalone's I2C/UATSerial port */ + UATSerial.begin(baud, SERIAL_IN_BITS, SOC_GPIO_PIN_CE, SOC_GPIO_PIN_PWR); +} + +static void ESP32_UATSerial_updateBaudRate(unsigned long baud) +{ + UATSerial.updateBaudRate(baud); +} + +static void ESP32_UATModule_restart() +{ + digitalWrite(SOC_GPIO_PIN_TXE, LOW); + pinMode(SOC_GPIO_PIN_TXE, OUTPUT); + + delay(100); + + digitalWrite(SOC_GPIO_PIN_TXE, HIGH); + + delay(100); + + pinMode(SOC_GPIO_PIN_TXE, INPUT); +} + +static void ESP32_WDT_setup() +{ + enableLoopWDT(); +} + +static void ESP32_WDT_fini() +{ + disableLoopWDT(); +} + +static void ESP32_Button_setup() +{ + /* TODO */ +} + +static void ESP32_Button_loop() +{ + /* TODO */ +} + +static void ESP32_Button_fini() +{ + /* TODO */ +} + +const SoC_ops_t ESP32_ops = { + SOC_ESP32, + "ESP32", + ESP32_setup, + ESP32_loop, + ESP32_fini, + ESP32_reset, + ESP32_getChipId, + ESP32_getResetInfoPtr, + ESP32_getResetInfo, + ESP32_getResetReason, + ESP32_getFreeHeap, + ESP32_random, + ESP32_maxSketchSpace, + ESP32_WiFi_setOutputPower, + ESP32_WiFi_transmit_UDP, + ESP32_WiFi_transmit_UDP_debug, + ESP32_WiFi_connect_TCP, + ESP32_WiFi_disconnect_TCP, + ESP32_WiFi_transmit_TCP, + ESP32_WiFi_receive_TCP, + ESP32_WiFi_isconnected_TCP, + ESP32_WiFiUDP_stopAll, + ESP32_WiFi_hostname, + ESP32_WiFi_clients_count, + ESP32_EEPROM_begin, + ESP32_SPI_begin, + ESP32_swSer_begin, + ESP32_swSer_enableRx, + &ESP32_Bluetooth_ops, + ESP32_Battery_setup, + ESP32_Battery_voltage, + ESP32_GNSS_PPS_Interrupt_handler, + ESP32_get_PPS_TimeMarker, + ESP32_UATSerial_begin, + ESP32_UATModule_restart, + ESP32_WDT_setup, + ESP32_WDT_fini, + ESP32_Button_setup, + ESP32_Button_loop, + ESP32_Button_fini +}; + +#endif /* ESP32 */ diff --git a/ognbase/Protocol_FANET.cpp b/ognbase/Protocol_FANET.cpp index 54ba872..83cf7b5 100644 --- a/ognbase/Protocol_FANET.cpp +++ b/ognbase/Protocol_FANET.cpp @@ -1,432 +1,431 @@ -/* - * Protocol_FANET.cpp - * - * Encoder and decoder for open FANET radio protocol - * - * URL: - * Development - https://github.com/3s1d/fanet-stm32 - * Deprecated - https://github.com/3s1d/fanet - * - * Copyright (C) 2017-2020 Linar Yusupov - * - * 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 . - */ - -#include - -#include -#include - -#include "SoftRF.h" -#include "Protocol_FANET.h" -#include "Protocol_Legacy.h" -#include "RF.h" - -#include "Log.h" - -const rf_proto_desc_t fanet_proto_desc = { - "FANET", - .type = RF_PROTOCOL_FANET, - .modulation_type = RF_MODULATION_TYPE_LORA, - .preamble_type = 0 /* INVALID FOR LORA */, - .preamble_size = 0 /* INVALID FOR LORA */, -#if defined(FANET_DEPRECATED) - .syncword = { 0x12 }, // sx127x default value, valid for FANET -#else - .syncword = { 0xF1 }, // FANET+ -#endif - .syncword_size = 1, - .net_id = 0x0000, /* not in use */ - .payload_type = RF_PAYLOAD_DIRECT, - .payload_size = FANET_PAYLOAD_SIZE, - .payload_offset = 0, - .crc_type = RF_CHECKSUM_TYPE_NONE, /* LoRa packet has built-in CRC */ - .crc_size = 0 /* INVALID FOR LORA */, - .bitrate = DR_SF7B /* CR_5 BW_250 SF_7 */, - - .deviation = 0 /* INVALID FOR LORA */, - .whitening = RF_WHITENING_NONE, - .bandwidth = 0, /* INVALID FOR LORA */ - - .tx_interval_min = FANET_TX_INTERVAL_MIN, - .tx_interval_max = FANET_TX_INTERVAL_MAX -}; - -const uint8_t aircraft_type_to_fanet[] PROGMEM = { - FANET_AIRCRAFT_TYPE_OTHER, - FANET_AIRCRAFT_TYPE_GLIDER, - FANET_AIRCRAFT_TYPE_POWERED, - FANET_AIRCRAFT_TYPE_HELICOPTER, - FANET_AIRCRAFT_TYPE_OTHER, - FANET_AIRCRAFT_TYPE_POWERED, - FANET_AIRCRAFT_TYPE_HANGGLIDER, - FANET_AIRCRAFT_TYPE_PARAGLIDER, - FANET_AIRCRAFT_TYPE_POWERED, - FANET_AIRCRAFT_TYPE_POWERED, - FANET_AIRCRAFT_TYPE_OTHER, - FANET_AIRCRAFT_TYPE_BALLOON, - FANET_AIRCRAFT_TYPE_BALLOON, - FANET_AIRCRAFT_TYPE_UAV, - FANET_AIRCRAFT_TYPE_OTHER, - FANET_AIRCRAFT_TYPE_OTHER -}; - -const uint8_t aircraft_type_from_fanet[] PROGMEM = { - AIRCRAFT_TYPE_UNKNOWN, - AIRCRAFT_TYPE_PARAGLIDER, - AIRCRAFT_TYPE_HANGGLIDER, - AIRCRAFT_TYPE_BALLOON, - AIRCRAFT_TYPE_GLIDER, - AIRCRAFT_TYPE_POWERED, - AIRCRAFT_TYPE_HELICOPTER, - AIRCRAFT_TYPE_UAV -}; - -#define AT_TO_FANET(x) (x > 15 ? \ - FANET_AIRCRAFT_TYPE_OTHER : pgm_read_byte(&aircraft_type_to_fanet[x])) - -#define AT_FROM_FANET(x) (x > 7 ? \ - AIRCRAFT_TYPE_UNKNOWN : pgm_read_byte(&aircraft_type_from_fanet[x])) - -#if defined(FANET_DEPRECATED) -/* ------------------------------------------------------------------------- */ -/* - * - * Created on: 30 Sep 2016 - * Author: sid - */ -static uint16_t coord2payload_compressed(float deg) -{ - float deg_round = roundf(deg); - bool deg_odd = ((int)deg_round) & 1; - const float decimal = deg - deg_round; - const int dec_int = constrain((int)(decimal * 32767), -16383, 16383); - - return (dec_int & 0x7FFF) | (!!deg_odd << 15); -} - -/* ------------------------------------------------------------------------- */ -/* - * Created on: 06 Dec 2017 - * Author: Linar Yusupov - */ -static float payload_compressed2coord(uint16_t payload, float ref_deg) -{ - float deg; - bool deg_odd = (payload >> 15) & 0x1; - unsigned int dec_uint = payload & 0x7FFF; - - float ref_deg_round = roundf(ref_deg); - bool ref_deg_odd = ((int)ref_deg_round) & 1; - - int dec_int = 0; - if (dec_uint <= 0x3FFF) - dec_int = (int) dec_uint; - else if (dec_uint >= 0x4001) - dec_int = (int)-1 - (int) (dec_uint ^ 0x7FFF); - - float decimal = (float) dec_int / 32767.0; - - if (deg_odd == ref_deg_odd) - deg = ref_deg_round + decimal; - else - { - if (decimal < 0) - deg = ref_deg_round + 1 + decimal; - else - deg = ref_deg_round - 1 + decimal; - } - - return deg; -} - -/* ------------------------------------------------------------------------- */ -#else - -/* ------------------------------------------------------------------------- */ -/* - * - * Created on: 30 Sep 2016 - * Author: sid - */ -static void coord2payload_absolut(float lat, float lon, uint8_t* buf) -{ - if (buf == NULL) - return; - - int32_t lat_i = roundf(lat * 93206.0f); - int32_t lon_i = roundf(lon * 46603.0f); - - buf[0] = ((uint8_t *)&lat_i)[0]; - buf[1] = ((uint8_t *)&lat_i)[1]; - buf[2] = ((uint8_t *)&lat_i)[2]; - - buf[3] = ((uint8_t *)&lon_i)[0]; - buf[4] = ((uint8_t *)&lon_i)[1]; - buf[5] = ((uint8_t *)&lon_i)[2]; -} - -/* ------------------------------------------------------------------------- */ -/* - * Created on: 06 Dec 2017 - * Author: Linar Yusupov - */ -static void payload_absolut2coord(float* lat, float* lon, uint8_t* buf) -{ - int32_t lat_i = 0; - int32_t lon_i = 0; - - if (buf == NULL || lat == NULL || lon == NULL) - return; - - ((uint8_t *)&lat_i)[0] = buf[0]; - ((uint8_t *)&lat_i)[1] = buf[1]; - ((uint8_t *)&lat_i)[2] = buf[2]; - ((uint8_t *)&lat_i)[3] = buf[2] & 0x80 ? 0xFF : 0x00; - - ((uint8_t *)&lon_i)[0] = buf[3]; - ((uint8_t *)&lon_i)[1] = buf[4]; - ((uint8_t *)&lon_i)[2] = buf[5]; - ((uint8_t *)&lon_i)[3] = buf[5] & 0x80 ? 0xFF : 0x00; - - *lat = (float) lat_i / 93206.0f; - *lon = (float) lon_i / 46603.0f; -} - -/* ------------------------------------------------------------------------- */ -#endif - -bool fanet_decode(void* fanet_pkt, ufo_t* this_aircraft, ufo_t* fop) -{ - fanet_packet_t* pkt = (fanet_packet_t *) fanet_pkt; - unsigned int altitude; - uint8_t speed_byte, climb_byte, offset_byte; - int speed_int, climb_int, offset_int; - bool rval = false; - - if (pkt->ext_header == 0 && pkt->type == 1) /* Tracking */ - - /* ignore this device own (relayed) packets */ - { - if (pkt->vendor == SOFRF_FANET_VENDOR_ID && - pkt->address == (this_aircraft->addr & 0xFFFF) /* && */ - /* pkt->forward == 1 */) - return rval; - - fop->protocol = RF_PROTOCOL_FANET; - fop->addr = (pkt->vendor << 16) | pkt->address; - -#if defined(FANET_DEPRECATED) - fop->latitude = payload_compressed2coord(pkt->latitude, this_aircraft->latitude); - fop->longitude = payload_compressed2coord(pkt->longitude, this_aircraft->longitude); -#else - payload_absolut2coord(&(fop->latitude), &(fop->longitude), - ((uint8_t *) pkt) + FANET_HEADER_SIZE); -#endif - - altitude = ((pkt->altitude_msb << 8) | pkt->altitude_lsb); - if (pkt->altitude_scale) - altitude = altitude * 4 /* -2 */; - fop->altitude = (float) altitude; - - fop->aircraft_type = AT_FROM_FANET(pkt->aircraft_type); - fop->course = (float) pkt->heading * 360.0 / 256.0; - - speed_byte = pkt->speed; - speed_int = (int) (speed_byte | (speed_byte & (1 << 6) ? 0xFFFFFF80U : 0)); - - if (pkt->speed_scale) - speed_int *= 5 /* -2 */; - fop->speed = ((float) speed_int) / (2 * _GPS_KMPH_PER_KNOT); - - climb_byte = pkt->climb; - climb_int = (int) (climb_byte | (climb_byte & (1 << 6) ? 0xFFFFFF80U : 0)); - - if (pkt->climb_scale) - climb_int *= 5 /* +-2 */; - fop->vs = ((float)climb_int) * (_GPS_FEET_PER_METER * 6.0); - -#if defined(FANET_NEXT) - offset_byte = pkt->qne_offset; - offset_int = (int) (offset_byte | (offset_byte & (1 << 6) ? 0xFFFFFF80U : 0)); - - if (pkt->qne_scale) - offset_int *= 4; - - fop->pressure_altitude = fop->altitude + (float) offset_int; -#endif - - fop->addr_type = ADDR_TYPE_FANET; - fop->timestamp = this_aircraft->timestamp; - - fop->stealth = 0; - fop->no_track = !(pkt->track_online); - - fop->ns[0] = 0; - fop->ns[1] = 0; - fop->ns[2] = 0; - fop->ns[3] = 0; - fop->ew[0] = 0; - fop->ew[1] = 0; - fop->ew[2] = 0; - fop->ew[3] = 0; -#if 0 - Serial.print(fop->addr, HEX); - Serial.print(','); - Serial.print(fop->aircraft_type, HEX); - Serial.print(','); - Serial.print(fop->latitude, 6); - Serial.print(','); - Serial.print(fop->longitude, 6); - Serial.print(','); - Serial.print(fop->altitude); - Serial.print(','); - Serial.print(fop->speed); - Serial.print(','); - Serial.print(fop->course); - Serial.println(); - Serial.flush(); -#endif - rval = true; - } - - if (pkt->ext_header == 0 && (pkt->type == 2 || pkt->type == 3 || pkt->type == 4)) /* Service */ - { - String logf = "found FANET service data"; - Logger_send_udp(&logf); - } - - return rval; -} - -size_t fanet_encode(void* fanet_pkt, ufo_t* this_aircraft) -{ - uint32_t id = this_aircraft->addr; - float lat = this_aircraft->latitude; - float lon = this_aircraft->longitude; - int16_t alt = (int16_t) this_aircraft->altitude; - unsigned int aircraft_type = this_aircraft->aircraft_type; - float speed = this_aircraft->speed * _GPS_KMPH_PER_KNOT; - float climb = this_aircraft->vs / (_GPS_FEET_PER_METER * 60.0); - float heading = this_aircraft->course; - float turnrate = 0; - int16_t alt_diff = this_aircraft->pressure_altitude == 0 ? 0 : - (int16_t) (this_aircraft->pressure_altitude - this_aircraft->altitude); - - fanet_packet_t* pkt = (fanet_packet_t *) fanet_pkt; - - pkt->ext_header = 0; - pkt->forward = 1; - pkt->type = 1; /* Tracking */ - - pkt->vendor = SOFRF_FANET_VENDOR_ID; - pkt->address = id & 0xFFFF; - -#if defined(FANET_DEPRECATED) - pkt->latitude = coord2payload_compressed(lat); - pkt->longitude = coord2payload_compressed(lon); -#else - coord2payload_absolut(lat, lon, ((uint8_t *) pkt) + FANET_HEADER_SIZE); -#endif - - pkt->track_online = (this_aircraft->no_track ? 0 : 1); - pkt->aircraft_type = AT_TO_FANET(aircraft_type); - - int altitude = constrain(alt, 0, 8190); - pkt->altitude_scale = altitude > 2047 ? (altitude = (altitude + 2) / 4, 1) : 0; - pkt->altitude_msb = (altitude & 0x700) >> 8; - pkt->altitude_lsb = (altitude & 0x0FF); - - int speed2 = constrain((int)roundf(speed * 2.0f), 0, 635); - if (speed2 > 127) - { - pkt->speed_scale = 1; - pkt->speed = ((speed2 + 2) / 5); - } - else - { - pkt->speed_scale = 0; - pkt->speed = speed2 & 0x7F; - } - - int climb10 = constrain((int)roundf(climb * 10.0f), -315, 315); - if (climb10 > 63) - { - pkt->climb_scale = 1; - pkt->climb = ((climb10 + (climb10 >= 0 ? 2 : -2)) / 5); - } - else - { - pkt->climb_scale = 0; - pkt->climb = climb10 & 0x7F; - } - - pkt->heading = constrain((int)roundf(heading * 256.0f) / 360.0f, 0, 255); - - int turnr4 = constrain((int)roundf(turnrate * 4.0f), -255, 255); - if (abs(turnr4) > 63) - { - pkt->turn_scale = 1; - pkt->turn_rate = ((turnr4 + (turnr4 >= 0 ? 2 : -2)) / 4); - } - else - { - pkt->turn_scale = 0; - pkt->turn_rate = turnr4 & 0x7F; - } - -#if defined(FANET_NEXT) - int16_t offset = constrain(alt_diff, -254, 254); - if (abs(offset) > 63) - { - pkt->qne_scale = 1; - pkt->qne_offset = ((offset + (offset >= 0 ? 2 : -2)) / 4); - } - else - { - pkt->qne_scale = 0; - pkt->qne_offset = offset & 0x7F; - } -#endif - - return sizeof(fanet_packet_t); -} - -size_t fanet_encode_sp(void* fanet_pkt_s, ufo_t* this_aircraft) -{ - - // SPB + 0 -> Gateway Temp Wind Humid Barom TBD TBD E-Header - - uint32_t id = this_aircraft->addr; - float lat = this_aircraft->latitude; - float lon = this_aircraft->longitude; - int16_t alt = (int16_t) this_aircraft->altitude; - - fanet_packet_s* spkt = (fanet_packet_s *) fanet_pkt_s; - - spkt->ext_header = 0; - spkt->forward = 1; - spkt->type = 4; /* Service */ - - spkt->vendor = SOFRF_FANET_VENDOR_ID; - spkt->address = id & 0xFFFF; - - coord2payload_absolut(lat, lon, ((uint8_t *) spkt) + FANET_HEADER_SIZE); - - spkt->header = 0b01000000; //bit 6 Temp - spkt->temperature = 0x25; //37 degrees - - - return sizeof(fanet_packet_s); -} +/* + * Protocol_FANET.cpp + * + * Encoder and decoder for open FANET radio protocol + * + * URL: + * Development - https://github.com/3s1d/fanet-stm32 + * Deprecated - https://github.com/3s1d/fanet + * + * Copyright (C) 2017-2020 Linar Yusupov + * + * 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 . + */ + +#include + +#include +#include + +#include "SoftRF.h" +#include "Protocol_FANET.h" +#include "Protocol_Legacy.h" +#include "RF.h" + +#include "Log.h" + +const rf_proto_desc_t fanet_proto_desc = { + "FANET", + .type = RF_PROTOCOL_FANET, + .modulation_type = RF_MODULATION_TYPE_LORA, + .preamble_type = 0 /* INVALID FOR LORA */, + .preamble_size = 0 /* INVALID FOR LORA */, +#if defined(FANET_DEPRECATED) + .syncword = { 0x12 }, // sx127x default value, valid for FANET +#else + .syncword = { 0xF1 }, // FANET+ +#endif + .syncword_size = 1, + .net_id = 0x0000, /* not in use */ + .payload_type = RF_PAYLOAD_DIRECT, + .payload_size = FANET_PAYLOAD_SIZE, + .payload_offset = 0, + .crc_type = RF_CHECKSUM_TYPE_NONE, /* LoRa packet has built-in CRC */ + .crc_size = 0 /* INVALID FOR LORA */, + .bitrate = DR_SF7B /* CR_5 BW_250 SF_7 */, + + .deviation = 0 /* INVALID FOR LORA */, + .whitening = RF_WHITENING_NONE, + .bandwidth = 0, /* INVALID FOR LORA */ + + .tx_interval_min = FANET_TX_INTERVAL_MIN, + .tx_interval_max = FANET_TX_INTERVAL_MAX +}; + +const uint8_t aircraft_type_to_fanet[] PROGMEM = { + FANET_AIRCRAFT_TYPE_OTHER, + FANET_AIRCRAFT_TYPE_GLIDER, + FANET_AIRCRAFT_TYPE_POWERED, + FANET_AIRCRAFT_TYPE_HELICOPTER, + FANET_AIRCRAFT_TYPE_OTHER, + FANET_AIRCRAFT_TYPE_POWERED, + FANET_AIRCRAFT_TYPE_HANGGLIDER, + FANET_AIRCRAFT_TYPE_PARAGLIDER, + FANET_AIRCRAFT_TYPE_POWERED, + FANET_AIRCRAFT_TYPE_POWERED, + FANET_AIRCRAFT_TYPE_OTHER, + FANET_AIRCRAFT_TYPE_BALLOON, + FANET_AIRCRAFT_TYPE_BALLOON, + FANET_AIRCRAFT_TYPE_UAV, + FANET_AIRCRAFT_TYPE_OTHER, + FANET_AIRCRAFT_TYPE_OTHER +}; + +const uint8_t aircraft_type_from_fanet[] PROGMEM = { + AIRCRAFT_TYPE_UNKNOWN, + AIRCRAFT_TYPE_PARAGLIDER, + AIRCRAFT_TYPE_HANGGLIDER, + AIRCRAFT_TYPE_BALLOON, + AIRCRAFT_TYPE_GLIDER, + AIRCRAFT_TYPE_POWERED, + AIRCRAFT_TYPE_HELICOPTER, + AIRCRAFT_TYPE_UAV +}; + +#define AT_TO_FANET(x) (x > 15 ? \ + FANET_AIRCRAFT_TYPE_OTHER : pgm_read_byte(&aircraft_type_to_fanet[x])) + +#define AT_FROM_FANET(x) (x > 7 ? \ + AIRCRAFT_TYPE_UNKNOWN : pgm_read_byte(&aircraft_type_from_fanet[x])) + +#if defined(FANET_DEPRECATED) +/* ------------------------------------------------------------------------- */ +/* + * + * Created on: 30 Sep 2016 + * Author: sid + */ +static uint16_t coord2payload_compressed(float deg) +{ + float deg_round = roundf(deg); + bool deg_odd = ((int)deg_round) & 1; + const float decimal = deg - deg_round; + const int dec_int = constrain((int)(decimal * 32767), -16383, 16383); + + return (dec_int & 0x7FFF) | (!!deg_odd << 15); +} + +/* ------------------------------------------------------------------------- */ +/* + * Created on: 06 Dec 2017 + * Author: Linar Yusupov + */ +static float payload_compressed2coord(uint16_t payload, float ref_deg) +{ + float deg; + bool deg_odd = (payload >> 15) & 0x1; + unsigned int dec_uint = payload & 0x7FFF; + + float ref_deg_round = roundf(ref_deg); + bool ref_deg_odd = ((int)ref_deg_round) & 1; + + int dec_int = 0; + if (dec_uint <= 0x3FFF) + dec_int = (int) dec_uint; + else if (dec_uint >= 0x4001) + dec_int = (int)-1 - (int) (dec_uint ^ 0x7FFF); + + float decimal = (float) dec_int / 32767.0; + + if (deg_odd == ref_deg_odd) + deg = ref_deg_round + decimal; + else + { + if (decimal < 0) + deg = ref_deg_round + 1 + decimal; + else + deg = ref_deg_round - 1 + decimal; + } + + return deg; +} + +/* ------------------------------------------------------------------------- */ +#else + +/* ------------------------------------------------------------------------- */ +/* + * + * Created on: 30 Sep 2016 + * Author: sid + */ +static void coord2payload_absolut(float lat, float lon, uint8_t* buf) +{ + if (buf == NULL) + return; + + int32_t lat_i = roundf(lat * 93206.0f); + int32_t lon_i = roundf(lon * 46603.0f); + + buf[0] = ((uint8_t *)&lat_i)[0]; + buf[1] = ((uint8_t *)&lat_i)[1]; + buf[2] = ((uint8_t *)&lat_i)[2]; + + buf[3] = ((uint8_t *)&lon_i)[0]; + buf[4] = ((uint8_t *)&lon_i)[1]; + buf[5] = ((uint8_t *)&lon_i)[2]; +} + +/* ------------------------------------------------------------------------- */ +/* + * Created on: 06 Dec 2017 + * Author: Linar Yusupov + */ +static void payload_absolut2coord(float* lat, float* lon, uint8_t* buf) +{ + int32_t lat_i = 0; + int32_t lon_i = 0; + + if (buf == NULL || lat == NULL || lon == NULL) + return; + + ((uint8_t *)&lat_i)[0] = buf[0]; + ((uint8_t *)&lat_i)[1] = buf[1]; + ((uint8_t *)&lat_i)[2] = buf[2]; + ((uint8_t *)&lat_i)[3] = buf[2] & 0x80 ? 0xFF : 0x00; + + ((uint8_t *)&lon_i)[0] = buf[3]; + ((uint8_t *)&lon_i)[1] = buf[4]; + ((uint8_t *)&lon_i)[2] = buf[5]; + ((uint8_t *)&lon_i)[3] = buf[5] & 0x80 ? 0xFF : 0x00; + + *lat = (float) lat_i / 93206.0f; + *lon = (float) lon_i / 46603.0f; +} + +/* ------------------------------------------------------------------------- */ +#endif + +bool fanet_decode(void* fanet_pkt, ufo_t* this_aircraft, ufo_t* fop) +{ + fanet_packet_t* pkt = (fanet_packet_t *) fanet_pkt; + unsigned int altitude; + uint8_t speed_byte, climb_byte, offset_byte; + int speed_int, climb_int, offset_int; + bool rval = false; + + if (pkt->ext_header == 0 && pkt->type == 1) /* Tracking */ + + /* ignore this device own (relayed) packets */ + { + if (pkt->vendor == SOFRF_FANET_VENDOR_ID && + pkt->address == (this_aircraft->addr & 0xFFFF) /* && */ + /* pkt->forward == 1 */) + return rval; + + fop->protocol = RF_PROTOCOL_FANET; + fop->addr = (pkt->vendor << 16) | pkt->address; + +#if defined(FANET_DEPRECATED) + fop->latitude = payload_compressed2coord(pkt->latitude, this_aircraft->latitude); + fop->longitude = payload_compressed2coord(pkt->longitude, this_aircraft->longitude); +#else + payload_absolut2coord(&(fop->latitude), &(fop->longitude), + ((uint8_t *) pkt) + FANET_HEADER_SIZE); +#endif + + altitude = ((pkt->altitude_msb << 8) | pkt->altitude_lsb); + if (pkt->altitude_scale) + altitude = altitude * 4 /* -2 */; + fop->altitude = (float) altitude; + + fop->aircraft_type = AT_FROM_FANET(pkt->aircraft_type); + fop->course = (float) pkt->heading * 360.0 / 256.0; + + speed_byte = pkt->speed; + speed_int = (int) (speed_byte | (speed_byte & (1 << 6) ? 0xFFFFFF80U : 0)); + + if (pkt->speed_scale) + speed_int *= 5 /* -2 */; + fop->speed = ((float) speed_int) / (2 * _GPS_KMPH_PER_KNOT); + + climb_byte = pkt->climb; + climb_int = (int) (climb_byte | (climb_byte & (1 << 6) ? 0xFFFFFF80U : 0)); + + if (pkt->climb_scale) + climb_int *= 5 /* +-2 */; + fop->vs = ((float)climb_int) * (_GPS_FEET_PER_METER * 6.0); + +#if defined(FANET_NEXT) + offset_byte = pkt->qne_offset; + offset_int = (int) (offset_byte | (offset_byte & (1 << 6) ? 0xFFFFFF80U : 0)); + + if (pkt->qne_scale) + offset_int *= 4; + + fop->pressure_altitude = fop->altitude + (float) offset_int; +#endif + + fop->addr_type = ADDR_TYPE_FANET; + fop->timestamp = this_aircraft->timestamp; + + fop->stealth = 0; + fop->no_track = !(pkt->track_online); + + fop->ns[0] = 0; + fop->ns[1] = 0; + fop->ns[2] = 0; + fop->ns[3] = 0; + fop->ew[0] = 0; + fop->ew[1] = 0; + fop->ew[2] = 0; + fop->ew[3] = 0; +#if 0 + Serial.print(fop->addr, HEX); + Serial.print(','); + Serial.print(fop->aircraft_type, HEX); + Serial.print(','); + Serial.print(fop->latitude, 6); + Serial.print(','); + Serial.print(fop->longitude, 6); + Serial.print(','); + Serial.print(fop->altitude); + Serial.print(','); + Serial.print(fop->speed); + Serial.print(','); + Serial.print(fop->course); + Serial.println(); + Serial.flush(); +#endif + rval = true; + } + + if (pkt->ext_header == 0 && (pkt->type == 2 || pkt->type == 3 || pkt->type == 4)) /* Service */ + { + String logf = "found FANET service data"; + Logger_send_udp(&logf); + } + + return rval; +} + +size_t fanet_encode(void* fanet_pkt, ufo_t* this_aircraft) +{ + uint32_t id = this_aircraft->addr; + float lat = this_aircraft->latitude; + float lon = this_aircraft->longitude; + int16_t alt = (int16_t) this_aircraft->altitude; + unsigned int aircraft_type = this_aircraft->aircraft_type; + float speed = this_aircraft->speed * _GPS_KMPH_PER_KNOT; + float climb = this_aircraft->vs / (_GPS_FEET_PER_METER * 60.0); + float heading = this_aircraft->course; + float turnrate = 0; + int16_t alt_diff = this_aircraft->pressure_altitude == 0 ? 0 : + (int16_t) (this_aircraft->pressure_altitude - this_aircraft->altitude); + + fanet_packet_t* pkt = (fanet_packet_t *) fanet_pkt; + + pkt->ext_header = 0; + pkt->forward = 1; + pkt->type = 1; /* Tracking */ + + pkt->vendor = SOFRF_FANET_VENDOR_ID; + pkt->address = id & 0xFFFF; + +#if defined(FANET_DEPRECATED) + pkt->latitude = coord2payload_compressed(lat); + pkt->longitude = coord2payload_compressed(lon); +#else + coord2payload_absolut(lat, lon, ((uint8_t *) pkt) + FANET_HEADER_SIZE); +#endif + + pkt->track_online = (this_aircraft->no_track ? 0 : 1); + pkt->aircraft_type = AT_TO_FANET(aircraft_type); + + int altitude = constrain(alt, 0, 8190); + pkt->altitude_scale = altitude > 2047 ? (altitude = (altitude + 2) / 4, 1) : 0; + pkt->altitude_msb = (altitude & 0x700) >> 8; + pkt->altitude_lsb = (altitude & 0x0FF); + + int speed2 = constrain((int)roundf(speed * 2.0f), 0, 635); + if (speed2 > 127) + { + pkt->speed_scale = 1; + pkt->speed = ((speed2 + 2) / 5); + } + else + { + pkt->speed_scale = 0; + pkt->speed = speed2 & 0x7F; + } + + int climb10 = constrain((int)roundf(climb * 10.0f), -315, 315); + if (climb10 > 63) + { + pkt->climb_scale = 1; + pkt->climb = ((climb10 + (climb10 >= 0 ? 2 : -2)) / 5); + } + else + { + pkt->climb_scale = 0; + pkt->climb = climb10 & 0x7F; + } + + pkt->heading = constrain((int)roundf(heading * 256.0f) / 360.0f, 0, 255); + + int turnr4 = constrain((int)roundf(turnrate * 4.0f), -255, 255); + if (abs(turnr4) > 63) + { + pkt->turn_scale = 1; + pkt->turn_rate = ((turnr4 + (turnr4 >= 0 ? 2 : -2)) / 4); + } + else + { + pkt->turn_scale = 0; + pkt->turn_rate = turnr4 & 0x7F; + } + +#if defined(FANET_NEXT) + int16_t offset = constrain(alt_diff, -254, 254); + if (abs(offset) > 63) + { + pkt->qne_scale = 1; + pkt->qne_offset = ((offset + (offset >= 0 ? 2 : -2)) / 4); + } + else + { + pkt->qne_scale = 0; + pkt->qne_offset = offset & 0x7F; + } +#endif + + return sizeof(fanet_packet_t); +} + +size_t fanet_encode_sp(void* fanet_pkt_s, ufo_t* this_aircraft) +{ + // SPB + 0 -> Gateway Temp Wind Humid Barom TBD TBD E-Header + + uint32_t id = this_aircraft->addr; + float lat = this_aircraft->latitude; + float lon = this_aircraft->longitude; + int16_t alt = (int16_t) this_aircraft->altitude; + + fanet_packet_s* spkt = (fanet_packet_s *) fanet_pkt_s; + + spkt->ext_header = 0; + spkt->forward = 1; + spkt->type = 4; /* Service */ + + spkt->vendor = SOFRF_FANET_VENDOR_ID; + spkt->address = id & 0xFFFF; + + coord2payload_absolut(lat, lon, ((uint8_t *) spkt) + FANET_HEADER_SIZE); + + spkt->header = 0b01000000; //bit 6 Temp + spkt->temperature = 0x25; //37 degrees + + + return sizeof(fanet_packet_s); +} diff --git a/ognbase/Protocol_FANET.h b/ognbase/Protocol_FANET.h index 2237126..bc5a5af 100644 --- a/ognbase/Protocol_FANET.h +++ b/ognbase/Protocol_FANET.h @@ -1,141 +1,140 @@ -/* - * - * Protocol_FANET.h - * - * Encoder and decoder for open FANET radio protocol - * URL: https://github.com/3s1d/fanet-stm32/tree/master/Src/fanet - * - * Copyright (C) 2017-2020 Linar Yusupov - * - * 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 . - */ - -#ifndef PROTOCOL_FANET_H -#define PROTOCOL_FANET_H - -/* - * FANET uses LoRa modulation - * FANET+ uses both LoRa (FANET) and FSK(FLARM) - * - * Freq: 868.2 [ 869.525 ] MHz - * Modulation: LoRa (TM) - * Parameters: BW_250 SF_7 CR_5 - */ - -#define SOFRF_FANET_VENDOR_ID 0x07 - -//#define FANET_NEXT - -enum -{ - FANET_AIRCRAFT_TYPE_OTHER, - FANET_AIRCRAFT_TYPE_PARAGLIDER, - FANET_AIRCRAFT_TYPE_HANGGLIDER, - FANET_AIRCRAFT_TYPE_BALLOON, - FANET_AIRCRAFT_TYPE_GLIDER, - FANET_AIRCRAFT_TYPE_POWERED, - FANET_AIRCRAFT_TYPE_HELICOPTER, - FANET_AIRCRAFT_TYPE_UAV -}; - -/* - * Tracking frame type (#1), - * Standard header, - * No signature, - * Broadcast - */ -typedef struct -{ - unsigned int type : 6; - unsigned int forward : 1; - unsigned int ext_header : 1; - - unsigned int vendor : 8; - unsigned int address : 16; - -#if defined(FANET_DEPRECATED) - unsigned int latitude : 16; - unsigned int longitude : 16; -#else - unsigned int latitude : 24; - unsigned int longitude : 24; -#endif - - /* units are degrees, seconds, and meter */ - unsigned int altitude_lsb : 8; /* FANET+ reported alt. comes from ext. source */ - unsigned int altitude_msb : 3; /* I assume that it is geo (GNSS) altitude */ - unsigned int altitude_scale : 1; - unsigned int aircraft_type : 3; - unsigned int track_online : 1; - - unsigned int speed : 7; - unsigned int speed_scale : 1; - - unsigned int climb : 7; - unsigned int climb_scale : 1; - - unsigned int heading : 8; - - unsigned int turn_rate : 7; - unsigned int turn_scale : 1; - -#if defined(FANET_NEXT) - unsigned int qne_offset : 7; - unsigned int qne_scale : 1; -#endif -} __attribute__((packed)) fanet_packet_t; - -typedef struct -{ - /*HEADER*/ - unsigned int type : 6; - unsigned int forward : 1; - unsigned int ext_header : 1; - - unsigned int vendor : 8; - unsigned int address : 16; - - /*TYPE 4 Service*/ - unsigned int header : 8; - unsigned int latitude : 24; - unsigned int longitude : 24; - - unsigned int temperature : 8; - unsigned int wind_heading : 8; - unsigned int s_scale : 1; - unsigned int wind_speed : 7; - unsigned int g_scale : 1; - unsigned int wind_gusts : 7; - unsigned int humidity : 8; - unsigned int barometic_lsb : 8; - unsigned int barometic_msb : 8; - -} __attribute__((packed)) fanet_packet_s; - -#define FANET_PAYLOAD_SIZE sizeof(fanet_packet_t) -#define FANET_HEADER_SIZE 4 - -/* Declared air time of FANET+ is 20-40 ms */ -#define FANET_TX_INTERVAL_MIN 2500 /* in ms */ -#define FANET_TX_INTERVAL_MAX 3500 - -extern const rf_proto_desc_t fanet_proto_desc; - -bool fanet_decode(void *, ufo_t *, ufo_t *); - -size_t fanet_encode(void *, ufo_t *); - -size_t fanet_encode_sp(void *, ufo_t *); - -#endif /* PROTOCOL_FANET_H */ +/* + * + * Protocol_FANET.h + * + * Encoder and decoder for open FANET radio protocol + * URL: https://github.com/3s1d/fanet-stm32/tree/master/Src/fanet + * + * Copyright (C) 2017-2020 Linar Yusupov + * + * 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 . + */ + +#ifndef PROTOCOL_FANET_H +#define PROTOCOL_FANET_H + +/* + * FANET uses LoRa modulation + * FANET+ uses both LoRa (FANET) and FSK(FLARM) + * + * Freq: 868.2 [ 869.525 ] MHz + * Modulation: LoRa (TM) + * Parameters: BW_250 SF_7 CR_5 + */ + +#define SOFRF_FANET_VENDOR_ID 0x07 + +//#define FANET_NEXT + +enum +{ + FANET_AIRCRAFT_TYPE_OTHER, + FANET_AIRCRAFT_TYPE_PARAGLIDER, + FANET_AIRCRAFT_TYPE_HANGGLIDER, + FANET_AIRCRAFT_TYPE_BALLOON, + FANET_AIRCRAFT_TYPE_GLIDER, + FANET_AIRCRAFT_TYPE_POWERED, + FANET_AIRCRAFT_TYPE_HELICOPTER, + FANET_AIRCRAFT_TYPE_UAV +}; + +/* + * Tracking frame type (#1), + * Standard header, + * No signature, + * Broadcast + */ +typedef struct +{ + unsigned int type : 6; + unsigned int forward : 1; + unsigned int ext_header : 1; + + unsigned int vendor : 8; + unsigned int address : 16; + +#if defined(FANET_DEPRECATED) + unsigned int latitude : 16; + unsigned int longitude : 16; +#else + unsigned int latitude : 24; + unsigned int longitude : 24; +#endif + + /* units are degrees, seconds, and meter */ + unsigned int altitude_lsb : 8; /* FANET+ reported alt. comes from ext. source */ + unsigned int altitude_msb : 3; /* I assume that it is geo (GNSS) altitude */ + unsigned int altitude_scale : 1; + unsigned int aircraft_type : 3; + unsigned int track_online : 1; + + unsigned int speed : 7; + unsigned int speed_scale : 1; + + unsigned int climb : 7; + unsigned int climb_scale : 1; + + unsigned int heading : 8; + + unsigned int turn_rate : 7; + unsigned int turn_scale : 1; + +#if defined(FANET_NEXT) + unsigned int qne_offset : 7; + unsigned int qne_scale : 1; +#endif +} __attribute__((packed)) fanet_packet_t; + +typedef struct +{ + /*HEADER*/ + unsigned int type : 6; + unsigned int forward : 1; + unsigned int ext_header : 1; + + unsigned int vendor : 8; + unsigned int address : 16; + + /*TYPE 4 Service*/ + unsigned int header : 8; + unsigned int latitude : 24; + unsigned int longitude : 24; + + unsigned int temperature : 8; + unsigned int wind_heading : 8; + unsigned int s_scale : 1; + unsigned int wind_speed : 7; + unsigned int g_scale : 1; + unsigned int wind_gusts : 7; + unsigned int humidity : 8; + unsigned int barometic_lsb : 8; + unsigned int barometic_msb : 8; +} __attribute__((packed)) fanet_packet_s; + +#define FANET_PAYLOAD_SIZE sizeof(fanet_packet_t) +#define FANET_HEADER_SIZE 4 + +/* Declared air time of FANET+ is 20-40 ms */ +#define FANET_TX_INTERVAL_MIN 2500 /* in ms */ +#define FANET_TX_INTERVAL_MAX 3500 + +extern const rf_proto_desc_t fanet_proto_desc; + +bool fanet_decode(void *, ufo_t *, ufo_t *); + +size_t fanet_encode(void *, ufo_t *); + +size_t fanet_encode_sp(void *, ufo_t *); + +#endif /* PROTOCOL_FANET_H */ diff --git a/ognbase/Protocol_Legacy.cpp b/ognbase/Protocol_Legacy.cpp index 981ad50..8765293 100644 --- a/ognbase/Protocol_Legacy.cpp +++ b/ognbase/Protocol_Legacy.cpp @@ -1,335 +1,335 @@ -/* - * Protocol_Legacy, decoder for legacy radio protocol - * Copyright (C) 2014-2015 Stanislaw Pusep - * - * Protocol_Legacy, encoder for legacy radio protocol - * Copyright (C) 2019-2020 Linar Yusupov - * - * - * 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 . - */ - -#include -#include - -#include - -#include "SoftRF.h" -#include "RF.h" -#include "Protocol_Legacy.h" -#include "EEPROM.h" -#include "Log.h" - -const rf_proto_desc_t legacy_proto_desc = { - "Legacy", - .type = RF_PROTOCOL_LEGACY, - .modulation_type = RF_MODULATION_TYPE_2FSK, - .preamble_type = LEGACY_PREAMBLE_TYPE, - .preamble_size = LEGACY_PREAMBLE_SIZE, - .syncword = LEGACY_SYNCWORD, - .syncword_size = LEGACY_SYNCWORD_SIZE, - .net_id = 0x0000, /* not in use */ - .payload_type = RF_PAYLOAD_INVERTED, - .payload_size = LEGACY_PAYLOAD_SIZE, - .payload_offset = 0, - .crc_type = LEGACY_CRC_TYPE, - .crc_size = LEGACY_CRC_SIZE, - - .bitrate = RF_BITRATE_100KBPS, - .deviation = RF_FREQUENCY_DEVIATION_50KHZ, - .whitening = RF_WHITENING_MANCHESTER, - .bandwidth = RF_RX_BANDWIDTH_SS_125KHZ, - - .tx_interval_min = LEGACY_TX_INTERVAL_MIN, - .tx_interval_max = LEGACY_TX_INTERVAL_MAX -}; - -/* http://en.wikipedia.org/wiki/XXTEA */ -void btea(uint32_t* v, int8_t n, const uint32_t key[4]) -{ - uint32_t y, z, sum; - uint32_t p, rounds, e; - - #define DELTA 0x9e3779b9 - // #define ROUNDS (6 + 52 / n) - #define ROUNDS 6 - #define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z))) - - if (n > 1) - { - /* Coding Part */ - rounds = ROUNDS; - sum = 0; - z = v[n - 1]; - do { - sum += DELTA; - e = (sum >> 2) & 3; - for (p = 0; p < n - 1; p++) { - y = v[p + 1]; - z = v[p] += MX; - } - y = v[0]; - z = v[n - 1] += MX; - } while (--rounds); - } - else if (n < -1) - { - /* Decoding Part */ - n = -n; - rounds = ROUNDS; - sum = rounds * DELTA; - y = v[0]; - do { - e = (sum >> 2) & 3; - for (p = n - 1; p > 0; p--) { - z = v[p - 1]; - y = v[p] -= MX; - } - z = v[n - 1]; - y = v[0] -= MX; - sum -= DELTA; - } while (--rounds); - } -} - -/* http://pastebin.com/YK2f8bfm */ -long obscure(uint32_t key, uint32_t seed) -{ - uint32_t m1 = seed * (key ^ (key >> 16)); - uint32_t m2 = (seed * (m1 ^ (m1 >> 16))); - return m2 ^ (m2 >> 16); -} - -static const uint32_t table[8] = LEGACY_KEY1; - -void make_key(uint32_t key[4], uint32_t timestamp, uint32_t address) -{ - int8_t i, ndx; - for (i = 0; i < 4; i++) { - ndx = ((timestamp >> 23) & 1) ? i + 4 : i; - key[i] = obscure(table[ndx] ^ ((timestamp >> 6) ^ address), LEGACY_KEY2) ^ LEGACY_KEY3; - } -} - -bool legacy_decode(void* legacy_pkt, ufo_t* this_aircraft, ufo_t* fop) -{ - String msg; - - legacy_packet_t* pkt = (legacy_packet_t *) legacy_pkt; - - float ref_lat = this_aircraft->latitude; - float ref_lon = this_aircraft->longitude; - float geo_separ = this_aircraft->geoid_separation; - uint32_t timestamp = (uint32_t) this_aircraft->timestamp; - - - uint32_t key[4]; - int ndx; - uint8_t pkt_parity=0; - - make_key(key, timestamp, (pkt->addr << 8) & 0xffffff); - btea((uint32_t *) pkt + 1, -5, key); - - for (ndx = 0; ndx < sizeof (legacy_packet_t); ndx++) - pkt_parity += parity(*(((unsigned char *) pkt) + ndx)); - if (pkt_parity % 2) - { - if (settings->nmea_p) - { - msg = "bad parity of decoded legacy packet"; - Logger_send_udp(&msg); - msg = "decoding failed"; - Logger_send_udp(&msg); - } - return false; - } - - int32_t round_lat = (int32_t) (ref_lat * 1e7) >> 7; - int32_t lat = (pkt->lat - round_lat) % (uint32_t) 0x080000; - if (lat >= 0x040000) - lat -= 0x080000; - lat = ((lat + round_lat) << 7) /* + 0x40 */; - - int32_t round_lon = (int32_t) (ref_lon * 1e7) >> 7; - int32_t lon = (pkt->lon - round_lon) % (uint32_t) 0x100000; - if (lon >= 0x080000) - lon -= 0x100000; - lon = ((lon + round_lon) << 7) /* + 0x40 */; - - int32_t ns = (pkt->ns[0] + pkt->ns[1] + pkt->ns[2] + pkt->ns[3]) / 4; - int32_t ew = (pkt->ew[0] + pkt->ew[1] + pkt->ew[2] + pkt->ew[3]) / 4; - float speed4 = sqrtf(ew * ew + ns * ns) * (1 << pkt->smult); - - float direction = 0; - if (speed4 > 0) - { - direction = atan2f(ew, ns) * 180.0 / PI; /* -180 ... 180 */ - direction = (direction >= 0.0 ? direction : direction + 360); - } - - uint16_t vs_u16 = pkt->vs; - int16_t vs_i16 = (int16_t) (vs_u16 | (vs_u16 & (1 << 9) ? 0xFC00U : 0)); - int16_t vs10 = vs_i16 << pkt->smult; - - int16_t alt = pkt->alt; /* relative to WGS84 ellipsoid */ - - fop->protocol = RF_PROTOCOL_LEGACY; - - fop->addr = pkt->addr; - fop->addr_type = pkt->addr_type; - fop->timestamp = timestamp; - fop->latitude = (float)lat / 1e7; - fop->longitude = (float)lon / 1e7; - fop->altitude = (float) alt - geo_separ; - fop->speed = speed4 / (4 * _GPS_MPS_PER_KNOT); - fop->course = direction; - fop->vs = ((float) vs10) * (_GPS_FEET_PER_METER * 6.0); - fop->aircraft_type = pkt->aircraft_type; - fop->stealth = pkt->stealth; - fop->no_track = pkt->no_track; - fop->ns[0] = pkt->ns[0]; - fop->ns[1] = pkt->ns[1]; - fop->ns[2] = pkt->ns[2]; - fop->ns[3] = pkt->ns[3]; - fop->ew[0] = pkt->ew[0]; - fop->ew[1] = pkt->ew[1]; - fop->ew[2] = pkt->ew[2]; - fop->ew[3] = pkt->ew[3]; - - return true; -} - -size_t legacy_encode(void* legacy_pkt, ufo_t* this_aircraft) -{ - legacy_packet_t* pkt = (legacy_packet_t *) legacy_pkt; - - int ndx; - uint8_t pkt_parity=0; - uint32_t key[4]; - - uint32_t id = this_aircraft->addr; - float lat = this_aircraft->latitude; - float lon = this_aircraft->longitude; - int16_t alt = (int16_t) (this_aircraft->altitude + this_aircraft->geoid_separation); - uint32_t timestamp = (uint32_t) this_aircraft->timestamp; - - float course = this_aircraft->course; - float speedf = this_aircraft->speed * _GPS_MPS_PER_KNOT; /* m/s */ - float vsf = this_aircraft->vs / (_GPS_FEET_PER_METER * 60.0); /* m/s */ - - // scale by 4, clamp to max - uint16_t speed4 = (uint16_t) roundf(speedf * 4.0f); - if (speed4 > 8 * 128 - 1) - speed4 = 8 * 128 - 1; - - // scale by 10, clamp to max - int16_t vs10 = (int16_t) roundf(vsf * 10.0f); - if (vs10 > 8 * 512 - 1) - vs10 = 8 * 512 - 1; - else if (vs10 < -8 * 512) - vs10 = -8 * 512; - - - pkt->smult = 0; - // first check horizontal speed - while ((pkt->smult < 3) && (speed4 > 128 - 1)) { - speed4 >>= 1; - pkt->smult++; - vs10 >>= 1; - } - // now check vertical speed - while ((pkt->smult < 3) && ((vs10 > 512 - 1) || (vs10 < -512))) { - vs10 >>= 1; - pkt->smult++; - speed4 >>= 1; - } - - uint8_t speed = speed4; - - int8_t ns = (int8_t) (speed * cosf(radians(course))); - int8_t ew = (int8_t) (speed * sinf(radians(course))); - - pkt->vs = vs10; - - pkt->addr = id & 0x00FFFFFF; - -#if !defined(SOFTRF_ADDRESS) - pkt->addr_type = ADDR_TYPE_FLARM; /* ADDR_TYPE_ANONYMOUS */ -#else - pkt->addr_type = (pkt->addr == SOFTRF_ADDRESS ? - ADDR_TYPE_ICAO : ADDR_TYPE_FLARM); /* ADDR_TYPE_ANONYMOUS */ -#endif - - pkt->parity = 0; - - pkt->stealth = this_aircraft->stealth; - pkt->no_track = this_aircraft->no_track; - - pkt->aircraft_type = this_aircraft->aircraft_type; - - pkt->gps = 323; - - pkt->lat = (uint32_t(lat * 1e7) >> 7) & 0x7FFFF; - pkt->lon = (uint32_t(lon * 1e7) >> 7) & 0xFFFFF; - - if (alt < 0) - { - pkt->alt = 0; // cannot be negative - } - else - { - if (alt >= (1 << 13)) - { - pkt->alt = (1 << 13) - 1; // clamp to Max - } - else - pkt->alt = alt; - } - - pkt->airborne = speed > 0 ? 1 : 0; - pkt->ns[0] = ns; - pkt->ns[1] = ns; - pkt->ns[2] = ns; - pkt->ns[3] = ns; - pkt->ew[0] = ew; - pkt->ew[1] = ew; - pkt->ew[2] = ew; - pkt->ew[3] = ew; - - pkt->_unk0 = 0; - pkt->_unk1 = 0; - pkt->_unk2 = 0; - pkt->_unk3 = 0; -// pkt->_unk4 = 0; - - for (ndx = 0; ndx < sizeof (legacy_packet_t); ndx++) - pkt_parity += parity(*(((unsigned char *) pkt) + ndx)); - - pkt->parity = (pkt_parity % 2); - - make_key(key, timestamp, (pkt->addr << 8) & 0xffffff); - -#if 0 - Serial.print(key[0]); - Serial.print(", "); - Serial.print(key[1]); - Serial.print(", "); - Serial.print(key[2]); - Serial.print(", "); - Serial.println(key[3]); -#endif - btea((uint32_t *) pkt + 1, 5, key); - - return sizeof(legacy_packet_t); -} +/* + * Protocol_Legacy, decoder for legacy radio protocol + * Copyright (C) 2014-2015 Stanislaw Pusep + * + * Protocol_Legacy, encoder for legacy radio protocol + * Copyright (C) 2019-2020 Linar Yusupov + * + * + * 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 . + */ + +#include +#include + +#include + +#include "SoftRF.h" +#include "RF.h" +#include "Protocol_Legacy.h" +#include "EEPROM.h" +#include "Log.h" + +const rf_proto_desc_t legacy_proto_desc = { + "Legacy", + .type = RF_PROTOCOL_LEGACY, + .modulation_type = RF_MODULATION_TYPE_2FSK, + .preamble_type = LEGACY_PREAMBLE_TYPE, + .preamble_size = LEGACY_PREAMBLE_SIZE, + .syncword = LEGACY_SYNCWORD, + .syncword_size = LEGACY_SYNCWORD_SIZE, + .net_id = 0x0000, /* not in use */ + .payload_type = RF_PAYLOAD_INVERTED, + .payload_size = LEGACY_PAYLOAD_SIZE, + .payload_offset = 0, + .crc_type = LEGACY_CRC_TYPE, + .crc_size = LEGACY_CRC_SIZE, + + .bitrate = RF_BITRATE_100KBPS, + .deviation = RF_FREQUENCY_DEVIATION_50KHZ, + .whitening = RF_WHITENING_MANCHESTER, + .bandwidth = RF_RX_BANDWIDTH_SS_125KHZ, + + .tx_interval_min = LEGACY_TX_INTERVAL_MIN, + .tx_interval_max = LEGACY_TX_INTERVAL_MAX +}; + +/* http://en.wikipedia.org/wiki/XXTEA */ +void btea(uint32_t* v, int8_t n, const uint32_t key[4]) +{ + uint32_t y, z, sum; + uint32_t p, rounds, e; + + #define DELTA 0x9e3779b9 + // #define ROUNDS (6 + 52 / n) + #define ROUNDS 6 + #define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z))) + + if (n > 1) + { + /* Coding Part */ + rounds = ROUNDS; + sum = 0; + z = v[n - 1]; + do { + sum += DELTA; + e = (sum >> 2) & 3; + for (p = 0; p < n - 1; p++) { + y = v[p + 1]; + z = v[p] += MX; + } + y = v[0]; + z = v[n - 1] += MX; + } while (--rounds); + } + else if (n < -1) + { + /* Decoding Part */ + n = -n; + rounds = ROUNDS; + sum = rounds * DELTA; + y = v[0]; + do { + e = (sum >> 2) & 3; + for (p = n - 1; p > 0; p--) { + z = v[p - 1]; + y = v[p] -= MX; + } + z = v[n - 1]; + y = v[0] -= MX; + sum -= DELTA; + } while (--rounds); + } +} + +/* http://pastebin.com/YK2f8bfm */ +long obscure(uint32_t key, uint32_t seed) +{ + uint32_t m1 = seed * (key ^ (key >> 16)); + uint32_t m2 = (seed * (m1 ^ (m1 >> 16))); + return m2 ^ (m2 >> 16); +} + +static const uint32_t table[8] = LEGACY_KEY1; + +void make_key(uint32_t key[4], uint32_t timestamp, uint32_t address) +{ + int8_t i, ndx; + for (i = 0; i < 4; i++) { + ndx = ((timestamp >> 23) & 1) ? i + 4 : i; + key[i] = obscure(table[ndx] ^ ((timestamp >> 6) ^ address), LEGACY_KEY2) ^ LEGACY_KEY3; + } +} + +bool legacy_decode(void* legacy_pkt, ufo_t* this_aircraft, ufo_t* fop) +{ + String msg; + + legacy_packet_t* pkt = (legacy_packet_t *) legacy_pkt; + + float ref_lat = this_aircraft->latitude; + float ref_lon = this_aircraft->longitude; + float geo_separ = this_aircraft->geoid_separation; + uint32_t timestamp = (uint32_t) this_aircraft->timestamp; + + + uint32_t key[4]; + int ndx; + uint8_t pkt_parity=0; + + make_key(key, timestamp, (pkt->addr << 8) & 0xffffff); + btea((uint32_t *) pkt + 1, -5, key); + + for (ndx = 0; ndx < sizeof (legacy_packet_t); ndx++) + pkt_parity += parity(*(((unsigned char *) pkt) + ndx)); + if (pkt_parity % 2) + { + if (settings->nmea_p) + { + msg = "bad parity of decoded legacy packet"; + Logger_send_udp(&msg); + msg = "decoding failed"; + Logger_send_udp(&msg); + } + return false; + } + + int32_t round_lat = (int32_t) (ref_lat * 1e7) >> 7; + int32_t lat = (pkt->lat - round_lat) % (uint32_t) 0x080000; + if (lat >= 0x040000) + lat -= 0x080000; + lat = ((lat + round_lat) << 7) /* + 0x40 */; + + int32_t round_lon = (int32_t) (ref_lon * 1e7) >> 7; + int32_t lon = (pkt->lon - round_lon) % (uint32_t) 0x100000; + if (lon >= 0x080000) + lon -= 0x100000; + lon = ((lon + round_lon) << 7) /* + 0x40 */; + + int32_t ns = (pkt->ns[0] + pkt->ns[1] + pkt->ns[2] + pkt->ns[3]) / 4; + int32_t ew = (pkt->ew[0] + pkt->ew[1] + pkt->ew[2] + pkt->ew[3]) / 4; + float speed4 = sqrtf(ew * ew + ns * ns) * (1 << pkt->smult); + + float direction = 0; + if (speed4 > 0) + { + direction = atan2f(ew, ns) * 180.0 / PI; /* -180 ... 180 */ + direction = (direction >= 0.0 ? direction : direction + 360); + } + + uint16_t vs_u16 = pkt->vs; + int16_t vs_i16 = (int16_t) (vs_u16 | (vs_u16 & (1 << 9) ? 0xFC00U : 0)); + int16_t vs10 = vs_i16 << pkt->smult; + + int16_t alt = pkt->alt; /* relative to WGS84 ellipsoid */ + + fop->protocol = RF_PROTOCOL_LEGACY; + + fop->addr = pkt->addr; + fop->addr_type = pkt->addr_type; + fop->timestamp = timestamp; + fop->latitude = (float)lat / 1e7; + fop->longitude = (float)lon / 1e7; + fop->altitude = (float) alt - geo_separ; + fop->speed = speed4 / (4 * _GPS_MPS_PER_KNOT); + fop->course = direction; + fop->vs = ((float) vs10) * (_GPS_FEET_PER_METER * 6.0); + fop->aircraft_type = pkt->aircraft_type; + fop->stealth = pkt->stealth; + fop->no_track = pkt->no_track; + fop->ns[0] = pkt->ns[0]; + fop->ns[1] = pkt->ns[1]; + fop->ns[2] = pkt->ns[2]; + fop->ns[3] = pkt->ns[3]; + fop->ew[0] = pkt->ew[0]; + fop->ew[1] = pkt->ew[1]; + fop->ew[2] = pkt->ew[2]; + fop->ew[3] = pkt->ew[3]; + + return true; +} + +size_t legacy_encode(void* legacy_pkt, ufo_t* this_aircraft) +{ + legacy_packet_t* pkt = (legacy_packet_t *) legacy_pkt; + + int ndx; + uint8_t pkt_parity=0; + uint32_t key[4]; + + uint32_t id = this_aircraft->addr; + float lat = this_aircraft->latitude; + float lon = this_aircraft->longitude; + int16_t alt = (int16_t) (this_aircraft->altitude + this_aircraft->geoid_separation); + uint32_t timestamp = (uint32_t) this_aircraft->timestamp; + + float course = this_aircraft->course; + float speedf = this_aircraft->speed * _GPS_MPS_PER_KNOT; /* m/s */ + float vsf = this_aircraft->vs / (_GPS_FEET_PER_METER * 60.0); /* m/s */ + + // scale by 4, clamp to max + uint16_t speed4 = (uint16_t) roundf(speedf * 4.0f); + if (speed4 > 8 * 128 - 1) + speed4 = 8 * 128 - 1; + + // scale by 10, clamp to max + int16_t vs10 = (int16_t) roundf(vsf * 10.0f); + if (vs10 > 8 * 512 - 1) + vs10 = 8 * 512 - 1; + else if (vs10 < -8 * 512) + vs10 = -8 * 512; + + + pkt->smult = 0; + // first check horizontal speed + while ((pkt->smult < 3) && (speed4 > 128 - 1)) { + speed4 >>= 1; + pkt->smult++; + vs10 >>= 1; + } + // now check vertical speed + while ((pkt->smult < 3) && ((vs10 > 512 - 1) || (vs10 < -512))) { + vs10 >>= 1; + pkt->smult++; + speed4 >>= 1; + } + + uint8_t speed = speed4; + + int8_t ns = (int8_t) (speed * cosf(radians(course))); + int8_t ew = (int8_t) (speed * sinf(radians(course))); + + pkt->vs = vs10; + + pkt->addr = id & 0x00FFFFFF; + +#if !defined(SOFTRF_ADDRESS) + pkt->addr_type = ADDR_TYPE_FLARM; /* ADDR_TYPE_ANONYMOUS */ +#else + pkt->addr_type = (pkt->addr == SOFTRF_ADDRESS ? + ADDR_TYPE_ICAO : ADDR_TYPE_FLARM); /* ADDR_TYPE_ANONYMOUS */ +#endif + + pkt->parity = 0; + + pkt->stealth = this_aircraft->stealth; + pkt->no_track = this_aircraft->no_track; + + pkt->aircraft_type = this_aircraft->aircraft_type; + + pkt->gps = 323; + + pkt->lat = (uint32_t(lat * 1e7) >> 7) & 0x7FFFF; + pkt->lon = (uint32_t(lon * 1e7) >> 7) & 0xFFFFF; + + if (alt < 0) + { + pkt->alt = 0; // cannot be negative + } + else + { + if (alt >= (1 << 13)) + { + pkt->alt = (1 << 13) - 1; // clamp to Max + } + else + pkt->alt = alt; + } + + pkt->airborne = speed > 0 ? 1 : 0; + pkt->ns[0] = ns; + pkt->ns[1] = ns; + pkt->ns[2] = ns; + pkt->ns[3] = ns; + pkt->ew[0] = ew; + pkt->ew[1] = ew; + pkt->ew[2] = ew; + pkt->ew[3] = ew; + + pkt->_unk0 = 0; + pkt->_unk1 = 0; + pkt->_unk2 = 0; + pkt->_unk3 = 0; +// pkt->_unk4 = 0; + + for (ndx = 0; ndx < sizeof (legacy_packet_t); ndx++) + pkt_parity += parity(*(((unsigned char *) pkt) + ndx)); + + pkt->parity = (pkt_parity % 2); + + make_key(key, timestamp, (pkt->addr << 8) & 0xffffff); + +#if 0 + Serial.print(key[0]); + Serial.print(", "); + Serial.print(key[1]); + Serial.print(", "); + Serial.print(key[2]); + Serial.print(", "); + Serial.println(key[3]); +#endif + btea((uint32_t *) pkt + 1, 5, key); + + return sizeof(legacy_packet_t); +} diff --git a/ognbase/RF.cpp b/ognbase/RF.cpp index 2623760..0af23e1 100644 --- a/ognbase/RF.cpp +++ b/ognbase/RF.cpp @@ -1,2293 +1,2359 @@ -/* - * RF.cpp - * Copyright (C) 2016-2020 Linar Yusupov - * - * 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 . - */ -#if defined(ARDUINO) -#include -#endif /* ARDUINO */ - -#include "RF.h" -#include "Protocol_Legacy.h" -#include "Protocol_OGNTP.h" -#include "Protocol_P3I.h" -#include "Protocol_FANET.h" -#include "Protocol_UAT978.h" -#include "SoC.h" -#include "EEPROM.h" -#include "Web.h" -#include "MAVLink.h" -#include - -#if LOGGER_IS_ENABLED -#include "LogHelper.h" -#endif /* LOGGER_IS_ENABLED */ - -byte RxBuffer[MAX_PKT_SIZE]; - -unsigned long TxTimeMarker = 0; -byte TxBuffer[MAX_PKT_SIZE]; - -uint32_t tx_packets_counter = 0; -uint32_t rx_packets_counter = 0; - -int8_t RF_last_rssi = 0; - -FreqPlan RF_FreqPlan; -static bool RF_ready = false; - -static size_t RF_tx_size = 0; -static long TxRandomValue = 0; - -const rfchip_ops_t *rf_chip = NULL; -bool RF_SX12XX_RST_is_connected = true; - -size_t (*protocol_encode)(void *, ufo_t *); -bool (*protocol_decode)(void *, ufo_t *, ufo_t *); - -static bool nrf905_probe(void); -static void nrf905_setup(void); -static void nrf905_channel(uint8_t); -static bool nrf905_receive(void); -static void nrf905_transmit(void); -static void nrf905_shutdown(void); - -static bool sx1276_probe(void); -static bool sx1262_probe(void); -static void sx12xx_setup(void); -static void sx12xx_channel(uint8_t); -static bool sx12xx_receive(void); -static void sx12xx_transmit(void); -static void sx12xx_shutdown(void); - -static bool uatm_probe(void); -static void uatm_setup(void); -static void uatm_channel(uint8_t); -static bool uatm_receive(void); -static void uatm_transmit(void); -static void uatm_shutdown(void); - -static bool cc13xx_probe(void); -static void cc13xx_setup(void); -static void cc13xx_channel(uint8_t); -static bool cc13xx_receive(void); -static void cc13xx_transmit(void); -static void cc13xx_shutdown(void); - -static bool ognrf_probe(void); -static void ognrf_setup(void); -static void ognrf_channel(uint8_t); -static bool ognrf_receive(void); -static void ognrf_transmit(void); -static void ognrf_shutdown(void); - -#if !defined(EXCLUDE_NRF905) -const rfchip_ops_t nrf905_ops = { - RF_IC_NRF905, - "NRF905", - nrf905_probe, - nrf905_setup, - nrf905_channel, - nrf905_receive, - nrf905_transmit, - nrf905_shutdown -}; -#endif -#if !defined(EXCLUDE_SX12XX) -const rfchip_ops_t sx1276_ops = { - RF_IC_SX1276, - "SX1276", - sx1276_probe, - sx12xx_setup, - sx12xx_channel, - sx12xx_receive, - sx12xx_transmit, - sx12xx_shutdown -}; -#if defined(USE_BASICMAC) -const rfchip_ops_t sx1262_ops = { - RF_IC_SX1262, - "SX1262", - sx1262_probe, - sx12xx_setup, - sx12xx_channel, - sx12xx_receive, - sx12xx_transmit, - sx12xx_shutdown -}; -#endif /* USE_BASICMAC */ -#endif /*EXCLUDE_SX12XX */ -#if !defined(EXCLUDE_UATM) -const rfchip_ops_t uatm_ops = { - RF_IC_UATM, - "UATM", - uatm_probe, - uatm_setup, - uatm_channel, - uatm_receive, - uatm_transmit, - uatm_shutdown -}; -#endif /* EXCLUDE_UATM */ -#if !defined(EXCLUDE_CC13XX) -const rfchip_ops_t cc13xx_ops = { - RF_IC_CC13XX, - "CC13XX", - cc13xx_probe, - cc13xx_setup, - cc13xx_channel, - cc13xx_receive, - cc13xx_transmit, - cc13xx_shutdown -}; -#endif /* EXCLUDE_CC13XX */ -#if defined(USE_OGN_RF_DRIVER) - -#define vTaskDelay delay - -#if defined(WITH_SI4X32) -#include -#else -#include -#endif /* WITH_SI4X32 */ - -const rfchip_ops_t ognrf_ops = { - RF_DRV_OGN, - "OGNDRV", - ognrf_probe, - ognrf_setup, - ognrf_channel, - ognrf_receive, - ognrf_transmit, - ognrf_shutdown -}; -#endif /* USE_OGN_RF_DRIVER */ - -String Bin2Hex(byte *buffer, size_t size) -{ - String str = ""; - for (int i=0; i < size; i++) { - byte c = buffer[i]; - str += (c < 0x10 ? "0" : "") + String(c, HEX); - } - return str; -} - -uint8_t parity(uint32_t x) { - uint8_t parity=0; - while (x > 0) { - if (x & 0x1) { - parity++; - } - x >>= 1; - } - return (parity % 2); -} - -byte RF_setup(void) -{ - - if (rf_chip == NULL) { -#if !defined(USE_OGN_RF_DRIVER) -#if !defined(EXCLUDE_SX12XX) -#if !defined(EXCLUDE_SX1276) - if (sx1276_ops.probe()) { - rf_chip = &sx1276_ops; -#else - if (false) { -#endif -#if defined(USE_BASICMAC) -#if !defined(EXCLUDE_SX1276) - SX12XX_LL = &sx127x_ll_ops; -#endif - } else if (sx1262_ops.probe()) { - rf_chip = &sx1262_ops; - SX12XX_LL = &sx126x_ll_ops; -#endif /* USE_BASICMAC */ -#else - if (false) { -#endif /* EXCLUDE_SX12XX */ -#if !defined(EXCLUDE_NRF905) - } else if (nrf905_ops.probe()) { - rf_chip = &nrf905_ops; -#endif /* EXCLUDE_NRF905 */ -#if !defined(EXCLUDE_UATM) - } else if (uatm_ops.probe()) { - rf_chip = &uatm_ops; -#endif /* EXCLUDE_UATM */ -#if !defined(EXCLUDE_CC13XX) - } else if (cc13xx_ops.probe()) { - rf_chip = &cc13xx_ops; -#endif /* EXCLUDE_CC13XX */ - } - if (rf_chip && rf_chip->name) { - Serial.print(rf_chip->name); - Serial.println(F(" RFIC is detected.")); - } else { - Serial.println(F("WARNING! None of supported RFICs is detected!")); - } -#else /* USE_OGN_RF_DRIVER */ - if (ognrf_ops.probe()) { - rf_chip = &ognrf_ops; - Serial.println(F("OGN_DRV: RFIC is detected.")); - } else { - Serial.println(F("WARNING! RFIC is NOT detected.")); - } -#endif /* USE_OGN_RF_DRIVER */ - } - - /* "AUTO" freq. will set the plan upon very first valid GNSS fix */ - if (settings->band == RF_BAND_AUTO) { - /* Supersede EU plan with UK when PAW is selected */ - if (rf_chip && -#if !defined(EXCLUDE_NRF905) - rf_chip != &nrf905_ops && -#endif - settings->rf_protocol == RF_PROTOCOL_P3I) { - RF_FreqPlan.setPlan(RF_BAND_UK); - } - } else { - RF_FreqPlan.setPlan(settings->band); - } - - if (rf_chip) { - rf_chip->setup(); - return rf_chip->type; - } else { - return RF_IC_NONE; - } -} - - -/* -#define DELAY_PPS_GPSTIME 200 // approx msec between PPS and time in NMEA sentence -#define SLOT1_START 400 // slot1 start msec after PPS -#define SLOT1_ADVANCE 100 // advance slot1 to mid of dead time between slots -#define SLOT2_START 800 // slot2 start msec after PPS -#define SLOT_DURATION 400 // slot msec duration - -extern int status_LED; // LEDHelper - -static long TimeReference = 0;// Hop reference timing -static long TimeReference_2 = 0; -static long Now_millis = 0; -static long prev_TimeCommit = 0; -uint8_t Slot = 0; -time_t slotTime = 0; - - -void RF_SetChannel(void) -{ - tmElements_t tm; - time_t Time; - - switch (settings->mode) - { - case SOFTRF_MODE_TXRX_TEST: - Time = now(); - break; - case SOFTRF_MODE_UAV: - Time = the_aircraft.location.gps_time_stamp / 1000000; - break; - case SOFTRF_MODE_GROUND: - case SOFTRF_MODE_NORMAL: - default: - unsigned long pps_btime_ms = SoC->get_PPS_TimeMarker(); - unsigned long time_corr_neg = 0; - unsigned long timeAge = 0; - unsigned long lastCommitTime = (Now_millis = millis()) - (timeAge = gnss.time.age()); - - // HOP Testing - NMEA sentence time commit - //Serial.printf("Commit: %d, %d, %d\r\n", lastCommitTime, prev_TimeCommit, pps_btime_ms); - - // Time could be in GGA or RMC. For consistency must pick only first one - // problem is that the second commit is 450 msec after the first or only 550 before next ! - // not needed if PPS is available - if (lastCommitTime - prev_TimeCommit < 500) - { - lastCommitTime = prev_TimeCommit; - timeAge = Now_millis - lastCommitTime; - } - else - prev_TimeCommit = lastCommitTime; - - // if PPS available, reference time is PPS relative for accuracy - if (pps_btime_ms) - { - // calculate delta time from millis() to PPS reference - if (pps_btime_ms <= lastCommitTime) - time_corr_neg = (lastCommitTime - pps_btime_ms) % 1000; - else - time_corr_neg = 1000 - ((pps_btime_ms - lastCommitTime) % 1000); - } - else // no PPS, approximate reference delay - time_corr_neg = DELAY_PPS_GPSTIME; - - // only frequency hop with legacy and OGN protocols - switch (settings->rf_protocol) - { - case RF_PROTOCOL_LEGACY: - case RF_PROTOCOL_OGNTP: - if ((Now_millis - TimeReference) >= 1000) - { - if (pps_btime_ms) - { - TimeReference = pps_btime_ms + SLOT1_START - SLOT1_ADVANCE - 0; // allow for latency ? - } - else - TimeReference = lastCommitTime - time_corr_neg + SLOT1_START - SLOT1_ADVANCE; - Slot = 0; - if ((Now_millis - TimeReference) >= 1000) // has PPS stopped ? - { - TxTimeMarker = Now_millis; // if so no Tx - return; - } - else - TxTimeMarker = TimeReference; - TxRandomValue = SoC->random(0, SLOT_DURATION - 10) + SLOT1_ADVANCE; // allow some margin - } - else - { - if ((Now_millis - TimeReference_2) >= 1000) - { - TimeReference_2 = TimeReference + SLOT_DURATION + SLOT1_ADVANCE; - Slot = 1; - TxTimeMarker = TimeReference_2; - TxRandomValue = SoC->random(10, SLOT_DURATION - 0); // allow some margin - } - else - return; - } - break; - default: - // FANET uses 868.2 MHz. Bandwidth is 250kHz - Slot = 0; - break; - } - - // HOP Testing - slot timing 400 and 800 msec after PPS - //Serial.printf("Timing: %d, %d, %d, %d, %d, %d, %d\r\n", Now_millis, pps_btime_ms, timeAge, time_corr_neg, TimeReference, TxRandomValue, Slot); - - // latest time from GPS - int yr = gnss.date.year(); - if (yr > 99) - yr = yr - 1970; - else - yr += 30; - tm.Year = yr; - tm.Month = gnss.date.month(); - tm.Day = gnss.date.day(); - tm.Hour = gnss.time.hour(); - tm.Minute = gnss.time.minute(); - tm.Second = gnss.time.second(); - - // time right now is: - slotTime = Time = makeTime(tm) + (timeAge + time_corr_neg) / 1000; - break; - } - - uint8_t OGN = (settings->rf_protocol == RF_PROTOCOL_OGNTP ? 1 : 0); - - uint8_t chan = RF_FreqPlan.getChannel(Time, Slot, OGN); - - // HOP Testing - time and channel - //Serial.printf("Time: %d, %d\r\n", Time,chan); -#if DEBUG - Serial.print("Plan: "); - Serial.println(RF_FreqPlan.Plan); - Serial.print("Slot: "); - Serial.println(Slot); - Serial.print("OGN: "); - Serial.println(OGN); - Serial.print("Channel: "); - Serial.println(chan); -#endif - - if (RF_ready && rf_chip) - rf_chip->channel(chan); -}*/ - -void RF_SetChannel(void) -{ - tmElements_t tm; - time_t Time; - - switch (settings->mode) - { - case SOFTRF_MODE_TXRX_TEST: - Time = now(); - break; - case SOFTRF_MODE_UAV: - Time = the_aircraft.location.gps_time_stamp / 1000000; - break; - case SOFTRF_MODE_GROUND: - default: - unsigned long pps_btime_ms = SoC->get_PPS_TimeMarker(); - unsigned long time_corr_pos = 0; - unsigned long time_corr_neg = 0; - - if (pps_btime_ms) { - unsigned long lastCommitTime = millis() - gnss.time.age(); - if (pps_btime_ms <= lastCommitTime) { - time_corr_neg = (lastCommitTime - pps_btime_ms) % 1000; - } else { - time_corr_neg = 1000 - ((pps_btime_ms - lastCommitTime) % 1000); - } - time_corr_pos = 400; /* 400 ms after PPS for V6, 350 ms - for OGNTP */ - } - - int yr = gnss.date.year(); - if( yr > 99) - yr = yr - 1970; - else - yr += 30; - tm.Year = yr; - tm.Month = gnss.date.month(); - tm.Day = gnss.date.day(); - tm.Hour = gnss.time.hour(); - tm.Minute = gnss.time.minute(); - tm.Second = gnss.time.second(); - - Time = makeTime(tm) + (gnss.time.age() - time_corr_neg + time_corr_pos)/ 1000; - break; - } - - uint8_t Slot = 0; /* only #0 "400ms" timeslot is currently in use */ - uint8_t OGN = (settings->rf_protocol == RF_PROTOCOL_OGNTP ? 1 : 0); - - /* FANET uses 868.2 MHz. Bandwidth is 250kHz */ - if (settings->rf_protocol == RF_PROTOCOL_FANET) { - Slot = 0; - } - - uint8_t chan = RF_FreqPlan.getChannel(Time, Slot, OGN); - - if (RF_ready && rf_chip) { - rf_chip->channel(chan); - } -} - -void RF_loop() -{ - if (!RF_ready) { - if (RF_FreqPlan.Plan == RF_BAND_AUTO) { - if (ThisAircraft.latitude || ThisAircraft.longitude) { - RF_FreqPlan.setPlan((int32_t)(ThisAircraft.latitude * 600000), - (int32_t)(ThisAircraft.longitude * 600000)); - RF_ready = true; - } - } else { - RF_ready = true; - } - } - - if (RF_ready) { - RF_SetChannel(); - } -} - -size_t RF_Encode(ufo_t *fop) -{ - size_t size = 0; - if (RF_ready && protocol_encode) { - - if (settings->txpower == RF_TX_POWER_OFF ) { - return size; - } - - if ((millis() - TxTimeMarker) > TxRandomValue) { - size = (*protocol_encode)((void *) &TxBuffer[0], fop); - } - } - return size; -} - -bool RF_Transmit(size_t size, bool wait) -{ - if (RF_ready && rf_chip && (size > 0)) { - RF_tx_size = size; - - if (settings->txpower == RF_TX_POWER_OFF ) { - return true; - } - - if (!wait || (millis() - TxTimeMarker) > TxRandomValue) { - - time_t timestamp = now(); - - rf_chip->transmit(); - - if (settings->nmea_p) { - StdOut.print(F("$PSRFO,")); - StdOut.print((unsigned long) timestamp); - StdOut.print(F(",")); - StdOut.println(Bin2Hex((byte *) &TxBuffer[0], - RF_Payload_Size(settings->rf_protocol))); - } - tx_packets_counter++; - RF_tx_size = 0; - - TxRandomValue = ( -#if !defined(EXCLUDE_SX12XX) - LMIC.protocol ? - SoC->random(LMIC.protocol->tx_interval_min, LMIC.protocol->tx_interval_max) : -#endif - SoC->random(LEGACY_TX_INTERVAL_MIN, LEGACY_TX_INTERVAL_MAX)); - - TxTimeMarker = millis(); - - return true; - } - } - return false; -} - -bool RF_Receive(void) -{ - bool rval = false; - - if (RF_ready && rf_chip) { - rval = rf_chip->receive(); - } - - return rval; -} - -void RF_Shutdown(void) -{ - if (rf_chip) { - rf_chip->shutdown(); - } -} - -uint8_t RF_Payload_Size(uint8_t protocol) -{ - switch (protocol) - { - case RF_PROTOCOL_LEGACY: return legacy_proto_desc.payload_size; - case RF_PROTOCOL_OGNTP: return ogntp_proto_desc.payload_size; - case RF_PROTOCOL_P3I: return p3i_proto_desc.payload_size; - case RF_PROTOCOL_FANET: return fanet_proto_desc.payload_size; - case RF_PROTOCOL_ADSB_UAT: return uat978_proto_desc.payload_size; - default: return 0; - } -} - -#if !defined(EXCLUDE_NRF905) -/* - * NRF905-specific code - * - * - */ - -static uint8_t nrf905_channel_prev = (uint8_t) -1; -static bool nrf905_receive_active = false; - -static bool nrf905_probe() -{ - uint8_t addr[4]; - uint8_t ref[] = TXADDR; - - digitalWrite(CSN, HIGH); - pinMode(CSN, OUTPUT); - - SoC->SPI_begin(); - -#if defined(ARDUINO) - SPI.setClockDivider(SPI_CLOCK_DIV2); -#endif /* ARDUINO */ - - digitalWrite(CSN, LOW); - - SPI.transfer(NRF905_CMD_R_TX_ADDRESS); - for(uint8_t i=4;i--;) { - addr[i] = SPI.transfer(NRF905_CMD_NOP); - } - - digitalWrite(CSN, HIGH); - pinMode(CSN, INPUT); - - SPI.end(); - -#if 0 - delay(3000); - Serial.print("NRF905 probe: "); - Serial.print(addr[0], HEX); Serial.print(" "); - Serial.print(addr[1], HEX); Serial.print(" "); - Serial.print(addr[2], HEX); Serial.print(" "); - Serial.print(addr[3], HEX); Serial.print(" "); - Serial.println(); -#endif - - /* Cold start state */ - if ((addr[0] == 0xE7) && (addr[1] == 0xE7) && (addr[2] == 0xE7) && (addr[3] == 0xE7)) { - return true; - } - - /* Warm restart state */ - if ((addr[0] == 0xE7) && (addr[1] == ref[0]) && (addr[2] == ref[1]) && (addr[3] == ref[2])) { - return true; - } - - return false; -} - -static void nrf905_channel(uint8_t channel) -{ - if (channel != nrf905_channel_prev) { - - uint32_t frequency; - nRF905_band_t band; - - frequency = RF_FreqPlan.getChanFrequency(channel); - band = (frequency >= 844800000UL ? NRF905_BAND_868 : NRF905_BAND_433); - - nRF905_setFrequency(band , frequency); - - nrf905_channel_prev = channel; - /* restart Rx upon a channel switch */ - nrf905_receive_active = false; - } -} - -static void nrf905_setup() -{ - SoC->SPI_begin(); - - // Start up - nRF905_init(); - - /* Channel selection is now part of RF_loop() */ -// nrf905_channel(channel); - - //nRF905_setTransmitPower(NRF905_PWR_10); - //nRF905_setTransmitPower(NRF905_PWR_n10); - - switch(settings->txpower) - { - case RF_TX_POWER_FULL: - - /* - * NRF905 is unable to give more than 10 dBm - * 10 dBm is legal everywhere in the world - */ - - nRF905_setTransmitPower((nRF905_pwr_t)NRF905_PWR_10); - break; - case RF_TX_POWER_OFF: - case RF_TX_POWER_LOW: - default: - nRF905_setTransmitPower((nRF905_pwr_t)NRF905_PWR_n10); - break; - } - - nRF905_setCRC(NRF905_CRC_16); - //nRF905_setCRC(NRF905_CRC_DISABLE); - - // Set address of this device - byte addr[] = RXADDR; - nRF905_setRXAddress(addr); - - /* Enforce radio settings to follow "Legacy" protocol's RF specs */ - settings->rf_protocol = RF_PROTOCOL_LEGACY; - - /* Enforce encoder and decoder to process "Legacy" frames only */ - protocol_encode = &legacy_encode; - protocol_decode = &legacy_decode; - - /* Put IC into receive mode */ - nRF905_receive(); -} - -static bool nrf905_receive() -{ - bool success = false; - - // Put into receive mode - if (!nrf905_receive_active) { - nRF905_receive(); - nrf905_receive_active = true; - } - - success = nRF905_getData(RxBuffer, LEGACY_PAYLOAD_SIZE); - if (success) { // Got data - rx_packets_counter++; - } - - if (SoC->Bluetooth) { - SoC->Bluetooth->loop(); - } - - return success; -} - -static void nrf905_transmit() -{ - nrf905_receive_active = false; - - // Set address of device to send to - byte addr[] = TXADDR; - nRF905_setTXAddress(addr); - - // Set payload data - nRF905_setData(&TxBuffer[0], LEGACY_PAYLOAD_SIZE ); - - // Send payload (send fails if other transmissions are going on, keep trying until success) - while (!nRF905_send()) { - yield(); - } ; -} - -static void nrf905_shutdown() -{ - nRF905_powerDown(); - SPI.end(); -} - -#endif /* EXCLUDE_NRF905 */ - -#if !defined(EXCLUDE_SX12XX) -/* - * SX12XX-specific code - * - * - */ - -osjob_t sx12xx_txjob; -osjob_t sx12xx_timeoutjob; - -static void sx12xx_tx_func (osjob_t* job); -static void sx12xx_rx_func (osjob_t* job); -static void sx12xx_rx(osjobcb_t func); - -static bool sx12xx_receive_complete = false; -bool sx12xx_receive_active = false; -static bool sx12xx_transmit_complete = false; - -static uint8_t sx12xx_channel_prev = (uint8_t) -1; - -#if defined(USE_BASICMAC) -void os_getDevEui (u1_t* buf) { } -u1_t os_getRegion (void) { return REGCODE_EU868; } -#else -#if !defined(DISABLE_INVERT_IQ_ON_RX) -#error This example requires DISABLE_INVERT_IQ_ON_RX to be set. Update \ - config.h in the lmic library to set it. -#endif -#endif - -#define SX1276_RegVersion 0x42 // common - -static u1_t sx1276_readReg (u1_t addr) { -#if defined(USE_BASICMAC) - hal_spi_select(1); -#else - hal_pin_nss(0); -#endif - hal_spi(addr & 0x7F); - u1_t val = hal_spi(0x00); -#if defined(USE_BASICMAC) - hal_spi_select(0); -#else - hal_pin_nss(1); -#endif - return val; -} - -static bool sx1276_probe() -{ - u1_t v, v_reset; - - SoC->SPI_begin(); - - hal_init (nullptr); - - // manually reset radio - hal_pin_rst(0); // drive RST pin low - hal_waitUntil(os_getTime()+ms2osticks(1)); // wait >100us - - v_reset = sx1276_readReg(SX1276_RegVersion); - - hal_pin_rst(2); // configure RST pin floating! - hal_waitUntil(os_getTime()+ms2osticks(5)); // wait 5ms - - v = sx1276_readReg(SX1276_RegVersion); - - pinMode(lmic_pins.nss, INPUT); - SPI.end(); - - if (v == 0x12) { - - if (v_reset == 0x12) { - RF_SX12XX_RST_is_connected = false; - } - - return true; - } else { - return false; - } -} - -#if defined(USE_BASICMAC) - -#define CMD_READREGISTER 0x1D -#define REG_LORASYNCWORDLSB 0x0741 -#define SX126X_DEF_LORASYNCWORDLSB 0x24 - -static void sx1262_ReadRegs (uint16_t addr, uint8_t* data, uint8_t len) { - hal_spi_select(1); - hal_pin_busy_wait(); - hal_spi(CMD_READREGISTER); - hal_spi(addr >> 8); - hal_spi(addr); - hal_spi(0x00); // NOP - for (uint8_t i = 0; i < len; i++) { - data[i] = hal_spi(0x00); - } - hal_spi_select(0); -} - -static uint8_t sx1262_ReadReg (uint16_t addr) { - uint8_t val; - sx1262_ReadRegs(addr, &val, 1); - return val; -} - -static bool sx1262_probe() -{ - u1_t v, v_reset; - - SoC->SPI_begin(); - - hal_init (nullptr); - - // manually reset radio - hal_pin_rst(0); // drive RST pin low - hal_waitUntil(os_getTime()+ms2osticks(1)); // wait >100us - - v_reset = sx1262_ReadReg(REG_LORASYNCWORDLSB); - - hal_pin_rst(2); // configure RST pin floating! - hal_waitUntil(os_getTime()+ms2osticks(5)); // wait 5ms - - v = sx1262_ReadReg(REG_LORASYNCWORDLSB); - - pinMode(lmic_pins.nss, INPUT); - SPI.end(); - - u1_t fanet_sw_lsb = ((fanet_proto_desc.syncword[0] & 0x0F) << 4) | 0x04; - if (v == SX126X_DEF_LORASYNCWORDLSB || v == fanet_sw_lsb) { - - if (v_reset == SX126X_DEF_LORASYNCWORDLSB || v == fanet_sw_lsb) { - RF_SX12XX_RST_is_connected = false; - } - - return true; - } else { - return false; - } -} -#endif - -static void sx12xx_channel(uint8_t channel) -{ - if (channel != sx12xx_channel_prev) { - uint32_t frequency = RF_FreqPlan.getChanFrequency(channel); - int8_t fc = settings->freq_corr; - - //Serial.print("frequency: "); Serial.println(frequency); - - if (sx12xx_receive_active) { - os_radio(RADIO_RST); - sx12xx_receive_active = false; - } - - if (rf_chip->type == RF_IC_SX1276) { - /* correction of not more than 30 kHz is allowed */ - if (fc > 30) { - fc = 30; - } else if (fc < -30) { - fc = -30; - }; - } else { - /* Most of SX1262 designs use TCXO */ - fc = 0; - } - - /* Actual RF chip's channel registers will be updated before each Tx or Rx session */ - LMIC.freq = frequency + (fc * 1000); - //LMIC.freq = 868200000UL; - - sx12xx_channel_prev = channel; - } -} - -static void sx12xx_setup() -{ - SoC->SPI_begin(); - - // initialize runtime env - os_init (nullptr); - - // Reset the MAC state. Session and pending data transfers will be discarded. - LMIC_reset(); - - - // range test. - LMIC.agcref = 0x00; - - - switch (settings->rf_protocol) - { - case RF_PROTOCOL_OGNTP: - LMIC.protocol = &ogntp_proto_desc; - protocol_encode = &ogntp_encode; - protocol_decode = &ogntp_decode; - break; - case RF_PROTOCOL_P3I: - LMIC.protocol = &p3i_proto_desc; - protocol_encode = &p3i_encode; - protocol_decode = &p3i_decode; - break; - case RF_PROTOCOL_FANET: - LMIC.protocol = &fanet_proto_desc; - protocol_encode = &fanet_encode; - protocol_decode = &fanet_decode; - break; - case RF_PROTOCOL_LEGACY: - default: - LMIC.protocol = &legacy_proto_desc; - protocol_encode = &legacy_encode; - protocol_decode = &legacy_decode; - /* - * Enforce legacy protocol setting for SX1276 - * if other value (UAT) left in EEPROM from other (UATM) radio - */ - settings->rf_protocol = RF_PROTOCOL_LEGACY; - break; - } - - switch(settings->txpower) - { - case RF_TX_POWER_FULL: - - /* Load regional max. EIRP at first */ - LMIC.txpow = RF_FreqPlan.MaxTxPower; - - if (rf_chip->type == RF_IC_SX1262) { - /* SX1262 is unable to give more than 22 dBm */ - if (LMIC.txpow > 22) - LMIC.txpow = 22; - } else { - /* SX1276 is unable to give more than 20 dBm */ - if (LMIC.txpow > 20) - LMIC.txpow = 20; - } - -#if 1 - /* - * Enforce Tx power limit until confirmation - * that RFM95W is doing well - * when antenna is not connected - */ - if (LMIC.txpow > 17) - LMIC.txpow = 17; -#endif - break; - case RF_TX_POWER_OFF: - case RF_TX_POWER_LOW: - default: - LMIC.txpow = 2; /* 2 dBm is minimum for RFM95W on PA_BOOST pin */ - break; - } -} - -static void sx12xx_setvars() -{ - if (LMIC.protocol && LMIC.protocol->modulation_type == RF_MODULATION_TYPE_LORA) { - LMIC.datarate = LMIC.protocol->bitrate; - LMIC.syncword = LMIC.protocol->syncword[0]; - } else { - LMIC.datarate = DR_FSK; - } - -#if defined(USE_BASICMAC) - -#define updr2rps LMIC_updr2rps - - // LMIC.rps = MAKERPS(sf, BW250, CR_4_5, 0, 0); - - LMIC.noRXIQinversion = true; - LMIC.rxsyms = 100; - -#endif /* USE_BASICMAC */ - - // This sets CR 4/5, BW125 (except for DR_SF7B, which uses BW250) - LMIC.rps = updr2rps(LMIC.datarate); - - - if (LMIC.protocol && LMIC.protocol->type == RF_PROTOCOL_FANET) { - /* for only a few nodes around, increase the coding rate to ensure a more robust transmission */ - LMIC.rps = setCr(LMIC.rps, CR_4_8); - } - - // set SX1276 AGC Reference - if(settings->sxlna){ - LMIC.agcref = 0x13; - // Serial.printf("setting agc ref to 0x%x\n", 0x13); - } - else{ - LMIC.agcref = 0x00; - //Serial.printf("setting agc ref to 0x%x\n", 0x00); - } - -} - -static bool sx12xx_receive() -{ - bool success = false; - - sx12xx_receive_complete = false; - - if (!sx12xx_receive_active) { - sx12xx_setvars(); - sx12xx_rx(sx12xx_rx_func); - sx12xx_receive_active = true; - } - - if (sx12xx_receive_complete == false) { - // execute scheduled jobs and events - os_runstep(); - }; - - if (SoC->Bluetooth) { - SoC->Bluetooth->loop(); - } - - if (sx12xx_receive_complete == true) { - - u1_t size = LMIC.dataLen - LMIC.protocol->payload_offset - LMIC.protocol->crc_size; - - if (size >sizeof(RxBuffer)) { - size = sizeof(RxBuffer); - } - - for (u1_t i=0; i < size; i++) { - RxBuffer[i] = LMIC.frame[i + LMIC.protocol->payload_offset]; - } - - RF_last_rssi = LMIC.rssi; - rx_packets_counter++; - success = true; - } - return success; -} - -static void sx12xx_transmit() -{ - sx12xx_transmit_complete = false; - sx12xx_receive_active = false; - - sx12xx_setvars(); - os_setCallback(&sx12xx_txjob, sx12xx_tx_func); - - while (sx12xx_transmit_complete == false) { - // execute scheduled jobs and events - os_runstep(); - - yield(); - }; -} - -static void sx12xx_shutdown() -{ - LMIC_shutdown(); - SPI.end(); -} - -// Enable rx mode and call func when a packet is received -static void sx12xx_rx(osjobcb_t func) { - LMIC.osjob.func = func; - LMIC.rxtime = os_getTime(); // RX _now_ - // Enable "continuous" RX for LoRa only (e.g. without a timeout, - // still stops after receiving a packet) - os_radio(LMIC.protocol && - LMIC.protocol->modulation_type == RF_MODULATION_TYPE_LORA ? - RADIO_RXON : RADIO_RX); - //Serial.println("RX"); -} - -static void sx12xx_rx_func (osjob_t* job) { - - u1_t crc8, pkt_crc8; - u2_t crc16, pkt_crc16; - u1_t i; - - // SX1276 is in SLEEP after IRQ handler, Force it to enter RX mode - sx12xx_receive_active = false; - - /* FANET (LoRa) LMIC IRQ handler may deliver empty packets here when CRC is invalid. */ - if (LMIC.dataLen == 0) { - return; - } - - switch (LMIC.protocol->crc_type) - { - case RF_CHECKSUM_TYPE_GALLAGER: - case RF_CHECKSUM_TYPE_NONE: - /* crc16 left not initialized */ - break; - case RF_CHECKSUM_TYPE_CRC8_107: - crc8 = 0x71; /* seed value */ - break; - case RF_CHECKSUM_TYPE_CCITT_0000: - crc16 = 0x0000; /* seed value */ - break; - case RF_CHECKSUM_TYPE_CCITT_FFFF: - default: - crc16 = 0xffff; /* seed value */ - break; - } - - //Serial.print("Got "); - //Serial.print(LMIC.dataLen); - //Serial.println(" bytes"); - - switch (LMIC.protocol->type) - { - case RF_PROTOCOL_LEGACY: - /* take in account NRF905/FLARM "address" bytes */ - crc16 = update_crc_ccitt(crc16, 0x31); - crc16 = update_crc_ccitt(crc16, 0xFA); - crc16 = update_crc_ccitt(crc16, 0xB6); - break; - case RF_PROTOCOL_P3I: - case RF_PROTOCOL_OGNTP: - default: - break; - } - - for (i = LMIC.protocol->payload_offset; - i < (LMIC.dataLen - LMIC.protocol->crc_size); - i++) - { - - switch (LMIC.protocol->crc_type) - { - case RF_CHECKSUM_TYPE_GALLAGER: - case RF_CHECKSUM_TYPE_NONE: - break; - case RF_CHECKSUM_TYPE_CRC8_107: - update_crc8(&crc8, (u1_t)(LMIC.frame[i])); - break; - case RF_CHECKSUM_TYPE_CCITT_FFFF: - case RF_CHECKSUM_TYPE_CCITT_0000: - default: - crc16 = update_crc_ccitt(crc16, (u1_t)(LMIC.frame[i])); - break; - } - - switch (LMIC.protocol->whitening) - { - case RF_WHITENING_NICERF: - LMIC.frame[i] ^= pgm_read_byte(&whitening_pattern[i - LMIC.protocol->payload_offset]); - break; - case RF_WHITENING_MANCHESTER: - case RF_WHITENING_NONE: - default: - break; - } -#if DEBUG - Serial.printf("%02x", (u1_t)(LMIC.frame[i])); -#endif - } - - switch (LMIC.protocol->crc_type) - { - case RF_CHECKSUM_TYPE_NONE: - sx12xx_receive_complete = true; - break; - case RF_CHECKSUM_TYPE_GALLAGER: - if (LDPC_Check((uint8_t *) &LMIC.frame[0])) { -#if DEBUG - Serial.printf(" %02x%02x%02x%02x%02x%02x is wrong FEC", - LMIC.frame[i], LMIC.frame[i+1], LMIC.frame[i+2], - LMIC.frame[i+3], LMIC.frame[i+4], LMIC.frame[i+5]); -#endif - sx12xx_receive_complete = false; - } else { - sx12xx_receive_complete = true; - } - break; - case RF_CHECKSUM_TYPE_CRC8_107: - pkt_crc8 = LMIC.frame[i]; -#if DEBUG - if (crc8 == pkt_crc8 ) { - Serial.printf(" %02x is valid crc", pkt_crc8); - } else { - Serial.printf(" %02x is wrong crc", pkt_crc8); - } -#endif - if (crc8 == pkt_crc8) { - sx12xx_receive_complete = true; - } else { - sx12xx_receive_complete = false; - } - break; - case RF_CHECKSUM_TYPE_CCITT_FFFF: - case RF_CHECKSUM_TYPE_CCITT_0000: - default: - pkt_crc16 = (LMIC.frame[i] << 8 | LMIC.frame[i+1]); -#if DEBUG - if (crc16 == pkt_crc16 ) { - Serial.printf(" %04x is valid crc", pkt_crc16); - } else { - Serial.printf(" %04x is wrong crc", pkt_crc16); - } -#endif - if (crc16 == pkt_crc16) { - sx12xx_receive_complete = true; - } else { - sx12xx_receive_complete = false; - } - break; - } - -#if DEBUG - Serial.println(); -#endif - -} - -// Transmit the given string and call the given function afterwards -static void sx12xx_tx(unsigned char *buf, size_t size, osjobcb_t func) { - - u1_t crc8; - u2_t crc16; - - switch (LMIC.protocol->crc_type) - { - case RF_CHECKSUM_TYPE_GALLAGER: - case RF_CHECKSUM_TYPE_NONE: - /* crc16 left not initialized */ - break; - case RF_CHECKSUM_TYPE_CRC8_107: - crc8 = 0x71; /* seed value */ - break; - case RF_CHECKSUM_TYPE_CCITT_0000: - crc16 = 0x0000; /* seed value */ - break; - case RF_CHECKSUM_TYPE_CCITT_FFFF: - default: - crc16 = 0xffff; /* seed value */ - break; - } - - os_radio(RADIO_RST); // Stop RX first - delay(1); // Wait a bit, without this os_radio below asserts, apparently because the state hasn't changed yet - - LMIC.dataLen = 0; - - switch (LMIC.protocol->type) - { - case RF_PROTOCOL_LEGACY: - /* take in account NRF905/FLARM "address" bytes */ - crc16 = update_crc_ccitt(crc16, 0x31); - crc16 = update_crc_ccitt(crc16, 0xFA); - crc16 = update_crc_ccitt(crc16, 0xB6); - break; - case RF_PROTOCOL_P3I: - /* insert Net ID */ - LMIC.frame[LMIC.dataLen++] = (u1_t) ((LMIC.protocol->net_id >> 24) & 0x000000FF); - LMIC.frame[LMIC.dataLen++] = (u1_t) ((LMIC.protocol->net_id >> 16) & 0x000000FF); - LMIC.frame[LMIC.dataLen++] = (u1_t) ((LMIC.protocol->net_id >> 8) & 0x000000FF); - LMIC.frame[LMIC.dataLen++] = (u1_t) ((LMIC.protocol->net_id >> 0) & 0x000000FF); - /* insert byte with payload size */ - LMIC.frame[LMIC.dataLen++] = LMIC.protocol->payload_size; - - /* insert byte with CRC-8 seed value when necessary */ - if (LMIC.protocol->crc_type == RF_CHECKSUM_TYPE_CRC8_107) { - LMIC.frame[LMIC.dataLen++] = crc8; - } - - break; - case RF_PROTOCOL_OGNTP: - default: - break; - } - - for (u1_t i=0; i < size; i++) { - - switch (LMIC.protocol->whitening) - { - case RF_WHITENING_NICERF: - LMIC.frame[LMIC.dataLen] = buf[i] ^ pgm_read_byte(&whitening_pattern[i]); - break; - case RF_WHITENING_MANCHESTER: - case RF_WHITENING_NONE: - default: - LMIC.frame[LMIC.dataLen] = buf[i]; - break; - } - - switch (LMIC.protocol->crc_type) - { - case RF_CHECKSUM_TYPE_GALLAGER: - case RF_CHECKSUM_TYPE_NONE: - break; - case RF_CHECKSUM_TYPE_CRC8_107: - update_crc8(&crc8, (u1_t)(LMIC.frame[LMIC.dataLen])); - break; - case RF_CHECKSUM_TYPE_CCITT_FFFF: - case RF_CHECKSUM_TYPE_CCITT_0000: - default: - crc16 = update_crc_ccitt(crc16, (u1_t)(LMIC.frame[LMIC.dataLen])); - break; - } - - LMIC.dataLen++; - } - - switch (LMIC.protocol->crc_type) - { - case RF_CHECKSUM_TYPE_GALLAGER: - case RF_CHECKSUM_TYPE_NONE: - break; - case RF_CHECKSUM_TYPE_CRC8_107: - LMIC.frame[LMIC.dataLen++] = crc8; - break; - case RF_CHECKSUM_TYPE_CCITT_FFFF: - case RF_CHECKSUM_TYPE_CCITT_0000: - default: - LMIC.frame[LMIC.dataLen++] = (crc16 >> 8) & 0xFF; - LMIC.frame[LMIC.dataLen++] = (crc16 ) & 0xFF; - break; - } - - LMIC.osjob.func = func; - os_radio(RADIO_TX); - //Serial.println("TX"); -} - -static void sx12xx_txdone_func (osjob_t* job) { - sx12xx_transmit_complete = true; -} - -static void sx12xx_tx_func (osjob_t* job) { - - if (RF_tx_size > 0) { - sx12xx_tx((unsigned char *) &TxBuffer[0], RF_tx_size, sx12xx_txdone_func); - } -} -#endif /* EXCLUDE_SX12XX */ - -#if !defined(EXCLUDE_UATM) -/* - * UATM-specific code - * - * - */ - -#include - -#define UAT_RINGBUF_SIZE (sizeof(Stratux_frame_t) * 2) - -static unsigned char uat_ringbuf[UAT_RINGBUF_SIZE]; -static unsigned int uatbuf_head = 0; -Stratux_frame_t uatradio_frame; - -const char UAT_ident[] PROGMEM = SOFTRF_IDENT; - -static bool uatm_probe() -{ - bool success = false; - unsigned long startTime; - unsigned int uatbuf_tail; - u1_t keylen = strlen_P(UAT_ident); - u1_t i=0; - - /* Do not probe on itself and ESP8266 */ - if (SoC->id == SOC_CC13XX || - SoC->id == SOC_ESP8266) { - return success; - } - - SoC->UATSerial_begin(UAT_RECEIVER_BR); - - SoC->UATModule_restart(); - - startTime = millis(); - - // Timeout if no valid response in 1 second - while (millis() - startTime < 1000) { - - if (UATSerial.available() > 0) { - unsigned char c = UATSerial.read(); -#if DEBUG - Serial.println(c, HEX); -#endif - uat_ringbuf[uatbuf_head % UAT_RINGBUF_SIZE] = c; - - uatbuf_tail = uatbuf_head - keylen; - uatbuf_head++; - - for (i=0; i < keylen; i++) { - if (pgm_read_byte(&UAT_ident[i]) != uat_ringbuf[(uatbuf_tail + i) % UAT_RINGBUF_SIZE]) { - break; - } - } - - if (i >= keylen) { - success = true; - break; - } - } - } - - /* cleanup UAT data buffer */ - uatbuf_head = 0; - memset(uat_ringbuf, 0, sizeof(uat_ringbuf)); - - /* Current ESP32 Core has a bug with Serial2.end()+Serial2.begin() cycle */ - if (SoC->id != SOC_ESP32) { - UATSerial.end(); - } - - return success; -} - -static void uatm_channel(uint8_t channel) -{ - /* Nothing to do */ -} - -static void uatm_setup() -{ - /* Current ESP32 Core has a bug with Serial2.end()+Serial2.begin() cycle */ - if (SoC->id != SOC_ESP32) { - SoC->UATSerial_begin(UAT_RECEIVER_BR); - } - - init_fec(); - - /* Enforce radio settings to follow UAT978 protocol's RF specs */ - settings->rf_protocol = RF_PROTOCOL_ADSB_UAT; - - protocol_encode = &uat978_encode; - protocol_decode = &uat978_decode; -} - -static bool uatm_receive() -{ - bool success = false; - unsigned int uatbuf_tail; - int rs_errors; - - while (UATSerial.available()) { - unsigned char c = UATSerial.read(); - - uat_ringbuf[uatbuf_head % UAT_RINGBUF_SIZE] = c; - - uatbuf_tail = uatbuf_head - sizeof(Stratux_frame_t); - uatbuf_head++; - - if (uat_ringbuf[ uatbuf_tail % UAT_RINGBUF_SIZE] == STRATUX_UATRADIO_MAGIC_1 && - uat_ringbuf[(uatbuf_tail + 1) % UAT_RINGBUF_SIZE] == STRATUX_UATRADIO_MAGIC_2 && - uat_ringbuf[(uatbuf_tail + 2) % UAT_RINGBUF_SIZE] == STRATUX_UATRADIO_MAGIC_3 && - uat_ringbuf[(uatbuf_tail + 3) % UAT_RINGBUF_SIZE] == STRATUX_UATRADIO_MAGIC_4) { - - unsigned char *pre_fec_buf = (unsigned char *) &uatradio_frame; - for (u1_t i=0; i < sizeof(Stratux_frame_t); i++) { - pre_fec_buf[i] = uat_ringbuf[(uatbuf_tail + i) % UAT_RINGBUF_SIZE]; - } - - int frame_type = correct_adsb_frame(uatradio_frame.data, &rs_errors); - - if (frame_type == -1) { - continue; - } - - u1_t size = 0; - - if (frame_type == 1) { - size = SHORT_FRAME_DATA_BYTES; - } else if (frame_type == 2) { - size = LONG_FRAME_DATA_BYTES; - } - - if (size > sizeof(RxBuffer)) { - size = sizeof(RxBuffer); - } - - if (size > 0) { - memcpy(RxBuffer, uatradio_frame.data, size); - - RF_last_rssi = uatradio_frame.rssi; - rx_packets_counter++; - success = true; - - break; - } - } - } - - return success; -} - -static void uatm_transmit() -{ - /* Nothing to do */ -} - -static void uatm_shutdown() -{ - /* Nothing to do */ -} -#endif /* EXCLUDE_UATM */ - -#if !defined(EXCLUDE_CC13XX) -/* - * CC13XX-specific code - * - * - */ - -#include "EasyLink.h" - -#include -#include -#include -#include -#include - -#define MAX_SYNCWORD_SIZE 4 - -const rf_proto_desc_t *cc13xx_protocol = &uat978_proto_desc; - -EasyLink myLink; -#if !defined(EXCLUDE_OGLEP3) -EasyLink_TxPacket txPacket; -#endif /* EXCLUDE_OGLEP3 */ - -static uint8_t cc13xx_channel_prev = (uint8_t) -1; - -static bool cc13xx_receive_complete = false; -static bool cc13xx_receive_active = false; -static bool cc13xx_transmit_complete = false; - -void cc13xx_Receive_callback(EasyLink_RxPacket *rxPacket_ptr, EasyLink_Status status) -{ - cc13xx_receive_active = false; - bool success = false; - - if (status == EasyLink_Status_Success) { - - size_t size = 0; - uint8_t offset; - - u1_t crc8, pkt_crc8; - u2_t crc16, pkt_crc16; - -#if !defined(EXCLUDE_OGLEP3) - switch (cc13xx_protocol->crc_type) - { - case RF_CHECKSUM_TYPE_GALLAGER: - case RF_CHECKSUM_TYPE_NONE: - /* crc16 left not initialized */ - break; - case RF_CHECKSUM_TYPE_CRC8_107: - crc8 = 0x71; /* seed value */ - break; - case RF_CHECKSUM_TYPE_CCITT_0000: - crc16 = 0x0000; /* seed value */ - break; - case RF_CHECKSUM_TYPE_CCITT_FFFF: - default: - crc16 = 0xffff; /* seed value */ - break; - } - - switch (cc13xx_protocol->type) - { - case RF_PROTOCOL_LEGACY: - /* take in account NRF905/FLARM "address" bytes */ - crc16 = update_crc_ccitt(crc16, 0x31); - crc16 = update_crc_ccitt(crc16, 0xFA); - crc16 = update_crc_ccitt(crc16, 0xB6); - break; - case RF_PROTOCOL_P3I: - case RF_PROTOCOL_OGNTP: - default: - break; - } -#endif /* EXCLUDE_OGLEP3 */ - - switch (cc13xx_protocol->type) - { -#if !defined(EXCLUDE_OGLEP3) - case RF_PROTOCOL_P3I: - uint8_t i; - offset = cc13xx_protocol->payload_offset; - for (i = 0; i < cc13xx_protocol->payload_size; i++) - { - update_crc8(&crc8, (u1_t)(rxPacket_ptr->payload[i + offset])); - if (i < sizeof(RxBuffer)) { - RxBuffer[i] = rxPacket_ptr->payload[i + offset] ^ - pgm_read_byte(&whitening_pattern[i]); - } - } - - pkt_crc8 = rxPacket_ptr->payload[i + offset]; - - if (crc8 == pkt_crc8) { - - success = true; - } - break; - case RF_PROTOCOL_OGNTP: - case RF_PROTOCOL_LEGACY: - offset = cc13xx_protocol->syncword_size - 4; - size = cc13xx_protocol->payload_offset + - cc13xx_protocol->payload_size + - cc13xx_protocol->payload_size + - cc13xx_protocol->crc_size + - cc13xx_protocol->crc_size; - if (rxPacket_ptr->len >= size + offset && - rxPacket_ptr->payload[0] == cc13xx_protocol->syncword[4] && - rxPacket_ptr->payload[1] == cc13xx_protocol->syncword[5] && - rxPacket_ptr->payload[2] == cc13xx_protocol->syncword[6] && - (offset > 3 ? (rxPacket_ptr->payload[3] == cc13xx_protocol->syncword[7]) : true)) { - - uint8_t i, val1, val2; - for (i = 0; i < size; i++) { - val1 = pgm_read_byte(&ManchesterDecode[rxPacket_ptr->payload[i + offset]]); - i++; - val2 = pgm_read_byte(&ManchesterDecode[rxPacket_ptr->payload[i + offset]]); - if ((i>>1) < sizeof(RxBuffer)) { - RxBuffer[i>>1] = ((val1 & 0x0F) << 4) | (val2 & 0x0F); - - if (i < size - (cc13xx_protocol->crc_size + cc13xx_protocol->crc_size)) { - switch (cc13xx_protocol->crc_type) - { - case RF_CHECKSUM_TYPE_GALLAGER: - case RF_CHECKSUM_TYPE_NONE: - break; - case RF_CHECKSUM_TYPE_CCITT_FFFF: - case RF_CHECKSUM_TYPE_CCITT_0000: - default: - crc16 = update_crc_ccitt(crc16, (u1_t)(RxBuffer[i>>1])); - break; - } - } - } - } - - switch (cc13xx_protocol->crc_type) - { - case RF_CHECKSUM_TYPE_GALLAGER: - if (LDPC_Check((uint8_t *) &RxBuffer[0]) == 0) { - - success = true; - } - break; - case RF_CHECKSUM_TYPE_CCITT_FFFF: - case RF_CHECKSUM_TYPE_CCITT_0000: - offset = cc13xx_protocol->payload_offset + cc13xx_protocol->payload_size; - if (offset + 1 < sizeof(RxBuffer)) { - pkt_crc16 = (RxBuffer[offset] << 8 | RxBuffer[offset+1]); - if (crc16 == pkt_crc16) { - - success = true; - } - } - break; - default: - break; - } - } - break; -#endif /* EXCLUDE_OGLEP3 */ - case RF_PROTOCOL_ADSB_UAT: - default: - int rs_errors; - int frame_type; - frame_type = correct_adsb_frame(rxPacket_ptr->payload, &rs_errors); - - if (frame_type != -1) { - - if (frame_type == 1) { - size = SHORT_FRAME_DATA_BYTES; - } else if (frame_type == 2) { - size = LONG_FRAME_DATA_BYTES; - } - - if (size > sizeof(RxBuffer)) { - size = sizeof(RxBuffer); - } - - if (size > 0) { - memcpy(RxBuffer, rxPacket_ptr->payload, size); - - success = true; - } - } - break; - } - - if (success) { - RF_last_rssi = rxPacket_ptr->rssi; - rx_packets_counter++; - - cc13xx_receive_complete = true; - } - } -} - -void cc13xx_Transmit_callback(EasyLink_Status status) -{ - if (status == EasyLink_Status_Success) { - cc13xx_transmit_complete = true; - } -} - -static bool cc13xx_Receive_Async() -{ - bool success = false; - EasyLink_Status status; - - if (!cc13xx_receive_active) { - status = myLink.receive(&cc13xx_Receive_callback); - - if (status == EasyLink_Status_Success) { - cc13xx_receive_active = true; - } - } - - if (cc13xx_receive_complete == true) { - success = true; - cc13xx_receive_complete = false; - } - - return success; -} - -static bool cc13xx_probe() -{ - bool success = false; - - if (SoC->id == SOC_CC13XX) { - success = true; - } - - return success; -} - -static void cc13xx_channel(uint8_t channel) -{ -#if !defined(EXCLUDE_OGLEP3) - if (settings->rf_protocol != RF_PROTOCOL_ADSB_UAT && - channel != cc13xx_channel_prev) { - uint32_t frequency = RF_FreqPlan.getChanFrequency(channel); - - if (cc13xx_receive_active) { - /* restart Rx upon a channel switch */ - EasyLink_abort(); - cc13xx_receive_active = false; - } - - EasyLink_setFrequency(frequency); - - cc13xx_channel_prev = channel; - } -#endif /* EXCLUDE_OGLEP3 */ -} - -static void cc13xx_setup() -{ - switch (settings->rf_protocol) - { -#if !defined(EXCLUDE_OGLEP3) - case RF_PROTOCOL_OGNTP: - cc13xx_protocol = &ogntp_proto_desc; - protocol_encode = &ogntp_encode; - protocol_decode = &ogntp_decode; - - myLink.begin(EasyLink_Phy_100kbps2gfsk_ogntp); - break; - case RF_PROTOCOL_P3I: - cc13xx_protocol = &p3i_proto_desc; - protocol_encode = &p3i_encode; - protocol_decode = &p3i_decode; - - myLink.begin(EasyLink_Phy_38400bps2gfsk_p3i); - break; - case RF_PROTOCOL_LEGACY: - cc13xx_protocol = &legacy_proto_desc; - protocol_encode = &legacy_encode; - protocol_decode = &legacy_decode; - - myLink.begin(EasyLink_Phy_100kbps2gfsk_legacy); - break; -#endif /* EXCLUDE_OGLEP3 */ - case RF_PROTOCOL_ADSB_UAT: - default: - cc13xx_protocol = &uat978_proto_desc; - protocol_encode = &uat978_encode; - protocol_decode = &uat978_decode; - /* - * Enforce UAT protocol setting - * if other value (FANET) left in EEPROM from other (SX12XX) radio - */ - settings->rf_protocol = RF_PROTOCOL_ADSB_UAT; - - init_fec(); - myLink.begin(EasyLink_Phy_Custom); - break; - } - - /* -10 dBm is a minumum for CC1310 ; CC1352 can operate down to -20 dBm */ - int8_t TxPower = -10; - - switch(settings->txpower) - { - case RF_TX_POWER_FULL: - - if (settings->rf_protocol != RF_PROTOCOL_ADSB_UAT) { - /* Load regional max. EIRP at first */ - TxPower = RF_FreqPlan.MaxTxPower; - } - - if (TxPower > 14) - TxPower = 14; /* 'high power' CC13XXP (up to 20 dBm) is not supported yet */ - - break; - case RF_TX_POWER_OFF: - case RF_TX_POWER_LOW: - default: - break; - } - - EasyLink_setRfPwr(TxPower); -} - -static bool cc13xx_receive() -{ - return cc13xx_Receive_Async(); -} - -static void cc13xx_transmit() -{ -#if !defined(EXCLUDE_OGLEP3) - EasyLink_Status status; - - u1_t crc8; - u2_t crc16; - u1_t i; - - if (RF_tx_size <= 0) { - return; - } - - if (cc13xx_protocol->type == RF_PROTOCOL_ADSB_UAT) { - return; /* no transmit on UAT */ - } - - EasyLink_abort(); - - cc13xx_receive_active = false; - cc13xx_transmit_complete = false; - - size_t PayloadLen = 0; - - switch (cc13xx_protocol->crc_type) - { - case RF_CHECKSUM_TYPE_GALLAGER: - case RF_CHECKSUM_TYPE_NONE: - /* crc16 left not initialized */ - break; - case RF_CHECKSUM_TYPE_CRC8_107: - crc8 = 0x71; /* seed value */ - break; - case RF_CHECKSUM_TYPE_CCITT_0000: - crc16 = 0x0000; /* seed value */ - break; - case RF_CHECKSUM_TYPE_CCITT_FFFF: - default: - crc16 = 0xffff; /* seed value */ - break; - } - - for (i = MAX_SYNCWORD_SIZE; i < cc13xx_protocol->syncword_size; i++) - { - txPacket.payload[PayloadLen++] = cc13xx_protocol->syncword[i]; - } - - switch (cc13xx_protocol->type) - { - case RF_PROTOCOL_LEGACY: - /* take in account NRF905/FLARM "address" bytes */ - crc16 = update_crc_ccitt(crc16, 0x31); - crc16 = update_crc_ccitt(crc16, 0xFA); - crc16 = update_crc_ccitt(crc16, 0xB6); - break; - case RF_PROTOCOL_P3I: - /* insert Net ID */ - txPacket.payload[PayloadLen++] = (u1_t) ((cc13xx_protocol->net_id >> 24) & 0x000000FF); - txPacket.payload[PayloadLen++] = (u1_t) ((cc13xx_protocol->net_id >> 16) & 0x000000FF); - txPacket.payload[PayloadLen++] = (u1_t) ((cc13xx_protocol->net_id >> 8) & 0x000000FF); - txPacket.payload[PayloadLen++] = (u1_t) ((cc13xx_protocol->net_id >> 0) & 0x000000FF); - /* insert byte with payload size */ - txPacket.payload[PayloadLen++] = cc13xx_protocol->payload_size; - - /* insert byte with CRC-8 seed value when necessary */ - if (cc13xx_protocol->crc_type == RF_CHECKSUM_TYPE_CRC8_107) { - txPacket.payload[PayloadLen++] = crc8; - } - - break; - case RF_PROTOCOL_OGNTP: - default: - break; - } - - for (i=0; i < RF_tx_size; i++) { - - switch (cc13xx_protocol->whitening) - { - case RF_WHITENING_NICERF: - txPacket.payload[PayloadLen] = TxBuffer[i] ^ pgm_read_byte(&whitening_pattern[i]); - break; - case RF_WHITENING_MANCHESTER: - txPacket.payload[PayloadLen] = pgm_read_byte(&ManchesterEncode[(TxBuffer[i] >> 4) & 0x0F]); - PayloadLen++; - txPacket.payload[PayloadLen] = pgm_read_byte(&ManchesterEncode[(TxBuffer[i] ) & 0x0F]); - break; - case RF_WHITENING_NONE: - default: - txPacket.payload[PayloadLen] = TxBuffer[i]; - break; - } - - switch (cc13xx_protocol->crc_type) - { - case RF_CHECKSUM_TYPE_GALLAGER: - case RF_CHECKSUM_TYPE_NONE: - break; - case RF_CHECKSUM_TYPE_CRC8_107: - update_crc8(&crc8, (u1_t)(txPacket.payload[PayloadLen])); - break; - case RF_CHECKSUM_TYPE_CCITT_FFFF: - case RF_CHECKSUM_TYPE_CCITT_0000: - default: - if (cc13xx_protocol->whitening == RF_WHITENING_MANCHESTER) { - crc16 = update_crc_ccitt(crc16, (u1_t)(TxBuffer[i])); - } else { - crc16 = update_crc_ccitt(crc16, (u1_t)(txPacket.payload[PayloadLen])); - } - break; - } - - PayloadLen++; - } - - switch (cc13xx_protocol->crc_type) - { - case RF_CHECKSUM_TYPE_GALLAGER: - case RF_CHECKSUM_TYPE_NONE: - break; - case RF_CHECKSUM_TYPE_CRC8_107: - txPacket.payload[PayloadLen++] = crc8; - break; - case RF_CHECKSUM_TYPE_CCITT_FFFF: - case RF_CHECKSUM_TYPE_CCITT_0000: - default: - if (cc13xx_protocol->whitening == RF_WHITENING_MANCHESTER) { - txPacket.payload[PayloadLen++] = pgm_read_byte(&ManchesterEncode[(((crc16 >> 8) & 0xFF) >> 4) & 0x0F]); - txPacket.payload[PayloadLen++] = pgm_read_byte(&ManchesterEncode[(((crc16 >> 8) & 0xFF) ) & 0x0F]); - txPacket.payload[PayloadLen++] = pgm_read_byte(&ManchesterEncode[(((crc16 ) & 0xFF) >> 4) & 0x0F]); - txPacket.payload[PayloadLen++] = pgm_read_byte(&ManchesterEncode[(((crc16 ) & 0xFF) ) & 0x0F]); - PayloadLen++; - } else { - txPacket.payload[PayloadLen++] = (crc16 >> 8) & 0xFF; - txPacket.payload[PayloadLen++] = (crc16 ) & 0xFF; - } - break; - } - - txPacket.len = PayloadLen; - // Transmit immediately - txPacket.absTime = EasyLink_ms_To_RadioTime(0); - -#if 0 - status = myLink.transmit(&txPacket, &cc13xx_Transmit_callback); - - if (status == EasyLink_Status_Success) { - while (cc13xx_transmit_complete == false) { - yield(); - }; - } -#else - myLink.transmit(&txPacket); -#endif - -#endif /* EXCLUDE_OGLEP3 */ -} - -static void cc13xx_shutdown() -{ - EasyLink_abort(); -} -#endif /* EXCLUDE_CC13XX */ - -#if defined(USE_OGN_RF_DRIVER) -/* - * OGN driver specific code - * - * - */ - -static RFM_TRX TRX; - -static uint8_t ognrf_channel_prev = (uint8_t) -1; -static bool ognrf_receive_active = false; - -void RFM_Select (void) { hal_pin_nss(0); } -void RFM_Deselect(void) { hal_pin_nss(1); } -uint8_t RFM_TransferByte(uint8_t Byte) { return hal_spi(Byte); } - -bool RFM_IRQ_isOn(void) { return lmic_pins.dio[0] == LMIC_UNUSED_PIN ? \ - false : digitalRead(lmic_pins.dio[0]); } - -#ifdef WITH_RFM95 // RESET is active LOW -void RFM_RESET(uint8_t On) -{ if(On) hal_pin_rst(0); - else hal_pin_rst(1); } -#endif - -#if defined(WITH_RFM69) || defined(WITH_SX1272) // RESET is active HIGH -void RFM_RESET(uint8_t On) -{ if(On) hal_pin_rst(1); - else hal_pin_rst(0); } -#endif - -static bool ognrf_probe() -{ - bool success = false; - - TRX.Select = RFM_Select; - TRX.Deselect = RFM_Deselect; - TRX.TransferByte = RFM_TransferByte; - TRX.RESET = RFM_RESET; - - SoC->SPI_begin(); - hal_init (nullptr); - - TRX.RESET(1); // RESET active - vTaskDelay(10); // wait 10ms - TRX.RESET(0); // RESET released - vTaskDelay(10); // wait 10ms - - uint8_t ChipVersion = TRX.ReadVersion(); - - pinMode(lmic_pins.nss, INPUT); - SPI.end(); - -#if defined(WITH_RFM95) - if (ChipVersion == 0x12) success = true; -#endif /* WITH_RFM95 */ -#if defined(WITH_RFM69) - if (ChipVersion == 0x24) success = true; -#endif /* WITH_RFM69 */ -#if defined(WITH_SX1272) - if (ChipVersion == 0x22) success = true; -#endif /* WITH_SX1272 */ -#if defined(WITH_SI4X32) - if (ChipVersion == 0x06 /* 4032 */ || - ChipVersion == 0x08 /* 4432 */ ) success = true; -#endif /* WITH_SI4X32 */ - - return success; -} - -static void ognrf_channel(uint8_t channel) -{ - if (channel != ognrf_channel_prev) { - - if (ognrf_receive_active) { - - TRX.WriteMode(RF_OPMODE_STANDBY); - vTaskDelay(1); - - /* restart Rx upon a channel switch */ - ognrf_receive_active = false; - } - - TRX.setChannel(channel & 0x7F); - - ognrf_channel_prev = channel; - } -} - -static void ognrf_setup() -{ - uint8_t TxPower = 0; - - /* Enforce radio settings to follow OGNTP protocol's RF specs */ - settings->rf_protocol = RF_PROTOCOL_OGNTP; - - LMIC.protocol = &ogntp_proto_desc; - - protocol_encode = &ogntp_encode; - protocol_decode = &ogntp_decode; - - TRX.Select = RFM_Select; - TRX.Deselect = RFM_Deselect; - TRX.TransferByte = RFM_TransferByte; - TRX.DIO0_isOn = RFM_IRQ_isOn; - TRX.RESET = RFM_RESET; - - SoC->SPI_begin(); - hal_init (nullptr); - - TRX.RESET(1); // RESET active - vTaskDelay(10); // wait 10ms - TRX.RESET(0); // RESET released - vTaskDelay(10); // wait 10ms - - // set TRX base frequency and channel separation - TRX.setBaseFrequency(RF_FreqPlan.BaseFreq); - TRX.setChannelSpacing(RF_FreqPlan.ChanSepar); - TRX.setFrequencyCorrection(0); - - TRX.Configure(0, ogntp_proto_desc.syncword); // setup RF chip parameters and set to channel #0 - TRX.WriteMode(RF_OPMODE_STANDBY); // set RF chip mode to STANDBY - - switch(settings->txpower) - { - case RF_TX_POWER_FULL: - - /* Load regional max. EIRP at first */ - TxPower = RF_FreqPlan.MaxTxPower; - - if (TxPower > 20) - TxPower = 20; -#if 1 - if (TxPower > 17) - TxPower = 17; -#endif - -#ifdef WITH_RFM69 - TRX.WriteTxPower(TxPower, RFM69_POWER_RATING == 1 ? true : false); -#else - TRX.WriteTxPower(TxPower); -#endif /* WITH_RFM69 */ - break; - case RF_TX_POWER_OFF: - case RF_TX_POWER_LOW: - default: - TRX.WriteTxPowerMin(); - break; - } - - /* Leave IC in standby mode */ -} - -static bool ognrf_receive() -{ - bool success = false; - -#if !defined(WITH_SI4X32) - - uint8_t RxRSSI = 0; - uint8_t Err [OGNTP_PAYLOAD_SIZE + OGNTP_CRC_SIZE]; - - // Put into receive mode - if (!ognrf_receive_active) { - -// TRX.ClearIrqFlags(); - - TRX.WriteSYNC(7, 7, ogntp_proto_desc.syncword); // Shorter SYNC for RX - TRX.WriteMode(RF_OPMODE_RECEIVER); - vTaskDelay(1); - - ognrf_receive_active = true; - } - - if(TRX.DIO0_isOn()) { - RxRSSI = TRX.ReadRSSI(); - - TRX.ReadPacket(RxBuffer, Err); - if (LDPC_Check((uint8_t *) RxBuffer) == 0) { - success = true; - } - } - - if (success) { - RF_last_rssi = RxRSSI; - rx_packets_counter++; - } - -#endif /* WITH_SI4X32 */ - - if (SoC->Bluetooth) { - SoC->Bluetooth->loop(); - } - - return success; -} - -static void ognrf_transmit() -{ - ognrf_receive_active = false; - -#if defined(WITH_SI4X32) - - TRX.WritePacket((uint8_t *) &TxBuffer[0]); - TRX.Transmit(); - vTaskDelay(6); - -#else - - TRX.WriteMode(RF_OPMODE_STANDBY); - vTaskDelay(1); - - TRX.WriteSYNC(8, 7, ogntp_proto_desc.syncword); // Full SYNC for TX - - TRX.ClearIrqFlags(); - TRX.WritePacket((uint8_t *) &TxBuffer[0]); - - TRX.WriteMode(RF_OPMODE_TRANSMITTER); - vTaskDelay(5); - - uint8_t Break=0; - for(uint16_t Wait=400; Wait; Wait--) // wait for transmission to end - { - uint16_t Flags=TRX.ReadIrqFlags(); - if(Flags&RF_IRQ_PacketSent) Break++; - if(Break>=2) break; - } - - TRX.WriteMode(RF_OPMODE_STANDBY); - -#endif /* WITH_SI4X32 */ -} - -static void ognrf_shutdown() -{ - TRX.WriteMode(RF_OPMODE_STANDBY); - SPI.end(); -} - -#endif /* USE_OGN_RF_DRIVER */ +/* + * RF.cpp + * Copyright (C) 2016-2020 Linar Yusupov + * + * 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 . + */ +#if defined(ARDUINO) +#include +#endif /* ARDUINO */ + +#include "RF.h" +#include "Protocol_Legacy.h" +#include "Protocol_OGNTP.h" +#include "Protocol_P3I.h" +#include "Protocol_FANET.h" +#include "Protocol_UAT978.h" +#include "SoC.h" +#include "EEPROM.h" +#include "Web.h" +#include "MAVLink.h" +#include "global.h" +#include + +#if LOGGER_IS_ENABLED +#include "LogHelper.h" +#endif /* LOGGER_IS_ENABLED */ + +byte RxBuffer[MAX_PKT_SIZE]; + +unsigned long TxTimeMarker = 0; +byte TxBuffer[MAX_PKT_SIZE]; + +uint32_t tx_packets_counter = 0; +uint32_t rx_packets_counter = 0; + +int8_t RF_last_rssi = 0; + +FreqPlan RF_FreqPlan; +static bool RF_ready = false; + +static size_t RF_tx_size = 0; +static long TxRandomValue = 0; + +const rfchip_ops_t* rf_chip = NULL; +bool RF_SX12XX_RST_is_connected = true; + +size_t (* protocol_encode)(void *, ufo_t *); +bool (* protocol_decode)(void *, ufo_t *, ufo_t *); + +static bool nrf905_probe(void); + +static void nrf905_setup(void); + +static void nrf905_channel(uint8_t); +static bool nrf905_receive(void); + +static void nrf905_transmit(void); + +static void nrf905_shutdown(void); + +static bool sx1276_probe(void); + +static bool sx1262_probe(void); + +static void sx12xx_setup(void); + +static void sx12xx_channel(uint8_t); +static bool sx12xx_receive(void); + +static void sx12xx_transmit(void); + +static void sx12xx_shutdown(void); + +static bool uatm_probe(void); + +static void uatm_setup(void); + +static void uatm_channel(uint8_t); +static bool uatm_receive(void); + +static void uatm_transmit(void); + +static void uatm_shutdown(void); + +static bool cc13xx_probe(void); + +static void cc13xx_setup(void); + +static void cc13xx_channel(uint8_t); +static bool cc13xx_receive(void); + +static void cc13xx_transmit(void); + +static void cc13xx_shutdown(void); + +static bool ognrf_probe(void); + +static void ognrf_setup(void); + +static void ognrf_channel(uint8_t); +static bool ognrf_receive(void); + +static void ognrf_transmit(void); + +static void ognrf_shutdown(void); + +#if !defined(EXCLUDE_NRF905) +const rfchip_ops_t nrf905_ops = { + RF_IC_NRF905, + "NRF905", + nrf905_probe, + nrf905_setup, + nrf905_channel, + nrf905_receive, + nrf905_transmit, + nrf905_shutdown +}; +#endif +#if !defined(EXCLUDE_SX12XX) +const rfchip_ops_t sx1276_ops = { + RF_IC_SX1276, + "SX1276", + sx1276_probe, + sx12xx_setup, + sx12xx_channel, + sx12xx_receive, + sx12xx_transmit, + sx12xx_shutdown +}; +#if defined(USE_BASICMAC) +const rfchip_ops_t sx1262_ops = { + RF_IC_SX1262, + "SX1262", + sx1262_probe, + sx12xx_setup, + sx12xx_channel, + sx12xx_receive, + sx12xx_transmit, + sx12xx_shutdown +}; +#endif /* USE_BASICMAC */ +#endif /*EXCLUDE_SX12XX */ +#if !defined(EXCLUDE_UATM) +const rfchip_ops_t uatm_ops = { + RF_IC_UATM, + "UATM", + uatm_probe, + uatm_setup, + uatm_channel, + uatm_receive, + uatm_transmit, + uatm_shutdown +}; +#endif /* EXCLUDE_UATM */ +#if !defined(EXCLUDE_CC13XX) +const rfchip_ops_t cc13xx_ops = { + RF_IC_CC13XX, + "CC13XX", + cc13xx_probe, + cc13xx_setup, + cc13xx_channel, + cc13xx_receive, + cc13xx_transmit, + cc13xx_shutdown +}; +#endif /* EXCLUDE_CC13XX */ +#if defined(USE_OGN_RF_DRIVER) + +#define vTaskDelay delay + +#if defined(WITH_SI4X32) +#include +#else +#include +#endif /* WITH_SI4X32 */ + +const rfchip_ops_t ognrf_ops = { + RF_DRV_OGN, + "OGNDRV", + ognrf_probe, + ognrf_setup, + ognrf_channel, + ognrf_receive, + ognrf_transmit, + ognrf_shutdown +}; +#endif /* USE_OGN_RF_DRIVER */ + +String Bin2Hex(byte* buffer, size_t size) +{ + String str = ""; + for (int i=0; i < size; i++) { + byte c = buffer[i]; + str += (c < 0x10 ? "0" : "") + String(c, HEX); + } + return str; +} + +uint8_t parity(uint32_t x) +{ + uint8_t parity=0; + while (x > 0) { + if (x & 0x1) + parity++; + x >>= 1; + } + return parity % 2; +} + +byte RF_setup(void) +{ + if (rf_chip == NULL) + { +#if !defined(USE_OGN_RF_DRIVER) +#if !defined(EXCLUDE_SX12XX) +#if !defined(EXCLUDE_SX1276) + if (sx1276_ops.probe()) + { + rf_chip = &sx1276_ops; +#else + if (false) + { +#endif +#if defined(USE_BASICMAC) +#if !defined(EXCLUDE_SX1276) + SX12XX_LL = &sx127x_ll_ops; +#endif + } + else if (sx1262_ops.probe()) + { + rf_chip = &sx1262_ops; + SX12XX_LL = &sx126x_ll_ops; +#endif /* USE_BASICMAC */ +#else + if (false) + { +#endif /* EXCLUDE_SX12XX */ +#if !defined(EXCLUDE_NRF905) + } + else if (nrf905_ops.probe()) + { + rf_chip = &nrf905_ops; +#endif /* EXCLUDE_NRF905 */ +#if !defined(EXCLUDE_UATM) + } + else if (uatm_ops.probe()) + { + rf_chip = &uatm_ops; +#endif /* EXCLUDE_UATM */ +#if !defined(EXCLUDE_CC13XX) + } + else if (cc13xx_ops.probe()) + { + rf_chip = &cc13xx_ops; +#endif /* EXCLUDE_CC13XX */ + } + if (rf_chip && rf_chip->name) + { + Serial.print(rf_chip->name); + Serial.println(F(" RFIC is detected.")); + } + else + Serial.println(F("WARNING! None of supported RFICs is detected!")); + +#else /* USE_OGN_RF_DRIVER */ + if (ognrf_ops.probe()) + { + rf_chip = &ognrf_ops; + Serial.println(F("OGN_DRV: RFIC is detected.")); + } + else + Serial.println(F("WARNING! RFIC is NOT detected.")); + +#endif /* USE_OGN_RF_DRIVER */ + } + + /* "AUTO" freq. will set the plan upon very first valid GNSS fix */ + if (ogn_band == RF_BAND_AUTO) + { + /* Supersede EU plan with UK when PAW is selected */ + if (rf_chip && +#if !defined(EXCLUDE_NRF905) + rf_chip != &nrf905_ops && +#endif + ogn_protocol_1 == RF_PROTOCOL_P3I) + RF_FreqPlan.setPlan(RF_BAND_UK); + } + else + RF_FreqPlan.setPlan(ogn_band); + + if (rf_chip) + { + rf_chip->setup(); + return rf_chip->type; + } + else + return RF_IC_NONE; +} + +/* + #define DELAY_PPS_GPSTIME 200 // approx msec between PPS and time in NMEA sentence + #define SLOT1_START 400 // slot1 start msec after PPS + #define SLOT1_ADVANCE 100 // advance slot1 to mid of dead time between slots + #define SLOT2_START 800 // slot2 start msec after PPS + #define SLOT_DURATION 400 // slot msec duration + + extern int status_LED; // LEDHelper + + static long TimeReference = 0;// Hop reference timing + static long TimeReference_2 = 0; + static long Now_millis = 0; + static long prev_TimeCommit = 0; + uint8_t Slot = 0; + time_t slotTime = 0; + + + void RF_SetChannel(void) + { + tmElements_t tm; + time_t Time; + + switch (settings->mode) + { + case SOFTRF_MODE_TXRX_TEST: + Time = now(); + break; + case SOFTRF_MODE_UAV: + Time = the_aircraft.location.gps_time_stamp / 1000000; + break; + case SOFTRF_MODE_GROUND: + case SOFTRF_MODE_NORMAL: + default: + unsigned long pps_btime_ms = SoC->get_PPS_TimeMarker(); + unsigned long time_corr_neg = 0; + unsigned long timeAge = 0; + unsigned long lastCommitTime = (Now_millis = millis()) - (timeAge = gnss.time.age()); + + // HOP Testing - NMEA sentence time commit + //Serial.printf("Commit: %d, %d, %d\r\n", lastCommitTime, prev_TimeCommit, pps_btime_ms); + + // Time could be in GGA or RMC. For consistency must pick only first one + // problem is that the second commit is 450 msec after the first or only 550 before next ! + // not needed if PPS is available + if (lastCommitTime - prev_TimeCommit < 500) + { + lastCommitTime = prev_TimeCommit; + timeAge = Now_millis - lastCommitTime; + } + else + prev_TimeCommit = lastCommitTime; + + // if PPS available, reference time is PPS relative for accuracy + if (pps_btime_ms) + { + // calculate delta time from millis() to PPS reference + if (pps_btime_ms <= lastCommitTime) + time_corr_neg = (lastCommitTime - pps_btime_ms) % 1000; + else + time_corr_neg = 1000 - ((pps_btime_ms - lastCommitTime) % 1000); + } + else // no PPS, approximate reference delay + time_corr_neg = DELAY_PPS_GPSTIME; + + // only frequency hop with legacy and OGN protocols + switch (ogn_protocol_1) + { + case RF_PROTOCOL_LEGACY: + case RF_PROTOCOL_OGNTP: + if ((Now_millis - TimeReference) >= 1000) + { + if (pps_btime_ms) + { + TimeReference = pps_btime_ms + SLOT1_START - SLOT1_ADVANCE - 0; // allow for latency ? + } + else + TimeReference = lastCommitTime - time_corr_neg + SLOT1_START - SLOT1_ADVANCE; + Slot = 0; + if ((Now_millis - TimeReference) >= 1000) // has PPS stopped ? + { + TxTimeMarker = Now_millis; // if so no Tx + return; + } + else + TxTimeMarker = TimeReference; + TxRandomValue = SoC->random(0, SLOT_DURATION - 10) + SLOT1_ADVANCE; // allow some margin + } + else + { + if ((Now_millis - TimeReference_2) >= 1000) + { + TimeReference_2 = TimeReference + SLOT_DURATION + SLOT1_ADVANCE; + Slot = 1; + TxTimeMarker = TimeReference_2; + TxRandomValue = SoC->random(10, SLOT_DURATION - 0); // allow some margin + } + else + return; + } + break; + default: + // FANET uses 868.2 MHz. Bandwidth is 250kHz + Slot = 0; + break; + } + + // HOP Testing - slot timing 400 and 800 msec after PPS + //Serial.printf("Timing: %d, %d, %d, %d, %d, %d, %d\r\n", Now_millis, pps_btime_ms, timeAge, time_corr_neg, TimeReference, TxRandomValue, Slot); + + // latest time from GPS + int yr = gnss.date.year(); + if (yr > 99) + yr = yr - 1970; + else + yr += 30; + tm.Year = yr; + tm.Month = gnss.date.month(); + tm.Day = gnss.date.day(); + tm.Hour = gnss.time.hour(); + tm.Minute = gnss.time.minute(); + tm.Second = gnss.time.second(); + + // time right now is: + slotTime = Time = makeTime(tm) + (timeAge + time_corr_neg) / 1000; + break; + } + + uint8_t OGN = (ogn_protocol_1 == RF_PROTOCOL_OGNTP ? 1 : 0); + + uint8_t chan = RF_FreqPlan.getChannel(Time, Slot, OGN); + + // HOP Testing - time and channel + //Serial.printf("Time: %d, %d\r\n", Time,chan); + #if DEBUG + Serial.print("Plan: "); + Serial.println(RF_FreqPlan.Plan); + Serial.print("Slot: "); + Serial.println(Slot); + Serial.print("OGN: "); + Serial.println(OGN); + Serial.print("Channel: "); + Serial.println(chan); + #endif + + if (RF_ready && rf_chip) + rf_chip->channel(chan); + }*/ + +void RF_SetChannel(void) +{ + tmElements_t tm; + time_t Time; + + switch (settings->mode) + { + case SOFTRF_MODE_TXRX_TEST: + Time = now(); + break; + case SOFTRF_MODE_UAV: + Time = the_aircraft.location.gps_time_stamp / 1000000; + break; + case SOFTRF_MODE_GROUND: + default: + unsigned long pps_btime_ms = SoC->get_PPS_TimeMarker(); + unsigned long time_corr_pos = 0; + unsigned long time_corr_neg = 0; + + if (pps_btime_ms) + { + unsigned long lastCommitTime = millis() - gnss.time.age(); + if (pps_btime_ms <= lastCommitTime) + time_corr_neg = (lastCommitTime - pps_btime_ms) % 1000; + else + time_corr_neg = 1000 - ((pps_btime_ms - lastCommitTime) % 1000); + time_corr_pos = 400; /* 400 ms after PPS for V6, 350 ms - for OGNTP */ + } + + int yr = gnss.date.year(); + if (yr > 99) + yr = yr - 1970; + else + yr += 30; + tm.Year = yr; + tm.Month = gnss.date.month(); + tm.Day = gnss.date.day(); + tm.Hour = gnss.time.hour(); + tm.Minute = gnss.time.minute(); + tm.Second = gnss.time.second(); + + Time = makeTime(tm) + (gnss.time.age() - time_corr_neg + time_corr_pos) / 1000; + break; + } + + uint8_t Slot = 0; /* only #0 "400ms" timeslot is currently in use */ + uint8_t OGN = (ogn_protocol_1 == RF_PROTOCOL_OGNTP ? 1 : 0); + + /* FANET uses 868.2 MHz. Bandwidth is 250kHz */ + if (ogn_protocol_1 == RF_PROTOCOL_FANET) + Slot = 0; + + uint8_t chan = RF_FreqPlan.getChannel(Time, Slot, OGN); + + if (RF_ready && rf_chip) + rf_chip->channel(chan); +} + +void RF_loop() +{ + if (!RF_ready) + { + if (RF_FreqPlan.Plan == RF_BAND_AUTO) + { + if (ThisAircraft.latitude || ThisAircraft.longitude) + { + RF_FreqPlan.setPlan((int32_t)(ThisAircraft.latitude * 600000), + (int32_t)(ThisAircraft.longitude * 600000)); + RF_ready = true; + } + } + else + RF_ready = true; + } + + if (RF_ready) + RF_SetChannel(); +} + +size_t RF_Encode(ufo_t* fop) +{ + size_t size = 0; + if (RF_ready && protocol_encode) + { + if (settings->txpower == RF_TX_POWER_OFF) + return size; + + if ((millis() - TxTimeMarker) > TxRandomValue) + size = (*protocol_encode)((void *) &TxBuffer[0], fop); + } + return size; +} + +bool RF_Transmit(size_t size, bool wait) +{ + if (RF_ready && rf_chip && (size > 0)) + { + RF_tx_size = size; + + if (settings->txpower == RF_TX_POWER_OFF) + return true; + + if (!wait || (millis() - TxTimeMarker) > TxRandomValue) + { + time_t timestamp = now(); + + rf_chip->transmit(); + + if (settings->nmea_p) + { + StdOut.print(F("$PSRFO,")); + StdOut.print((unsigned long) timestamp); + StdOut.print(F(",")); + StdOut.println(Bin2Hex((byte *) &TxBuffer[0], + RF_Payload_Size(ogn_protocol_1))); + } + tx_packets_counter++; + RF_tx_size = 0; + + TxRandomValue = ( +#if !defined(EXCLUDE_SX12XX) + LMIC.protocol ? + SoC->random(LMIC.protocol->tx_interval_min, LMIC.protocol->tx_interval_max) : +#endif + SoC->random(LEGACY_TX_INTERVAL_MIN, LEGACY_TX_INTERVAL_MAX)); + + TxTimeMarker = millis(); + + return true; + } + } + return false; +} + +bool RF_Receive(void) +{ + bool rval = false; + + if (RF_ready && rf_chip) + rval = rf_chip->receive(); + + return rval; +} + +void RF_Shutdown(void) +{ + if (rf_chip) + rf_chip->shutdown(); +} + +uint8_t RF_Payload_Size(uint8_t protocol) +{ + switch (protocol) + { + case RF_PROTOCOL_LEGACY: + return legacy_proto_desc.payload_size; + case RF_PROTOCOL_OGNTP: + return ogntp_proto_desc.payload_size; + case RF_PROTOCOL_P3I: + return p3i_proto_desc.payload_size; + case RF_PROTOCOL_FANET: + return fanet_proto_desc.payload_size; + case RF_PROTOCOL_ADSB_UAT: + return uat978_proto_desc.payload_size; + default: + return 0; + } +} + +#if !defined(EXCLUDE_NRF905) +/* + * NRF905-specific code + * + * + */ + +static uint8_t nrf905_channel_prev = (uint8_t) -1; +static bool nrf905_receive_active = false; + +static bool nrf905_probe() +{ + uint8_t addr[4]; + uint8_t ref[] = TXADDR; + + digitalWrite(CSN, HIGH); + pinMode(CSN, OUTPUT); + + SoC->SPI_begin(); + +#if defined(ARDUINO) + SPI.setClockDivider(SPI_CLOCK_DIV2); +#endif /* ARDUINO */ + + digitalWrite(CSN, LOW); + + SPI.transfer(NRF905_CMD_R_TX_ADDRESS); + for (uint8_t i=4; i--;) + addr[i] = SPI.transfer(NRF905_CMD_NOP); + + digitalWrite(CSN, HIGH); + pinMode(CSN, INPUT); + + SPI.end(); + +#if 0 + delay(3000); + Serial.print("NRF905 probe: "); + Serial.print(addr[0], HEX); + Serial.print(" "); + Serial.print(addr[1], HEX); + Serial.print(" "); + Serial.print(addr[2], HEX); + Serial.print(" "); + Serial.print(addr[3], HEX); + Serial.print(" "); + Serial.println(); +#endif + + /* Cold start state */ + if ((addr[0] == 0xE7) && (addr[1] == 0xE7) && (addr[2] == 0xE7) && (addr[3] == 0xE7)) + return true; + + /* Warm restart state */ + if ((addr[0] == 0xE7) && (addr[1] == ref[0]) && (addr[2] == ref[1]) && (addr[3] == ref[2])) + return true; + + return false; +} + +static void nrf905_channel(uint8_t channel) +{ + if (channel != nrf905_channel_prev) + { + uint32_t frequency; + nRF905_band_t band; + + frequency = RF_FreqPlan.getChanFrequency(channel); + band = (frequency >= 844800000UL ? NRF905_BAND_868 : NRF905_BAND_433); + + nRF905_setFrequency(band, frequency); + + nrf905_channel_prev = channel; + /* restart Rx upon a channel switch */ + nrf905_receive_active = false; + } +} + +static void nrf905_setup() +{ + SoC->SPI_begin(); + + // Start up + nRF905_init(); + + /* Channel selection is now part of RF_loop() */ +// nrf905_channel(channel); + + //nRF905_setTransmitPower(NRF905_PWR_10); + //nRF905_setTransmitPower(NRF905_PWR_n10); + + switch (settings->txpower) + { + case RF_TX_POWER_FULL: + + /* + * NRF905 is unable to give more than 10 dBm + * 10 dBm is legal everywhere in the world + */ + + nRF905_setTransmitPower((nRF905_pwr_t)NRF905_PWR_10); + break; + case RF_TX_POWER_OFF: + case RF_TX_POWER_LOW: + default: + nRF905_setTransmitPower((nRF905_pwr_t)NRF905_PWR_n10); + break; + } + + nRF905_setCRC(NRF905_CRC_16); + //nRF905_setCRC(NRF905_CRC_DISABLE); + + // Set address of this device + byte addr[] = RXADDR; + nRF905_setRXAddress(addr); + + /* Enforce radio settings to follow "Legacy" protocol's RF specs */ + ogn_protocol_1 = RF_PROTOCOL_LEGACY; + + /* Enforce encoder and decoder to process "Legacy" frames only */ + protocol_encode = &legacy_encode; + protocol_decode = &legacy_decode; + + /* Put IC into receive mode */ + nRF905_receive(); +} + +static bool nrf905_receive() +{ + bool success = false; + + // Put into receive mode + if (!nrf905_receive_active) + { + nRF905_receive(); + nrf905_receive_active = true; + } + + success = nRF905_getData(RxBuffer, LEGACY_PAYLOAD_SIZE); + if (success) // Got data + rx_packets_counter++; + + if (SoC->Bluetooth) + SoC->Bluetooth->loop(); + + return success; +} + +static void nrf905_transmit() +{ + nrf905_receive_active = false; + + // Set address of device to send to + byte addr[] = TXADDR; + nRF905_setTXAddress(addr); + + // Set payload data + nRF905_setData(&TxBuffer[0], LEGACY_PAYLOAD_SIZE); + + // Send payload (send fails if other transmissions are going on, keep trying until success) + while (!nRF905_send()) { + yield(); + }; +} + +static void nrf905_shutdown() +{ + nRF905_powerDown(); + SPI.end(); +} + +#endif /* EXCLUDE_NRF905 */ + +#if !defined(EXCLUDE_SX12XX) +/* + * SX12XX-specific code + * + * + */ + +osjob_t sx12xx_txjob; +osjob_t sx12xx_timeoutjob; + +static void sx12xx_tx_func(osjob_t* job); + +static void sx12xx_rx_func(osjob_t* job); + +static void sx12xx_rx(osjobcb_t func); + +static bool sx12xx_receive_complete = false; +bool sx12xx_receive_active = false; +static bool sx12xx_transmit_complete = false; + +static uint8_t sx12xx_channel_prev = (uint8_t) -1; + +#if defined(USE_BASICMAC) +void os_getDevEui(u1_t* buf) +{ } +u1_t os_getRegion(void) +{ + return REGCODE_EU868; +} + +#else +#if !defined(DISABLE_INVERT_IQ_ON_RX) +#error This example requires DISABLE_INVERT_IQ_ON_RX to be set. Update \ + config.h in the lmic library to set it. +#endif +#endif + +#define SX1276_RegVersion 0x42 // common + +static u1_t sx1276_readReg(u1_t addr) +{ +#if defined(USE_BASICMAC) + hal_spi_select(1); +#else + hal_pin_nss(0); +#endif + hal_spi(addr & 0x7F); + u1_t val = hal_spi(0x00); +#if defined(USE_BASICMAC) + hal_spi_select(0); +#else + hal_pin_nss(1); +#endif + return val; +} + +static bool sx1276_probe() +{ + u1_t v, v_reset; + + SoC->SPI_begin(); + + hal_init(nullptr); + + // manually reset radio + hal_pin_rst(0); // drive RST pin low + hal_waitUntil(os_getTime() + ms2osticks(1)); // wait >100us + + v_reset = sx1276_readReg(SX1276_RegVersion); + + hal_pin_rst(2); // configure RST pin floating! + hal_waitUntil(os_getTime() + ms2osticks(5)); // wait 5ms + + v = sx1276_readReg(SX1276_RegVersion); + + pinMode(lmic_pins.nss, INPUT); + SPI.end(); + + if (v == 0x12) + { + if (v_reset == 0x12) + RF_SX12XX_RST_is_connected = false; + + return true; + } + else + return false; +} + +#if defined(USE_BASICMAC) + +#define CMD_READREGISTER 0x1D +#define REG_LORASYNCWORDLSB 0x0741 +#define SX126X_DEF_LORASYNCWORDLSB 0x24 + +static void sx1262_ReadRegs(uint16_t addr, uint8_t* data, uint8_t len) +{ + hal_spi_select(1); + hal_pin_busy_wait(); + hal_spi(CMD_READREGISTER); + hal_spi(addr >> 8); + hal_spi(addr); + hal_spi(0x00); // NOP + for (uint8_t i = 0; i < len; i++) + data[i] = hal_spi(0x00); + hal_spi_select(0); +} + +static uint8_t sx1262_ReadReg(uint16_t addr) +{ + uint8_t val; + sx1262_ReadRegs(addr, &val, 1); + return val; +} + +static bool sx1262_probe() +{ + u1_t v, v_reset; + + SoC->SPI_begin(); + + hal_init(nullptr); + + // manually reset radio + hal_pin_rst(0); // drive RST pin low + hal_waitUntil(os_getTime() + ms2osticks(1)); // wait >100us + + v_reset = sx1262_ReadReg(REG_LORASYNCWORDLSB); + + hal_pin_rst(2); // configure RST pin floating! + hal_waitUntil(os_getTime() + ms2osticks(5)); // wait 5ms + + v = sx1262_ReadReg(REG_LORASYNCWORDLSB); + + pinMode(lmic_pins.nss, INPUT); + SPI.end(); + + u1_t fanet_sw_lsb = ((fanet_proto_desc.syncword[0] & 0x0F) << 4) | 0x04; + if (v == SX126X_DEF_LORASYNCWORDLSB || v == fanet_sw_lsb) + { + if (v_reset == SX126X_DEF_LORASYNCWORDLSB || v == fanet_sw_lsb) + RF_SX12XX_RST_is_connected = false; + + return true; + } + else + return false; +} + +#endif + +static void sx12xx_channel(uint8_t channel) +{ + if (channel != sx12xx_channel_prev) + { + uint32_t frequency = RF_FreqPlan.getChanFrequency(channel); + int8_t fc = settings->freq_corr; + + //Serial.print("frequency: "); Serial.println(frequency); + + if (sx12xx_receive_active) + { + os_radio(RADIO_RST); + sx12xx_receive_active = false; + } + + if (rf_chip->type == RF_IC_SX1276) + { + /* correction of not more than 30 kHz is allowed */ + if (fc > 30) + fc = 30; + else if (fc < -30) + fc = -30; + ; + } + else + /* Most of SX1262 designs use TCXO */ + fc = 0; + + /* Actual RF chip's channel registers will be updated before each Tx or Rx session */ + LMIC.freq = frequency + (fc * 1000); + //LMIC.freq = 868200000UL; + + sx12xx_channel_prev = channel; + } +} + +static void sx12xx_setup() +{ + SoC->SPI_begin(); + + // initialize runtime env + os_init(nullptr); + + // Reset the MAC state. Session and pending data transfers will be discarded. + LMIC_reset(); + + + // range test. + LMIC.agcref = 0x00; + + + switch (ogn_protocol_1) + { + case RF_PROTOCOL_OGNTP: + LMIC.protocol = &ogntp_proto_desc; + protocol_encode = &ogntp_encode; + protocol_decode = &ogntp_decode; + break; + case RF_PROTOCOL_P3I: + LMIC.protocol = &p3i_proto_desc; + protocol_encode = &p3i_encode; + protocol_decode = &p3i_decode; + break; + case RF_PROTOCOL_FANET: + LMIC.protocol = &fanet_proto_desc; + protocol_encode = &fanet_encode; + protocol_decode = &fanet_decode; + break; + case RF_PROTOCOL_LEGACY: + default: + LMIC.protocol = &legacy_proto_desc; + protocol_encode = &legacy_encode; + protocol_decode = &legacy_decode; + /* + * Enforce legacy protocol setting for SX1276 + * if other value (UAT) left in EEPROM from other (UATM) radio + */ + ogn_protocol_1 = RF_PROTOCOL_LEGACY; + break; + } + + switch (settings->txpower) + { + case RF_TX_POWER_FULL: + + /* Load regional max. EIRP at first */ + LMIC.txpow = RF_FreqPlan.MaxTxPower; + + if (rf_chip->type == RF_IC_SX1262) + { + /* SX1262 is unable to give more than 22 dBm */ + if (LMIC.txpow > 22) + LMIC.txpow = 22; + } + else + /* SX1276 is unable to give more than 20 dBm */ + if (LMIC.txpow > 20) + LMIC.txpow = 20; + +#if 1 + /* + * Enforce Tx power limit until confirmation + * that RFM95W is doing well + * when antenna is not connected + */ + if (LMIC.txpow > 17) + LMIC.txpow = 17; +#endif + break; + case RF_TX_POWER_OFF: + case RF_TX_POWER_LOW: + default: + LMIC.txpow = 2; /* 2 dBm is minimum for RFM95W on PA_BOOST pin */ + break; + } +} + +static void sx12xx_setvars() +{ + if (LMIC.protocol && LMIC.protocol->modulation_type == RF_MODULATION_TYPE_LORA) + { + LMIC.datarate = LMIC.protocol->bitrate; + LMIC.syncword = LMIC.protocol->syncword[0]; + } + else + LMIC.datarate = DR_FSK; + +#if defined(USE_BASICMAC) + +#define updr2rps LMIC_updr2rps + + // LMIC.rps = MAKERPS(sf, BW250, CR_4_5, 0, 0); + + LMIC.noRXIQinversion = true; + LMIC.rxsyms = 100; + +#endif /* USE_BASICMAC */ + + // This sets CR 4/5, BW125 (except for DR_SF7B, which uses BW250) + LMIC.rps = updr2rps(LMIC.datarate); + + + if (LMIC.protocol && LMIC.protocol->type == RF_PROTOCOL_FANET) + /* for only a few nodes around, increase the coding rate to ensure a more robust transmission */ + LMIC.rps = setCr(LMIC.rps, CR_4_8); + + // set SX1276 AGC Reference + /*if(settings->sxlna){ + LMIC.agcref = 0x13; + // Serial.printf("setting agc ref to 0x%x\n", 0x13); + } + else{ + LMIC.agcref = 0x00; + //Serial.printf("setting agc ref to 0x%x\n", 0x00); + }*/ +} + +static bool sx12xx_receive() +{ + bool success = false; + + sx12xx_receive_complete = false; + + if (!sx12xx_receive_active) + { + sx12xx_setvars(); + sx12xx_rx(sx12xx_rx_func); + sx12xx_receive_active = true; + } + + if (sx12xx_receive_complete == false) + // execute scheduled jobs and events + os_runstep(); + ; + + if (SoC->Bluetooth) + SoC->Bluetooth->loop(); + + if (sx12xx_receive_complete == true) + { + u1_t size = LMIC.dataLen - LMIC.protocol->payload_offset - LMIC.protocol->crc_size; + + if (size > sizeof(RxBuffer)) + size = sizeof(RxBuffer); + + for (u1_t i=0; i < size; i++) + RxBuffer[i] = LMIC.frame[i + LMIC.protocol->payload_offset]; + + RF_last_rssi = LMIC.rssi; + rx_packets_counter++; + success = true; + } + return success; +} + +static void sx12xx_transmit() +{ + sx12xx_transmit_complete = false; + sx12xx_receive_active = false; + + sx12xx_setvars(); + os_setCallback(&sx12xx_txjob, sx12xx_tx_func); + + while (sx12xx_transmit_complete == false) { + // execute scheduled jobs and events + os_runstep(); + + yield(); + }; +} + +static void sx12xx_shutdown() +{ + LMIC_shutdown(); + SPI.end(); +} + +// Enable rx mode and call func when a packet is received +static void sx12xx_rx(osjobcb_t func) +{ + LMIC.osjob.func = func; + LMIC.rxtime = os_getTime(); // RX _now_ + // Enable "continuous" RX for LoRa only (e.g. without a timeout, + // still stops after receiving a packet) + os_radio(LMIC.protocol && + LMIC.protocol->modulation_type == RF_MODULATION_TYPE_LORA ? + RADIO_RXON : RADIO_RX); + //Serial.println("RX"); +} + +static void sx12xx_rx_func(osjob_t* job) +{ + u1_t crc8, pkt_crc8; + u2_t crc16, pkt_crc16; + u1_t i; + + // SX1276 is in SLEEP after IRQ handler, Force it to enter RX mode + sx12xx_receive_active = false; + + /* FANET (LoRa) LMIC IRQ handler may deliver empty packets here when CRC is invalid. */ + if (LMIC.dataLen == 0) + return; + + switch (LMIC.protocol->crc_type) + { + case RF_CHECKSUM_TYPE_GALLAGER: + case RF_CHECKSUM_TYPE_NONE: + /* crc16 left not initialized */ + break; + case RF_CHECKSUM_TYPE_CRC8_107: + crc8 = 0x71; /* seed value */ + break; + case RF_CHECKSUM_TYPE_CCITT_0000: + crc16 = 0x0000; /* seed value */ + break; + case RF_CHECKSUM_TYPE_CCITT_FFFF: + default: + crc16 = 0xffff; /* seed value */ + break; + } + + //Serial.print("Got "); + //Serial.print(LMIC.dataLen); + //Serial.println(" bytes"); + + switch (LMIC.protocol->type) + { + case RF_PROTOCOL_LEGACY: + /* take in account NRF905/FLARM "address" bytes */ + crc16 = update_crc_ccitt(crc16, 0x31); + crc16 = update_crc_ccitt(crc16, 0xFA); + crc16 = update_crc_ccitt(crc16, 0xB6); + break; + case RF_PROTOCOL_P3I: + case RF_PROTOCOL_OGNTP: + default: + break; + } + + for (i = LMIC.protocol->payload_offset; + i < (LMIC.dataLen - LMIC.protocol->crc_size); + i++) + { + switch (LMIC.protocol->crc_type) + { + case RF_CHECKSUM_TYPE_GALLAGER: + case RF_CHECKSUM_TYPE_NONE: + break; + case RF_CHECKSUM_TYPE_CRC8_107: + update_crc8(&crc8, (u1_t)(LMIC.frame[i])); + break; + case RF_CHECKSUM_TYPE_CCITT_FFFF: + case RF_CHECKSUM_TYPE_CCITT_0000: + default: + crc16 = update_crc_ccitt(crc16, (u1_t)(LMIC.frame[i])); + break; + } + + switch (LMIC.protocol->whitening) + { + case RF_WHITENING_NICERF: + LMIC.frame[i] ^= pgm_read_byte(&whitening_pattern[i - LMIC.protocol->payload_offset]); + break; + case RF_WHITENING_MANCHESTER: + case RF_WHITENING_NONE: + default: + break; + } +#if DEBUG + Serial.printf("%02x", (u1_t)(LMIC.frame[i])); +#endif + } + + switch (LMIC.protocol->crc_type) + { + case RF_CHECKSUM_TYPE_NONE: + sx12xx_receive_complete = true; + break; + case RF_CHECKSUM_TYPE_GALLAGER: + if (LDPC_Check((uint8_t *) &LMIC.frame[0])) + { +#if DEBUG + Serial.printf(" %02x%02x%02x%02x%02x%02x is wrong FEC", + LMIC.frame[i], LMIC.frame[i + 1], LMIC.frame[i + 2], + LMIC.frame[i + 3], LMIC.frame[i + 4], LMIC.frame[i + 5]); +#endif + sx12xx_receive_complete = false; + } + else + sx12xx_receive_complete = true; + break; + case RF_CHECKSUM_TYPE_CRC8_107: + pkt_crc8 = LMIC.frame[i]; +#if DEBUG + if (crc8 == pkt_crc8) + Serial.printf(" %02x is valid crc", pkt_crc8); + else + Serial.printf(" %02x is wrong crc", pkt_crc8); + +#endif + if (crc8 == pkt_crc8) + sx12xx_receive_complete = true; + else + sx12xx_receive_complete = false; + break; + case RF_CHECKSUM_TYPE_CCITT_FFFF: + case RF_CHECKSUM_TYPE_CCITT_0000: + default: + pkt_crc16 = (LMIC.frame[i] << 8 | LMIC.frame[i + 1]); +#if DEBUG + if (crc16 == pkt_crc16) + Serial.printf(" %04x is valid crc", pkt_crc16); + else + Serial.printf(" %04x is wrong crc", pkt_crc16); + +#endif + if (crc16 == pkt_crc16) + sx12xx_receive_complete = true; + else + sx12xx_receive_complete = false; + break; + } + +#if DEBUG + Serial.println(); +#endif +} + +// Transmit the given string and call the given function afterwards +static void sx12xx_tx(unsigned char* buf, size_t size, osjobcb_t func) +{ + u1_t crc8; + u2_t crc16; + + switch (LMIC.protocol->crc_type) + { + case RF_CHECKSUM_TYPE_GALLAGER: + case RF_CHECKSUM_TYPE_NONE: + /* crc16 left not initialized */ + break; + case RF_CHECKSUM_TYPE_CRC8_107: + crc8 = 0x71; /* seed value */ + break; + case RF_CHECKSUM_TYPE_CCITT_0000: + crc16 = 0x0000; /* seed value */ + break; + case RF_CHECKSUM_TYPE_CCITT_FFFF: + default: + crc16 = 0xffff; /* seed value */ + break; + } + + os_radio(RADIO_RST); // Stop RX first + delay(1); // Wait a bit, without this os_radio below asserts, apparently because the state hasn't changed yet + + LMIC.dataLen = 0; + + switch (LMIC.protocol->type) + { + case RF_PROTOCOL_LEGACY: + /* take in account NRF905/FLARM "address" bytes */ + crc16 = update_crc_ccitt(crc16, 0x31); + crc16 = update_crc_ccitt(crc16, 0xFA); + crc16 = update_crc_ccitt(crc16, 0xB6); + break; + case RF_PROTOCOL_P3I: + /* insert Net ID */ + LMIC.frame[LMIC.dataLen++] = (u1_t) ((LMIC.protocol->net_id >> 24) & 0x000000FF); + LMIC.frame[LMIC.dataLen++] = (u1_t) ((LMIC.protocol->net_id >> 16) & 0x000000FF); + LMIC.frame[LMIC.dataLen++] = (u1_t) ((LMIC.protocol->net_id >> 8) & 0x000000FF); + LMIC.frame[LMIC.dataLen++] = (u1_t) ((LMIC.protocol->net_id >> 0) & 0x000000FF); + /* insert byte with payload size */ + LMIC.frame[LMIC.dataLen++] = LMIC.protocol->payload_size; + + /* insert byte with CRC-8 seed value when necessary */ + if (LMIC.protocol->crc_type == RF_CHECKSUM_TYPE_CRC8_107) + LMIC.frame[LMIC.dataLen++] = crc8; + + break; + case RF_PROTOCOL_OGNTP: + default: + break; + } + + for (u1_t i=0; i < size; i++) { + switch (LMIC.protocol->whitening) + { + case RF_WHITENING_NICERF: + LMIC.frame[LMIC.dataLen] = buf[i] ^ pgm_read_byte(&whitening_pattern[i]); + break; + case RF_WHITENING_MANCHESTER: + case RF_WHITENING_NONE: + default: + LMIC.frame[LMIC.dataLen] = buf[i]; + break; + } + + switch (LMIC.protocol->crc_type) + { + case RF_CHECKSUM_TYPE_GALLAGER: + case RF_CHECKSUM_TYPE_NONE: + break; + case RF_CHECKSUM_TYPE_CRC8_107: + update_crc8(&crc8, (u1_t)(LMIC.frame[LMIC.dataLen])); + break; + case RF_CHECKSUM_TYPE_CCITT_FFFF: + case RF_CHECKSUM_TYPE_CCITT_0000: + default: + crc16 = update_crc_ccitt(crc16, (u1_t)(LMIC.frame[LMIC.dataLen])); + break; + } + + LMIC.dataLen++; + } + + switch (LMIC.protocol->crc_type) + { + case RF_CHECKSUM_TYPE_GALLAGER: + case RF_CHECKSUM_TYPE_NONE: + break; + case RF_CHECKSUM_TYPE_CRC8_107: + LMIC.frame[LMIC.dataLen++] = crc8; + break; + case RF_CHECKSUM_TYPE_CCITT_FFFF: + case RF_CHECKSUM_TYPE_CCITT_0000: + default: + LMIC.frame[LMIC.dataLen++] = (crc16 >> 8) & 0xFF; + LMIC.frame[LMIC.dataLen++] = (crc16) & 0xFF; + break; + } + + LMIC.osjob.func = func; + os_radio(RADIO_TX); + //Serial.println("TX"); +} + +static void sx12xx_txdone_func(osjob_t* job) +{ + sx12xx_transmit_complete = true; +} + +static void sx12xx_tx_func(osjob_t* job) +{ + if (RF_tx_size > 0) + sx12xx_tx((unsigned char *) &TxBuffer[0], RF_tx_size, sx12xx_txdone_func); +} + +#endif /* EXCLUDE_SX12XX */ + +#if !defined(EXCLUDE_UATM) +/* + * UATM-specific code + * + * + */ + +#include + +#define UAT_RINGBUF_SIZE (sizeof(Stratux_frame_t) * 2) + +static unsigned char uat_ringbuf[UAT_RINGBUF_SIZE]; +static unsigned int uatbuf_head = 0; +Stratux_frame_t uatradio_frame; + +const char UAT_ident[] PROGMEM = SOFTRF_IDENT; + +static bool uatm_probe() +{ + bool success = false; + unsigned long startTime; + unsigned int uatbuf_tail; + u1_t keylen = strlen_P(UAT_ident); + u1_t i =0; + + /* Do not probe on itself and ESP8266 */ + if (SoC->id == SOC_CC13XX || + SoC->id == SOC_ESP8266) + return success; + + SoC->UATSerial_begin(UAT_RECEIVER_BR); + + SoC->UATModule_restart(); + + startTime = millis(); + + // Timeout if no valid response in 1 second + while (millis() - startTime < 1000) { + if (UATSerial.available() > 0) + { + unsigned char c = UATSerial.read(); +#if DEBUG + Serial.println(c, HEX); +#endif + uat_ringbuf[uatbuf_head % UAT_RINGBUF_SIZE] = c; + + uatbuf_tail = uatbuf_head - keylen; + uatbuf_head++; + + for (i=0; i < keylen; i++) + if (pgm_read_byte(&UAT_ident[i]) != uat_ringbuf[(uatbuf_tail + i) % UAT_RINGBUF_SIZE]) + break; + + if (i >= keylen) + { + success = true; + break; + } + } + } + + /* cleanup UAT data buffer */ + uatbuf_head = 0; + memset(uat_ringbuf, 0, sizeof(uat_ringbuf)); + + /* Current ESP32 Core has a bug with Serial2.end()+Serial2.begin() cycle */ + if (SoC->id != SOC_ESP32) + UATSerial.end(); + + return success; +} + +static void uatm_channel(uint8_t channel) +{ + /* Nothing to do */ +} + +static void uatm_setup() +{ + /* Current ESP32 Core has a bug with Serial2.end()+Serial2.begin() cycle */ + if (SoC->id != SOC_ESP32) + SoC->UATSerial_begin(UAT_RECEIVER_BR); + + init_fec(); + + /* Enforce radio settings to follow UAT978 protocol's RF specs */ + ogn_protocol_1 = RF_PROTOCOL_ADSB_UAT; + + protocol_encode = &uat978_encode; + protocol_decode = &uat978_decode; +} + +static bool uatm_receive() +{ + bool success = false; + unsigned int uatbuf_tail; + int rs_errors; + + while (UATSerial.available()) { + unsigned char c = UATSerial.read(); + + uat_ringbuf[uatbuf_head % UAT_RINGBUF_SIZE] = c; + + uatbuf_tail = uatbuf_head - sizeof(Stratux_frame_t); + uatbuf_head++; + + if (uat_ringbuf[ uatbuf_tail % UAT_RINGBUF_SIZE] == STRATUX_UATRADIO_MAGIC_1 && + uat_ringbuf[(uatbuf_tail + 1) % UAT_RINGBUF_SIZE] == STRATUX_UATRADIO_MAGIC_2 && + uat_ringbuf[(uatbuf_tail + 2) % UAT_RINGBUF_SIZE] == STRATUX_UATRADIO_MAGIC_3 && + uat_ringbuf[(uatbuf_tail + 3) % UAT_RINGBUF_SIZE] == STRATUX_UATRADIO_MAGIC_4) + { + unsigned char* pre_fec_buf = (unsigned char *) &uatradio_frame; + for (u1_t i=0; i < sizeof(Stratux_frame_t); i++) + pre_fec_buf[i] = uat_ringbuf[(uatbuf_tail + i) % UAT_RINGBUF_SIZE]; + + int frame_type = correct_adsb_frame(uatradio_frame.data, &rs_errors); + + if (frame_type == -1) + continue; + + u1_t size = 0; + + if (frame_type == 1) + size = SHORT_FRAME_DATA_BYTES; + else if (frame_type == 2) + size = LONG_FRAME_DATA_BYTES; + + if (size > sizeof(RxBuffer)) + size = sizeof(RxBuffer); + + if (size > 0) + { + memcpy(RxBuffer, uatradio_frame.data, size); + + RF_last_rssi = uatradio_frame.rssi; + rx_packets_counter++; + success = true; + + break; + } + } + } + + return success; +} + +static void uatm_transmit() +{ + /* Nothing to do */ +} + +static void uatm_shutdown() +{ + /* Nothing to do */ +} + +#endif /* EXCLUDE_UATM */ + +#if !defined(EXCLUDE_CC13XX) +/* + * CC13XX-specific code + * + * + */ + +#include "EasyLink.h" + +#include +#include +#include +#include +#include + +#define MAX_SYNCWORD_SIZE 4 + +const rf_proto_desc_t* cc13xx_protocol = &uat978_proto_desc; + +EasyLink myLink; +#if !defined(EXCLUDE_OGLEP3) +EasyLink_TxPacket txPacket; +#endif /* EXCLUDE_OGLEP3 */ + +static uint8_t cc13xx_channel_prev = (uint8_t) -1; + +static bool cc13xx_receive_complete = false; +static bool cc13xx_receive_active = false; +static bool cc13xx_transmit_complete = false; + +void cc13xx_Receive_callback(EasyLink_RxPacket* rxPacket_ptr, EasyLink_Status status) +{ + cc13xx_receive_active = false; + bool success = false; + + if (status == EasyLink_Status_Success) + { + size_t size = 0; + uint8_t offset; + + u1_t crc8, pkt_crc8; + u2_t crc16, pkt_crc16; + +#if !defined(EXCLUDE_OGLEP3) + switch (cc13xx_protocol->crc_type) + { + case RF_CHECKSUM_TYPE_GALLAGER: + case RF_CHECKSUM_TYPE_NONE: + /* crc16 left not initialized */ + break; + case RF_CHECKSUM_TYPE_CRC8_107: + crc8 = 0x71; /* seed value */ + break; + case RF_CHECKSUM_TYPE_CCITT_0000: + crc16 = 0x0000; /* seed value */ + break; + case RF_CHECKSUM_TYPE_CCITT_FFFF: + default: + crc16 = 0xffff; /* seed value */ + break; + } + + switch (cc13xx_protocol->type) + { + case RF_PROTOCOL_LEGACY: + /* take in account NRF905/FLARM "address" bytes */ + crc16 = update_crc_ccitt(crc16, 0x31); + crc16 = update_crc_ccitt(crc16, 0xFA); + crc16 = update_crc_ccitt(crc16, 0xB6); + break; + case RF_PROTOCOL_P3I: + case RF_PROTOCOL_OGNTP: + default: + break; + } +#endif /* EXCLUDE_OGLEP3 */ + + switch (cc13xx_protocol->type) + { +#if !defined(EXCLUDE_OGLEP3) + case RF_PROTOCOL_P3I: + uint8_t i; + offset = cc13xx_protocol->payload_offset; + for (i = 0; i < cc13xx_protocol->payload_size; i++) + { + update_crc8(&crc8, (u1_t)(rxPacket_ptr->payload[i + offset])); + if (i < sizeof(RxBuffer)) + RxBuffer[i] = rxPacket_ptr->payload[i + offset] ^ + pgm_read_byte(&whitening_pattern[i]); + } + + pkt_crc8 = rxPacket_ptr->payload[i + offset]; + + if (crc8 == pkt_crc8) + + success = true; + break; + case RF_PROTOCOL_OGNTP: + case RF_PROTOCOL_LEGACY: + offset = cc13xx_protocol->syncword_size - 4; + size = cc13xx_protocol->payload_offset + + cc13xx_protocol->payload_size + + cc13xx_protocol->payload_size + + cc13xx_protocol->crc_size + + cc13xx_protocol->crc_size; + if (rxPacket_ptr->len >= size + offset && + rxPacket_ptr->payload[0] == cc13xx_protocol->syncword[4] && + rxPacket_ptr->payload[1] == cc13xx_protocol->syncword[5] && + rxPacket_ptr->payload[2] == cc13xx_protocol->syncword[6] && + (offset > 3 ? (rxPacket_ptr->payload[3] == cc13xx_protocol->syncword[7]) : true)) + { + uint8_t i, val1, val2; + for (i = 0; i < size; i++) { + val1 = pgm_read_byte(&ManchesterDecode[rxPacket_ptr->payload[i + offset]]); + i++; + val2 = pgm_read_byte(&ManchesterDecode[rxPacket_ptr->payload[i + offset]]); + if ((i >> 1) < sizeof(RxBuffer)) + { + RxBuffer[i >> 1] = ((val1 & 0x0F) << 4) | (val2 & 0x0F); + + if (i < size - (cc13xx_protocol->crc_size + cc13xx_protocol->crc_size)) + switch (cc13xx_protocol->crc_type) + { + case RF_CHECKSUM_TYPE_GALLAGER: + case RF_CHECKSUM_TYPE_NONE: + break; + case RF_CHECKSUM_TYPE_CCITT_FFFF: + case RF_CHECKSUM_TYPE_CCITT_0000: + default: + crc16 = update_crc_ccitt(crc16, (u1_t)(RxBuffer[i >> 1])); + break; + } + } + } + + switch (cc13xx_protocol->crc_type) + { + case RF_CHECKSUM_TYPE_GALLAGER: + if (LDPC_Check((uint8_t *) &RxBuffer[0]) == 0) + + success = true; + break; + case RF_CHECKSUM_TYPE_CCITT_FFFF: + case RF_CHECKSUM_TYPE_CCITT_0000: + offset = cc13xx_protocol->payload_offset + cc13xx_protocol->payload_size; + if (offset + 1 < sizeof(RxBuffer)) + { + pkt_crc16 = (RxBuffer[offset] << 8 | RxBuffer[offset + 1]); + if (crc16 == pkt_crc16) + + success = true; + } + break; + default: + break; + } + } + break; +#endif /* EXCLUDE_OGLEP3 */ + case RF_PROTOCOL_ADSB_UAT: + default: + int rs_errors; + int frame_type; + frame_type = correct_adsb_frame(rxPacket_ptr->payload, &rs_errors); + + if (frame_type != -1) + { + if (frame_type == 1) + size = SHORT_FRAME_DATA_BYTES; + else if (frame_type == 2) + size = LONG_FRAME_DATA_BYTES; + + if (size > sizeof(RxBuffer)) + size = sizeof(RxBuffer); + + if (size > 0) + { + memcpy(RxBuffer, rxPacket_ptr->payload, size); + + success = true; + } + } + break; + } + + if (success) + { + RF_last_rssi = rxPacket_ptr->rssi; + rx_packets_counter++; + + cc13xx_receive_complete = true; + } + } +} + +void cc13xx_Transmit_callback(EasyLink_Status status) +{ + if (status == EasyLink_Status_Success) + cc13xx_transmit_complete = true; +} + +static bool cc13xx_Receive_Async() +{ + bool success = false; + EasyLink_Status status; + + if (!cc13xx_receive_active) + { + status = myLink.receive(&cc13xx_Receive_callback); + + if (status == EasyLink_Status_Success) + cc13xx_receive_active = true; + } + + if (cc13xx_receive_complete == true) + { + success = true; + cc13xx_receive_complete = false; + } + + return success; +} + +static bool cc13xx_probe() +{ + bool success = false; + + if (SoC->id == SOC_CC13XX) + success = true; + + return success; +} + +static void cc13xx_channel(uint8_t channel) +{ +#if !defined(EXCLUDE_OGLEP3) + if (ogn_protocol_1 != RF_PROTOCOL_ADSB_UAT && + channel != cc13xx_channel_prev) + { + uint32_t frequency = RF_FreqPlan.getChanFrequency(channel); + + if (cc13xx_receive_active) + { + /* restart Rx upon a channel switch */ + EasyLink_abort(); + cc13xx_receive_active = false; + } + + EasyLink_setFrequency(frequency); + + cc13xx_channel_prev = channel; + } +#endif /* EXCLUDE_OGLEP3 */ +} + +static void cc13xx_setup() +{ + switch (ogn_protocol_1) + { +#if !defined(EXCLUDE_OGLEP3) + case RF_PROTOCOL_OGNTP: + cc13xx_protocol = &ogntp_proto_desc; + protocol_encode = &ogntp_encode; + protocol_decode = &ogntp_decode; + + myLink.begin(EasyLink_Phy_100kbps2gfsk_ogntp); + break; + case RF_PROTOCOL_P3I: + cc13xx_protocol = &p3i_proto_desc; + protocol_encode = &p3i_encode; + protocol_decode = &p3i_decode; + + myLink.begin(EasyLink_Phy_38400bps2gfsk_p3i); + break; + case RF_PROTOCOL_LEGACY: + cc13xx_protocol = &legacy_proto_desc; + protocol_encode = &legacy_encode; + protocol_decode = &legacy_decode; + + myLink.begin(EasyLink_Phy_100kbps2gfsk_legacy); + break; +#endif /* EXCLUDE_OGLEP3 */ + case RF_PROTOCOL_ADSB_UAT: + default: + cc13xx_protocol = &uat978_proto_desc; + protocol_encode = &uat978_encode; + protocol_decode = &uat978_decode; + /* + * Enforce UAT protocol setting + * if other value (FANET) left in EEPROM from other (SX12XX) radio + */ + ogn_protocol_1 = RF_PROTOCOL_ADSB_UAT; + + init_fec(); + myLink.begin(EasyLink_Phy_Custom); + break; + } + + /* -10 dBm is a minumum for CC1310 ; CC1352 can operate down to -20 dBm */ + int8_t TxPower = -10; + + switch (settings->txpower) + { + case RF_TX_POWER_FULL: + + if (ogn_protocol_1 != RF_PROTOCOL_ADSB_UAT) + /* Load regional max. EIRP at first */ + TxPower = RF_FreqPlan.MaxTxPower; + + if (TxPower > 14) + TxPower = 14; /* 'high power' CC13XXP (up to 20 dBm) is not supported yet */ + + break; + case RF_TX_POWER_OFF: + case RF_TX_POWER_LOW: + default: + break; + } + + EasyLink_setRfPwr(TxPower); +} + +static bool cc13xx_receive() +{ + return cc13xx_Receive_Async(); +} + +static void cc13xx_transmit() +{ +#if !defined(EXCLUDE_OGLEP3) + EasyLink_Status status; + + u1_t crc8; + u2_t crc16; + u1_t i; + + if (RF_tx_size <= 0) + return; + + if (cc13xx_protocol->type == RF_PROTOCOL_ADSB_UAT) + { + return; /* no transmit on UAT */ + } + + EasyLink_abort(); + + cc13xx_receive_active = false; + cc13xx_transmit_complete = false; + + size_t PayloadLen = 0; + + switch (cc13xx_protocol->crc_type) + { + case RF_CHECKSUM_TYPE_GALLAGER: + case RF_CHECKSUM_TYPE_NONE: + /* crc16 left not initialized */ + break; + case RF_CHECKSUM_TYPE_CRC8_107: + crc8 = 0x71; /* seed value */ + break; + case RF_CHECKSUM_TYPE_CCITT_0000: + crc16 = 0x0000; /* seed value */ + break; + case RF_CHECKSUM_TYPE_CCITT_FFFF: + default: + crc16 = 0xffff; /* seed value */ + break; + } + + for (i = MAX_SYNCWORD_SIZE; i < cc13xx_protocol->syncword_size; i++) + txPacket.payload[PayloadLen++] = cc13xx_protocol->syncword[i]; + + switch (cc13xx_protocol->type) + { + case RF_PROTOCOL_LEGACY: + /* take in account NRF905/FLARM "address" bytes */ + crc16 = update_crc_ccitt(crc16, 0x31); + crc16 = update_crc_ccitt(crc16, 0xFA); + crc16 = update_crc_ccitt(crc16, 0xB6); + break; + case RF_PROTOCOL_P3I: + /* insert Net ID */ + txPacket.payload[PayloadLen++] = (u1_t) ((cc13xx_protocol->net_id >> 24) & 0x000000FF); + txPacket.payload[PayloadLen++] = (u1_t) ((cc13xx_protocol->net_id >> 16) & 0x000000FF); + txPacket.payload[PayloadLen++] = (u1_t) ((cc13xx_protocol->net_id >> 8) & 0x000000FF); + txPacket.payload[PayloadLen++] = (u1_t) ((cc13xx_protocol->net_id >> 0) & 0x000000FF); + /* insert byte with payload size */ + txPacket.payload[PayloadLen++] = cc13xx_protocol->payload_size; + + /* insert byte with CRC-8 seed value when necessary */ + if (cc13xx_protocol->crc_type == RF_CHECKSUM_TYPE_CRC8_107) + txPacket.payload[PayloadLen++] = crc8; + + break; + case RF_PROTOCOL_OGNTP: + default: + break; + } + + for (i=0; i < RF_tx_size; i++) { + switch (cc13xx_protocol->whitening) + { + case RF_WHITENING_NICERF: + txPacket.payload[PayloadLen] = TxBuffer[i] ^ pgm_read_byte(&whitening_pattern[i]); + break; + case RF_WHITENING_MANCHESTER: + txPacket.payload[PayloadLen] = pgm_read_byte(&ManchesterEncode[(TxBuffer[i] >> 4) & 0x0F]); + PayloadLen++; + txPacket.payload[PayloadLen] = pgm_read_byte(&ManchesterEncode[(TxBuffer[i]) & 0x0F]); + break; + case RF_WHITENING_NONE: + default: + txPacket.payload[PayloadLen] = TxBuffer[i]; + break; + } + + switch (cc13xx_protocol->crc_type) + { + case RF_CHECKSUM_TYPE_GALLAGER: + case RF_CHECKSUM_TYPE_NONE: + break; + case RF_CHECKSUM_TYPE_CRC8_107: + update_crc8(&crc8, (u1_t)(txPacket.payload[PayloadLen])); + break; + case RF_CHECKSUM_TYPE_CCITT_FFFF: + case RF_CHECKSUM_TYPE_CCITT_0000: + default: + if (cc13xx_protocol->whitening == RF_WHITENING_MANCHESTER) + crc16 = update_crc_ccitt(crc16, (u1_t)(TxBuffer[i])); + else + crc16 = update_crc_ccitt(crc16, (u1_t)(txPacket.payload[PayloadLen])); + break; + } + + PayloadLen++; + } + + switch (cc13xx_protocol->crc_type) + { + case RF_CHECKSUM_TYPE_GALLAGER: + case RF_CHECKSUM_TYPE_NONE: + break; + case RF_CHECKSUM_TYPE_CRC8_107: + txPacket.payload[PayloadLen++] = crc8; + break; + case RF_CHECKSUM_TYPE_CCITT_FFFF: + case RF_CHECKSUM_TYPE_CCITT_0000: + default: + if (cc13xx_protocol->whitening == RF_WHITENING_MANCHESTER) + { + txPacket.payload[PayloadLen++] = pgm_read_byte(&ManchesterEncode[(((crc16 >> 8) & 0xFF) >> 4) & 0x0F]); + txPacket.payload[PayloadLen++] = pgm_read_byte(&ManchesterEncode[(((crc16 >> 8) & 0xFF)) & 0x0F]); + txPacket.payload[PayloadLen++] = pgm_read_byte(&ManchesterEncode[(((crc16) & 0xFF) >> 4) & 0x0F]); + txPacket.payload[PayloadLen++] = pgm_read_byte(&ManchesterEncode[(((crc16) & 0xFF)) & 0x0F]); + PayloadLen++; + } + else + { + txPacket.payload[PayloadLen++] = (crc16 >> 8) & 0xFF; + txPacket.payload[PayloadLen++] = (crc16) & 0xFF; + } + break; + } + + txPacket.len = PayloadLen; + // Transmit immediately + txPacket.absTime = EasyLink_ms_To_RadioTime(0); + +#if 0 + status = myLink.transmit(&txPacket, &cc13xx_Transmit_callback); + + if (status == EasyLink_Status_Success) + { + while (cc13xx_transmit_complete == false) { + yield(); + }; + } +#else + myLink.transmit(&txPacket); +#endif + +#endif /* EXCLUDE_OGLEP3 */ +} + +static void cc13xx_shutdown() +{ + EasyLink_abort(); +} + +#endif /* EXCLUDE_CC13XX */ + +#if defined(USE_OGN_RF_DRIVER) +/* + * OGN driver specific code + * + * + */ + +static RFM_TRX TRX; + +static uint8_t ognrf_channel_prev = (uint8_t) -1; +static bool ognrf_receive_active = false; + +void RFM_Select(void) +{ + hal_pin_nss(0); +} + +void RFM_Deselect(void) +{ + hal_pin_nss(1); +} + +uint8_t RFM_TransferByte(uint8_t Byte) +{ + return hal_spi(Byte); +} + +bool RFM_IRQ_isOn(void) +{ + return lmic_pins.dio[0] == LMIC_UNUSED_PIN ? \ + false : digitalRead(lmic_pins.dio[0]); +} + +#ifdef WITH_RFM95 // RESET is active LOW +void RFM_RESET(uint8_t On) +{ + if (On) + hal_pin_rst(0); + else + hal_pin_rst(1); +} + +#endif + +#if defined(WITH_RFM69) || defined(WITH_SX1272) // RESET is active HIGH +void RFM_RESET(uint8_t On) +{ + if (On) + hal_pin_rst(1); + else + hal_pin_rst(0); +} + +#endif + +static bool ognrf_probe() +{ + bool success = false; + + TRX.Select = RFM_Select; + TRX.Deselect = RFM_Deselect; + TRX.TransferByte = RFM_TransferByte; + TRX.RESET = RFM_RESET; + + SoC->SPI_begin(); + hal_init(nullptr); + + TRX.RESET(1); // RESET active + vTaskDelay(10); // wait 10ms + TRX.RESET(0); // RESET released + vTaskDelay(10); // wait 10ms + + uint8_t ChipVersion = TRX.ReadVersion(); + + pinMode(lmic_pins.nss, INPUT); + SPI.end(); + +#if defined(WITH_RFM95) + if (ChipVersion == 0x12) + success = true; +#endif /* WITH_RFM95 */ +#if defined(WITH_RFM69) + if (ChipVersion == 0x24) + success = true; +#endif /* WITH_RFM69 */ +#if defined(WITH_SX1272) + if (ChipVersion == 0x22) + success = true; +#endif /* WITH_SX1272 */ +#if defined(WITH_SI4X32) + if (ChipVersion == 0x06 /* 4032 */ || + ChipVersion == 0x08 /* 4432 */) + success = true; +#endif /* WITH_SI4X32 */ + + return success; +} + +static void ognrf_channel(uint8_t channel) +{ + if (channel != ognrf_channel_prev) + { + if (ognrf_receive_active) + { + TRX.WriteMode(RF_OPMODE_STANDBY); + vTaskDelay(1); + + /* restart Rx upon a channel switch */ + ognrf_receive_active = false; + } + + TRX.setChannel(channel & 0x7F); + + ognrf_channel_prev = channel; + } +} + +static void ognrf_setup() +{ + uint8_t TxPower = 0; + + /* Enforce radio settings to follow OGNTP protocol's RF specs */ + ogn_protocol_1 = RF_PROTOCOL_OGNTP; + + LMIC.protocol = &ogntp_proto_desc; + + protocol_encode = &ogntp_encode; + protocol_decode = &ogntp_decode; + + TRX.Select = RFM_Select; + TRX.Deselect = RFM_Deselect; + TRX.TransferByte = RFM_TransferByte; + TRX.DIO0_isOn = RFM_IRQ_isOn; + TRX.RESET = RFM_RESET; + + SoC->SPI_begin(); + hal_init(nullptr); + + TRX.RESET(1); // RESET active + vTaskDelay(10); // wait 10ms + TRX.RESET(0); // RESET released + vTaskDelay(10); // wait 10ms + + // set TRX base frequency and channel separation + TRX.setBaseFrequency(RF_FreqPlan.BaseFreq); + TRX.setChannelSpacing(RF_FreqPlan.ChanSepar); + TRX.setFrequencyCorrection(0); + + TRX.Configure(0, ogntp_proto_desc.syncword); // setup RF chip parameters and set to channel #0 + TRX.WriteMode(RF_OPMODE_STANDBY); // set RF chip mode to STANDBY + + switch (settings->txpower) + { + case RF_TX_POWER_FULL: + + /* Load regional max. EIRP at first */ + TxPower = RF_FreqPlan.MaxTxPower; + + if (TxPower > 20) + TxPower = 20; +#if 1 + if (TxPower > 17) + TxPower = 17; +#endif + +#ifdef WITH_RFM69 + TRX.WriteTxPower(TxPower, RFM69_POWER_RATING == 1 ? true : false); +#else + TRX.WriteTxPower(TxPower); +#endif /* WITH_RFM69 */ + break; + case RF_TX_POWER_OFF: + case RF_TX_POWER_LOW: + default: + TRX.WriteTxPowerMin(); + break; + } + + /* Leave IC in standby mode */ +} + +static bool ognrf_receive() +{ + bool success = false; + +#if !defined(WITH_SI4X32) + + uint8_t RxRSSI = 0; + uint8_t Err[OGNTP_PAYLOAD_SIZE + OGNTP_CRC_SIZE]; + + // Put into receive mode + if (!ognrf_receive_active) + { +// TRX.ClearIrqFlags(); + + TRX.WriteSYNC(7, 7, ogntp_proto_desc.syncword); // Shorter SYNC for RX + TRX.WriteMode(RF_OPMODE_RECEIVER); + vTaskDelay(1); + + ognrf_receive_active = true; + } + + if (TRX.DIO0_isOn()) + { + RxRSSI = TRX.ReadRSSI(); + + TRX.ReadPacket(RxBuffer, Err); + if (LDPC_Check((uint8_t *) RxBuffer) == 0) + success = true; + } + + if (success) + { + RF_last_rssi = RxRSSI; + rx_packets_counter++; + } + +#endif /* WITH_SI4X32 */ + + if (SoC->Bluetooth) + SoC->Bluetooth->loop(); + + return success; +} + +static void ognrf_transmit() +{ + ognrf_receive_active = false; + +#if defined(WITH_SI4X32) + + TRX.WritePacket((uint8_t *) &TxBuffer[0]); + TRX.Transmit(); + vTaskDelay(6); + +#else + + TRX.WriteMode(RF_OPMODE_STANDBY); + vTaskDelay(1); + + TRX.WriteSYNC(8, 7, ogntp_proto_desc.syncword); // Full SYNC for TX + + TRX.ClearIrqFlags(); + TRX.WritePacket((uint8_t *) &TxBuffer[0]); + + TRX.WriteMode(RF_OPMODE_TRANSMITTER); + vTaskDelay(5); + + uint8_t Break=0; + for (uint16_t Wait=400; Wait; Wait--) // wait for transmission to end + { + uint16_t Flags=TRX.ReadIrqFlags(); + if (Flags & RF_IRQ_PacketSent) + Break++; + if (Break >= 2) + break; + } + + TRX.WriteMode(RF_OPMODE_STANDBY); + +#endif /* WITH_SI4X32 */ +} + +static void ognrf_shutdown() +{ + TRX.WriteMode(RF_OPMODE_STANDBY); + SPI.end(); +} + +#endif /* USE_OGN_RF_DRIVER */ diff --git a/ognbase/RF.h b/ognbase/RF.h index 8e61584..44075f5 100644 --- a/ognbase/RF.h +++ b/ognbase/RF.h @@ -1,119 +1,119 @@ -/* - * RF.h - * Copyright (C) 2019-2020 Linar Yusupov - * - * 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 . - */ - -#ifndef RFHELPER_H -#define RFHELPER_H - -#include -#include - -#include "SoC.h" - -#if defined(USE_BASICMAC) -#include -#else -#include -#endif -#include -#include -#include -#include - -#include "GNSS.h" -#include "Protocol_Legacy.h" -#include "Protocol_OGNTP.h" -#include "Protocol_P3I.h" -#include "Protocol_FANET.h" -#include "Protocol_UAT978.h" - -#define maxof2(a, b) (a > b ? a : b) -#define maxof3(a, b, c) maxof2(maxof2(a, b), c) -#define maxof5(a, b, c, d, e) maxof2(maxof2(a, b), maxof3(c, d, e)) - -/* Max. paket's payload size for all supported RF protocols */ -//#define MAX_PKT_SIZE 32 /* 48 = UAT LONG_FRAME_DATA_BYTES */ -#define MAX_PKT_SIZE maxof5(LEGACY_PAYLOAD_SIZE, OGNTP_PAYLOAD_SIZE, \ - P3I_PAYLOAD_SIZE, FANET_PAYLOAD_SIZE, \ - UAT978_PAYLOAD_SIZE) - -#define RXADDR {0x31, 0xfa, 0xb6} // Address of this device (4 bytes) -#define TXADDR {0x31, 0xfa, 0xb6} // Address of device to send to (4 bytes) - -enum -{ - RF_IC_NONE, - RF_IC_NRF905, - RF_IC_SX1276, - RF_IC_UATM, - RF_IC_CC13XX, - RF_DRV_OGN, - RF_IC_SX1262 -}; - -enum -{ - RF_TX_POWER_FULL, - RF_TX_POWER_LOW, - RF_TX_POWER_OFF -}; - -typedef struct rfchip_ops_struct -{ - byte type; - const char name[8]; - bool (* probe)(); - void (* setup)(); - void (* channel)(uint8_t); - bool (* receive)(); - void (* transmit)(); - void (* shutdown)(); -} rfchip_ops_t; - -String Bin2Hex(byte *, size_t); - -uint8_t parity(uint32_t); - -byte RF_setup(void); - -void RF_SetChannel(void); - -void RF_loop(void); - -size_t RF_Encode(ufo_t *); - -size_t RF_Encode_Fanet_s(ufo_t *); - -bool RF_Transmit(size_t, bool); - -bool RF_Receive(void); - -void RF_Shutdown(void); - -uint8_t RF_Payload_Size(uint8_t); - -extern byte TxBuffer[MAX_PKT_SIZE], RxBuffer[MAX_PKT_SIZE]; -extern unsigned long TxTimeMarker; - -extern const rfchip_ops_t* rf_chip; -extern bool RF_SX12XX_RST_is_connected; -extern size_t (* protocol_encode)(void *, ufo_t *); -extern bool (* protocol_decode)(void *, ufo_t *, ufo_t *); - -extern int8_t RF_last_rssi; - -#endif /* RFHELPER_H */ +/* + * RF.h + * Copyright (C) 2019-2020 Linar Yusupov + * + * 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 . + */ + +#ifndef RFHELPER_H +#define RFHELPER_H + +#include +#include + +#include "SoC.h" + +#if defined(USE_BASICMAC) +#include +#else +#include +#endif +#include +#include +#include +#include + +#include "GNSS.h" +#include "Protocol_Legacy.h" +#include "Protocol_OGNTP.h" +#include "Protocol_P3I.h" +#include "Protocol_FANET.h" +#include "Protocol_UAT978.h" + +#define maxof2(a, b) (a > b ? a : b) +#define maxof3(a, b, c) maxof2(maxof2(a, b), c) +#define maxof5(a, b, c, d, e) maxof2(maxof2(a, b), maxof3(c, d, e)) + +/* Max. paket's payload size for all supported RF protocols */ +//#define MAX_PKT_SIZE 32 /* 48 = UAT LONG_FRAME_DATA_BYTES */ +#define MAX_PKT_SIZE maxof5(LEGACY_PAYLOAD_SIZE, OGNTP_PAYLOAD_SIZE, \ + P3I_PAYLOAD_SIZE, FANET_PAYLOAD_SIZE, \ + UAT978_PAYLOAD_SIZE) + +#define RXADDR {0x31, 0xfa, 0xb6} // Address of this device (4 bytes) +#define TXADDR {0x31, 0xfa, 0xb6} // Address of device to send to (4 bytes) + +enum +{ + RF_IC_NONE, + RF_IC_NRF905, + RF_IC_SX1276, + RF_IC_UATM, + RF_IC_CC13XX, + RF_DRV_OGN, + RF_IC_SX1262 +}; + +enum +{ + RF_TX_POWER_FULL, + RF_TX_POWER_LOW, + RF_TX_POWER_OFF +}; + +typedef struct rfchip_ops_struct +{ + byte type; + const char name[8]; + bool (* probe)(); + void (* setup)(); + void (* channel)(uint8_t); + bool (* receive)(); + void (* transmit)(); + void (* shutdown)(); +} rfchip_ops_t; + +String Bin2Hex(byte *, size_t); + +uint8_t parity(uint32_t); + +byte RF_setup(void); + +void RF_SetChannel(void); + +void RF_loop(void); + +size_t RF_Encode(ufo_t *); + +size_t RF_Encode_Fanet_s(ufo_t *); + +bool RF_Transmit(size_t, bool); + +bool RF_Receive(void); + +void RF_Shutdown(void); + +uint8_t RF_Payload_Size(uint8_t); + +extern byte TxBuffer[MAX_PKT_SIZE], RxBuffer[MAX_PKT_SIZE]; +extern unsigned long TxTimeMarker; + +extern const rfchip_ops_t* rf_chip; +extern bool RF_SX12XX_RST_is_connected; +extern size_t (* protocol_encode)(void *, ufo_t *); +extern bool (* protocol_decode)(void *, ufo_t *, ufo_t *); + +extern int8_t RF_last_rssi; + +#endif /* RFHELPER_H */ diff --git a/ognbase/RSM.cpp b/ognbase/RSM.cpp index dc7e246..bd0b0fa 100644 --- a/ognbase/RSM.cpp +++ b/ognbase/RSM.cpp @@ -79,50 +79,50 @@ void RSM_receiver() if (message.receiverConfiguration.has_maxrange) - settings->range = message.receiverConfiguration.maxrange; + ogn_range = message.receiverConfiguration.maxrange; if (message.receiverConfiguration.has_band) { - settings->band = message.receiverConfiguration.band; + ogn_band = message.receiverConfiguration.band; Serial.println("setting band"); } if (message.receiverConfiguration.has_protocol) { - settings->rf_protocol = message.receiverConfiguration.protocol; + ogn_protocol_1 = message.receiverConfiguration.protocol; Serial.println("setting protocol"); } if (message.receiverConfiguration.has_aprsd) { - settings->ogndebug = message.receiverConfiguration.aprsd; + ogn_debug= message.receiverConfiguration.aprsd; Serial.println("enable aprs debugging"); } if (message.receiverConfiguration.has_aprsp) { - settings->ogndebugp = message.receiverConfiguration.aprsp; + ogn_debugport = message.receiverConfiguration.aprsp; Serial.println("change aprs debug port"); } if (message.receiverConfiguration.has_itrackb) { - settings->ignore_no_track = message.receiverConfiguration.itrackb; + ogn_itrackbit= message.receiverConfiguration.itrackb; Serial.println("ignore track bit set"); } if (message.receiverConfiguration.has_istealthb) { - settings->ignore_stealth = message.receiverConfiguration.istealthb; + ogn_istealthbit= message.receiverConfiguration.istealthb; Serial.println("ignore stealth bit set"); } if (message.receiverConfiguration.has_sleepm) { - settings->sleep_mode = message.receiverConfiguration.sleepm; + ogn_sleepmode = message.receiverConfiguration.sleepm; Serial.println("enabling sleep mode"); } if (message.receiverConfiguration.has_rxidle) { - settings->sleep_after_rx_idle = message.receiverConfiguration.rxidle; + ogn_rxidle = message.receiverConfiguration.rxidle; Serial.println("enable sleep after rx idle"); } if (message.receiverConfiguration.has_wakeup) { - settings->wake_up_timer = message.receiverConfiguration.wakeup; + ogn_wakeuptimer= message.receiverConfiguration.wakeup; Serial.println("setting wakeup timer value"); } if (message.receiverConfiguration.has_reset) diff --git a/ognbase/SoftRF.h b/ognbase/SoftRF.h index 3fba300..a936bbc 100644 --- a/ognbase/SoftRF.h +++ b/ognbase/SoftRF.h @@ -1,221 +1,221 @@ -/* - * SoftRF.h - * Copyright (C) 2019-2020 Linar Yusupov - * - * 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 . - */ - -#ifndef SOFTRF_H -#define SOFTRF_H - -#if defined(ARDUINO) -#include -#endif /* ARDUINO */ - -#if defined(ENERGIA_ARCH_CC13XX) || defined(ENERGIA_ARCH_CC13X2) -#include -#endif /* ENERGIA_ARCH_CC13XX || ENERGIA_ARCH_CC13X2 */ - -#if defined(RASPBERRY_PI) -#include -#endif /* RASPBERRY_PI */ - -#include "version.h" - -#define SOFTRF_FIRMWARE_VERSION _VERSION -#define SOFTRF_IDENT "OGNB-" - -#define ENTRY_EXPIRATION_TIME 10 /* seconds */ -#define LED_EXPIRATION_TIME 5 /* seconds */ -#define EXPORT_EXPIRATION_TIME 5 /* seconds */ - -/* - * If you need for SoftRF to operate in wireless - * client mode - specify your local AP's SSID/PSK: - * - * #define MY_ACCESSPOINT_SSID "My_AP_SSID" - * #define MY_ACCESSPOINT_PSK "My_AP_PSK" - * - * If SoftRF's built-in AP is not stable enough for you, consider - * to use "reverse" operation when your smartphone is acting - * as an AP for the SoftRF unit as a client: - * - * #define MY_ACCESSPOINT_SSID "AndroidAP" - * #define MY_ACCESSPOINT_PSK "12345678" - */ - -// Default mode is AP with -// SSID: SoftRF-XXXXXX -// KEY: 12345678 -// IP: 192.168.1.1 -// NETMASK: 255.255.255.0 - -#define MY_ACCESSPOINT_SSID "" -#define MY_ACCESSPOINT_PSK "" - -#define RELAY_DST_PORT 12390 -#define RELAY_SRC_PORT (RELAY_DST_PORT - 1) - -#define GDL90_DST_PORT 4000 -#define D1090_DST_PORT 4001 -#define NMEA_UDP_PORT 10110 -#define NMEA_TCP_PORT 2000 - -/* - * Serial I/O default values. - * Can be overridden by platfrom-specific code. - */ -#if !defined(SERIAL_IN_BR) -/* - * 9600 is default value of NMEA baud rate - * for most of GNSS modules - * being used in SoftRF project - */ -#define SERIAL_IN_BR 9600 -#endif -#if !defined(SERIAL_IN_BITS) -#define SERIAL_IN_BITS SERIAL_8N1 -#endif - -/* - * 38400 is known as maximum baud rate - * that HC-05 Bluetooth module - * can handle without symbols loss. - * - * Applicable for Standalone Edition. Inherited by most of other SoftRF platforms. - */ -#define STD_OUT_BR 38400 -#define STD_OUT_BITS SERIAL_8N1 - -#if !defined(SERIAL_OUT_BR) -#define SERIAL_OUT_BR STD_OUT_BR -#endif -#if !defined(SERIAL_OUT_BITS) -#define SERIAL_OUT_BITS STD_OUT_BITS -#endif - -#define UAT_RECEIVER_BR 2000000 - -#if defined(PREMIUM_PACKAGE) && !defined(RASPBERRY_PI) -#define ENABLE_AHRS -#endif /* PREMIUM_PACKAGE */ - -typedef struct UFO -{ - uint8_t raw[34]; - time_t timestamp; - - uint8_t protocol; - - uint32_t addr; - uint8_t addr_type; - float latitude; - float longitude; - float altitude; - float pressure_altitude; - float course; /* CoG */ - float speed; /* ground speed in knots */ - uint8_t aircraft_type; - - float vs; /* feet per minute */ - - bool stealth; - bool no_track; - - int8_t ns[4]; - int8_t ew[4]; - - float geoid_separation; /* metres */ - uint16_t hdop; /* cm */ - int8_t rssi; /* SX1276 only */ - - /* 'legacy' specific data */ - float distance; - float bearing; - int8_t alarm_level; - - /* ADS-B (ES, UAT, GDL90) specific data */ - uint8_t callsign[8]; -} ufo_t; - -typedef struct hardware_info -{ - byte model; - byte revision; - byte soc; - byte rf; - byte gnss; - byte baro; - byte display; -#if defined(ENABLE_AHRS) - byte ahrs; -#endif /* ENABLE_AHRS */ -} hardware_info_t; - -enum -{ - SOFTRF_MODE_NORMAL, - SOFTRF_MODE_GROUND, - SOFTRF_MODE_WATCHOUT, - SOFTRF_MODE_BRIDGE, - SOFTRF_MODE_RELAY, - SOFTRF_MODE_TXRX_TEST, - SOFTRF_MODE_LOOPBACK, - SOFTRF_MODE_UAV, - SOFTRF_MODE_RECEIVER -}; - -enum -{ - SOFTRF_MODEL_STANDALONE, - SOFTRF_MODEL_PRIME, - SOFTRF_MODEL_UAV, - SOFTRF_MODEL_PRIME_MK2, - SOFTRF_MODEL_RASPBERRY, - SOFTRF_MODEL_UAT, - SOFTRF_MODEL_SKYVIEW, - SOFTRF_MODEL_RETRO, - SOFTRF_MODEL_SKYWATCH, - SOFTRF_MODEL_DONGLE, - SOFTRF_MODEL_MULTI, - SOFTRF_MODEL_UNI, - SOFTRF_MODEL_MINI -}; - -extern ufo_t ThisAircraft; -extern hardware_info_t hw_info; -extern const float txrx_test_positions[90][2] PROGMEM; - -extern void shutdown(const char *); - -#define TXRX_TEST_NUM_POSITIONS (sizeof(txrx_test_positions) / sizeof(float) / 2) -#define TXRX_TEST_ALTITUDE 438.0 -#define TXRX_TEST_COURSE 280.0 -#define TXRX_TEST_SPEED 50.0 -#define TXRX_TEST_VS -300.0 - -//#define ENABLE_TTN -//#define ENABLE_BT_VOICE -//#define TEST_PAW_ON_NICERF_SV610_FW466 -#define DO_GDL90_FF_EXT - -#define LOGGER_IS_ENABLED 0 - -#if LOGGER_IS_ENABLED -#define StdOut LogFile -#else -#define StdOut Serial -#endif /* LOGGER_IS_ENABLED */ - -#endif /* SOFTRF_H */ +/* + * SoftRF.h + * Copyright (C) 2019-2020 Linar Yusupov + * + * 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 . + */ + +#ifndef SOFTRF_H +#define SOFTRF_H + +#if defined(ARDUINO) +#include +#endif /* ARDUINO */ + +#if defined(ENERGIA_ARCH_CC13XX) || defined(ENERGIA_ARCH_CC13X2) +#include +#endif /* ENERGIA_ARCH_CC13XX || ENERGIA_ARCH_CC13X2 */ + +#if defined(RASPBERRY_PI) +#include +#endif /* RASPBERRY_PI */ + +#include "version.h" + +#define SOFTRF_FIRMWARE_VERSION _VERSION +#define SOFTRF_IDENT "OGNB-" + +#define ENTRY_EXPIRATION_TIME 10 /* seconds */ +#define LED_EXPIRATION_TIME 5 /* seconds */ +#define EXPORT_EXPIRATION_TIME 5 /* seconds */ + +/* + * If you need for SoftRF to operate in wireless + * client mode - specify your local AP's SSID/PSK: + * + * #define MY_ACCESSPOINT_SSID "My_AP_SSID" + * #define MY_ACCESSPOINT_PSK "My_AP_PSK" + * + * If SoftRF's built-in AP is not stable enough for you, consider + * to use "reverse" operation when your smartphone is acting + * as an AP for the SoftRF unit as a client: + * + * #define MY_ACCESSPOINT_SSID "AndroidAP" + * #define MY_ACCESSPOINT_PSK "12345678" + */ + +// Default mode is AP with +// SSID: SoftRF-XXXXXX +// KEY: 12345678 +// IP: 192.168.1.1 +// NETMASK: 255.255.255.0 + +#define MY_ACCESSPOINT_SSID "" +#define MY_ACCESSPOINT_PSK "" + +#define RELAY_DST_PORT 12390 +#define RELAY_SRC_PORT (RELAY_DST_PORT - 1) + +#define GDL90_DST_PORT 4000 +#define D1090_DST_PORT 4001 +#define NMEA_UDP_PORT 10110 +#define NMEA_TCP_PORT 2000 + +/* + * Serial I/O default values. + * Can be overridden by platfrom-specific code. + */ +#if !defined(SERIAL_IN_BR) +/* + * 9600 is default value of NMEA baud rate + * for most of GNSS modules + * being used in SoftRF project + */ +#define SERIAL_IN_BR 9600 +#endif +#if !defined(SERIAL_IN_BITS) +#define SERIAL_IN_BITS SERIAL_8N1 +#endif + +/* + * 38400 is known as maximum baud rate + * that HC-05 Bluetooth module + * can handle without symbols loss. + * + * Applicable for Standalone Edition. Inherited by most of other SoftRF platforms. + */ +#define STD_OUT_BR 38400 +#define STD_OUT_BITS SERIAL_8N1 + +#if !defined(SERIAL_OUT_BR) +#define SERIAL_OUT_BR STD_OUT_BR +#endif +#if !defined(SERIAL_OUT_BITS) +#define SERIAL_OUT_BITS STD_OUT_BITS +#endif + +#define UAT_RECEIVER_BR 2000000 + +#if defined(PREMIUM_PACKAGE) && !defined(RASPBERRY_PI) +#define ENABLE_AHRS +#endif /* PREMIUM_PACKAGE */ + +typedef struct UFO +{ + uint8_t raw[34]; + time_t timestamp; + + uint8_t protocol; + + uint32_t addr; + uint8_t addr_type; + float latitude; + float longitude; + float altitude; + float pressure_altitude; + float course; /* CoG */ + float speed; /* ground speed in knots */ + uint8_t aircraft_type; + + float vs; /* feet per minute */ + + bool stealth; + bool no_track; + + int8_t ns[4]; + int8_t ew[4]; + + float geoid_separation; /* metres */ + uint16_t hdop; /* cm */ + int8_t rssi; /* SX1276 only */ + + /* 'legacy' specific data */ + float distance; + float bearing; + int8_t alarm_level; + + /* ADS-B (ES, UAT, GDL90) specific data */ + uint8_t callsign[8]; +} ufo_t; + +typedef struct hardware_info +{ + byte model; + byte revision; + byte soc; + byte rf; + byte gnss; + byte baro; + byte display; +#if defined(ENABLE_AHRS) + byte ahrs; +#endif /* ENABLE_AHRS */ +} hardware_info_t; + +enum +{ + SOFTRF_MODE_NORMAL, + SOFTRF_MODE_GROUND, + SOFTRF_MODE_WATCHOUT, + SOFTRF_MODE_BRIDGE, + SOFTRF_MODE_RELAY, + SOFTRF_MODE_TXRX_TEST, + SOFTRF_MODE_LOOPBACK, + SOFTRF_MODE_UAV, + SOFTRF_MODE_RECEIVER +}; + +enum +{ + SOFTRF_MODEL_STANDALONE, + SOFTRF_MODEL_PRIME, + SOFTRF_MODEL_UAV, + SOFTRF_MODEL_PRIME_MK2, + SOFTRF_MODEL_RASPBERRY, + SOFTRF_MODEL_UAT, + SOFTRF_MODEL_SKYVIEW, + SOFTRF_MODEL_RETRO, + SOFTRF_MODEL_SKYWATCH, + SOFTRF_MODEL_DONGLE, + SOFTRF_MODEL_MULTI, + SOFTRF_MODEL_UNI, + SOFTRF_MODEL_MINI +}; + +extern ufo_t ThisAircraft; +extern hardware_info_t hw_info; +extern const float txrx_test_positions[90][2] PROGMEM; + +extern void shutdown(const char *); + +#define TXRX_TEST_NUM_POSITIONS (sizeof(txrx_test_positions) / sizeof(float) / 2) +#define TXRX_TEST_ALTITUDE 438.0 +#define TXRX_TEST_COURSE 280.0 +#define TXRX_TEST_SPEED 50.0 +#define TXRX_TEST_VS -300.0 + +//#define ENABLE_TTN +//#define ENABLE_BT_VOICE +//#define TEST_PAW_ON_NICERF_SV610_FW466 +#define DO_GDL90_FF_EXT + +#define LOGGER_IS_ENABLED 0 + +#if LOGGER_IS_ENABLED +#define StdOut LogFile +#else +#define StdOut Serial +#endif /* LOGGER_IS_ENABLED */ + +#endif /* SOFTRF_H */ diff --git a/ognbase/Time.cpp b/ognbase/Time.cpp index 31b943f..655a579 100644 --- a/ognbase/Time.cpp +++ b/ognbase/Time.cpp @@ -1,159 +1,159 @@ -/* - * Time.cpp - * Copyright (C) 2019-2020 Linar Yusupov - * - * 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 . - */ - -#include "SoC.h" - -#if defined(EXCLUDE_WIFI) -void Time_setup() -{} -#else - -#include - -unsigned int localPort = 2390; // local port to listen for UDP packets - -/* Don't hardwire the IP address or we won't get the benefits of the pool. - * Lookup the IP address for the host name instead */ -//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server -IPAddress timeServerIP; // time.nist.gov NTP server address -//const char* ntpServerName = "time.nist.gov"; -const String ntpServerName_suffix = ".pool.ntp.org"; - -const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message - -byte NTPPacketBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets - -// A UDP instance to let us send and receive packets over UDP -WiFiUDP NTP_udp; - -// send an NTP request to the time server at the given address -unsigned long sendNTPpacket(IPAddress& address) -{ - Serial.println(F("sending NTP packet...")); - // set all bytes in the buffer to 0 - memset(NTPPacketBuffer, 0, NTP_PACKET_SIZE); - // Initialize values needed to form NTP request - // (see URL above for details on the packets) - NTPPacketBuffer[0] = 0b11100011; // LI, Version, Mode - NTPPacketBuffer[1] = 0; // Stratum, or type of clock - NTPPacketBuffer[2] = 6; // Polling Interval - NTPPacketBuffer[3] = 0xEC; // Peer Clock Precision - // 8 bytes of zero for Root Delay & Root Dispersion - NTPPacketBuffer[12] = 49; - NTPPacketBuffer[13] = 0x4E; - NTPPacketBuffer[14] = 49; - NTPPacketBuffer[15] = 52; - - // all NTP fields have been given values, now - // you can send a packet requesting a timestamp: - NTP_udp.beginPacket(address, 123); //NTP requests are to port 123 - NTP_udp.write(NTPPacketBuffer, NTP_PACKET_SIZE); - NTP_udp.endPacket(); -} - -void Time_setup() -{ - int cb = 0; - String ntpServerName; - - // Do not attempt to timesync in Soft AP mode - if (WiFi.getMode() == WIFI_AP) - return; - - Serial.println(F("Starting NTP UDP")); - NTP_udp.begin(localPort); - Serial.print(F("Local port: ")); - Serial.println(localPort); - - for (int attempt = 1; attempt <= 4; attempt++) { - //get a random server from the pool - ntpServerName = String(attempt - 1) + ntpServerName_suffix; - WiFi.hostByName(ntpServerName.c_str(), timeServerIP); - - Serial.print('#'); - Serial.print(attempt); - Serial.print(F(" NTP server's IP address: ")); - Serial.println(timeServerIP); - - sendNTPpacket(timeServerIP); // send an NTP packet to a time server - - // wait to see if a reply is available - delay(2000); - - cb = NTP_udp.parsePacket(); - if (!cb) - { - Serial.print(F("No response on request #")); - Serial.println(attempt); - continue; - } - else - { - Serial.print(F("Reply packet received, length=")); - Serial.println(cb); - // We've received a packet, read the data from it - NTP_udp.read(NTPPacketBuffer, NTP_PACKET_SIZE); // read the packet into the buffer - break; - } - } - - NTP_udp.stop(); - - if (!cb) - { - Serial.println(F("WARNING! Unable to sync time by NTP.")); - return; - } - - //the timestamp starts at byte 40 of the received packet and is four bytes, - // or two words, long. First, esxtract the two words: - - unsigned long highWord = word(NTPPacketBuffer[40], NTPPacketBuffer[41]); - unsigned long lowWord = word(NTPPacketBuffer[42], NTPPacketBuffer[43]); - // combine the four bytes (two words) into a long integer - // this is NTP time (seconds since Jan 1 1900): - unsigned long secsSince1900 = highWord << 16 | lowWord; - Serial.print(F("Seconds since Jan 1 1900 = ")); - Serial.println(secsSince1900); - - // now convert NTP time into everyday time: - Serial.print(F("Unix time = ")); - // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: - const unsigned long seventyYears = 2208988800UL; - // subtract seventy years: - unsigned long epoch = secsSince1900 - seventyYears; - // print Unix time: - Serial.println(epoch); - setTime((time_t) epoch); - - // print the hour, minute and second: - Serial.print(F("The UTC time is ")); // UTC is the time at Greenwich Meridian (GMT) - Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) - Serial.print(':'); - if (((epoch % 3600) / 60) < 10) - // In the first 10 minutes of each hour, we'll want a leading '0' - Serial.print('0'); - Serial.print((epoch % 3600) / 60);// print the minute (3600 equals secs per minute) - Serial.print(':'); - if ((epoch % 60) < 10) - // In the first 10 seconds of each minute, we'll want a leading '0' - Serial.print('0'); - Serial.println(epoch % 60); // print the second -} - -#endif /* EXCLUDE_WIFI */ +/* + * Time.cpp + * Copyright (C) 2019-2020 Linar Yusupov + * + * 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 . + */ + +#include "SoC.h" + +#if defined(EXCLUDE_WIFI) +void Time_setup() +{} +#else + +#include + +unsigned int localPort = 2390; // local port to listen for UDP packets + +/* Don't hardwire the IP address or we won't get the benefits of the pool. + * Lookup the IP address for the host name instead */ +//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server +IPAddress timeServerIP; // time.nist.gov NTP server address +//const char* ntpServerName = "time.nist.gov"; +const String ntpServerName_suffix = ".pool.ntp.org"; + +const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message + +byte NTPPacketBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets + +// A UDP instance to let us send and receive packets over UDP +WiFiUDP NTP_udp; + +// send an NTP request to the time server at the given address +unsigned long sendNTPpacket(IPAddress& address) +{ + Serial.println(F("sending NTP packet...")); + // set all bytes in the buffer to 0 + memset(NTPPacketBuffer, 0, NTP_PACKET_SIZE); + // Initialize values needed to form NTP request + // (see URL above for details on the packets) + NTPPacketBuffer[0] = 0b11100011; // LI, Version, Mode + NTPPacketBuffer[1] = 0; // Stratum, or type of clock + NTPPacketBuffer[2] = 6; // Polling Interval + NTPPacketBuffer[3] = 0xEC; // Peer Clock Precision + // 8 bytes of zero for Root Delay & Root Dispersion + NTPPacketBuffer[12] = 49; + NTPPacketBuffer[13] = 0x4E; + NTPPacketBuffer[14] = 49; + NTPPacketBuffer[15] = 52; + + // all NTP fields have been given values, now + // you can send a packet requesting a timestamp: + NTP_udp.beginPacket(address, 123); //NTP requests are to port 123 + NTP_udp.write(NTPPacketBuffer, NTP_PACKET_SIZE); + NTP_udp.endPacket(); +} + +void Time_setup() +{ + int cb = 0; + String ntpServerName; + + // Do not attempt to timesync in Soft AP mode + if (WiFi.getMode() == WIFI_AP) + return; + + Serial.println(F("Starting NTP UDP")); + NTP_udp.begin(localPort); + Serial.print(F("Local port: ")); + Serial.println(localPort); + + for (int attempt = 1; attempt <= 4; attempt++) { + //get a random server from the pool + ntpServerName = String(attempt - 1) + ntpServerName_suffix; + WiFi.hostByName(ntpServerName.c_str(), timeServerIP); + + Serial.print('#'); + Serial.print(attempt); + Serial.print(F(" NTP server's IP address: ")); + Serial.println(timeServerIP); + + sendNTPpacket(timeServerIP); // send an NTP packet to a time server + + // wait to see if a reply is available + delay(2000); + + cb = NTP_udp.parsePacket(); + if (!cb) + { + Serial.print(F("No response on request #")); + Serial.println(attempt); + continue; + } + else + { + Serial.print(F("Reply packet received, length=")); + Serial.println(cb); + // We've received a packet, read the data from it + NTP_udp.read(NTPPacketBuffer, NTP_PACKET_SIZE); // read the packet into the buffer + break; + } + } + + NTP_udp.stop(); + + if (!cb) + { + Serial.println(F("WARNING! Unable to sync time by NTP.")); + return; + } + + //the timestamp starts at byte 40 of the received packet and is four bytes, + // or two words, long. First, esxtract the two words: + + unsigned long highWord = word(NTPPacketBuffer[40], NTPPacketBuffer[41]); + unsigned long lowWord = word(NTPPacketBuffer[42], NTPPacketBuffer[43]); + // combine the four bytes (two words) into a long integer + // this is NTP time (seconds since Jan 1 1900): + unsigned long secsSince1900 = highWord << 16 | lowWord; + Serial.print(F("Seconds since Jan 1 1900 = ")); + Serial.println(secsSince1900); + + // now convert NTP time into everyday time: + Serial.print(F("Unix time = ")); + // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: + const unsigned long seventyYears = 2208988800UL; + // subtract seventy years: + unsigned long epoch = secsSince1900 - seventyYears; + // print Unix time: + Serial.println(epoch); + setTime((time_t) epoch); + + // print the hour, minute and second: + Serial.print(F("The UTC time is ")); // UTC is the time at Greenwich Meridian (GMT) + Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) + Serial.print(':'); + if (((epoch % 3600) / 60) < 10) + // In the first 10 minutes of each hour, we'll want a leading '0' + Serial.print('0'); + Serial.print((epoch % 3600) / 60);// print the minute (3600 equals secs per minute) + Serial.print(':'); + if ((epoch % 60) < 10) + // In the first 10 seconds of each minute, we'll want a leading '0' + Serial.print('0'); + Serial.println(epoch % 60); // print the second +} + +#endif /* EXCLUDE_WIFI */ diff --git a/ognbase/Traffic.cpp b/ognbase/Traffic.cpp index e8b8ad7..f5f4dfd 100644 --- a/ognbase/Traffic.cpp +++ b/ognbase/Traffic.cpp @@ -1,233 +1,234 @@ -/* - * Traffic.cpp - * Copyright (C) 2018-2020 Linar Yusupov - * - * 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 . - */ - -#include "Traffic.h" -#include "EEPROM.h" -#include "RF.h" -#include "GNSS.h" -#include "Web.h" -#include "Protocol_Legacy.h" -#include "OLED.h" - - -unsigned long UpdateTrafficTimeMarker = 0; - -ufo_t fo, Container[MAX_TRACKING_OBJECTS], EmptyFO; - -static int8_t (* Alarm_Level)(ufo_t *, ufo_t *); - -/* - * No any alarms issued by the firmware. - * Rely upon high-level flight management software. - */ -static int8_t Alarm_None(ufo_t* this_aircraft, ufo_t* fop) -{ - return ALARM_LEVEL_NONE; -} - -/* - * Simple, distance based alarm level assignment. - */ -static int8_t Alarm_Distance(ufo_t* this_aircraft, ufo_t* fop) -{ - int distance = (int) fop->distance; - int8_t rval = ALARM_LEVEL_NONE; - int alt_diff = (int) (fop->altitude - this_aircraft->altitude); - - if (abs(alt_diff) < VERTICAL_SEPARATION) /* no warnings if too high or too low */ - { - if (distance < ALARM_ZONE_URGENT) - rval = ALARM_LEVEL_URGENT; - else if (distance < ALARM_ZONE_IMPORTANT) - rval = ALARM_LEVEL_IMPORTANT; - else if (distance < ALARM_ZONE_LOW) - rval = ALARM_LEVEL_LOW; - } - - return rval; -} - -/* - * EXPERIMENTAL - * - * Linear, CoG and GS based collision prediction. - */ -static int8_t Alarm_Vector(ufo_t* this_aircraft, ufo_t* fop) -{ - int8_t rval = ALARM_LEVEL_NONE; - int alt_diff = (int) (fop->altitude - this_aircraft->altitude); - - if (abs(alt_diff) < VERTICAL_SEPARATION) /* no warnings if too high or too low */ - - /* Subtract 2D velocity vector of traffic from 2D velocity vector of this aircraft */ - { - float V_rel_x = this_aircraft->speed * cosf(radians(90.0 - this_aircraft->course)) - - fop->speed * cosf(radians(90.0 - fop->course)); - float V_rel_y = this_aircraft->speed * sinf(radians(90.0 - this_aircraft->course)) - - fop->speed * sinf(radians(90.0 - fop->course)); - - float V_rel_magnitude = sqrtf(V_rel_x * V_rel_x + V_rel_y * V_rel_y) * _GPS_MPS_PER_KNOT; - float V_rel_direction = atan2f(V_rel_y, V_rel_x) * 180.0 / PI; /* -180 ... 180 */ - - /* convert from math angle into course relative to north */ - V_rel_direction = (V_rel_direction <= 90.0 ? 90.0 - V_rel_direction : - 450.0 - V_rel_direction); - - /* +- 10 degrees tolerance for collision course */ - if (V_rel_magnitude > 0.1 && fabs(V_rel_direction - fop->bearing) < 10.0) - { - /* time is seconds prior to impact */ - float t = fop->distance / V_rel_magnitude; - - /* time limit values are compliant with FLARM data port specs */ - if (t < 9.0) - rval = ALARM_LEVEL_URGENT; - else if (t < 13.0) - rval = ALARM_LEVEL_IMPORTANT; - else if (t < 19.0) - rval = ALARM_LEVEL_LOW; - } - } - return rval; -} - -/* - * "Legacy" method is based on short history of 2D velocity vectors (NS/EW) - */ -static int8_t Alarm_Legacy(ufo_t* this_aircraft, ufo_t* fop) -{ - int8_t rval = ALARM_LEVEL_NONE; - - /* TBD */ - - return rval; -} - -void Traffic_Update(int ndx) -{ - Container[ndx].distance = gnss.distanceBetween(ThisAircraft.latitude, - ThisAircraft.longitude, - Container[ndx].latitude, - Container[ndx].longitude); - - Container[ndx].bearing = gnss.courseTo(ThisAircraft.latitude, - ThisAircraft.longitude, - Container[ndx].latitude, - Container[ndx].longitude); - - if (Alarm_Level) - Container[ndx].alarm_level = (*Alarm_Level)(&ThisAircraft, &Container[ndx]); -} - -void ParseData() -{ - size_t rx_size = RF_Payload_Size(settings->rf_protocol); - rx_size = rx_size > sizeof(fo.raw) ? sizeof(fo.raw) : rx_size; - - char buf[16]; - -#if DEBUG - Hex2Bin(TxDataTemplate, RxBuffer); -#endif - - memset(fo.raw, 0, sizeof(fo.raw)); - memcpy(fo.raw, RxBuffer, rx_size); - - if (settings->nmea_p) - { - StdOut.print(F("$PSRFI,")); - StdOut.print((unsigned long) now()); - StdOut.print(F(",")); - StdOut.print(Bin2Hex(fo.raw, rx_size)); - StdOut.print(F(",")); - StdOut.println(RF_last_rssi); - } - - if (protocol_decode && (*protocol_decode)((void *) RxBuffer, &ThisAircraft, &fo)) - { - int i; - - fo.rssi = RF_last_rssi; - - for (i=0; i < MAX_TRACKING_OBJECTS; i++) { - if (Container[i].addr == fo.addr) - { - Container[i] = fo; - Traffic_Update(i); - break; - } - else if (now() - Container[i].timestamp > ENTRY_EXPIRATION_TIME) - { - Container[i] = fo; - Traffic_Update(i); - break; - } - } - // detect and delete double IDs - Caz Yokoyama fix - while (++i < MAX_TRACKING_OBJECTS) { - if (Container[i].addr == fo.addr) - Container[i] = EmptyFO; - } - } -} - -void Traffic_setup() -{ - switch (settings->alarm) - { - case TRAFFIC_ALARM_NONE: - Alarm_Level = &Alarm_None; - break; - case TRAFFIC_ALARM_VECTOR: - Alarm_Level = &Alarm_Vector; - break; - case TRAFFIC_ALARM_LEGACY: - Alarm_Level = &Alarm_Legacy; - break; - case TRAFFIC_ALARM_DISTANCE: - default: - Alarm_Level = &Alarm_Distance; - break; - } -} - -void Traffic_loop() -{ - if (isTimeToUpdateTraffic()) - { - for (int i=0; i < MAX_TRACKING_OBJECTS; i++) { - if (Container[i].addr && - (ThisAircraft.timestamp - Container[i].timestamp) <= ENTRY_EXPIRATION_TIME) - { - if ((ThisAircraft.timestamp - Container[i].timestamp) >= TRAFFIC_VECTOR_UPDATE_INTERVAL) - Traffic_Update(i); - } - else - Container[i] = EmptyFO; - } - - UpdateTrafficTimeMarker = millis(); - } -} - -void ClearExpired() -{ - for (int i=0; i < MAX_TRACKING_OBJECTS; i++) - if (Container[i].addr && (ThisAircraft.timestamp - Container[i].timestamp) > ENTRY_EXPIRATION_TIME) - Container[i] = EmptyFO; -} +/* + * Traffic.cpp + * Copyright (C) 2018-2020 Linar Yusupov + * + * 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 . + */ + +#include "Traffic.h" +#include "EEPROM.h" +#include "RF.h" +#include "GNSS.h" +#include "Web.h" +#include "Protocol_Legacy.h" +#include "OLED.h" +#include "global.h" + + +unsigned long UpdateTrafficTimeMarker = 0; + +ufo_t fo, Container[MAX_TRACKING_OBJECTS], EmptyFO; + +static int8_t (* Alarm_Level)(ufo_t *, ufo_t *); + +/* + * No any alarms issued by the firmware. + * Rely upon high-level flight management software. + */ +static int8_t Alarm_None(ufo_t* this_aircraft, ufo_t* fop) +{ + return ALARM_LEVEL_NONE; +} + +/* + * Simple, distance based alarm level assignment. + */ +static int8_t Alarm_Distance(ufo_t* this_aircraft, ufo_t* fop) +{ + int distance = (int) fop->distance; + int8_t rval = ALARM_LEVEL_NONE; + int alt_diff = (int) (fop->altitude - this_aircraft->altitude); + + if (abs(alt_diff) < VERTICAL_SEPARATION) /* no warnings if too high or too low */ + { + if (distance < ALARM_ZONE_URGENT) + rval = ALARM_LEVEL_URGENT; + else if (distance < ALARM_ZONE_IMPORTANT) + rval = ALARM_LEVEL_IMPORTANT; + else if (distance < ALARM_ZONE_LOW) + rval = ALARM_LEVEL_LOW; + } + + return rval; +} + +/* + * EXPERIMENTAL + * + * Linear, CoG and GS based collision prediction. + */ +static int8_t Alarm_Vector(ufo_t* this_aircraft, ufo_t* fop) +{ + int8_t rval = ALARM_LEVEL_NONE; + int alt_diff = (int) (fop->altitude - this_aircraft->altitude); + + if (abs(alt_diff) < VERTICAL_SEPARATION) /* no warnings if too high or too low */ + + /* Subtract 2D velocity vector of traffic from 2D velocity vector of this aircraft */ + { + float V_rel_x = this_aircraft->speed * cosf(radians(90.0 - this_aircraft->course)) - + fop->speed * cosf(radians(90.0 - fop->course)); + float V_rel_y = this_aircraft->speed * sinf(radians(90.0 - this_aircraft->course)) - + fop->speed * sinf(radians(90.0 - fop->course)); + + float V_rel_magnitude = sqrtf(V_rel_x * V_rel_x + V_rel_y * V_rel_y) * _GPS_MPS_PER_KNOT; + float V_rel_direction = atan2f(V_rel_y, V_rel_x) * 180.0 / PI; /* -180 ... 180 */ + + /* convert from math angle into course relative to north */ + V_rel_direction = (V_rel_direction <= 90.0 ? 90.0 - V_rel_direction : + 450.0 - V_rel_direction); + + /* +- 10 degrees tolerance for collision course */ + if (V_rel_magnitude > 0.1 && fabs(V_rel_direction - fop->bearing) < 10.0) + { + /* time is seconds prior to impact */ + float t = fop->distance / V_rel_magnitude; + + /* time limit values are compliant with FLARM data port specs */ + if (t < 9.0) + rval = ALARM_LEVEL_URGENT; + else if (t < 13.0) + rval = ALARM_LEVEL_IMPORTANT; + else if (t < 19.0) + rval = ALARM_LEVEL_LOW; + } + } + return rval; +} + +/* + * "Legacy" method is based on short history of 2D velocity vectors (NS/EW) + */ +static int8_t Alarm_Legacy(ufo_t* this_aircraft, ufo_t* fop) +{ + int8_t rval = ALARM_LEVEL_NONE; + + /* TBD */ + + return rval; +} + +void Traffic_Update(int ndx) +{ + Container[ndx].distance = gnss.distanceBetween(ThisAircraft.latitude, + ThisAircraft.longitude, + Container[ndx].latitude, + Container[ndx].longitude); + + Container[ndx].bearing = gnss.courseTo(ThisAircraft.latitude, + ThisAircraft.longitude, + Container[ndx].latitude, + Container[ndx].longitude); + + if (Alarm_Level) + Container[ndx].alarm_level = (*Alarm_Level)(&ThisAircraft, &Container[ndx]); +} + +void ParseData() +{ + size_t rx_size = RF_Payload_Size(ogn_protocol_1); + rx_size = rx_size > sizeof(fo.raw) ? sizeof(fo.raw) : rx_size; + + char buf[16]; + +#if DEBUG + Hex2Bin(TxDataTemplate, RxBuffer); +#endif + + memset(fo.raw, 0, sizeof(fo.raw)); + memcpy(fo.raw, RxBuffer, rx_size); + + if (settings->nmea_p) + { + StdOut.print(F("$PSRFI,")); + StdOut.print((unsigned long) now()); + StdOut.print(F(",")); + StdOut.print(Bin2Hex(fo.raw, rx_size)); + StdOut.print(F(",")); + StdOut.println(RF_last_rssi); + } + + if (protocol_decode && (*protocol_decode)((void *) RxBuffer, &ThisAircraft, &fo)) + { + int i; + + fo.rssi = RF_last_rssi; + + for (i=0; i < MAX_TRACKING_OBJECTS; i++) { + if (Container[i].addr == fo.addr) + { + Container[i] = fo; + Traffic_Update(i); + break; + } + else if (now() - Container[i].timestamp > ENTRY_EXPIRATION_TIME) + { + Container[i] = fo; + Traffic_Update(i); + break; + } + } + // detect and delete double IDs - Caz Yokoyama fix + while (++i < MAX_TRACKING_OBJECTS) { + if (Container[i].addr == fo.addr) + Container[i] = EmptyFO; + } + } +} + +void Traffic_setup() +{ + switch (settings->alarm) + { + case TRAFFIC_ALARM_NONE: + Alarm_Level = &Alarm_None; + break; + case TRAFFIC_ALARM_VECTOR: + Alarm_Level = &Alarm_Vector; + break; + case TRAFFIC_ALARM_LEGACY: + Alarm_Level = &Alarm_Legacy; + break; + case TRAFFIC_ALARM_DISTANCE: + default: + Alarm_Level = &Alarm_Distance; + break; + } +} + +void Traffic_loop() +{ + if (isTimeToUpdateTraffic()) + { + for (int i=0; i < MAX_TRACKING_OBJECTS; i++) { + if (Container[i].addr && + (ThisAircraft.timestamp - Container[i].timestamp) <= ENTRY_EXPIRATION_TIME) + { + if ((ThisAircraft.timestamp - Container[i].timestamp) >= TRAFFIC_VECTOR_UPDATE_INTERVAL) + Traffic_Update(i); + } + else + Container[i] = EmptyFO; + } + + UpdateTrafficTimeMarker = millis(); + } +} + +void ClearExpired() +{ + for (int i=0; i < MAX_TRACKING_OBJECTS; i++) + if (Container[i].addr && (ThisAircraft.timestamp - Container[i].timestamp) > ENTRY_EXPIRATION_TIME) + Container[i] = EmptyFO; +} diff --git a/ognbase/Web.cpp b/ognbase/Web.cpp index 5ea2de2..5da50af 100644 --- a/ognbase/Web.cpp +++ b/ognbase/Web.cpp @@ -1,528 +1,434 @@ -/* - * Web.cpp - * Copyright (C) 2020 Manuel Rösel - * - * 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 . - */ - -#include "WiFi.h" -#include "ESPAsyncWebServer.h" -#include "SPIFFS.h" -#include "SoC.h" -#include "EEPROM.h" -#include "RF.h" -#include "global.h" -#include "Battery.h" -#include "Log.h" - -#include - -#include // Include the SPIFFS library - -#define U_PART U_FLASH -#define INDEX_CRC 3948812196 - -#define hours() (millis() / 3600000) - - -File fsUploadFile; - -String ogn_ssid = "ognbase"; -String ogn_wpass = "123456789"; -String ogn_callsign = "callsign"; - -float ogn_lat = 0; -float ogn_lon = 0; -int ogn_alt = 0; -int ogn_geoid_separation = 0; -uint8_t largest_range = 0; - -#define countof(a) (sizeof(a) / sizeof(a[0])) - -// Create AsyncWebServer object on port 80 -AsyncWebServer wserver(80); -AsyncWebSocket ws("/ws"); - -AsyncWebSocketClient* globalClient = NULL; - -size_t content_len; - -static const char upload_html[] PROGMEM = "\ - \ - \ - \ -
\ -
\ - \ -
\ - "; - - -void onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) -{ - if (type == WS_EVT_CONNECT) - - globalClient = client; - - else if (type == WS_EVT_DISCONNECT) - - globalClient = NULL; -} - -// Replaces placeholder with LED state value -String processor(const String& var) -{ - Serial.println(var); - return "ON"; -} - -bool OGN_config_store(String* ssid, String* pass, String* callsign, float lat, float lon, int alt) -{ - // Deleting old file - SPIFFS.remove("/ogn_conf.txt"); - - // Open config file for writing. - File configFile = SPIFFS.open("/ogn_conf.txt", "w"); - if (!configFile) - { - Serial.println(F("Failed to open ogn_conf.txt for writing")); - return false; - } - - // Save SSID and PSK. - configFile.println(*ssid); - configFile.println(*pass); - configFile.println(*callsign); - - configFile.println(lat, 6); - configFile.println(lon, 6); - configFile.println(alt); - configFile.println(ogn_geoid_separation); - - configFile.close(); - - return true; -} - -bool loadConfig() -{ - int line = 0; - - // open file for reading. - File configFile = SPIFFS.open("/ogn_conf.txt", "r"); - if (!configFile) - { - Serial.println(F("Failed to open ogn_conf.txt.")); - return false; - } - - while (configFile.available() && line < 7) - { - if (line == 0) - ogn_ssid = configFile.readStringUntil('\n').c_str(); - if (line == 1) - ogn_wpass = configFile.readStringUntil('\n').c_str(); - if (line == 2) - ogn_callsign = configFile.readStringUntil('\n').c_str(); - if (line == 3) - ogn_lat = configFile.readStringUntil('\n').toFloat(); - if (line == 4) - ogn_lon = configFile.readStringUntil('\n').toFloat(); - if (line == 5) - ogn_alt = configFile.readStringUntil('\n').toInt(); - if (line == 6) - ogn_geoid_separation = configFile.readStringUntil('\n').toInt(); - line++; - } - - configFile.close(); - - if (line < 2) - return false; - - ogn_ssid.trim(); - ogn_wpass.trim(); - ogn_callsign.trim(); - - return true; -} // loadConfig - -void Web_fini() -{} - -void handleUpdate(AsyncWebServerRequest* request) -{ - char* html = "
"; - request->send(200, "text/html", html); -} - -void handleUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final) -{ - if (!index) - request->_tempFile = SPIFFS.open("/" + filename, "w"); - if (len) - // stream the incoming chunk to the opened file - request->_tempFile.write(data, len); - if (final) - { - request->_tempFile.close(); - request->redirect("/"); - } -} - -void handleDoUpdate(AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, size_t len, bool final) -{ - String msg; - - if (!index) - { - Serial.println("Update"); - content_len = request->contentLength(); - // if filename includes spiffs, update the spiffs partition - int cmd = (filename.indexOf("spiffs") > -1) ? U_PART : U_FLASH; -#ifdef ESP8266 - Update.runAsync(true); - if (!Update.begin(content_len, cmd)) - { -#else - if (!Update.begin(UPDATE_SIZE_UNKNOWN, cmd)) - { -#endif - Update.printError(Serial); - } - } - - if (Update.write(data, len) != len) - { - Update.printError(Serial); -#ifdef ESP8266 - } - else - { - Serial.printf("Progress: %d%%\n", (Update.progress() * 100) / Update.size()); -#endif - } - - if (final) - { - AsyncWebServerResponse* response = request->beginResponse(302, "text/plain", "Please wait while the device reboots"); - response->addHeader("Refresh", "20"); - response->addHeader("Location", "/"); - request->send(response); - if (!Update.end(true)) - Update.printError(Serial); - else - { - Serial.println("Update complete"); - Serial.flush(); - msg = "updating firmware"; - Logger_send_udp(&msg); - ESP.restart(); - } - } -} - -void Web_start() -{ - wserver.begin(); -} - -void Web_stop() -{ - wserver.end(); -} - -void Web_setup(ufo_t* this_aircraft) -{ - if (!SPIFFS.begin(true)) - { - Serial.println("An Error has occurred while mounting SPIFFS"); - return; - } - - if (!SPIFFS.exists("/index.html")) - { - wserver.on("/", HTTP_GET, [upload_html](AsyncWebServerRequest* request){ - request->send(200, "text/html", upload_html); - }); - - wserver.on("/doUpload", HTTP_POST, [](AsyncWebServerRequest* request) {}, handleUpload); - - Web_start(); - return; - } - - loadConfig(); - - File file = SPIFFS.open("/index.html", "r"); - if (!file) - { - Serial.println("An Error has occurred while opening index.html"); - return; - } - - ws.onEvent(onWsEvent); - wserver.addHandler(&ws); - - - size_t filesize = file.size(); - char* index_html = (char *) malloc(filesize + 1); - - file.read((uint8_t *)index_html, filesize); - index_html[filesize] = '\0'; - - //CRC check 1363406144 - /* - uint32_t crc = crc32String(index_html); - if (crc != INDEX_CRC) - { - SPIFFS.remove("/index.html"); - Serial.println("CRC checksum from index.html doesnt match"); - Serial.println(crc); - ESP.restart(); - } - // - */ - - size_t size = 8700; - char* offset; - char* Settings_temp = (char *) malloc(size); - - if (Settings_temp == NULL) - return; - - offset = Settings_temp; - - String station_addr = String(this_aircraft->addr, HEX); - station_addr.toUpperCase(); - - snprintf(offset, size, index_html, - station_addr, - SOFTRF_FIRMWARE_VERSION, - ogn_callsign, - String(ogn_lat, 5), - String(ogn_lon, 5), - String(ogn_alt), - String(ogn_geoid_separation), - String(settings->range), - (settings->band == RF_BAND_AUTO ? "selected" : ""), RF_BAND_AUTO, - (settings->band == RF_BAND_EU ? "selected" : ""), RF_BAND_EU, - (settings->band == RF_BAND_RU ? "selected" : ""), RF_BAND_RU, - (settings->band == RF_BAND_CN ? "selected" : ""), RF_BAND_CN, - (settings->band == RF_BAND_US ? "selected" : ""), RF_BAND_US, - (settings->band == RF_BAND_NZ ? "selected" : ""), RF_BAND_NZ, - (settings->band == RF_BAND_UK ? "selected" : ""), RF_BAND_UK, - (settings->band == RF_BAND_AU ? "selected" : ""), RF_BAND_AU, - (settings->band == RF_BAND_IN ? "selected" : ""), RF_BAND_IN, - (settings->rf_protocol == RF_PROTOCOL_LEGACY ? "selected" : ""), - RF_PROTOCOL_LEGACY, legacy_proto_desc.name, - (settings->rf_protocol == RF_PROTOCOL_OGNTP ? "selected" : ""), - RF_PROTOCOL_OGNTP, ogntp_proto_desc.name, - (settings->rf_protocol == RF_PROTOCOL_P3I ? "selected" : ""), - RF_PROTOCOL_P3I, p3i_proto_desc.name, - (settings->rf_protocol == RF_PROTOCOL_FANET ? "selected" : ""), - RF_PROTOCOL_FANET, fanet_proto_desc.name, - - (settings->rf_protocol2 == RF_PROTOCOL_LEGACY ? "selected" : ""), - RF_PROTOCOL_LEGACY, legacy_proto_desc.name, - (settings->rf_protocol2 == RF_PROTOCOL_OGNTP ? "selected" : ""), - RF_PROTOCOL_OGNTP, ogntp_proto_desc.name, - (settings->rf_protocol2 == RF_PROTOCOL_P3I ? "selected" : ""), - RF_PROTOCOL_P3I, p3i_proto_desc.name, - (settings->rf_protocol2 == RF_PROTOCOL_FANET ? "selected" : ""), - RF_PROTOCOL_FANET, fanet_proto_desc.name, - - (settings->ogndebug == true ? "selected" : ""), - (settings->ogndebug == false ? "selected" : ""), - String(settings->ogndebugp), - - (settings->ignore_no_track == true ? "selected" : ""), "True", - (settings->ignore_no_track == false ? "selected" : ""), "False", - - (settings->ignore_stealth == true ? "selected" : ""), "True", - (settings->ignore_stealth == false ? "selected" : ""), "False", - - ogn_ssid.c_str(), - ogn_wpass.c_str(), - - (settings->sleep_mode == 0 ? "selected" : ""), "Disabled", - (settings->sleep_mode == 1 ? "selected" : ""), "Full", - (settings->sleep_mode == 2 ? "selected" : ""), "without GPS", //zabbix_trap_en - - String(settings->sleep_after_rx_idle), - String(settings->wake_up_timer), - - (settings->zabbix_en == 0 ? "selected" : ""), "Disabled", - (settings->zabbix_en == 1 ? "selected" : ""), "Enabled" - ); - - size_t len = strlen(offset); - String html = String(offset); - - wserver.on("/", HTTP_GET, [html](AsyncWebServerRequest* request){ - request->send(200, "text/html", html); - }); - - - // Route to load style.css file - wserver.on("/style.css", HTTP_GET, [](AsyncWebServerRequest* request){ - request->send(SPIFFS, "/style.css", "text/css"); - }); - - wserver.on("/update", HTTP_GET, [](AsyncWebServerRequest* request){ - handleUpdate(request); - request->redirect("/"); - }); - - wserver.on("/doUpdate", HTTP_POST, - [](AsyncWebServerRequest* request) {}, - [](AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, - size_t len, bool final) { - handleDoUpdate(request, filename, index, data, len, final); - }); - - wserver.on("/upload", HTTP_GET, [upload_html](AsyncWebServerRequest* request){ - request->send(200, "text/html", upload_html); - }); - - wserver.on("/doUpload", HTTP_POST, [](AsyncWebServerRequest* request) {}, handleUpload); - - - // Send a GET request to /get?inputString= - wserver.on("/get", HTTP_GET, [](AsyncWebServerRequest* request) { - if (request->hasParam("callsign")) - ogn_callsign = request->getParam("callsign")->value(); - if (request->hasParam("ogn_lat")) - ogn_lat = request->getParam("ogn_lat")->value().toFloat(); - - if (request->hasParam("ogn_lon")) - ogn_lon = request->getParam("ogn_lon")->value().toFloat(); - - if (request->hasParam("ogn_alt")) - ogn_alt = request->getParam("ogn_alt")->value().toInt(); - - if (request->hasParam("ogn_freq")) - settings->band = request->getParam("ogn_freq")->value().toInt(); - - if (request->hasParam("ogn_proto")) - settings->rf_protocol = request->getParam("ogn_proto")->value().toInt(); - - if (request->hasParam("ogn_proto2")) - settings->rf_protocol2 = request->getParam("ogn_proto2")->value().toInt(); - - if (request->hasParam("ogn_d1090")) - settings->d1090 = request->getParam("ogn_d1090")->value().toInt(); - - if (request->hasParam("ogn_gdl90")) - settings->gdl90 = request->getParam("ogn_gdl90")->value().toInt(); - - if (request->hasParam("ogn_nmea")) - settings->nmea_out = request->getParam("ogn_nmea")->value().toInt(); - - if (request->hasParam("ogn_no_track_bit")) - settings->no_track = request->getParam("ogn_no_track_bit")->value().toInt(); - - if (request->hasParam("ogn_stealth_bit")) - settings->stealth = request->getParam("ogn_stealth_bit")->value().toInt(); - - if (request->hasParam("ogn_aprs_debug")) - settings->ogndebug = request->getParam("ogn_aprs_debug")->value().toInt(); - - if (request->hasParam("aprs_debug_port")) - settings->ogndebugp = request->getParam("aprs_debug_port")->value().toInt(); - - if (request->hasParam("ogn_range")) - settings->range = request->getParam("ogn_range")->value().toInt(); - - if (request->hasParam("ogn_agc")) - settings->sxlna = request->getParam("ogn_agc")->value().toInt(); - - if (request->hasParam("ogn_ssid")) - ogn_ssid = request->getParam("ogn_ssid")->value(); - - if (request->hasParam("ogn_wifi_password")) - ogn_wpass = request->getParam("ogn_wifi_password")->value(); - //geoid_separation - if (request->hasParam("ogn_geoid")) - ogn_geoid_separation = request->getParam("ogn_geoid")->value().toInt(); - - if (request->hasParam("ogn_ignore_track")) - settings->ignore_no_track = request->getParam("ogn_ignore_track")->value().toInt(); - - if (request->hasParam("ogn_ignore_stealth")) - settings->ignore_stealth = request->getParam("ogn_ignore_stealth")->value().toInt(); - - if (request->hasParam("ogn_deep_sleep")) - settings->sleep_mode = request->getParam("ogn_deep_sleep")->value().toInt(); - - if (request->hasParam("ogn_sleep_time")) - { - if (request->getParam("ogn_sleep_time")->value().toInt() <= 60) - settings->sleep_after_rx_idle = 60; - else - settings->sleep_after_rx_idle = request->getParam("ogn_sleep_time")->value().toInt(); - } - if (request->hasParam("ogn_wakeup_time")) - settings->wake_up_timer = request->getParam("ogn_wakeup_time")->value().toInt(); - - if (request->hasParam("zabbix_trap_en")) - settings->zabbix_en = request->getParam("zabbix_trap_en")->value().toInt(); - - - request->redirect("/"); - - // ogn_reset_all - if (request->hasParam("ogn_reset_all")) - if (request->getParam("ogn_reset_all")->value() == "on") - { - SPIFFS.format(); - RF_Shutdown(); - delay(1000); - SoC->reset(); - } - - EEPROM_store(); - OGN_config_store(&ogn_ssid, &ogn_wpass, &ogn_callsign, ogn_lat, ogn_lon, ogn_alt); - RF_Shutdown(); - delay(1000); - SoC->reset(); - }); - - SoC->swSer_enableRx(true); - free(Settings_temp); - free(index_html); - - // Start server - Web_start(); -} - -void Web_loop(void) -{ - if (globalClient != NULL && globalClient->status() == WS_CONNECTED) - { - String values; - values =+SoC->Battery_voltage(); - values += "_"; - values += RF_last_rssi; - values += "_"; - values += hours(); - values += "_"; - values += gnss.satellites.value(); - values += "_"; - values += now(); - values += "_"; - values += largest_range; - globalClient->text(values); - } -} +/* + * Web.cpp + * Copyright (C) 2020 Manuel Rösel + * + * 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 . + */ + +#include "WiFi.h" +#include "ESPAsyncWebServer.h" +#include "SPIFFS.h" +#include "SoC.h" +#include "EEPROM.h" +#include "RF.h" +#include "global.h" +#include "Battery.h" +#include "Log.h" +#include "config.h" +#include + +#include + +#include // Include the SPIFFS library + +#define U_PART U_FLASH +#define INDEX_CRC 3948812196 + +#define hours() (millis() / 3600000) + + +File fsUploadFile; + +#define countof(a) (sizeof(a) / sizeof(a[0])) + +// Create AsyncWebServer object on port 80 +AsyncWebServer wserver(80); +AsyncWebSocket ws("/ws"); + +AsyncWebSocketClient* globalClient = NULL; + +size_t content_len; + +static const char upload_html[] PROGMEM = "\ + \ + \ + \ +
\ +
\ + \ +
\ + "; + + +void onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) +{ + if (type == WS_EVT_CONNECT) + + globalClient = client; + + else if (type == WS_EVT_DISCONNECT) + + globalClient = NULL; +} + +// Replaces placeholder with LED state value +String processor(const String& var) +{ + Serial.println(var); + return "ON"; +} + +void Web_fini() +{} + +void handleUpdate(AsyncWebServerRequest* request) +{ + char* html = "
"; + request->send(200, "text/html", html); +} + +void handleUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final) +{ + if (!index) + request->_tempFile = SPIFFS.open("/" + filename, "w"); + if (len) + // stream the incoming chunk to the opened file + request->_tempFile.write(data, len); + if (final) + { + request->_tempFile.close(); + request->redirect("/"); + } +} + +void handleDoUpdate(AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, size_t len, bool final) +{ + String msg; + + if (!index) + { + Serial.println("Update"); + content_len = request->contentLength(); + // if filename includes spiffs, update the spiffs partition + int cmd = (filename.indexOf("spiffs") > -1) ? U_PART : U_FLASH; +#ifdef ESP8266 + Update.runAsync(true); + if (!Update.begin(content_len, cmd)) + { +#else + if (!Update.begin(UPDATE_SIZE_UNKNOWN, cmd)) + { +#endif + Update.printError(Serial); + } + } + + if (Update.write(data, len) != len) + { + Update.printError(Serial); +#ifdef ESP8266 + } + else + { + Serial.printf("Progress: %d%%\n", (Update.progress() * 100) / Update.size()); +#endif + } + + if (final) + { + AsyncWebServerResponse* response = request->beginResponse(302, "text/plain", "Please wait while the device reboots"); + response->addHeader("Refresh", "20"); + response->addHeader("Location", "/"); + request->send(response); + if (!Update.end(true)) + Update.printError(Serial); + else + { + Serial.println("Update complete"); + Serial.flush(); + msg = "updating firmware"; + Logger_send_udp(&msg); + ESP.restart(); + } + } +} + +void Web_start() +{ + wserver.begin(); +} + +void Web_stop() +{ + wserver.end(); +} + +void Web_setup(ufo_t* this_aircraft) +{ + if (!SPIFFS.begin(true)) + { + Serial.println("An Error has occurred while mounting SPIFFS"); + return; + } + + if (!SPIFFS.exists("/index.html")) + { + wserver.on("/", HTTP_GET, [upload_html](AsyncWebServerRequest* request){ + request->send(200, "text/html", upload_html); + }); + + wserver.on("/doUpload", HTTP_POST, [](AsyncWebServerRequest* request) {}, handleUpload); + + Web_start(); + return; + } + + File file = SPIFFS.open("/index.html", "r"); + if (!file) + { + Serial.println("An Error has occurred while opening index.html"); + return; + } + + ws.onEvent(onWsEvent); + wserver.addHandler(&ws); + + + size_t filesize = file.size(); + char* index_html = (char *) malloc(filesize + 1); + + file.read((uint8_t *)index_html, filesize); + index_html[filesize] = '\0'; + + size_t size = 8700; + char* offset; + char* Settings_temp = (char *) malloc(size); + + if (Settings_temp == NULL) + return; + + offset = Settings_temp; + + String station_addr = String(this_aircraft->addr, HEX); + station_addr.toUpperCase(); + + snprintf(offset, size, index_html, + station_addr, + SOFTRF_FIRMWARE_VERSION, + ogn_callsign, + String(ogn_lat, 5), + String(ogn_lon, 5), + String(ogn_alt), + String(ogn_geoid_separation), + String(ogn_range), + (ogn_band == RF_BAND_AUTO ? "selected" : ""), RF_BAND_AUTO, + (ogn_band == RF_BAND_EU ? "selected" : ""), RF_BAND_EU, + (ogn_band == RF_BAND_RU ? "selected" : ""), RF_BAND_RU, + (ogn_band == RF_BAND_CN ? "selected" : ""), RF_BAND_CN, + (ogn_band == RF_BAND_US ? "selected" : ""), RF_BAND_US, + (ogn_band == RF_BAND_NZ ? "selected" : ""), RF_BAND_NZ, + (ogn_band == RF_BAND_UK ? "selected" : ""), RF_BAND_UK, + (ogn_band == RF_BAND_AU ? "selected" : ""), RF_BAND_AU, + (ogn_band == RF_BAND_IN ? "selected" : ""), RF_BAND_IN, + (ogn_protocol_1 == RF_PROTOCOL_LEGACY ? "selected" : ""), + RF_PROTOCOL_LEGACY, legacy_proto_desc.name, + (ogn_protocol_1 == RF_PROTOCOL_OGNTP ? "selected" : ""), + RF_PROTOCOL_OGNTP, ogntp_proto_desc.name, + (ogn_protocol_1 == RF_PROTOCOL_P3I ? "selected" : ""), + RF_PROTOCOL_P3I, p3i_proto_desc.name, + (ogn_protocol_1 == RF_PROTOCOL_FANET ? "selected" : ""), + RF_PROTOCOL_FANET, fanet_proto_desc.name, + + (ogn_protocol_2 == RF_PROTOCOL_LEGACY ? "selected" : ""), + RF_PROTOCOL_LEGACY, legacy_proto_desc.name, + (ogn_protocol_2 == RF_PROTOCOL_OGNTP ? "selected" : ""), + RF_PROTOCOL_OGNTP, ogntp_proto_desc.name, + (ogn_protocol_2 == RF_PROTOCOL_P3I ? "selected" : ""), + RF_PROTOCOL_P3I, p3i_proto_desc.name, + (ogn_protocol_2 == RF_PROTOCOL_FANET ? "selected" : ""), + RF_PROTOCOL_FANET, fanet_proto_desc.name, + + (ogn_debug == true ? "selected" : ""), + (ogn_debug == false ? "selected" : ""), + String(ogn_debugport), + + (ogn_itrackbit == true ? "selected" : ""), "True", + (ogn_itrackbit == false ? "selected" : ""), "False", + + (ogn_istealthbit == true ? "selected" : ""), "True", + (ogn_istealthbit == false ? "selected" : ""), "False", + + ogn_ssid[0].c_str(), + ogn_wpass[0].c_str(), + + (ogn_sleepmode == 0 ? "selected" : ""), "Disabled", + (ogn_sleepmode == 1 ? "selected" : ""), "Full", + (ogn_sleepmode == 2 ? "selected" : ""), "without GPS", //zabbix_trap_en + + String(ogn_rxidle), + String(ogn_wakeuptimer), + + (zabbix_enable == 0 ? "selected" : ""), "Disabled", + (zabbix_enable == 1 ? "selected" : ""), "Enabled" + ); + + size_t len = strlen(offset); + String html = String(offset); + + wserver.on("/", HTTP_GET, [html](AsyncWebServerRequest* request){ + request->send(200, "text/html", html); + }); + + + // Route to load style.css file + wserver.on("/style.css", HTTP_GET, [](AsyncWebServerRequest* request){ + request->send(SPIFFS, "/style.css", "text/css"); + }); + + wserver.on("/update", HTTP_GET, [](AsyncWebServerRequest* request){ + handleUpdate(request); + request->redirect("/"); + }); + + wserver.on("/doUpdate", HTTP_POST, + [](AsyncWebServerRequest* request) {}, + [](AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, + size_t len, bool final) { + handleDoUpdate(request, filename, index, data, len, final); + }); + + wserver.on("/upload", HTTP_GET, [upload_html](AsyncWebServerRequest* request){ + request->send(200, "text/html", upload_html); + }); + + wserver.on("/doUpload", HTTP_POST, [](AsyncWebServerRequest* request) {}, handleUpload); + + + // Send a GET request to /get?inputString= + wserver.on("/get", HTTP_GET, [](AsyncWebServerRequest* request) { + if (request->hasParam("callsign")) + ogn_callsign = request->getParam("callsign")->value(); + if (request->hasParam("ogn_lat")) + ogn_lat = request->getParam("ogn_lat")->value().toFloat(); + + if (request->hasParam("ogn_lon")) + ogn_lon = request->getParam("ogn_lon")->value().toFloat(); + + if (request->hasParam("ogn_alt")) + ogn_alt = request->getParam("ogn_alt")->value().toInt(); + + if (request->hasParam("ogn_freq")) + ogn_band = request->getParam("ogn_freq")->value().toInt(); + + if (request->hasParam("ogn_proto")) + ogn_protocol_1 = request->getParam("ogn_proto")->value().toInt(); + + if (request->hasParam("ogn_proto2")) + ogn_protocol_2 = request->getParam("ogn_proto2")->value().toInt(); + + if (request->hasParam("ogn_d1090")) + settings->d1090 = request->getParam("ogn_d1090")->value().toInt(); + + if (request->hasParam("ogn_gdl90")) + settings->gdl90 = request->getParam("ogn_gdl90")->value().toInt(); + + if (request->hasParam("ogn_nmea")) + settings->nmea_out = request->getParam("ogn_nmea")->value().toInt(); + + if (request->hasParam("ogn_no_track_bit")) + settings->no_track = request->getParam("ogn_no_track_bit")->value().toInt(); + + if (request->hasParam("ogn_stealth_bit")) + settings->stealth = request->getParam("ogn_stealth_bit")->value().toInt(); + + if (request->hasParam("ogn_aprs_debug")) + ogn_debug= request->getParam("ogn_aprs_debug")->value().toInt(); + + if (request->hasParam("aprs_debug_port")) + ogn_debugport = request->getParam("aprs_debug_port")->value().toInt(); + + if (request->hasParam("ogn_range")) + ogn_range = request->getParam("ogn_range")->value().toInt(); + + //if (request->hasParam("ogn_agc")) + // settings->sxlna = request->getParam("ogn_agc")->value().toInt(); + + if (request->hasParam("ogn_ssid")) + ogn_ssid[0] = request->getParam("ogn_ssid")->value(); + + if (request->hasParam("ogn_wifi_password")) + ogn_wpass[0] = request->getParam("ogn_wifi_password")->value(); + //geoid_separation + if (request->hasParam("ogn_geoid")) + ogn_geoid_separation = request->getParam("ogn_geoid")->value().toInt(); + + if (request->hasParam("ogn_ignore_track")) + ogn_itrackbit= request->getParam("ogn_ignore_track")->value().toInt(); + + if (request->hasParam("ogn_ignore_stealth")) + ogn_istealthbit= request->getParam("ogn_ignore_stealth")->value().toInt(); + + if (request->hasParam("ogn_deep_sleep")) + ogn_sleepmode = request->getParam("ogn_deep_sleep")->value().toInt(); + + if (request->hasParam("ogn_sleep_time")) + { + if (request->getParam("ogn_sleep_time")->value().toInt() <= 60) + ogn_rxidle = 60; + else + ogn_rxidle = request->getParam("ogn_sleep_time")->value().toInt(); + } + if (request->hasParam("ogn_wakeup_time")) + ogn_wakeuptimer= request->getParam("ogn_wakeup_time")->value().toInt(); + + if (request->hasParam("zabbix_trap_en")) + zabbix_enable = request->getParam("zabbix_trap_en")->value().toInt(); + + + request->redirect("/"); + + // ogn_reset_all + if (request->hasParam("ogn_reset_all")) + if (request->getParam("ogn_reset_all")->value() == "on") + { + SPIFFS.format(); + RF_Shutdown(); + delay(1000); + SoC->reset(); + } + + EEPROM_store(); + OGN_save_config(); + RF_Shutdown(); + delay(1000); + SoC->reset(); + }); + + SoC->swSer_enableRx(true); + free(Settings_temp); + free(index_html); + + // Start server + Web_start(); +} + +void Web_loop(void) +{ + if (globalClient != NULL && globalClient->status() == WS_CONNECTED) + { + String values; + values =+SoC->Battery_voltage(); + values += "_"; + values += RF_last_rssi; + values += "_"; + values += hours(); + values += "_"; + values += gnss.satellites.value(); + values += "_"; + values += now(); + values += "_"; + values += largest_range; + globalClient->text(values); + } +} diff --git a/ognbase/WiFi.cpp b/ognbase/WiFi.cpp index cd44a77..b42e7d6 100644 --- a/ognbase/WiFi.cpp +++ b/ognbase/WiFi.cpp @@ -1,309 +1,272 @@ -/* - * WiFi.cpp - * Copyright (C) 2019-2020 Linar Yusupov - * - * Bug fixes and improvements - * Copyright (C) 2020 Manuel Roesel - * - * 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 . - */ - -#include "SoC.h" - -#if defined(EXCLUDE_WIFI) -void WiFi_setup() -{} -void WiFi_loop() -{} -void WiFi_fini() -{} -#else - -#include -#include - -#include "OTA.h" -#include "GNSS.h" -#include "EEPROM.h" -#include "WiFi.h" -#include "Traffic.h" -#include "RF.h" -#include "Web.h" -#include "NMEA.h" -#include "Battery.h" - -String station_ssid = "ognbase"; -String station_psk = "123456789"; - -String host_name = HOSTNAME; - -IPAddress local_IP(192, 168, 1, 1); -IPAddress gateway(192, 168, 1, 1); -IPAddress subnet(255, 255, 255, 0); - -/** - * Default WiFi connection information. - * - */ -const char* ap_default_psk = "987654321"; ///< Default PSK. - -#if defined(USE_DNS_SERVER) -#include - -const byte DNS_PORT = 53; -DNSServer dnsServer; -bool dns_active = false; -#endif - -// A UDP instance to let us send and receive packets over UDP -WiFiUDP Uni_Udp; - -unsigned int RFlocalPort = RELAY_SRC_PORT; // local port to listen for UDP packets - -char UDPpacketBuffer[256]; // buffer to hold incoming and outgoing packets - -#if defined(POWER_SAVING_WIFI_TIMEOUT) -static unsigned long WiFi_No_Clients_Time_ms = 0; -#endif - -/** - * @brief Read WiFi connection information from file system. - * @param ssid String pointer for storing SSID. - * @param pass String pointer for storing PSK. - * @return True or False. - * - * The config file have to containt the WiFi SSID in the first line - * and the WiFi PSK in the second line. - * Line seperator can be \r\n (CR LF) \r or \n. - */ -bool loadConfig(String* ssid, String* pass) -{ - int line = 0; - - // open file for reading. - File configFile = SPIFFS.open("/ogn_conf.txt", "r"); - if (!configFile) - { - Serial.println(F("Failed to open ogn_conf.txt.")); - return false; - } - - while (configFile.available() && line < 5) - { - if (line == 0) - *ssid = configFile.readStringUntil('\n').c_str(); - if (line == 1) - *pass = configFile.readStringUntil('\n').c_str(); - line++; - } - - configFile.close(); - - if (line < 2) - return false; - - ssid->trim(); - pass->trim(); - - - return true; -} // loadConfig - -size_t Raw_Receive_UDP(uint8_t* buf) -{ - int noBytes = Uni_Udp.parsePacket(); - if (noBytes) - { - if (noBytes > MAX_PKT_SIZE) - noBytes = MAX_PKT_SIZE; - - // We've received a packet, read the data from it - Uni_Udp.read(buf, noBytes); // read the packet into the buffer - - return (size_t) noBytes; - } - else - return 0; -} - -void Raw_Transmit_UDP() -{ - size_t rx_size = RF_Payload_Size(settings->rf_protocol); - rx_size = rx_size > sizeof(fo.raw) ? sizeof(fo.raw) : rx_size; - String str = Bin2Hex(fo.raw, rx_size); - size_t len = str.length(); - // ASSERT(sizeof(UDPpacketBuffer) > 2 * PKT_SIZE + 1) - str.toCharArray(UDPpacketBuffer, sizeof(UDPpacketBuffer)); - UDPpacketBuffer[len] = '\n'; - SoC->WiFi_transmit_UDP(RELAY_DST_PORT, (byte *)UDPpacketBuffer, len + 1); -} - -/** - * @brief Arduino setup function. - */ -void WiFi_setup() -{ -#if 1 - // Initialize file system. - if (!SPIFFS.begin(true)) - { - Serial.println(F("Failed to mount file system")); - return; - } - - // Load wifi connection information. - if (!loadConfig(&station_ssid, &station_psk)) - { - station_ssid = MY_ACCESSPOINT_SSID; - station_psk = MY_ACCESSPOINT_PSK; - - Serial.println(F("No WiFi connection information available.")); - } -#endif - - // Check WiFi connection - // ... check mode - if (WiFi.getMode() != WIFI_STA) - { - WiFi.mode(WIFI_STA); - delay(10); - } - - // ... Compare file config with sdk config. - if (WiFi.SSID() != station_ssid || WiFi.psk() != station_psk) - { - Serial.println(F("WiFi config changed.")); - - // ... Try to connect to WiFi station. - WiFi.begin(station_ssid.c_str(), station_psk.c_str()); - - // ... Pritn new SSID - Serial.print(F("new SSID: ")); - Serial.println(WiFi.SSID()); - - // ... Uncomment this for debugging output. - //WiFi.printDiag(Serial); - } - else - // ... Begin with sdk config. - WiFi.begin(); - - // Set Hostname. - host_name += String((SoC->getChipId() & 0xFFFFFF), HEX); - SoC->WiFi_hostname(host_name); - - // Print hostname. - Serial.println("Hostname: " + host_name); - - Serial.println(F("Wait for WiFi connection.")); - - // ... Give ESP 10 seconds to connect to station. - unsigned long startTime = millis(); - while (WiFi.status() != WL_CONNECTED && millis() - startTime < 20000) - { - Serial.write('.'); - //Serial.print(WiFi.status()); - delay(500); - } - Serial.println(); - - // Check connection - if (WiFi.status() == WL_CONNECTED) - { - // ... print IP Address - Serial.print(F("IP address: ")); - Serial.println(WiFi.localIP()); - } - else - { - Serial.println(F("Can not connect to WiFi station. Go into AP mode.")); // if (WiFi.status() != WL_CONNECTED) Connect(); - - // Go into software AP mode. - WiFi.mode(WIFI_AP); - SoC->WiFi_setOutputPower(WIFI_TX_POWER_MED); // 10 dB - // WiFi.setOutputPower(0); // 0 dB - //system_phy_set_max_tpw(4 * 0); // 0 dB - delay(10); - - Serial.print(F("Setting soft-AP configuration ... ")); - Serial.println(WiFi.softAPConfig(local_IP, gateway, subnet) ? - F("Ready") : F("Failed!")); - - Serial.print(F("Setting soft-AP ... ")); - Serial.println(WiFi.softAP(host_name.c_str(), ap_default_psk) ? - F("Ready") : F("Failed!")); -#if defined(USE_DNS_SERVER) - // if DNSServer is started with "*" for domain name, it will reply with - // provided IP to all DNS request - dnsServer.start(DNS_PORT, "*", WiFi.softAPIP()); - dns_active = true; -#endif - Serial.print(F("IP address: ")); - Serial.println(WiFi.softAPIP()); - } - - Uni_Udp.begin(RFlocalPort); - Serial.print(F("UDP server has started at port: ")); - Serial.println(RFlocalPort); - -#if defined(POWER_SAVING_WIFI_TIMEOUT) - WiFi_No_Clients_Time_ms = millis(); -#endif -} - -bool Wifi_connected() -{ - if (WiFi.status() != WL_CONNECTED) - return false; - else - return true; -} - -void WiFi_loop() -{ -#if defined(USE_DNS_SERVER) - if (dns_active) - dnsServer.processNextRequest(); - -#endif - -#if defined(POWER_SAVING_WIFI_TIMEOUT) - if ((settings->power_save & POWER_SAVE_WIFI) && WiFi.getMode() == WIFI_AP) - { - if (SoC->WiFi_clients_count() == 0) - { - if ((millis() - WiFi_No_Clients_Time_ms) > POWER_SAVING_WIFI_TIMEOUT) - { - NMEA_fini(); - Web_fini(); - WiFi_fini(); - - if (settings->nmea_p) - StdOut.println(F("$PSRFS,WIFI_OFF")); - } - } - else - WiFi_No_Clients_Time_ms = millis(); - } -#endif -} - -void WiFi_fini() -{ - Uni_Udp.stop(); - - WiFi.mode(WIFI_OFF); -} - -#endif /* EXCLUDE_WIFI */ +/* + * WiFi.cpp + * Copyright (C) 2019-2020 Linar Yusupov + * + * Bug fixes and improvements + * Copyright (C) 2020 Manuel Roesel + * + * 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 . + */ + +#include "SoC.h" + +#if defined(EXCLUDE_WIFI) +void WiFi_setup() +{} +void WiFi_loop() +{} +void WiFi_fini() +{} +#else + +#include +#include + +#include "OTA.h" +#include "GNSS.h" +#include "EEPROM.h" +#include "OLED.h" +#include "WiFi.h" +#include "Traffic.h" +#include "RF.h" +#include "Web.h" +#include "NMEA.h" +#include "Battery.h" + +#include "config.h" +#include "global.h" +#include "logos.h" + +String host_name = HOSTNAME; + +IPAddress local_IP(192, 168, 1, 1); +IPAddress gateway(192, 168, 1, 1); +IPAddress subnet(255, 255, 255, 0); + +/** + * Default WiFi connection information. + * + */ + +String station_ssid = "ognbase"; +String station_psk = "123456789"; + +const char* ap_default_psk = "987654321"; ///< Default PSK. + +#if defined(USE_DNS_SERVER) +#include + +const byte DNS_PORT = 53; +DNSServer dnsServer; +bool dns_active = false; +#endif + +// A UDP instance to let us send and receive packets over UDP +WiFiUDP Uni_Udp; + +unsigned int RFlocalPort = RELAY_SRC_PORT; // local port to listen for UDP packets + +char UDPpacketBuffer[256]; // buffer to hold incoming and outgoing packets + +#if defined(POWER_SAVING_WIFI_TIMEOUT) +static unsigned long WiFi_No_Clients_Time_ms = 0; +#endif + +size_t Raw_Receive_UDP(uint8_t* buf) +{ + int noBytes = Uni_Udp.parsePacket(); + if (noBytes) + { + if (noBytes > MAX_PKT_SIZE) + noBytes = MAX_PKT_SIZE; + + // We've received a packet, read the data from it + Uni_Udp.read(buf, noBytes); // read the packet into the buffer + + return (size_t) noBytes; + } + else + return 0; +} + +void Raw_Transmit_UDP() +{ + size_t rx_size = RF_Payload_Size(ogn_protocol_1); + rx_size = rx_size > sizeof(fo.raw) ? sizeof(fo.raw) : rx_size; + String str = Bin2Hex(fo.raw, rx_size); + size_t len = str.length(); + // ASSERT(sizeof(UDPpacketBuffer) > 2 * PKT_SIZE + 1) + str.toCharArray(UDPpacketBuffer, sizeof(UDPpacketBuffer)); + UDPpacketBuffer[len] = '\n'; + SoC->WiFi_transmit_UDP(RELAY_DST_PORT, (byte *)UDPpacketBuffer, len + 1); +} + +/** + * @brief Arduino setup function. + */ +void WiFi_setup() +{ + char buf[32]; + + if (WiFi.getMode() != WIFI_STA) + { + WiFi.mode(WIFI_STA); + delay(10); + } + + if (OGN_read_config()) + { + Serial.println(F("WiFi config changed.")); + + delay(1500); + + for (int i=0; i < 5; i++) { + if (ogn_ssid[i] != "") + { + OLED_draw_Bitmap(85, 20, 1, true); + snprintf(buf, sizeof(buf), "try connecting"); + OLED_write(buf, 0, 15, false); + snprintf(buf, sizeof(buf), "%s", ogn_ssid[i].c_str()); + OLED_write(buf, 0, 26, false); + + WiFi.begin(ogn_ssid[i].c_str(), ogn_wpass[i].c_str()); + ssid_index = i; + + // + unsigned long startTime = millis(); + + while (WiFi.status() != WL_CONNECTED && millis() - startTime < 15000) + { + Serial.write('.'); + Serial.print(WiFi.status()); + delay(500); + } + } + + // Check connection + if (WiFi.status() == WL_CONNECTED) + { + // ... print IP Address + Serial.print(F("IP address: ")); + Serial.println(WiFi.localIP()); + snprintf(buf, sizeof(buf), "success.."); + OLED_write(buf, 0, 44, false); + host_name += String((SoC->getChipId() & 0xFFFFFF), HEX); + SoC->WiFi_hostname(host_name); + + // Print hostname. + Serial.println("Hostname: " + host_name); + break; + } + if (WiFi.status() != WL_CONNECTED) + { + Serial.println(); + Serial.println(F("Can not connect to WiFi station")); + snprintf(buf, sizeof(buf), "failed.."); + OLED_write(buf, 0, 44, false); + } + } + } + else + { + station_ssid = MY_ACCESSPOINT_SSID; + station_psk = MY_ACCESSPOINT_PSK; + Serial.println(F("No WiFi connection information available.")); + snprintf(buf, sizeof(buf), "no config file found.."); + OLED_write(buf, 0, 25, false); + WiFi.begin(); + delay(1000); + } + + if (WiFi.status() != WL_CONNECTED) + { + host_name += String((SoC->getChipId() & 0xFFFFFF), HEX); + SoC->WiFi_hostname(host_name); + + // Print hostname. + Serial.println("Hostname: " + host_name); + Serial.println(F("Wait for WiFi connection.")); + + WiFi.mode(WIFI_AP); + SoC->WiFi_setOutputPower(WIFI_TX_POWER_MED); // 10 dB + // WiFi.setOutputPower(0); // 0 dB + //system_phy_set_max_tpw(4 * 0); // 0 dB + delay(10); + + Serial.print(F("Setting soft-AP configuration ... ")); + Serial.println(WiFi.softAPConfig(local_IP, gateway, subnet) ? + F("Ready") : F("Failed!")); + + Serial.print(F("Setting soft-AP ... ")); + Serial.println(WiFi.softAP(host_name.c_str(), ap_default_psk) ? + F("Ready") : F("Failed!")); + Serial.print(F("IP address: ")); + Serial.println(WiFi.softAPIP()); + } + + + Uni_Udp.begin(RFlocalPort); + Serial.print(F("UDP server has started at port: ")); + Serial.println(RFlocalPort); + +#if defined(POWER_SAVING_WIFI_TIMEOUT) + WiFi_No_Clients_Time_ms = millis(); +#endif +} + +bool Wifi_connected() +{ + if (WiFi.status() != WL_CONNECTED) + return false; + else + return true; +} + +void WiFi_loop() +{ +#if defined(USE_DNS_SERVER) + if (dns_active) + dnsServer.processNextRequest(); + +#endif + +#if defined(POWER_SAVING_WIFI_TIMEOUT) + if ((settings->power_save & POWER_SAVE_WIFI) && WiFi.getMode() == WIFI_AP) + { + if (SoC->WiFi_clients_count() == 0) + { + if ((millis() - WiFi_No_Clients_Time_ms) > POWER_SAVING_WIFI_TIMEOUT) + { + NMEA_fini(); + Web_fini(); + WiFi_fini(); + + if (settings->nmea_p) + StdOut.println(F("$PSRFS,WIFI_OFF")); + } + } + else + WiFi_No_Clients_Time_ms = millis(); + } +#endif +} + +void WiFi_fini() +{ + Uni_Udp.stop(); + + WiFi.mode(WIFI_OFF); +} + +#endif /* EXCLUDE_WIFI */ diff --git a/ognbase/config.cpp b/ognbase/config.cpp index f892b5a..378c2f1 100644 --- a/ognbase/config.cpp +++ b/ognbase/config.cpp @@ -1,87 +1,270 @@ -/* - CONFIG.cpp - Copyright (C) 2020 Manuel Rösel - - 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 . -*/ - - -#include "SoftRF.h" -#include "EEPROM.h" -#include "global.h" -#include - -using namespace tinyxml2; - - -static bool OGN_save_config() { - - SPIFFS.remove("/config.xml"); - - File configFile = SPIFFS.open("/config.xml", "w"); - if (!configFile) - { - Serial.println(F("Failed to open config.txt for writing")); - return false; - } - -} - -bool OGN_read_config() { - - if (!SPIFFS.begin(true)) - { - Serial.println("An Error has occurred while mounting SPIFFS"); - return false; - } - - File file = SPIFFS.open("/config.xml", "r"); - if (!file) - { - Serial.println("An Error has occurred while opening index.html"); - return false; - } - - size_t filesize = file.size(); - char * config_file = (char *) malloc(filesize + 1); - - file.read((uint8_t *)config_file, filesize); - config_file[filesize+1] = '\0'; - - XMLDocument xmlDocument; - - /* - if(xmlDocument.Parse(values)!= XML_SUCCESS){ - Serial.println("Error parsing"); - return false; - }; - - XMLElement * pRootElement = xmlDocument.RootElement(); - - if (NULL != pRootElement) { - XMLElement * pWifi = pRootElement->FirstChildElement("wifi"); - - while (pWifi) { - const char* value = pWifi->Attribute( "ssid" ); - Serial.println(value); - - value = pWifi->Attribute( "pass" ); - Serial.println(value); - } - - }*/ - - free(config_file); - return true; -} +/* + CONFIG.cpp + Copyright (C) 2020 Manuel Rösel + + 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 . + */ + + +#include "SoftRF.h" +#include "EEPROM.h" +#include "global.h" +#include "config.h" +#include + +//wifi +String ogn_ssid[5]; +String ogn_wpass[5]; +int ssid_index = 0; + +//aprs default values +String ogn_callsign = "callsign"; +String ogn_server = "aprs.glidernet.org"; +uint16_t ogn_port = 14580; +uint8_t ogn_band = 1; +uint8_t ogn_protocol_1 = 0; +uint8_t ogn_protocol_2 = 1; +bool ogn_debug = false; +uint16_t ogn_debugport = 12000; +bool ogn_itrackbit = false; +bool ogn_istealthbit = false; +bool ogn_sleepmode = false; +uint16_t ogn_rxidle = 3600; +uint16_t ogn_wakeuptimer = 3600; +uint8_t ogn_range = 100; + +//position +float ogn_lat = 0; +float ogn_lon = 0; +int ogn_alt = 0; +uint8_t ogn_geoid_separation = 0; +uint8_t largest_range = 0; + +//fanet service +bool fanet_enable = false; + +//zabbix +bool zabbix_enable = false; +String zabbix_server = "127.0.0.1"; +int zabbix_port = 10051; +String zabbix_key = "ogn_base"; + +//supporters +bool beers_show = false; + + +bool OGN_read_config(void) +{ + const size_t capacity = 1024; + DynamicJsonDocument baseConfig(capacity); + JsonObject obj; + + const char* kerror; + + if (!SPIFFS.begin(true)) + { + Serial.println("An Error has occurred while mounting SPIFFS"); + return false; + } + + + File configFile = SPIFFS.open("/config.json", "r"); + if (!configFile) + { + Serial.println(F("Failed to open config.json.")); + return false; + } + + DeserializationError error = deserializeJson(baseConfig, configFile); + + if (error) + { + Serial.println(F("Failed to read file, using default configuration")); + configFile.close(); + return false; + } + else + { + obj = baseConfig.as(); + configFile.close(); + } + + if (!obj.containsKey(F("wifi"))) + return false; + else + { + Serial.println(F("found wifi config!")); + if (1) + for (int i=0; i < 5; i++) { + ogn_ssid[i] = obj["wifi"]["ssid"][i].as(); + ogn_wpass[i] = obj["wifi"]["pass"][i].as(); + } + } + + if (!obj.containsKey(F("coordinates"))) + return false; + else + { + Serial.println(F("found coordinates config!")); + if (1) + { + ogn_lat = obj["coordinates"]["lat"]; + ogn_lon = obj["coordinates"]["lon"]; + ogn_alt = obj["coordinates"]["alt"]; + ogn_geoid_separation = obj["coordinates"]["geoidsep"]; + } + } + + if (!obj.containsKey(F("aprs"))) + return false; + else + { + Serial.println(F("found aprs config!")); + if (1) + { + ogn_callsign = obj["aprs"]["callsign"].as(); + ogn_server = obj["aprs"]["server"].as(); + ogn_port = obj["aprs"]["port"]; + + ogn_band = obj["aprs"]["band"]; + ogn_protocol_1 = obj["aprs"]["protocol_1"]; + ogn_protocol_2 = obj["aprs"]["protocol_2"]; + ogn_debug = obj["aprs"]["debug"]; + ogn_debugport = obj["aprs"]["debugport"]; + ogn_itrackbit = obj["aprs"]["itrackbit"]; + ogn_istealthbit = obj["aprs"]["istealthbit"]; + ogn_sleepmode = obj["aprs"]["sleepmode"]; + ogn_rxidle = obj["aprs"]["rxidle"]; + ogn_wakeuptimer = obj["aprs"]["wakeuptimer"]; + } + } + + + if (!obj.containsKey(F("zabbix"))) + return false; + else + { + Serial.println(F("found zabbix config!")); + if (1) + { + zabbix_enable = obj["zabbix"]["enable"]; + zabbix_server = obj["zabbix"]["server"].as(); + ; + zabbix_port = obj["zabbix"]["port"]; + zabbix_key = obj["zabbix"]["key"].as(); + ; + } + } + + if (!obj.containsKey(F("fanetservice"))) + return false; + else + { + Serial.println(F("found fanetservice config!")); + if (1) + fanet_enable = obj["fanetservice"]["enable"]; + } + + if (!obj.containsKey(F("beers"))) + {} + else if (1) + beers_show = obj["beers"]["show"]; + + + + return true; +} + +bool OGN_save_config(void) +{ + const size_t capacity = 1024; + DynamicJsonDocument baseConfig(capacity); + JsonObject obj; + + const char* kerror; + + if (!SPIFFS.begin(true)) + { + Serial.println("An Error has occurred while mounting SPIFFS"); + return false; + } + + + File configFile = SPIFFS.open("/config.json", "r"); + if (!configFile) + { + Serial.println(F("Failed to open config.json readonly")); + return false; + } + + DeserializationError error = deserializeJson(baseConfig, configFile); + + if (error) + { + Serial.println(F("Failed to read file, using default configuration")); + configFile.close(); + return false; + } + else + { + obj = baseConfig.as(); + configFile.close(); + } + + configFile = SPIFFS.open("/config.json", "w"); + if (!configFile) + { + Serial.println(F("Failed to open config.json write operation")); + return false; + } + + //position config + obj["coordinates"]["lat"] = ogn_lat; + obj["coordinates"]["lon"] = ogn_lon; + obj["coordinates"]["alt"] = ogn_alt; + obj["coordinates"]["geoidsep"] = ogn_geoid_separation; + //aps config + obj["aprs"]["callsign"] = ogn_callsign; + + obj["aprs"]["server"] = ogn_server; + obj["aprs"]["port"] = ogn_port; + + obj["aprs"]["band"] = ogn_band; + obj["aprs"]["protocol_1"] = ogn_protocol_1; + obj["aprs"]["protocol_2"] = ogn_protocol_2; + obj["aprs"]["debug"] = ogn_debug; + obj["aprs"]["debugport"] = ogn_debugport; + obj["aprs"]["itrackbit"] = ogn_itrackbit; + obj["aprs"]["istealthbit"] = ogn_istealthbit; + obj["aprs"]["sleepmode"] = ogn_sleepmode; + obj["aprs"]["rxidle"] = ogn_rxidle; + obj["aprs"]["wakeuptimer"] = ogn_wakeuptimer; + + //wifi config + obj["wifi"]["ssid"][0] = ogn_ssid[0]; + obj["wifi"]["pass"][0] = ogn_wpass[0]; + //fanet config + obj["fanetservice"]["enable"] = fanet_enable; + //zabbix config + obj["zabbix"]["enable"] = zabbix_enable; + obj["zabbix"]["server"] = zabbix_server; + obj["zabbix"]["port"] = zabbix_port; + obj["zabbix"]["key"] = zabbix_key; + + if (serializeJson(obj, configFile) == 0) + Serial.println(F("Failed to write to file")); + + configFile.close(); + return true; +} diff --git a/ognbase/config.h b/ognbase/config.h index 83ad753..ea24647 100644 --- a/ognbase/config.h +++ b/ognbase/config.h @@ -1,30 +1,30 @@ -/* - * CONFIG.h - * Copyright (C) 2020 Manuel Rösel - * - * 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 . - */ - -#include -#include "SoC.h" - - -#ifndef CONFIGHELPER_H -#define CONFIGHELPER_H - -static bool OGN_save_config(); - -bool OGN_read_config(); - -#endif /* CONFIGHELPER_H */ +/* + * CONFIG.h + * Copyright (C) 2020 Manuel Rösel + * + * 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 . + */ + +#include +#include "SoC.h" + + +#ifndef CONFIGHELPER_H +#define CONFIGHELPER_H + +bool OGN_save_config(void); + +bool OGN_read_config(void); + +#endif /* CONFIGHELPER_H */ diff --git a/ognbase/data/config.json b/ognbase/data/config.json new file mode 100644 index 0000000..b4d59f8 --- /dev/null +++ b/ognbase/data/config.json @@ -0,0 +1,54 @@ +{ + "wifi":{ + "ssid":[ + "ssid1", + "", + "", + "", + "" + ], + "pass":[ + "pass1", + "", + "", + "", + "" + ], + "timeout":12000 + }, + "coordinates":{ + "lat":46.90929623063438, + "lon":6.8723000923436715, + "alt":550, + "geoidsep":55 + }, + "zabbix":{ + "enable":false, + "server":"127.0.0.1", + "port":10051, + "key":"ogn_base" + }, + "aprs":{ + "callsign":"Neuenburg", + "server":"aprs.glidernet.org", + "port":14580, + "band":1, + "protocol_1":0, + "protocol_2":1, + "debug":false, + "debugport":12000, + "itrackbit":false, + "istealthbit":false, + "sleepmode":false, + "rxidle":3600, + "wakeuptimer":3600, + "range":100 + }, + "fanetservice":{ + "enable":1 + }, + "beers":{ + "show":0 + } +} + diff --git a/ognbase/data/config.xml b/ognbase/data/config.xml deleted file mode 100644 index 8622ec7..0000000 --- a/ognbase/data/config.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - mobile - Test1234 - - - callsign - 46.12345 - 7.12345 - 550 - 50 - 100 - 1 - 1 - 1 - 0 - 12000 - 1 - 1 - 1 - 3600 - 3600 - 1 - 10.0.0.200 - - diff --git a/ognbase/data/zabbix.txt b/ognbase/data/zabbix.txt deleted file mode 100644 index 92261d4..0000000 --- a/ognbase/data/zabbix.txt +++ /dev/null @@ -1,3 +0,0 @@ -xxx.xxx.xxx.xxx -10051 -ogn_base diff --git a/ognbase/global.h b/ognbase/global.h index 4634cac..5ad845b 100644 --- a/ognbase/global.h +++ b/ognbase/global.h @@ -1,8 +1,35 @@ -extern String ogn_ssid; -extern String ogn_wpass; -extern String ogn_callsign; +extern String ogn_ssid[]; +extern String ogn_wpass[]; + +extern int ssid_index; + + extern float ogn_lat; extern float ogn_lon; extern int ogn_alt; -extern int ogn_geoid_separation; +extern uint8_t ogn_geoid_separation; extern uint8_t largest_range; + +extern String ogn_callsign; +extern String ogn_server; +extern uint16_t ogn_port; + +extern uint8_t ogn_band; +extern uint8_t ogn_protocol_1; +extern uint8_t ogn_protocol_2; +extern bool ogn_debug; +extern uint16_t ogn_debugport; +extern bool ogn_itrackbit; +extern bool ogn_istealthbit; +extern bool ogn_sleepmode; +extern uint16_t ogn_rxidle; +extern uint16_t ogn_wakeuptimer; +extern uint8_t ogn_range; + +extern bool fanet_enable; +extern bool zabbix_enable; +extern String zabbix_server; +extern int zabbix_port; +extern String zabbix_key; + +extern bool beers_show; diff --git a/ognbase/logos.h b/ognbase/logos.h new file mode 100644 index 0000000..4b6482e --- /dev/null +++ b/ognbase/logos.h @@ -0,0 +1,167 @@ +const unsigned char wifi_50_28 [] PROGMEM = { + 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0xC0, 0x02, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x40, 0x07, + 0x00, 0x1B, 0x00, 0x00, 0x00, 0x60, 0x09, 0x60, 0x1B, 0x00, 0x00, 0x00, + 0xA0, 0x0D, 0xC0, 0x16, 0x00, 0x00, 0x00, 0xA0, 0x8D, 0xC7, 0x16, 0x00, + 0x00, 0x00, 0xA0, 0x8D, 0x87, 0x1A, 0x00, 0x00, 0x00, 0x60, 0x8D, 0xC7, + 0x1A, 0x00, 0x00, 0x00, 0x60, 0x09, 0x43, 0x1B, 0x00, 0x00, 0x00, 0x60, + 0x0B, 0x00, 0x1B, 0x00, 0x00, 0x00, 0xC0, 0x02, 0x83, 0x0D, 0x00, 0x00, + 0x00, 0x80, 0x01, 0x02, 0x06, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, + 0xFF, 0x00, 0x00, 0x00, }; + +const unsigned char supporter_50_64 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0xFF, + 0x07, 0x00, 0x00, 0x80, 0x01, 0x00, 0x07, 0x06, 0x00, 0x00, 0xC0, 0x01, + 0x00, 0x03, 0x0C, 0x00, 0x00, 0xF0, 0x01, 0x80, 0x01, 0x0C, 0x00, 0x00, + 0x38, 0x00, 0x80, 0x01, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x01, 0x38, + 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x0C, 0x10, 0x00, + 0x00, 0xE0, 0x00, 0x00, 0x0E, 0x7C, 0x00, 0x07, 0xC2, 0x00, 0x00, 0x06, + 0x7E, 0x80, 0x9F, 0x8F, 0x01, 0x00, 0x06, 0x66, 0x80, 0x99, 0xDF, 0x00, + 0x00, 0x46, 0x66, 0x80, 0x99, 0xFD, 0x00, 0x00, 0xC6, 0xC6, 0xC0, 0xD8, + 0x79, 0x00, 0x00, 0xEE, 0xC7, 0xE1, 0xF8, 0x18, 0x00, 0x00, 0xE6, 0x83, + 0x7F, 0x70, 0x1C, 0x00, 0x00, 0x66, 0x00, 0x1F, 0x00, 0xF8, 0x07, 0x00, + 0x64, 0x00, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0xEE, 0xE7, 0x79, 0x9E, 0x1F, + 0x38, 0x00, 0xE6, 0xFF, 0xFF, 0xFF, 0x1F, 0x70, 0x00, 0xEE, 0x3C, 0xCF, + 0x73, 0xFC, 0xE7, 0x00, 0x66, 0x18, 0x86, 0x61, 0xFC, 0xCF, 0x00, 0xE6, + 0x18, 0x86, 0x61, 0x18, 0xCC, 0x00, 0x6E, 0x18, 0x86, 0x71, 0x18, 0x8C, + 0x00, 0x7C, 0x18, 0x86, 0x61, 0x18, 0xD8, 0x01, 0xF0, 0x18, 0x86, 0x61, + 0x1C, 0xD8, 0x00, 0x60, 0x18, 0x86, 0x61, 0x18, 0xCC, 0x00, 0x60, 0x18, + 0x86, 0x61, 0x18, 0xDC, 0x01, 0x60, 0x18, 0x86, 0x61, 0x18, 0x88, 0x00, + 0x60, 0x18, 0x86, 0x61, 0x08, 0xC8, 0x00, 0x60, 0x18, 0x86, 0x61, 0x1C, + 0xDC, 0x01, 0x60, 0x18, 0x86, 0x61, 0x18, 0x8C, 0x00, 0x60, 0x18, 0x86, + 0x61, 0x18, 0xC8, 0x01, 0x60, 0x18, 0x86, 0x61, 0x08, 0x98, 0x00, 0x60, + 0x18, 0x86, 0x61, 0x18, 0xCC, 0x01, 0x60, 0x18, 0x86, 0x61, 0x1C, 0xD8, + 0x00, 0x60, 0x18, 0x86, 0x71, 0x18, 0x8C, 0x00, 0x60, 0x18, 0x86, 0x61, + 0x1C, 0xD8, 0x01, 0x60, 0x18, 0x86, 0x61, 0x18, 0xCC, 0x00, 0x60, 0x18, + 0x86, 0x61, 0x18, 0xD8, 0x00, 0x60, 0x18, 0x86, 0x61, 0x08, 0x8C, 0x01, + 0x60, 0x18, 0x86, 0x61, 0x18, 0xCC, 0x00, 0x60, 0x18, 0x86, 0x61, 0x1C, + 0xCC, 0x00, 0xE0, 0x18, 0x86, 0x61, 0x0C, 0xCC, 0x00, 0x60, 0x18, 0x86, + 0x61, 0xF8, 0xCF, 0x00, 0x60, 0x18, 0x86, 0x61, 0xF8, 0x63, 0x00, 0xE0, + 0x18, 0x86, 0x61, 0x18, 0x70, 0x00, 0x40, 0x18, 0x86, 0x71, 0x1C, 0x3C, + 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, + 0xFF, 0x03, 0x00, 0x60, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0xE0, 0x26, 0x69, 0x92, 0x0E, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x0F, + 0x00, 0x00, 0x80, 0xD5, 0x59, 0x9D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, }; + +const unsigned char signal_25_18_100 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const unsigned char network_50_44 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, + 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x00, 0x00, 0xaa, 0xaa, 0x57, 0x55, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x80, 0x57, + 0xd5, 0x57, 0xd5, 0x03, 0x00, 0x00, 0x07, 0x80, 0x07, 0x80, 0x03, 0x00, + 0x00, 0x07, 0x00, 0x03, 0x80, 0x03, 0x00, 0x00, 0x07, 0x80, 0x07, 0x80, + 0x03, 0x00, 0x80, 0x07, 0x80, 0x03, 0x80, 0x07, 0x00, 0xf8, 0xff, 0xfc, + 0xff, 0xfc, 0x7f, 0x00, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x00, 0xfc, + 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x00, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, + 0x00, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x00, 0x3c, 0xe0, 0x1c, 0xe0, + 0x1c, 0x70, 0x00, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x00, 0x3c, 0xe0, + 0x1c, 0xe0, 0x1c, 0xf0, 0x00, 0x1c, 0xe0, 0x1c, 0xe0, 0x1c, 0xe0, 0x00, + 0x3c, 0xe0, 0x1c, 0xe0, 0x1c, 0x60, 0x00, 0xfc, 0xff, 0xfc, 0xff, 0xfc, + 0xff, 0x00, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x00, 0xf8, 0xff, 0xf8, + 0x7f, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +const unsigned char fanet_export_100_63 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x0F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x3F, 0xC0, 0x7F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x00, + 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, + 0x00, 0xC0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0x03, 0xE8, 0xFF, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE0, 0x00, 0xFE, 0xFF, 0x07, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0xC0, 0x3F, 0x40, 0x3F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0xF0, 0x01, 0x00, 0xFC, 0xC0, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x78, 0x00, 0x00, 0xE0, 0x81, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x09, 0x00, 0x0F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0xF8, 0xFF, 0x01, 0x1C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0xFE, 0xFB, 0x07, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, + 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, + 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, + 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x40, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7C, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x3F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, + 0x0F, 0x3E, 0x00, 0x3C, 0x80, 0xE7, 0xFF, 0x1F, 0xFF, 0xFF, 0x00, 0xF0, + 0xFF, 0x07, 0x3F, 0x00, 0x7E, 0x80, 0xEF, 0xFF, 0x1F, 0xFF, 0x7F, 0x00, + 0xF0, 0xFF, 0x87, 0x7F, 0x00, 0xFE, 0x80, 0xEF, 0xFF, 0xCF, 0xFF, 0x3F, + 0x00, 0xF8, 0xBF, 0x81, 0xFF, 0x00, 0xFE, 0xC1, 0xEF, 0xAF, 0xC7, 0xFF, + 0x3F, 0x00, 0xF0, 0x00, 0xC0, 0xFF, 0x01, 0xFE, 0x83, 0xE7, 0x03, 0x00, + 0xF0, 0x01, 0x00, 0xF0, 0xB7, 0xED, 0xFF, 0x01, 0xFE, 0x8F, 0xEF, 0xDF, + 0x0B, 0xF0, 0x01, 0x00, 0xF0, 0xFF, 0xF7, 0xF7, 0x03, 0xFE, 0xDF, 0xEF, + 0xFF, 0x0F, 0xF0, 0x01, 0x00, 0xF0, 0xFF, 0xF3, 0xF3, 0x07, 0xBE, 0xBF, + 0xEF, 0xFF, 0x07, 0xF0, 0x01, 0x00, 0xF8, 0xFF, 0xF9, 0xE1, 0x07, 0x3E, + 0xFF, 0xE7, 0xFF, 0x07, 0xF0, 0x01, 0x00, 0xF0, 0x49, 0xFC, 0xC1, 0x0F, + 0x3E, 0xFE, 0xEF, 0x13, 0x00, 0xF0, 0x01, 0x00, 0xF0, 0x01, 0xFC, 0x80, + 0x1F, 0x3E, 0xFC, 0xEF, 0x03, 0x00, 0xF0, 0x01, 0x00, 0xF8, 0x01, 0x7E, + 0xFE, 0x3F, 0x3E, 0xF0, 0xEF, 0xFF, 0x1F, 0xF0, 0x01, 0x00, 0xF0, 0x00, + 0x3F, 0xFF, 0x3F, 0x3E, 0xE0, 0xE7, 0xFF, 0x1F, 0xF0, 0x01, 0x00, 0xF0, + 0x81, 0xBF, 0xFF, 0x7F, 0x3E, 0xC0, 0xEF, 0xFF, 0x0F, 0xF0, 0x01, 0x00, + 0xF0, 0x81, 0xDF, 0xFF, 0xFF, 0x3E, 0x80, 0xE7, 0xFF, 0x07, 0xF0, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, }; + diff --git a/ognbase/ogn_service.pb.c b/ognbase/ogn_service.pb.c index d45ce69..b2e89f9 100644 --- a/ognbase/ogn_service.pb.c +++ b/ognbase/ogn_service.pb.c @@ -1,24 +1,22 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.4-dev */ - -#include "ogn_service.pb.h" -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -PB_BIND(type_4, type_4, 2) - - -PB_BIND(type_5, type_5, AUTO) - - -PB_BIND(FanetService, FanetService, 2) - - -PB_BIND(ReceiverConfiguration, ReceiverConfiguration, AUTO) - - -PB_BIND(OneMessage, OneMessage, 2) - - - +/* Automatically generated nanopb constant definitions + Generated by nanopb-0.4.4-dev*/ + +#include "ogn_service.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(type_4, type_4, 2) + + +PB_BIND(type_5, type_5, AUTO) + + +PB_BIND(FanetService, FanetService, 2) + + +PB_BIND(ReceiverConfiguration, ReceiverConfiguration, AUTO) + + +PB_BIND(OneMessage, OneMessage, 2) + diff --git a/ognbase/ogn_service.pb.h b/ognbase/ogn_service.pb.h index a080864..33fd957 100644 --- a/ognbase/ogn_service.pb.h +++ b/ognbase/ogn_service.pb.h @@ -1,216 +1,221 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.4-dev */ - -#ifndef PB_OGN_SERVICE_PB_H_INCLUDED -#define PB_OGN_SERVICE_PB_H_INCLUDED -#include - -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -/* Struct definitions */ -typedef struct _type_4 { - pb_callback_t header; - pb_callback_t value1; - pb_callback_t value2; - pb_callback_t value3; - pb_callback_t temperature; - pb_callback_t wind_heading; - pb_callback_t s_scale; - pb_callback_t wind_speed; - pb_callback_t g_scale; - pb_callback_t wind_gusts; - pb_callback_t hunidity; - pb_callback_t barometic_lsb; - pb_callback_t barometic_msb; -} type_4; - -typedef struct _type_5 { - pb_callback_t header; -} type_5; - -typedef struct _FanetService { - float latitude; - float longitude; - bool has_Type_4; - type_4 Type_4; - bool has_Type_5; - type_5 Type_5; -} FanetService; - -typedef struct _ReceiverConfiguration { - bool has_maxrange; - int32_t maxrange; - bool has_band; - int32_t band; - bool has_protocol; - int32_t protocol; - bool has_aprsd; - bool aprsd; - bool has_aprsp; - int32_t aprsp; - bool has_itrackb; - bool itrackb; - bool has_istealthb; - bool istealthb; - bool has_sleepm; - int32_t sleepm; - bool has_rxidle; - int32_t rxidle; - bool has_wakeup; - int32_t wakeup; - bool has_reset; - bool reset; - bool has_reboot; - bool reboot; - bool has_alt; - float alt; - bool has_zabbixen; - bool zabbixen; -} ReceiverConfiguration; - -typedef struct _OneMessage { - bool has_fanetService; - FanetService fanetService; - bool has_receiverConfiguration; - ReceiverConfiguration receiverConfiguration; -} OneMessage; - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Initializer values for message structs */ -#define type_4_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} -#define type_5_init_default {{{NULL}, NULL}} -#define FanetService_init_default {0, 0, false, type_4_init_default, false, type_5_init_default} -#define ReceiverConfiguration_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -#define OneMessage_init_default {false, FanetService_init_default, false, ReceiverConfiguration_init_default} -#define type_4_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} -#define type_5_init_zero {{{NULL}, NULL}} -#define FanetService_init_zero {0, 0, false, type_4_init_zero, false, type_5_init_zero} -#define ReceiverConfiguration_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -#define OneMessage_init_zero {false, FanetService_init_zero, false, ReceiverConfiguration_init_zero} - -/* Field tags (for use in manual encoding/decoding) */ -#define type_4_header_tag 1 -#define type_4_value1_tag 2 -#define type_4_value2_tag 3 -#define type_4_value3_tag 4 -#define type_4_temperature_tag 5 -#define type_4_wind_heading_tag 6 -#define type_4_s_scale_tag 7 -#define type_4_wind_speed_tag 8 -#define type_4_g_scale_tag 9 -#define type_4_wind_gusts_tag 10 -#define type_4_hunidity_tag 11 -#define type_4_barometic_lsb_tag 12 -#define type_4_barometic_msb_tag 13 -#define type_5_header_tag 1 -#define FanetService_latitude_tag 1 -#define FanetService_longitude_tag 2 -#define FanetService_Type_4_tag 3 -#define FanetService_Type_5_tag 4 -#define ReceiverConfiguration_maxrange_tag 1 -#define ReceiverConfiguration_band_tag 2 -#define ReceiverConfiguration_protocol_tag 3 -#define ReceiverConfiguration_aprsd_tag 4 -#define ReceiverConfiguration_aprsp_tag 5 -#define ReceiverConfiguration_itrackb_tag 6 -#define ReceiverConfiguration_istealthb_tag 7 -#define ReceiverConfiguration_sleepm_tag 8 -#define ReceiverConfiguration_rxidle_tag 9 -#define ReceiverConfiguration_wakeup_tag 10 -#define ReceiverConfiguration_reset_tag 11 -#define ReceiverConfiguration_reboot_tag 12 -#define ReceiverConfiguration_alt_tag 13 -#define ReceiverConfiguration_zabbixen_tag 14 -#define OneMessage_fanetService_tag 1 -#define OneMessage_receiverConfiguration_tag 2 - -/* Struct field encoding specification for nanopb */ -#define type_4_FIELDLIST(X, a) \ -X(a, CALLBACK, REQUIRED, BYTES, header, 1) \ -X(a, CALLBACK, OPTIONAL, BYTES, value1, 2) \ -X(a, CALLBACK, OPTIONAL, BYTES, value2, 3) \ -X(a, CALLBACK, OPTIONAL, BYTES, value3, 4) \ -X(a, CALLBACK, OPTIONAL, BYTES, temperature, 5) \ -X(a, CALLBACK, OPTIONAL, BYTES, wind_heading, 6) \ -X(a, CALLBACK, OPTIONAL, BYTES, s_scale, 7) \ -X(a, CALLBACK, OPTIONAL, BYTES, wind_speed, 8) \ -X(a, CALLBACK, OPTIONAL, BYTES, g_scale, 9) \ -X(a, CALLBACK, OPTIONAL, BYTES, wind_gusts, 10) \ -X(a, CALLBACK, OPTIONAL, BYTES, hunidity, 11) \ -X(a, CALLBACK, OPTIONAL, BYTES, barometic_lsb, 12) \ -X(a, CALLBACK, OPTIONAL, BYTES, barometic_msb, 13) -#define type_4_CALLBACK pb_default_field_callback -#define type_4_DEFAULT NULL - -#define type_5_FIELDLIST(X, a) \ -X(a, CALLBACK, REQUIRED, BYTES, header, 1) -#define type_5_CALLBACK pb_default_field_callback -#define type_5_DEFAULT NULL - -#define FanetService_FIELDLIST(X, a) \ -X(a, STATIC, REQUIRED, FLOAT, latitude, 1) \ -X(a, STATIC, REQUIRED, FLOAT, longitude, 2) \ -X(a, STATIC, OPTIONAL, MESSAGE, Type_4, 3) \ -X(a, STATIC, OPTIONAL, MESSAGE, Type_5, 4) -#define FanetService_CALLBACK NULL -#define FanetService_DEFAULT NULL -#define FanetService_Type_4_MSGTYPE type_4 -#define FanetService_Type_5_MSGTYPE type_5 - -#define ReceiverConfiguration_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, INT32, maxrange, 1) \ -X(a, STATIC, OPTIONAL, INT32, band, 2) \ -X(a, STATIC, OPTIONAL, INT32, protocol, 3) \ -X(a, STATIC, OPTIONAL, BOOL, aprsd, 4) \ -X(a, STATIC, OPTIONAL, INT32, aprsp, 5) \ -X(a, STATIC, OPTIONAL, BOOL, itrackb, 6) \ -X(a, STATIC, OPTIONAL, BOOL, istealthb, 7) \ -X(a, STATIC, OPTIONAL, INT32, sleepm, 8) \ -X(a, STATIC, OPTIONAL, INT32, rxidle, 9) \ -X(a, STATIC, OPTIONAL, INT32, wakeup, 10) \ -X(a, STATIC, OPTIONAL, BOOL, reset, 11) \ -X(a, STATIC, OPTIONAL, BOOL, reboot, 12) \ -X(a, STATIC, OPTIONAL, FLOAT, alt, 13) \ -X(a, STATIC, OPTIONAL, BOOL, zabbixen, 14) -#define ReceiverConfiguration_CALLBACK NULL -#define ReceiverConfiguration_DEFAULT NULL - -#define OneMessage_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, MESSAGE, fanetService, 1) \ -X(a, STATIC, OPTIONAL, MESSAGE, receiverConfiguration, 2) -#define OneMessage_CALLBACK NULL -#define OneMessage_DEFAULT NULL -#define OneMessage_fanetService_MSGTYPE FanetService -#define OneMessage_receiverConfiguration_MSGTYPE ReceiverConfiguration - -extern const pb_msgdesc_t type_4_msg; -extern const pb_msgdesc_t type_5_msg; -extern const pb_msgdesc_t FanetService_msg; -extern const pb_msgdesc_t ReceiverConfiguration_msg; -extern const pb_msgdesc_t OneMessage_msg; - -/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ -#define type_4_fields &type_4_msg -#define type_5_fields &type_5_msg -#define FanetService_fields &FanetService_msg -#define ReceiverConfiguration_fields &ReceiverConfiguration_msg -#define OneMessage_fields &OneMessage_msg - -/* Maximum encoded size of messages (where known) */ -/* type_4_size depends on runtime parameters */ -/* type_5_size depends on runtime parameters */ -/* FanetService_size depends on runtime parameters */ -#define ReceiverConfiguration_size 94 -/* OneMessage_size depends on runtime parameters */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif +/* Automatically generated nanopb header + Generated by nanopb-0.4.4-dev*/ + +#ifndef PB_OGN_SERVICE_PB_H_INCLUDED +#define PB_OGN_SERVICE_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Struct definitions */ +typedef struct _type_4 +{ + pb_callback_t header; + pb_callback_t value1; + pb_callback_t value2; + pb_callback_t value3; + pb_callback_t temperature; + pb_callback_t wind_heading; + pb_callback_t s_scale; + pb_callback_t wind_speed; + pb_callback_t g_scale; + pb_callback_t wind_gusts; + pb_callback_t hunidity; + pb_callback_t barometic_lsb; + pb_callback_t barometic_msb; +} type_4; + +typedef struct _type_5 +{ + pb_callback_t header; +} type_5; + +typedef struct _FanetService +{ + float latitude; + float longitude; + bool has_Type_4; + type_4 Type_4; + bool has_Type_5; + type_5 Type_5; +} FanetService; + +typedef struct _ReceiverConfiguration +{ + bool has_maxrange; + int32_t maxrange; + bool has_band; + int32_t band; + bool has_protocol; + int32_t protocol; + bool has_aprsd; + bool aprsd; + bool has_aprsp; + int32_t aprsp; + bool has_itrackb; + bool itrackb; + bool has_istealthb; + bool istealthb; + bool has_sleepm; + int32_t sleepm; + bool has_rxidle; + int32_t rxidle; + bool has_wakeup; + int32_t wakeup; + bool has_reset; + bool reset; + bool has_reboot; + bool reboot; + bool has_alt; + float alt; + bool has_zabbixen; + bool zabbixen; +} ReceiverConfiguration; + +typedef struct _OneMessage +{ + bool has_fanetService; + FanetService fanetService; + bool has_receiverConfiguration; + ReceiverConfiguration receiverConfiguration; +} OneMessage; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define type_4_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define type_5_init_default {{{NULL}, NULL}} +#define FanetService_init_default {0, 0, false, type_4_init_default, false, type_5_init_default} +#define ReceiverConfiguration_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define OneMessage_init_default {false, FanetService_init_default, false, ReceiverConfiguration_init_default} +#define type_4_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define type_5_init_zero {{{NULL}, NULL}} +#define FanetService_init_zero {0, 0, false, type_4_init_zero, false, type_5_init_zero} +#define ReceiverConfiguration_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define OneMessage_init_zero {false, FanetService_init_zero, false, ReceiverConfiguration_init_zero} + +/* Field tags (for use in manual encoding/decoding) */ +#define type_4_header_tag 1 +#define type_4_value1_tag 2 +#define type_4_value2_tag 3 +#define type_4_value3_tag 4 +#define type_4_temperature_tag 5 +#define type_4_wind_heading_tag 6 +#define type_4_s_scale_tag 7 +#define type_4_wind_speed_tag 8 +#define type_4_g_scale_tag 9 +#define type_4_wind_gusts_tag 10 +#define type_4_hunidity_tag 11 +#define type_4_barometic_lsb_tag 12 +#define type_4_barometic_msb_tag 13 +#define type_5_header_tag 1 +#define FanetService_latitude_tag 1 +#define FanetService_longitude_tag 2 +#define FanetService_Type_4_tag 3 +#define FanetService_Type_5_tag 4 +#define ReceiverConfiguration_maxrange_tag 1 +#define ReceiverConfiguration_band_tag 2 +#define ReceiverConfiguration_protocol_tag 3 +#define ReceiverConfiguration_aprsd_tag 4 +#define ReceiverConfiguration_aprsp_tag 5 +#define ReceiverConfiguration_itrackb_tag 6 +#define ReceiverConfiguration_istealthb_tag 7 +#define ReceiverConfiguration_sleepm_tag 8 +#define ReceiverConfiguration_rxidle_tag 9 +#define ReceiverConfiguration_wakeup_tag 10 +#define ReceiverConfiguration_reset_tag 11 +#define ReceiverConfiguration_reboot_tag 12 +#define ReceiverConfiguration_alt_tag 13 +#define ReceiverConfiguration_zabbixen_tag 14 +#define OneMessage_fanetService_tag 1 +#define OneMessage_receiverConfiguration_tag 2 + +/* Struct field encoding specification for nanopb */ +#define type_4_FIELDLIST(X, a) \ + X(a, CALLBACK, REQUIRED, BYTES, header, 1) \ + X(a, CALLBACK, OPTIONAL, BYTES, value1, 2) \ + X(a, CALLBACK, OPTIONAL, BYTES, value2, 3) \ + X(a, CALLBACK, OPTIONAL, BYTES, value3, 4) \ + X(a, CALLBACK, OPTIONAL, BYTES, temperature, 5) \ + X(a, CALLBACK, OPTIONAL, BYTES, wind_heading, 6) \ + X(a, CALLBACK, OPTIONAL, BYTES, s_scale, 7) \ + X(a, CALLBACK, OPTIONAL, BYTES, wind_speed, 8) \ + X(a, CALLBACK, OPTIONAL, BYTES, g_scale, 9) \ + X(a, CALLBACK, OPTIONAL, BYTES, wind_gusts, 10) \ + X(a, CALLBACK, OPTIONAL, BYTES, hunidity, 11) \ + X(a, CALLBACK, OPTIONAL, BYTES, barometic_lsb, 12) \ + X(a, CALLBACK, OPTIONAL, BYTES, barometic_msb, 13) +#define type_4_CALLBACK pb_default_field_callback +#define type_4_DEFAULT NULL + +#define type_5_FIELDLIST(X, a) \ + X(a, CALLBACK, REQUIRED, BYTES, header, 1) +#define type_5_CALLBACK pb_default_field_callback +#define type_5_DEFAULT NULL + +#define FanetService_FIELDLIST(X, a) \ + X(a, STATIC, REQUIRED, FLOAT, latitude, 1) \ + X(a, STATIC, REQUIRED, FLOAT, longitude, 2) \ + X(a, STATIC, OPTIONAL, MESSAGE, Type_4, 3) \ + X(a, STATIC, OPTIONAL, MESSAGE, Type_5, 4) +#define FanetService_CALLBACK NULL +#define FanetService_DEFAULT NULL +#define FanetService_Type_4_MSGTYPE type_4 +#define FanetService_Type_5_MSGTYPE type_5 + +#define ReceiverConfiguration_FIELDLIST(X, a) \ + X(a, STATIC, OPTIONAL, INT32, maxrange, 1) \ + X(a, STATIC, OPTIONAL, INT32, band, 2) \ + X(a, STATIC, OPTIONAL, INT32, protocol, 3) \ + X(a, STATIC, OPTIONAL, BOOL, aprsd, 4) \ + X(a, STATIC, OPTIONAL, INT32, aprsp, 5) \ + X(a, STATIC, OPTIONAL, BOOL, itrackb, 6) \ + X(a, STATIC, OPTIONAL, BOOL, istealthb, 7) \ + X(a, STATIC, OPTIONAL, INT32, sleepm, 8) \ + X(a, STATIC, OPTIONAL, INT32, rxidle, 9) \ + X(a, STATIC, OPTIONAL, INT32, wakeup, 10) \ + X(a, STATIC, OPTIONAL, BOOL, reset, 11) \ + X(a, STATIC, OPTIONAL, BOOL, reboot, 12) \ + X(a, STATIC, OPTIONAL, FLOAT, alt, 13) \ + X(a, STATIC, OPTIONAL, BOOL, zabbixen, 14) +#define ReceiverConfiguration_CALLBACK NULL +#define ReceiverConfiguration_DEFAULT NULL + +#define OneMessage_FIELDLIST(X, a) \ + X(a, STATIC, OPTIONAL, MESSAGE, fanetService, 1) \ + X(a, STATIC, OPTIONAL, MESSAGE, receiverConfiguration, 2) +#define OneMessage_CALLBACK NULL +#define OneMessage_DEFAULT NULL +#define OneMessage_fanetService_MSGTYPE FanetService +#define OneMessage_receiverConfiguration_MSGTYPE ReceiverConfiguration + +extern const pb_msgdesc_t type_4_msg; +extern const pb_msgdesc_t type_5_msg; +extern const pb_msgdesc_t FanetService_msg; +extern const pb_msgdesc_t ReceiverConfiguration_msg; +extern const pb_msgdesc_t OneMessage_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define type_4_fields &type_4_msg +#define type_5_fields &type_5_msg +#define FanetService_fields &FanetService_msg +#define ReceiverConfiguration_fields &ReceiverConfiguration_msg +#define OneMessage_fields &OneMessage_msg + +/* Maximum encoded size of messages (where known) + type_4_size depends on runtime parameters + type_5_size depends on runtime parameters + FanetService_size depends on runtime parameters*/ +#define ReceiverConfiguration_size 94 +/* OneMessage_size depends on runtime parameters */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/ognbase/ognbase.ino b/ognbase/ognbase.ino index 5a89ad1..567690b 100644 --- a/ognbase/ognbase.ino +++ b/ognbase/ognbase.ino @@ -120,7 +120,7 @@ #define APRS_CHECK_KEEPALIVE_TIME 20 #define TimeToCheckKeepAliveOGN() (seconds() - ExportTimeCheckKeepAliveOGN >= APRS_CHECK_KEEPALIVE_TIME) -#define APRS_CHECK_WIFI_TIME 300 +#define APRS_CHECK_WIFI_TIME 600 #define TimeToCheckWifi() (seconds() - ExportTimeCheckWifi >= APRS_CHECK_WIFI_TIME) #define APRS_STATUS_REC 1800 @@ -134,10 +134,10 @@ //testing #define TIME_TO_SLEEP 60 -#define TimeToSleep() (seconds() - ExportTimeSleep >= settings->sleep_after_rx_idle) +#define TimeToSleep() (seconds() - ExportTimeSleep >= ogn_rxidle) /*Testing FANET service messages*/ -#define TIME_TO_EXPORT_FANET_SERVICE 20 /*every 40 sec 10 for testing*/ +#define TIME_TO_EXPORT_FANET_SERVICE 40 /*every 40 sec 10 for testing*/ #define TimeToExportFanetService() (seconds() - ExportTimeFanetService >= TIME_TO_EXPORT_FANET_SERVICE) @@ -255,7 +255,7 @@ void setup() hw_info.gnss = GNSS_setup(); ThisAircraft.aircraft_type = settings->aircraft_type; } - ThisAircraft.protocol = settings->rf_protocol; + ThisAircraft.protocol = ogn_protocol_1; ThisAircraft.stealth = settings->stealth; ThisAircraft.no_track = settings->no_track; @@ -368,9 +368,12 @@ void ground() if((WiFi.getMode() == WIFI_AP)){ OLED_write("Setup mode..", 0, 9, true); - OLED_write("connect to AP", 0, 18, false); - snprintf (buf, sizeof(buf), "reboot in %d seconds", 300 - seconds()); + snprintf (buf, sizeof(buf), "SSID: %s", host_name); + OLED_write(buf, 0, 18, false); + snprintf (buf, sizeof(buf), "ip: %s", "192.168.1.1"); OLED_write(buf, 0, 27, false); + snprintf (buf, sizeof(buf), "reboot in %d seconds", 300 - seconds()); + OLED_write(buf, 0, 36, false); delay(1000); if(300 < seconds()){ SoC->reset(); @@ -420,6 +423,18 @@ void ground() ExportTimeRegisterOGN = seconds(); } + if(ground_registred == -1){ + OLED_write("server registration failed!", 0, 18, true); + OLED_write("please check json file!", 0, 27, false); + snprintf (buf, sizeof(buf), "%s : %d", ogn_server.c_str(), ogn_port); + OLED_write(buf, 0, 36, false); + ground_registred = -2; + } + + if(ground_registred == -2){ + // + } + if (TimeToExportOGN() && ground_registred == 1) { OGN_APRS_Export(); @@ -458,16 +473,16 @@ void ground() } - if ( TimeToSleep() && settings->sleep_mode ) + if ( TimeToSleep() && ogn_sleepmode ) { msg = "entering sleep mode for "; - msg += String(settings->wake_up_timer); + msg += String(ogn_wakeuptimer); msg += " seconds - good night"; Logger_send_udp(&msg); - esp_sleep_enable_timer_wakeup(settings->wake_up_timer*1000000LL); + esp_sleep_enable_timer_wakeup(ogn_wakeuptimer*1000000LL); esp_sleep_enable_ext0_wakeup(GPIO_NUM_26,1); - if (settings->sleep_mode == 1){ + if (ogn_sleepmode == 1){ GNSS_sleep(); } ground_registred = 0; @@ -477,14 +492,14 @@ void ground() if(ground_registred == 1 && TimeToExportFanetService()){ - disp = "export FANET service..."; - OLED_write(disp, 0, 24, true); + + OLED_draw_Bitmap(14, 0, 2 , true); if( fanet_transmitter ){ RSM_receiver(); } else{ - fanet_transmitter = RSM_Setup(settings->ogndebugp+1); + fanet_transmitter = RSM_Setup(ogn_debugport+1); } ExportTimeFanetService = seconds(); msg = "current system time "; @@ -499,9 +514,14 @@ void ground() } if( TimeToCheckWifi() ){ - disp = "checking Wifi..."; - OLED_write(disp, 0, 24, true); - OGN_APRS_check_Wifi(); + OLED_draw_Bitmap(39, 5, 3 , true); + OLED_write("check connections..", 15, 45, false); + if(OGN_APRS_check_Wifi()){ + OLED_write("success", 35, 54, false); + } + else{ + OLED_write("error", 35, 54, false); + } ExportTimeCheckWifi = seconds(); } @@ -517,7 +537,7 @@ void watchout() success = RF_Receive(); if (success) { - size_t rx_size = RF_Payload_Size(settings->rf_protocol); + size_t rx_size = RF_Payload_Size(ogn_protocol_1); rx_size = rx_size > sizeof(fo.raw) ? sizeof(fo.raw) : rx_size; memset(fo.raw, 0, sizeof(fo.raw)); diff --git a/ognbase/version.h b/ognbase/version.h index a6bb606..68461fb 100644 --- a/ognbase/version.h +++ b/ognbase/version.h @@ -1,11 +1,11 @@ -//The version number conforms to semver.org format -#define _VERSION_MAJOR 0 -#define _VERSION_MINOR 1 -#define _VERSION_PATCH 0 -#define _VERSION_BUILD 13 -#define _VERSION_DATE "28/02/2021" -#define _VERSION_TIME "23:06:46" -#define _VERSION_ONLY "0.1.0" -#define _VERSION_NOBUILD "0.1.0 (28/02/2021)" -#define _VERSION "0.1.0-13" -//The version information is created automatically, more information here: https://github.com/rvdbreemen/autoinc-semver +//The version number conforms to semver.org format +#define _VERSION_MAJOR 0 +#define _VERSION_MINOR 1 +#define _VERSION_PATCH 0 +#define _VERSION_BUILD 17 +#define _VERSION_DATE "07/03/2021" +#define _VERSION_TIME "21:24:21" +#define _VERSION_ONLY "0.1.0" +#define _VERSION_NOBUILD "0.1.0 (07/03/2021)" +#define _VERSION "0.1.0-17" +//The version information is created automatically, more information here: https://github.com/rvdbreemen/autoinc-semver