Initial commit
This commit is contained in:
38
libazeron/CMakeLists.txt
Normal file
38
libazeron/CMakeLists.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
# libazeron - Core Azeron device library
|
||||
|
||||
set(LIBAZERON_SOURCES
|
||||
azeron.c
|
||||
protocol.c
|
||||
device.c
|
||||
utils.c
|
||||
)
|
||||
|
||||
set(LIBAZERON_HEADERS
|
||||
azeron.h
|
||||
internal.h
|
||||
)
|
||||
|
||||
# Create shared library
|
||||
add_library(azeron SHARED ${LIBAZERON_SOURCES})
|
||||
|
||||
# Link libraries
|
||||
target_link_libraries(azeron ${LIBUSB_LIBRARIES} ${JSON_LIBRARIES})
|
||||
|
||||
# Set properties
|
||||
set_target_properties(azeron PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION 1
|
||||
PUBLIC_HEADER "${LIBAZERON_HEADERS}"
|
||||
)
|
||||
|
||||
# Install library
|
||||
install(TARGETS azeron
|
||||
LIBRARY DESTINATION lib
|
||||
PUBLIC_HEADER DESTINATION include/azeron
|
||||
)
|
||||
|
||||
# Install pkg-config file
|
||||
configure_file(azeron.pc.in azeron.pc @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/azeron.pc
|
||||
DESTINATION lib/pkgconfig
|
||||
)
|
||||
420
libazeron/azeron.c
Normal file
420
libazeron/azeron.c
Normal file
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Azeron Linux Configuration Library
|
||||
* Copyright (C) 2024 Azeron Linux Project
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "azeron.h"
|
||||
#include "internal.h"
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static bool g_initialized = false;
|
||||
static libusb_context *g_context = NULL;
|
||||
|
||||
/* Initialize the library */
|
||||
int azeron_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (g_initialized) {
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
ret = libusb_init(&g_context);
|
||||
if (ret < 0) {
|
||||
AZERON_ERROR("Failed to initialize libusb: %s", azeron_usb_error_string(ret));
|
||||
return AZERON_ERROR_INIT;
|
||||
}
|
||||
|
||||
#ifdef AZERON_DEBUG
|
||||
libusb_set_debug(g_context, LIBUSB_LOG_LEVEL_INFO);
|
||||
#endif
|
||||
|
||||
g_initialized = true;
|
||||
AZERON_LOG("Library initialized");
|
||||
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
/* Cleanup the library */
|
||||
void azeron_exit(void)
|
||||
{
|
||||
if (!g_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_context) {
|
||||
libusb_exit(g_context);
|
||||
g_context = NULL;
|
||||
}
|
||||
|
||||
g_initialized = false;
|
||||
AZERON_LOG("Library exited");
|
||||
}
|
||||
|
||||
/* Convert error code to string */
|
||||
const char *azeron_error_string(int error)
|
||||
{
|
||||
switch (error) {
|
||||
case AZERON_SUCCESS:
|
||||
return "Success";
|
||||
case AZERON_ERROR_INIT:
|
||||
return "Initialization error";
|
||||
case AZERON_ERROR_NOT_FOUND:
|
||||
return "Device not found";
|
||||
case AZERON_ERROR_ACCESS:
|
||||
return "Access denied";
|
||||
case AZERON_ERROR_IO:
|
||||
return "I/O error";
|
||||
case AZERON_ERROR_PROTOCOL:
|
||||
return "Protocol error";
|
||||
case AZERON_ERROR_INVALID_PARAM:
|
||||
return "Invalid parameter";
|
||||
case AZERON_ERROR_NO_MEM:
|
||||
return "Out of memory";
|
||||
case AZERON_ERROR_UNSUPPORTED:
|
||||
return "Unsupported operation";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert libusb error to azeron error */
|
||||
int azeron_libusb_to_azeron_error(int libusb_error)
|
||||
{
|
||||
switch (libusb_error) {
|
||||
case LIBUSB_SUCCESS:
|
||||
return AZERON_SUCCESS;
|
||||
case LIBUSB_ERROR_IO:
|
||||
return AZERON_ERROR_IO;
|
||||
case LIBUSB_ERROR_INVALID_PARAM:
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
case LIBUSB_ERROR_ACCESS:
|
||||
return AZERON_ERROR_ACCESS;
|
||||
case LIBUSB_ERROR_NO_DEVICE:
|
||||
return AZERON_ERROR_NOT_FOUND;
|
||||
case LIBUSB_ERROR_NOT_FOUND:
|
||||
return AZERON_ERROR_NOT_FOUND;
|
||||
case LIBUSB_ERROR_BUSY:
|
||||
return AZERON_ERROR_ACCESS;
|
||||
case LIBUSB_ERROR_TIMEOUT:
|
||||
return AZERON_ERROR_IO;
|
||||
case LIBUSB_ERROR_OVERFLOW:
|
||||
return AZERON_ERROR_IO;
|
||||
case LIBUSB_ERROR_PIPE:
|
||||
return AZERON_ERROR_PROTOCOL;
|
||||
case LIBUSB_ERROR_INTERRUPTED:
|
||||
return AZERON_ERROR_IO;
|
||||
case LIBUSB_ERROR_NO_MEM:
|
||||
return AZERON_ERROR_NO_MEM;
|
||||
case LIBUSB_ERROR_NOT_SUPPORTED:
|
||||
return AZERON_ERROR_UNSUPPORTED;
|
||||
default:
|
||||
return AZERON_ERROR_IO;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get USB error string */
|
||||
const char *azeron_usb_error_string(int error)
|
||||
{
|
||||
return libusb_error_name(error);
|
||||
}
|
||||
|
||||
/* Extract device info from libusb device */
|
||||
void azeron_device_info_from_libusb(struct azeron_device *device, libusb_device *libusb_dev)
|
||||
{
|
||||
struct libusb_device_descriptor desc;
|
||||
int ret;
|
||||
|
||||
ret = libusb_get_device_descriptor(libusb_dev, &desc);
|
||||
if (ret < 0) {
|
||||
AZERON_ERROR("Failed to get device descriptor: %s", azeron_usb_error_string(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
device->info.vendor_id = desc.idVendor;
|
||||
device->info.product_id = desc.idProduct;
|
||||
device->info.firmware_version = desc.bcdDevice;
|
||||
|
||||
/* Get string descriptors if possible */
|
||||
if (device->handle) {
|
||||
if (desc.iSerialNumber > 0) {
|
||||
libusb_get_string_descriptor_ascii(device->handle, desc.iSerialNumber,
|
||||
(unsigned char *)device->info.serial_number,
|
||||
sizeof(device->info.serial_number));
|
||||
}
|
||||
if (desc.iManufacturer > 0) {
|
||||
libusb_get_string_descriptor_ascii(device->handle, desc.iManufacturer,
|
||||
(unsigned char *)device->info.manufacturer,
|
||||
sizeof(device->info.manufacturer));
|
||||
}
|
||||
if (desc.iProduct > 0) {
|
||||
libusb_get_string_descriptor_ascii(device->handle, desc.iProduct,
|
||||
(unsigned char *)device->info.product,
|
||||
sizeof(device->info.product));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* List all Azeron devices */
|
||||
int azeron_device_list(struct azeron_device_info **devices, size_t *count)
|
||||
{
|
||||
libusb_device **dev_list;
|
||||
ssize_t num_devs;
|
||||
size_t azeron_count = 0;
|
||||
struct azeron_device_info *azeron_devices = NULL;
|
||||
int i;
|
||||
|
||||
if (!devices || !count) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!g_initialized) {
|
||||
return AZERON_ERROR_INIT;
|
||||
}
|
||||
|
||||
num_devs = libusb_get_device_list(g_context, &dev_list);
|
||||
if (num_devs < 0) {
|
||||
AZERON_ERROR("Failed to get device list: %s", azeron_usb_error_string(num_devs));
|
||||
return azeron_libusb_to_azeron_error(num_devs);
|
||||
}
|
||||
|
||||
/* First pass: count Azeron devices */
|
||||
for (i = 0; i < num_devs; i++) {
|
||||
struct libusb_device_descriptor desc;
|
||||
int ret = libusb_get_device_descriptor(dev_list[i], &desc);
|
||||
if (ret >= 0 && desc.idVendor == AZERON_VENDOR_ID && desc.idProduct == AZERON_PRODUCT_ID) {
|
||||
azeron_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (azeron_count == 0) {
|
||||
libusb_free_device_list(dev_list, 1);
|
||||
*devices = NULL;
|
||||
*count = 0;
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
/* Allocate memory for device info */
|
||||
azeron_devices = calloc(azeron_count, sizeof(struct azeron_device_info));
|
||||
if (!azeron_devices) {
|
||||
libusb_free_device_list(dev_list, 1);
|
||||
return AZERON_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
/* Second pass: fill device info */
|
||||
azeron_count = 0;
|
||||
for (i = 0; i < num_devs; i++) {
|
||||
struct libusb_device_descriptor desc;
|
||||
int ret = libusb_get_device_descriptor(dev_list[i], &desc);
|
||||
if (ret >= 0 && desc.idVendor == AZERON_VENDOR_ID && desc.idProduct == AZERON_PRODUCT_ID) {
|
||||
struct azeron_device tmp_device = {0};
|
||||
int open_ret;
|
||||
|
||||
tmp_device.context = g_context;
|
||||
open_ret = libusb_open(dev_list[i], &tmp_device.handle);
|
||||
if (open_ret >= 0) {
|
||||
azeron_device_info_from_libusb(&tmp_device, dev_list[i]);
|
||||
libusb_close(tmp_device.handle);
|
||||
} else {
|
||||
/* Still fill basic info even if we can't open */
|
||||
tmp_device.info.vendor_id = desc.idVendor;
|
||||
tmp_device.info.product_id = desc.idProduct;
|
||||
tmp_device.info.firmware_version = desc.bcdDevice;
|
||||
snprintf(tmp_device.info.product, sizeof(tmp_device.info.product), "Azeron Keypad");
|
||||
}
|
||||
|
||||
memcpy(&azeron_devices[azeron_count], &tmp_device.info, sizeof(struct azeron_device_info));
|
||||
azeron_count++;
|
||||
}
|
||||
}
|
||||
|
||||
libusb_free_device_list(dev_list, 1);
|
||||
|
||||
*devices = azeron_devices;
|
||||
*count = azeron_count;
|
||||
|
||||
AZERON_LOG("Found %zu Azeron device(s)", azeron_count);
|
||||
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
/* Free device list */
|
||||
void azeron_device_list_free(struct azeron_device_info *devices, size_t count)
|
||||
{
|
||||
(void)count; /* Not used currently */
|
||||
free(devices);
|
||||
}
|
||||
|
||||
/* Open device by VID/PID */
|
||||
int azeron_device_open(struct azeron_device **device, uint16_t vendor_id, uint16_t product_id)
|
||||
{
|
||||
struct azeron_device *dev;
|
||||
int ret;
|
||||
|
||||
if (!device) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!g_initialized) {
|
||||
return AZERON_ERROR_INIT;
|
||||
}
|
||||
|
||||
dev = calloc(1, sizeof(struct azeron_device));
|
||||
if (!dev) {
|
||||
return AZERON_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
dev->context = g_context;
|
||||
pthread_mutex_init(&dev->mutex, NULL);
|
||||
|
||||
ret = libusb_open_device_with_vid_pid(g_context, vendor_id, product_id);
|
||||
if (!ret) {
|
||||
AZERON_ERROR("Failed to open device %04x:%04x", vendor_id, product_id);
|
||||
free(dev);
|
||||
return AZERON_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
dev->handle = ret;
|
||||
azeron_device_info_from_libusb(dev, libusb_get_device(dev->handle));
|
||||
|
||||
*device = dev;
|
||||
|
||||
AZERON_LOG("Device opened: %s (%04x:%04x)", dev->info.product, vendor_id, product_id);
|
||||
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
/* Open device by index */
|
||||
int azeron_device_open_index(struct azeron_device **device, size_t index)
|
||||
{
|
||||
libusb_device **dev_list;
|
||||
ssize_t num_devs;
|
||||
int i;
|
||||
size_t azeron_idx = 0;
|
||||
int ret;
|
||||
|
||||
if (!device) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!g_initialized) {
|
||||
return AZERON_ERROR_INIT;
|
||||
}
|
||||
|
||||
num_devs = libusb_get_device_list(g_context, &dev_list);
|
||||
if (num_devs < 0) {
|
||||
return azeron_libusb_to_azeron_error(num_devs);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_devs; i++) {
|
||||
struct libusb_device_descriptor desc;
|
||||
ret = libusb_get_device_descriptor(dev_list[i], &desc);
|
||||
if (ret >= 0 && desc.idVendor == AZERON_VENDOR_ID && desc.idProduct == AZERON_PRODUCT_ID) {
|
||||
if (azeron_idx == index) {
|
||||
struct azeron_device *dev = calloc(1, sizeof(struct azeron_device));
|
||||
if (!dev) {
|
||||
libusb_free_device_list(dev_list, 1);
|
||||
return AZERON_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
dev->context = g_context;
|
||||
pthread_mutex_init(&dev->mutex, NULL);
|
||||
|
||||
ret = libusb_open(dev_list[i], &dev->handle);
|
||||
if (ret < 0) {
|
||||
AZERON_ERROR("Failed to open device at index %zu: %s", index, azeron_usb_error_string(ret));
|
||||
free(dev);
|
||||
libusb_free_device_list(dev_list, 1);
|
||||
return azeron_libusb_to_azeron_error(ret);
|
||||
}
|
||||
|
||||
azeron_device_info_from_libusb(dev, dev_list[i]);
|
||||
libusb_free_device_list(dev_list, 1);
|
||||
|
||||
*device = dev;
|
||||
|
||||
AZERON_LOG("Device opened at index %zu: %s", index, dev->info.product);
|
||||
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
azeron_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
libusb_free_device_list(dev_list, 1);
|
||||
return AZERON_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Close device */
|
||||
void azeron_device_close(struct azeron_device *device)
|
||||
{
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (device->claimed) {
|
||||
azeron_device_release(device);
|
||||
}
|
||||
|
||||
if (device->handle) {
|
||||
libusb_close(device->handle);
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&device->mutex);
|
||||
free(device);
|
||||
|
||||
AZERON_LOG("Device closed");
|
||||
}
|
||||
|
||||
/* Get device information */
|
||||
int azeron_device_get_info(struct azeron_device *device, struct azeron_device_info *info)
|
||||
{
|
||||
if (!device || !info) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
memcpy(info, &device->info, sizeof(struct azeron_device_info));
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
/* Button type to string */
|
||||
const char *azeron_button_type_string(enum azeron_button_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case AZERON_BTN_KEYBOARD:
|
||||
return "keyboard";
|
||||
case AZERON_BTN_MOUSE:
|
||||
return "mouse";
|
||||
case AZERON_BTN_GAMEPAD:
|
||||
return "gamepad";
|
||||
case AZERON_BTN_MACRO:
|
||||
return "macro";
|
||||
case AZERON_BTN_LAYER_SWITCH:
|
||||
return "layer_switch";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* Stick mode to string */
|
||||
const char *azeron_stick_mode_string(enum azeron_stick_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case AZERON_STICK_ANALOG:
|
||||
return "analog";
|
||||
case AZERON_STICK_DIGITAL_4:
|
||||
return "digital_4";
|
||||
case AZERON_STICK_DIGITAL_8:
|
||||
return "digital_8";
|
||||
case AZERON_STICK_MOUSE:
|
||||
return "mouse";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
151
libazeron/azeron.h
Normal file
151
libazeron/azeron.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Azeron Linux Configuration Library
|
||||
* Copyright (C) 2024 Azeron Linux Project
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef AZERON_H
|
||||
#define AZERON_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <json-c/json.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define AZERON_VENDOR_ID 0x16d0
|
||||
#define AZERON_PRODUCT_ID 0x113c
|
||||
|
||||
#define AZERON_MAX_BUTTONS 32
|
||||
#define AZERON_MAX_PROFILES 3
|
||||
|
||||
/* Error codes */
|
||||
enum azeron_error {
|
||||
AZERON_SUCCESS = 0,
|
||||
AZERON_ERROR_INIT = -1,
|
||||
AZERON_ERROR_NOT_FOUND = -2,
|
||||
AZERON_ERROR_ACCESS = -3,
|
||||
AZERON_ERROR_IO = -4,
|
||||
AZERON_ERROR_PROTOCOL = -5,
|
||||
AZERON_ERROR_INVALID_PARAM = -6,
|
||||
AZERON_ERROR_NO_MEM = -7,
|
||||
AZERON_ERROR_UNSUPPORTED = -8,
|
||||
};
|
||||
|
||||
/* Button types that can be mapped */
|
||||
enum azeron_button_type {
|
||||
AZERON_BTN_KEYBOARD = 0,
|
||||
AZERON_BTN_MOUSE,
|
||||
AZERON_BTN_GAMEPAD,
|
||||
AZERON_BTN_MACRO,
|
||||
AZERON_BTN_LAYER_SWITCH,
|
||||
};
|
||||
|
||||
/* Analog stick modes */
|
||||
enum azeron_stick_mode {
|
||||
AZERON_STICK_ANALOG = 0,
|
||||
AZERON_STICK_DIGITAL_4,
|
||||
AZERON_STICK_DIGITAL_8,
|
||||
AZERON_STICK_MOUSE,
|
||||
};
|
||||
|
||||
/* Device information */
|
||||
struct azeron_device_info {
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
char serial_number[64];
|
||||
char manufacturer[128];
|
||||
char product[128];
|
||||
uint8_t firmware_version;
|
||||
uint8_t num_profiles;
|
||||
uint8_t active_profile;
|
||||
};
|
||||
|
||||
/* Button mapping */
|
||||
struct azeron_button_mapping {
|
||||
uint8_t button_id;
|
||||
enum azeron_button_type type;
|
||||
uint16_t key_code; /* Linux input event code */
|
||||
char *macro; /* For macro type */
|
||||
uint8_t layer_target; /* For layer switch type */
|
||||
};
|
||||
|
||||
/* Analog stick configuration */
|
||||
struct azeron_stick_config {
|
||||
enum azeron_stick_mode mode;
|
||||
uint8_t deadzone; /* 0-100 */
|
||||
uint8_t sensitivity; /* 0-100 */
|
||||
bool invert_x;
|
||||
bool invert_y;
|
||||
uint8_t response_curve; /* 0=linear, 1=exponential, etc. */
|
||||
};
|
||||
|
||||
/* Profile configuration */
|
||||
struct azeron_profile {
|
||||
uint8_t profile_id;
|
||||
char name[64];
|
||||
struct azeron_button_mapping buttons[AZERON_MAX_BUTTONS];
|
||||
uint8_t num_buttons;
|
||||
struct azeron_stick_config stick_config;
|
||||
};
|
||||
|
||||
/* Opaque device handle */
|
||||
struct azeron_device;
|
||||
|
||||
/* Library initialization */
|
||||
int azeron_init(void);
|
||||
void azeron_exit(void);
|
||||
const char *azeron_error_string(int error);
|
||||
|
||||
/* Device management */
|
||||
int azeron_device_list(struct azeron_device_info **devices, size_t *count);
|
||||
void azeron_device_list_free(struct azeron_device_info *devices, size_t count);
|
||||
|
||||
int azeron_device_open(struct azeron_device **device, uint16_t vendor_id, uint16_t product_id);
|
||||
int azeron_device_open_index(struct azeron_device **device, size_t index);
|
||||
void azeron_device_close(struct azeron_device *device);
|
||||
|
||||
int azeron_device_get_info(struct azeron_device *device, struct azeron_device_info *info);
|
||||
|
||||
/* Button mapping */
|
||||
int azeron_device_get_button_mapping(struct azeron_device *device, uint8_t button_id,
|
||||
struct azeron_button_mapping *mapping);
|
||||
int azeron_device_set_button_mapping(struct azeron_device *device,
|
||||
const struct azeron_button_mapping *mapping);
|
||||
|
||||
/* Analog stick configuration */
|
||||
int azeron_device_get_stick_config(struct azeron_device *device,
|
||||
struct azeron_stick_config *config);
|
||||
int azeron_device_set_stick_config(struct azeron_device *device,
|
||||
const struct azeron_stick_config *config);
|
||||
|
||||
/* Profile management */
|
||||
int azeron_device_get_active_profile(struct azeron_device *device, uint8_t *profile_id);
|
||||
int azeron_device_set_active_profile(struct azeron_device *device, uint8_t profile_id);
|
||||
|
||||
int azeron_device_get_profile(struct azeron_device *device, uint8_t profile_id,
|
||||
struct azeron_profile *profile);
|
||||
int azeron_device_set_profile(struct azeron_device *device,
|
||||
const struct azeron_profile *profile);
|
||||
|
||||
/* Configuration import/export */
|
||||
int azeron_device_export_config(struct azeron_device *device, const char *filename);
|
||||
int azeron_device_import_config(struct azeron_device *device, const char *filename);
|
||||
|
||||
int azeron_device_export_config_json(struct azeron_device *device, struct json_object **json);
|
||||
int azeron_device_import_config_json(struct azeron_device *device, struct json_object *json);
|
||||
|
||||
/* Utility functions */
|
||||
const char *azeron_button_type_string(enum azeron_button_type type);
|
||||
const char *azeron_stick_mode_string(enum azeron_stick_mode mode);
|
||||
int azeron_keycode_from_string(const char *key_name);
|
||||
const char *azeron_keycode_to_string(int keycode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* AZERON_H */
|
||||
11
libazeron/azeron.pc.in
Normal file
11
libazeron/azeron.pc.in
Normal file
@@ -0,0 +1,11 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: azeron
|
||||
Description: Azeron device configuration library
|
||||
Version: @PROJECT_VERSION@
|
||||
Libs: -L${libdir} -lazeron
|
||||
Cflags: -I${includedir}
|
||||
Requires: libusb-1.0 json-c
|
||||
218
libazeron/device.c
Normal file
218
libazeron/device.c
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Azeron Linux Configuration Library - Device Communication
|
||||
* Copyright (C) 2024 Azeron Linux Project
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "azeron.h"
|
||||
#include "internal.h"
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Claim device interfaces */
|
||||
int azeron_device_claim(struct azeron_device *device)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!device || !device->handle) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (device->claimed) {
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&device->mutex);
|
||||
|
||||
/* Claim all interfaces - the device has 5 interfaces (0-4) */
|
||||
for (int i = 0; i <= 4; i++) {
|
||||
ret = libusb_claim_interface(device->handle, i);
|
||||
if (ret < 0) {
|
||||
AZERON_ERROR("Failed to claim interface %d: %s", i, azeron_usb_error_string(ret));
|
||||
|
||||
/* Release already claimed interfaces */
|
||||
for (int j = 0; j < i; j++) {
|
||||
libusb_release_interface(device->handle, j);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
return azeron_libusb_to_azeron_error(ret);
|
||||
}
|
||||
}
|
||||
|
||||
device->claimed = true;
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
|
||||
AZERON_LOG("Device interfaces claimed");
|
||||
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
/* Release device interfaces */
|
||||
int azeron_device_release(struct azeron_device *device)
|
||||
{
|
||||
int ret;
|
||||
int overall_ret = AZERON_SUCCESS;
|
||||
|
||||
if (!device || !device->handle) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!device->claimed) {
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&device->mutex);
|
||||
|
||||
/* Release all interfaces */
|
||||
for (int i = 0; i <= 4; i++) {
|
||||
ret = libusb_release_interface(device->handle, i);
|
||||
if (ret < 0) {
|
||||
AZERON_ERROR("Failed to release interface %d: %s", i, azeron_usb_error_string(ret));
|
||||
overall_ret = azeron_libusb_to_azeron_error(ret);
|
||||
}
|
||||
}
|
||||
|
||||
device->claimed = false;
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
|
||||
AZERON_LOG("Device interfaces released");
|
||||
|
||||
return overall_ret;
|
||||
}
|
||||
|
||||
/* Read data from endpoint */
|
||||
int azeron_device_read(struct azeron_device *device, uint8_t endpoint, uint8_t *data, size_t size, int timeout)
|
||||
{
|
||||
int transferred;
|
||||
int ret;
|
||||
|
||||
if (!device || !device->handle || !data) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!device->claimed) {
|
||||
ret = azeron_device_claim(device);
|
||||
if (ret != AZERON_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&device->mutex);
|
||||
|
||||
ret = libusb_interrupt_transfer(device->handle, endpoint, data, size, &transferred, timeout);
|
||||
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
|
||||
if (ret < 0) {
|
||||
AZERON_ERROR("Failed to read from endpoint 0x%02x: %s", endpoint, azeron_usb_error_string(ret));
|
||||
return azeron_libusb_to_azeron_error(ret);
|
||||
}
|
||||
|
||||
AZERON_LOG("Read %d bytes from endpoint 0x%02x", transferred, endpoint);
|
||||
|
||||
return transferred;
|
||||
}
|
||||
|
||||
/* Write data to endpoint */
|
||||
int azeron_device_write(struct azeron_device *device, uint8_t endpoint, const uint8_t *data, size_t size, int timeout)
|
||||
{
|
||||
int transferred;
|
||||
int ret;
|
||||
|
||||
if (!device || !device->handle || !data) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!device->claimed) {
|
||||
ret = azeron_device_claim(device);
|
||||
if (ret != AZERON_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&device->mutex);
|
||||
|
||||
ret = libusb_interrupt_transfer(device->handle, endpoint, (uint8_t *)data, size, &transferred, timeout);
|
||||
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
|
||||
if (ret < 0) {
|
||||
AZERON_ERROR("Failed to write to endpoint 0x%02x: %s", endpoint, azeron_usb_error_string(ret));
|
||||
return azeron_libusb_to_azeron_error(ret);
|
||||
}
|
||||
|
||||
AZERON_LOG("Wrote %d bytes to endpoint 0x%02x", transferred, endpoint);
|
||||
|
||||
return transferred;
|
||||
}
|
||||
|
||||
/* Perform control transfer */
|
||||
int azeron_device_control_transfer(struct azeron_device *device, uint8_t request_type, uint8_t request,
|
||||
uint16_t value, uint16_t index, uint8_t *data, size_t size, int timeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!device || !device->handle) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!device->claimed) {
|
||||
ret = azeron_device_claim(device);
|
||||
if (ret != AZERON_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&device->mutex);
|
||||
|
||||
ret = libusb_control_transfer(device->handle, request_type, request, value, index, data, size, timeout);
|
||||
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
|
||||
if (ret < 0) {
|
||||
AZERON_ERROR("Control transfer failed: %s", azeron_usb_error_string(ret));
|
||||
return azeron_libusb_to_azeron_error(ret);
|
||||
}
|
||||
|
||||
AZERON_LOG("Control transfer: %d bytes transferred", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get button type string */
|
||||
const char *azeron_button_type_string(enum azeron_button_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case AZERON_BTN_KEYBOARD:
|
||||
return "keyboard";
|
||||
case AZERON_BTN_MOUSE:
|
||||
return "mouse";
|
||||
case AZERON_BTN_GAMEPAD:
|
||||
return "gamepad";
|
||||
case AZERON_BTN_MACRO:
|
||||
return "macro";
|
||||
case AZERON_BTN_LAYER_SWITCH:
|
||||
return "layer_switch";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* Get stick mode string */
|
||||
const char *azeron_stick_mode_string(enum azeron_stick_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case AZERON_STICK_ANALOG:
|
||||
return "analog";
|
||||
case AZERON_STICK_DIGITAL_4:
|
||||
return "digital_4";
|
||||
case AZERON_STICK_DIGITAL_8:
|
||||
return "digital_8";
|
||||
case AZERON_STICK_MOUSE:
|
||||
return "mouse";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
61
libazeron/internal.h
Normal file
61
libazeron/internal.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Azeron Linux Configuration Library - Internal Header
|
||||
* Copyright (C) 2024 Azeron Linux Project
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef AZERON_INTERNAL_H
|
||||
#define AZERON_INTERNAL_H
|
||||
|
||||
#include "azeron.h"
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define AZERON_USB_TIMEOUT 1000
|
||||
#define AZERON_MAX_STRING_LENGTH 256
|
||||
|
||||
/* Debug logging */
|
||||
#ifdef AZERON_DEBUG
|
||||
#define AZERON_LOG(fmt, ...) fprintf(stderr, "[AZERON] " fmt "\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define AZERON_LOG(fmt, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
/* Error logging */
|
||||
#define AZERON_ERROR(fmt, ...) fprintf(stderr, "[AZERON ERROR] " fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
/* Device structure */
|
||||
struct azeron_device {
|
||||
libusb_device_handle *handle;
|
||||
libusb_context *context;
|
||||
struct azeron_device_info info;
|
||||
pthread_mutex_t mutex;
|
||||
bool claimed;
|
||||
};
|
||||
|
||||
/* Protocol functions */
|
||||
int azeron_protocol_init(struct azeron_device *device);
|
||||
int azeron_protocol_read_config(struct azeron_device *device, uint8_t *data, size_t *size);
|
||||
int azeron_protocol_write_config(struct azeron_device *device, const uint8_t *data, size_t size);
|
||||
int azeron_protocol_get_button_mapping(struct azeron_device *device, uint8_t button_id, struct azeron_button_mapping *mapping);
|
||||
int azeron_protocol_set_button_mapping(struct azeron_device *device, const struct azeron_button_mapping *mapping);
|
||||
int azeron_protocol_get_stick_config(struct azeron_device *device, struct azeron_stick_config *config);
|
||||
int azeron_protocol_set_stick_config(struct azeron_device *device, const struct azeron_stick_config *config);
|
||||
int azeron_protocol_get_profile(struct azeron_device *device, uint8_t profile_id, struct azeron_profile *profile);
|
||||
int azeron_protocol_set_profile(struct azeron_device *device, const struct azeron_profile *profile);
|
||||
int azeron_protocol_save_to_device(struct azeron_device *device);
|
||||
|
||||
/* Device functions */
|
||||
int azeron_device_claim(struct azeron_device *device);
|
||||
int azeron_device_release(struct azeron_device *device);
|
||||
int azeron_device_read(struct azeron_device *device, uint8_t endpoint, uint8_t *data, size_t size, int timeout);
|
||||
int azeron_device_write(struct azeron_device *device, uint8_t endpoint, const uint8_t *data, size_t size, int timeout);
|
||||
int azeron_device_control_transfer(struct azeron_device *device, uint8_t request_type, uint8_t request, uint16_t value, uint16_t index, uint8_t *data, size_t size, int timeout);
|
||||
|
||||
/* Utility functions */
|
||||
const char *azeron_usb_error_string(int error);
|
||||
int azeron_libusb_to_azeron_error(int libusb_error);
|
||||
void azeron_device_info_from_libusb(struct azeron_device *device, libusb_device *libusb_dev);
|
||||
|
||||
#endif /* AZERON_INTERNAL_H */
|
||||
108
libazeron/protocol.c
Normal file
108
libazeron/protocol.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Azeron Linux Configuration Library - Protocol Implementation
|
||||
* Copyright (C) 2024 Azeron Linux Project
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "azeron.h"
|
||||
#include "internal.h"
|
||||
#include <string.h>
|
||||
|
||||
/* Protocol initialization */
|
||||
int azeron_protocol_init(struct azeron_device *device)
|
||||
{
|
||||
(void)device;
|
||||
AZERON_LOG("Protocol initialization - not yet implemented");
|
||||
return AZERON_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* Read configuration from device */
|
||||
int azeron_protocol_read_config(struct azeron_device *device, uint8_t *data, size_t *size)
|
||||
{
|
||||
(void)device;
|
||||
(void)data;
|
||||
(void)size;
|
||||
AZERON_LOG("Read config - not yet implemented");
|
||||
return AZERON_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* Write configuration to device */
|
||||
int azeron_protocol_write_config(struct azeron_device *device, const uint8_t *data, size_t size)
|
||||
{
|
||||
(void)device;
|
||||
(void)data;
|
||||
(void)size;
|
||||
AZERON_LOG("Write config - not yet implemented");
|
||||
return AZERON_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* Get button mapping */
|
||||
int azeron_protocol_get_button_mapping(struct azeron_device *device, uint8_t button_id,
|
||||
struct azeron_button_mapping *mapping)
|
||||
{
|
||||
(void)device;
|
||||
(void)button_id;
|
||||
(void)mapping;
|
||||
AZERON_LOG("Get button mapping - not yet implemented");
|
||||
return AZERON_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* Set button mapping */
|
||||
int azeron_protocol_set_button_mapping(struct azeron_device *device,
|
||||
const struct azeron_button_mapping *mapping)
|
||||
{
|
||||
(void)device;
|
||||
(void)mapping;
|
||||
AZERON_LOG("Set button mapping - not yet implemented");
|
||||
return AZERON_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* Get stick configuration */
|
||||
int azeron_protocol_get_stick_config(struct azeron_device *device,
|
||||
struct azeron_stick_config *config)
|
||||
{
|
||||
(void)device;
|
||||
(void)config;
|
||||
AZERON_LOG("Get stick config - not yet implemented");
|
||||
return AZERON_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* Set stick configuration */
|
||||
int azeron_protocol_set_stick_config(struct azeron_device *device,
|
||||
const struct azeron_stick_config *config)
|
||||
{
|
||||
(void)device;
|
||||
(void)config;
|
||||
AZERON_LOG("Set stick config - not yet implemented");
|
||||
return AZERON_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* Get profile */
|
||||
int azeron_protocol_get_profile(struct azeron_device *device, uint8_t profile_id,
|
||||
struct azeron_profile *profile)
|
||||
{
|
||||
(void)device;
|
||||
(void)profile_id;
|
||||
(void)profile;
|
||||
AZERON_LOG("Get profile - not yet implemented");
|
||||
return AZERON_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* Set profile */
|
||||
int azeron_protocol_set_profile(struct azeron_device *device,
|
||||
const struct azeron_profile *profile)
|
||||
{
|
||||
(void)device;
|
||||
(void)profile;
|
||||
AZERON_LOG("Set profile - not yet implemented");
|
||||
return AZERON_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* Save configuration to device */
|
||||
int azeron_protocol_save_to_device(struct azeron_device *device)
|
||||
{
|
||||
(void)device;
|
||||
AZERON_LOG("Save to device - not yet implemented");
|
||||
return AZERON_ERROR_UNSUPPORTED;
|
||||
}
|
||||
229
libazeron/utils.c
Normal file
229
libazeron/utils.c
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Azeron Linux Configuration Library - Utility Functions
|
||||
* Copyright (C) 2024 Azeron Linux Project
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "azeron.h"
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Key name to keycode mapping table */
|
||||
static struct {
|
||||
const char *name;
|
||||
int keycode;
|
||||
} keymap[] = {
|
||||
/* Letters */
|
||||
{"KEY_A", KEY_A}, {"KEY_B", KEY_B}, {"KEY_C", KEY_C}, {"KEY_D", KEY_D},
|
||||
{"KEY_E", KEY_E}, {"KEY_F", KEY_F}, {"KEY_G", KEY_G}, {"KEY_H", KEY_H},
|
||||
{"KEY_I", KEY_I}, {"KEY_J", KEY_J}, {"KEY_K", KEY_K}, {"KEY_L", KEY_L},
|
||||
{"KEY_M", KEY_M}, {"KEY_N", KEY_N}, {"KEY_O", KEY_O}, {"KEY_P", KEY_P},
|
||||
{"KEY_Q", KEY_Q}, {"KEY_R", KEY_R}, {"KEY_S", KEY_S}, {"KEY_T", KEY_T},
|
||||
{"KEY_U", KEY_U}, {"KEY_V", KEY_V}, {"KEY_W", KEY_W}, {"KEY_X", KEY_X},
|
||||
{"KEY_Y", KEY_Y}, {"KEY_Z", KEY_Z},
|
||||
|
||||
/* Numbers */
|
||||
{"KEY_1", KEY_1}, {"KEY_2", KEY_2}, {"KEY_3", KEY_3}, {"KEY_4", KEY_4},
|
||||
{"KEY_5", KEY_5}, {"KEY_6", KEY_6}, {"KEY_7", KEY_7}, {"KEY_8", KEY_8},
|
||||
{"KEY_9", KEY_9}, {"KEY_0", KEY_0},
|
||||
|
||||
/* Function keys */
|
||||
{"KEY_F1", KEY_F1}, {"KEY_F2", KEY_F2}, {"KEY_F3", KEY_F3}, {"KEY_F4", KEY_F4},
|
||||
{"KEY_F5", KEY_F5}, {"KEY_F6", KEY_F6}, {"KEY_F7", KEY_F7}, {"KEY_F8", KEY_F8},
|
||||
{"KEY_F9", KEY_F9}, {"KEY_F10", KEY_F10}, {"KEY_F11", KEY_F11}, {"KEY_F12", KEY_F12},
|
||||
|
||||
/* Special keys */
|
||||
{"KEY_ESC", KEY_ESC},
|
||||
{"KEY_TAB", KEY_TAB},
|
||||
{"KEY_CAPSLOCK", KEY_CAPSLOCK},
|
||||
{"KEY_LEFTSHIFT", KEY_LEFTSHIFT}, {"KEY_RIGHTSHIFT", KEY_RIGHTSHIFT},
|
||||
{"KEY_LEFTCTRL", KEY_LEFTCTRL}, {"KEY_RIGHTCTRL", KEY_RIGHTCTRL},
|
||||
{"KEY_LEFTALT", KEY_LEFTALT}, {"KEY_RIGHTALT", KEY_RIGHTALT},
|
||||
{"KEY_SPACE", KEY_SPACE},
|
||||
{"KEY_ENTER", KEY_ENTER},
|
||||
{"KEY_BACKSPACE", KEY_BACKSPACE},
|
||||
{"KEY_DELETE", KEY_DELETE},
|
||||
{"KEY_INSERT", KEY_INSERT},
|
||||
{"KEY_HOME", KEY_HOME},
|
||||
{"KEY_END", KEY_END},
|
||||
{"KEY_PAGEUP", KEY_PAGEUP},
|
||||
{"KEY_PAGEDOWN", KEY_PAGEDOWN},
|
||||
|
||||
/* Arrow keys */
|
||||
{"KEY_UP", KEY_UP},
|
||||
{"KEY_DOWN", KEY_DOWN},
|
||||
{"KEY_LEFT", KEY_LEFT},
|
||||
{"KEY_RIGHT", KEY_RIGHT},
|
||||
|
||||
/* Numpad */
|
||||
{"KEY_NUMLOCK", KEY_NUMLOCK},
|
||||
{"KEY_KP0", KEY_KP0}, {"KEY_KP1", KEY_KP1}, {"KEY_KP2", KEY_KP2}, {"KEY_KP3", KEY_KP3},
|
||||
{"KEY_KP4", KEY_KP4}, {"KEY_KP5", KEY_KP5}, {"KEY_KP6", KEY_KP6}, {"KEY_KP7", KEY_KP7},
|
||||
{"KEY_KP8", KEY_KP8}, {"KEY_KP9", KEY_KP9},
|
||||
{"KEY_KPSLASH", KEY_KPSLASH}, {"KEY_KPASTERISK", KEY_KPASTERISK},
|
||||
{"KEY_KPMINUS", KEY_KPMINUS}, {"KEY_KPPLUS", KEY_KPPLUS},
|
||||
{"KEY_KPENTER", KEY_KPENTER}, {"KEY_KPDOT", KEY_KPDOT},
|
||||
|
||||
/* Mouse buttons */
|
||||
{"BTN_LEFT", BTN_LEFT},
|
||||
{"BTN_RIGHT", BTN_RIGHT},
|
||||
{"BTN_MIDDLE", BTN_MIDDLE},
|
||||
{"BTN_SIDE", BTN_SIDE},
|
||||
{"BTN_EXTRA", BTN_EXTRA},
|
||||
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
/* Convert key name to keycode */
|
||||
int azeron_keycode_from_string(const char *key_name)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!key_name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* First try exact match */
|
||||
for (i = 0; keymap[i].name != NULL; i++) {
|
||||
if (strcmp(key_name, keymap[i].name) == 0) {
|
||||
return keymap[i].keycode;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try without KEY_ prefix */
|
||||
if (strncmp(key_name, "KEY_", 4) != 0) {
|
||||
char prefixed[64];
|
||||
snprintf(prefixed, sizeof(prefixed), "KEY_%s", key_name);
|
||||
for (i = 0; keymap[i].name != NULL; i++) {
|
||||
if (strcmp(prefixed, keymap[i].name) == 0) {
|
||||
return keymap[i].keycode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert keycode to string */
|
||||
const char *azeron_keycode_to_string(int keycode)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; keymap[i].name != NULL; i++) {
|
||||
if (keymap[i].keycode == keycode) {
|
||||
return keymap[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
/* Export configuration to JSON */
|
||||
int azeron_device_export_config_json(struct azeron_device *device, struct json_object **json)
|
||||
{
|
||||
struct json_object *root;
|
||||
struct json_object *profiles_array;
|
||||
struct azeron_device_info info;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (!device || !json) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
root = json_object_new_object();
|
||||
if (!root) {
|
||||
return AZERON_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
/* Add device info */
|
||||
ret = azeron_device_get_info(device, &info);
|
||||
if (ret == AZERON_SUCCESS) {
|
||||
json_object_object_add(root, "vendor_id", json_object_new_int(info.vendor_id));
|
||||
json_object_object_add(root, "product_id", json_object_new_int(info.product_id));
|
||||
json_object_object_add(root, "serial_number", json_object_new_string(info.serial_number));
|
||||
json_object_object_add(root, "firmware_version", json_object_new_int(info.firmware_version));
|
||||
}
|
||||
|
||||
/* Create profiles array */
|
||||
profiles_array = json_object_new_array();
|
||||
if (!profiles_array) {
|
||||
json_object_put(root);
|
||||
return AZERON_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
/* Add placeholder profiles - actual implementation would read from device */
|
||||
for (i = 0; i < 3; i++) {
|
||||
struct json_object *profile = json_object_new_object();
|
||||
char name[32];
|
||||
|
||||
snprintf(name, sizeof(name), "Profile %d", i + 1);
|
||||
json_object_object_add(profile, "id", json_object_new_int(i));
|
||||
json_object_object_add(profile, "name", json_object_new_string(name));
|
||||
json_object_object_add(profile, "active", json_object_new_boolean(i == 0));
|
||||
|
||||
json_object_array_add(profiles_array, profile);
|
||||
}
|
||||
|
||||
json_object_object_add(root, "profiles", profiles_array);
|
||||
|
||||
*json = root;
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
/* Import configuration from JSON */
|
||||
int azeron_device_import_config_json(struct azeron_device *device, struct json_object *json)
|
||||
{
|
||||
(void)device;
|
||||
(void)json;
|
||||
|
||||
AZERON_LOG("Import config from JSON - not yet implemented");
|
||||
return AZERON_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* Export configuration to file */
|
||||
int azeron_device_export_config(struct azeron_device *device, const char *filename)
|
||||
{
|
||||
struct json_object *json;
|
||||
int ret;
|
||||
|
||||
if (!device || !filename) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
ret = azeron_device_export_config_json(device, &json);
|
||||
if (ret != AZERON_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = json_object_to_file_ext(filename, json, JSON_C_TO_STRING_PRETTY);
|
||||
json_object_put(json);
|
||||
|
||||
if (ret != 0) {
|
||||
return AZERON_ERROR_IO;
|
||||
}
|
||||
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
/* Import configuration from file */
|
||||
int azeron_device_import_config(struct azeron_device *device, const char *filename)
|
||||
{
|
||||
struct json_object *json;
|
||||
int ret;
|
||||
|
||||
if (!device || !filename) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
json = json_object_from_file(filename);
|
||||
if (!json) {
|
||||
return AZERON_ERROR_IO;
|
||||
}
|
||||
|
||||
ret = azeron_device_import_config_json(device, json);
|
||||
json_object_put(json);
|
||||
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user