You've already forked UGREEN-NAS
This commit is contained in:
10
sources/ugreen-led-cli/Makefile
Normal file
10
sources/ugreen-led-cli/Makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
CC = g++
|
||||
CFLAGS = -I. -O2 -Wall
|
||||
DEPS = i2c.h main.h
|
||||
OBJ = i2c.o main.o
|
||||
|
||||
%.o: %.cpp $(DEPS)
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
ugreen-led-cli: $(OBJ) ugreen-led-cli.o
|
||||
$(CC) -o $@ $^ $(CFLAGS)
|
||||
96
sources/ugreen-led-cli/i2c.cpp
Normal file
96
sources/ugreen-led-cli/i2c.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "i2c.h"
|
||||
|
||||
i2c_device_t::~i2c_device_t() {
|
||||
if (_fd) close(_fd);
|
||||
}
|
||||
|
||||
int i2c_device_t::start(const char * filename, uint16_t addr) {
|
||||
_fd = open(filename, O_RDWR);
|
||||
|
||||
if (_fd < 0) {
|
||||
int rc = _fd;
|
||||
_fd = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int rc = ioctl(_fd, I2C_SLAVE, addr);
|
||||
if (rc < 0) {
|
||||
close(_fd);
|
||||
_fd = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
std::vector < uint8_t > i2c_device_t::read_block_data(uint8_t command, uint32_t size) {
|
||||
if (!_fd) return {};
|
||||
|
||||
if (size > I2C_SMBUS_BLOCK_MAX)
|
||||
return {};
|
||||
|
||||
i2c_smbus_data smbus_data;
|
||||
smbus_data.block[0] = size;
|
||||
|
||||
i2c_smbus_ioctl_data ioctl_data;
|
||||
ioctl_data.size = I2C_SMBUS_I2C_BLOCK_DATA;
|
||||
ioctl_data.read_write = I2C_SMBUS_READ;
|
||||
ioctl_data.command = command;
|
||||
ioctl_data.data = & smbus_data;
|
||||
|
||||
int rc = ioctl(_fd, I2C_SMBUS, & ioctl_data);
|
||||
|
||||
if (rc < 0) return {};
|
||||
|
||||
std::vector < uint8_t > data;
|
||||
for (uint32_t i = 0; i < size; ++i)
|
||||
data.push_back(smbus_data.block[i + 1]);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
int i2c_device_t::write_block_data(uint8_t command, std::vector < uint8_t > data) {
|
||||
if (!_fd) return -1;
|
||||
|
||||
uint32_t size = data.size();
|
||||
if (size > I2C_SMBUS_BLOCK_MAX)
|
||||
size = I2C_SMBUS_BLOCK_MAX;
|
||||
|
||||
i2c_smbus_data smbus_data;
|
||||
smbus_data.block[0] = size;
|
||||
for (uint32_t i = 0; i < size; ++i)
|
||||
smbus_data.block[i + 1] = data[i];
|
||||
|
||||
i2c_smbus_ioctl_data ioctl_data;
|
||||
ioctl_data.size = I2C_SMBUS_I2C_BLOCK_DATA;
|
||||
ioctl_data.read_write = I2C_SMBUS_WRITE;
|
||||
ioctl_data.command = command;
|
||||
ioctl_data.data = & smbus_data;
|
||||
|
||||
int rc = ioctl(_fd, I2C_SMBUS, & ioctl_data);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
uint8_t i2c_device_t::read_byte_data(uint8_t command) {
|
||||
if (!_fd) return {};
|
||||
|
||||
i2c_smbus_data smbus_data;
|
||||
|
||||
i2c_smbus_ioctl_data ioctl_data;
|
||||
ioctl_data.size = I2C_SMBUS_BYTE_DATA;
|
||||
ioctl_data.read_write = I2C_SMBUS_READ;
|
||||
ioctl_data.command = command;
|
||||
ioctl_data.data = & smbus_data;
|
||||
|
||||
int rc = ioctl(_fd, I2C_SMBUS, & ioctl_data);
|
||||
|
||||
if (rc < 0) return {};
|
||||
|
||||
return smbus_data.byte & 0xff;
|
||||
}
|
||||
20
sources/ugreen-led-cli/i2c.h
Normal file
20
sources/ugreen-led-cli/i2c.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef __UGREEN_I2C_H__
|
||||
#define __UGREEN_I2C_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
class i2c_device_t {
|
||||
|
||||
private:
|
||||
int _fd;
|
||||
|
||||
public:
|
||||
~i2c_device_t();
|
||||
int start(const char * filename, uint16_t addr);
|
||||
std::vector < uint8_t > read_block_data(uint8_t command, uint32_t size);
|
||||
int write_block_data(uint8_t command, std::vector < uint8_t > data);
|
||||
uint8_t read_byte_data(uint8_t command);
|
||||
};
|
||||
|
||||
#endif
|
||||
136
sources/ugreen-led-cli/main.cpp
Normal file
136
sources/ugreen-led-cli/main.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
#include "main.h"
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#define I2C_DEV_PATH "/sys/class/i2c-dev/"
|
||||
|
||||
int ugreen_leds_t::start() {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
if (!fs::exists(I2C_DEV_PATH))
|
||||
return -1;
|
||||
|
||||
for (const auto & entry: fs::directory_iterator(I2C_DEV_PATH)) {
|
||||
if (entry.is_directory()) {
|
||||
std::ifstream ifs(entry.path() / "device/name");
|
||||
std::string line;
|
||||
std::getline(ifs, line);
|
||||
|
||||
if (line.rfind("SMBus I801 adapter", 0) == 0) {
|
||||
const auto i2c_dev = "/dev/" + entry.path().filename().string();
|
||||
return _i2c.start(i2c_dev.c_str(), UGREEN_LED_I2C_ADDR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int compute_checksum(const std::vector < uint8_t > & data, int size) {
|
||||
if (size < 2 || size > (int) data.size())
|
||||
return 0;
|
||||
|
||||
int sum = 0;
|
||||
for (int i = 0; i < size; ++i)
|
||||
sum += (int) data[i];
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static bool verify_checksum(const std::vector < uint8_t > & data) {
|
||||
int size = data.size();
|
||||
if (size < 2) return false;
|
||||
int sum = compute_checksum(data, size - 2);
|
||||
return sum != 0 && sum == (data[size - 1] | (((int) data[size - 2]) << 8));
|
||||
}
|
||||
|
||||
static void append_checksum(std::vector < uint8_t > & data) {
|
||||
int size = data.size();
|
||||
int sum = compute_checksum(data, size);
|
||||
data.push_back((sum >> 8) & 0xff);
|
||||
data.push_back(sum & 0xff);
|
||||
}
|
||||
|
||||
ugreen_leds_t::led_data_t ugreen_leds_t::get_status(led_type_t id) {
|
||||
led_data_t data {};
|
||||
data.is_available = false;
|
||||
|
||||
auto raw_data = _i2c.read_block_data(0x81 + (uint8_t) id, 0xb);
|
||||
if (raw_data.size() != 0xb || !verify_checksum(raw_data))
|
||||
return data;
|
||||
|
||||
switch (raw_data[0]) {
|
||||
case 0: data.op_mode = op_mode_t::off; break;
|
||||
case 1: data.op_mode = op_mode_t::on; break;
|
||||
case 2: data.op_mode = op_mode_t::blink; break;
|
||||
case 3: data.op_mode = op_mode_t::breath; break;
|
||||
default: return data;
|
||||
};
|
||||
|
||||
data.brightness = raw_data[1];
|
||||
data.color_r = raw_data[2];
|
||||
data.color_g = raw_data[3];
|
||||
data.color_b = raw_data[4];
|
||||
int t_hight = (((int) raw_data[5]) << 8) | raw_data[6];
|
||||
int t_low = (((int) raw_data[7]) << 8) | raw_data[8];
|
||||
data.t_on = t_low;
|
||||
data.t_off = t_hight - t_low;
|
||||
data.is_available = true;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
int ugreen_leds_t::_change_status(led_type_t id, uint8_t command, std::array < std::optional < uint8_t > , 4 > params) {
|
||||
std::vector < uint8_t > data {
|
||||
0x00, 0xa0, 0x01,
|
||||
0x00, 0x00, command,
|
||||
params[0].value_or(0x00),
|
||||
params[1].value_or(0x00),
|
||||
params[2].value_or(0x00),
|
||||
params[3].value_or(0x00),
|
||||
};
|
||||
|
||||
append_checksum(data);
|
||||
data[0] = (uint8_t) id;
|
||||
return _i2c.write_block_data((uint8_t) id, data);
|
||||
}
|
||||
|
||||
int ugreen_leds_t::set_onoff(led_type_t id, uint8_t status) {
|
||||
if (status >= 2) return -1;
|
||||
return _change_status(id, 0x03, {
|
||||
status
|
||||
});
|
||||
}
|
||||
|
||||
int ugreen_leds_t::_set_blink_or_breath(uint8_t command, led_type_t id, uint16_t t_on, uint16_t t_off) {
|
||||
uint16_t t_hight = t_on + t_off;
|
||||
uint16_t t_low = t_on;
|
||||
return _change_status(id, command, {
|
||||
(uint8_t)(t_hight >> 8),
|
||||
(uint8_t)(t_hight & 0xff),
|
||||
(uint8_t)(t_low >> 8),
|
||||
(uint8_t)(t_low & 0xff),
|
||||
});
|
||||
}
|
||||
|
||||
int ugreen_leds_t::set_rgb(led_type_t id, uint8_t r, uint8_t g, uint8_t b) {
|
||||
return _change_status(id, 0x02, { r, g, b } );
|
||||
}
|
||||
|
||||
int ugreen_leds_t::set_brightness(led_type_t id, uint8_t brightness) {
|
||||
return _change_status(id, 0x01, { brightness } );
|
||||
}
|
||||
|
||||
bool ugreen_leds_t::is_last_modification_successful() {
|
||||
return _i2c.read_byte_data(0x80) == 1;
|
||||
}
|
||||
|
||||
int ugreen_leds_t::set_blink(led_type_t id, uint16_t t_on, uint16_t t_off) {
|
||||
return _set_blink_or_breath(0x04, id, t_on, t_off);
|
||||
}
|
||||
|
||||
int ugreen_leds_t::set_breath(led_type_t id, uint16_t t_on, uint16_t t_off) {
|
||||
return _set_blink_or_breath(0x05, id, t_on, t_off);
|
||||
}
|
||||
58
sources/ugreen-led-cli/main.h
Normal file
58
sources/ugreen-led-cli/main.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef __UGREEN_LEDS_H__
|
||||
#define __UGREEN_LEDS_H__
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include "i2c.h"
|
||||
|
||||
#define UGREEN_LED_POWER ugreen_leds_t::led_type_t::power
|
||||
#define UGREEN_LED_NETDEV ugreen_leds_t::led_type_t::netdev
|
||||
#define UGREEN_LED_DISK1 ugreen_leds_t::led_type_t::disk1
|
||||
#define UGREEN_LED_DISK2 ugreen_leds_t::led_type_t::disk2
|
||||
#define UGREEN_LED_DISK3 ugreen_leds_t::led_type_t::disk3
|
||||
#define UGREEN_LED_DISK4 ugreen_leds_t::led_type_t::disk4
|
||||
#define UGREEN_LED_DISK5 ugreen_leds_t::led_type_t::disk5
|
||||
#define UGREEN_LED_DISK6 ugreen_leds_t::led_type_t::disk6
|
||||
#define UGREEN_LED_DISK7 ugreen_leds_t::led_type_t::disk7
|
||||
#define UGREEN_LED_DISK8 ugreen_leds_t::led_type_t::disk8
|
||||
|
||||
// #define UGREEN_LED_I2C_DEV "/dev/i2c-1"
|
||||
#define UGREEN_LED_I2C_ADDR 0x3a
|
||||
|
||||
class ugreen_leds_t {
|
||||
|
||||
i2c_device_t _i2c;
|
||||
|
||||
public:
|
||||
enum class op_mode_t: uint8_t {
|
||||
off = 0, on, blink, breath
|
||||
};
|
||||
|
||||
enum class led_type_t: uint8_t {
|
||||
power = 0, netdev, disk1, disk2, disk3, disk4, disk5, disk6, disk7, disk8
|
||||
};
|
||||
|
||||
struct led_data_t {
|
||||
bool is_available;
|
||||
op_mode_t op_mode;
|
||||
uint8_t brightness;
|
||||
uint8_t color_r, color_g, color_b;
|
||||
uint16_t t_on, t_off;
|
||||
};
|
||||
|
||||
public:
|
||||
int start();
|
||||
led_data_t get_status(led_type_t id);
|
||||
int set_onoff(led_type_t id, uint8_t status);
|
||||
int set_rgb(led_type_t id, uint8_t r, uint8_t g, uint8_t b);
|
||||
int set_brightness(led_type_t id, uint8_t brightness);
|
||||
int set_blink(led_type_t id, uint16_t t_on, uint16_t t_off);
|
||||
int set_breath(led_type_t id, uint16_t t_on, uint16_t t_off);
|
||||
bool is_last_modification_successful();
|
||||
|
||||
private:
|
||||
int _set_blink_or_breath(uint8_t command, led_type_t id, uint16_t t_on, uint16_t t_off);
|
||||
int _change_status(led_type_t id, uint8_t command, std::array < std::optional < uint8_t > , 4 > params);
|
||||
};
|
||||
|
||||
#endif
|
||||
288
sources/ugreen-led-cli/ugreen-led-cli.cpp
Normal file
288
sources/ugreen-led-cli/ugreen-led-cli.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include "main.h"
|
||||
|
||||
#define MAX_RETRY_COUNT 5
|
||||
#define USLEEP_READ_STATUS_INTERVAL 8000
|
||||
#define USLEEP_READ_STATUS_RETRY_INTERVAL 3000
|
||||
#define USLEEP_MODIFICATION_INTERVAL 500
|
||||
#define USLEEP_MODIFICATION_RETRY_INTERVAL 3000
|
||||
#define USLEEP_MODIFICATION_QUERY_RESULT_INTERVAL 2000
|
||||
|
||||
static std::map<std::string, ugreen_leds_t::led_type_t> led_name_map = {
|
||||
{ "power", UGREEN_LED_POWER },
|
||||
{ "netdev", UGREEN_LED_NETDEV },
|
||||
{ "disk1", UGREEN_LED_DISK1 },
|
||||
{ "disk2", UGREEN_LED_DISK2 },
|
||||
{ "disk3", UGREEN_LED_DISK3 },
|
||||
{ "disk4", UGREEN_LED_DISK4 },
|
||||
{ "disk5", UGREEN_LED_DISK5 },
|
||||
{ "disk6", UGREEN_LED_DISK6 },
|
||||
{ "disk7", UGREEN_LED_DISK7 },
|
||||
{ "disk8", UGREEN_LED_DISK8 },
|
||||
};
|
||||
|
||||
using led_type_pair = std::pair < std::string, ugreen_leds_t::led_type_t > ;
|
||||
|
||||
ugreen_leds_t::led_data_t get_status_robust(ugreen_leds_t & leds_controller, ugreen_leds_t::led_type_t led) {
|
||||
usleep(USLEEP_READ_STATUS_INTERVAL);
|
||||
auto data = leds_controller.get_status(led);
|
||||
|
||||
for (int retry_cnt = 1; !data.is_available && retry_cnt < MAX_RETRY_COUNT; ++retry_cnt) {
|
||||
usleep(USLEEP_READ_STATUS_RETRY_INTERVAL);
|
||||
data = leds_controller.get_status(led);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void show_leds_info(ugreen_leds_t & leds_controller,
|
||||
const std::vector < led_type_pair > & leds) {
|
||||
|
||||
for (auto led: leds) {
|
||||
|
||||
auto data = get_status_robust(leds_controller, led.second);
|
||||
|
||||
if (!data.is_available) {
|
||||
std::printf("%s: unavailable or non-existent\n", led.first.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string op_mode_txt = "unknown";
|
||||
|
||||
switch (data.op_mode) {
|
||||
case ugreen_leds_t::op_mode_t::off:
|
||||
op_mode_txt = "off";
|
||||
break;
|
||||
case ugreen_leds_t::op_mode_t::on:
|
||||
op_mode_txt = "on";
|
||||
break;
|
||||
case ugreen_leds_t::op_mode_t::blink:
|
||||
op_mode_txt = "blink";
|
||||
break;
|
||||
case ugreen_leds_t::op_mode_t::breath:
|
||||
op_mode_txt = "breath";
|
||||
break;
|
||||
};
|
||||
|
||||
std::printf("%s: status = %s, brightness = %d, color = RGB(%d, %d, %d)",
|
||||
led.first.c_str(), op_mode_txt.c_str(), (int) data.brightness,
|
||||
(int) data.color_r, (int) data.color_g, (int) data.color_b);
|
||||
|
||||
if (data.op_mode == ugreen_leds_t::op_mode_t::blink) {
|
||||
std::printf(", blink_on = %d ms, blink_off = %d ms",
|
||||
(int) data.t_on, (int) data.t_off);
|
||||
}
|
||||
|
||||
std::puts("");
|
||||
}
|
||||
}
|
||||
|
||||
void show_help() {
|
||||
std::cerr <<
|
||||
"Usage: ugreen-led-cli [LED-NAME...] [-on] [-off] [-(blink|breath) T_ON T_OFF] [-color R G B] [-brightness BRIGHTNESS] [-status]\n\n"
|
||||
" LED_NAME: Separated by white space, possible values are { power, netdev, disk[1-8], all }.\n\n"
|
||||
" -on / -off: Turn ON / OFF corresponding LEDs.\n\n"
|
||||
" -blink / -breath: set LED to the blink / breath mode. This mode keeps the LED on for T_ON millseconds\n"
|
||||
" and then keeps it off for T_OFF millseconds.\n"
|
||||
" T_ON and T_OFF should belong to [0, 65535].\n\n"
|
||||
" -color: Set the color of corresponding LEDs.\n"
|
||||
" R, G and B should belong to [0, 255].\n\n"
|
||||
" -brightness: Set the brightness of corresponding LEDs.\n"
|
||||
" BRIGHTNESS should belong to [0, 255].\n\n"
|
||||
" -status: Display the status of corresponding LEDs.\n" <<
|
||||
std::endl;
|
||||
}
|
||||
|
||||
void show_help_and_exit() {
|
||||
show_help();
|
||||
std::exit(-1);
|
||||
}
|
||||
|
||||
ugreen_leds_t::led_type_t get_led_type(const std::string & name) {
|
||||
if (led_name_map.find(name) == led_name_map.end()) {
|
||||
std::cerr << "Err: unknown LED name " << name << std::endl;
|
||||
show_help_and_exit();
|
||||
}
|
||||
|
||||
return led_name_map[name];
|
||||
}
|
||||
|
||||
int parse_integer(const std::string & str, int low = 0, int high = 0xffff) {
|
||||
std::size_t size;
|
||||
int x = std::stoi(str, & size);
|
||||
|
||||
if (size != str.size()) {
|
||||
std::cerr << "Err: " << str << " is not an integer." << std::endl;
|
||||
show_help_and_exit();
|
||||
}
|
||||
|
||||
if (x < low || x > high) {
|
||||
std::cerr << "Err: " << str << " is not in [" << low << ", " << high << "]" << std::endl;
|
||||
show_help_and_exit();
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
if (argc < 2) {
|
||||
show_help();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ugreen_leds_t leds_controller;
|
||||
if (leds_controller.start() != 0) {
|
||||
std::cerr << "The command-line tool and the kernel module do conflict." << std::endl;
|
||||
std::cerr << "To use the command-line tool, you must unload the led_ugreen module." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::deque < std::string > args;
|
||||
for (int i = 1; i < argc; ++i)
|
||||
args.emplace_back(argv[i]);
|
||||
|
||||
// parse LED names
|
||||
std::vector < led_type_pair > leds;
|
||||
|
||||
while (!args.empty() && args.front().front() != '-') {
|
||||
if (args.front() == "all") {
|
||||
for (const auto & v: led_name_map) {
|
||||
if (get_status_robust(leds_controller, v.second).is_available)
|
||||
leds.push_back(v);
|
||||
}
|
||||
} else {
|
||||
auto led_type = get_led_type(args.front());
|
||||
leds.emplace_back(args.front(), led_type);
|
||||
}
|
||||
|
||||
args.pop_front();
|
||||
}
|
||||
|
||||
// if no additional parameters, display current info
|
||||
if (args.empty()) {
|
||||
show_leds_info(leds_controller, leds);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// (is_modification, callback)
|
||||
using ops_pair = std::pair < bool, std:: function < int(led_type_pair) >> ;
|
||||
std::vector < ops_pair > ops_seq;
|
||||
|
||||
while (!args.empty()) {
|
||||
if (args.front() == "-on" || args.front() == "-off") {
|
||||
// turn on / off LEDs
|
||||
uint8_t status = args.front() == "-on";
|
||||
ops_seq.emplace_back(true, [ = , & leds_controller](led_type_pair led) {
|
||||
return leds_controller.set_onoff(led.second, status);
|
||||
});
|
||||
|
||||
args.pop_front();
|
||||
} else if (args.front() == "-blink" || args.front() == "-breath") {
|
||||
// set blink
|
||||
bool is_blink = (args.front() == "-blink");
|
||||
args.pop_front();
|
||||
|
||||
if (args.size() < 2) {
|
||||
std::cerr << "Err: -blink / -breath requires 2 parameters" << std::endl;
|
||||
show_help_and_exit();
|
||||
}
|
||||
|
||||
uint16_t t_on = parse_integer(args.front(), 0x0000, 0xffff);
|
||||
args.pop_front();
|
||||
uint16_t t_off = parse_integer(args.front(), 0x0000, 0xffff);
|
||||
args.pop_front();
|
||||
|
||||
ops_seq.emplace_back(true, [ = , & leds_controller](led_type_pair led) {
|
||||
if (is_blink) {
|
||||
return leds_controller.set_blink(led.second, t_on, t_off);
|
||||
} else {
|
||||
return leds_controller.set_breath(led.second, t_on, t_off);
|
||||
}
|
||||
});
|
||||
} else if (args.front() == "-color") {
|
||||
// set color
|
||||
args.pop_front();
|
||||
|
||||
if (args.size() < 3) {
|
||||
std::cerr << "Err: -color requires 3 parameters" << std::endl;
|
||||
show_help_and_exit();
|
||||
}
|
||||
|
||||
uint8_t R = parse_integer(args.front(), 0x00, 0xff);
|
||||
args.pop_front();
|
||||
uint8_t G = parse_integer(args.front(), 0x00, 0xff);
|
||||
args.pop_front();
|
||||
uint8_t B = parse_integer(args.front(), 0x00, 0xff);
|
||||
args.pop_front();
|
||||
ops_seq.emplace_back(true, [ = , & leds_controller](led_type_pair led) {
|
||||
return leds_controller.set_rgb(led.second, R, G, B);
|
||||
});
|
||||
} else if (args.front() == "-brightness") {
|
||||
// set brightness
|
||||
args.pop_front();
|
||||
|
||||
if (args.size() < 1) {
|
||||
std::cerr << "Err: -brightness requires 1 parameter" << std::endl;
|
||||
show_help_and_exit();
|
||||
}
|
||||
|
||||
uint8_t brightness = parse_integer(args.front(), 0x00, 0xff);
|
||||
args.pop_front();
|
||||
ops_seq.emplace_back(true, [ = , & leds_controller](led_type_pair led) {
|
||||
return leds_controller.set_brightness(led.second, brightness);
|
||||
});
|
||||
} else if (args.front() == "-status") {
|
||||
// display the status
|
||||
args.pop_front();
|
||||
|
||||
ops_seq.emplace_back(false, [ = , & leds_controller](led_type_pair led) {
|
||||
show_leds_info(leds_controller, {
|
||||
led
|
||||
});
|
||||
return 0;
|
||||
});
|
||||
} else {
|
||||
std::cerr << "Err: unknown parameter " << args.front() << std::endl;
|
||||
show_help_and_exit();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto & led: leds) {
|
||||
for (const auto & fn_pair: ops_seq) {
|
||||
bool is_modification = fn_pair.first;
|
||||
const auto & fn = fn_pair.second;
|
||||
int last_status = -1;
|
||||
|
||||
for (int retry_cnt = 0; retry_cnt < MAX_RETRY_COUNT && last_status != 0; ++retry_cnt) {
|
||||
|
||||
if (retry_cnt == 0) {
|
||||
if (is_modification)
|
||||
usleep(USLEEP_MODIFICATION_INTERVAL); // usleep_range(200, 0x5dc)
|
||||
} else {
|
||||
usleep(USLEEP_MODIFICATION_RETRY_INTERVAL);
|
||||
}
|
||||
|
||||
last_status = fn(led);
|
||||
|
||||
if (last_status == 0 && is_modification) {
|
||||
usleep(USLEEP_MODIFICATION_QUERY_RESULT_INTERVAL);
|
||||
last_status = !leds_controller.is_last_modification_successful();
|
||||
}
|
||||
}
|
||||
|
||||
if (last_status != 0) {
|
||||
std::cerr << "failed to change status!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user