270 lines
7.9 KiB
C++
270 lines
7.9 KiB
C++
/*
|
|
ESP32-8048S043 based DashDisplay for simracing and stuff
|
|
by Eduardo Silva and others
|
|
|
|
TODO:
|
|
- Add a better communication mechanism that allows the desktop interface
|
|
to have more ways to run analytics
|
|
*/
|
|
|
|
#include "Arduino_GFX.h"
|
|
#include "HardwareSerial.h"
|
|
#include "UIComponent.h"
|
|
#include "UIDecorations.h"
|
|
#include "UIDimensions.h"
|
|
#include "UIScreen.h"
|
|
#include "communication/commands.h"
|
|
#include "communication/packets.h"
|
|
#include "communication/walkieTalkie.h"
|
|
#include "values.h"
|
|
#include "windowPool.h"
|
|
// #include "UIDrawing.h"
|
|
#include "UIString.h"
|
|
// #include "UITable.h"
|
|
// #include "data.h"
|
|
#include "displaySetup.h"
|
|
#include "esp32-hal-psram.h"
|
|
// #include "ui.h"
|
|
#include <Arduino.h>
|
|
#include <Arduino_GFX_Library.h>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <unistd.h>
|
|
// #include <nvs.h>
|
|
// #include <nvs_flash.h>
|
|
|
|
#define ESLABS_DEVICE_ID 0x01
|
|
#define ESLABS_DEVICE_NAME "ESLabs CDashDisplay"
|
|
|
|
#define UART1_TX 19
|
|
#define UART1_RX 18
|
|
|
|
Arduino_ESP32RGBPanel *panel = new Arduino_ESP32RGBPanel(
|
|
40 /* DE */, 41 /* VSYNC */, 39 /* HSYNC */, 42 /* DCLK */, 45 /* R0 */,
|
|
48 /* R1 */, 47 /* R2 */, 21 /* R3 */, 14 /* R4 */, 5 /* G0 */, 6 /* G1 */,
|
|
7 /* G2 */, 15 /* G3 */, 16 /* G4 */, 4 /* G5 */, 8 /* B0 */, 3 /* B1 */,
|
|
46 /* B2 */, 9 /* B3 */, 1 /* B4 */, 0 /*hsync_polarity*/,
|
|
8 /* hsync_front_porch*/, 4 /* hsync_pulse_width*/,
|
|
43 /* hsync_back_porch*/, 0 /*vsync_polarity*/, 8 /*vsync_front_porch*/,
|
|
4 /*vsync_pulse_width*/, 12 /*vsync_back_porch*/, 1 /*pclk_active_neg*/,
|
|
16000000 /*prefer_speed*/, false /*useBigEndian*/, 0 /*de_idle_high*/,
|
|
0 /*pclk_idle_high*/
|
|
);
|
|
|
|
//
|
|
Arduino_GFX *gfx = new Arduino_RGB_Display(TFT_HOR_RES, TFT_VER_RES, panel, 16);
|
|
|
|
// HardwareSerial debugSerial(1);
|
|
Curses::Screen mainScreen(gfx, UIDimensions(0, 0, TFT_HOR_RES, TFT_VER_RES),
|
|
UIDecorations());
|
|
|
|
// UIelements
|
|
// UIDecorations *gearTextDecor = new UIDecorations();
|
|
// UIString gearText(gfx, UIDimensions(0, 0, 0, 0), gearTextDecor, (char
|
|
// *)"Gear");
|
|
//
|
|
// UIElement mainWindow(
|
|
// gfx,
|
|
// UIDimensions(0, 0, TFT_HOR_RES, TFT_VER_RES),
|
|
// gearTextDecor,
|
|
// (char*)"MAIN WINDOW"
|
|
// );
|
|
|
|
void setup() {
|
|
psramInit();
|
|
Serial.begin(115200);
|
|
|
|
// Initialize the debug serial object
|
|
Serial2.begin(115200, SERIAL_8N1, UART1_RX, UART1_TX);
|
|
Serial2.flush();
|
|
|
|
Serial2.print(F("\r=== ESP32 SimRacing DashDisplay ===\r\n"));
|
|
|
|
Serial2.print(F("* Initiating display\r\n"));
|
|
initialDisplaySetup(gfx);
|
|
|
|
// Only setup the main screen after initializing the Serial2
|
|
mainScreen.Setup("Main Window");
|
|
|
|
// Grab a handle for the main window of the screen
|
|
UIElement *mainWindow = mainScreen.mainWindowHandle;
|
|
mainWindow->drawBox();
|
|
|
|
// int16_t childID = mainWindow->AddChild(STRING);
|
|
// if (childID < 0) {
|
|
// Serial2.println("Failed to add new window!");
|
|
// } else {
|
|
// Serial2.print("Successfully added a new window: ");
|
|
// Serial2.println(childID);
|
|
//
|
|
// UIElement *childComponent = mainWindow->GetChild(childID);
|
|
//
|
|
// childComponent->SetTitle((char *)"%s [%2d]", (const char *)"Child Window",
|
|
// childID);
|
|
// childComponent->SetUIDecorations(UIDecorations());
|
|
// childComponent->SetUIDimensions(UIDimensions(20, 20, 300, 300));
|
|
// childComponent->SetDisplay(mainScreen.display);
|
|
//
|
|
// childComponent->drawBox();
|
|
// }
|
|
//
|
|
// childID = mainWindow->AddChild(STRING);
|
|
// if (childID < 0) {
|
|
// Serial2.println("Failed to add new window!");
|
|
// } else {
|
|
// Serial2.print("Successfully added a new window: ");
|
|
// Serial2.println(childID);
|
|
//
|
|
// UIElement *childComponent = mainWindow->GetChild(childID);
|
|
//
|
|
// childComponent->SetTitle((char *)"%s [%2d]", (const char *)"Second Child",
|
|
// childID);
|
|
// childComponent->SetUIDecorations(UIDecorations());
|
|
// childComponent->SetUIDimensions(UIDimensions(330, 20, 300, 300));
|
|
// childComponent->SetDisplay(mainScreen.display);
|
|
//
|
|
// childComponent->drawBox();
|
|
// }
|
|
//
|
|
// mainWindow->RemoveChild(1);
|
|
//
|
|
// childID = mainWindow->AddChild(STRING);
|
|
// if (childID < 0) {
|
|
// Serial2.println("Failed to add new window!");
|
|
// } else {
|
|
// Serial2.print("Successfully added a new window: ");
|
|
// Serial2.println(childID);
|
|
//
|
|
// UIElement *childComponent = mainWindow->GetChild(childID);
|
|
//
|
|
// childComponent->SetTitle((char *)"%s [%2d]", (const char *)"Third Child",
|
|
// childID);
|
|
// childComponent->SetUIDecorations(UIDecorations());
|
|
// childComponent->SetUIDimensions(UIDimensions(20, 20, 300, 300));
|
|
// childComponent->SetDisplay(mainScreen.display);
|
|
//
|
|
// childComponent->drawBox();
|
|
// }
|
|
|
|
WindowPool::PrintInUse();
|
|
|
|
delay(500);
|
|
Serial2.println("* Ready for loop");
|
|
}
|
|
|
|
uint64_t lastDataRead = 0;
|
|
|
|
bool gotAck = false;
|
|
|
|
struct header {
|
|
uint8_t StartMarker;
|
|
Command Cmd;
|
|
uint8_t EndMarker;
|
|
};
|
|
|
|
void PrintHeader(header *h) {
|
|
Serial2.println("HEADER:");
|
|
Serial2.print(" StartMarker: ");
|
|
Serial2.println(h->StartMarker);
|
|
Serial2.print(" Command : ");
|
|
Serial2.println(CommandToStr(h->Cmd));
|
|
Serial2.print(" EndMarker : ");
|
|
Serial2.println(h->EndMarker);
|
|
Serial2.println();
|
|
}
|
|
|
|
struct UIWindowPacket {
|
|
uint8_t StartMarker;
|
|
uint16_t x0;
|
|
uint16_t y0;
|
|
uint16_t width;
|
|
uint16_t height;
|
|
uint8_t EndMarker;
|
|
};
|
|
|
|
uint64_t lastSent = 0;
|
|
void loop(void) {
|
|
uint64_t cur = millis();
|
|
|
|
// with this new way of reading data, we are just gonna read a payload
|
|
// and get a command
|
|
Command cmd = CmdUnknown;
|
|
uint8_t payload[256] = {0};
|
|
|
|
if (Serial.available() > 0) {
|
|
int16_t resp = WalkieTalkie::RecvStream(&cmd, payload, 256);
|
|
if (resp < 0) {
|
|
Serial2.println(F("Failed to receive data from serial"));
|
|
return;
|
|
} else if (resp == 0) {
|
|
Serial2.println(F("No data to receive"));
|
|
return;
|
|
}
|
|
|
|
Serial2.print("Command: ");
|
|
Serial2.println(CommandToStr(cmd));
|
|
Serial2.print("Response: ");
|
|
Serial2.println(resp);
|
|
|
|
switch(cmd) {
|
|
case CmdRequestID:
|
|
IdentificationPacket papers;
|
|
initIdentificationPacket(&papers, ESLABS_DEVICE_NAME, ESLABS_DEVICE_ID);
|
|
WalkieTalkie::SendData(&papers);
|
|
break;
|
|
default:
|
|
Serial2.print(F("Command `"));
|
|
Serial2.print(CommandToStr(cmd));
|
|
Serial2.print(F("` has not been implemented yet."));
|
|
}
|
|
}
|
|
|
|
// // Try to use a state machine for this instead? Would it be better or just more
|
|
// // verbose and difficult to read?
|
|
// if (Serial.available() >= 1) {
|
|
// // Receive the header
|
|
// header h = {0};
|
|
// int res = WalkieTalkie::RecvData(&h);
|
|
// if (res > 0) {
|
|
// PrintHeader(&h);
|
|
// } else {
|
|
// Serial2.println(F("Failed to read header"));
|
|
// return;
|
|
// }
|
|
//
|
|
// // Now we receive the body
|
|
// switch(h.Cmd) {
|
|
// case CmdRequestID:
|
|
// // We have no body to receive, we just return data
|
|
// break;
|
|
// case CmdCreateWindow:
|
|
// Serial2.println("Awaiting body...");
|
|
// // We have to receive a body, should have plenty of data
|
|
// //
|
|
// UIWindowPacket windowData;
|
|
// size_t bytes = WalkieTalkie::RecvData(&windowData);
|
|
// if (bytes <= 0) {
|
|
// Serial2.println("Malformed data");
|
|
// }
|
|
//
|
|
// Serial2.print("StartMarker: ");
|
|
// Serial2.println(windowData.StartMarker);
|
|
// Serial2.print("x0: ");
|
|
// Serial2.println(windowData.x0);
|
|
// Serial2.print("y0: ");
|
|
// Serial2.println(windowData.y0);
|
|
// Serial2.print("width: ");
|
|
// Serial2.println(windowData.width);
|
|
// Serial2.print("height: ");
|
|
// Serial2.println(windowData.height);
|
|
// // Serial2.print("title: ");
|
|
// // Serial2.println(windowData.title);
|
|
// Serial2.print("EndMarker: ");
|
|
// Serial2.println(windowData.EndMarker);
|
|
//
|
|
// Serial2.println("Received body... Continuing");
|
|
// break;
|
|
// }
|
|
// }
|
|
}
|