LedDevice.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. #include <leddevice/LedDevice.h>
  2. //QT include
  3. #include <QResource>
  4. #include <QStringList>
  5. #include <QDir>
  6. #include <QDateTime>
  7. #include <QEventLoop>
  8. #include <QTimer>
  9. #include <QDateTime>
  10. #include "hyperion/Hyperion.h"
  11. #include <utils/JsonUtils.h>
  12. //std includes
  13. #include <sstream>
  14. #include <iomanip>
  15. #include <chrono>
  16. // Constants
  17. namespace {
  18. // Configuration settings
  19. const char CONFIG_CURRENT_LED_COUNT[] = "currentLedCount";
  20. const char CONFIG_COLOR_ORDER[] = "colorOrder";
  21. const char CONFIG_AUTOSTART[] = "autoStart";
  22. const char CONFIG_LATCH_TIME[] = "latchTime";
  23. const char CONFIG_REWRITE_TIME[] = "rewriteTime";
  24. int DEFAULT_LED_COUNT{ 1 };
  25. const char DEFAULT_COLOR_ORDER[]{ "RGB" };
  26. const bool DEFAULT_IS_AUTOSTART{ true };
  27. const char CONFIG_ENABLE_ATTEMPTS[] = "enableAttempts";
  28. const char CONFIG_ENABLE_ATTEMPTS_INTERVALL[] = "enableAttemptsInterval";
  29. const int DEFAULT_MAX_ENABLE_ATTEMPTS{ 5 };
  30. constexpr std::chrono::seconds DEFAULT_ENABLE_ATTEMPTS_INTERVAL{ 5 };
  31. } //End of constants
  32. LedDevice::LedDevice(const QJsonObject& deviceConfig, QObject* parent)
  33. : QObject(parent)
  34. , _devConfig(deviceConfig)
  35. , _log(Logger::getInstance("LEDDEVICE"))
  36. , _ledBuffer(0)
  37. , _refreshTimer(nullptr)
  38. , _refreshTimerInterval_ms(0)
  39. , _latchTime_ms(0)
  40. , _ledCount(0)
  41. , _isRestoreOrigState(false)
  42. , _isStayOnAfterStreaming(false)
  43. , _isEnabled(false)
  44. , _isDeviceInitialised(false)
  45. , _isDeviceReady(false)
  46. , _isOn(false)
  47. , _isDeviceInError(false)
  48. , _isDeviceRecoverable(false)
  49. , _lastWriteTime(QDateTime::currentDateTime())
  50. , _enableAttemptsTimer(nullptr)
  51. , _enableAttemptTimerInterval(DEFAULT_ENABLE_ATTEMPTS_INTERVAL)
  52. , _enableAttempts(0)
  53. , _maxEnableAttempts(DEFAULT_MAX_ENABLE_ATTEMPTS)
  54. , _isRefreshEnabled(false)
  55. , _isAutoStart(true)
  56. {
  57. _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
  58. }
  59. LedDevice::~LedDevice()
  60. {
  61. }
  62. void LedDevice::start()
  63. {
  64. Info(_log, "Start LedDevice '%s'.", QSTRING_CSTR(_activeDeviceType));
  65. close();
  66. _isDeviceInitialised = false;
  67. if (init(_devConfig))
  68. {
  69. // Everything is OK -> enable device
  70. _isDeviceInitialised = true;
  71. if (_isAutoStart)
  72. {
  73. if (!_isEnabled)
  74. {
  75. Debug(_log, "Not enabled -> enable device");
  76. enable();
  77. }
  78. }
  79. }
  80. }
  81. void LedDevice::stop()
  82. {
  83. Debug(_log, "Stop device");
  84. this->stopEnableAttemptsTimer();
  85. this->disable();
  86. this->stopRefreshTimer();
  87. Info(_log, " Stopped LedDevice '%s'", QSTRING_CSTR(_activeDeviceType));
  88. }
  89. int LedDevice::open()
  90. {
  91. _isDeviceReady = true;
  92. int retval = 0;
  93. return retval;
  94. }
  95. int LedDevice::close()
  96. {
  97. _isDeviceReady = false;
  98. int retval = 0;
  99. return retval;
  100. }
  101. void LedDevice::setInError(const QString& errorMsg, bool isRecoverable)
  102. {
  103. _isOn = false;
  104. _isDeviceInError = true;
  105. _isDeviceReady = false;
  106. _isEnabled = false;
  107. this->stopRefreshTimer();
  108. if (isRecoverable)
  109. {
  110. _isDeviceRecoverable = isRecoverable;
  111. }
  112. Error(_log, "Device disabled, device '%s' signals error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(errorMsg));
  113. emit enableStateChanged(_isEnabled);
  114. }
  115. void LedDevice::enable()
  116. {
  117. Debug(_log, "Enable device %s'", QSTRING_CSTR(_activeDeviceType));
  118. if (!_isEnabled)
  119. {
  120. if (_enableAttemptsTimer != nullptr && _enableAttemptsTimer->isActive())
  121. {
  122. _enableAttemptsTimer->stop();
  123. }
  124. _isDeviceInError = false;
  125. if (!_isDeviceInitialised)
  126. {
  127. _isDeviceInitialised = init(_devConfig);
  128. }
  129. if (!_isDeviceReady)
  130. {
  131. open();
  132. }
  133. bool isEnableFailed(true);
  134. if (_isDeviceReady)
  135. {
  136. if (switchOn())
  137. {
  138. stopEnableAttemptsTimer();
  139. _isEnabled = true;
  140. isEnableFailed = false;
  141. emit enableStateChanged(_isEnabled);
  142. Info(_log, "LedDevice '%s' enabled", QSTRING_CSTR(_activeDeviceType));
  143. }
  144. }
  145. if (isEnableFailed)
  146. {
  147. emit enableStateChanged(false);
  148. if (_maxEnableAttempts > 0 && _isDeviceRecoverable)
  149. {
  150. Debug(_log, "Device's enablement failed - Start retry timer. Retried already done [%d], isEnabled: [%d]", _enableAttempts, _isEnabled);
  151. startEnableAttemptsTimer();
  152. }
  153. else
  154. {
  155. Debug(_log, "Device's enablement failed");
  156. }
  157. }
  158. }
  159. }
  160. void LedDevice::disable()
  161. {
  162. Debug(_log, "Disable device %s'", QSTRING_CSTR(_activeDeviceType));
  163. if (_isEnabled)
  164. {
  165. _isEnabled = false;
  166. this->stopEnableAttemptsTimer();
  167. this->stopRefreshTimer();
  168. switchOff();
  169. close();
  170. emit enableStateChanged(_isEnabled);
  171. }
  172. }
  173. void LedDevice::setActiveDeviceType(const QString& deviceType)
  174. {
  175. _activeDeviceType = deviceType;
  176. }
  177. bool LedDevice::init(const QJsonObject& deviceConfig)
  178. {
  179. Debug(_log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData());
  180. setLedCount(deviceConfig[CONFIG_CURRENT_LED_COUNT].toInt(DEFAULT_LED_COUNT)); // property injected to reflect real led count
  181. setColorOrder(deviceConfig[CONFIG_COLOR_ORDER].toString(DEFAULT_COLOR_ORDER));
  182. setLatchTime(deviceConfig[CONFIG_LATCH_TIME].toInt(_latchTime_ms));
  183. setRewriteTime(deviceConfig[CONFIG_REWRITE_TIME].toInt(_refreshTimerInterval_ms));
  184. setAutoStart(deviceConfig[CONFIG_AUTOSTART].toBool(DEFAULT_IS_AUTOSTART));
  185. setEnableAttempts(deviceConfig[CONFIG_ENABLE_ATTEMPTS].toInt(DEFAULT_MAX_ENABLE_ATTEMPTS),
  186. std::chrono::seconds(deviceConfig[CONFIG_ENABLE_ATTEMPTS_INTERVALL].toInt(DEFAULT_ENABLE_ATTEMPTS_INTERVAL.count()))
  187. );
  188. return true;
  189. }
  190. void LedDevice::startRefreshTimer()
  191. {
  192. if (_refreshTimerInterval_ms > 0)
  193. {
  194. if (_isDeviceReady && _isOn)
  195. {
  196. // setup refreshTimer
  197. if (_refreshTimer == nullptr)
  198. {
  199. _refreshTimer = new QTimer(this);
  200. _refreshTimer->setTimerType(Qt::PreciseTimer);
  201. connect(_refreshTimer, &QTimer::timeout, this, &LedDevice::rewriteLEDs);
  202. }
  203. _refreshTimer->setInterval(_refreshTimerInterval_ms);
  204. _refreshTimer->start();
  205. }
  206. else
  207. {
  208. Debug(_log, "Device is not ready to start a refresh timer");
  209. }
  210. }
  211. }
  212. void LedDevice::stopRefreshTimer()
  213. {
  214. if (_refreshTimer != nullptr)
  215. {
  216. _refreshTimer->stop();
  217. delete _refreshTimer;
  218. _refreshTimer = nullptr;
  219. }
  220. }
  221. void LedDevice::startEnableAttemptsTimer()
  222. {
  223. ++_enableAttempts;
  224. if (_isDeviceRecoverable)
  225. {
  226. if (_enableAttempts <= _maxEnableAttempts)
  227. {
  228. if (_enableAttemptTimerInterval.count() > 0)
  229. {
  230. // setup enable retry timer
  231. if (_enableAttemptsTimer == nullptr)
  232. {
  233. _enableAttemptsTimer = new QTimer(this);
  234. _enableAttemptsTimer->setTimerType(Qt::PreciseTimer);
  235. connect(_enableAttemptsTimer, &QTimer::timeout, this, &LedDevice::enable);
  236. }
  237. _enableAttemptsTimer->setInterval(static_cast<int>(_enableAttemptTimerInterval.count() * 1000)); //NOLINT
  238. Info(_log, "Start %d. attempt of %d to enable the device in %d seconds", _enableAttempts, _maxEnableAttempts, _enableAttemptTimerInterval.count());
  239. _enableAttemptsTimer->start();
  240. }
  241. }
  242. else
  243. {
  244. Error(_log, "Device disabled. Maximum number of %d attempts enabling the device reached. Tried for %d seconds.", _maxEnableAttempts, _enableAttempts * _enableAttemptTimerInterval.count());
  245. _enableAttempts = 0;
  246. }
  247. }
  248. }
  249. void LedDevice::stopEnableAttemptsTimer()
  250. {
  251. if (_enableAttemptsTimer != nullptr)
  252. {
  253. Debug(_log, "Stopping enable retry timer");
  254. _enableAttemptsTimer->stop();
  255. delete _enableAttemptsTimer;
  256. _enableAttemptsTimer = nullptr;
  257. _enableAttempts = 0;
  258. }
  259. }
  260. int LedDevice::updateLeds(std::vector<ColorRgb> ledValues)
  261. {
  262. int retval = 0;
  263. if (!_isEnabled || !_isOn || !_isDeviceReady || _isDeviceInError)
  264. {
  265. // LedDevice NOT ready!
  266. retval = -1;
  267. }
  268. else
  269. {
  270. qint64 elapsedTimeMs = _lastWriteTime.msecsTo(QDateTime::currentDateTime());
  271. if (_latchTime_ms == 0 || elapsedTimeMs >= _latchTime_ms)
  272. {
  273. retval = write(ledValues);
  274. _lastWriteTime = QDateTime::currentDateTime();
  275. // if device requires refreshing, save Led-Values and restart the timer
  276. if (_isRefreshEnabled && _isEnabled)
  277. {
  278. _lastLedValues = ledValues;
  279. this->startRefreshTimer();
  280. }
  281. }
  282. else
  283. {
  284. // Skip write as elapsedTime < latchTime
  285. if (_isRefreshEnabled)
  286. {
  287. //Stop timer to allow for next non-refresh update
  288. this->stopRefreshTimer();
  289. }
  290. }
  291. }
  292. return retval;
  293. }
  294. int LedDevice::rewriteLEDs()
  295. {
  296. int retval = -1;
  297. if (_isEnabled && _isOn && _isDeviceReady && !_isDeviceInError)
  298. {
  299. if (!_lastLedValues.empty())
  300. {
  301. retval = write(_lastLedValues);
  302. _lastWriteTime = QDateTime::currentDateTime();
  303. }
  304. }
  305. else
  306. {
  307. // If Device is not ready stop timer
  308. this->stopRefreshTimer();
  309. }
  310. return retval;
  311. }
  312. int LedDevice::writeBlack(int numberOfWrites)
  313. {
  314. Debug(_log, "Set LED strip to black to switch of LEDs");
  315. return writeColor(ColorRgb::BLACK, numberOfWrites);
  316. }
  317. int LedDevice::writeColor(const ColorRgb& color, int numberOfWrites)
  318. {
  319. int rc = -1;
  320. for (int i = 0; i < numberOfWrites; i++)
  321. {
  322. if (_latchTime_ms > 0)
  323. {
  324. // Wait latch time before writing black
  325. QEventLoop loop;
  326. QTimer::singleShot(_latchTime_ms, &loop, &QEventLoop::quit);
  327. loop.exec();
  328. }
  329. _lastLedValues = std::vector<ColorRgb>(static_cast<unsigned long>(_ledCount), color);
  330. rc = write(_lastLedValues);
  331. }
  332. return rc;
  333. }
  334. bool LedDevice::switchOn()
  335. {
  336. bool rc{ false };
  337. if (_isOn)
  338. {
  339. Debug(_log, "Device %s is already on. Skipping.", QSTRING_CSTR(_activeDeviceType));
  340. rc = true;
  341. }
  342. else
  343. {
  344. if (_isDeviceReady)
  345. {
  346. Info(_log, "Switching device %s ON", QSTRING_CSTR(_activeDeviceType));
  347. if (storeState())
  348. {
  349. if (powerOn())
  350. {
  351. Info(_log, "Device %s is ON", QSTRING_CSTR(_activeDeviceType));
  352. _isOn = true;
  353. emit enableStateChanged(_isEnabled);
  354. rc = true;
  355. }
  356. else
  357. {
  358. Warning(_log, "Failed switching device %s ON", QSTRING_CSTR(_activeDeviceType));
  359. }
  360. }
  361. }
  362. }
  363. return rc;
  364. }
  365. bool LedDevice::switchOff()
  366. {
  367. bool rc{ false };
  368. if (!_isOn)
  369. {
  370. rc = true;
  371. }
  372. else
  373. {
  374. if (_isDeviceInitialised)
  375. {
  376. Info(_log, "Switching device %s OFF", QSTRING_CSTR(_activeDeviceType));
  377. // Disable device to ensure no standard LED updates are written/processed
  378. _isOn = false;
  379. rc = true;
  380. if (_isDeviceReady)
  381. {
  382. if (_isRestoreOrigState)
  383. {
  384. //Restore devices state
  385. restoreState();
  386. }
  387. else
  388. {
  389. if (powerOff())
  390. {
  391. Info(_log, "Device %s is OFF", QSTRING_CSTR(_activeDeviceType));
  392. }
  393. else
  394. {
  395. Warning(_log, "Failed switching device %s OFF", QSTRING_CSTR(_activeDeviceType));
  396. }
  397. }
  398. }
  399. }
  400. }
  401. return rc;
  402. }
  403. bool LedDevice::powerOff()
  404. {
  405. bool rc{ true };
  406. if (!_isStayOnAfterStreaming)
  407. {
  408. Debug(_log, "Power Off: %s", QSTRING_CSTR(_activeDeviceType));
  409. // Simulate power-off by writing a final "Black" to have a defined outcome
  410. if (writeBlack() < 0)
  411. {
  412. rc = false;
  413. }
  414. }
  415. return rc;
  416. }
  417. bool LedDevice::powerOn()
  418. {
  419. bool rc{ true };
  420. Debug(_log, "Power On: %s", QSTRING_CSTR(_activeDeviceType));
  421. return rc;
  422. }
  423. bool LedDevice::storeState()
  424. {
  425. bool rc{ true };
  426. #if 0
  427. if (_isRestoreOrigState)
  428. {
  429. // Save device's original state
  430. // _originalStateValues = get device's state;
  431. // store original power on/off state, if available
  432. }
  433. #endif
  434. return rc;
  435. }
  436. bool LedDevice::restoreState()
  437. {
  438. bool rc{ true };
  439. #if 0
  440. if (_isRestoreOrigState)
  441. {
  442. // Restore device's original state
  443. // update device using _originalStateValues
  444. // update original power on/off state, if supported
  445. }
  446. #endif
  447. return rc;
  448. }
  449. QJsonObject LedDevice::discover(const QJsonObject& /*params*/)
  450. {
  451. QJsonObject devicesDiscovered;
  452. devicesDiscovered.insert("ledDeviceType", _activeDeviceType);
  453. QJsonArray deviceList;
  454. devicesDiscovered.insert("devices", deviceList);
  455. Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
  456. return devicesDiscovered;
  457. }
  458. QString LedDevice::discoverFirst()
  459. {
  460. QString deviceDiscovered;
  461. Debug(_log, "deviceDiscovered: [%s]", QSTRING_CSTR(deviceDiscovered));
  462. return deviceDiscovered;
  463. }
  464. QJsonObject LedDevice::getProperties(const QJsonObject& params)
  465. {
  466. Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
  467. QJsonObject properties;
  468. QJsonObject deviceProperties;
  469. properties.insert("properties", deviceProperties);
  470. Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData());
  471. return properties;
  472. }
  473. void LedDevice::setLogger(Logger* log)
  474. {
  475. _log = log;
  476. }
  477. void LedDevice::setLedCount(int ledCount)
  478. {
  479. assert(ledCount >= 0);
  480. _ledCount = static_cast<uint>(ledCount);
  481. _ledRGBCount = _ledCount * sizeof(ColorRgb);
  482. _ledRGBWCount = _ledCount * sizeof(ColorRgbw);
  483. Debug(_log, "LedCount set to %d", _ledCount);
  484. }
  485. void LedDevice::setColorOrder(const QString& colorOrder)
  486. {
  487. _colorOrder = colorOrder;
  488. Debug(_log, "ColorOrder set to %s", QSTRING_CSTR(_colorOrder.toUpper()));
  489. }
  490. void LedDevice::setLatchTime(int latchTime_ms)
  491. {
  492. assert(latchTime_ms >= 0);
  493. _latchTime_ms = latchTime_ms;
  494. Debug(_log, "LatchTime set to %dms", _latchTime_ms);
  495. }
  496. void LedDevice::setAutoStart(bool isAutoStart)
  497. {
  498. _isAutoStart = isAutoStart;
  499. Debug(_log, "AutoStart %s", (_isAutoStart ? "enabled" : "disabled"));
  500. }
  501. void LedDevice::setRewriteTime(int rewriteTime_ms)
  502. {
  503. _refreshTimerInterval_ms = qMax(rewriteTime_ms, 0);
  504. if (_refreshTimerInterval_ms > 0)
  505. {
  506. _isRefreshEnabled = true;
  507. if (_refreshTimerInterval_ms <= _latchTime_ms)
  508. {
  509. int new_refresh_timer_interval = _latchTime_ms + 10; //NOLINT
  510. Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d), set rewriteTime to %dms", _latchTime_ms, _refreshTimerInterval_ms, new_refresh_timer_interval);
  511. _refreshTimerInterval_ms = new_refresh_timer_interval;
  512. }
  513. Debug(_log, "Refresh interval = %dms", _refreshTimerInterval_ms);
  514. startRefreshTimer();
  515. }
  516. else
  517. {
  518. _isRefreshEnabled = false;
  519. stopRefreshTimer();
  520. }
  521. }
  522. void LedDevice::setEnableAttempts(int maxEnableRetries, std::chrono::seconds enableRetryTimerInterval)
  523. {
  524. stopEnableAttemptsTimer();
  525. maxEnableRetries = qMax(maxEnableRetries, 0);
  526. _enableAttempts = 0;
  527. _maxEnableAttempts = maxEnableRetries;
  528. _enableAttemptTimerInterval = enableRetryTimerInterval;
  529. Debug(_log, "Max enable retries: %d, enable retry interval = %llds", _maxEnableAttempts, _enableAttemptTimerInterval.count());
  530. }
  531. void LedDevice::printLedValues(const std::vector<ColorRgb>& ledValues)
  532. {
  533. std::cout << "LedValues [" << ledValues.size() << "] [";
  534. for (const ColorRgb& color : ledValues)
  535. {
  536. std::cout << color;
  537. }
  538. std::cout << "]" << std::endl;
  539. }
  540. QString LedDevice::uint8_t_to_hex_string(const uint8_t* data, const int size, int number)
  541. {
  542. if (number <= 0 || number > size)
  543. {
  544. number = size;
  545. }
  546. QByteArray bytes(reinterpret_cast<const char*>(data), number);
  547. #if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
  548. return bytes.toHex(':');
  549. #else
  550. return bytes.toHex();
  551. #endif
  552. }
  553. QString LedDevice::toHex(const QByteArray& data, int number)
  554. {
  555. if (number <= 0 || number > data.size())
  556. {
  557. number = data.size();
  558. }
  559. #if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
  560. return data.left(number).toHex(':');
  561. #else
  562. return data.left(number).toHex();
  563. #endif
  564. }
  565. bool LedDevice::isInitialised() const
  566. {
  567. return _isDeviceInitialised;
  568. }
  569. bool LedDevice::isReady() const
  570. {
  571. return _isDeviceReady;
  572. }
  573. bool LedDevice::isInError() const
  574. {
  575. return _isDeviceInError;
  576. }
  577. int LedDevice::getLatchTime() const
  578. {
  579. return _latchTime_ms;
  580. }
  581. int LedDevice::getRewriteTime() const
  582. {
  583. return _refreshTimerInterval_ms;
  584. }
  585. int LedDevice::getLedCount() const
  586. {
  587. return static_cast<int>(_ledCount);
  588. }
  589. QString LedDevice::getActiveDeviceType() const
  590. {
  591. return _activeDeviceType;
  592. }
  593. QString LedDevice::getColorOrder() const
  594. {
  595. return _colorOrder;
  596. }
  597. bool LedDevice::componentState() const {
  598. return _isEnabled;
  599. }