#include #include #include #include #include #include #include "mbedtls/md5.h" #include "hal.h" #include "esp_http_server.h" #include "format.h" #include "rf.h" #include "proc.h" #include "gps.h" #include "log.h" #include "http.h" #include "ognconv.h" // #define DEBUG_PRINT #ifdef WITH_HTTP // ============================================================================================================ // generic HTML list for submit forms static void SelectList(httpd_req_t *Req, const char *Name, const char **List, int Size, int Sel=0) { char Line[64]; int Len; Len =Format_String(Line, "\n"); } static void Begin_Control_Row(httpd_req_t *Req, const char *Label) { httpd_resp_sendstr_chunk(Req, "
\n
\n"); } static void End_Control_Row(httpd_req_t *Req) { httpd_resp_sendstr_chunk(Req, "\n
\n"); } static void Page_Control_Row(httpd_req_t *Req, const char *Name, const int Index, const char *IndexChar) { Begin_Control_Row(Req, Name); httpd_resp_sendstr_chunk(Req, ">Index)&1) != 0 ) { httpd_resp_sendstr_chunk(Req, " checked"); } httpd_resp_sendstr_chunk(Req, "/>\n\ >Index)&1) == 0 ) { httpd_resp_sendstr_chunk(Req, " disabled"); } httpd_resp_sendstr_chunk(Req, "/>\n"); End_Control_Row(Req); } // HTML form for the Info parameters static void ParmForm_Info(httpd_req_t *Req) { httpd_resp_sendstr_chunk(Req, "

Info

"); httpd_resp_sendstr_chunk(Req, "
\n"); Begin_Control_Row(Req, "Pilot"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Crew"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Base airfield"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Registration"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Manufacturer"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Model"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Type"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); httpd_resp_sendstr_chunk(Req, "
\n"); httpd_resp_sendstr_chunk(Req, "
\n"); } // HTML form for the Aircraft identification: address, address-type, aircraft-type static void ParmForm_Acft(httpd_req_t *Req) { char Line[16]; httpd_resp_sendstr_chunk(Req, "

Aircraft

"); httpd_resp_sendstr_chunk(Req, "
\n"); Begin_Control_Row(Req, "Address"); httpd_resp_sendstr_chunk(Req, ">16)); Format_Hex(Line+2, (uint16_t)Parameters.Address); httpd_resp_send_chunk(Req, Line, 6); httpd_resp_sendstr_chunk(Req, "\">"); End_Control_Row(Req); Begin_Control_Row(Req, "Addr-Type"); const char *AddrTypeTable[4] = { "Random", "ICAO", "FLARM", "OGN" } ; SelectList(Req, "AddrType", AddrTypeTable, 4, Parameters.AddrType); End_Control_Row(Req); Begin_Control_Row(Req, "Acft-Type"); const char *AcftTypeTable[16] = { "Unknown", "(moto)Glider", "Tow-plane", "Helicopter", "Parachute", "Drop-plane", "Hang-glider", "Para-glider", "Powered-aircraft", "Jet-aircraft", "UFO", "Balloon", "Airship", "UAV/drone", "Ground support", "Static object" } ; SelectList(Req, "AcftType", AcftTypeTable, 16, Parameters.AcftType); End_Control_Row(Req); httpd_resp_sendstr_chunk(Req, "
\n"); httpd_resp_sendstr_chunk(Req, "
\n"); } static void ParmForm_GPS(httpd_req_t *Req) // produce HTML form for GPS parameters { char Line[16]; int Len; #ifdef WITH_GPS_UBX httpd_resp_sendstr_chunk(Req, "

GPS: UBX

"); #else #ifdef WITH_GPS_MTK httpd_resp_sendstr_chunk(Req, "

GPS: MTK

"); #else httpd_resp_sendstr_chunk(Req, "

GPS

"); #endif #endif httpd_resp_sendstr_chunk(Req, "
\n"); Begin_Control_Row(Req, "Nav. rate [Hz]"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Nav. mode"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Geoid-Separ."); const char *GeoidSeparTable[2] = { "GPS", "Override" } ; SelectList(Req, "manGeoidSepar", GeoidSeparTable, 2, Parameters.manGeoidSepar); httpd_resp_sendstr_chunk(Req, "\n"); End_Control_Row(Req); Begin_Control_Row(Req, "GNSS mode"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "PPS delay [ms]"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); httpd_resp_sendstr_chunk(Req, "
\n"); httpd_resp_sendstr_chunk(Req, "
\n"); } static void ParmForm_Page(httpd_req_t *Req) // produce HTML form for parameters not included in other forms { char Line[16]; int Len; httpd_resp_sendstr_chunk(Req, "

Pages

"); httpd_resp_sendstr_chunk(Req, "
\n"); Begin_Control_Row(Req, "Altitude Unit"); const char *AltitudeUnitTable[2] = { "meter", "feet" } ; SelectList(Req, "AltitudeUnit", AltitudeUnitTable, 2, Parameters.AltitudeUnit); End_Control_Row(Req); Begin_Control_Row(Req, "Speed Unit"); const char *SpeedUnitTable[2] = { "km/h", "knot" } ; SelectList(Req, "SpeedUnit", SpeedUnitTable, 2, Parameters.SpeedUnit); End_Control_Row(Req); Begin_Control_Row(Req, "Vario Unit"); const char *VarioUnitTable[2] = { "m/s", "fpm" } ; SelectList(Req, "VarioUnit", VarioUnitTable, 2, Parameters.VarioUnit); End_Control_Row(Req); Begin_Control_Row(Req, "Pages"); httpd_resp_sendstr_chunk(Req, ""); httpd_resp_sendstr_chunk(Req, "ShowInitial Page"); End_Control_Row(Req); Page_Control_Row(Req, "ID", 0, "0"); Page_Control_Row(Req, "GPS", 1, "1"); Page_Control_Row(Req, "RF", 2, "2"); Page_Control_Row(Req, "Baro", 3, "3"); Page_Control_Row(Req, "System", 4, "4"); Page_Control_Row(Req, "Battery", 5, "5"); Page_Control_Row(Req, "AltitudeAndSpeed", 6, "6"); Page_Control_Row(Req, "Relay", 7, "7"); Page_Control_Row(Req, "Lookout", 8, "8"); Page_Control_Row(Req, "TrafWarn", 9, "9"); Page_Control_Row(Req, "Flight", 10, "10"); Page_Control_Row(Req, "LoRaWAN", 11, "11"); httpd_resp_sendstr_chunk(Req, "\n"); httpd_resp_sendstr_chunk(Req, "
\n"); httpd_resp_sendstr_chunk(Req, "
\n"); } static void ParmForm_Other(httpd_req_t *Req) // produce HTML form for parameters not included in other forms { char Line[16]; int Len; httpd_resp_sendstr_chunk(Req, "

Other

"); httpd_resp_sendstr_chunk(Req, "
\n"); Begin_Control_Row(Req, "Freq. plan"); const char *FreqPlanTable[6] = { "Auto", "Europe/Africa", "USA/Canada", "Australia/Chile", "New Zeeland", "Izrael" }; SelectList(Req, "FreqPlan", FreqPlanTable, 6, Parameters.FreqPlan); End_Control_Row(Req); Begin_Control_Row(Req, "Tx power [dBm]"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Freq.corr. [ppm]"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Console baud"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Verbose"); const char *VerboseTable[2] = { "0 (off)", "1 (on)" }; SelectList(Req, "Verbose", VerboseTable, 2, Parameters.Verbose); End_Control_Row(Req); httpd_resp_sendstr_chunk(Req, "
\n"); httpd_resp_sendstr_chunk(Req, "
\n"); } #ifdef WITH_STRATUX static void ParmForm_Stratux(httpd_req_t *Req) // Connection to Stratux WiFi parameters and options { char Line[16]; int Len; httpd_resp_sendstr_chunk(Req, "

Stratux

"); httpd_resp_sendstr_chunk(Req, "
\n"); Begin_Control_Row(Req, "SSID"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Password"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "TCP host"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "TCP port"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Tx power [dBm]"); httpd_resp_sendstr_chunk(Req, ">2, 2, 1); httpd_resp_send_chunk(Req, Line, Len); httpd_resp_sendstr_chunk(Req, "\">"); End_Control_Row(Req); Begin_Control_Row(Req, "Min. RSSI [dBm]"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); httpd_resp_sendstr_chunk(Req, "
\n"); httpd_resp_sendstr_chunk(Req, "
\n"); } #endif #ifdef WITH_AP static void ParmForm_AP(httpd_req_t *Req) // Wi-Fi access point parameters { char Line[16]; int Len; { char Line[16]; int Len; httpd_resp_sendstr_chunk(Req, "

Wi-Fi AP

"); httpd_resp_sendstr_chunk(Req, "
\n"); Begin_Control_Row(Req, "SSID"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Password"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Data port"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); Begin_Control_Row(Req, "Tx power [dBm]"); httpd_resp_sendstr_chunk(Req, ">2, 2, 1); httpd_resp_send_chunk(Req, Line, Len); httpd_resp_sendstr_chunk(Req, "\">"); End_Control_Row(Req); Begin_Control_Row(Req, "Min. RSSI [dBm]"); httpd_resp_sendstr_chunk(Req, ""); End_Control_Row(Req); httpd_resp_sendstr_chunk(Req, "
\n"); httpd_resp_sendstr_chunk(Req, "
\n"); } #endif static void ParmForm_Defaults(httpd_req_t *Req) { httpd_resp_sendstr_chunk(Req, "\
\n\ \n\ \n\
\n"); } static void ParmForm_Restart(httpd_req_t *Req) { httpd_resp_sendstr_chunk(Req, "\
\n\ \n\ \n\
\n"); } // ============================================================================================================ static void Table_System(httpd_req_t *Req) { char Line[128]; int Len; uint32_t Time=TimeSync_Time(); uint32_t Sec = (Time-1)%60; GPS_Position *GPS = GPS_getPosition(Sec); if(GPS==0) return; httpd_resp_sendstr_chunk(Req, "

System

"); httpd_resp_sendstr_chunk(Req, "\n"); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); httpd_resp_sendstr_chunk(Req, "
Board"); #ifdef WITH_FollowMe Len+=Format_String(Line+Len, "FollowMe"); #endif #ifdef WITH_TTGO Len+=Format_String(Line+Len, "TTGO"); #endif #if defined(WITH_HELTEC) || defined(WITH_HELTEC_V2) Len+=Format_String(Line+Len, "HELTEC"); #endif #if defined(WITH_TBEAM) || defined(WITH_TBEAM_V10) Len+=Format_String(Line+Len, "T-BEAM"); #endif Len+=Format_String(Line+Len, "
Display"); #ifdef WITH_ILI9341 // 320x240 M5stack Len+=Format_String(Line+Len, "ILI9341"); #endif #ifdef WITH_ST7789 // IPS 240x240 ST7789 Len+=Format_String(Line+Len, "ST7789"); #endif #ifdef WITH_TFT_LCD // TFT LCD Len+=Format_String(Line+Len, "TFT_LCD"); #endif #ifdef WITH_OLED // OLED display on the I2C: some TTGO modules are without OLED display Len+=Format_String(Line+Len, "OLED"); #endif #ifdef WITH_OLED2 // 2nd OLED display, I2C address next higher Len+=Format_String(Line+Len, "
OLED2"); #endif #ifdef WITH_U8G2_OLED // I2C OLED through the U8g2 library Len+=Format_String(Line+Len, "U8G2_OLED"); #endif Len+=Format_String(Line+Len, "
GPS"); #ifdef WITH_GPS_MTK Len+=Format_String(Line+Len, "MTK GPS"); #endif #ifdef WITH_GPS_UBX Len+=Format_String(Line+Len, "UBX GPS"); #endif #ifdef WITH_GPS_SRF Len+=Format_String(Line+Len, "SRF GPS"); #endif Len+=Format_String(Line+Len, "
Radio"); #ifdef WITH_RFM95 Len+=Format_String(Line+Len, "RFM95"); #endif #ifdef WITH_RFM69 Len+=Format_String(Line+Len, "RFM69"); #endif Len+=Format_String(Line+Len, "
Baro"); #ifdef WITH_BMP180 Len+=Format_String(Line+Len, "BMP180"); #endif #ifdef WITH_BMP280 Len+=Format_String(Line+Len, "BMP280"); #endif #ifdef WITH_BME280 Len+=Format_String(Line+Len, "BME280"); #endif #ifdef WITH_MS5607 Len+=Format_String(Line+Len, "MS5607"); #endif #ifdef WITH_MS5611 Len+=Format_String(Line+Len, "MS5611"); #endif Len+=Format_String(Line+Len, "
Bluetooth serial port"); #ifdef WITH_BT_SPP Len+=Format_String(Line+Len, "Yes"); #else Len+=Format_String(Line+Len, "No"); #endif Len+=Format_String(Line+Len, "
LoRaWAN"); #ifdef WITH_LORAWAN Len+=Format_String(Line+Len, "Yes"); #else Len+=Format_String(Line+Len, "No"); #endif Len+=Format_String(Line+Len, "
Digital Buzzer"); #ifdef WITH_BEEPER Len+=Format_String(Line+Len, "Yes"); #else Len+=Format_String(Line+Len, "No"); #endif Len+=Format_String(Line+Len, "
Analog Sound"); #ifdef WITH_SOUND Len+=Format_String(Line+Len, "Yes"); #else Len+=Format_String(Line+Len, "No"); #endif Len+=Format_String(Line+Len, "
SD Card"); #ifdef WITH_SD Len+=Format_String(Line+Len, "Yes"); #else Len+=Format_String(Line+Len, "No"); #endif Len+=Format_String(Line+Len, "
SPIFFS"); #ifdef WITH_SPIFFS Len+=Format_String(Line+Len, "Yes"); #else Len+=Format_String(Line+Len, "No"); #endif Len+=Format_String(Line+Len, "
WiFi"); #ifdef WITH_WIFI Len+=Format_String(Line+Len, "Yes"); #else Len+=Format_String(Line+Len, "No"); #endif Len+=Format_String(Line+Len, "
Access Point (wifi)"); #ifdef WITH_AP Len+=Format_String(Line+Len, "Yes"); #else Len+=Format_String(Line+Len, "No"); #endif Len+=Format_String(Line+Len, "
Encrypt"); #ifdef WITH_ENCRYPT Len+=Format_String(Line+Len, "Yes"); #else Len+=Format_String(Line+Len, "No"); #endif Len+=Format_String(Line+Len, "
\n"); } static void Table_GPS(httpd_req_t *Req) { char Line[128]; int Len; uint32_t Time=TimeSync_Time(); uint32_t Sec = (Time-1)%60; GPS_Position *GPS = GPS_getPosition(Sec); if(GPS==0) return; httpd_resp_sendstr_chunk(Req, "

GPS

"); httpd_resp_sendstr_chunk(Req, "\n"); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len=Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len=Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); if(GPS->hasBaro) { Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); } Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); httpd_resp_sendstr_chunk(Req, "
Date"); Len+=Format_UnsDec(Line+Len, GPS->Year+2000 , 4); Line[Len++]='.'; Len+=Format_UnsDec(Line+Len, GPS->Month, 2); Line[Len++]='.'; Len+=Format_UnsDec(Line+Len, GPS->Day , 2); Len+=Format_String(Line+Len, "
Time"); Len+=Format_UnsDec(Line+Len, GPS->Hour , 2); Line[Len++]=':'; Len+=Format_UnsDec(Line+Len, GPS->Min , 2); Line[Len++]=':'; Len+=Format_UnsDec(Line+Len, GPS->Sec , 2); Line[Len++]='.'; Len+=Format_UnsDec(Line+Len, GPS->mSec, 3); Len+=Format_String(Line+Len, "
Lock"); if(GPS->FixMode>=2) { strcpy(Line+Len, "0-D "); Line[Len]='0'+GPS->FixMode; } else { strcpy(Line+Len, "--- "); } Len+=4; Len+=Format_String(Line+Len, " Hdop"); Len+=Format_UnsDec(Line+Len, GPS->HDOP, 2, 1); Len+=Format_String(Line+Len, "
Satellites"); Len+=Format_UnsDec(Line+Len, GPS->Satellites); Len+=Format_String(Line+Len, "sats "); Len+=Format_UnsDec(Line+Len, ((uint16_t)10*GPS_SatSNR+2)/4, 2, 1); Len+=Format_String(Line+Len, "dB
Latitude"); Len+=Format_SignDec(Line+Len, GPS->Latitude/6, 7, 5); Len+=Format_String(Line+Len, "°
Longitude"); Len+=Format_SignDec(Line+Len, GPS->Longitude/6, 8, 5); Len+=Format_String(Line+Len, "°
Altitude"); Len+=Format_SignDec(Line+Len, GPS->Altitude, 2, 1); Len+=Format_String(Line+Len, " m
Geoid Separ."); Len+=Format_SignDec(Line+Len, GPS->GeoidSeparation, 2, 1); Len+=Format_String(Line+Len, " m
Pressure Alt."); Len+=Format_SignDec(Line+Len, GPS->StdAltitude, 2, 1); Len+=Format_String(Line+Len, " m
Pressure"); Len+=Format_SignDec(Line+Len, (GPS->Pressure+2)/4, 3, 2); Len+=Format_String(Line+Len, " hPa
Temperature"); Len+=Format_SignDec(Line+Len, GPS->Temperature, 2, 1); Len+=Format_String(Line+Len, " ℃
Climb rate"); Len+=Format_SignDec(Line+Len, GPS->ClimbRate, 2, 1); Len+=Format_String(Line+Len, " m/s
Hor. speed"); Len+=Format_UnsDec(Line+Len, GPS->Speed, 2, 1); Len+=Format_String(Line+Len, " m/s
Hor. track"); Len+=Format_UnsDec(Line+Len, GPS->Heading, 4, 1); Len+=Format_String(Line+Len, "°
\n"); } // ------------------------------------------------------------------------------------------------------------- #ifdef WITH_LOOKOUT static void Table_LookOut(httpd_req_t *Req) { char Line[128]; int Len; httpd_resp_sendstr_chunk(Req, "

LookOut

"); httpd_resp_sendstr_chunk(Req, "\n"); httpd_resp_sendstr_chunk(Req, "\n\n"); for( uint8_t Idx=0; IdxAlloc) continue; Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); } httpd_resp_sendstr_chunk(Req, "\n
LookOutTime MarginDistance
"); Len+=Format_Hex(Line+Len, Tgt->ID, 7); Len+=Format_String(Line+Len, ""); Len+=Format_UnsDec(Line+Len, Tgt->TimeMargin>>1, 2); Len+=Format_String(Line+Len, "s"); Len+=Format_UnsDec(Line+Len, ((Tgt->HorDist>>1)+5)/10, 2, 2); Len+=Format_String(Line+Len, "km
\n"); } #endif // ------------------------------------------------------------------------------------------------------------- static void Table_Relay(httpd_req_t *Req) { char Line[128]; int Len; httpd_resp_sendstr_chunk(Req, "

Relay

"); httpd_resp_sendstr_chunk(Req, "\n"); httpd_resp_sendstr_chunk(Req, "\n\n"); for( uint8_t Idx=0; Idx *Packet = RelayQueue.Packet+Idx; if(Packet->Rank==0) continue; Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); } httpd_resp_sendstr_chunk(Req, "\n
RelayRank[sec]
"); Line[Len++]='0'+Packet->Packet.Header.AddrType; Line[Len++]=':'; Len+=Format_Hex(Line+Len, Packet->Packet.Header.Address, 6); Len+=Format_String(Line+Len, ""); Len+=Format_Hex(Line+Len, Packet->Rank); Len+=Format_String(Line+Len, ""); Len+=Format_UnsDec(Line+Len, Packet->Packet.Position.Time, 2); Len+=Format_String(Line+Len, "
\n"); } // ------------------------------------------------------------------------------------------------------------- static void Table_RF(httpd_req_t *Req) { char Line[128]; int Len; httpd_resp_sendstr_chunk(Req, "

RF chip

"); httpd_resp_sendstr_chunk(Req, "\n"); Len=Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); httpd_resp_sendstr_chunk(Req, "
RF chip"); #ifdef WITH_RFM69 Len+=Format_String(Line+Len, "RFM69"); #endif #ifdef WITH_RFM95 Len+=Format_String(Line+Len, "sx1276"); #endif #ifdef WITH_SX1272 Len+=Format_String(Line+Len, "sx1272"); #endif Len+=Format_String(Line+Len, "
Tx power"); Len+=Format_SignDec(Line+Len, (int16_t)Parameters.TxPower); Len+=Format_String(Line+Len, "dBm
Freq. corr."); Len+=Format_SignDec(Line+Len, (int32_t)Parameters.RFchipFreqCorr, 2, 1); Len+=Format_String(Line+Len, "ppm
Rx noise"); Len+=Format_SignDec(Line+Len, -5*TRX.averRSSI, 2, 1); Len+=Format_String(Line+Len, "dBm
Rx rate"); Len+=Format_UnsDec(Line+Len, RX_OGN_Count64); Len+=Format_String(Line+Len, "/min
Temperature"); Len+=Format_SignDec(Line+Len, (int16_t)TRX.chipTemp); Len+=Format_String(Line+Len, "°C
Rx queue"); Len+=Format_UnsDec(Line+Len, RF_RxFIFO.Full()); Len+=Format_String(Line+Len, "pkt
Band"); Len+=Format_UnsDec(Line+Len, (uint16_t)(RF_FreqPlan.getCenterFreq()/100000), 3, 1); Len+=Format_String(Line+Len, "MHz
\n"); } static uint8_t BattCapacity(uint16_t mVolt) { if(mVolt>=4100) return 100; if(mVolt<=3600) return 0; return (mVolt-3600+2)/5; } // ------------------------------------------------------------------------------------------------------------- static void Table_Batt(httpd_req_t *Req) { char Line[128]; int Len; httpd_resp_sendstr_chunk(Req, "

Battery

"); httpd_resp_sendstr_chunk(Req, "\n"); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); #ifdef WITH_BQ uint8_t Status = BQ.readStatus(); // read status register uint8_t State = (Status>>4)&0x03; // charging status const char *StateName[4] = { "Charge OFF" , "Pre-charge", "Charging", "Full" } ; Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); #endif #ifdef WITH_AXP uint16_t InpCurr=AXP.readBatteryInpCurrent(); // [mA] uint16_t OutCurr=AXP.readBatteryOutCurrent(); // [mA] uint16_t Vbus=AXP.readVbusVoltage(); // [mV] uint16_t VbusCurr=AXP.readVbusCurrent(); // [mA] int16_t Temp=AXP.readTemperature(); // [0.1degC] uint32_t InpCharge=AXP.readBatteryInpCharge(); uint32_t OutCharge=AXP.readBatteryOutCharge(); int16_t Current = InpCurr-OutCurr; Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); int32_t Charge = InpCharge-OutCharge; Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); #endif httpd_resp_sendstr_chunk(Req, "
Voltage"); #ifdef WITH_MAVLINK Len+=Format_UnsDec(Line+Len, MAVLINK_BattVolt, 4, 3); #else Len+=Format_UnsDec(Line+Len, BatteryVoltage>>8, 4, 3); // print the battery voltage readout #endif Len+=Format_String(Line+Len, " V
Capacity"); #ifdef WITH_MAVLINK uint8_t Cap=MAVLINK_BattCap; // [%] from the drone's telemetry #else uint8_t Cap=BattCapacity(BatteryVoltage>>8); // [%] est. battery capacity based on the voltage readout #endif Len+=Format_UnsDec(Line+Len, (uint16_t)Cap); Len+=Format_String(Line+Len, " %
State"); Len+=Format_String(Line+Len, StateName[State]); Len+=Format_String(Line+Len, "
Current"); Len+=Format_SignDec(Line+Len, Current, 3); Len+=Format_String(Line+Len, " mA
Charge"); Len+=Format_SignDec(Line+Len, (((int64_t)Charge<<12)+562)/1125, 2, 1); Len+=Format_String(Line+Len, " mAh
USB volt."); Len+=Format_UnsDec(Line+Len, Vbus, 4, 3); Len+=Format_String(Line+Len, " V
USB curr."); Len+=Format_UnsDec(Line+Len, VbusCurr, 4, 3); Len+=Format_String(Line+Len, " A
\n"); } // ------------------------------------------------------------------------------------------------------------- #ifdef WITH_SPIFFS static void Table_SPIFFS(httpd_req_t *Req) { char Line[128]; int Len; httpd_resp_sendstr_chunk(Req, "

SPIFFS

"); httpd_resp_sendstr_chunk(Req, "\n"); size_t Total, Used; if(SPIFFS_Info(Total, Used)==0) // get the SPIFFS usage summary { Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); Len =Format_String(Line, "\n"); httpd_resp_send_chunk(Req, Line, Len); } httpd_resp_sendstr_chunk(Req, "
Free"); Len+=Format_UnsDec(Line+Len, (Total-Used)/1024); Len+=Format_String(Line+Len, " kB
Used"); Len+=Format_UnsDec(Line+Len, Used/1024); Len+=Format_String(Line+Len, " kB
Total"); Len+=Format_UnsDec(Line+Len, Total/1024); Len+=Format_String(Line+Len, " kB
\n"); } #endif // ------------------------------------------------------------------------------------------------------------- static void Html_Start(httpd_req_t *Req, const char *Title, const uint8_t ActiveMenuIndex) { httpd_resp_sendstr_chunk(Req, "\ \n\ \n\ \n\ "); httpd_resp_sendstr_chunk(Req, Title); httpd_resp_sendstr_chunk(Req, "\n\ \n\ \n\ \ \n\ \n\ "); httpd_resp_sendstr_chunk(Req, "

OGN-Tracker

\n"); httpd_resp_sendstr_chunk(Req, "
\n"); httpd_resp_sendstr_chunk(Req, "\n"); httpd_resp_sendstr_chunk(Req, "\n"); httpd_resp_sendstr_chunk(Req, "\n"); httpd_resp_sendstr_chunk(Req, "
\n"); httpd_resp_sendstr_chunk(Req, "
\n"); } static void Html_End(httpd_req_t *Req) { httpd_resp_sendstr_chunk(Req, "
\n\n\n"); httpd_resp_send_chunk(Req, 0, 0); } // ============================================================================================================ static esp_err_t parm_post_handler(httpd_req_t *Req) { bool Restart=0; bool Defaults=0; /* Destination buffer for content of HTTP POST request. * httpd_req_recv() accepts char* only, but content could * as well be any binary data (needs type casting). * In case of string data, null termination will be absent, and * content length would give length of string */ char content[1024]; char *URL = (char *)malloc(Req->content_len+1); /* Truncate if content length larger than the buffer */ size_t recv_size = std::min(Req->content_len, sizeof(content)); int ret = httpd_req_recv(Req, URL, recv_size); if (ret <= 0) { /* 0 return value indicates connection closed */ /* Check if timeout occurred */ if (ret == HTTPD_SOCK_ERR_TIMEOUT) { /* In case of timeout one can choose to retry calling * httpd_req_recv(), but to keep it simple, here we * respond with an HTTP 408 (Request Timeout) error */ httpd_resp_send_408(Req); } /* In case of error, returning ESP_FAIL will * ensure that the underlying socket is closed */ return ESP_FAIL; } #ifdef DEBUG_PRINT xSemaphoreTake(CONS_Mutex, portMAX_DELAY); Format_String(CONS_UART_Write, "parm_post_handler() => ["); Format_UnsDec(CONS_UART_Write, Req->content_len, 1); Format_String(CONS_UART_Write, "] "); Format_String(CONS_UART_Write, URL); Format_String(CONS_UART_Write, "\n"); xSemaphoreGive(CONS_Mutex); #endif char *Line=URL; Restart = strstr(Line,"Restart=1"); Defaults = strstr(Line,"Defaults=1"); for( ; ; ) { Parameters.ReadLine(Line); Line = strchr(Line, '&'); if(Line==0) break; Line++; } free(URL); Parameters.WriteToNVS(); if(Defaults) { Parameters.setDefault(); } if(Restart) { #ifdef WITH_SPIFFS FlashLog_SaveReq=1; #endif vTaskDelay(1000); esp_restart(); } // redirect to get handler httpd_resp_set_type(Req, "text/html"); httpd_resp_set_status(Req, "302 Found"); httpd_resp_set_hdr(Req, "Location", "/parm.html"); httpd_resp_send(Req, NULL, 0); return ESP_OK; } static esp_err_t parm_get_handler(httpd_req_t *Req) { Html_Start(Req, "OGN-Tracker configuration", 2); ParmForm_Acft(Req); ParmForm_Info(Req); ParmForm_GPS(Req); #ifdef WITH_AP ParmForm_AP(Req); #endif #ifdef WITH_STRATUX ParmForm_Stratux(Req); #endif ParmForm_Page(Req); ParmForm_Other(Req); ParmForm_Defaults(Req); ParmForm_Restart(Req); Html_End(Req); return ESP_OK; } static esp_err_t top_get_handler(httpd_req_t *Req) { Html_Start(Req, "OGN-Tracker status", 1); char Line[32]; int Len; httpd_resp_sendstr_chunk(Req, "EUID: "); Len=Format_Hex(Line, getUniqueID()); httpd_resp_send_chunk(Req, Line, Len); httpd_resp_sendstr_chunk(Req, "
\n"); Table_System(Req); Table_GPS(Req); Table_RF(Req); Table_Batt(Req); #ifdef WITH_SPIFFS Table_SPIFFS(Req); #endif #ifdef WITH_LOOKOUT Table_LookOut(Req); #endif Table_Relay(Req); Html_End(Req); return ESP_OK; } static int Format_DateTime(char *Out, time_t Time) { struct tm *TM = gmtime(&Time); int Len=Format_UnsDec(Out, (uint16_t)1900+TM->tm_year, 4); Out[Len++]='.'; Len+=Format_UnsDec(Out+Len, (uint16_t)1+TM->tm_mon, 2); Out[Len++]='.'; Len+=Format_UnsDec(Out+Len, (uint16_t)TM->tm_mday, 2); Out[Len++]=' '; Len+=Format_UnsDec(Out+Len, (uint16_t)TM->tm_hour, 2); Out[Len++]=':'; Len+=Format_UnsDec(Out+Len, (uint16_t)TM->tm_min, 2); Out[Len++]=':'; Len+=Format_UnsDec(Out+Len, (uint16_t)TM->tm_sec, 2); return Len; } static int LogFileName(char *Name, time_t Time, const char *Ext=0) { int Len=Parameters.getAprsCall(Name); Name[Len++]='_'; struct tm *TM = gmtime(&Time); Len+=Format_UnsDec(Name+Len, (uint16_t)1900+TM->tm_year, 4); Name[Len++]='.'; Len+=Format_UnsDec(Name+Len, (uint16_t)1+TM->tm_mon, 2); Name[Len++]='.'; Len+=Format_UnsDec(Name+Len, (uint16_t)TM->tm_mday, 2); Name[Len++]='_'; Len+=Format_UnsDec(Name+Len, (uint16_t)TM->tm_hour, 2); Len+=Format_UnsDec(Name+Len, (uint16_t)TM->tm_min, 2); Len+=Format_UnsDec(Name+Len, (uint16_t)TM->tm_sec, 2); if(Ext) Len+=Format_String(Name+Len, Ext); Name[Len]=0; return Len; } // send give log file in the IGC format static esp_err_t SendLog_IGC(httpd_req_t *Req, const char *FileName, uint32_t FileTime) { char ContDisp[64]; mbedtls_md5_context MD5; mbedtls_md5_starts_ret(&MD5); char Line[1000]; int Len=0; Len=Format_String(ContDisp, "attachement; filename=\""); Len+=LogFileName(ContDisp+Len, FileTime, ".IGC"); ContDisp[Len++]='\"'; ContDisp[Len]=0; httpd_resp_set_hdr(Req, "Content-Disposition", ContDisp); httpd_resp_set_type(Req, "text/plain"); FILE *File = fopen(FileName, "rb"); if(File==0) { httpd_resp_send_chunk(Req, 0, 0); return ESP_OK; } Len=Format_String(Line, "AXXX ESP32-OGN-TRACKER\nHFFXA020\n"); // IGC file header Len+=Format_String(Line+Len, "HFDTE"); GPS_Time Time; Time.setUnixTime(FileTime); Len+=Format_UnsDec(Line+Len, (uint16_t)Time.Day , 2); Len+=Format_UnsDec(Line+Len, (uint16_t)Time.Month, 2); Len+=Format_UnsDec(Line+Len, (uint16_t)Time.Year , 2); Line[Len++]='\n'; if(Parameters.Pilot[0]) { Len+=Format_String(Line+Len, "HFPLTPILOTINCHARGE:"); Len+=Format_String(Line+Len, Parameters.Pilot); Line[Len++]='\n'; } if(Parameters.Manuf[0]) { Len+=Format_String(Line+Len, "HFGTYGLIDERTYPE:"); Len+=Format_String(Line+Len, Parameters.Manuf); if(Parameters.Model[0]) { Len+=Format_String(Line+Len, " "); Len+=Format_String(Line+Len, Parameters.Model); } Line[Len++]='\n'; } if(Parameters.Reg[0]) { Len+=Format_String(Line+Len, "HFGIDGLIDERID:"); Len+=Format_String(Line+Len, Parameters.Reg); Line[Len++]='\n'; } #ifdef WITH_FollowMe Len+=Format_String(Line+Len, "HFRHWHARDWAREVERSION:FollowMe\n"); #else Len+=Format_String(Line+Len, "HFRHWHARDWAREVERSION:ESP32+LoRa\n"); // hardware version #endif Len+=Format_String(Line+Len, "HFRFWFIRMWAREVERSION:ESP32-OGN-TRACKER " __DATE__ " " __TIME__ "\n"); #ifdef WITH_BMP180 Len+=Format_String(Line+Len, "HFPRSPRESSALTSENSOR:BMP180\n"); // pressure sensor #endif #ifdef WITH_BMP280 Len+=Format_String(Line+Len, "HFPRSPRESSALTSENSOR:BMP280\n"); // pressure sensor #endif #ifdef WITH_BME280 Len+=Format_String(Line+Len, "HFPRSPRESSALTSENSOR:BME280/BMP280\n"); // pressure sensor #endif Len+=Format_String(Line+Len, "LOGN"); Len+=Format_HHMMSS(Line+Len, FileTime); Len+=Format_String(Line+Len, "ID "); Len+=Format_Hex(Line+Len, Parameters.AcftID); Line[Len++]='\n'; uint64_t MAC = getUniqueID(); Len+=Format_String(Line+Len, "LOGN"); Len+=Format_HHMMSS(Line+Len, FileTime); Len+=Format_String(Line+Len, "MAC "); Len+=Format_Hex(Line+Len, (uint16_t)(MAC>>32)); // ESP32 48-bit ID Len+=Format_Hex(Line+Len, (uint32_t) MAC ); Line[Len++]='\n'; httpd_resp_send_chunk(Req, Line, Len); mbedtls_md5_update_ret(&MD5, (uint8_t *)Line, Len); OGN_LogPacket Packet; Len=0; for( ; ; ) { if(fread(&Packet, Packet.Bytes, 1, File)!=1) break; // read the next packet if(!Packet.isCorrect()) continue; uint32_t Time = Packet.getTime(FileTime); // [sec] get exact time from short time in the packet and the file start time Len+=Format_String(Line+Len, "LGNE "); // attach APRS as LGNE record char *APRS=Line+Len; Len+=Packet.Packet.WriteAPRS(Line+Len, Time); // packet in the APRS format Line[Len++]='\n'; Line[Len]=0; bool Own = Packet.Packet.Header.Address==Parameters.Address && Packet.Packet.Header.AddrType==Parameters.AddrType; // if(Own && !Packet.Packet.Header.NonPos && !Packet.Packet.Header.Encrypted) Len+=APRS2IGC(Line+Len, APRS, GPS_GeoidSepar); // IGC B-record if(Len>=800) // when more than 800 bytes then write this part to the socket { httpd_resp_send_chunk(Req, Line, Len); mbedtls_md5_update_ret(&MD5, (uint8_t *)Line, Len); Len=0; vTaskDelay(1); } } fclose(File); if(Len) { httpd_resp_send_chunk(Req, Line, Len); mbedtls_md5_update_ret(&MD5, (uint8_t *)Line, Len); Len=0; } uint8_t Digest[16]; mbedtls_md5_finish_ret(&MD5, Digest); Len=0; Line[Len++]='G'; // G-record, not signed yet, just MD5 for(int Idx=0; Idx<16; Idx++) Len+=Format_Hex(Line+Len, Digest[Idx]); Line[Len++]='\n'; Line[Len]=0; httpd_resp_send_chunk(Req, Line, Len); httpd_resp_send_chunk(Req, 0, 0); return ESP_OK; } // send give log file in the APRS format static esp_err_t SendLog_APRS(httpd_req_t *Req, const char *FileName, uint32_t FileTime) { char ContDisp[64]; char Line[1000]; int Len=0; Len=Format_String(ContDisp, "attachement; filename=\""); Len+=LogFileName(ContDisp+Len, FileTime, ".aprs"); ContDisp[Len++]='\"'; ContDisp[Len]=0; httpd_resp_set_hdr(Req, "Content-Disposition", ContDisp); httpd_resp_set_type(Req, "text/plain"); FILE *File = fopen(FileName, "rb"); if(File==0) { httpd_resp_send_chunk(Req, 0, 0); return ESP_OK; } OGN_LogPacket Packet; Len=0; for( ; ; ) { if(fread(&Packet, Packet.Bytes, 1, File)!=1) break; // read the next packet if(!Packet.isCorrect()) continue; uint32_t Time = Packet.getTime(FileTime); // [sec] get exact time from short time in the packet and the file start time Len+=Packet.Packet.WriteAPRS(Line+Len, Time); // print the packet in the APRS format Line[Len++]='\n'; Line[Len]=0; if(Len>850) { httpd_resp_send_chunk(Req, Line, Len); Len=0; } vTaskDelay(1); } fclose(File); if(Len) { httpd_resp_send_chunk(Req, Line, Len); Len=0; } httpd_resp_send_chunk(Req, 0, 0); return ESP_OK; } // send given log file in the TLG (binary) format static esp_err_t SendLog_TLG(httpd_req_t *Req, const char *FileName, uint32_t FileTime) { char ContDisp[64]; char Line[512]; int Len; Len=Format_String(ContDisp, "attachement; filename=\""); Len+=Parameters.getAprsCall(ContDisp+Len); ContDisp[Len++]='_'; Len+=Format_Hex(ContDisp+Len, FileTime); Len+=Format_String(ContDisp+Len, ".TLG"); ContDisp[Len++]='\"'; ContDisp[Len]=0; httpd_resp_set_hdr(Req, "Content-Disposition", ContDisp); httpd_resp_set_type(Req, "application/octet-stream"); FILE *File = fopen(FileName, "rb"); if(File==0) { httpd_resp_send_chunk(Req, 0, 0); return ESP_OK; } for( ; ; ) { Len=fread(Line, 1, 512, File); if(Len<=0) break; httpd_resp_send_chunk(Req, Line, Len); vTaskDelay(1); } fclose(File); httpd_resp_send_chunk(Req, 0, 0); return ESP_OK; } // handle the HTTP request for the log files page static esp_err_t log_get_handler(httpd_req_t *Req) { char FullName[32]; char Line[256]; struct stat Stat; const char *Path= "/spiffs"; uint16_t URLlen=httpd_req_get_url_query_len(Req); if(URLlen) { char *URL = (char *)malloc(URLlen+1); httpd_req_get_url_query_str(Req, URL, URLlen+1); char Name[16]; bool SendFile = httpd_query_key_value(URL, "File", Name, 16)==ESP_OK; char Format[8] = { 0 }; httpd_query_key_value(URL, "Format", Format, 8); free(URL); if(SendFile) { AddPath(FullName, Name, Path); uint32_t Time=FlashLog_ReadShortFileTime(Name); if(Time) { if(strcmp(Format, "APRS")==0) return SendLog_APRS(Req, FullName, Time); if(strcmp(Format, "IGC" )==0) return SendLog_IGC(Req, FullName, Time); return SendLog_TLG(Req, FullName, Time); } } } Html_Start(Req, "OGN-Tracker log files", 3); std::vector FileList; // list of log files DIR *Dir=opendir(Path); // open the log file directory if(Dir==0) { httpd_resp_sendstr_chunk(Req, "

