#ifndef VK_DRIVER_H
#define VK_DRIVER_H

#include "vk-osdep.h"

/****************************************************************************************************************/
//
// Structure for holding magstripe data
//
struct vk_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 reader
//
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;
};

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

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

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

// Initialize data structure
void vk_init(struct vk_driver *vkp, void *data);

// Clear stale data
void vk_clear_version(struct vk_driver *vkp);
void vk_clear_trackdata(struct vk_driver *vkp);
void vk_clear_chipdata(struct vk_driver *vkp);

// Start/Stop driver
void vk_start(struct vk_driver *vkp);
void vk_stop(struct vk_driver *vkp);

// Actions
void vk_reset(struct vk_driver *vkp);
void vk_initialize(struct vk_driver *vkp);
void vk_insert(struct vk_driver *vkp, unsigned int insflags);
void vk_lock(struct vk_driver *vkp);
void vk_eject(struct vk_driver *vkp);
void vk_capture(struct vk_driver *vkp);

// Chip access
int vk_chip_atr(struct vk_driver *vkp, enum vk_chip_type type);
int vk_chip_off(struct vk_driver *vkp);
int vk_chip_read(struct vk_driver *vkp, unsigned int address, unsigned int length);
int vk_chip_write(struct vk_driver *vkp, unsigned int address);
int vk_chip_read_ex(struct vk_driver *vkp, unsigned int clains, unsigned int address, unsigned int length);
int vk_chip_write_ex(struct vk_driver *vkp, unsigned int clains, unsigned int address);
int vk_chip_activate(struct vk_driver *vkp);
int vk_chip_identify(struct vk_driver *vkp, unsigned int flags, unsigned int country_code);
int vk_chip_pin(struct vk_driver *vkp, unsigned int pin, int set_tries);

VK_INLINE void *vk_get_chip_data(struct vk_driver *vkp);
VK_INLINE unsigned int vk_get_chip_length(struct vk_driver *vkp);
VK_INLINE void vk_set_chip_length(struct vk_driver *vkp, unsigned int length);
int vk_command(struct vk_driver *vkp, const void *cmd, unsigned int len);
int vk_apdu(struct vk_driver *vkp, const void *apdu, unsigned int len);

// Queries
int vk_is_empty(struct vk_driver *vkp);
int vk_has_card(struct vk_driver *vkp);
int vk_has_locked_card(struct vk_driver *vkp);
VK_INLINE int vk_has_card_data(struct vk_driver *vkp);
VK_INLINE int vk_is_online(struct vk_driver *vkp);
VK_INLINE int vk_is_ready(struct vk_driver *vkp);
VK_INLINE int vk_is_processing(struct vk_driver *vkp);
VK_INLINE const struct vk_trackdata *vk_get_tracks(struct vk_driver *vkp);
VK_INLINE enum vk_reader_type vk_reader_type(struct vk_driver *vkp);
VK_INLINE enum vk_state vk_state(struct vk_driver *vkp);
VK_INLINE unsigned int vk_sensors(struct vk_driver *vkp);
VK_INLINE const struct vk_reader_version *vk_get_version(struct vk_driver *vkp);

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

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

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

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

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

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

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

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

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

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

// Send data to serial port
void vk_os_send(struct vk_driver *vkp, const void *data, int len);

// Read state of DSR line
int vk_os_get_dsr(struct vk_driver *vkp);

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

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

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

// Get number of milliseconds since last call
int vk_os_get_elapsed(struct vk_driver *vkp);

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

// Call if retry timer has expired
void vk_trigger_retry(struct vk_driver *vkp);

// Call if poll timer has expired
void vk_trigger_poll(struct vk_driver *vkp);

// Call if sequencer timer has expired
void vk_trigger_timer(struct vk_driver *vkp);

// Call if data has been received
void vk_received(struct vk_driver *vkp, const void *data, int len);

/****************************************************************************************************************/
//
// Debug tools
//
void vk_set_trace(struct vk_driver *vkp, unsigned int trace);
unsigned int vk_get_trace(struct vk_driver *vkp);

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

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