/*
Copyright 2021, 2022 V.R. Little & Rob Prior
Contributors : 2023 e.vlad.engineer
**** Supports both huVVer-AVI (with installed huVVerLink & GaugeWidgets libraries),
and M5Stack (with installed M5Stack & GaugeWidgets libraries) ***
Permission is hereby granted, free of charge, to any person provided a copy of this software and associated documentation files
(the "Software") to use, copy, modify, or merge copies of the Software for non-commercial purposes, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// =============================================================//
#define Version 7.3 // This will be displayed on unit //
// =============================================================//
// =============================================================//
// Specification of hardware is in the //
// Library folder "DeviceDefines.h" file //
// Within the file, specify either of the following: //
// #define DEVICE_HUVVER //
// #define DEVICE_M5 //
// =============================================================//
// =============================================================//
// For software development, set DEBUG = 1 to //
// allow debugging messages. //
// Otherwise, set DEBUG = 0 for proper in-service operation. //
// =============================================================//
// const bool DEBUG = false;
const bool DEBUG = true;
// =============================================================//
// =============================================================//
// For software development, set DRAWTIME = 1 to //
// allow for displaying instrument drawing time on USB Serial. //
// Otherwise, set DRAWTIME = 0 for proper in-service operation. //
// =============================================================//
const bool DRAWTIME = false;
// const bool DRAWTIME = true;
// =============================================================//
// =============================================================//
// Network information (defined using the WiFi Manager): //
// Use any valid Network name and Password up to 20 chars each. //
// This can be your Dynon SkyView login, //
// Or your own private network if you are are not using SkyView //
// and want to have one instrument configured as a Transmitter, //
// and one or more configured as Receivers. //
// =============================================================//
char ssid [21];
char pw [21];
const uint16_t port = 49155;
char OTAssid[21];
char OTApassword[21];
#include <EncButton.h>
// buttons pins
// Подтяжка может быть внешней (режим пина нужно поставить INPUT) или внутренней (режим пина INPUT_PULLUP).
// init(npin, mode, dbTime);
// при нажатии 0(LOW)
// Button btn_left(39, INPUT, 150, true);// внешняя подтяжка
Button btn_left(34, INPUT);// внешняя подтяжка
// при нажатии 1(HIGH)
// Button btn_right(36, INPUT, 150, false);// внешняя подтяжка
Button btn_right(35, INPUT);// внешняя подтяжка
#include <ezButton.h>
ezButton button1(34); // create ezButton object that attach to pin 34;
ezButton button2(35); // create ezButton object that attach to pin 35;
// =============================================================//
#include "Options.h"
#include "Free_Fonts.h"
#include <WiFi.h>
#include <Preferences.h>
#include <nvs_flash.h>
#include "bableFish.h"
#include "Menus.h"
//#include "GaugeWidgets_Button.h"
#include "flightGauges.h"
// #include "logo.h"
#include <WiFiClient.h>
//#include <ESP32SJA1000.h> // https://github.com/sandeepmistry/arduino-CAN (new for version 6.3+)
//#include <AsyncTCP.h> // https://github.com/me-no-dev/AsyncTCP
//#include <ESPAsyncWebServer.h> // https://github.com/me-no-dev/ESPAsyncWebServer
//#include <AsyncElegantOTA.h> // https://github.com/ayushsharma82/AsyncElegantOTA
#define WIFIPOWER WIFI_POWER_MINUS_1dBm
//
//CAN
//
// const long CAN_Bitrate = 250000;
const long CAN_Bitrate = 125000;
const boolean CAN_Loopback = false;
String CANRxBuffer = "";
const long UART_Bitrate = 115200;
const uint16_t SCREEN_X = 320; // Screen sizes are set here.
const uint16_t SCREEN_Y = 240;
TFT_eSprite gdraw = TFT_eSprite(&VVLcd);
TFT_eSprite gdrawMenu = TFT_eSprite(&VVLcd);
Preferences preferences;
Menus myMenus;
Gauges myGauges;
EFISdata myEFISdata;
Flight myFlight;
WiFiUDP udp;
extern const uint8_t MENU_DEFAULT;
extern const uint8_t MENU_LIST;
extern const uint8_t MENU_ACTION;
extern const uint8_t MENU_SETUP;
const uint32_t BITRATE = 115200;
// #include <EncButton.h>
//
// WiFi data. Depending on mode configuration, some of this may not be used.
//
IPAddress ip(192, 168, 4, 1); // Connect to this IP
IPAddress broadcastIp (192, 168, 4, 255);
IPAddress netmask(255, 255, 255, 0);
char chipID[23];
// unsigned long sendTime; // Переменная для хранения времени отправки
// bool sendDataCompleted; // Флаг, указывающий, что отправка завершена
// bool alignmentCompleted; // Флаг, указывающий, что выравнивание завершено
bool buttonPressed = false; // Флаг, указывающий, что кнопка была нажата
bool sendDataDone = false; // Флаг, указывающий, что sendData выполнено
unsigned long startTime = 0; // Время начала отсчета
const uint16_t LOOPTIME = 62; // milliseconds.
const uint16_t FRAMES = 2000 / LOOPTIME; // number of frames before link failure detected
const uint16_t FLASHCOUNT = 2; // number of frames for alarm flashing rate.
const uint8_t WIFIOFF = 0; // AKA Serial mode
const uint8_t WIFIRX = 1;
const uint8_t WIFITX = 2;
const uint8_t WIFIOFFDEMO = 3; // AKA Serial Demo mode
const uint8_t WIFIRXDEMO = 4;
const uint8_t WIFITXDEMO = 5;
const uint8_t DIMMER_CH = 4; // Dimmer PWM channel
const uint64_t DIMMER_FREQ = 8192; // Dimmer PWM frequency
const uint8_t DIMMER_RES = 12; // Dimmer PWM resolution
const uint8_t SYSTEMPAGE = 0;
const uint8_t READMEPAGE = 16; // Index number
const bool RS232 = false; // with RS232 transceiver
const bool TTL = true; // no RS232 transceiver
const uint16_t RXBUFFER = 8192; // serial receive FIFO size
const uint16_t TXBUFFER = 8192; // serial receive FIFO size
//
// ADARHS variables
//
int16_t Pitch;
int16_t Roll;
int16_t Heading; // Not supported by OnSpeed
int16_t AirSpeed;
int32_t PressAlt;
int32_t Altitude; // only D10A uses Altitude directly
int16_t TurnRate;
int16_t LatAccel;
int16_t VertAccel = 10;
int16_t AOA;
int16_t VertSpeed;
int16_t OAT;
int16_t TASpeed; // Not supported by Garmin or OnSpeed
int16_t Baro = 242; // Not supported by OnSpeed
int32_t DensAlt; // Not supported by Garmin or OnSpeed
int16_t WindDir = -1; // Not supported by Garmin or OnSpeed
int16_t WindSpeed = -1; // Not supported by Garmin or OnSpeed
//
// Derived variables, computed herein
//
int16_t GroundTrack = -1000;
int16_t GroundSpeed = -1;
int16_t DriftAngle = -1000;
//
// OnSpeed additional IMU constants and variables
//
int16_t OnSpeedAOA;
int16_t FlightPath = -1000;
int16_t FlapPos;
int16_t OSStallWarnAOA = 20;
int16_t OSSlowAOA = 15;
int16_t OSFastAOA = 10;
int16_t OSTonesOnAOA = 5;
int16_t gOnsetRate = 0;
int16_t SpinRecoveryCue = 0;
int16_t DataMark = 0;
//
// The following are used for the OnSpeed Energy Display
//
int16_t PercentLift; // Actually displayed AOA numbers
const float aoaSmoothingAlpha = 0.7f; //1 = max smoothing, 0.01 no smoothing.
const float slipSmoothingAlpha = 0.5f; //1 = max smoothing, 0.01 no smoothing.
const float decelSmoothingAlpha = 0.04f; //1 = max smoothing, 0.01 no smoothing.
const float serialRate = 0.1f; // 10 hz;
int16_t Slip;
uint16_t ballSize = 34; //for Slip Filter
float SmoothedLateralG;
float SmoothedAOA = 0.00;
float DecelRate;
float SmoothedDecelRate = 0.0;
float gHistory[300];
int16_t gHistoryIndex = 0;
//
// System variables (Dynon Only)
//
int16_t HdgBug = -1;
int16_t AltBug = -10000;
int16_t ASBug = -1;
int16_t VSBug = -1000;
int16_t Course = -1;
uint8_t CDSTyp;
uint8_t CDSPor;
uint8_t CDScal;
int16_t CDDefl = -100;
int16_t GlideS = -100;
uint8_t APEngd;
uint8_t APRMod;
uint8_t APPMod;
int16_t APRFor;
int16_t APRPos = -10000;
uint8_t APRSlp;
int16_t APPFor;
int16_t APPPos = -10000;
uint8_t APPSlp;
int16_t APYFor;
int16_t APYPos = -10000;
uint8_t APYSlp;
uint8_t XPStat;
uint8_t XPRep;
uint8_t XPID;
uint16_t XPCode = 00000;
//
// Engine variables
//
int16_t OilP; // -100 invalid
int16_t OilT; // -1000 invalid
int16_t RpmL;
int16_t RpmR;
int16_t Map; // -100 invalid
int16_t FuelF1; // -100 invalid
int16_t FuelF2; // -100 invalid
int16_t FuelP; // -100 invalid
int16_t FuelL; // -100 invalid
int16_t FuelR; // -100 invalid
int16_t FuelRem; // -100 invalid
int16_t Volts1; // -100 invalid
int16_t Volts2; // -100 invalid
int16_t Amps; // -1000 invalid
uint32_t HobbsT;
uint32_t TachT;
int16_t TCpl[14]; // -1000 invalid
int16_t GpIn[13]; // -10000invalid
int8_t CtctIn[16]; // -1 invalid
int16_t PercentPwr; // -100 invalid
char LeanState;
//
// Top level operating states
//
int32_t SerialPort; // change from System Configuration menu or by holding down Menu button for 4 seconds.
uint16_t operationMode; // current operating mode. Combinations of serial, wifi and demo modes.
bool updateMode; // pending OTA update mode
bool managerMode; // pending WiFi manager mode
uint16_t Brightness; // screen brightness
uint64_t loopTime = millis(); // main programe loop timing variables
uint64_t currentMillis = millis();
uint64_t previousMillis = millis();
int16_t displayMode = 0; // instrument page select
int8_t displayDirection = 1; // for navigating active instruments
uint16_t flashCount = 0;
bool flashFlag; // allows flashing of graphics or numerics at the rate set by LOOPTIME
int16_t frameCount = FRAMES; // number of sequential frames missing before display is disabled
bool dimDirection = true; // allows for increment or decrement of screen brightness.
int16_t toggle = 0;
IPAddress OTAip(192, 168, 4, 1); // Connect to this IP
IPAddress OTAbroadcastIp (192, 168, 4, 255);
IPAddress OTAnetmask(255, 255, 255, 0);
//AsyncWebServer server(80);
void setup()
{
// т.к правая кнопка подтянута к 3.3 вольт
//btn_left.setButtonLevel(HIGH);
//btn_right.setButtonLevel(HIGH);
//pinMode(34, INPUT);
//pinMode(35, INPUT);
btn_right.setButtonLevel(HIGH);
// click timeout (button)
// можно отрегулировать быстроту обработки клика
btn_left.setClickTimeout(1000);
btn_right.setClickTimeout(1000);
// таймаут удержания (кнопка)
btn_left.setHoldTimeout(500);
btn_right.setHoldTimeout(500);
// таймаут гашения дребезга кнопки (кнопка)
// btn_left.setDebTimeout(20);
// btn_right.setDebTimeout(20);
//
//digitalWrite (TFT_BL, LOW);
// digitalWrite (TFT_LED_PIN, LOW);
//pinMode (TFT_BL, OUTPUT);
// pinMode (TFT_LED_PIN, OUTPUT);
pinMode(INT_PIN, OUTPUT);
digitalWrite(INT_PIN, LOW);
VVbegin();
//
// Force display off and initialize
//
// Init the back-light LED PWM
// myFlight.BacklightInit(TFT_LED_PIN, DIMMER_CH, DIMMER_FREQ, DIMMER_RES);
//myFlight.BacklightInit(TFT_BL, DIMMER_CH, DIMMER_FREQ, DIMMER_RES);
//myFlight.Backlight(0);
//
// Display splash screen
//
VVLcd.setSwapBytes(true);
VVLcd.fillScreen(TFT_BLACK);
myFlight.Backlight(0);
preferences.begin ("huVVer-app");
Brightness = preferences.getUInt ("Brightness", 1023);
preferences.end ();
// VVLcd.pushImage(0, 0, logoWidth, logoHeight, Logo);
// Вывод надписи "flight gauges" на спрайт
// gdraw.setColorDepth(8);
// gdraw.createSprite(SCREEN_X, SCREEN_Y);
// gdraw.fillScreen (TFT_BLACK);
VVLcd.setTextColor(TFT_WHITE);
VVLcd.setTextDatum(MC_DATUM);
VVLcd.setCursor(10, 60);
VVLcd.setTextSize(3);
VVLcd.println("Flight gauges");
VVLcd.setCursor(20, 150);
VVLcd.setTextSize(3);
VVLcd.println("for AVIATION");
// gdraw.pushSprite(0, 0); // Отображение спрайта на дисплее
for (float i = 1.0f; i <= Brightness; i += (float)Brightness / 200.0f)
{
myFlight.Backlight(i);
delay (3);
}
delay (150);
for (float i = 1.0f; i <= Brightness; i += (float)Brightness / 200.0f)
{
myFlight.Backlight(Brightness - i);
delay (3);
}
delay (250);
WiFi.persistent (false); // very important... we are using program constants!
gdraw.setColorDepth(8);
gdraw.createSprite(SCREEN_X, SCREEN_Y);
gdraw.fillSprite (TFT_BLACK);
gdraw.pushSprite (0, 0);
// gdrawMenu.setColorDepth(8);
// gdrawMenu.createSprite(SCREEN_X, SCREEN_Y);
// gdrawMenu.fillSprite (TFT_BLACK);
// gdrawMenu.setTextColor(TFT_WHITE);
// gdrawMenu.setTextDatum(MC_DATUM);
// gdrawMenu.setCursor(160 - 30, 120 - 30);
// gdrawMenu.setTextSize(4);
//
// Preset outputs
//
// digitalWrite (PIN_AUDL, LOW); digitalWrite (PIN_AUDR, LOW);
// pinMode (PIN_AUDL, OUTPUT); pinMode (PIN_AUDR, OUTPUT);
// digitalWrite (PIN_OC1, LOW); digitalWrite (PIN_OC2, LOW);
// pinMode (PIN_OC1, OUTPUT); pinMode (PIN_OC2, OUTPUT);
//
// Get Active Serial Port - при старте устройства, идет загрузка из преференсов
//
preferences.begin ("getSetup", false);
SerialPort = preferences.getInt (SERIALPORT, 2);
preferences.end();
Serial2.setRxBufferSize (RXBUFFER);
switch (SerialPort)
{
case 1: // On the M5Stack, this takes over the I2C port.
Serial1.setRxBufferSize (RXBUFFER);
Serial1.setTxBufferSize (TXBUFFER);
Serial1.begin (BITRATE, SERIAL_8N1, PIN_RX1, PIN_TX1, RS232);
break;
case 2:
Serial2.setRxBufferSize (RXBUFFER);
Serial2.setTxBufferSize (TXBUFFER);
Serial2.begin (BITRATE, SERIAL_8N1, PIN_RX2, PIN_TX2, RS232);
break;
case -1: // On the M5Stack, this takes over the I2C port.
Serial1.setRxBufferSize (RXBUFFER);
Serial1.setTxBufferSize (TXBUFFER);
Serial1.begin (BITRATE, SERIAL_8N1, PIN_RX1, PIN_TX1, TTL);
break;
case -2:
Serial2.setRxBufferSize (RXBUFFER);
Serial2.setTxBufferSize (TXBUFFER);
Serial2.begin (BITRATE, SERIAL_8N1, PIN_RX2, PIN_TX2, TTL);
break;
default:
break;
}
//
// Power-on mode configuration.
//
myFlight.LoadEnables(); // load all of the system settings
// myMenus.loadPrefs = true;
preferences.begin ("huVVer-app", false);
// Get the value of the counter key saved on preferences.
// If it doesn’t find any value, it returns 0 by default
// (which happens when this code runs for the first time).
Magnet = preferences.getUInt("Magnet", 1);
FilterNum = preferences.getUInt("FilterNum", 0);
OffsetPitch = preferences.getUInt("OffsetPitch", 5);
myEFISdata.sendData(false, Magnet, FilterNum, thousands, hundreds, tens, units, OffsetPitch);
// Magnet = myMenus.LoadPrefs("getAI", "Magnet");
operationMode = 1;
if (myFlight.WiFiRX == 1 && myFlight.WiFiTX == 0 && myFlight.demoMode == 0)
{
operationMode = WIFIRX;
}
if (myFlight.WiFiRX == 0 && myFlight.WiFiTX == 1 && myFlight.demoMode == 0)
{
operationMode = WIFITX;
}
if (myFlight.WiFiRX == 0 && myFlight.WiFiTX == 0 && myFlight.demoMode == 0)
{
operationMode = WIFIOFF; // Serial mode
}
if (myFlight.WiFiRX == 1 && myFlight.WiFiTX == 1 && myFlight.demoMode == 0)
{
operationMode = WIFIOFF; // Serial mode
}
if (myFlight.WiFiRX == 1 && myFlight.WiFiTX == 0 && myFlight.demoMode == 1)
{
operationMode = WIFIRXDEMO;
}
if (myFlight.WiFiRX == 0 && myFlight.WiFiTX == 1 && myFlight.demoMode == 1)
{
operationMode = WIFITXDEMO;
}
if (myFlight.WiFiRX == 0 && myFlight.WiFiTX == 0 && myFlight.demoMode == 1)
{
operationMode = WIFIOFFDEMO; // Serial Demod mode
}
if (myFlight.WiFiRX == 1 && myFlight.WiFiTX == 1 && myFlight.demoMode == 1)
{
operationMode = WIFIOFFDEMO; // Serial Demo mode
}
preferences.putUInt("operationMode", operationMode);
preferences.end(); // huVVer-app
//Buttons A ([]) and B [O] held down at bootup forces a System Restore
//Нажав и удерживая одновременно две кнопки и перезагрузив, получим сброс настроек до заводских
if (btn_left.hold() && btn_right.hold())
// while (btn_left.busy() && btn_right.busy())
// if (ButtonA.read() && ButtonB.read())
{
if (DEBUG) Serial.println ("SYSTEM SETTINGS RESTORED ");
//
// Restore System Configuration setting to factory default.
// This can eliminate the problem of sticking at boot in WiFi Rx mode
// with no WiFi transmitter available.
//
myFlight.RestoreAll();
VVLcd.setFreeFont(FSSB12);
VVLcd.setTextColor (TFT_WHITE);
VVLcd.setTextDatum (MC_DATUM);
VVLcd.drawString ("System Settings Restored", SCREEN_X / 2, SCREEN_Y / 2);
delay (5000);
}
//
// V3.00 Adds a WiFi credential manager.
//
preferences.begin ("getSetup", false);
int32_t WiFiManager = preferences.getInt (WIFIMANAGER, 0);
preferences.putInt (WIFIMANAGER, 0); // clear upDate
preferences.end();
if (WiFiManager == 1)
{ // If we are in WiFi Manager mode
managerMode = true; // this will be cleared in flightGauges.h
}
//
// Holding Menu button A ([]) down during splash screen brings up credential manager page.
// Or, you can enable WiFi Manager in System Configuration menu.
//
// if ((ButtonA.isReleased() && ButtonA.read() == false) || managerMode)
/* MenuBtn - левая кнопка
SelectBtn - правая кнопка
read = 1 когда левая кнопка НАЖАТА, а правая не нажата - потому, что левая кнопка при нажатии дает 3.3 вольт(1), а правая дает GND(0)
правая кнопка в ненажатом состоянии дает 1, в нажатом 0, левая наоборот. */
// MenuBtn.read() = 1 когда нажата
// MenuBtn.read() = 0 когда отпущена
// SelectBtn.read() = 1 когда отпущена
// SelectBtn.read() = 0 когда нажата
// Нажав левую кнопку и удержав при перезагрузке, попадаем в меню Wi-Fi
// if ((MenuBtn.read() && SelectBtn.read()) || managerMode)
if ((btn_left.hold() && !btn_right.hold()) || managerMode)
// while ((btn_left.busy() && !btn_right.busy()) || managerMode)
{
//
// Call Keyboard(true) for initialization of WiFi credentials
//
// initialize brightness, a bug fix required after a RestoreAll
preferences.begin ("huVVer-app", false); // restore brightness during setup
preferences.putUInt ("Brightness", Brightness);
preferences.end();
myFlight.Keyboard(true);
bool done = false;
preferences.begin ("getSetup", false);
//int32_t WiFiManager = preferences.getInt (WIFIMANAGER, 0);
preferences.putInt (WIFIMANAGER, 0); // clear upDate
preferences.end();
while (!done)
{
// VVupdate();
gdraw.fillSprite (TFT_BLACK);
gdraw.setTextColor(TFT_WHITE);
//
// Call Keyboard(false) for editing WiFi credentials.
// 'done' state indicates that credentials have been saved,
// otherwise the loop continues.
//
done = myFlight.Keyboard(false);
gdraw.pushSprite (0, 0);
delay(50);
if (done)
{
myFlight.PrintMessage ("WiFi Config Saved", 2000, TFT_WHITE, TFT_RED);
}
// if (SelectBtn.releasedFor(4000))
if (btn_right.hold())//не работает в setup(), нужен опрос в loop()
{
myFlight.PrintMessage ("WiFi Config Ended", 2000, TFT_WHITE, TFT_RED);
done = true;
}
}
//
// Fade out and blank screen
//
for (float i = 1.0f; i <= Brightness; i += (float)Brightness / 200.0f)
{
myFlight.Backlight(Brightness);
delay (5);
}
gdraw.fillSprite (TFT_BLACK);
gdraw.pushSprite (0, 0);
ESP.restart();
} // end WiFi Manager
preferences.begin ("huVVer-app", false);
preferences.getString("EFIS-ID", "Wokwi-GUEST") .toCharArray(ssid, 21);
preferences.getString("EFIS-PW", "") .toCharArray(pw, 21);
preferences.getString("UNIT-ID", "huVVer-AVI") .toCharArray(OTAssid, 21);
preferences.getString("UNIT-PW", "huVVer-AVI") .toCharArray(OTApassword, 21);
// operationMode = preferences.getUInt("operationMode", WIFIOFF);
// демо режим, при котором отсутствуют красные рамки Х
operationMode = WIFIOFFDEMO;
// operationMode = WIFITX;
// case 4:
// if (myFlight.aiEnable)
// выбор дисплея по умолчанию при загрузке - preferences в wokwi не работают
displayMode = preferences.getInt("displayMode", 4);
Brightness = preferences.getUInt("Brightness", 1023);
myFlight.Backlight(Brightness);
preferences.end();
//================================================================//
// Main Configuration Menu. //
//================================================================//
{
// Display operating mode on screen
gdraw.setFreeFont(FSSB12);
gdraw.setTextColor (TFT_GREEN);
gdraw.setTextDatum (MC_DATUM);
String portId = "Serial " + String(SerialPort);
switch (operationMode)
{
case WIFIOFF:
break;
case WIFIRX:
portId = "WiFi Rx";
break;
case WIFITX:
portId = "WiFi Tx";
break;
case WIFIOFFDEMO:
portId += " Demo";
break;
case WIFIRXDEMO:
portId = "WiFi Rx Demo";
break;
case WIFITXDEMO:
portId = "WiFi Tx Demo";
break;
default:
operationMode = WIFIOFF;
break;
}
preferences.begin ("getSetup", false);
if (preferences.getInt (UPDATE, 0) > 0) portId = "OTA Update";
preferences.end();
gdraw.setTextColor (TFT_WHITE);
gdraw.drawString (portId, SCREEN_X / 2, SCREEN_Y / 2);
} // Main Configuration Menu.
gdraw.pushSprite (0, 0);
delay (1500); // duration of splash screen display
snprintf(chipID, 23, "%04X%08X", (uint16_t)(ESP.getEfuseMac() >> 32), (uint32_t)ESP.getEfuseMac());
Serial.println (chipID);
//
// WiFi operating mode selection
//
if (operationMode == WIFIRX || operationMode == WIFIRXDEMO)
{
// WiFi.disconnect();
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, pw, 6);
//
// Adust WiFi power levels as required for the application.
// Note, for bench testing multiple devices, keep the power low to prevent crashes
// due to RF interference.
//
WiFi.setTxPower(WIFIPOWER);
delay (1000);
//
// The following tries to connect to the access point,
// and if it can't after 60 seconds, restarts the entire device.
//
uint16_t wifiLoop = 60;
while (WiFi.status() != WL_CONNECTED)
{
Serial.println("WiFi Failed");
delay(1000);
//нажать правую кнопку
// if (!SelectBtn.read())
{
preferences.begin("getSetup", false);
preferences.putInt (P_WIFIRX, 0);
preferences.end();
myFlight.Backlight(0);
ESP.restart();
}
wifiLoop--;
if (wifiLoop == 0)
{
myFlight.Backlight(0);
ESP.restart(); // something is wrong!
}
}
udp.begin(port);
Serial.println ("WiFi Station Connected, listening for UDP Broadcasts");
Serial.print ("Local IP address: "); Serial.println (WiFi.localIP());
}
//
// The following sequence is absolutely critical for reliable operation
// and prevents guru meditation errors.
// https://github.com/espressif/arduino-esp32/issues/2283#
//
if (operationMode == WIFITX || operationMode == WIFITXDEMO)
{
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, pw); // configure ssid and password for softAP
uint16_t wifiLoop = 60;
while (!(WiFi.softAPIP() == ip))
{
WiFi.softAPConfig(ip, ip, netmask); // configure ip address for softAP
delay (1000);
wifiLoop--;
if (wifiLoop == 0)
{
myFlight.Backlight(0);
ESP.restart(); // something is wrong!
}
}
//
// Adjust WiFi power levels as required for the application.
// Note, for bench testing multiple devices, keep the power low to prevent crashes
// due to RF interference.
//
WiFi.setTxPower(WIFIPOWER);
Serial.printf("\nStarting UDP Broadcast Server...");
Serial.printf("Using UDP/IP over Wifi, this Server will broadcast any data received on the serial port.\n");
Serial.printf("Connect to ssid:%s, password:%s\n", ssid, pw);
Serial.print("IP Address:"); Serial.print (ip); Serial.print(", Port:"); Serial.println(port);
}
//
// Load the instrument enable preferences.
//
myFlight.LoadEnables ();
if (DEBUG) Serial.println ("Loaded Enables...");
//
// load the default instrument preferences.
//
myMenus.loadPrefs = true;
// myMenus.LoadPrefs("getAI", Values[1][5]);
// myEFISdata.sendData(false, Magnet, FilterNum, thousands, hundreds, tens, units, OffsetPitch);
//
// OTA Updater
//
preferences.begin ("getSetup", false);
int32_t upDate = preferences.getInt (UPDATE, 0);
preferences.putInt (UPDATE, 0); // clear upDate
preferences.end();
if (upDate == 1) // If we are in upDate mode
{
updateMode = true; // this will be cleared in flightGauges.h
// Start a Soft Access Point
WiFi.disconnect();
WiFi.softAP(OTAssid, OTApassword); // configure ssid and password for softAP
uint16_t wifiLoop = 60;
while (!(WiFi.softAPIP() == OTAip))
{
WiFi.softAPConfig(OTAip, OTAip, OTAnetmask); // configure ip address for softAP
delay (1000);
wifiLoop--;
if (wifiLoop == 0)
{
myFlight.Backlight(0);
ESP.restart(); // something is wrong!
}
}
Serial.println("");
Serial.print("Connect to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// server.on("/", HTTP_GET, [](AsyncWebServerRequest * request)
// {
// request->send(200, "text/plain", "huVVer-AVI OTA Updater.\n");
// });
// AsyncElegantOTA.begin(&server); // Start ElegantOTA
// server.begin();
// Serial.println("HTTP server started");
}
//
// CAN setup
//
//CAN.setPins (PIN_CANRX, PIN_CANTX);
//pinMode (PIN_CANRS, INPUT); // float for edge control
// if pins define -1 we have errors
// E (6409) gpio: gpio_set_direction(274): GPIO number error
// E (6410) gpio: gpio_set_direction(274): GPIO number error
// while (!CAN.begin(CAN_Bitrate)) {
// Serial.println("Starting CAN failed!");
// ESP.restart(); // try again
// }
//
// set up CAN modes
//
//if (CAN_Loopback) CAN.loopback();
//
// 0x000 is reserved to send embedded 8-byte commands:
// DIMnVVVV (dimmer value)
// DIM --> Dimmer command
// n = 0 analog dimmer value
// n = 1 persistent analog dimmer value
// n = 2 digital dimmer value
// n = 3 persistent digital dimmer value
// VVVV = 1...4095 brightness value
//
// CAN.filter(0, 0x7ff);
}
//=========End of Setup=============//
void loop()
{
//btn_left.tick(!digitalRead(34));
//btn_right.tick(!digitalRead(35));
btn_left.tick();
btn_right.tick();
button1.loop();
button2.loop();
long unsigned int time1 = micros();
static int16_t msgTime = 0;
static const char *myMessage = "20 character message";
// VVupdate();
//AsyncElegantOTA.loop();
//
// Check WiFi operating state every few seconds
//
if (operationMode == WIFIRX || operationMode == WIFIRXDEMO)
{
currentMillis = millis();
if ((currentMillis - previousMillis) >= 5000)
{
if (WiFi.status() != WL_CONNECTED)
{
Serial.printf("WiFi disconnected, reconnecting...\n");
WiFi.disconnect();
WiFi.mode(WIFI_AP_STA);
WiFi.begin(ssid, pw, 6);
WiFi.setTxPower(WIFIPOWER);
}
previousMillis = currentMillis;
}
}
//переключение на "лету" нажать МЕНЮ() и потом снова и удержать 4 секунды
// if (MenuBtn.pressedFor(10000))
if (btn_left.hold(4))
{
if (operationMode == WIFIRX || operationMode == WIFIRXDEMO)
{
WiFi.disconnect();
if (operationMode == WIFIRX) operationMode = WIFIOFF;
if (operationMode == WIFIRXDEMO) operationMode = WIFIOFFDEMO;
preferences.begin ("huVVer-app", false);
preferences.putUInt ("operationMode", operationMode);
preferences.end();
}
else
{
switch (SerialPort)
{
case -2:
Serial2.end();
Serial1.setRxBufferSize (RXBUFFER);
Serial1.setTxBufferSize (TXBUFFER);
Serial1.begin (BITRATE, SERIAL_8N1, PIN_RX1, PIN_TX1, TTL);
SerialPort = -1;
break;
case -1:
Serial1.end();
Serial2.setRxBufferSize (RXBUFFER);
Serial2.setTxBufferSize (TXBUFFER);
Serial2.begin (BITRATE, SERIAL_8N1, PIN_RX2, PIN_TX2, TTL);
SerialPort = -2;
break;
case 1:
Serial1.end();
Serial2.setRxBufferSize (RXBUFFER);
Serial2.setTxBufferSize (TXBUFFER);
Serial2.begin (BITRATE, SERIAL_8N1, PIN_RX2, PIN_TX2, RS232);
SerialPort = 2;
break;
case 2:
Serial2.end();
Serial1.setRxBufferSize (RXBUFFER);
Serial1.setTxBufferSize (TXBUFFER);
Serial1.begin (BITRATE, SERIAL_8N1, PIN_RX1, PIN_TX1, RS232);
SerialPort = 1;
break;
default:
break;
}
// Save new selection
preferences.begin ("getSetup", false);
preferences.putInt (SERIALPORT, SerialPort);
preferences.end();
}
myFlight.PrintMessage ("Serial " + String(SerialPort), 2000, TFT_WHITE, TFT_WHITE);
// Establish top level selection and refresh
myMenus.menuState = MENU_DEFAULT; // Back to instrument display
myMenus.loadPrefs = true;
//если выставлял MenuBtn.read() без ! то смена приборов была очень шустро
// while (!MenuBtn.read());
// while (btn_left.read());//держишь, сменяется порт и пропадает сообщение когда отпускаешь, работает с новой либой кнопок и без этого
}
//
// Top level (Default) menu handling.
//
switch (myMenus.menuState)
{
//btn_left.tick(!digitalRead(34));
//btn_right.tick(!digitalRead(35));
btn_left.tick();
btn_right.tick();
button1.loop();
button2.loop();
case MENU_DEFAULT: // Default (top level)
// if (!MenuBtn.wasPressed() && SelectBtn.releasedFor(6000))
if (btn_left.hold() && btn_right.hold())//перезагрузка на главном меню
{
myFlight.Backlight(0);
ESP.restart();
}
//
// Press Menu Button A ([]) to enter list menu.
// Вход в меню настроек - удерживаем левую кнопку 3 секунды
// if (MenuBtn.pressedFor(1000) && !SelectBtn.read())
// if (btn_left.hold(1))//вход в меню параметров
if(button2.isPressed())
{
myMenus.menuState = MENU_LIST;
myMenus.loadPrefs = true;
preferences.begin ("huVVer-app", false); // restore brightness during setup
Brightness = preferences.getUInt("Brightness", 1023);
myFlight.Backlight(Brightness);
preferences.end();
if (DEBUG) Serial.println ("Menu List");
}
// Проверка, была ли кнопка нажата и sendData еще не выполнено
if (button1.isPressed() && !buttonPressed && (displayMode == 4)) {
// if (btn_left.hold() && !buttonPressed && (displayMode == 4)) {
// myMenus.menuState = MENU_LIST;
// myEFISdata.sendData();
// myEFISdata.sendData(true, false, 1, 0, 1, 3, +0);// ALIGN, no MAG, 1013 hPa, +5 OffsetPitch
myEFISdata.sendData(true, Magnet, FilterNum, thousands, hundreds, tens, units, OffsetPitch);
buttonPressed = true; // Установка флага, указывающего, что кнопка была нажата
startTime = millis(); // Запись текущего времени
}
if (buttonPressed && !sendDataDone) {
if (millis() - startTime <= 5000) {
VVLcd.setTextColor(TFT_RED);
VVLcd.setTextDatum(MC_DATUM);
VVLcd.setCursor((SCREEN_X / 2) - 40, SCREEN_Y / 2);
VVLcd.setTextSize(1);
VVLcd.println("ALIGN");
} else if (millis() - startTime >= 1000) {
buttonPressed = false;
sendDataDone = true; // Установка флага, указывающего, что sendData выполнено
startTime = millis(); // Запись текущего времени
}
}
if (sendDataDone) {
if (millis() - startTime <= 1000) {
VVLcd.setTextColor(TFT_GREEN);
VVLcd.setTextDatum(MC_DATUM);
VVLcd.setCursor((SCREEN_X / 2) - 64, SCREEN_Y / 2);
VVLcd.setTextSize(1);
VVLcd.println("ALIGN OK");
} else if (millis() - startTime >= 1000) {
sendDataDone = false; // Сброс флага, указывающего, что sendData выполнено
}
}
// if (btn_left.hold(5))//вход в меню setup
// if(button1.isPressed())
// {
// unsigned long sendTime = 0; // Переменная для хранения времени отправки
// bool sendDataCompleted = false; // Флаг, указывающий, что отправка завершена
// bool alignmentCompleted = false; // Флаг, указывающий, что выравнивание завершено
// unsigned long currentTime = millis(); // Получение текущего времени
// // Отправка данных один раз
// if (!sendDataCompleted) {
// // myMenus.menuState = MENU_SETUP;
// myEFISdata.sendData();
// //myMenus.loadPrefs = true;
// sendTime = currentTime; // Запоминаем время отправки
// sendDataCompleted = true; // Установка флага, указывающего, что отправка завершена
// }
// // Проверка, прошло ли 10 секунд с момента отправки
// if (sendDataCompleted && currentTime - sendTime >= 10000) {
// alignmentCompleted = true; // Установка флага, указывающего, что выравнивание завершено
// }
// // Вывод надписи и изменение цвета
// if (alignmentCompleted) {
// VVLcd.setTextColor(TFT_GREEN);
// VVLcd.setTextDatum(MC_DATUM);
// VVLcd.setCursor((SCREEN_X / 2) - 40, SCREEN_Y / 2);
// VVLcd.setTextSize(1);
// VVLcd.println("ALIGN OK");
// } else {
// VVLcd.setTextColor(TFT_RED);
// VVLcd.setTextDatum(MC_DATUM);
// VVLcd.setCursor((SCREEN_X / 2) - 40, SCREEN_Y / 2);
// VVLcd.setTextSize(1);
// VVLcd.println("ALIGN");
// }
// preferences.begin ("huVVer-app", false); // restore brightness during setup
// // Brightness = preferences.getUInt("Brightness", 1023);
// Brightness = 1023;
// myFlight.Backlight(Brightness);
// preferences.end();
// if (DEBUG) Serial.println ("Setup List");
// }
{ // Modify the scope to keep variables local
static bool selectMode = false; // used to automatically save brightness, one-shot state.
static uint64_t buttonTimer = 0; // timer for brightness saving.
VVLcd.setTextDatum (MC_DATUM);
VVLcd.setFreeFont(FSSB12);
// Press Select button B(O) to increase or decrease brightness
// if (SelectBtn.wasPressed() && !MenuBtn.wasPressed() && !FwdBtn.wasPressed() && !BackBtnWasPressed())
// if (SelectBtn.releasedFor(10000) && !MenuBtn.wasPressed() && !BackBtnWasPressed())
if (btn_right.hold(1))//смена направления яркости - не работает
{
// Brightness up
if (dimDirection)
{
/* if (Brightness < 4096)
{
Brightness *= 2; // brightness
if (Brightness >= 4095) Brightness = 4095;
if (myFlight.dimChannel >= 1 && myFlight.dimChannel <= 4)
{
myFlight.Backlight (Brightness, myFlight.dimChannel, 1); // share temporary Brightness information
}
msgTime = 4; //loops
myMessage = "Dim ++";
} */
if (Brightness >= 4095)
{
Brightness = 4095;
msgTime = 8; //loops
myMessage = "Max Brightness";
dimDirection = !dimDirection; // automatically toggle up/down direction
}
}
// Brightness down
else {
if (Brightness > 1)
/* {
Brightness = Brightness/2;
if (myFlight.dimChannel >= 1 && myFlight.dimChannel <= 4)
{
myFlight.Backlight (Brightness, myFlight.dimChannel, 1); // share temporary Brightness information
}
msgTime = 4; //loops
myMessage = "Dim--";
} */
if (Brightness <= 1)
{
Brightness = 1;
msgTime = 12; //loops
myMessage = "Min Brightness";
dimDirection = !dimDirection; // automatically toggle up/down direction
}
}
buttonTimer = millis(); // zero the brightness save timer on every Select button push
selectMode = true;
}
//кнопка А нажимается для изменения яркости(увеличение по кругу)
// if (SelectBtn.releasedFor(1000) && !MenuBtn.wasPressed())
if (btn_left.hold(3)) //яркость ++ по кругу
{
// if (SelectBtn.wasPressed() && !MenuBtn.wasPressed() && !FwdBtn.wasReleased() && !BackBtnWasPressed()) {
Brightness *= 2; // brightness up
if (Brightness == 4096) Brightness = 4095;
if (Brightness > 4096) Brightness = 1;
if (Brightness == 0) Brightness = 1;
// VVLcd.setBrightness (Brightness);
myFlight.Backlight (Brightness);
if (Brightness == 4095) {
VVLcd.setTextDatum (MC_DATUM);
VVLcd.setFreeFont(FSSB12);
char *buffer = "MAX BRIGHTNESS";
VVLcd.setTextColor (TFT_BLACK);
VVLcd.drawString(buffer, 161, 121, GFXFF);
VVLcd.setTextColor (TFT_WHITE);
VVLcd.drawString(buffer, 160, 120, GFXFF);
uint64_t lastTime = millis();
while (millis() < (lastTime + 2000));
delay(100);
}
buttonTimer = millis(); // zero the timer
selectMode = true;
}
if (selectMode && millis() > (buttonTimer + 4000))
{
//
// When selection is stable, send persistent Brightness level to all other units
// over CAN and save it in preferences. This delay minimizes memory wear.
//
selectMode = false;
/* if (myFlight.dimChannel >= 1 && myFlight.dimChannel <= 4)
{
myFlight.Backlight (Brightness, myFlight.dimChannel, 2); // share persistent Brightness information
} */
preferences.begin ("huVVer-app", false);
preferences.putUInt("Brightness", Brightness);
preferences.end();
static uint64_t lastTime = millis();
while (millis() < (lastTime + 500));
}
//
// Hold Select button B (O) to toggle dimmer up/down direction
//
/* if (SelectBtn.releasedFor(750))
{
// For pressedFor() must use PrintMessage, not DrawMessage
myMessage = " Dim Toggle "; // Extra spaces to overwrite OTA Update message
myFlight.PrintMessage (myMessage, 500, TFT_WHITE, TFT_WHITE);
dimDirection = !dimDirection;
} */
}
//
// press Fwd Button C (>) to change selected item.
//
// if (FwdBtn.wasPressed() && !BackBtnWasPressed())
// if (SelectBtn.releasedFor(2000))
// if (btn_right.hold(2))//листать виджеты по одному
// if (btn_right.step(2))//листать виджеты по одному
if (button2.isPressed())//листать виджеты по одному
{
displayDirection = 1;
displayMode ++;
delay(500);
// Reset the menu selection to top of the list
myMenus.menuState = MENU_DEFAULT;
myMenus.itemSelect = 1;
myMenus.digitAction = 0;
myMenus.digitSelect = -1;
myMenus.loadPrefs = true;
}
/* if (btn_right.step(2) && btn_left.hold(1))//листать виджеты непрерывно - пока не работает
{
displayDirection = 1;
displayMode ++;
delay(500);
// Reset the menu selection to top of the list
myMenus.menuState = MENU_DEFAULT;
myMenus.itemSelect = 1;
myMenus.digitAction = 0;
myMenus.digitSelect = -1;
myMenus.loadPrefs = true;
} */
//
// press Back Button D (<) to change selected item.
//
// if (BackBtnWasPressed() && !SelectBtn.wasPressed() && !MenuBtn.wasPressed())
// if (MenuBtn.pressedFor(2000))
if (btn_left.step(2))
// if (button2.isPressed())
// if (btn_left.hold(2))//листать виджеты по одному
{
displayDirection = -1;
displayMode --;
delay(500);
// Reset the menu selection to top of the list
myMenus.menuState = MENU_DEFAULT;
myMenus.itemSelect = 1;
myMenus.digitAction = 0;
myMenus.digitSelect = -1;
myMenus.loadPrefs = true;
}
/* if (btn_left.step(2) && btn_right.hold(1))//листать виджеты непрерывно - пока не работает
{
displayDirection = -1;
displayMode --;
delay(500);
// Reset the menu selection to top of the list
myMenus.menuState = MENU_DEFAULT;
myMenus.itemSelect = 1;
myMenus.digitAction = 0;
myMenus.digitSelect = -1;
myMenus.loadPrefs = true;
} */
break; // end (MENU_DEFAULT)
case MENU_LIST:
// if (BackBtnWasPressed() && !FwdBtn.wasPressed())
// if (MenuBtn.pressedFor(2000) && !SelectBtn.wasReleased())
// if (MenuBtn.wasPressed && !SelectBtn.wasReleased())
// if (btn_left.hold(1))// > button
// {
// myMenus.itemSelect --;
// if (DEBUG) Serial.println (myMenus.itemSelect);
// }
// if (FwdBtn.wasPressed() && !BackBtnWasPressed())
// if (!MenuBtn.wasPressed() && SelectBtn.releasedFor(1000))
// нажимая правую кнопку перемещаемся вперед(по кругу) по пунктам настроек
// if (MenuBtn.read() && SelectBtn.wasReleased())
if (btn_right.hold(1))// > button
{ // > button
myMenus.itemSelect ++;
if (DEBUG) Serial.println (myMenus.itemSelect);
}
// возврат на самый верх к виджетам
// if (MenuBtn.pressedFor(4000) && !SelectBtn.wasReleased())
// if (MenuBtn.wasPressed() && !SelectBtn.wasReleased())
// if (btn_left.hold(1))//выход из меню параметров
if(button1.isPressed())
{ // [] button
myMenus.menuState = MENU_DEFAULT;
if (DEBUG) Serial.println ("Default");
}
// if (SelectBtn.releasedFor(2000) && !MenuBtn.wasPressed())
if (btn_right.hold(2))
{ // O button
myMenus.menuState = MENU_ACTION;
myMenus.digitSelect = 1; //enable digit editing
if (DEBUG) Serial.println ("Data Entry");
}
break; // end (MENU_LIST)
case MENU_ACTION:
// if (BackBtnWasPressed() && !FwdBtn.wasPressed())
// if (MenuBtn.pressedFor(2000) && SelectBtn.read())
if (btn_left.hold(1)) // < button
{
myMenus.digitAction = -1;
if (DEBUG) Serial.println ("<");
}
// if (FwdBtn.wasPressed() && !BackBtnWasPressed())
// if (!MenuBtn.wasPressed() && SelectBtn.releasedFor(1000))
// if (MenuBtn.wasPressed() && SelectBtn.read())
if (btn_right.hold(1)) // > button
{ // > button
myMenus.digitAction = +1;
if (DEBUG) Serial.println (">");
}
// if (MenuBtn.pressedFor(4000) && !SelectBtn.wasReleased())
if (btn_right.hold(3))
{ // [] button
//
// Trigger the save data function
//
myMenus.saveAction = true;
myMenus.menuState = MENU_LIST;
myMenus.digitAction = 0;
myMenus.digitSelect = -1;
if (DEBUG) Serial.println ("Data Saved Temporarily");
}
// if (SelectBtn.wasReleased() && !MenuBtn.wasPressed())
if (btn_right.hold(2))
{ // O button
myMenus.digitSelect ++;
myMenus.digitAction = 0;
if (DEBUG) Serial.println ("digit " + String (myMenus.digitSelect));
}
break; // end (MENU_ACTION)
//должно быть всплывающее меню из 4-х пунктов
case MENU_SETUP:
if(button2.isPressed())
// if (btn_right.hold(1)) // > button
{ // > button
if (DEBUG) Serial.println ("Change button");
}
// Вход в четырехкнопочное меню - удерживаем такую то кнопку
// if (!MenuBtn.read() && SelectBtn.releasedFor(2000))
// if (btn_left.hold(1))
if(button1.isPressed())
{
myMenus.menuState = MENU_DEFAULT;
// myMenus.loadPrefs = true;
preferences.begin ("huVVer-app", false); // restore brightness during setup
Brightness = preferences.getUInt("Brightness", 1023);
myFlight.Backlight(Brightness);
preferences.end();
if (DEBUG) Serial.println ("Return to Main Menu");
}
break; // end (MENU_ACTION)
default:
if (DEBUG) Serial.println ("Illegal Menu");
break;
}
//
// Main serial processing routing, reads all incoming serial data and processes sentences (aka packets) when detected.
//
if (operationMode == WIFIOFF || operationMode == WIFITX || operationMode == WIFIOFFDEMO || operationMode == WIFITXDEMO)
{
switch (SerialPort)
{
case 2:
while (Serial2.available())
{
myEFISdata.serPacketFrame(2);
if (myEFISdata.packetValid) break;
}
break;
case -2:
while (Serial2.available())
{
myEFISdata.serPacketFrame(2);
if (myEFISdata.packetValid) break;
}
break;
case 0:
while (Serial.available() )
{
myEFISdata.serPacketFrame(0); // process data
if (myEFISdata.packetValid) break; // until packet received
}
break;
case 1:
while (Serial1.available())
{
myEFISdata.serPacketFrame(1);
if (myEFISdata.packetValid) break;
}
break;
case -1:
while (Serial1.available())
{
myEFISdata.serPacketFrame(1);
if (myEFISdata.packetValid) break;
}
break;
}
}
//
// Get packets from WiFi (if provisioned).
//
else if (operationMode == WIFIRX || operationMode == WIFIRXDEMO)
{
int packetSize = udp.parsePacket();
if (packetSize > 0)
{
if (DEBUG)
{
Serial.printf("Received packet of size %d ", packetSize);
IPAddress remoteIp = udp.remoteIP();
Serial.printf("From Port %d ", udp.remotePort());
}
// read the packet into packetChars
int len = udp.read(myEFISdata.packetChars, NUMCHARS);
if (len > 0)
{
myEFISdata.packetChars[len] = 0;
}
if (DEBUG) Serial.printf ("Contents: %s", myEFISdata.packetChars);
//
// Forward packet data to selected serial port
//
if (SerialPort == 1 || SerialPort == -1) Serial1.println(myEFISdata.packetChars);
if (SerialPort == 2 || SerialPort == -2) Serial2.println(myEFISdata.packetChars);
// Extract the data fields.
myEFISdata.udpPacketFrame(myEFISdata.packetChars, len);
}
}
// if (myEFISdata.packetValid) // a sentence has been detected.
if (true) // a sentence has been detected.
{
frameCount = FRAMES; // indicates serial link activity.
//
// Send over WiFi (if provisioned).
//
if (operationMode == WIFITX || operationMode == WIFITXDEMO)
{
//
// send udp
//
udp.beginPacket(broadcastIp, port); // remote IP and port
udp.print(myEFISdata.packetChars);
udp.endPacket();
if (DEBUG) Serial.printf ("Destination Port: %d\n", port);
if (DEBUG) Serial.println (broadcastIp);
}
}
myEFISdata.packetValid = false; // release framed packet
//
// check for dimmer value received on CAN bus
//
// if (CAN.parsePacket())
// {
// uint16_t checkBright = myFlight.receiveCANdim();
// if (checkBright > 0) Brightness = checkBright;
// }
//
// Set loop update time and alarm flash rate
//
if (millis() > (loopTime + LOOPTIME))
{ //in milliseconds
loopTime = millis();
gdraw.fillSprite (TFT_BLACK);
// Disable timeout if in demonstration mode, system menu, readme menu, or submenus.
if (operationMode == WIFIOFFDEMO || operationMode == WIFIRXDEMO || operationMode == WIFITXDEMO
|| !myMenus.menuState == MENU_DEFAULT) frameCount = FRAMES;
//
// Main instrument display selection
//
if (displayMode > READMEPAGE) displayMode = SYSTEMPAGE;
if (displayMode < SYSTEMPAGE) displayMode = READMEPAGE;
preferences.begin ("getSetup", false);
int32_t restoreAll = preferences.getInt(RESTOREALL, 0); // check bit to clear to factory new
preferences.end();
if (displayDirection > 0)
{
switch (displayMode)
{
case SYSTEMPAGE:
myFlight.SystemSetup();
if (restoreAll > 0)
{
myFlight.RestoreAll();
if (DEBUG) Serial.println ("All Preferences restored, restarting");
myFlight.Backlight(0);
ESP.restart();
}
break;
case 1:
if (myFlight.asiEnable)
{
myFlight.ASIDisplay (AirSpeed, TASpeed, ASBug);
break;
}
else displayMode ++;
case 2:
if (myFlight.altEnable)
{
myFlight.ALTDisplay (Altitude, PressAlt, DensAlt,
Baro, AltBug, AirSpeed, VertSpeed, VSBug);
break;
}
else displayMode ++;
case 3:
if (myFlight.hdgEnable)
{
myFlight.HDGDisplay (Heading, HdgBug, Course,
WindDir, WindSpeed);
break;
}
else displayMode ++;
case 4:
if (myFlight.aiEnable)
{
myFlight.AiDisplay (Pitch, Roll, Slip, AirSpeed,
Altitude, PressAlt, DensAlt, Baro,
Heading, VertAccel, AOA, FlightPath,
DriftAngle);
break;
}
else displayMode ++;
case 5:
if (myFlight.aoaEnable)
{
myFlight.AOADisplay (AOA, Slip, VertAccel, flashFlag,
AirSpeed, TASpeed, Heading, Altitude,
PressAlt, DensAlt, VertSpeed, Baro);
break;
}
else displayMode ++;
case 6:
if (myFlight.energyEnable)
{
myFlight.EnergyDisplay (AOA, OnSpeedAOA, SmoothedAOA,
Slip, VertAccel, AirSpeed, FlapPos,
flashFlag, OSTonesOnAOA, OSFastAOA, OSSlowAOA,
OSStallWarnAOA, gOnsetRate);
break;
}
else displayMode ++;
case 7:
if (myFlight.powerEnable)
{
//
// compensates for fuel return flow to tank
//
int16_t FuelFlow = 0, fuel1 = 0, fuel2 = 0;
if (FuelF1 >= 0) fuel1 = FuelF1;
if (FuelF2 >= 0) fuel2 = FuelF2;
FuelFlow = fuel1 - fuel2;
if (FuelFlow < 0) FuelFlow = 0;
myFlight.PowerDisplay(RpmL, Map, FuelFlow, FuelP, FuelRem, PercentPwr, LeanState, GroundTrack, GroundSpeed);
break;
}
else displayMode ++;
case 8: // EGTCHT
if (myFlight.egtChtEnable)
{
int16_t FuelFlow = 0, fuel1 = 0, fuel2 = 0;
if (FuelF1 >= 0) fuel1 = FuelF1;
if (FuelF2 >= 0) fuel2 = FuelF2;
FuelFlow = fuel1 - fuel2;
if (FuelFlow < 0) FuelFlow = 0;
myFlight.EgtChtDisplay(TCpl, 14, FuelFlow, FuelRem, PercentPwr, LeanState, GroundSpeed);
break;
}
else displayMode ++;
case 9: // Fuel, Oil, Volts, Amps
if (myFlight.fuelOilEnable)
{
myFlight.FuelOilDisplay (FuelL, FuelR,
FuelP, OilP, OilT,
Volts1, Amps);
break;
}
else displayMode ++;
case 10: // Flow, Oil, Volts, Amps
if (myFlight.flowOilEnable)
{
//
// compensates for fuel return flow to tank
//
int16_t FuelFlow = 0, fuel1 = 0, fuel2 = 0;
if (FuelF1 >= 0) fuel1 = FuelF1;
if (FuelF2 >= 0) fuel2 = FuelF2;
FuelFlow = fuel1 - fuel2;
if (FuelFlow < 0) FuelFlow = 0;
myFlight.FlowOilDisplay (FuelFlow, FuelRem, FuelP,
OilP, OilT, Volts1, Amps);
break;
}
else displayMode ++;
case 11:
if (myFlight.adahrsRaw)
{
myFlight.ADAHRSRaw();
break;
}
else displayMode ++;
case 12:
if (myFlight.systemRaw)
{
myFlight.SYSTEMRaw();
break;
}
else displayMode ++;
case 13:
if (myFlight.emsRaw1)
{
myFlight.EMSRaw1();
break;
}
else displayMode ++;
case 14:
if (myFlight.emsRaw2)
{
myFlight.EMSRaw2();
break;
}
else displayMode ++;
case 15:
if (myFlight.emsRaw3)
{
myFlight.EMSRaw3();
break;
}
else displayMode ++;
case READMEPAGE: // Notes
//if (myFlight.readMe)
//{
myFlight.ReadMe();
break;
//}
//else displayMode ++;
default:
break;
}
}
else
{
switch (displayMode)
{
case READMEPAGE: // Notes
//if (myFlight.readMe)
//{
myFlight.ReadMe();
break;
//}
//else displayMode --;
case 15:
if (myFlight.emsRaw3)
{
myFlight.EMSRaw3();
break;
}
else displayMode --;
case 14:
if (myFlight.emsRaw2)
{
myFlight.EMSRaw2();
break;
}
else displayMode --;
case 13:
if (myFlight.emsRaw1)
{
myFlight.EMSRaw1();
break;
}
else displayMode --;
case 12:
if (myFlight.systemRaw)
{
myFlight.SYSTEMRaw();
break;
}
else displayMode --;
case 11:
if (myFlight.adahrsRaw)
{
myFlight.ADAHRSRaw();
break;
}
else displayMode --;
case 10: // Flow, Oil, Volts, Amps
if (myFlight.flowOilEnable)
{
//
// compensates for fuel return flow to tank
//
int16_t FuelFlow = 0, fuel1 = 0, fuel2 = 0;
if (FuelF1 >= 0) fuel1 = FuelF1;
if (FuelF2 >= 0) fuel2 = FuelF2;
FuelFlow = fuel1 - fuel2;
if (FuelFlow < 0) FuelFlow = 0;
myFlight.FlowOilDisplay (FuelFlow, FuelRem, FuelP,
OilP, OilT, Volts1, Amps);
break;
}
else displayMode --;
case 9: // Fuel, Oil, Volts, Amps
if (myFlight.fuelOilEnable)
{
myFlight.FuelOilDisplay (FuelL, FuelR,
FuelP, OilP, OilT,
Volts1, Amps);
break;
}
else displayMode --;
case 8: // EGTCHT
if (myFlight.egtChtEnable)
{
int16_t FuelFlow = 0, fuel1 = 0, fuel2 = 0;
if (FuelF1 >= 0) fuel1 = FuelF1;
if (FuelF2 >= 0) fuel2 = FuelF2;
FuelFlow = fuel1 - fuel2;
if (FuelFlow < 0) FuelFlow = 0;
myFlight.EgtChtDisplay(TCpl, 14, FuelFlow, FuelRem, PercentPwr, LeanState, GroundSpeed);
break;
}
else displayMode --;
case 7: // Power
if (myFlight.powerEnable)
{
//
// compensates for fuel return flow to tank
//
int16_t FuelFlow = 0, fuel1 = 0, fuel2 = 0;
if (FuelF1 >= 0) fuel1 = FuelF1;
if (FuelF2 >= 0) fuel2 = FuelF2;
FuelFlow = fuel1 - fuel2;
if (FuelFlow < 0) FuelFlow = 0;
myFlight.PowerDisplay(RpmL, Map, FuelFlow, FuelP, FuelRem, PercentPwr, LeanState, GroundTrack, GroundSpeed);
break;
}
else displayMode --;
case 6:
if (myFlight.energyEnable)
{
myFlight.EnergyDisplay (AOA, OnSpeedAOA, SmoothedAOA,
Slip, VertAccel, AirSpeed, FlapPos,
flashFlag, OSTonesOnAOA, OSFastAOA, OSSlowAOA,
OSStallWarnAOA, gOnsetRate);
break;
}
else displayMode --;
case 5:
if (myFlight.aoaEnable)
{
myFlight.AOADisplay (AOA, Slip, VertAccel, flashFlag,
AirSpeed, TASpeed, Heading,
Altitude, PressAlt,
DensAlt, VertSpeed, Baro);
break;
}
else displayMode --;
case 4:
if (myFlight.aiEnable)
{
myFlight.AiDisplay (Pitch, Roll, Slip, AirSpeed,
Altitude, PressAlt, DensAlt, Baro,
Heading, VertAccel, AOA, FlightPath,
DriftAngle);
break;
}
else displayMode --;
case 3:
if (myFlight.hdgEnable)
{
myFlight.HDGDisplay (Heading, HdgBug, Course,
WindDir, WindSpeed);
break;
}
else displayMode --;
case 2:
if (myFlight.altEnable)
{
myFlight.ALTDisplay (Altitude, PressAlt, DensAlt,
Baro, AltBug, AirSpeed, VertSpeed, VSBug);
break;
}
else displayMode --;
case 1:
if (myFlight.asiEnable)
{
myFlight.ASIDisplay (AirSpeed, TASpeed, ASBug);
break;
}
else displayMode --;
case SYSTEMPAGE:
myFlight.SystemSetup();
if (restoreAll > 0)
{
myFlight.RestoreAll();
if (DEBUG) Serial.println ("All Preferences cleared, restarting");
myFlight.Backlight(0);
ESP.restart();
}
break;
default:
break;
}
}
//
// Look for serial link failure
//
frameCount --;
if (frameCount <= 0 && displayMode != SYSTEMPAGE && displayMode != READMEPAGE)
{
// Draw red X across display
frameCount = 0;
myGauges.drawLine (0, 0, SCREEN_X, SCREEN_Y, TFT_RED, 6, NONE, gdraw.alphaBlend (100, TFT_WHITE, TFT_RED), 2, NONE);
myGauges.drawLine (0, SCREEN_Y, SCREEN_X, 0, TFT_RED, 6, NONE, gdraw.alphaBlend (100, TFT_WHITE, TFT_RED), 2, NONE);
}
//
// flashFlag toggles every loop to allow for alarm indication.
// Changing the LOOPTIME constant will also change the flash rate.
//
flashCount++;
if (flashCount >= FLASHCOUNT)
{
flashCount = 0;
flashFlag = !flashFlag;
}
//
// Deferred message overlay printing. msgTime is the number of display loops.
//
if (msgTime) myFlight.DrawMessage (myMessage, TFT_WHITE, TFT_WHITE);
if (msgTime > 0) msgTime--;
//
// Mode indication, copyrights, and error counts when in DEMO mode
//
if ((operationMode == WIFIOFFDEMO || operationMode == WIFIRXDEMO ||
operationMode == WIFITXDEMO) && myMenus.menuState == MENU_DEFAULT)
{
gdraw.setFreeFont(TT1);
gdraw.setTextColor (TFT_WHITE, TFT_BLACK);
gdraw.setTextDatum (BC_DATUM);
// gdraw.setTextPadding (gdraw.textWidth("DEMO MODE, NOT FOR FLIGHT") + 4);
gdraw.drawString ("DEMO MODE, NOT FOR FLIGHT", SCREEN_X / 2, SCREEN_Y);
}
//
// Push updated display to screen
//
// gdrawMenu.pushSprite (0, 0);
gdraw.pushSprite (0, 0);
// All instruments should execute in an average of about 60 milliseconds
// or less to minimize packet loss cause by eventual buffer overflow.
if (DRAWTIME)
{
Serial.println ((micros() - time1) / 1000);
Serial.print ("Errs: "); Serial.println (myEFISdata.checkSumErrs);
}
} // end if (millis() > (loopTime + LOOPTIME);
// btn_left.tick();
// btn_right.tick();
} // end of loop
esp:VIN
esp:GND.2
esp:D13
esp:D12
esp:D14
esp:D27
esp:D26
esp:D25
esp:D33
esp:D32
esp:D35
esp:D34
esp:VN
esp:VP
esp:EN
esp:3V3
esp:GND.1
esp:D15
esp:D2
esp:D4
esp:RX2
esp:TX2
esp:D5
esp:D18
esp:D19
esp:D21
esp:RX0
esp:TX0
esp:D22
esp:D23
lcd1:VCC
lcd1:GND
lcd1:CS
lcd1:RST
lcd1:D/C
lcd1:MOSI
lcd1:SCK
lcd1:LED
lcd1:MISO
lcd1:SCL
lcd1:SDA
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
r1:1
r1:2
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
r2:1
r2:2
r3:1
r3:2
led1:A
led1:C