build: clean up the mess of ifdefs from platform into a scons-configured hal
This commit is contained in:
93
src/platform/arduino/esp32/BluetoothSerialTelemetry.cpp
Normal file
93
src/platform/arduino/esp32/BluetoothSerialTelemetry.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
#include "BluetoothSerialTelemetry.h"
|
||||
#include "../../Static.h"
|
||||
#include "../../Platform.h"
|
||||
#include <ArduinoLog.h>
|
||||
#include "../../inputs/Buttons.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
BluetoothSerialTelemetry::BluetoothSerialTelemetry() : InputSource("Bluetooth")
|
||||
{
|
||||
//m_serial.setPin("0000");
|
||||
m_serial.enableSSP();
|
||||
}
|
||||
|
||||
InputEvent
|
||||
BluetoothSerialTelemetry::read()
|
||||
{
|
||||
bool didRead = false;
|
||||
while (m_serial.available()) {
|
||||
didRead = true;
|
||||
char charRead = m_serial.read();
|
||||
m_ringbuf.insert(charRead);
|
||||
if (charRead == '*') {
|
||||
static char commandBuf[32];
|
||||
size_t cmdSize = m_ringbuf.write(commandBuf);
|
||||
// Overwrite the '*' character, to leave us with a complete command
|
||||
commandBuf[cmdSize-1] = 0;
|
||||
|
||||
Log.verbose("Bluetooth read %s", commandBuf);
|
||||
|
||||
if (commandBuf[0] == 'R') {
|
||||
m_color = CRGB(std::atoi(&commandBuf[1]), m_color.g, m_color.b);
|
||||
return InputEvent{InputEvent::SetColor, m_color};
|
||||
} else if (commandBuf[0] == 'G') {
|
||||
m_color = CRGB(m_color.r, std::atoi(&commandBuf[1]), m_color.b);
|
||||
return InputEvent{InputEvent::SetColor, m_color};
|
||||
} else if (commandBuf[0] == 'B') {
|
||||
m_color = CRGB(m_color.r, m_color.g, std::atoi(&commandBuf[1]));
|
||||
return InputEvent{InputEvent::SetColor, m_color};
|
||||
} else if (commandBuf[0] == 'O') {
|
||||
return InputEvent{InputEvent::UserInput, Buttons::Circle};
|
||||
} else if (commandBuf[0] == 'S') {
|
||||
return InputEvent{InputEvent::UserInput, Buttons::Triangle};
|
||||
} else if (commandBuf[0] == 'X') {
|
||||
return InputEvent{InputEvent::UserInput, Buttons::Cross};
|
||||
} else if (commandBuf[0] == '+') {
|
||||
return InputEvent{InputEvent::SetPower, 1};
|
||||
} else if (commandBuf[0] == '-') {
|
||||
return InputEvent{InputEvent::SetPower, 0};
|
||||
} else if (commandBuf[0] == 'p') {
|
||||
return InputEvent{InputEvent::SetPattern, &commandBuf[1]};
|
||||
} else if (commandBuf[0] == 'b') {
|
||||
return InputEvent::BeatDetect;
|
||||
} else if (commandBuf[0] == 'c') {
|
||||
return InputEvent{InputEvent::SetDisplayLength, std::atoi(&commandBuf[1])};
|
||||
} else if (commandBuf[0] == 'Y') {
|
||||
return InputEvent::SaveConfigurationRequest;
|
||||
} else if (commandBuf[0] == 'A') {
|
||||
char* axisVal = strtok(&commandBuf[1], ",");
|
||||
const uint8_t accelX = std::atof(axisVal) * 10;
|
||||
axisVal = strtok(NULL, ",");
|
||||
const uint8_t accelY = std::atof(axisVal) * 10;
|
||||
axisVal = strtok(NULL, ",");
|
||||
const uint8_t accelZ = std::atof(axisVal) * 10;
|
||||
const uint16_t accelSum = abs(accelX) + abs(accelY) + abs(accelZ);
|
||||
const uint16_t delta = abs(m_value.value() - accelSum);
|
||||
m_value.add(accelSum);
|
||||
if (delta > 32) {
|
||||
return InputEvent{InputEvent::Acceleration, delta};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (didRead) {
|
||||
return InputEvent::NetworkActivity;
|
||||
} else {
|
||||
return InputEvent{};
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothSerialTelemetry::onStart()
|
||||
{
|
||||
Log.trace("Starting up Bluetooth...");
|
||||
if (m_serial.begin(Platform::deviceName())) {
|
||||
Log.notice("Bluetooth started! Device name is %s", Platform::deviceName());
|
||||
} else {
|
||||
Log.warning("Bluetooth could not be started!");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC_ALLOC(BluetoothSerialTelemetry);
|
||||
STATIC_TASK(BluetoothSerialTelemetry);
|
||||
41
src/platform/arduino/esp32/BluetoothSerialTelemetry.h
Normal file
41
src/platform/arduino/esp32/BluetoothSerialTelemetry.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <Figments.h>
|
||||
#include <BluetoothSerial.h>
|
||||
#include <Ringbuf.h>
|
||||
|
||||
class BluetoothSerialTelemetry : public InputSource {
|
||||
public:
|
||||
BluetoothSerialTelemetry();
|
||||
void onStart() override;
|
||||
InputEvent read() override;
|
||||
|
||||
template<typename T, uint8_t Size = 8>
|
||||
struct Averager {
|
||||
std::array<T, Size> buf;
|
||||
unsigned int idx = 0;
|
||||
unsigned int count = 0;
|
||||
|
||||
void add(const T &value) {
|
||||
buf[idx] = value;
|
||||
idx = (idx + 1) % Size;
|
||||
if (count < Size) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
T value() const {
|
||||
if (count == 0) {
|
||||
return T{};
|
||||
}
|
||||
long long int sum = 0;
|
||||
for(unsigned int i = 0; i < count; i++) {
|
||||
sum += buf[i];
|
||||
}
|
||||
return sum / count;
|
||||
}
|
||||
};
|
||||
private:
|
||||
BluetoothSerial m_serial;
|
||||
Ringbuf<char, 32> m_ringbuf;
|
||||
CRGB m_color;
|
||||
Averager<int16_t, 32> m_value;
|
||||
};
|
||||
106
src/platform/arduino/esp32/Platform.cpp
Normal file
106
src/platform/arduino/esp32/Platform.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#include "../../../Platform.h"
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <esp_task_wdt.h>
|
||||
|
||||
__NOINIT_ATTR static uint8_t s_rebootCount;
|
||||
__NOINIT_ATTR static uint16_t s_forceSafeMode;
|
||||
#define SAFE_MODE_MAGIC 6942
|
||||
|
||||
template<>
|
||||
void
|
||||
PlatformImpl<HAL_ESP32>::initBootOptions(BootOptions& opts)
|
||||
{
|
||||
opts.resetReason = esp_reset_reason();
|
||||
opts.crashCount = s_rebootCount;
|
||||
if (opts.resetReason >= 4) { // TODO: These values are defined in
|
||||
// esp32/rom/rtc.h, but not sure if that's included
|
||||
// on platformio builds
|
||||
if (opts.crashCount++ >= 3) {
|
||||
// Boot into safe mode if the watchdog reset us three times in a row.
|
||||
isSafeMode = true;
|
||||
}
|
||||
} else {
|
||||
opts.crashCount = 0;
|
||||
}
|
||||
s_rebootCount = crashCount;
|
||||
}
|
||||
|
||||
template<>
|
||||
const char*
|
||||
PlatformImpl<HAL_ESP32>::name()
|
||||
{
|
||||
return "ESP32";
|
||||
}
|
||||
|
||||
template<>
|
||||
const char*
|
||||
PlatformImpl<HAL_ESP32>::version()
|
||||
{
|
||||
return ESP.getSdkVersion();
|
||||
}
|
||||
|
||||
template<>
|
||||
const char*
|
||||
PlatformImpl<HAL_ESP32>::deviceID()
|
||||
{
|
||||
uint64_t chipid;
|
||||
chipid = ESP.getEfuseMac();
|
||||
snprintf(s_deviceID, sizeof(s_deviceID), "%08X", (uint32_t)chipid);
|
||||
return s_deviceID;
|
||||
}
|
||||
|
||||
template<>
|
||||
int
|
||||
PlatformImpl<HAL_ESP32>::freeRam()
|
||||
{
|
||||
return ESP.getFreeHeap();
|
||||
}
|
||||
|
||||
int printEspLog(const char* fmt, va_list args)
|
||||
{
|
||||
Log.notice(fmt, args);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
PlatformImpl<HAL_ESP32>::startWatchdog()
|
||||
{
|
||||
esp_task_wdt_init(10, true);
|
||||
esp_task_wdt_add(NULL);
|
||||
esp_log_set_vprintf(printEspLog);
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
PlatformImpl<HAL_ESP32>::startNTP()
|
||||
{
|
||||
constexpr int dst = 1;
|
||||
configTime(0, 3600 * dst, "pool.ntp.org");
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
PlatformImpl<HAL_ESP32>::loop()
|
||||
{
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
|
||||
template<>
|
||||
bool
|
||||
PlatformImpl<HAL_ESP32>::getLocalTime(struct tm* timedata, int timezone)
|
||||
{
|
||||
time_t rawtime;
|
||||
memset(&rawtime, 0, sizeof(rawtime));
|
||||
time(&rawtime);
|
||||
(*timedata) = (*localtime(&rawtime));
|
||||
return (timedata->tm_year > (2016-1990));
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
PlatformImpl<HAL_ESP32>::restart()
|
||||
{
|
||||
ESP.restart();
|
||||
}
|
||||
238
src/platform/arduino/esp32/U8Display.cpp
Normal file
238
src/platform/arduino/esp32/U8Display.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
#include <Figments.h>
|
||||
#include <U8g2lib.h>
|
||||
#include "../../Static.h"
|
||||
#include <ArduinoLog.h>
|
||||
#include "../../LogService.h"
|
||||
|
||||
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, 16, 15, 4);
|
||||
|
||||
class U8Display : public Task {
|
||||
public:
|
||||
U8Display() : Task("U8Display") {}
|
||||
|
||||
enum ScreenState {
|
||||
BootSplash,
|
||||
Running,
|
||||
Message,
|
||||
Idle = Running
|
||||
};
|
||||
|
||||
void onStart() {
|
||||
Log.trace("display: starting redraw thread");
|
||||
xTaskCreatePinnedToCore(
|
||||
&U8Display::redrawTask,
|
||||
name,
|
||||
2000,
|
||||
this,
|
||||
1,
|
||||
&m_renderTask, 0
|
||||
);
|
||||
}
|
||||
|
||||
void onStop() {
|
||||
Log.trace("display: stopping redraw thread");
|
||||
vTaskDelete(m_renderTask);
|
||||
}
|
||||
|
||||
void handleEvent(const InputEvent& evt) {
|
||||
m_lastEvent = evt;
|
||||
if (m_state == Idle) {
|
||||
switch(evt.intent) {
|
||||
case InputEvent::NetworkStatus:
|
||||
m_nextState = Message;
|
||||
m_message = evt.asBool() ? "Online!" : "Offline :[";
|
||||
break;
|
||||
case InputEvent::SetPattern:
|
||||
m_nextState = Message;
|
||||
m_message = "Pattern: " + String(evt.asString());
|
||||
break;
|
||||
case InputEvent::SetPower:
|
||||
m_nextState = Message;
|
||||
m_message = evt.asBool() ? "Power On" : "Power Off";
|
||||
break;
|
||||
case InputEvent::SaveConfigurationRequest:
|
||||
m_nextState = Message;
|
||||
m_message = "Settings Saved!";
|
||||
break;
|
||||
case InputEvent::FirmwareUpdate:
|
||||
m_nextState = Message;
|
||||
m_message = "Firmware update";
|
||||
break;
|
||||
case InputEvent::PreviousPattern:
|
||||
m_nextState = Message;
|
||||
m_message = "Previous Pattern";
|
||||
break;
|
||||
case InputEvent::NextPattern:
|
||||
m_nextState = Message;
|
||||
m_message = "Next Pattern";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawSplash() {
|
||||
//u8g2.setFont(u8g2_font_VCR_OSD_mr);
|
||||
u8g2.setFont(u8g2_font_HelvetiPixelOutline_tr);
|
||||
u8g2.setDrawColor(1);
|
||||
uint8_t splashWidth = u8g2.getStrWidth("Renderbug!");
|
||||
u8g2.drawStr(64 - splashWidth / 2, 32 - 15, "Renderbug!");
|
||||
u8g2.setFont(u8g2_font_7x13B_mr);
|
||||
u8g2.setCursor(15, 64 - 7);
|
||||
u8g2.print("Version ");
|
||||
u8g2.print(RENDERBUG_VERSION);
|
||||
|
||||
for(int i = 0; i < 3; i++) {
|
||||
uint8_t sparkleX = (64 - splashWidth/2) + scale8(7-i, beatsin8(40)) * (splashWidth/7) + 5;
|
||||
uint8_t sparkleY = scale8(3+i, beatsin8(40)) * 3 + 7;
|
||||
u8g2.setDrawColor(2);
|
||||
if (beatsin8(60*4) + i * 3 >= 170) {
|
||||
u8g2.drawLine(sparkleX - 3, sparkleY - 3, sparkleX + 3, sparkleY + 3);
|
||||
u8g2.drawLine(sparkleX + 3, sparkleY - 3, sparkleX - 3, sparkleY + 3);
|
||||
} else if (beatsin8(60*4) + i * 2 >= 82) {
|
||||
u8g2.drawLine(sparkleX - 4, sparkleY - 4, sparkleX + 2, sparkleY + 2);
|
||||
u8g2.drawLine(sparkleX - 2, sparkleY - 2, sparkleX + 4, sparkleY + 4);
|
||||
u8g2.drawLine(sparkleX + 4, sparkleY - 4, sparkleX - 2, sparkleY + 2);
|
||||
u8g2.drawLine(sparkleX + 2, sparkleY - 2, sparkleX - 4, sparkleY + 4);
|
||||
} else {
|
||||
u8g2.drawLine(sparkleX - 2, sparkleY, sparkleX + 2, sparkleY);
|
||||
u8g2.drawLine(sparkleX, sparkleY - 2, sparkleX, sparkleY + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawMessage() {
|
||||
//u8g2.setFont(u8g2_font_VCR_OSD_mr);
|
||||
u8g2.setFont(u8g2_font_HelvetiPixelOutline_tr);
|
||||
uint8_t splashWidth = u8g2.getStrWidth(m_message.c_str());
|
||||
if (splashWidth >= 128) {
|
||||
u8g2.setFont(u8g2_font_7x13B_mr);
|
||||
splashWidth = u8g2.getStrWidth(m_message.c_str());
|
||||
}
|
||||
u8g2.drawStr(64 - splashWidth / 2, 32 - 15, m_message.c_str());
|
||||
}
|
||||
|
||||
void drawTime() {
|
||||
u8g2.setFont(u8g2_font_7x13O_tn);
|
||||
u8g2.setCursor(0, 64);
|
||||
struct tm timeinfo;
|
||||
Platform::getLocalTime(&timeinfo);
|
||||
uint8_t hour = timeinfo.tm_hour;
|
||||
uint8_t minute = timeinfo.tm_min;
|
||||
u8g2.print(hour);
|
||||
u8g2.print(":");
|
||||
u8g2.print(minute);
|
||||
}
|
||||
|
||||
void drawState(ScreenState state) {
|
||||
switch(state) {
|
||||
case BootSplash:
|
||||
drawSplash();
|
||||
break;
|
||||
case Message:
|
||||
drawMessage();
|
||||
break;
|
||||
case Running:
|
||||
uint8_t y = 11;
|
||||
u8g2.setFont(u8g2_font_7x13B_mr);
|
||||
u8g2.setCursor(0, y);
|
||||
u8g2.print("FPS: ");
|
||||
u8g2.setFont(u8g2_font_7x13O_tn);
|
||||
u8g2.print(FastLED.getFPS());
|
||||
y += 12;
|
||||
u8g2.setCursor(0, y);
|
||||
u8g2.setFont(u8g2_font_7x13B_mr);
|
||||
u8g2.print("Last event: ");
|
||||
y += 7;
|
||||
u8g2.setCursor(10, y);
|
||||
u8g2.setFont(u8g2_font_4x6_tr);
|
||||
const char* intentName = LogService::intentName(m_lastEvent.intent);
|
||||
if (intentName) {
|
||||
u8g2.print(intentName);
|
||||
} else {
|
||||
u8g2.print("<");
|
||||
u8g2.print(m_lastEvent.intent);
|
||||
u8g2.print(">");
|
||||
}
|
||||
y += 12;
|
||||
u8g2.setCursor(15, y);
|
||||
u8g2.setFont(u8g2_font_7x13O_tf);
|
||||
u8g2.print(LogService::eventValue(m_lastEvent));
|
||||
drawTime();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
EVERY_N_MILLISECONDS(8) {
|
||||
xTaskNotifyGive(m_renderTask);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ScreenState m_state = BootSplash;
|
||||
ScreenState m_nextState = BootSplash;
|
||||
uint8_t m_transitionFrame = 0;
|
||||
uint8_t m_screenStartTime = 0;
|
||||
InputEvent m_lastEvent;
|
||||
String m_message;
|
||||
|
||||
TaskHandle_t m_renderTask;
|
||||
void redraw() {
|
||||
if (m_state != m_nextState) {
|
||||
EVERY_N_MILLISECONDS(8) {
|
||||
constexpr uint8_t speed = 11;
|
||||
if (m_transitionFrame <= 255 - speed) {
|
||||
m_transitionFrame += speed;
|
||||
} else {
|
||||
m_transitionFrame = 255;
|
||||
}
|
||||
uint8_t offset = ease8InOutApprox(m_transitionFrame);
|
||||
u8g2.clearBuffer();
|
||||
if (m_transitionFrame <= 128) {
|
||||
uint8_t width = scale8(128, offset * 2);
|
||||
u8g2.setDrawColor(1);
|
||||
drawState(m_state);
|
||||
u8g2.drawBox(0, 0, width, 64);
|
||||
u8g2.setDrawColor(2);
|
||||
u8g2.drawBox(width, 0, 8, 64);
|
||||
} else {
|
||||
uint8_t width = scale8(128, offset/2)*2;
|
||||
u8g2.setDrawColor(1);
|
||||
drawState(m_nextState);
|
||||
u8g2.setDrawColor(2);
|
||||
u8g2.drawBox(std::max(0, width - 8), 0, 8, 64);
|
||||
u8g2.setDrawColor(1);
|
||||
u8g2.drawBox(width, 0, 128, 64);
|
||||
}
|
||||
u8g2.sendBuffer();
|
||||
|
||||
if (m_transitionFrame == 255) {
|
||||
m_state = m_nextState;
|
||||
m_screenStartTime = millis();
|
||||
m_transitionFrame = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
u8g2.clearBuffer();
|
||||
drawState(m_state);
|
||||
u8g2.sendBuffer();
|
||||
uint16_t screenTime = millis() - m_screenStartTime;
|
||||
if (screenTime >= 7000 && m_state != Idle) {
|
||||
m_nextState = Idle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void redrawTask(void* data) {
|
||||
u8g2.begin();
|
||||
U8Display* self = static_cast<U8Display*>(data);
|
||||
self->m_screenStartTime = millis();
|
||||
while (true) {
|
||||
self->redraw();
|
||||
ulTaskNotifyTake(0, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
STATIC_ALLOC(U8Display);
|
||||
STATIC_TASK(U8Display);
|
||||
Reference in New Issue
Block a user