From 56b9c5f99730915ab44d0e42ab106beb5329a22d Mon Sep 17 00:00:00 2001 From: Ruslan Golovinsky Date: Sun, 5 Jun 2022 19:09:56 +0300 Subject: [PATCH] Implement communication protocol --- project.ino | 11 +++++ src/LightShow/LightShow.cpp | 90 +++++++++++++++++++++++++++++++++++++ src/LightShow/LightShow.h | 49 ++++++++++++++++++++ src/serialParse.ino | 71 ----------------------------- src/software.cpp | 86 +++++++++++++++++++++++++++++++++++ src/software.h | 36 +++++++++++++++ 6 files changed, 272 insertions(+), 71 deletions(-) create mode 100644 project.ino create mode 100644 src/LightShow/LightShow.cpp create mode 100644 src/LightShow/LightShow.h delete mode 100644 src/serialParse.ino create mode 100644 src/software.cpp create mode 100644 src/software.h diff --git a/project.ino b/project.ino new file mode 100644 index 0000000..f9c1e20 --- /dev/null +++ b/project.ino @@ -0,0 +1,11 @@ +#include "src/software.h" + +murxy::Software software; + +void setup() { + software.initialize(); +} + +void loop() { + software.loop(); +} diff --git a/src/LightShow/LightShow.cpp b/src/LightShow/LightShow.cpp new file mode 100644 index 0000000..f78fce4 --- /dev/null +++ b/src/LightShow/LightShow.cpp @@ -0,0 +1,90 @@ +#include "LightShow.h" + +namespace murxy { + +void LightShow::initialize() { + for(uint8_t column = Columns::Left; column != Columns::Count; ++column) { + mLights[column].begin(getAddress(static_cast(column))); + } +} + +XSAA1064 &LightShow::operator[](Columns column) { + return mLights[column]; +} +const XSAA1064 &LightShow::operator[](Columns column) const { + return mLights[column]; +} + +void LightShow::update() { + for (auto &light : mLights) + light.update(); +} + +void LightShow::clear() { + for (auto &light : mLights) + light.clear(); +} + +void LightShow::execute(uint16_t command) { + constexpr uint16_t TargetMask = 0b1000000000000000; + constexpr uint16_t ColumnMask = 0b0100000000000000; + constexpr uint16_t CommandMask = 0b0011000000000000; + constexpr uint16_t FromLedsMask = 0b0000111110000000; + constexpr uint16_t ToLedsMask = 0b0000000001111100; + constexpr uint16_t ValueMask = 0b0000000000000010; + constexpr uint16_t LinkMask = 0b0000000000000001; + + enum Command { + Clear, Set, Range, All + }; + + static const auto check = [](uint16_t command, uint16_t mask) -> bool { + return (command & mask) != mask; + }; + + if (!check(command, TargetMask)) + return; + + const Columns column = static_cast((command & ColumnMask) >> 14); + const Command cmd = static_cast((command & CommandMask) >> 12); + const bool enabled = (command & ValueMask) >> 1; + const bool hasLink = check(command, LinkMask); + + switch(cmd) { + case Command::Clear: { + mLights[column].clear(); + } break; + case Command::Set: { + const uint8_t position = ((command & FromLedsMask) >> 7); + mLights[column].set(position, enabled); + } break; + case Command::Range: { + const uint8_t from = ((command & FromLedsMask) >> 7); + const uint8_t to = ((command & ToLedsMask) >> 2); + mLights[column].set(from, to, enabled); + } break; + case Command::All: { + mLights[column].setAll(enabled); + } + } + mLights[column].set(XSAA1064::LinkLed, hasLink); +} + +XSAA1064 *LightShow::begin() { + return mLights; +} +const XSAA1064 *LightShow::begin() const { + return mLights; +} +XSAA1064 *LightShow::end() { + return mLights + Columns::Count; +} +const XSAA1064 *LightShow::end() const { + return mLights + Columns::Count; +} + +uint8_t LightShow::getAddress(Columns c) { + return 0b00111000 | (c << 0) | (c << 1); +} + +} // namespace murxy diff --git a/src/LightShow/LightShow.h b/src/LightShow/LightShow.h new file mode 100644 index 0000000..c860855 --- /dev/null +++ b/src/LightShow/LightShow.h @@ -0,0 +1,49 @@ +#if !defined(__LIGHT_SHOW__) +#define __LIGHT_SHOW__ + +#include + +namespace murxy { + +class LightShow { +public: + enum Columns{ Left, Right, Count }; + + void initialize(); + + XSAA1064 &operator[](Columns column); + const XSAA1064 &operator[](Columns column) const; + + /// @brief Update all light + void update(); + + /// @brief Clear all light including link light + void clear(); + + /** + * @brief Execute command + * + * @param command The data in format [T][C][CMD] + * Where is: + * T - Target. Have to be 0. Otherwise the command will be ignored + * C - Column. Left or right column + * CMD - Command. 0 - clear, 1 - set, 2 - set (range), 3 - all + * @see in documentation @link + */ + void execute(uint16_t command); + + XSAA1064 *begin(); + const XSAA1064 *begin() const; + XSAA1064 *end(); + const XSAA1064 *end() const; + + static uint8_t getAddress(Columns column); + +private: + XSAA1064 mLights[Columns::Count]; +}; + +} // namespace murxy + + +#endif diff --git a/src/serialParse.ino b/src/serialParse.ino deleted file mode 100644 index 9c9628a..0000000 --- a/src/serialParse.ino +++ /dev/null @@ -1,71 +0,0 @@ -#include -//#include -#include -#include "AsyncStream.h" -//#include // Load the PCA9554 Library -AsyncStream<10> serial(&Serial, ';'); //Executer and terminator - -#define SRL_SPD 9600 //Serial Speed - -XSAA1064 LeftColumn = XSAA1064(0x38); //Constructor XSAA1064 -XSAA1064 RightColumn = XSAA1064(0x3B); //Constructor XSAA1064 - -//PCA9554 ioCon1(0x24); - -/***************Button**************/ - -//#include - -//#define PWR_BTN 3 // Power button is connected to D3 -//#define RBT_BTN 4 // Reboot button is connected to D4 -//#define RBT_BTN 5 // Open trigger is connected to D5 - -//EncButton PWR; -//EncButton RBT; -//EncButton OPN; - -/***************Flags***************/ - -//bool isPressedPWR = 0; //Flag for PWR_BTN -//bool isPressedRBT = 0; //Flag for RBT_BTN -//bool isPressedOPN = 0; //Flag for OPN_BTN - -void setup() { - LeftColumn.begin(); - RightColumn.begin(); - //ioCon1.portMode(ALLOUTPUT); - Serial.begin(SRL_SPD); - //pinMode(PWR_BTN, INPUT); - //pinMode(RBT_BTN, INPUT); - //pinMode(RBT_BTN, INPUT); - LeftColumn.value(0, 1); // Reset LLightShow - RightColumn.value(0, 1); // Reset RLightShow -} - -void loop() { - parsing(); -} - -void parsing() { -if (serial.available()) { - GParser data(serial.buf, ','); // Parser take buffer - int ints[10]; // Array for ints - data.parseInts(ints); // Move ints to array - - switch (ints[0]) { - case 0: - switch (ints[1]) { - case 0: - LeftColumn.value(ints[2], ints[3]); - break; - case 1: - RightColumn.value(ints[2], ints[3]); - break; - } - break; - case 1: - - break; - } - } -} diff --git a/src/software.cpp b/src/software.cpp new file mode 100644 index 0000000..357c73a --- /dev/null +++ b/src/software.cpp @@ -0,0 +1,86 @@ +#include + +#include "software.h" + +namespace murxy { + +const Software::Handler Software::mStateHandlers[] = { + &Software::onLoading, + &Software::onReady, +}; + +void Software::initialize() { + Serial.begin(9600); + mLightShow.initialize(); +} + +void Software::loop() { + (this->*mStateHandlers[mCurrentState])(); + mLightShow.update(); +} + +void Software::onLoading() { + constexpr uint8_t count = 5; + static LightShow::Columns cur[count] = { LightShow::Columns::Left }; + static uint8_t pos[count] = { 1, 2, 3, 4, 6 }; + + if (mTimer == 0) { + mTimer = millis(); + mLightShow.clear(); + } + + uint8_t erasePos = 0; + for (uint8_t i = 0; i < count; ++i) { + uint8_t& position = pos[i]; + LightShow::Columns& column = cur[i]; + if (i == 0) + mLightShow[column].set(position, false); + + if (column == LightShow::Columns::Left) + ++position; + else + --position; + + if (position > 0 && position < XSAA1064::ledCount()) { + mLightShow[column].set(position, true); + continue; + } + + if (column == LightShow::Columns::Left) + column = LightShow::Columns::Right; + else + column = LightShow::Columns::Left; + } + + delay(millis() / 100); + if (millis() - mTimer >= 5 * 1000) + setState(States::Ready); +} + +void Software::onReady() { + if (mTimer == 0) { + for (auto &led : mLightShow) + led.set(XSAA1064::LinkLed); + mTimer = millis(); + } + + uint8_t byte = 0; + if (Serial.readBytes(&byte, 1) > 0) { + if (byte != 'B') return; + } + + uint16_t command = 0; + size_t size = Serial.readBytes(reinterpret_cast(&command) + 1, 1); + size += Serial.readBytes(reinterpret_cast(&command) + 0, 1); + if (size == sizeof(command)) { + mLightShow.execute(command); + } +} + +void Software::setState(States newState) { + mCurrentState = newState; + mLightShow.clear(); + mTimer = 0; +} + +} // namespace murxy diff --git a/src/software.h b/src/software.h new file mode 100644 index 0000000..c478778 --- /dev/null +++ b/src/software.h @@ -0,0 +1,36 @@ +#if !defined(__SOFTWARE__) +#define __SOFTWARE__ + +#include "LightShow/LightShow.h" + +namespace murxy { + +class Software { + using Handler = void(Software::*)(); +public: + + void initialize(); + void loop(); + +private: + enum States { + Loading, + Ready, + Count + }; + + States mCurrentState = States::Loading; + LightShow mLightShow; + uint32_t mTimer = 0; + + void onLoading(); + void onReady(); + + static const Handler mStateHandlers[States::Count]; + + void setState(States newState); +}; + +} // namespace murxy + +#endif