Cleaned up repository
- only moving files around
This commit is contained in:
249
esp-firmware/src/Messages.h
Normal file
249
esp-firmware/src/Messages.h
Normal 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
129
esp-firmware/src/TaskLed.h
Normal 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);
|
||||
}
|
||||
120
esp-firmware/src/host_test.cpp
Normal file
120
esp-firmware/src/host_test.cpp
Normal 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
241
esp-firmware/src/main.cpp
Normal 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();
|
||||
}
|
||||
64
esp-firmware/src/mfrc_version.h
Normal file
64
esp-firmware/src/mfrc_version.h
Normal 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();
|
||||
}
|
||||
Reference in New Issue
Block a user