blob: 75113c971d58ea5961508b3bfd9de23acc6f0734 [file] [log] [blame]
Tomáš Peckaaf7b7042021-04-20 20:14:13 +02001/*
2 * Copyright (C) 2021 CESNET, https://photonics.cesnet.cz/
3 *
4 * Written by Tomáš Pecka <tomas.pecka@cesnet.cz>
5 *
6 */
7
8#include "LED.h"
9
10#include <utility>
11#include "utils/io.h"
Tomáš Pecka5be83e42021-04-21 17:26:40 +020012#include "utils/libyang.h"
Tomáš Peckaaf7b7042021-04-20 20:14:13 +020013#include "utils/log.h"
14#include "utils/sysrepo.h"
15
16using namespace std::literals;
17
18namespace {
19
20const auto CZECHLIGHT_SYSTEM_MODULE_NAME = "czechlight-system"s;
21const auto CZECHLIGHT_SYSTEM_LEDS_MODULE_PREFIX = "/"s + CZECHLIGHT_SYSTEM_MODULE_NAME + ":leds/"s;
22
Tomáš Pecka5be83e42021-04-21 17:26:40 +020023const auto UID_LED = "uid:blue"s;
Tomáš Pecka63b2d652021-04-22 19:03:14 +020024const auto POLL_INTERVAL = 125ms;
Tomáš Peckaaf7b7042021-04-20 20:14:13 +020025}
26
27namespace velia::system {
28
Václav Kubernát7efd6d52021-11-09 01:31:11 +010029LED::LED(::sysrepo::Connection srConn, std::filesystem::path sysfsLeds)
Tomáš Peckaaf7b7042021-04-20 20:14:13 +020030 : m_log(spdlog::get("system"))
Václav Kubernát7efd6d52021-11-09 01:31:11 +010031 , m_srSession(srConn.sessionStart())
32 , m_srSubscribe()
Tomáš Pecka63b2d652021-04-22 19:03:14 +020033 , m_thrRunning(true)
Tomáš Peckaaf7b7042021-04-20 20:14:13 +020034{
35 utils::ensureModuleImplemented(m_srSession, CZECHLIGHT_SYSTEM_MODULE_NAME, "2021-01-13");
36
Tomáš Pecka63b2d652021-04-22 19:03:14 +020037 for (const auto& entry : std::filesystem::directory_iterator(sysfsLeds)) {
38 if (!std::filesystem::is_directory(entry.path())) {
39 continue;
40 }
Tomáš Peckaaf7b7042021-04-20 20:14:13 +020041
Tomáš Pecka63b2d652021-04-22 19:03:14 +020042 const auto fullPath = sysfsLeds / entry.path();
43 uint32_t maxBrightness = velia::utils::readFileInt64(fullPath / "max_brightness");
44 m_log->debug("Discovered LED '{}' (max brightness {})", std::string(entry.path().filename()), maxBrightness);
45 m_ledsMaxBrightness[fullPath] = maxBrightness;
46 }
Tomáš Peckaaf7b7042021-04-20 20:14:13 +020047
Tomáš Pecka63b2d652021-04-22 19:03:14 +020048 m_thr = std::thread(&LED::poll, this);
Tomáš Peckaaf7b7042021-04-20 20:14:13 +020049
Tomáš Pecka63b2d652021-04-22 19:03:14 +020050 const auto uidMaxBrightness = std::to_string(velia::utils::readFileInt64(sysfsLeds / UID_LED / "max_brightness"));
51 const auto triggerFile = sysfsLeds / UID_LED / "trigger";
52 const auto brightnessFile = sysfsLeds / UID_LED / "brightness";
Tomáš Pecka5be83e42021-04-21 17:26:40 +020053
Václav Kubernát7efd6d52021-11-09 01:31:11 +010054 m_srSubscribe = m_srSession.onRPCAction(
Jan Kundrátb3e99982022-03-18 17:38:20 +010055 CZECHLIGHT_SYSTEM_LEDS_MODULE_PREFIX + "uid",
Václav Kubernát7efd6d52021-11-09 01:31:11 +010056 [this, uidMaxBrightness, triggerFile, brightnessFile](auto session, auto, auto, auto input, auto, auto, auto) {
Jan Kundrátb3e99982022-03-18 17:38:20 +010057 std::string val = utils::getValueAsString(utils::getUniqueSubtree(input, CZECHLIGHT_SYSTEM_LEDS_MODULE_PREFIX + "uid/state").value());
Tomáš Pecka5be83e42021-04-21 17:26:40 +020058
59 try {
60 if (val == "on") {
61 utils::writeFile(triggerFile, "none");
62 utils::writeFile(brightnessFile, uidMaxBrightness);
63 } else if (val == "off") {
64 utils::writeFile(triggerFile, "none");
65 utils::writeFile(brightnessFile, "0");
66 } else if (val == "blinking") {
67 utils::writeFile(triggerFile, "timer");
68 utils::writeFile(brightnessFile, uidMaxBrightness);
69 }
70 } catch (const std::invalid_argument& e) {
71 m_log->warn("Failed to set state of the UID LED: '{}'", e.what());
Václav Kubernát7efd6d52021-11-09 01:31:11 +010072 utils::setErrors(session, "Failed to set state of the UID LED");
73 return sysrepo::ErrorCode::OperationFailed;
Tomáš Pecka5be83e42021-04-21 17:26:40 +020074 }
75
Václav Kubernát7efd6d52021-11-09 01:31:11 +010076 return sysrepo::ErrorCode::Ok;
Tomáš Pecka5be83e42021-04-21 17:26:40 +020077 });
Tomáš Peckaaf7b7042021-04-20 20:14:13 +020078}
79
Tomáš Pecka63b2d652021-04-22 19:03:14 +020080LED::~LED()
81{
82 m_thrRunning = false;
83 m_thr.join();
84}
85
86void LED::poll() const
87{
88 while (m_thrRunning) {
89 std::map<std::string, std::string> data;
90
91 for (const auto& [ledDirectory, maxBrightness] : m_ledsMaxBrightness) {
92 const auto deviceName = ledDirectory.filename();
93
94 try {
95 /* actually just uint32_t is needed for the next two variables; but there is no harm in reading them as int64_t and downcasting them later (especially when the code for reading int64_t already exists)
96 * See https://github.com/torvalds/linux/commit/af0bfab907a011e146304d20d81dddce4e4d62d0
97 */
98 const uint32_t brightness = velia::utils::readFileInt64(ledDirectory / "brightness");
99 auto percent = brightness * 100 / maxBrightness;
100
101 data[CZECHLIGHT_SYSTEM_LEDS_MODULE_PREFIX + "led[name='" + std::string(deviceName) + "']/brightness"] = std::to_string(percent);
102 } catch (const std::invalid_argument& e) {
103 m_log->warn("Failed reading state of the LED '{}': {}", std::string(deviceName), e.what());
104 }
105 }
106
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100107 utils::valuesPush(data, {}, m_srSession, sysrepo::Datastore::Operational);
Tomáš Pecka63b2d652021-04-22 19:03:14 +0200108
109 std::this_thread::sleep_for(POLL_INTERVAL);
110 }
111}
Tomáš Peckaaf7b7042021-04-20 20:14:13 +0200112}