#pragma once #include struct MaskCoordinateMapping : CoordinateMapping { struct Span { int length = 0; int x = 0; int y = 0; Span(int length, int x, int y) : length(length), x(x), y(y) {} }; Span displayMap[13] = { {6, 0, 6}, {6, 1, 6}, {7, 2, 6}, {9, 3, 4}, {14, 4, 4}, {17, 5, 0}, {12, 6, 2}, {18, 7, 0}, {14, 8, 4}, {9, 9, 5}, {7, 10, 4}, {6, 11, 5}, {6, 12, 5} }; VirtualCoordinates physicalToVirtualCoords(const PhysicalCoordinates localCoords) const override { int offset = localCoords.x; for(int i = 0; i < 12; i++) { if (offset > displayMap[i].length) { offset -= displayMap[i].length; } else { return VirtualCoordinates{i, offset}; } } } PhysicalCoordinates virtualToPhysicalCoords(const VirtualCoordinates virtualCoords) const override { const uint8_t spanIdx = scale8(12, virtualCoords.x); const uint8_t spanOffset = scale8(17, virtualCoords.y); return PhysicalCoordinates{spanIdx, spanOffset}; } int physicalCoordsToIndex(const PhysicalCoordinates localCoords) const override { uint8_t idx = 0; bool inverse = false; for(int i = 0; i < localCoords.x; i++) { idx += displayMap[i].length; inverse = !inverse; } if (inverse) { idx += std::max(0, displayMap[localCoords.x].length - 1 - std::max(0, (int)localCoords.y - displayMap[localCoords.x].y)); } else { idx += std::min((int)displayMap[localCoords.x].length - 1, std::max(0, (int)localCoords.y - displayMap[localCoords.x].y)); } return idx; } unsigned int physicalPixelCount() const override { int total = 0; for(int i = 0; i < 13; i++) { total += displayMap[i].length; } return total; } }; struct HardwareConfig { uint8_t version = 3; uint8_t checksum = 0; struct Data { uint16_t pixelCount = 255; uint16_t startPixel = 0; uint8_t lastRed = 255; uint8_t lastGreen = 255; uint8_t lastBlue = 255; char lastScene[16] = {0}; }; Data data; static HardwareConfig load(); void save(); bool isValid() const; LinearCoordinateMapping toCoordMap() const; static constexpr uint16_t MAX_LED_NUM = 255; private: uint8_t getCRC() const; static constexpr uint8_t CRC7_POLY = 0x91; }; // A task that manages the EEPROM settings and coord mapping when modified via // Particle. This allows for multiple devices with wildly different displays to // run the same code struct ConfigService: public Task { ConfigService() : Task("Configuration") {} void onStart(); void loop() override; void handleEvent(const InputEvent &evt) override; const CoordinateMapping* coordMap() const { return /*&m_maskMap;*/ &m_coordMap; } private: HardwareConfig m_config; MaskCoordinateMapping m_maskMap; LinearCoordinateMapping m_coordMap; };