#include "mag160c/mag160c.h" #include #include #include #include #include #include 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(std::tolower(static_cast(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(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(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(d.bus) << " address " << static_cast(d.address) << " interface " << static_cast(d.interface_number) << " bulk-in 0x" << std::hex << static_cast(d.bulk_in_endpoint) << " bulk-out 0x" << static_cast(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; }