Cleaned up repository

- only moving files around
This commit is contained in:
2026-08-25 17:06:32 +02:00
parent b2c060fcc9
commit bd8925a278
87 changed files with 512097 additions and 74 deletions

249
esp-firmware/src/Messages.h Normal file
View File

@@ -0,0 +1,249 @@
#include "effects/Circular.h"
#include "effects/Static.h"
#include "effects/AlexaSwipe.h"
#include "effects/ReverseSwipe.h"
#include "effects/RandomTwoColorInterpolation.h"
#include "effects/SwipeAndChange.h"
#include "Arduino.h"
#include <cstdint>
constexpr uint32_t MAGIC_TOKEN_HOST_TO_FW = 0x1d6379e3;
constexpr uint32_t MAGIC_TOKEN_FW_TO_HOST = 0x10c65631;
template <typename T>
struct ClassToMessageType
{
};
enum class MessageFwToHost : uint8_t
{
RFID_TOKEN_READ = 0,
ROTARY_ENCODER = 1,
TOUCH_BUTTON_PRESS = 2,
TOUCH_BUTTON_RELEASE = 3,
BUTTON_EVENT = 4,
};
enum class TouchButton : uint8_t
{
LEFT_FOOT = 0,
RIGHT_FOOT = 1,
LEFT_EAR = 2,
RIGHT_EAR = 3
};
#pragma pack(push, 1)
struct MsgRfidTokenRead
{
uint8_t tagId[5];
};
struct MsgRotaryEncoder
{
int32_t position;
int32_t increment;
uint8_t direction;
};
struct MsgTouchButtonPress
{
TouchButton button;
};
struct MsgTouchButtonRelease
{
TouchButton button;
};
struct MsgButtonEvent
{
uint8_t buttonNr;
uint8_t eventType;
};
#pragma pack(pop)
template <>
struct ClassToMessageType<MsgRfidTokenRead>
{
static constexpr auto msgType = MessageFwToHost::RFID_TOKEN_READ;
};
template <>
struct ClassToMessageType<MsgRotaryEncoder>
{
static constexpr auto msgType = MessageFwToHost::ROTARY_ENCODER;
};
template <>
struct ClassToMessageType<MsgTouchButtonPress>
{
static constexpr auto msgType = MessageFwToHost::TOUCH_BUTTON_PRESS;
};
template <>
struct ClassToMessageType<MsgTouchButtonRelease>
{
static constexpr auto msgType = MessageFwToHost::TOUCH_BUTTON_RELEASE;
};
template <>
struct ClassToMessageType<MsgButtonEvent>
{
static constexpr auto msgType = MessageFwToHost::BUTTON_EVENT;
};
//----------------------------------------------------------------------------------------------------
enum class MessageHostToFw : uint8_t
{
LED_WHEEL_EFFECT_STATIC = 0,
LED_WHEEL_EFFECT_ALEXA_SWIPE = 1,
LED_WHEEL_EFFECT_CIRCULAR = 2,
LED_WHEEL_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION = 3,
LED_WHEEL_EFFECT_SWIPE_AND_CHANGE = 4,
LED_WHEEL_EFFECT_REVERSE_SWIPE = 5,
MOUSE_LED_EFFECT_STATIC = 6,
MOUSE_LED_EFFECT_CIRCULAR = 7,
MOUSE_LED_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION = 8,
MOUSE_LED_EFFECT_SWIPE_AND_CHANGE = 9,
MOUSE_LED_EFFECT_REVERSE_SWIPE = 10,
SHELF_LED_EFFECT_STATIC = 15,
SHELF_LED_EFFECT_CIRCULAR = 16,
SHELF_LED_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION = 17,
SHELF_LED_EFFECT_SWIPE_AND_CHANGE = 18,
SHELF_LED_EFFECT_REVERSE_SWIPE = 19,
SHELF_LED_EFFECT_STATIC_DETAILED = 20,
PREV_BUTTON_LED = 21,
NEXT_BUTTON_LED = 22,
};
template <>
struct ClassToMessageType<EffectStaticConfig>
{
static constexpr auto msgType = MessageHostToFw::LED_WHEEL_EFFECT_STATIC;
};
template <>
struct ClassToMessageType<EffectAlexaSwipeConfig>
{
static constexpr auto msgType = MessageHostToFw::LED_WHEEL_EFFECT_ALEXA_SWIPE;
};
template <>
struct ClassToMessageType<EffectCircularConfig>
{
static constexpr auto msgType = MessageHostToFw::LED_WHEEL_EFFECT_CIRCULAR;
};
template <>
struct ClassToMessageType<EffectRandomTwoColorInterpolationConfig>
{
static constexpr auto msgType = MessageHostToFw::LED_WHEEL_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION;
};
template <>
struct ClassToMessageType<EffectSwipeAndChangeConfig>
{
static constexpr auto msgType = MessageHostToFw::LED_WHEEL_EFFECT_SWIPE_AND_CHANGE;
};
//----------------------------------------------------------------------------------------------------
template <typename TMessage>
void sendMessageToHost(const TMessage &msg)
{
Serial.write((uint8_t *)&MAGIC_TOKEN_FW_TO_HOST, sizeof(MAGIC_TOKEN_FW_TO_HOST));
MessageFwToHost msgType = ClassToMessageType<TMessage>::msgType;
Serial.write((uint8_t *)&msgType, sizeof(msgType));
uint16_t msgSize = sizeof(msg);
Serial.write((uint8_t *)&msgSize, sizeof(msgSize));
Serial.write((uint8_t *)&msg, sizeof(msg));
}
template <typename TEffectConfig, typename TLedTask>
inline bool handleLedEffect(TLedTask *ledTask, MessageHostToFw msgType, MessageHostToFw incomingMsgType, uint8_t *msgBuffer)
{
if (msgType == incomingMsgType)
{
auto cfg = reinterpret_cast<TEffectConfig *>(msgBuffer);
ledTask->startEffect(*cfg);
return true;
}
else
return false;
}
template <typename LedTask1, typename LedTask2, typename LedTaskShelf>
inline void handleIncomingMessagesFromHost(LedTask1 *ledTaskCircle, LedTask2 *ledTaskMouse, LedTaskShelf *ledTaskShelf, uint8_t ledChannelLeft, uint8_t ledChannelRight)
{
if (Serial.available() < sizeof(MAGIC_TOKEN_FW_TO_HOST) + sizeof(MessageHostToFw) + sizeof(uint16_t))
return;
uint32_t token;
Serial.readBytes((uint8_t *)(&token), sizeof(token));
if (token != MAGIC_TOKEN_HOST_TO_FW)
{
Serial.println("Received invalid message");
return;
}
MessageHostToFw msgType;
Serial.readBytes((uint8_t *)(&msgType), sizeof(msgType));
uint16_t msgSize;
Serial.readBytes((uint8_t *)(&msgSize), sizeof(msgSize));
static constexpr int maxIncomingBufferSize = 1024;
static uint8_t msgBuffer[maxIncomingBufferSize];
if (msgSize < maxIncomingBufferSize)
{
Serial.readBytes(msgBuffer, msgSize);
// clang-format off
// LED Circle
if(handleLedEffect<EffectStaticConfig >(ledTaskCircle, MessageHostToFw::LED_WHEEL_EFFECT_STATIC, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectAlexaSwipeConfig >(ledTaskCircle, MessageHostToFw::LED_WHEEL_EFFECT_ALEXA_SWIPE, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectCircularConfig >(ledTaskCircle, MessageHostToFw::LED_WHEEL_EFFECT_CIRCULAR, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectRandomTwoColorInterpolationConfig>(ledTaskCircle, MessageHostToFw::LED_WHEEL_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectSwipeAndChangeConfig >(ledTaskCircle, MessageHostToFw::LED_WHEEL_EFFECT_SWIPE_AND_CHANGE, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectReverseSwipeConfig >(ledTaskCircle, MessageHostToFw::LED_WHEEL_EFFECT_REVERSE_SWIPE, msgType, msgBuffer)) {}
// Mouse LEDs
else if(handleLedEffect<EffectStaticConfig >(ledTaskMouse, MessageHostToFw::MOUSE_LED_EFFECT_STATIC, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectCircularConfig >(ledTaskMouse, MessageHostToFw::MOUSE_LED_EFFECT_CIRCULAR, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectRandomTwoColorInterpolationConfig>(ledTaskMouse, MessageHostToFw::MOUSE_LED_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectSwipeAndChangeConfig >(ledTaskMouse, MessageHostToFw::MOUSE_LED_EFFECT_SWIPE_AND_CHANGE, msgType, msgBuffer)) {}
else if(handleLedEffect<EffectReverseSwipeConfig >(ledTaskMouse, MessageHostToFw::MOUSE_LED_EFFECT_REVERSE_SWIPE, msgType, msgBuffer)) {}
// Shelf LEDs
else if (handleLedEffect<EffectStaticConfig >(ledTaskShelf, MessageHostToFw::SHELF_LED_EFFECT_STATIC, msgType, msgBuffer)) {}
else if (handleLedEffect<EffectCircularConfig >(ledTaskShelf, MessageHostToFw::SHELF_LED_EFFECT_CIRCULAR, msgType, msgBuffer)) {}
else if (handleLedEffect<EffectRandomTwoColorInterpolationConfig>(ledTaskShelf, MessageHostToFw::SHELF_LED_EFFECT_RANDOM_TWO_COLOR_INTERPOLATION, msgType, msgBuffer)) {}
else if (handleLedEffect<EffectSwipeAndChangeConfig >(ledTaskShelf, MessageHostToFw::SHELF_LED_EFFECT_SWIPE_AND_CHANGE, msgType, msgBuffer)) {}
else if (handleLedEffect<EffectReverseSwipeConfig >(ledTaskShelf, MessageHostToFw::SHELF_LED_EFFECT_REVERSE_SWIPE, msgType, msgBuffer)) {}
else if (handleLedEffect<EffectStaticDetailedConfig >(ledTaskShelf, MessageHostToFw::SHELF_LED_EFFECT_STATIC_DETAILED, msgType, msgBuffer)) {}
// clang-format on
else if (msgType == MessageHostToFw::PREV_BUTTON_LED)
{
float *val = reinterpret_cast<float *>(msgBuffer);
ledcWrite(ledChannelLeft, uint32_t(255 * (*val)));
}
else if (msgType == MessageHostToFw::NEXT_BUTTON_LED)
{
float *val = reinterpret_cast<float *>(msgBuffer);
ledcWrite(ledChannelRight, uint32_t(255 * (*val)));
}
else
Serial.println("Unknown message type");
}
else
Serial.printf("Incoming message too large (or invalid) %d\n", msgSize);
}

129
esp-firmware/src/TaskLed.h Normal file
View File

@@ -0,0 +1,129 @@
#pragma once
#include "effects/Circular.h"
#include "effects/Common.h"
#include "drivers/Esp32DriverRGBW.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include <functional>
#include <cstring>
static constexpr int MAX_EFFECT_CONFIG_SIZE = 128;
static constexpr int MAX_EFFECT_CLASS_SIZE = 8 * 1024;
template <typename TLedStrip>
class LedTask
{
public:
void begin(TLedStrip &strip, Esp32DriverRGBW &driver);
template <typename TEffectConfig>
void startEffect(const TEffectConfig &cfg);
private:
template <typename T>
friend void _led_task_func(void *);
QueueHandle_t queue_ = nullptr;
TLedStrip *ledStrip_ = nullptr;
Esp32DriverRGBW *driver_ = nullptr;
};
// -----------------------------------------------------------------------------------------------
template <EffectId staticEffectId, typename TLedStrip>
bool dispatchEffectId(EffectId dynamicEffectId, std::function<int()> &effectFunction, TLedStrip &ledStrip,
unsigned char *msgBuffer, unsigned char *effectStorage)
{
if (staticEffectId == dynamicEffectId)
{
typename EffectIdToConfig<staticEffectId>::type cfg;
memcpy(&cfg, msgBuffer + sizeof(EffectId), sizeof(decltype(cfg)));
using TEffect = typename EffectIdToClass<staticEffectId, TLedStrip>::type;
static_assert(sizeof(TEffect) < MAX_EFFECT_CLASS_SIZE, "Effect to big for effectStorage, increase MAX_EFFECT_CLASS_SIZE");
TEffect *effect = new (effectStorage) TEffect(cfg, ledStrip);
effectFunction = [effect]()
{ return (*effect)(); };
return true;
}
else
return false;
}
template <typename TLedStrip>
void _led_task_func(void *params)
{
LedTask<TLedStrip> *task = reinterpret_cast<LedTask<TLedStrip> *>(params);
unsigned char msgBuffer[MAX_EFFECT_CONFIG_SIZE];
unsigned char effectStorage[MAX_EFFECT_CLASS_SIZE];
std::function<int()> effectFunction = []() -> int
{ return 100000; };
int timeoutMsForEffect = 100000; // huge timeout since there is no effect in the beginning
while (true)
{
if (xQueueReceive(task->queue_, msgBuffer, (TickType_t)(timeoutMsForEffect / portTICK_PERIOD_MS)) == pdTRUE)
{
// Read and parse effect from queue
EffectId id;
memcpy(&id, msgBuffer, sizeof(EffectId));
TLedStrip &ledStrip = *(task->ledStrip_);
// clang-format off
if (dispatchEffectId<EffectId::CIRCULAR >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
else if (dispatchEffectId<EffectId::STATIC >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
else if (dispatchEffectId<EffectId::STATIC_DETAILED >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
else if (dispatchEffectId<EffectId::ALEXA_SWIPE >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
else if (dispatchEffectId<EffectId::RANDOM_TWO_COLOR_INTERPOLATION>(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
else if (dispatchEffectId<EffectId::SWIPE_AND_CHANGE >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
else if (dispatchEffectId<EffectId::REVERSE_SWIPE >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
// clang-format on
timeoutMsForEffect = 0;
}
else
{
timeoutMsForEffect = effectFunction();
task->driver_->writeSync(task->ledStrip_->rawData(), task->ledStrip_->numLeds());
}
}
}
template <typename TLedStrip>
void LedTask<TLedStrip>::begin(TLedStrip &strip, Esp32DriverRGBW &driver)
{
queue_ = xQueueCreate(4, MAX_EFFECT_CONFIG_SIZE);
if (!queue_)
Serial.println("Failed to create LED effect queue");
ledStrip_ = &strip;
driver_ = &driver;
xTaskCreate(_led_task_func<TLedStrip>, "led task", MAX_EFFECT_CLASS_SIZE + MAX_EFFECT_CONFIG_SIZE + 2048 * 2,
(void *)(this), 1, nullptr);
}
template <typename TLedStrip>
template <typename TEffectConfig>
void LedTask<TLedStrip>::startEffect(const TEffectConfig &cfg)
{
static constexpr auto msgSize = sizeof(TEffectConfig) + sizeof(EffectId);
static_assert(msgSize < MAX_EFFECT_CONFIG_SIZE,
"Effect config too large, increase MAX_EFFECT_CONFIG_SIZE");
unsigned char buffer[MAX_EFFECT_CONFIG_SIZE];
if (queue_ == nullptr)
{
Serial.println("Trying to start effect before queue was set up!");
return;
}
EffectId id = EffectConfigToId<TEffectConfig>::id;
memcpy(buffer, &id, sizeof(EffectId));
memcpy(buffer + sizeof(EffectId), &cfg, sizeof(TEffectConfig));
xQueueSend(queue_, (void *)buffer, (TickType_t)10);
}

View File

@@ -0,0 +1,120 @@
#include "containers/LedStripRGBW.h"
#include "effects/AlexaSwipe.h"
#include "effects/ReverseSwipe.h"
#include "helpers/ColorConversions.h"
#include <iostream>
#include <vector>
#include <fstream>
template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &vec)
{
os << "[";
for (const auto &e : vec)
{
if (std::is_same<uint8_t, T>::value)
os << int(e) << ",";
else
os << e << ",";
}
os << "]";
return os;
}
template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<std::vector<T>> &vec)
{
os << "[";
for (const auto &e : vec)
os << e << ",";
os << "]";
return os;
}
template <typename TEffect, int NLeds>
void effectToFile(const std::string &filename, TEffect &effect, LedStripRGBW<NLeds> &strip, int calls = 100)
{
std::vector<std::vector<uint8_t>> vr(calls);
std::vector<std::vector<uint8_t>> vg(calls);
std::vector<std::vector<uint8_t>> vb(calls);
std::vector<std::vector<float>> vh(calls);
std::vector<std::vector<float>> vs(calls);
std::vector<std::vector<float>> vv(calls);
for (int time = 0; time < calls; ++time)
{
effect();
vr[time].resize(NLeds);
vg[time].resize(NLeds);
vb[time].resize(NLeds);
vh[time].resize(NLeds);
vs[time].resize(NLeds);
vv[time].resize(NLeds);
for (int i = 0; i < NLeds; ++i)
{
uint8_t r, g, b, w;
strip.getRGBW(i, r, g, b, w);
vr[time][i] = r;
vg[time][i] = g;
vb[time][i] = b;
auto hsv = rgb2hsv(ColorRGBW{r, g, b, w});
vh[time][i] = hsv.h;
vs[time][i] = hsv.s;
vv[time][i] = hsv.v;
}
}
std::ofstream fs(filename.c_str());
fs << "r = " << vr << "\n";
fs << "g = " << vg << "\n";
fs << "b = " << vb << "\n";
fs << "h = " << vh << "\n";
fs << "s = " << vs << "\n";
fs << "v = " << vv << "\n";
}
int main(int argc, char **argv)
{
{
auto cfg = EffectAlexaSwipeConfig{20.f, 20.f, 90.f, 5.f, 180, true, ColorRGBW{255, 0, 0, 0}, ColorRGBW{255, 0, 0, 0}};
LedStripRGBW<51> strip;
EffectAlexaSwipe<decltype(strip)> effect(cfg, strip);
effectToFile("swipe.py", effect, strip, 200);
}
{
auto cfg = EffectReverseSwipeConfig{360.f, 5.f, 180};
LedStripRGBW<51> strip;
for (int i = 0; i < strip.numLeds(); ++i)
setLedRGBW(strip, i, ColorRGBW{255, 255, 255, 0});
EffectReverseSwipe<decltype(strip)> effect(cfg, strip);
effectToFile("reverse_swipe.py", effect, strip, 200);
}
/*
effect.currentPosition_ = 150;
const auto numLeds = strip.numLeds() / 2;
std::vector<float> brightness(numLeds, 0);
std::vector<float> interpolation(numLeds, 0);
for (int i = 0; i < numLeds; ++i)
effect.getParams(float(i), interpolation[i], brightness[i]);
printVec(brightness);
printVec(interpolation);
effect();
*/
return 0;
}

241
esp-firmware/src/main.cpp Normal file
View File

@@ -0,0 +1,241 @@
#include <Arduino.h>
#include "rc522.h"
#include "SPI.h"
#include <MFRC522.h>
#include "rotary_encoder.h"
#include "containers/LedStripRGBW.h"
#include "drivers/Esp32DriverRGBW.h"
#include "effects/Circular.h"
#include "effects/Static.h"
#include "effects/StaticDetailed.h"
#include "effects/AlexaSwipe.h"
#include "effects/RandomTwoColorInterpolation.h"
#include "AceButton.h"
#include "driver/touch_pad.h"
#include "Messages.h"
#include "TaskLed.h"
// -------------------------------------------------- RFID Reader ----------------------------------------
MFRC522 rfid;
MFRC522::MIFARE_Key key;
void tagHandler(uint8_t *sn)
{
if (sn != nullptr)
sendMessageToHost(MsgRfidTokenRead{{sn[0], sn[1], sn[2], sn[3], sn[4]}});
else
sendMessageToHost(MsgRfidTokenRead{{0, 0, 0, 0, 0}});
}
void setupRfidReader()
{
const rc522_start_args_t start_args = {
21, // MISO
5, // MOSI
18, // SCK
19, // SDA
VSPI_HOST,
&tagHandler,
125, // scan_interval_ms
8 * 1024, // stacksize
4 // task priority
};
rc522_start(start_args);
}
// -------------------------------------------------- Rotary Enc ----------------------------------------
QueueHandle_t eventQueueRotaryEncoder;
rotary_encoder_info_t info;
void setupRotaryEncoder()
{
ESP_ERROR_CHECK(gpio_install_isr_service(0));
ESP_ERROR_CHECK(rotary_encoder_init(&info, GPIO_NUM_26, GPIO_NUM_27));
ESP_ERROR_CHECK(rotary_encoder_enable_half_steps(&info, false));
eventQueueRotaryEncoder = rotary_encoder_create_queue();
ESP_ERROR_CHECK(rotary_encoder_set_queue(&info, eventQueueRotaryEncoder));
}
int32_t lastRotaryPosition = 0;
bool lastRotaryPositionValid = false;
void handleRotaryEncoder()
{
rotary_encoder_event_t event = {0};
if (xQueueReceive(eventQueueRotaryEncoder, &event, 0) == pdTRUE)
{
int32_t increment = 0;
if (lastRotaryPositionValid)
increment = lastRotaryPosition - event.state.position;
sendMessageToHost(MsgRotaryEncoder{event.state.position, increment, (uint8_t)(event.state.direction)});
lastRotaryPositionValid = true;
lastRotaryPosition = event.state.position;
}
}
// -------------------------------------------------- Buttons ----------------------------------------
constexpr int BUTTON_RIGHT_PIN = 25;
constexpr int BUTTON_LEFT_PIN = 14;
constexpr int ROTARY_PRESS_PIN = 13;
constexpr int BUTTON_RIGHT_LED_PIN = 33;
constexpr int BUTTON_LEFT_LED_PIN = 12;
constexpr int PWM_FREQ = 5000;
constexpr int PWM_RESOLUTION = 8;
using ace_button::AceButton;
AceButton buttonLeft(BUTTON_LEFT_PIN);
AceButton buttonRight(BUTTON_RIGHT_PIN);
AceButton buttonRotary(ROTARY_PRESS_PIN);
void handleButtonEvent(AceButton *button, uint8_t eventType, uint8_t /*buttonState*/)
{
uint8_t buttonNr = 0;
if (button == &buttonLeft)
buttonNr = 1;
else if (button == &buttonRight)
buttonNr = 2;
else if (button == &buttonRotary)
buttonNr = 3;
sendMessageToHost(MsgButtonEvent{buttonNr, eventType});
}
void setupButtons()
{
pinMode(BUTTON_RIGHT_PIN, INPUT_PULLUP);
pinMode(BUTTON_LEFT_PIN, INPUT_PULLUP);
pinMode(ROTARY_PRESS_PIN, INPUT_PULLUP);
pinMode(BUTTON_RIGHT_LED_PIN, OUTPUT);
pinMode(BUTTON_LEFT_LED_PIN, OUTPUT);
buttonLeft.setEventHandler(handleButtonEvent);
buttonRight.setEventHandler(handleButtonEvent);
buttonRotary.setEventHandler(handleButtonEvent);
ledcSetup(0, PWM_FREQ, PWM_RESOLUTION);
ledcAttachPin(BUTTON_LEFT_LED_PIN, 0);
ledcSetup(1, PWM_FREQ, PWM_RESOLUTION);
ledcAttachPin(BUTTON_RIGHT_LED_PIN, 1);
}
void handleButtons()
{
buttonLeft.check();
buttonRight.check();
buttonRotary.check();
}
// -------------------------------------------------- Led circle ------------------------------------------
LedStripRGBW<51> ledStripCircle;
Esp32DriverRGBW ledDriverCircle;
LedTask<decltype(ledStripCircle)> ledTaskCircle;
void setupLedCircle()
{
ledDriverCircle.begin(22, 0);
ledTaskCircle.begin(ledStripCircle, ledDriverCircle);
ledTaskCircle.startEffect(EffectStaticConfig(ColorRGBW{0, 0, 0, 0}));
}
// -------------------------------------------------- Mouse Leds -- ----------------------------------------
LedStripRGBW<12 + 16 + 17> ledStripMouse;
Esp32DriverRGBW ledDriverMouse;
LedTask<decltype(ledStripMouse)> ledTaskMouse;
void setupMouseLeds()
{
ledDriverMouse.begin(16, 1);
ledTaskMouse.begin(ledStripMouse, ledDriverMouse);
ledTaskMouse.startEffect(EffectStaticConfig{ColorRGBW{0, 0, 0, 0}, 0, 0});
}
// -------------------------------------------------- Shelf Leds -------------------------------------------
LedStripRGBW<252> ledStripShelf;
Esp32DriverRGBW ledDriverShelf;
LedTask<decltype(ledStripShelf)> ledTaskShelf;
void setupShelfLeds()
{
ledDriverShelf.begin(17, 2);
ledTaskShelf.begin(ledStripShelf, ledDriverShelf);
ledTaskShelf.startEffect(EffectStaticConfig{ColorRGBW{0, 0, 0, 0}, 0, 0});
}
// -------------------------------------------------- Touch Buttons ----------------------------------------
constexpr auto TOUCH_PAD_RIGHT_EAR = TOUCH_PAD_NUM0;
constexpr auto TOUCH_PAD_LEFT_EAR = TOUCH_PAD_NUM9;
constexpr auto TOUCH_PAD_RIGHT_FOOT = TOUCH_PAD_NUM2;
constexpr auto TOUCH_PAD_LEFT_FOOT = TOUCH_PAD_NUM3;
void setupTouchButtons()
{
touch_pad_init();
touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V);
for (auto pad : {TOUCH_PAD_RIGHT_EAR, TOUCH_PAD_LEFT_EAR, TOUCH_PAD_RIGHT_FOOT, TOUCH_PAD_LEFT_FOOT})
touch_pad_config(pad, 0);
touch_pad_filter_start(2);
}
void handleTouchInputs()
{
static bool previousState[4];
uint16_t touchLeftEar = 0;
uint16_t touchRightEar = 0;
uint16_t touchLeftFoot = 0;
uint16_t touchRightFoot = 0;
touch_pad_read(TOUCH_PAD_LEFT_FOOT, &touchLeftFoot);
touch_pad_read(TOUCH_PAD_RIGHT_FOOT, &touchRightFoot);
touch_pad_read(TOUCH_PAD_LEFT_EAR, &touchLeftEar);
touch_pad_read(TOUCH_PAD_RIGHT_EAR, &touchRightEar);
//Serial.printf("Feet %d %d, Ears %d, %d\n", touchLeftFoot, touchRightFoot, touchLeftEar, touchRightEar);
//delay(100);
bool currentState[4];
currentState[int(TouchButton::LEFT_FOOT)] = touchLeftFoot < 380;
currentState[int(TouchButton::RIGHT_FOOT)] = touchRightFoot < 380;
currentState[int(TouchButton::LEFT_EAR)] = touchLeftEar < 430;
currentState[int(TouchButton::RIGHT_EAR)] = touchRightEar < 400;
for (int i = 0; i < 4; ++i)
{
if (previousState[i] == false && currentState[i] == true)
sendMessageToHost(MsgTouchButtonPress{TouchButton(i)});
else if (previousState[i] == true && currentState[i] == false)
sendMessageToHost(MsgTouchButtonRelease{TouchButton(i)});
previousState[i] = currentState[i];
}
}
//-------------------------------------------------------------------------------------------------------
void setup()
{
Serial.begin(115200);
setupRfidReader();
setupRotaryEncoder();
setupLedCircle();
setupButtons();
setupTouchButtons();
setupMouseLeds();
setupShelfLeds();
}
void loop()
{
handleIncomingMessagesFromHost(&ledTaskCircle, &ledTaskMouse, &ledTaskShelf, 0, 1);
handleTouchInputs();
handleRotaryEncoder();
handleButtons();
}

View File

@@ -0,0 +1,64 @@
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 5 // Configurable, see typical pin layout above
#define SS_PIN 23 // Configurable, see typical pin layout above
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
//*****************************************************************************************//
void setup() {
Serial.begin(115200);
SPI.begin(22, 19, 18, 23); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522 card
}
/**
* Helper routine to dump a byte array as hex values to Serial.
*/
void PrintHex(byte *buffer, byte bufferSize) {
for (byte i = 0; i < bufferSize; i++) {
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
}
}
//*****************************************************************************************//
void loop() {
// Look for new cards
if ( !mfrc522.PICC_IsNewCardPresent()) {
return;
}
if ( !mfrc522.PICC_ReadCardSerial()) {
return;
}
//mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); //dump some details about the card
Serial.print("NewCard");
PrintHex(mfrc522.uid.uidByte, mfrc522.uid.size);
Serial.println("");
// Check if Card was removed
bool cardRemoved = false;
int counter = 0;
bool current, previous;
previous = !mfrc522.PICC_IsNewCardPresent();
while(!cardRemoved){
current =!mfrc522.PICC_IsNewCardPresent();
if (current && previous) counter++;
previous = current;
cardRemoved = (counter>2);
delay(50);
}
Serial.println("Card was removed");
delay(500); //change value if you want to read cards faster
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
}