#ifndef XK_DRIVER_H
#define XK_DRIVER_H

#include "xk-osdep.h"

/****************************************************************************************************************/
//
// Structure for holding magstripe data
//
struct xk_trackdata {
  int status;			// Status from reader for this track
  unsigned int length;		// Length of track data
  uint8_t data[120];		// Actual data (zero terminated)
};

/****************************************************************************************************************/
//
// Firmware versions as reported by Leadus
//
struct vk_firmware_version {
  char type[16];
  char version[4];
  unsigned int sum;
};

struct vk_reader_version {
  struct vk_firmware_version cpu;
  struct vk_firmware_version spare;
  struct vk_firmware_version total;
  struct vk_firmware_version icc;
  struct vk_firmware_version sam;
  struct vk_firmware_version mem;
};

/****************************************************************************************************************/
//
// Firmware versions as reported by Sankyo
//
struct sk_firmware_version {
  char text[24];
};

struct sk_reader_version {
  struct sk_firmware_version supervisor_code;
  struct sk_firmware_version user_code;
  struct sk_firmware_version emv2000_code;
  struct sk_firmware_version emv_approval;
  struct sk_firmware_version reserve4;
  struct sk_firmware_version ifm_number;
  struct sk_firmware_version reserve6;
  struct sk_firmware_version reserve7;
  struct sk_firmware_version reserve8;
  struct sk_firmware_version reserve9;
};

/****************************************************************************************************************/
//
// Firmware versions as reported by Hopt+Schuler
//
struct hs_firmware_version {
  char text[64];
};

struct hs_reader_version {
  struct hs_firmware_version firmware;      // -
  struct hs_firmware_version serial;        // 0
  struct hs_firmware_version copyright;     // 1
  struct hs_firmware_version model;         // 2
  struct hs_firmware_version pcb;           // 3
  struct hs_firmware_version application;   // 4
  struct hs_firmware_version boot;          // 5
  struct hs_firmware_version loader;        // 6
  struct hs_firmware_version usb;           // 8
};

/****************************************************************************************************************/

#include "xk-enum.h"
#include "xk-private.h"

/****************************************************************************************************************/
//
// API calls
//

// Initialize data structure
void xk_init(struct xk_driver *xkp, enum xk_protocol_type pt, void *data);
void xk_set_protocol(struct xk_driver *xkp, enum xk_protocol_type pt);
XK_INLINE enum xk_protocol_type xk_get_protocol(struct xk_driver *xkp);
int xk_get_serial_port_speed(struct xk_driver *xkp);
int xk_get_serial_parity(struct xk_driver *xkp); // 0=none, 1=odd, 2=even

// Clear stale data
void xk_clear_trackdata(struct xk_driver *xkp);
void xk_clear_chipdata(struct xk_driver *xkp);

// Start/Stop driver
void xk_start(struct xk_driver *xkp);
void xk_stop(struct xk_driver *xkp);

// Actions
void xk_reset(struct xk_driver *xkp);
void xk_initialize(struct xk_driver *xkp);
void xk_insert(struct xk_driver *xkp, unsigned int insflags);
void xk_lock(struct xk_driver *xkp);
void xk_eject(struct xk_driver *xkp);
void xk_capture(struct xk_driver *xkp);

// Chip access
int xk_chip_select_socket(struct xk_driver *xkp, unsigned int ch); // 0=chip, 1=1st SAM, 2=2nd SAM, etc...
unsigned int xk_chip_get_socket(struct xk_driver *xkp);
int xk_chip_atr(struct xk_driver *xkp, enum xk_chip_type type);
int xk_chip_off(struct xk_driver *xkp);
int xk_chip_read(struct xk_driver *xkp, unsigned int address, unsigned int length);
int xk_chip_write(struct xk_driver *xkp, unsigned int address);
int xk_chip_read_ex(struct xk_driver *xkp, unsigned int clains, unsigned int address, unsigned int length);
int xk_chip_write_ex(struct xk_driver *xkp, unsigned int clains, unsigned int address);
int xk_chip_activate(struct xk_driver *xkp);
int xk_chip_identify(struct xk_driver *xkp, unsigned int flags, unsigned int country_code);
int xk_chip_pin(struct xk_driver *xkp, unsigned int pin, int set_tries);