Cannot open the log directory !

\n"); httpd_resp_send_chunk(Req, 0, 0); return ESP_OK; } for( ; ; ) { struct dirent *Ent = readdir(Dir); if(!Ent) break; // read next directory entry, break if all read if(Ent->d_type != DT_REG) continue; // skip non-regular files char *Name = Ent->d_name; uint32_t Time=FlashLog_ReadShortFileTime(Name); // read time from the file name if(Time==0) continue; // skip if not .TLG format FileList.push_back(Time); } closedir(Dir); std::sort(FileList.begin(), FileList.end()); httpd_resp_sendstr_chunk(Req, "\n\n\n"); for(size_t Idx=0; Idx=0) // get file info Size = Stat.st_size; int Len=Format_String(Line, ""); Len+=Format_String(Line+Len, "\n"); httpd_resp_send_chunk(Req, Line, Len); vTaskDelay(1); } httpd_resp_sendstr_chunk(Req, "
File[KB]Date
"); Len+=Format_String(Line+Len, Name); Len+=Format_String(Line+Len, "APRSIGC"); Len+=Format_UnsDec(Line+Len, (Size+512)>>10); Len+=Format_String(Line+Len, ""); Len+=Format_DateTime(Line+Len, Time); Len+=Format_String(Line+Len, "
\n"); Html_End(Req); return ESP_OK; } static esp_err_t logo_get_handler(httpd_req_t *Req) { extern const uint8_t OGN_logo_jpg[] asm("_binary_OGN_logo_240x240_jpg_start"); extern const uint8_t OGN_logo_end[] asm("_binary_OGN_logo_240x240_jpg_end"); const int OGN_logo_size = OGN_logo_end-OGN_logo_jpg; httpd_resp_set_type(Req, "image/jpeg"); httpd_resp_send(Req, (const char *)OGN_logo_jpg, OGN_logo_size); return ESP_OK; } static const httpd_uri_t HTTPtop = { .uri = "/", .method = HTTP_GET, .handler = top_get_handler, .user_ctx = 0 }; static const httpd_uri_t HTTPlogo = { .uri = "/logo.jpeg", .method = HTTP_GET, .handler = logo_get_handler, .user_ctx = 0 }; static const httpd_uri_t HTTPparm = { .uri = "/parm.html", .method = HTTP_GET, .handler = parm_get_handler, .user_ctx = 0 }; static const httpd_uri_t HTTPparmPost = { .uri = "/parm.html", .method = HTTP_POST, .handler = parm_post_handler, .user_ctx = 0 }; static const httpd_uri_t HTTPlog = { .uri = "/log.html", .method = HTTP_GET, .handler = log_get_handler, .user_ctx = 0 }; static httpd_handle_t HTTPserver = 0; esp_err_t HTTP_Start(int MaxSockets, int Port) { httpd_config_t Config = HTTPD_DEFAULT_CONFIG(); Config.server_port = Port; Config.task_priority = tskIDLE_PRIORITY+3; Config.max_open_sockets = MaxSockets; esp_err_t Err=httpd_start(&HTTPserver, &Config); if(Err!=ESP_OK) return Err; httpd_register_uri_handler(HTTPserver, &HTTPtop); // top URL httpd_register_uri_handler(HTTPserver, &HTTPparm); // parameters URL httpd_register_uri_handler(HTTPserver, &HTTPparmPost); // parameters URL httpd_register_uri_handler(HTTPserver, &HTTPlog); // log files URL httpd_register_uri_handler(HTTPserver, &HTTPlogo); // OGN logo return Err; } void HTTP_Stop(void) { if(HTTPserver) httpd_stop(HTTPserver); HTTPserver=0; } // ============================================================================================================ #endif // WITH_HTTP