233 lines
6.8 KiB
C++
233 lines
6.8 KiB
C++
#include "mag160c/mag160c.h"
|
|
|
|
#include <cctype>
|
|
#include <cstdlib>
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
namespace {
|
|
|
|
void print_usage() {
|
|
std::cout << "usage:\n"
|
|
<< " mag160c-cli probe\n"
|
|
<< " mag160c-cli tcm-rotate --dry-run ANGLE\n"
|
|
<< " mag160c-cli tcm-light --dry-run COLOR MODE\n"
|
|
<< " mag160c-cli ir-info\n";
|
|
}
|
|
|
|
std::string lower(std::string value) {
|
|
for (char& ch : value) {
|
|
ch = static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
|
|
}
|
|
return value;
|
|
}
|
|
|
|
void print_hex(const uint8_t* bytes, size_t size) {
|
|
std::ios old_state(nullptr);
|
|
old_state.copyfmt(std::cout);
|
|
|
|
for (size_t i = 0; i < size; ++i) {
|
|
if (i != 0) {
|
|
std::cout << ' ';
|
|
}
|
|
std::cout << std::hex << std::setfill('0') << std::setw(2)
|
|
<< static_cast<unsigned int>(bytes[i]);
|
|
}
|
|
std::cout << '\n';
|
|
std::cout.copyfmt(old_state);
|
|
}
|
|
|
|
int parse_int(const char* text, int* out) {
|
|
if (text == nullptr || out == nullptr) {
|
|
return 0;
|
|
}
|
|
|
|
char* end = nullptr;
|
|
const long value = std::strtol(text, &end, 10);
|
|
if (end == text || *end != '\0') {
|
|
return 0;
|
|
}
|
|
|
|
*out = static_cast<int>(value);
|
|
return 1;
|
|
}
|
|
|
|
int command_tcm_rotate(int argc, char** argv) {
|
|
if (argc != 4 || std::string(argv[2]) != "--dry-run") {
|
|
print_usage();
|
|
return 1;
|
|
}
|
|
|
|
int angle = 0;
|
|
if (!parse_int(argv[3], &angle)) {
|
|
std::cerr << "invalid angle\n";
|
|
return 1;
|
|
}
|
|
|
|
uint8_t frame[64] = {};
|
|
size_t frame_size = 0;
|
|
const mag160c_error_t rc = mag160c_tcm_build_rotate_frame(
|
|
angle, frame, sizeof(frame), &frame_size
|
|
);
|
|
if (rc != MAG160C_OK) {
|
|
std::cerr << mag160c_error_name(rc) << ": " << mag160c_last_error() << '\n';
|
|
return 2;
|
|
}
|
|
|
|
print_hex(frame, frame_size);
|
|
return 0;
|
|
}
|
|
|
|
int parse_color(const std::string& value, mag160c_tcm_light_color_t* out) {
|
|
const std::string v = lower(value);
|
|
if (v == "off") { *out = MAG160C_TCM_LIGHT_OFF; return 1; }
|
|
if (v == "red") { *out = MAG160C_TCM_LIGHT_RED; return 1; }
|
|
if (v == "green") { *out = MAG160C_TCM_LIGHT_GREEN; return 1; }
|
|
if (v == "blue") { *out = MAG160C_TCM_LIGHT_BLUE; return 1; }
|
|
if (v == "yellow") { *out = MAG160C_TCM_LIGHT_YELLOW; return 1; }
|
|
return 0;
|
|
}
|
|
|
|
int parse_mode(const std::string& value, mag160c_tcm_light_mode_t* out) {
|
|
const std::string v = lower(value);
|
|
if (v == "steady") { *out = MAG160C_TCM_LIGHT_STEADY; return 1; }
|
|
if (v == "blink") { *out = MAG160C_TCM_LIGHT_BLINK; return 1; }
|
|
if (v == "breath") { *out = MAG160C_TCM_LIGHT_BREATH; return 1; }
|
|
return 0;
|
|
}
|
|
|
|
int command_tcm_light(int argc, char** argv) {
|
|
if (argc != 5 || std::string(argv[2]) != "--dry-run") {
|
|
print_usage();
|
|
return 1;
|
|
}
|
|
|
|
mag160c_tcm_light_color_t color = MAG160C_TCM_LIGHT_OFF;
|
|
mag160c_tcm_light_mode_t mode = MAG160C_TCM_LIGHT_STEADY;
|
|
if (!parse_color(argv[3], &color)) {
|
|
std::cerr << "invalid color\n";
|
|
return 1;
|
|
}
|
|
if (!parse_mode(argv[4], &mode)) {
|
|
std::cerr << "invalid mode\n";
|
|
return 1;
|
|
}
|
|
|
|
uint8_t frame[64] = {};
|
|
size_t frame_size = 0;
|
|
const mag160c_error_t rc = mag160c_tcm_build_light_frame(
|
|
color, mode, frame, sizeof(frame), &frame_size
|
|
);
|
|
if (rc != MAG160C_OK) {
|
|
std::cerr << mag160c_error_name(rc) << ": " << mag160c_last_error() << '\n';
|
|
return 2;
|
|
}
|
|
|
|
print_hex(frame, frame_size);
|
|
return 0;
|
|
}
|
|
|
|
int command_ir_info() {
|
|
mag160c_context_t* ctx = nullptr;
|
|
mag160c_ir_device_t* ir = nullptr;
|
|
mag160c_ir_info_t info{};
|
|
|
|
mag160c_error_t rc = mag160c_init(&ctx);
|
|
if (rc != MAG160C_OK) {
|
|
std::cerr << mag160c_error_name(rc) << ": " << mag160c_last_error() << '\n';
|
|
return 2;
|
|
}
|
|
|
|
rc = mag160c_ir_open_first(ctx, &ir);
|
|
if (rc == MAG160C_OK) {
|
|
rc = mag160c_ir_get_info(ir, &info);
|
|
}
|
|
|
|
if (rc != MAG160C_OK) {
|
|
std::cerr << mag160c_error_name(rc) << ": " << mag160c_last_error() << '\n';
|
|
mag160c_ir_close(ir);
|
|
mag160c_shutdown(ctx);
|
|
return 2;
|
|
}
|
|
|
|
std::cout << "name: " << info.name << '\n'
|
|
<< "type: " << info.type << '\n'
|
|
<< "size: " << info.width << "x" << info.height << '\n'
|
|
<< "output: " << info.output_width << "x" << info.output_height << '\n'
|
|
<< "protocol: vid 0x833c config=2 iface=0; cmd EP OUT 0x03 / IN 0x82;\n"
|
|
<< " stream EP IN 0x81 (marker 0x1bb1b11b, data at +0x1c, size 0x38+len);\n"
|
|
<< " cmds 0x6bb6b66b..0x6bb6b677 (start 0x6bb6b673, stop 0x6bb6b674,\n"
|
|
<< " ffc 0x6bb6b672); responses 0x5bb5b55b..0x5bb5b57b\n";
|
|
|
|
mag160c_ir_close(ir);
|
|
mag160c_shutdown(ctx);
|
|
return 0;
|
|
}
|
|
|
|
int command_probe() {
|
|
mag160c_context_t* ctx = nullptr;
|
|
mag160c_error_t rc = mag160c_init(&ctx);
|
|
if (rc != MAG160C_OK) {
|
|
std::cerr << mag160c_error_name(rc) << ": " << mag160c_last_error() << '\n';
|
|
return 2;
|
|
}
|
|
|
|
mag160c_device_info_t* devices = nullptr;
|
|
size_t count = 0;
|
|
rc = mag160c_list_devices(ctx, &devices, &count);
|
|
if (rc != MAG160C_OK) {
|
|
std::cerr << mag160c_error_name(rc) << ": " << mag160c_last_error() << '\n';
|
|
mag160c_shutdown(ctx);
|
|
return 2;
|
|
}
|
|
|
|
std::cout << "devices: " << count << '\n';
|
|
std::ios old_state(nullptr);
|
|
old_state.copyfmt(std::cout);
|
|
for (size_t i = 0; i < count; ++i) {
|
|
const mag160c_device_info_t& d = devices[i];
|
|
std::cout << "[" << i << "] vid:pid "
|
|
<< std::hex << std::setfill('0') << std::setw(4) << d.vendor_id
|
|
<< ':' << std::setw(4) << d.product_id
|
|
<< std::dec << " bus " << static_cast<unsigned int>(d.bus)
|
|
<< " address " << static_cast<unsigned int>(d.address)
|
|
<< " interface " << static_cast<unsigned int>(d.interface_number)
|
|
<< " bulk-in 0x" << std::hex << static_cast<unsigned int>(d.bulk_in_endpoint)
|
|
<< " bulk-out 0x" << static_cast<unsigned int>(d.bulk_out_endpoint)
|
|
<< '\n';
|
|
}
|
|
std::cout.copyfmt(old_state);
|
|
|
|
mag160c_free_device_list(devices);
|
|
mag160c_shutdown(ctx);
|
|
return 0;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main(int argc, char** argv) {
|
|
if (argc < 2) {
|
|
print_usage();
|
|
return 1;
|
|
}
|
|
|
|
const std::string command = argv[1];
|
|
if (command == "probe") {
|
|
return command_probe();
|
|
}
|
|
if (command == "tcm-rotate") {
|
|
return command_tcm_rotate(argc, argv);
|
|
}
|
|
if (command == "tcm-light") {
|
|
return command_tcm_light(argc, argv);
|
|
}
|
|
if (command == "ir-info") {
|
|
return command_ir_info();
|
|
}
|
|
|
|
print_usage();
|
|
return 1;
|
|
}
|