XK_INLINE void *xk_get_chip_data(struct xk_driver *xkp);
XK_INLINE unsigned int xk_get_chip_length(struct xk_driver *xkp);
XK_INLINE void xk_set_chip_length(struct xk_driver *xkp, unsigned int length);
int xk_command(struct xk_driver *xkp, const void *cmd, unsigned int len);
int xk_apdu(struct xk_driver *xkp, const void *apdu, unsigned int len);

// Queries
int xk_is_empty(struct xk_driver *xkp);
int xk_has_card(struct xk_driver *xkp);
int xk_has_locked_card(struct xk_driver *xkp);
XK_INLINE int xk_has_card_data(struct xk_driver *xkp);
XK_INLINE int xk_is_online(struct xk_driver *xkp);
XK_INLINE int xk_is_ready(struct xk_driver *xkp);
XK_INLINE int xk_is_processing(struct xk_driver *xkp);
XK_INLINE const struct xk_trackdata *xk_get_tracks(struct xk_driver *xkp);
XK_INLINE enum xk_reader_type xk_reader_type(struct xk_driver *xkp);
XK_INLINE enum xk_state xk_state(struct xk_driver *xkp);
XK_INLINE unsigned int xk_sensors(struct xk_driver *xkp);
const struct vk_reader_version *vk_get_version(struct xk_driver *xkp);
const struct sk_reader_version *sk_get_version(struct xk_driver *xkp);
const struct hs_reader_version *hs_get_version(struct xk_driver *xkp);

/****************************************************************************************************************/
//
// Callbacks to application code
//

// Reader changed from offline to online
void xk_app_online(void *data);

// Reader changed from online to offline
void xk_app_error(void *data, unsigned int error_code);

// Called when reader state changes
void xk_app_state_changed(void *data, enum xk_state oldstate, enum xk_state newstate);

// Called when magstripe data was read
void xk_app_card_data_updated(void *data);

// Called when a chip command has finished
void xk_app_processing_complete(void *data, unsigned int error_code);

// Called whenever some of the sensor states changes
void xk_app_sensors_changed(void *data, unsigned int sensors);

// Called whenever a command completes. Can be used to update status info.
void xk_app_heartbeat(void *data);

// Can be used to control an indicator LED
void xk_app_led(void *data, int on);

/****************************************************************************************************************/
//
// Call from XK protocol driver to system layer
//

// Send data to serial port
void xk_os_send(struct xk_driver *xkp, const void *data, int len);

// Read state of control line
int xk_os_get_dsr(struct xk_driver *xkp);
int xk_os_get_cts(struct xk_driver *xkp);

// Some devices do not have DSR and wire to CTS instead.
int xk_os_get_dsr_or_cts(struct xk_driver *xkp);

// Start/stop retry timer. This is a single shot timer. If ms <= 0, timer stops.
void xk_os_set_retry_timer(struct xk_driver *xkp, int ms);

// Start/stop poll timer. This is a free running timer. If ms <= 0, timer stops.
void xk_os_set_poll_timer(struct xk_driver *xkp, int ms);

// Start/stop sequencer timer. This is a single shot timer. If ms <= 0, timer stops.
void xk_os_set_seq_timer(struct xk_driver *xkp, int ms);

// Get number of milliseconds since last call
int xk_os_get_elapsed(struct xk_driver *xkp);

/****************************************************************************************************************/
//
// Calls from system layer to XK protocol driver
//

// Call if retry timer has expired
void xk_trigger_retry(struct xk_driver *xkp);

// Call if poll timer has expired
void xk_trigger_poll(struct xk_driver *xkp);

// Call if sequencer timer has expired
void xk_trigger_timer(struct xk_driver *xkp);

// Call if data has been received
void xk_received(struct xk_driver *xkp, const void *data, int len);

/****************************************************************************************************************/
//
// Debug tools
//
void xk_set_trace(struct xk_driver *xkp, unsigned int trace);
unsigned int xk_get_trace(struct xk_driver *xkp);

void xk_trace(void *data, const char *fmt, ...);

void xk_trace_text(struct xk_driver *xkp, const void *data, unsigned int len);
void xk_trace_bin(struct xk_driver *xkp, const void *data, unsigned int len);
void xk_trace_command_timing(struct xk_driver *xkp, const char *txt);

/****************************************************************************************************************/
#endif
