From 4d7818837f0918555e97de7057ccadbf1959e906 Mon Sep 17 00:00:00 2001 From: Awawa <69086569+awawa-dev@users.noreply.github.com> Date: Mon, 12 Dec 2022 15:56:13 +0100 Subject: [PATCH] ESP32-S2 mini support (Adalight AWA protocol) (#452) --- .github/workflows/image-builder-from-repo.yml | 12 +- sources/leddevice/dev_serial/EspTools.h | 108 ++++++++++++++++++ .../dev_serial/LedDeviceAdalight.cpp | 9 +- .../leddevice/dev_serial/ProviderRs232.cpp | 72 +++--------- sources/leddevice/dev_serial/ProviderRs232.h | 2 +- .../leddevice/dev_spi/LedDeviceAWA_spi.cpp | 9 +- 6 files changed, 146 insertions(+), 66 deletions(-) create mode 100644 sources/leddevice/dev_serial/EspTools.h diff --git a/.github/workflows/image-builder-from-repo.yml b/.github/workflows/image-builder-from-repo.yml index 1c3cf23d1..813df0f5c 100644 --- a/.github/workflows/image-builder-from-repo.yml +++ b/.github/workflows/image-builder-from-repo.yml @@ -63,12 +63,12 @@ jobs: echo 'set -x' >> start_chroot_script echo 'set -e' >> start_chroot_script echo 'source /common.sh' >> start_chroot_script - echo 'type -p curl >/dev/null || sudo apt install curl -y' >> start_chroot_script - echo 'curl -fsSL https://awawa-dev.github.io/hyperhdr.public.apt.gpg.key | sudo dd of=/usr/share/keyrings/hyperhdr.public.apt.gpg.key \' >> start_chroot_script - echo '&& sudo chmod go+r /usr/share/keyrings/hyperhdr.public.apt.gpg.key \' >> start_chroot_script - echo '&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hyperhdr.public.apt.gpg.key] https://awawa-dev.github.io $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hyperhdr.list > /dev/null \' >> start_chroot_script - echo '&& sudo apt update \' >> start_chroot_script - echo '&& sudo apt install hyperhdr -y' >> start_chroot_script + echo 'type -p curl >/dev/null || apt install curl -y' >> start_chroot_script + echo 'curl -fsSL https://awawa-dev.github.io/hyperhdr.public.apt.gpg.key | dd of=/usr/share/keyrings/hyperhdr.public.apt.gpg.key \' >> start_chroot_script + echo '&& chmod go+r /usr/share/keyrings/hyperhdr.public.apt.gpg.key \' >> start_chroot_script + echo '&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hyperhdr.public.apt.gpg.key] https://awawa-dev.github.io $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/hyperhdr.list > /dev/null \' >> start_chroot_script + echo '&& apt update \' >> start_chroot_script + echo '&& apt install hyperhdr -y' >> start_chroot_script echo 'touch /boot/ssh' >> start_chroot_script echo "echo -n 'pi:' > /boot/userconf" >> start_chroot_script echo "echo 'raspberry' | openssl passwd -6 -stdin >> /boot/userconf" >> start_chroot_script diff --git a/sources/leddevice/dev_serial/EspTools.h b/sources/leddevice/dev_serial/EspTools.h new file mode 100644 index 000000000..4a0a5ee6b --- /dev/null +++ b/sources/leddevice/dev_serial/EspTools.h @@ -0,0 +1,108 @@ +/* EspTools.h +* +* MIT License +* +* Copyright (c) 2022 awawa-dev +* +* Project homesite: https://github.com/awawa-dev/HyperHDR +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. + +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. + */ + +#ifndef ESPTOOLS_H +#define ESPTOOLS_H + +class EspTools +{ + public: + + static void goingSleep(QSerialPort& _rs232Port) + { + uint8_t comBuffer[] = { 0x41, 0x77, 0x41, 0x2a, 0xa2, 0x35, 0x68, 0x79, 0x70, 0x65, 0x72, 0x68, 0x64, 0x72 }; + _rs232Port.write((char*)comBuffer, sizeof(comBuffer)); + _rs232Port.flush(); + _rs232Port.clear(); + } + + static void initializeEsp(QSerialPort& _rs232Port, QSerialPortInfo& serialPortInfo, Logger*& _log) + { + if (serialPortInfo.productIdentifier() == 0x80c2 && serialPortInfo.vendorIdentifier() == 0x303a) + { + Warning(_log, "Detected ESP32-S2 lolin mini type board. HyperHDR skips the reset. State: %i, %i", + _rs232Port.isDataTerminalReady(), _rs232Port.isRequestToSend()); + + uint8_t comBuffer[] = { 0x41, 0x77, 0x41, 0x2a, 0xa2, 0x15, 0x68, 0x79, 0x70, 0x65, 0x72, 0x68, 0x64, 0x72 }; + _rs232Port.write((char*)comBuffer, sizeof(comBuffer)); + + _rs232Port.setDataTerminalReady(true); + _rs232Port.setRequestToSend(true); + _rs232Port.setRequestToSend(false); + } + else + { + // reset to defaults + _rs232Port.setDataTerminalReady(true); + _rs232Port.setRequestToSend(false); + QThread::msleep(50); + + // reset device + _rs232Port.setDataTerminalReady(false); + _rs232Port.setRequestToSend(true); + QThread::msleep(100); + + // resume device + _rs232Port.setRequestToSend(false); + QThread::msleep(100); + } + + // read the reset message, search for AWA tag + auto start = InternalClock::now(); + + while (InternalClock::now() - start < 1000) + { + _rs232Port.waitForReadyRead(100); + if (_rs232Port.bytesAvailable() > 16) + { + auto incoming = _rs232Port.readAll(); + for (int i = 0; i < incoming.length(); i++) + if (!(incoming[i] == '\n' || + (incoming[i] >= ' ' && incoming[i] <= 'Z') || + (incoming[i] >= 'a' && incoming[i] <= 'z'))) + { + incoming.replace(incoming[i], '*'); + } + QString result = QString(incoming).remove('*').replace('\n', ' ').trimmed(); + if (result.indexOf("Awa driver", Qt::CaseInsensitive) >= 0) + { + Info(_log, "DETECTED DEVICE USING HYPERSERIALESP8266/HYPERSERIALESP32 FIRMWARE (%s) at %i msec", QSTRING_CSTR(result), int(InternalClock::now() - start)); + start = 0; + break; + } + } + + if (InternalClock::now() <= start) + break; + } + + if (start != 0) + Error(_log, "Could not detect HyperSerialEsp8266/HyperSerialESP32 device"); + } +}; + +#endif diff --git a/sources/leddevice/dev_serial/LedDeviceAdalight.cpp b/sources/leddevice/dev_serial/LedDeviceAdalight.cpp index 786b0fe18..b36cd53e6 100644 --- a/sources/leddevice/dev_serial/LedDeviceAdalight.cpp +++ b/sources/leddevice/dev_serial/LedDeviceAdalight.cpp @@ -72,7 +72,7 @@ void LedDeviceAdalight::CreateHeader() { _ligthBerryAPA102Mode = false; totalLedCount -= 1; - auto finalSize = (uint64_t)_headerSize + _ledRGBCount + ((_awa_mode) ? 7 : 0); + auto finalSize = (uint64_t)_headerSize + _ledRGBCount + ((_awa_mode) ? 8 : 0); _ledBuffer.resize(finalSize, 0x00); if (_awa_mode) @@ -113,7 +113,7 @@ int LedDeviceAdalight::write(const std::vector& ledValues) } else { - auto bufferLength = _headerSize + ledValues.size() * sizeof(ColorRgb) + ((_awa_mode) ? 7 : 0); + auto bufferLength = _headerSize + ledValues.size() * sizeof(ColorRgb) + ((_awa_mode) ? 8 : 0); if (bufferLength > _ledBuffer.size()) { @@ -131,14 +131,17 @@ int LedDeviceAdalight::write(const std::vector& ledValues) { whiteChannelExtension(writer); - uint16_t fletcher1 = 0, fletcher2 = 0; + uint16_t fletcher1 = 0, fletcher2 = 0, fletcherExt = 0; + uint8_t position = 0; while (hasher < writer) { + fletcherExt = (fletcherExt + (*(hasher) ^ (position++))) % 255; fletcher1 = (fletcher1 + *(hasher++)) % 255; fletcher2 = (fletcher2 + fletcher1) % 255; } *(writer++) = (uint8_t)fletcher1; *(writer++) = (uint8_t)fletcher2; + *(writer++) = (uint8_t)((fletcherExt != 0x41) ? fletcherExt : 0xaa); } bufferLength = writer - _ledBuffer.data(); diff --git a/sources/leddevice/dev_serial/ProviderRs232.cpp b/sources/leddevice/dev_serial/ProviderRs232.cpp index 08e6b573c..35e685240 100644 --- a/sources/leddevice/dev_serial/ProviderRs232.cpp +++ b/sources/leddevice/dev_serial/ProviderRs232.cpp @@ -11,6 +11,8 @@ #include #include +#include "EspTools.h" + // Constants constexpr std::chrono::milliseconds WRITE_TIMEOUT{ 1000 }; // device write timeout in ms constexpr std::chrono::milliseconds OPEN_TIMEOUT{ 5000 }; // device open timeout in ms @@ -83,17 +85,23 @@ int ProviderRs232::open() return retval; } -void ProviderRs232::waitForExitStats() -{ +void ProviderRs232::waitForExitStats(bool force) +{ if (_rs232Port.isOpen()) { - if (_rs232Port.bytesAvailable() > 16) + if (!force && _rs232Port.bytesAvailable() > 32) { - auto incoming = QString(_rs232Port.readAll()); + auto check = _rs232Port.peek(256); + if (check.lastIndexOf('\n') > 1) + { + auto incoming = QString(_rs232Port.readAll()); + force = true; - Info(_log, "Received: %s", QSTRING_CSTR(incoming)); + Info(_log, "Received: '%s' (%i)", QSTRING_CSTR(incoming), incoming.length()); + } } - if (!_isDeviceReady) + + if (!_isDeviceReady && force) { Debug(_log, "Close UART: %s", QSTRING_CSTR(_deviceName)); _rs232Port.close(); @@ -118,9 +126,10 @@ int ProviderRs232::close() if (_espHandshake) { - // read the statistics on goodbye - QTimer::singleShot(6000, this, &ProviderRs232::waitForExitStats); - connect(&_rs232Port, &QSerialPort::readyRead, this, &ProviderRs232::waitForExitStats); + EspTools::goingSleep(_rs232Port); + + QTimer::singleShot(6000, this, [this](){waitForExitStats(true); }); + connect(&_rs232Port, &QSerialPort::readyRead, this, [this]() {waitForExitStats(false); }); } else { @@ -196,50 +205,7 @@ bool ProviderRs232::tryOpen(int delayAfterConnect_ms) { disconnect(&_rs232Port, &QSerialPort::readyRead, nullptr, nullptr); - // reset to defaults - _rs232Port.setDataTerminalReady(true); - _rs232Port.setRequestToSend(false); - QThread::msleep(50); - - // reset device - _rs232Port.setDataTerminalReady(false); - _rs232Port.setRequestToSend(true); - QThread::msleep(100); - - // resume device - _rs232Port.setRequestToSend(false); - QThread::msleep(100); - - // read the reset message, search for AWA tag - auto start = InternalClock::now(); - - while(InternalClock::now() - start < 1000) - { - _rs232Port.waitForReadyRead(100); - if (_rs232Port.bytesAvailable() > 16) - { - auto incoming = _rs232Port.readAll(); - for (int i = 0; i < incoming.length(); i++) - if (!(incoming[i] == '\n' || - (incoming[i] >= ' ' && incoming[i] <= 'Z') || - (incoming[i] >= 'a' && incoming[i] <= 'z'))) - { - incoming.replace(incoming[i], '*'); - } - QString result = QString(incoming).remove('*').replace('\n',' ').trimmed(); - if (result.indexOf("Awa driver",Qt::CaseInsensitive) >= 0) - { - Info(_log, "DETECTED DEVICE USING HYPERSERIALESP8266/HYPERSERIALESP32 FIRMWARE (%s) at %i msec", QSTRING_CSTR(result), int(InternalClock::now() - start)); - start = 0; - break; - } - } - if (InternalClock::now() <= start) - break; - } - - if (start != 0) - Error(_log, "Could not detect HyperSerialEsp8266/HyperSerialESP32 device"); + EspTools::initializeEsp(_rs232Port, serialPortInfo, _log); } } else diff --git a/sources/leddevice/dev_serial/ProviderRs232.h b/sources/leddevice/dev_serial/ProviderRs232.h index 068f2e4ec..3dd00143e 100644 --- a/sources/leddevice/dev_serial/ProviderRs232.h +++ b/sources/leddevice/dev_serial/ProviderRs232.h @@ -98,7 +98,7 @@ protected slots: void setInError(const QString& errorMsg) override; public slots: - void waitForExitStats(); + void waitForExitStats(bool force); private: diff --git a/sources/leddevice/dev_spi/LedDeviceAWA_spi.cpp b/sources/leddevice/dev_spi/LedDeviceAWA_spi.cpp index d4c0d01b1..a27329e26 100644 --- a/sources/leddevice/dev_spi/LedDeviceAWA_spi.cpp +++ b/sources/leddevice/dev_spi/LedDeviceAWA_spi.cpp @@ -46,7 +46,7 @@ void LedDeviceAWA_spi::CreateHeader() { unsigned int totalLedCount = _ledCount - 1; - auto finalSize = (uint64_t)_headerSize + (_ledCount * 3) + 7; + auto finalSize = (uint64_t)_headerSize + (_ledCount * 3) + 8; _ledBuffer.resize(finalSize, 0x00); Debug(_log, "SPI driver with data integration check AWA protocol"); @@ -72,7 +72,7 @@ int LedDeviceAWA_spi::write(const std::vector& ledValues) CreateHeader(); } - auto bufferLength = _headerSize + ledValues.size() * sizeof(ColorRgb) + 7; + auto bufferLength = _headerSize + ledValues.size() * sizeof(ColorRgb) + 8; if (bufferLength > _ledBuffer.size()) { @@ -89,14 +89,17 @@ int LedDeviceAWA_spi::write(const std::vector& ledValues) whiteChannelExtension(writer); - uint16_t fletcher1 = 0, fletcher2 = 0; + uint16_t fletcher1 = 0, fletcher2 = 0, fletcherExt = 0; + uint8_t position = 0; while (hasher < writer) { + fletcherExt = (fletcherExt + (*(hasher) ^ (position++))) % 255; fletcher1 = (fletcher1 + *(hasher++)) % 255; fletcher2 = (fletcher2 + fletcher1) % 255; } *(writer++) = (uint8_t)fletcher1; *(writer++) = (uint8_t)fletcher2; + *(writer++) = (uint8_t)((fletcherExt != 0x41) ? fletcherExt : 0xaa); bufferLength = writer -_ledBuffer.data(); if (_spiType == "esp8266")