Files
MAG160C/analysis/legacy-cpp/tools/mag160c_cli.cpp
T

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;
}