#ifndef _usbtenki_h__
#define _usbtenki_h__


#include "quantity.h"
#include "calpoint.h"
#include "calcurve.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
#include <basetsd.h>
typedef SSIZE_T ssize_t;
#endif


#define USBTENKI_FLAG_NO_HUMIDEX_RANGE				1
#define USBTENKI_FLAG_NO_HEAT_INDEX_RANGE			2
#define USBTENKI_FLAG_USE_OLD_SHT75_COMPENSATION	4
#define USBTENKI_FLAG_VERBOSE						8

#define USBTENKI_CHN_STATUS_UNDEFINED			0
#define USBTENKI_CHN_STATUS_VALID				1
#define USBTENKI_CHN_STATUS_SATURATED			2
#define USBTENKI_CHN_STATUS_SENSOR_ERROR		3
#define USBTENKI_CHN_STATUS_PROBE_DISCONNECTED	4
#define USBTENKI_CHN_STATUS_OUT_OF_RANGE		5
#define USBTENKI_CHN_STATUS_INVALID_DATA		6
#define USBTENKI_CHN_STATUS_SENSOR_SHORTED		7


typedef void* USBTenki_dev_handle; // Cast from usb_dev_handle
typedef void* USBTenki_device; // Cast from usb_device

struct USBTenki_channel {

	int channel_id;
	int chip_id;
	unsigned char raw_data[32];
	int raw_len;
	double raw_value; // Not always used.
	Quantity quantity;
	uint8_t calpoints_count;
	Point calpoints[CAL_POINTS_COUNT];  // for display

};

struct USBTenki_info {
	USBTenki_device usb_device;
	uint8_t bus;
	uint8_t address;
	uint8_t port;
	uint8_t path[8];
	char str_prodname[256];
	char str_serial[256];
	int major, minor;
};

struct USBTenki_list_ctx {
	struct USBTenki_info *devices;
	ssize_t n_devices;
};


typedef enum USBTenki_Error {
    USBTENKI_SUCCESS = 0,
	USBTENKI_ERR_UNDEF,
	USBTENKI_ERR_ASSERT,
	USBTENKI_ERR_TIMEOUT,
	USBTENKI_ERR_BROKEN_PIPE,
	USBTENKI_ERR_ALLOC,
	USBTENKI_ERR_VALUE_OOR,

	USBTENKI_ERR_USB_LIBERROR,
	USBTENKI_ERR_USB_OPEN,
	USBTENKI_ERR_USB_GET_DESCRIPTOR,
	USBTENKI_ERR_USB_GETCONFIG,
	USBTENKI_ERR_USB_SETCONFIG,
	USBTENKI_ERR_USB_CLAIM_INTERFACE,
	USBTENKI_ERR_USB_CTRL_MESSAGE,
	USBTENKI_ERR_USB_CMD_MISMATCH,
	USBTENKI_ERR_USB_CHECKSUM,
	USBTENKI_ERR_USB_UNDERFLOW,
	USBTENKI_ERR_USB_OVERFLOW,

	USBTENKI_ERR_DEVICE_OPEN,
	USBTENKI_ERR_DEVICE_NOT_FOUND,
	USBTENKI_ERR_DEVICE_CHANNEL_INVALID,
	USBTENKI_ERR_DEVICE_CHANNEL_MISMATCH,
	USBTENKI_ERR_DEVICE_USERCALPOINT_NOT_SUPPORTED,
	USBTENKI_ERR_DEVICE_USERCALCURVE_NOT_SUPPORTED,

	USBTENKI_ERR_DATA_INVALID,
	USBTENKI_ERR_DATA_RAW_CONVERT,
	USBTENKI_ERR_DATA_SET_ZERO,
	USBTENKI_ERR_DATA_AUTOCAL_SET,
	USBTENKI_ERR_DATA_AUTOCAL_GET,
	USBTENKI_ERR_DATA_AUTOCAL_LOCK,
	USBTENKI_ERR_DATA_AUTOCAL_UNLOCK,
	USBTENKI_ERR_DATA_CALPOINT_INVALID,
	USBTENKI_ERR_DATA_CALPOINT_GET,
	USBTENKI_ERR_DATA_CALPOINT_SET,
	USBTENKI_ERR_DATA_CALPOINT_SAVE,
	USBTENKI_ERR_DATA_CALCURVE_INVALID,
	USBTENKI_ERR_DATA_CALCURVE_GET,
	USBTENKI_ERR_DATA_CALCURVE_SET,
	USBTENKI_ERR_DATA_CALCURVE_SAVE
} USBTenki_Error;


struct USBTenki_list_ctx;

int usbtenki_errno(void);
void usbtenki_perror(const char * str);
char * usbtenki_strerror(int errnum);

int usbtenki_init(void);
void usbtenki_shutdown(void);

struct USBTenki_list_ctx *usbtenki_initListCtx(void);
void usbtenki_freeListCtx(struct USBTenki_list_ctx *ctx);

USBTenki_dev_handle usbtenki_openDevice(struct USBTenki_info *info);
USBTenki_dev_handle usbtenki_openBySerial(struct USBTenki_info *info);

void usbtenki_closeDevice(USBTenki_dev_handle hdl);


int usbtenki_command(USBTenki_dev_handle hdl, unsigned char cmd,
										unsigned int id, unsigned char *dst, int dst_max_size);

int usbtenki_getCalibration(USBTenki_dev_handle hdl, int id, unsigned char *dst, int dst_max_size);
int usbtenki_setCalibration(USBTenki_dev_handle hdl, int channel_id, uint8_t *buf, int len);
int usbtenki_getRaw(USBTenki_dev_handle hdl, int id, unsigned char *dst, int dst_max_size);

int usbtenki_getUserCalibrationChannels(USBTenki_dev_handle hdl, uint16_t *channels);
// Destination array length must be at least CAL_POINTS_COUNT
int usbtenki_getUserCalibrationPoints(USBTenki_dev_handle hdl, int id, Point *points);
int usbtenki_setUserCalibrationPoint(USBTenki_dev_handle hdl, int channel_id, int point_id, const Point *point);
int usbtenki_getUserCalibrationCoeffs(USBTenki_dev_handle hdl, int channel_id, Point *points, double *coeffs);
int usbtenki_setUserCalibrationCoeffs(USBTenki_dev_handle hdl, int channel_id, const Point *points);

int usbtenki_getChipID(USBTenki_dev_handle hdl, int id);
int usbtenki_getNumChannels(USBTenki_dev_handle hdl);

int usbtenki_listChannels(USBTenki_dev_handle hdl, struct USBTenki_channel *dstArray, int arr_size);

int usbtenki_readChannelList(USBTenki_dev_handle hdl, const int channel_ids[], int num, struct USBTenki_channel *dst, int dst_total, int num_attempts, unsigned long flags);
int usbtenki_readChannel(USBTenki_dev_handle hdl, struct USBTenki_channel *chn, unsigned long flags);

int usbtenki_set_dxc120_asc(USBTenki_dev_handle hdl, int value);
int usbtenki_set_dxc120_frc(USBTenki_dev_handle hdl, int value);
int usbtenki_get_dxc120_asc(USBTenki_dev_handle hdl);

int usbtenki_set_dxc220_kz(USBTenki_dev_handle hdl, int value);


extern int g_has_at_least_one_unseen_dxc320;

#ifdef __cplusplus
}
#endif

#endif // _usbtenki_h__
