#ifndef PYNECT_DIRECT_H
#define PYNECT_DIRECT_H

#include <stdint.h>

#ifdef _WIN32
  #ifdef PYNECT_DIRECT_BUILD_DLL
    #define PYNECT_DIRECT_API __declspec(dllexport)
  #elif defined(PYNECT_DIRECT_USE_DLL)
    #define PYNECT_DIRECT_API __declspec(dllimport)
  #else
    #define PYNECT_DIRECT_API
  #endif
#else
  #define PYNECT_DIRECT_API
#endif

#define PYNECT_DIRECT_SUCCESS                      0
#define PYNECT_DIRECT_ERR_NOT_INITIALIZED         -1
#define PYNECT_DIRECT_ERR_DEVICE_NOT_FOUND        -2
#define PYNECT_DIRECT_ERR_DEVICE_NOT_OPEN         -3
#define PYNECT_DIRECT_ERR_COMM_FAIL                -4
#define PYNECT_DIRECT_ERR_INVALID_PARAM            -5
#define PYNECT_DIRECT_ERR_OPEN_FAILED              -6
#define PYNECT_DIRECT_ERR_CRC                      -7
#define PYNECT_DIRECT_ERR_PREAMBLE                -8
#define PYNECT_DIRECT_ERR_TIMEOUT                 -9
#define PYNECT_DIRECT_ERR_WPROT                   -10
#define PYNECT_DIRECT_ERR_UNSUPPORTED             -11

#define PYNECT_DIRECT_MAX_DEVICES                  4

#define XENON_OFF         0x00
#define XENON_CONTINUOUS  0x01
#define XENON_SINGLE      0x81

#define TRIGGER_OFF       0x00
#define TRIGGER_ON_RISE   0xAA
#define TRIGGER_ON_LEVEL  0xBB

typedef struct PynectDirectSelectedWavelengthRange {
    double request_start_nm;
    double request_end_nm;
    double actual_start_nm;
    double actual_end_nm;
    uint16_t start_pixel;
    uint16_t end_pixel;
    uint16_t count;
} PynectDirectSelectedWavelengthRange;

typedef enum PynectDirectDeviceProtocol {
    PYNECT_DIRECT_PROTOCOL_AUTO = 0,
    PYNECT_DIRECT_PROTOCOL_UVVIS_CM2 = 1,
    PYNECT_DIRECT_PROTOCOL_NIR_LEGACY = 2,
    PYNECT_DIRECT_PROTOCOL_UNKNOWN = 255
} PynectDirectDeviceProtocol;

#define PYNECT_DIRECT_CAP_INTEGRATION_TIME      0x00000001u
#define PYNECT_DIRECT_CAP_AVERAGE_NUMBER        0x00000002u
#define PYNECT_DIRECT_CAP_LEVEL_OUTPUT          0x00000004u
#define PYNECT_DIRECT_CAP_FLASH                 0x00000008u
#define PYNECT_DIRECT_CAP_WAVELENGTH_DATA       0x00000010u
#define PYNECT_DIRECT_CAP_SPECTRUM_DATA         0x00000020u
#define PYNECT_DIRECT_CAP_TEMPERATURE           0x00000040u
#define PYNECT_DIRECT_CAP_HARDWARE_VERSION      0x00000080u
#define PYNECT_DIRECT_CAP_CALIBRATION           0x00000100u
#define PYNECT_DIRECT_CAP_XENON                 0x00000200u
#define PYNECT_DIRECT_CAP_USB_STATUS            0x00000400u
#define PYNECT_DIRECT_CAP_EXTERNAL_TRIGGER      0x00000800u
#define PYNECT_DIRECT_CAP_DAC                   0x00001000u
#define PYNECT_DIRECT_CAP_STORED_CONFIG         0x00002000u
#define PYNECT_DIRECT_CAP_SLIT_WIDTH            0x00004000u

typedef struct PynectDirectDeviceInfo {
    PynectDirectDeviceProtocol protocol;
    uint32_t capabilities;
    char protocol_name[32];
    char model[32];
    char serial_number[32];
    char hardware_version[64];
} PynectDirectDeviceInfo;

