/**
 * RH56F1 EtherCAT Hand Controller - C API Wrapper (Multi-Instance Support)
 * 
 * This header provides a C-compatible API for the RH56F1 EtherCAT hand controller
 * that can be easily called from Python using ctypes.
 * 
 * MULTI-INSTANCE SUPPORT:
 * Each RH56F1Hand instance can use a different EtherCAT master, enabling
 * control of hands on separate masters (e.g., master 0 and master 1).
 * 
 * PDO Input Indices (0x6000, use with rh56f1_get_input):
 *   [0-5]:   POSACT1-6      - Actuator position per finger
 *   [6-11]:  ANGLEACT1-6    - Actual angle per finger (0.1 deg units)
 *   [12-17]: FORCEACT1-6    - Actual force per finger
 *   [18-23]: CURACT1-6      - Actual current per finger
 *   [24-29]: ERROR1-6       - Error codes per finger
 *   [30-35]: STATUS1-6      - Status word per finger
 *   [36-41]: TEMP1-6        - Temperature per finger (°C)
 *   [42-75]: Tactile sensors
 * 
 * PDO Output Indices (0x7000, use with rh56f1_set_output):
 *   [0]:     ENABLE_SET     - Motion control enable (bit-packed)
 *   [1-6]:   ANGLESET1-6    - Target angle per finger
 *   [7-12]:  FORCESET1-6    - Force limit per finger
 *   [13-18]: SPEEDSET1-6    - Speed limit per finger
 */

#ifndef RH56F1_WRAPPER_H
#define RH56F1_WRAPPER_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>
#include <stdbool.h>

/**
 * Opaque handle to a hand controller instance
 */
typedef void* rh56f1_handle_t;

// Input PDO index offsets (for rh56f1_get_input)
#define RH56F1_IN_POSACT_BASE     0   // POSACT1 at index 0
#define RH56F1_IN_ANGLEACT_BASE   6   // ANGLEACT1 at index 6
#define RH56F1_IN_FORCEACT_BASE   12  // FORCEACT1 at index 12
#define RH56F1_IN_CURACT_BASE     18  // CURACT1 at index 18
#define RH56F1_IN_ERROR_BASE      24  // ERROR1 at index 24
#define RH56F1_IN_STATUS_BASE     30  // STATUS1 at index 30
#define RH56F1_IN_TEMP_BASE       36  // TEMP1 at index 36
#define RH56F1_IN_TACTILE_BASE    42  // Tactile sensors at index 42

// Output PDO index offsets (for rh56f1_set_output)
#define RH56F1_OUT_ENABLE_SET     0   // ENABLE_SET at index 0
#define RH56F1_OUT_ANGLESET_BASE  1   // ANGLESET1 at index 1
#define RH56F1_OUT_FORCESET_BASE  7   // FORCESET1 at index 7
#define RH56F1_OUT_SPEEDSET_BASE  13  // SPEEDSET1 at index 13

// Finger IDs (1-6)
#define RH56F1_FINGER_LITTLE      1
#define RH56F1_FINGER_RING        2
#define RH56F1_FINGER_MIDDLE      3
#define RH56F1_FINGER_INDEX       4
#define RH56F1_FINGER_THUMB_BEND  5
#define RH56F1_FINGER_THUMB_SIDESWAY 6

// Parameter ranges
#define RH56F1_ANGLE_MIN    0
#define RH56F1_ANGLE_MAX    3600
#define RH56F1_FORCE_MIN    0
#define RH56F1_FORCE_MAX    10000
#define RH56F1_SPEED_MIN    0
#define RH56F1_SPEED_MAX    5000

/**
 * Create a new hand controller instance
 * 
 * @param master_index EtherCAT master index (0, 1, 2, etc.)
 * @param slave_position Slave position (usually 0)
 * @return Handle to the controller instance, or NULL on failure
 */
rh56f1_handle_t rh56f1_create(uint32_t master_index, uint32_t slave_position);

/**
 * Start the real-time control loop for this instance
 * 
 * @param handle Controller instance handle
 * @return 0 on success, -1 on failure
 */
int rh56f1_start(rh56f1_handle_t handle);

/**
 * Stop the real-time control loop for this instance
 * 
 * @param handle Controller instance handle
 * @return 0 on success, -1 on failure
 */
int rh56f1_stop(rh56f1_handle_t handle);

