773 lines
23 KiB
C
773 lines
23 KiB
C
/*
|
|
* Azeron CLI - Command-line tool for Azeron device configuration
|
|
* Copyright (C) 2024 Azeron Linux Project
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <getopt.h>
|
|
#include "azeron.h"
|
|
#include "../libazeron/internal.h"
|
|
|
|
#define AZERON_CLI_VERSION "1.0.0"
|
|
|
|
/* Command function prototypes */
|
|
int cmd_list(int argc, char *argv[]);
|
|
int cmd_info(int argc, char *argv[]);
|
|
int cmd_map_button(int argc, char *argv[]);
|
|
int cmd_show_mappings(int argc, char *argv[]);
|
|
int cmd_set_profile(int argc, char *argv[]);
|
|
int cmd_save_profile(int argc, char *argv[]);
|
|
int cmd_load_profile(int argc, char *argv[]);
|
|
int cmd_export_config(int argc, char *argv[]);
|
|
int cmd_import_config(int argc, char *argv[]);
|
|
int cmd_set_stick(int argc, char *argv[]);
|
|
int cmd_read_raw(int argc, char *argv[]);
|
|
|
|
/* Command structure */
|
|
struct command {
|
|
const char *name;
|
|
const char *description;
|
|
int (*func)(int argc, char *argv[]);
|
|
};
|
|
|
|
static struct command commands[] = {
|
|
{"list", "List connected Azeron devices", cmd_list},
|
|
{"info", "Show device information", cmd_info},
|
|
{"map-button", "Map a button to a key or action", cmd_map_button},
|
|
{"show-mappings", "Show current button mappings", cmd_show_mappings},
|
|
{"set-profile", "Set active profile", cmd_set_profile},
|
|
{"save-profile", "Save current configuration to profile", cmd_save_profile},
|
|
{"load-profile", "Load configuration from profile", cmd_load_profile},
|
|
{"export-config", "Export configuration to file", cmd_export_config},
|
|
{"import-config", "Import configuration from file", cmd_import_config},
|
|
{"set-stick", "Configure analog stick settings", cmd_set_stick},
|
|
{"read-raw", "Read raw memory from device", cmd_read_raw},
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
/* Print usage information */
|
|
static void print_usage(const char *program_name)
|
|
{
|
|
printf("Azeron CLI - Configuration tool for Azeron devices\n");
|
|
printf("Version: %s\n\n", AZERON_CLI_VERSION);
|
|
printf("Usage: %s <command> [options]\n\n", program_name);
|
|
printf("Commands:\n");
|
|
|
|
for (int i = 0; commands[i].name != NULL; i++) {
|
|
printf(" %-15s %s\n", commands[i].name, commands[i].description);
|
|
}
|
|
|
|
printf("\nExamples:\n");
|
|
printf(" %s list\n", program_name);
|
|
printf(" %s info\n", program_name);
|
|
printf(" %s map-button 5 KEY_W\n", program_name);
|
|
printf(" %s set-profile 1\n", program_name);
|
|
printf("\nFor help with a specific command:\n");
|
|
printf(" %s <command> --help\n", program_name);
|
|
}
|
|
|
|
/* List connected devices */
|
|
int cmd_list(int argc, char *argv[])
|
|
{
|
|
struct azeron_device_info *devices;
|
|
size_t count;
|
|
int ret;
|
|
int i;
|
|
|
|
(void)argc;
|
|
(void)argv;
|
|
|
|
ret = azeron_init();
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to initialize library: %s\n", azeron_error_string(ret));
|
|
return 1;
|
|
}
|
|
|
|
ret = azeron_device_list(&devices, &count);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to list devices: %s\n", azeron_error_string(ret));
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
|
|
if (count == 0) {
|
|
printf("No Azeron devices found.\n");
|
|
printf("Make sure your device is connected and you have proper permissions.\n");
|
|
} else {
|
|
printf("Found %zu Azeron device(s):\n\n", count);
|
|
|
|
for (i = 0; i < count; i++) {
|
|
printf("Device %d:\n", i);
|
|
printf(" Product: %s\n", devices[i].product);
|
|
printf(" Manufacturer: %s\n", devices[i].manufacturer);
|
|
printf(" Serial: %s\n", devices[i].serial_number);
|
|
printf(" USB ID: %04x:%04x\n", devices[i].vendor_id, devices[i].product_id);
|
|
printf(" Firmware: %d.%d\n",
|
|
devices[i].firmware_version >> 8,
|
|
devices[i].firmware_version & 0xFF);
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
azeron_device_list_free(devices, count);
|
|
azeron_exit();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Show device information */
|
|
int cmd_info(int argc, char *argv[])
|
|
{
|
|
struct azeron_device *device;
|
|
struct azeron_device_info info;
|
|
struct azeron_stick_config stick;
|
|
int ret;
|
|
int device_index = 0;
|
|
|
|
/* Parse options */
|
|
static struct option long_options[] = {
|
|
{"device", required_argument, 0, 'd'},
|
|
{"help", no_argument, 0, 'h'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
int opt;
|
|
int option_index = 0;
|
|
while ((opt = getopt_long(argc, argv, "d:h", long_options, &option_index)) != -1) {
|
|
switch (opt) {
|
|
case 'd':
|
|
device_index = atoi(optarg);
|
|
break;
|
|
case 'h':
|
|
printf("Usage: %s info [options]\n", argv[0]);
|
|
printf("Options:\n");
|
|
printf(" -d, --device <index> Select device by index (default: 0)\n");
|
|
printf(" -h, --help Show this help message\n");
|
|
return 0;
|
|
default:
|
|
fprintf(stderr, "Unknown option. Use --help for usage.\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
ret = azeron_init();
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to initialize library: %s\n", azeron_error_string(ret));
|
|
return 1;
|
|
}
|
|
|
|
ret = azeron_device_open_index(&device, device_index);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to open device %d: %s\n", device_index, azeron_error_string(ret));
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
|
|
ret = azeron_device_get_info(device, &info);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to get device info: %s\n", azeron_error_string(ret));
|
|
azeron_device_close(device);
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
|
|
printf("Device Information:\n");
|
|
printf("===================\n\n");
|
|
printf("Product: %s\n", info.product);
|
|
printf("Manufacturer: %s\n", info.manufacturer);
|
|
printf("Serial Number: %s\n", info.serial_number);
|
|
printf("USB ID: %04x:%04x\n", info.vendor_id, info.product_id);
|
|
printf("Firmware: %d.%d\n", info.firmware_version >> 8, info.firmware_version & 0xFF);
|
|
printf("Active Profile: %d\n", info.active_profile);
|
|
|
|
ret = azeron_device_get_stick_config(device, &stick);
|
|
if (ret == AZERON_SUCCESS) {
|
|
printf("\nStick Configuration:\n");
|
|
printf("--------------------\n");
|
|
printf("Mode: %s\n", azeron_stick_mode_string(stick.mode));
|
|
printf("Deadzone: %d%%\n", stick.deadzone);
|
|
printf("Sensitivity: %d\n", stick.sensitivity);
|
|
printf("Response Curve: %d\n", stick.response_curve);
|
|
printf("Invert X: %s\n", stick.invert_x ? "Yes" : "No");
|
|
printf("Invert Y: %s\n", stick.invert_y ? "Yes" : "No");
|
|
}
|
|
|
|
azeron_device_close(device);
|
|
azeron_exit();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Show current button mappings */
|
|
int cmd_show_mappings(int argc, char *argv[])
|
|
{
|
|
struct azeron_device *device;
|
|
int ret;
|
|
int device_index = 0;
|
|
int i;
|
|
|
|
/* Parse options */
|
|
static struct option long_options[] = {
|
|
{"device", required_argument, 0, 'd'},
|
|
{"help", no_argument, 0, 'h'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
int opt;
|
|
int option_index = 0;
|
|
while ((opt = getopt_long(argc, argv, "d:h", long_options, &option_index)) != -1) {
|
|
switch (opt) {
|
|
case 'd':
|
|
device_index = atoi(optarg);
|
|
break;
|
|
case 'h':
|
|
printf("Usage: %s show-mappings [options]\n", argv[0]);
|
|
printf("Options:\n");
|
|
printf(" -d, --device <index> Select device by index (default: 0)\n");
|
|
printf(" -h, --help Show this help message\n");
|
|
return 0;
|
|
default:
|
|
fprintf(stderr, "Unknown option. Use --help for usage.\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
ret = azeron_init();
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to initialize library: %s\n", azeron_error_string(ret));
|
|
return 1;
|
|
}
|
|
|
|
ret = azeron_device_open_index(&device, device_index);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to open device %d: %s\n", device_index, azeron_error_string(ret));
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
|
|
printf("Button Mappings:\n");
|
|
printf("================\n\n");
|
|
printf("%-10s %-15s %s\n", "Button", "Type", "Mapping");
|
|
printf("%-10s %-15s %s\n", "------", "----", "-------");
|
|
|
|
for (i = 0; i < 30; i++) {
|
|
struct azeron_button_mapping mapping;
|
|
ret = azeron_device_get_button_mapping(device, i, &mapping);
|
|
if (ret == AZERON_SUCCESS) {
|
|
printf("%-10d %-15s 0x%02x\n",
|
|
i + 1,
|
|
azeron_button_type_string(mapping.type),
|
|
mapping.key_code);
|
|
} else {
|
|
printf("%-10d %-15s <error: %s>\n",
|
|
i + 1,
|
|
"unknown",
|
|
azeron_error_string(ret));
|
|
}
|
|
}
|
|
|
|
azeron_device_close(device);
|
|
azeron_exit();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Map button */
|
|
int cmd_map_button(int argc, char *argv[])
|
|
{
|
|
struct azeron_device *device;
|
|
struct azeron_button_mapping mapping;
|
|
int ret;
|
|
int device_index = 0;
|
|
int button_id;
|
|
const char *key_name;
|
|
|
|
if (argc < 3) {
|
|
fprintf(stderr, "Usage: %s map-button <button-id> <key> [options]\n", argv[0]);
|
|
fprintf(stderr, "Example: %s map-button 1 KEY_W\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
button_id = atoi(argv[1]) - 1; /* 1-based to 0-based */
|
|
key_name = argv[2];
|
|
|
|
if (button_id < 0 || button_id >= 30) {
|
|
fprintf(stderr, "Error: Invalid button ID %d. Must be 1-30.\n", button_id + 1);
|
|
return 1;
|
|
}
|
|
|
|
/* Parse options */
|
|
static struct option long_options[] = {
|
|
{"device", required_argument, 0, 'd'},
|
|
{"help", no_argument, 0, 'h'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
int opt;
|
|
int option_index = 0;
|
|
optind = 3; /* Skip command, button-id and key */
|
|
while ((opt = getopt_long(argc, argv, "d:h", long_options, &option_index)) != -1) {
|
|
switch (opt) {
|
|
case 'd':
|
|
device_index = atoi(optarg);
|
|
break;
|
|
case 'h':
|
|
printf("Usage: %s map-button <button-id> <key> [options]\n", argv[0]);
|
|
return 0;
|
|
default:
|
|
fprintf(stderr, "Unknown option. Use --help for usage.\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
ret = azeron_init();
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to initialize library: %s\n", azeron_error_string(ret));
|
|
return 1;
|
|
}
|
|
|
|
ret = azeron_device_open_index(&device, device_index);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to open device %d: %s\n", device_index, azeron_error_string(ret));
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
|
|
/* Prepare mapping */
|
|
mapping.button_id = (uint8_t)button_id;
|
|
mapping.type = AZERON_BTN_KEYBOARD;
|
|
|
|
int keycode = azeron_keycode_from_string(key_name);
|
|
if (keycode == -1) {
|
|
/* Try parsing as hex if string lookup fails */
|
|
if (strncmp(key_name, "0x", 2) == 0) {
|
|
mapping.key_code = (uint16_t)strtol(key_name, NULL, 16);
|
|
} else {
|
|
fprintf(stderr, "Error: Unknown key '%s'.\n", key_name);
|
|
azeron_device_close(device);
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
} else {
|
|
mapping.key_code = (uint16_t)keycode;
|
|
}
|
|
|
|
printf("Mapping button %d to key 0x%02x (%s)...\n", button_id + 1, mapping.key_code, key_name);
|
|
ret = azeron_device_set_button_mapping(device, &mapping);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to set button mapping: %s\n", azeron_error_string(ret));
|
|
azeron_device_close(device);
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
|
|
printf("Mapping updated successfully (Note: changes are temporary until saved with save-profile).\n");
|
|
|
|
azeron_device_close(device);
|
|
azeron_exit();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Set active profile */
|
|
int cmd_set_profile(int argc, char *argv[])
|
|
{
|
|
struct azeron_device *device;
|
|
int ret;
|
|
int device_index = 0;
|
|
int profile_id;
|
|
|
|
if (argc < 2) {
|
|
fprintf(stderr, "Usage: %s set-profile <profile-id> [options]\n", argv[0]);
|
|
fprintf(stderr, "Example: %s set-profile 1\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
profile_id = atoi(argv[1]);
|
|
if (profile_id < 0 || profile_id > 2) {
|
|
fprintf(stderr, "Error: Invalid profile ID %d. Must be 0, 1 or 2.\n", profile_id);
|
|
return 1;
|
|
}
|
|
|
|
/* Parse options */
|
|
static struct option long_options[] = {
|
|
{"device", required_argument, 0, 'd'},
|
|
{"help", no_argument, 0, 'h'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
int opt;
|
|
int option_index = 0;
|
|
optind = 2; /* Skip command and profile-id */
|
|
while ((opt = getopt_long(argc, argv, "d:h", long_options, &option_index)) != -1) {
|
|
switch (opt) {
|
|
case 'd':
|
|
device_index = atoi(optarg);
|
|
break;
|
|
case 'h':
|
|
printf("Usage: %s set-profile <profile-id> [options]\n", argv[0]);
|
|
printf("Options:\n");
|
|
printf(" -d, --device <index> Select device by index (default: 0)\n");
|
|
printf(" -h, --help Show this help message\n");
|
|
return 0;
|
|
default:
|
|
fprintf(stderr, "Unknown option. Use --help for usage.\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
ret = azeron_init();
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to initialize library: %s\n", azeron_error_string(ret));
|
|
return 1;
|
|
}
|
|
|
|
ret = azeron_device_open_index(&device, device_index);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to open device %d: %s\n", device_index, azeron_error_string(ret));
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
|
|
printf("Setting active profile to %d...\n", profile_id);
|
|
ret = azeron_device_set_active_profile(device, profile_id);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to set active profile: %s\n", azeron_error_string(ret));
|
|
azeron_device_close(device);
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
|
|
printf("Active profile set to %d.\n", profile_id);
|
|
|
|
azeron_device_close(device);
|
|
azeron_exit();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Save profile */
|
|
int cmd_save_profile(int argc, char *argv[])
|
|
{
|
|
struct azeron_device *device;
|
|
int ret;
|
|
int device_index = 0;
|
|
int profile_id;
|
|
|
|
if (argc < 2) {
|
|
fprintf(stderr, "Usage: %s save-profile <profile-id> [options]\n", argv[0]);
|
|
fprintf(stderr, "Example: %s save-profile 0\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
profile_id = atoi(argv[1]);
|
|
if (profile_id < 0 || profile_id > 2) {
|
|
fprintf(stderr, "Error: Invalid profile ID %d. Must be 0, 1 or 2.\n", profile_id);
|
|
return 1;
|
|
}
|
|
|
|
/* Parse options */
|
|
static struct option long_options[] = {
|
|
{"device", required_argument, 0, 'd'},
|
|
{"help", no_argument, 0, 'h'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
int opt;
|
|
int option_index = 0;
|
|
optind = 2; /* Skip command and profile-id */
|
|
while ((opt = getopt_long(argc, argv, "d:h", long_options, &option_index)) != -1) {
|
|
switch (opt) {
|
|
case 'd':
|
|
device_index = atoi(optarg);
|
|
break;
|
|
case 'h':
|
|
printf("Usage: %s save-profile <profile-id> [options]\n", argv[0]);
|
|
printf("Options:\n");
|
|
printf(" -d, --device <index> Select device by index (default: 0)\n");
|
|
printf(" -h, --help Show this help message\n");
|
|
return 0;
|
|
default:
|
|
fprintf(stderr, "Unknown option. Use --help for usage.\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
ret = azeron_init();
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to initialize library: %s\n", azeron_error_string(ret));
|
|
return 1;
|
|
}
|
|
|
|
ret = azeron_device_open_index(&device, device_index);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to open device %d: %s\n", device_index, azeron_error_string(ret));
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
|
|
printf("Saving configuration to profile %d EEPROM...\n", profile_id);
|
|
ret = azeron_device_save_profile(device, profile_id);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to save profile: %s\n", azeron_error_string(ret));
|
|
azeron_device_close(device);
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
|
|
printf("Profile %d saved successfully.\n", profile_id);
|
|
|
|
azeron_device_close(device);
|
|
azeron_exit();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Load profile (placeholder) */
|
|
int cmd_load_profile(int argc, char *argv[])
|
|
{
|
|
if (argc < 2) {
|
|
fprintf(stderr, "Usage: %s load-profile <profile-name>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
fprintf(stderr, "Profile loading is not yet implemented.\n");
|
|
fprintf(stderr, "Protocol reverse engineering is required for this feature.\n");
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Export config (placeholder) */
|
|
int cmd_export_config(int argc, char *argv[])
|
|
{
|
|
if (argc < 2) {
|
|
fprintf(stderr, "Usage: %s export-config <filename>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
fprintf(stderr, "Config export is not yet implemented.\n");
|
|
fprintf(stderr, "Protocol reverse engineering is required for this feature.\n");
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Import config (placeholder) */
|
|
int cmd_import_config(int argc, char *argv[])
|
|
{
|
|
if (argc < 2) {
|
|
fprintf(stderr, "Usage: %s import-config <filename>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
fprintf(stderr, "Config import is not yet implemented.\n");
|
|
fprintf(stderr, "Protocol reverse engineering is required for this feature.\n");
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Set stick configuration */
|
|
int cmd_set_stick(int argc, char *argv[])
|
|
{
|
|
struct azeron_device *device;
|
|
struct azeron_stick_config stick;
|
|
int ret;
|
|
int device_index = 0;
|
|
|
|
/* Parse options */
|
|
static struct option long_options[] = {
|
|
{"device", required_argument, 0, 'd'},
|
|
{"deadzone", required_argument, 0, 'z'},
|
|
{"sensitivity", required_argument, 0, 's'},
|
|
{"curve", required_argument, 0, 'c'},
|
|
{"invert-x", no_argument, 0, 'x'},
|
|
{"invert-y", no_argument, 0, 'y'},
|
|
{"help", no_argument, 0, 'h'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
int opt;
|
|
int option_index = 0;
|
|
|
|
/* Initialize defaults from current config if possible, or zeros */
|
|
memset(&stick, 0, sizeof(stick));
|
|
bool dz_set = false, sens_set = false, curve_set = false;
|
|
|
|
while ((opt = getopt_long(argc, argv, "d:z:s:c:xyh", long_options, &option_index)) != -1) {
|
|
switch (opt) {
|
|
case 'd': device_index = atoi(optarg); break;
|
|
case 'z': stick.deadzone = atoi(optarg); dz_set = true; break;
|
|
case 's': stick.sensitivity = atoi(optarg); sens_set = true; break;
|
|
case 'c': stick.response_curve = atoi(optarg); curve_set = true; break;
|
|
case 'x': stick.invert_x = true; break;
|
|
case 'y': stick.invert_y = true; break;
|
|
case 'h':
|
|
printf("Usage: %s set-stick [options]\n", argv[0]);
|
|
printf("Options:\n");
|
|
printf(" -d, --device <index> Select device (default: 0)\n");
|
|
printf(" -z, --deadzone <0-100> Set deadzone percentage\n");
|
|
printf(" -s, --sensitivity <0-255> Set sensitivity\n");
|
|
printf(" -c, --curve <0-255> Set response curve\n");
|
|
printf(" -x, --invert-x Invert X axis\n");
|
|
printf(" -y, --invert-y Invert Y axis\n");
|
|
return 0;
|
|
default:
|
|
fprintf(stderr, "Unknown option. Use --help for usage.\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
ret = azeron_init();
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to initialize library: %s\n", azeron_error_string(ret));
|
|
return 1;
|
|
}
|
|
|
|
ret = azeron_device_open_index(&device, device_index);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to open device %d: %s\n", device_index, azeron_error_string(ret));
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
|
|
/* Get current config to fill in unset values */
|
|
struct azeron_stick_config current;
|
|
ret = azeron_device_get_stick_config(device, ¤t);
|
|
if (ret == AZERON_SUCCESS) {
|
|
if (!dz_set) stick.deadzone = current.deadzone;
|
|
if (!sens_set) stick.sensitivity = current.sensitivity;
|
|
if (!curve_set) stick.response_curve = current.response_curve;
|
|
}
|
|
|
|
printf("Updating stick configuration...\n");
|
|
ret = azeron_device_set_stick_config(device, &stick);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to set stick config: %s\n", azeron_error_string(ret));
|
|
azeron_device_close(device);
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
|
|
printf("Stick configuration updated successfully.\n");
|
|
|
|
azeron_device_close(device);
|
|
azeron_exit();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Read raw memory */
|
|
int cmd_read_raw(int argc, char *argv[])
|
|
{
|
|
struct azeron_device *device;
|
|
int ret;
|
|
int device_index = 0;
|
|
uint32_t offset;
|
|
size_t length = 16;
|
|
|
|
if (argc < 2) {
|
|
fprintf(stderr, "Usage: %s read-raw <offset> [length] [options]\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
offset = (uint32_t)strtol(argv[1], NULL, 0);
|
|
if (argc > 2) {
|
|
length = (size_t)atoi(argv[2]);
|
|
}
|
|
|
|
/* Parse options */
|
|
static struct option long_options[] = {
|
|
{"device", required_argument, 0, 'd'},
|
|
{"help", no_argument, 0, 'h'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
int opt;
|
|
int option_index = 0;
|
|
optind = 3;
|
|
while ((opt = getopt_long(argc, argv, "d:h", long_options, &option_index)) != -1) {
|
|
switch (opt) {
|
|
case 'd':
|
|
device_index = atoi(optarg);
|
|
break;
|
|
case 'h':
|
|
printf("Usage: %s read-raw <offset> [length] [options]\n", argv[0]);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ret = azeron_init();
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to initialize library: %s\n", azeron_error_string(ret));
|
|
return 1;
|
|
}
|
|
|
|
ret = azeron_device_open_index(&device, device_index);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to open device %d: %s\n", device_index, azeron_error_string(ret));
|
|
azeron_exit();
|
|
return 1;
|
|
}
|
|
|
|
uint8_t buffer[64];
|
|
size_t read_size = length > 58 ? 58 : length;
|
|
|
|
printf("Reading %zu bytes from offset 0x%04x...\n", read_size, offset);
|
|
ret = azeron_protocol_read_config(device, offset, buffer, &read_size);
|
|
if (ret != AZERON_SUCCESS) {
|
|
fprintf(stderr, "Failed to read memory: %s\n", azeron_error_string(ret));
|
|
} else {
|
|
printf("Data:");
|
|
for (size_t i = 0; i < read_size; i++) {
|
|
printf(" %02x", buffer[i]);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
azeron_device_close(device);
|
|
azeron_exit();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Main function */
|
|
int main(int argc, char *argv[])
|
|
{
|
|
const char *command;
|
|
int i;
|
|
|
|
if (argc < 2) {
|
|
print_usage(argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
command = argv[1];
|
|
|
|
/* Help command */
|
|
if (strcmp(command, "help") == 0 || strcmp(command, "--help") == 0 || strcmp(command, "-h") == 0) {
|
|
print_usage(argv[0]);
|
|
return 0;
|
|
}
|
|
|
|
/* Version command */
|
|
if (strcmp(command, "version") == 0 || strcmp(command, "--version") == 0 || strcmp(command, "-v") == 0) {
|
|
printf("azeron-cli version %s\n", AZERON_CLI_VERSION);
|
|
return 0;
|
|
}
|
|
|
|
/* Find and execute command */
|
|
for (i = 0; commands[i].name != NULL; i++) {
|
|
if (strcmp(command, commands[i].name) == 0) {
|
|
return commands[i].func(argc - 1, argv + 1);
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "Unknown command: %s\n", command);
|
|
fprintf(stderr, "Use '%s help' for usage information.\n", argv[0]);
|
|
|
|
return 1;
|
|
}
|