#ifdef __cplusplus
extern "C" {
#endif

PYNECT_DIRECT_API int pynect_direct_scan_devices(void);
PYNECT_DIRECT_API int pynect_direct_get_chip_serial_by_index(int index, char* chip_serial, int max_len);
PYNECT_DIRECT_API int pynect_direct_open_device(int index);
PYNECT_DIRECT_API int pynect_direct_open_device_by_chip_serial(const char* chip_serial);
PYNECT_DIRECT_API void pynect_direct_close_device(void);
PYNECT_DIRECT_API int pynect_direct_is_open(void);
PYNECT_DIRECT_API int pynect_direct_get_open_device_count(void);
PYNECT_DIRECT_API int pynect_direct_select_device(int device_index);
PYNECT_DIRECT_API void pynect_direct_close_all_devices(void);
PYNECT_DIRECT_API int pynect_direct_set_protocol_preference(PynectDirectDeviceProtocol protocol);
PYNECT_DIRECT_API int pynect_direct_get_device_protocol(PynectDirectDeviceProtocol* protocol);
PYNECT_DIRECT_API int pynect_direct_get_capabilities(uint32_t* capabilities);
PYNECT_DIRECT_API int pynect_direct_get_device_info(PynectDirectDeviceInfo* info);

PYNECT_DIRECT_API int pynect_direct_set_integration_time(unsigned int us);
PYNECT_DIRECT_API int pynect_direct_get_integration_time(unsigned int* us);

PYNECT_DIRECT_API int pynect_direct_set_xenon_pulse(unsigned int period_10ns, unsigned int high_10ns);
PYNECT_DIRECT_API int pynect_direct_get_xenon_pulse(unsigned int* period, unsigned int* high);

PYNECT_DIRECT_API int pynect_direct_set_xenon_mode(uint8_t mode);
PYNECT_DIRECT_API int pynect_direct_get_xenon_mode(uint8_t* mode);

PYNECT_DIRECT_API int pynect_direct_set_average_number(uint8_t count);
PYNECT_DIRECT_API int pynect_direct_get_average_number(uint8_t* count);

PYNECT_DIRECT_API int pynect_direct_set_level_output(uint8_t level);
PYNECT_DIRECT_API int pynect_direct_get_level_output(uint8_t* level);

PYNECT_DIRECT_API int pynect_direct_set_flash_write_protect(void);
PYNECT_DIRECT_API int pynect_direct_get_flash_write_protect(int* enabled);

PYNECT_DIRECT_API int pynect_direct_reset_device(void);

PYNECT_DIRECT_API int pynect_direct_get_calibration_coefficients(double coeffs[4]);

PYNECT_DIRECT_API int pynect_direct_get_temperature(float* temp_c);

PYNECT_DIRECT_API int pynect_direct_get_hardware_version(char* version_str, int max_len);

PYNECT_DIRECT_API int pynect_direct_get_serial_number(char* sn, int max_len);
PYNECT_DIRECT_API int pynect_direct_get_detector_serial_number(char* sn, int max_len);

PYNECT_DIRECT_API int pynect_direct_get_device_model(char* model, int max_len);

PYNECT_DIRECT_API int pynect_direct_set_usb_baud_rate(uint16_t rate);
PYNECT_DIRECT_API int pynect_direct_get_usb_baud_rate(uint16_t* rate);

PYNECT_DIRECT_API int pynect_direct_get_usb_status(int* connected);

PYNECT_DIRECT_API int pynect_direct_get_wavelength_count(uint16_t* count);
PYNECT_DIRECT_API int pynect_direct_get_full_wavelength_range(double* start_nm, double* end_nm);

PYNECT_DIRECT_API int pynect_direct_get_full_wavelength_data(double* buffer, int max_len);
PYNECT_DIRECT_API int pynect_direct_get_full_spectrum_data(uint16_t* buffer, int max_len);
PYNECT_DIRECT_API int pynect_direct_set_selected_wavelength_range(double start_nm, double end_nm);
PYNECT_DIRECT_API int pynect_direct_get_selected_wavelength_range(PynectDirectSelectedWavelengthRange* out_range);
PYNECT_DIRECT_API int pynect_direct_get_selected_wavelength_data(double* buffer, int max_len);
PYNECT_DIRECT_API int pynect_direct_get_selected_spectrum_data(uint16_t* buffer, int max_len);

PYNECT_DIRECT_API int pynect_direct_flash_read(uint16_t sector, uint8_t* data_out, int max_len);
PYNECT_DIRECT_API int pynect_direct_flash_write(uint16_t sector, const uint8_t* data, int len);

PYNECT_DIRECT_API int pynect_direct_set_external_trigger_config(uint8_t enable, uint8_t trig_type, uint8_t scan_num);
PYNECT_DIRECT_API int pynect_direct_get_external_trigger_config(uint8_t* enable, uint8_t* trig_type, uint8_t* scan_num);
PYNECT_DIRECT_API int pynect_direct_get_spectrum_capture_status(uint64_t* status);
PYNECT_DIRECT_API int pynect_direct_external_spectrum_control(uint16_t frame_index, uint8_t* data_out, int max_len);

PYNECT_DIRECT_API int pynect_direct_set_dac_voltage(uint16_t dac_value);
PYNECT_DIRECT_API int pynect_direct_get_dac_voltage(uint16_t* dac_value);

PYNECT_DIRECT_API int pynect_direct_set_stored_integration_time(unsigned int us);
PYNECT_DIRECT_API int pynect_direct_set_stored_average_number(uint8_t count);
PYNECT_DIRECT_API int pynect_direct_set_stored_smoothing_width(uint8_t width);
PYNECT_DIRECT_API int pynect_direct_get_stored_integration_time(unsigned int* us);
PYNECT_DIRECT_API int pynect_direct_get_stored_average_number(uint8_t* count);
PYNECT_DIRECT_API int pynect_direct_get_stored_smoothing_width(uint8_t* width);
PYNECT_DIRECT_API int pynect_direct_get_slit_width(uint8_t* um);

#ifdef __cplusplus
}
#endif

#endif