/**
 * Deactivate the EtherCAT master (leave operation phase, keep reservation).
 * Use after stop() on abort so the same handle can be reactivated later without re-requesting the master.
 * 
 * @param handle Controller instance handle
 * @return 0 on success, -1 on failure
 */
int rh56f1_deactivate(rh56f1_handle_t handle);

/**
 * Activate the EtherCAT master (enter operation phase). Call before start() when resuming after deactivate().
 * 
 * @param handle Controller instance handle
 * @return 0 on success, -1 on failure
 */
int rh56f1_activate(rh56f1_handle_t handle);

/**
 * Destroy the controller instance and release all resources (release master reservation).
 * Call when the hand will not be used again (e.g. process exit).
 * 
 * @param handle Controller instance handle
 */
void rh56f1_destroy(rh56f1_handle_t handle);

/**
 * Get all 76 input PDO values (0x6000:01-4C)
 * 
 * @param handle Controller instance handle
 * @param values Array to store all 76 input values
 * @param size Size of array (must be at least 76)
 * @return Number of values copied (76), -1 on failure
 * 
 * Example: Read finger 1 angle
 *   int16_t inputs[76];
 *   rh56f1_get_all_inputs(handle, inputs, 76);
 *   int16_t finger1_angle = inputs[RH56F1_IN_ANGLEACT_BASE + 0];  // finger 1 = index 0
 */
int rh56f1_get_all_inputs(rh56f1_handle_t handle, int16_t* values, int size);

/**
 * Get specific input PDO value by index (0x6000)
 * 
 * @param handle Controller instance handle
 * @param index Input index (0-75), use RH56F1_IN_* constants + (finger_id - 1)
 * @param value Pointer to store value
 * @return 0 on success, -1 on failure
 * 
 * Example: Read finger 3 angle
 *   int16_t angle;
 *   rh56f1_get_input(handle, RH56F1_IN_ANGLEACT_BASE + 2, &angle);  // finger 3 = index 2
 */
int rh56f1_get_input(rh56f1_handle_t handle, int index, int16_t* value);

/**
 * Set specific output PDO value by index (0x7000)
 * 
 * @param handle Controller instance handle
 * @param index Output index (0-18), use RH56F1_OUT_* constants + (finger_id - 1)
 * @param value Value to set
 * @return 0 on success, -1 on failure
 * 
 * Example: Set finger 3 angle to 170 degrees
 *   rh56f1_set_output(handle, RH56F1_OUT_ANGLESET_BASE + 2, 1700);  // finger 3 = index 2
 * 
 * Example: Enable finger 3
 *   uint16_t enable_bits = 0b00000100;  // bit 2 for finger 3
 *   rh56f1_set_output(handle, RH56F1_OUT_ENABLE_SET, enable_bits);
 */
int rh56f1_set_output(rh56f1_handle_t handle, int index, uint16_t value);

/**
 * Check if controller is running
 * 
 * @param handle Controller instance handle
 * @return 1 if running, 0 if not
 */
int rh56f1_is_running(rh56f1_handle_t handle);

/**
 * Get error message for this instance
 * 
 * @param handle Controller instance handle
 * @return Pointer to error string, or NULL if no error
 */
const char* rh56f1_get_error(rh56f1_handle_t handle);

/**
 * Read an SDO (Service Data Object) from the device
 * 
 * @param handle Controller instance handle
 * @param index Object index (e.g., 0x2000)
 * @param subindex Subindex (e.g., 0x01)
 * @param value Pointer to store the read value
 * @return 0 on success, -1 on error
 * 
 * Example: Read HAND_ID
 *   int16_t hand_id;
 *   rh56f1_read_sdo(handle, 0x2000, 0x01, &hand_id);
 */
int rh56f1_read_sdo(rh56f1_handle_t handle, uint16_t index, uint8_t subindex, int16_t* value);

/**
 * Write an SDO (Service Data Object) to the device
 * 
 * @param handle Controller instance handle
 * @param index Object index (e.g., 0x2000)
 * @param subindex Subindex (e.g., 0x01)
 * @param value Value to write
 * @return 0 on success, -1 on error
 * 
 * Example: Clear errors
 *   rh56f1_write_sdo(handle, 0x2000, 0x03, 1);
 */
int rh56f1_write_sdo(rh56f1_handle_t handle, uint16_t index, uint8_t subindex, int16_t value);

#ifdef __cplusplus
}
#endif

#endif // RH56F1_WRAPPER_H

