/***********************************************************************
 *
 * Copyrigth: Karl Hammar, Aspö Data, LGPL
 *
 */

#ifndef __FEIG_H__
#define __FEIG_H__

#include <aspoutil.h>
#include <stddef.h>
#include <stdint.h>

/*
  All section and page referenses are for H20800-18e-ID-B.pdf,
  ask a Feig represenative for the file.

  Note: content on page 3 have false page numbers
  starting with "4.7. CFG6: Scan-Mode1" which starts on page 51, not 52
 */

/*************************************************
 * 3. Asynchronous Interface
 * p. 18-20
 */

/*
 p. 18: 3.1. Data Format and Protocol Frames

Pos.| Field name
----+-----------
 request frame (host -> reader):
 0  | length (n)
 1  | com-adr
 2  | cmdand byte
 4  | data byte 1
   ... (l = length)
n-3 | data byte N
n-2 | crc16 low  byte
n-1 | crc16 high byte

 "Standard" reply frame (reader -> host):
 0  | length (n = 6..255)
 1  | com-adr
 2  | cmdand byte
 3  | status
 4  | data byte 1
   ...
n-3 | data byte N
n-2 | crc16 low  byte
n-1 | crc16 high byte

 "Advanced" reply frame:
 0  | STX                always 0x02 (ascii: STX)
 1  | length, high byte (n = 8..65535)
 2  | length, low  byte
 3  | com-adr
 4  | cmdand byte
 5  | status
 6  | data byte 1
   ...
n-3 | data byte N
n-2 | crc16 low  byte
n-1 | crc16 high byte

The only commands which uses (marked with a #) the "advanced" reply are:
 7.4.4. [0xBE] ISO 14443-4 T=CL (#)
 7.4.5. [0xBF] ISO 14443-4 Container Command (#)
and they are internally restrained by a data buffer of 256 bytes
 */

/* p.19 LENGTH (n = 6...255) */
/* DOC BUG: the statement that n = 6...255 is bogus, n = 5 for e.g. "CPU Reset" p.67 */
/* To get the buffer sizes of a connected reader use p.70 6.5. [0x66] Get Reader Info, and */
/* look at the RX-BUF and TX-BUF return values. */
#define FEIG_MAX_STDPKT_LEN 255
#define FEIG_MIN_STDPKT_LEN   5

/* p.18-19: all communications to readers will use this value */
/* I'll set it 255 as default, i.e. the broadcast adress */
/* p.23: readers COM_ADR is set to 0 at factory, to change it use 0x81, "Write Configuration" (p.62) */
extern uint8_t feig_com_adr;

/* p. 20: 3.2. CRC16 Calculation Algorithm */
#define FEIG_CRC_POLYNOM 0x8408
#define FEIG_CRC_PRESET  0xffff

/* as can be tested with Test_feigcrc.c, crc of total packet is == 0 */
#define feig_crc(buf, len) feig_crc_seed(buf, len, FEIG_CRC_PRESET)
uint16_t feig_crc_seed(uint8_t *buf, uint16_t len, uint16_t crc);
uint16_t feig_add_crc(uint8_t *buf);

int feig_verify_pkg( uint8_t *buf, const uint16_t sz, uint8_t *com_adr, uint8_t *cmd, uint8_t **data, uint16_t *data_len);

/****************************
 * 4. Configuration Parameters (CFG)
 * p. 21-60
 */

/* see p. 64 for the mode parameter */
/* see p. 166 for CFGn parameter */
#define feig_cfg_adr( LOC_eeprom, MODE_all_blocks, CFGn ) \
  ( BT( LOC_eeprom, 7 ) | BT(MODE_all_blocks, 6) | ( (CFGn) & 0x3f ) )

/* p. 23: 4.2. CFG1: Interface; byte numbers */
/* to change the com-adr, write the new address to eeprom and do a hard or cpu reset */
#define FEIG_CNF1_COM_ADR      0
#define FEIG_CNF1_BAUD         2
#define FEIG_CNF1_TRANSFORM    3
#define FEIG_CNF1_PSST         5
#define FEIG_CNF1_TR_RESP_HI   6 /* high byte */
#define FEIG_CNF1_TR_RESP_LO   8 /* low  byte */
#define FEIG_CNF1_READER_MODE 13

/* p.24: BAUD convert between baud rate and config value */
/* Note: the target might be a mcu with small amount of ram/flash */
/* I didn't want a lot of padding, so this instead of arr of struct {uint8_t cnf1; uint32_t rate); */
#define FEIG_BAUD_SZ 11
extern const uint32_t feig_baud[FEIG_BAUD_SZ]; /* this what is defined for the feig module */
#define feig_baud_cnf(ix)  ( feig_baud[ix] >> 3*8 )
#define feig_baud_rate(ix) ( feig_baud[ix] & 0xffffff )
uint8_t  feig_baud_r2c( uint32_t rate );
uint32_t feig_baud_c2r( uint8_t  cnf  );
extern const int feig_baud_bits[]; /* this is what's usable for the host */
extern const uint8_t feig_baud_bits_sz; /* sizeof(feig_baud_bits)/sizeof(int) */

/* p. 25: TRANS-FORM */
#define FEIG_NOPARITY   0
#define FEIG_EVENPARITY 1
#define FEIG_ODDPARITY  2
/* always 8 bits */
/* always 1 stop bit */

/* p. 26: READER-MODE */
/* bit 0 */
#define FEIG_SCAN_E_ISO_HOST     0
#define FEIG_SCAN_E_SCAN         1
#define FEIG_SCAN_IF_ASYNC       0
/* bit 1 */
#define FEIG_SCAN_IF_DATA_CLOCK  (1<<1)
/* bit 2-4, see 4.2.1. Magnetic Strip Emulation, and 4.2.2. Wiegand Emulation */
#define FEIG_DCF_WIEGAND_BINARY  (0<<2)
#define FEIG_DCF_MAGSTR_BINARY   (1<<2)
#define FEIG_DCF_MAGSTR_5BIT     (2<<2)
#define FEIG_DCF_MAGSTR_7BIT     (3<<2)
#define FEIG_DCF_WIEGAND_FORM_SS (4<<2)
#define FEIG_DCF_MAGSTR_5BIT_ZZ  (5<<2)
#define FEIG_DCF_WIEGAND_FORM    (6<<2)

/* p. 32: 4.3. CFG2: Inputs / Outputs general; byte numbers */
/* p. 32: 4.3.1. ID CPR.02 */

#define FEIG_CNF2_SIGNAL_EVENTS  1
#define FEIG_CNF2_IDLE_STATE     3
#define FEIG_CNF2_IDLE_FLASH     4
#define FEIG_CNF2_INPUT_EVENT    5
#define FEIG_CNF2_INPUT_FLASH    6
#define FEIG_CNF2_OFFL_STATE     7
#define FEIG_CNF2_OFFL_FLASH     8
#define FEIG_CNF2_OFFL_TIME      9

/* p. 33 SIGNAL-EVENTS */
#define FEIG_TAG_DETECT_GLED_NOSIG 0
#define FEIG_TAG_DETECT_GLED_OFF   1
#define FEIG_TAG_DETECT_GLED_ON    2

#define FEIG_TAG_DETECT_RLED_NOSIG 0
#define FEIG_TAG_DETECT_RLED_OFF   (1<<2)
#define FEIG_TAG_DETECT_RLED_ON    (2<<2)

#define FEIG_OFFL_DETECT           (1<<5)
#define FEIG_TAG_DETECT            (1<<6)
#define FEIG_STARTUP_SIGNAL        (1<<7)

/* p. 34 IDLE-STATE */
#define FEIG_IDLE_GRN_ON   1
#define FEIG_IDLE_GRN_OFF  2
#define FEIG_IDLE_GRN_FLSH 3

#define FEIG_IDLE_RED_ON   (1<<2)
#define FEIG_IDLE_RED_OFF  (2<<2)
#define FEIG_IDLE_RED_FLSH (3<<2)

#define FEIG_IDLE_BUZ_ON   (1<<4)
#define FEIG_IDLE_BUZ_OFF  (2<<4)
#define FEIG_IDLE_BUZ_FLSH (3<<4)

/* p. 34/35: INPUT-EVENT */
#define FEIG_IN1_GRN       (0<<0)
#define FEIG_IN1_GRNFL     (1<<0)
#define FEIG_IN1_GRNBUZ    (2<<0)
#define FEIG_IN1_GRNFLBUZ  (3<<0)

#define FEIG_IN2_RED       (0<<2)
#define FEIG_IN2_REDFL     (1<<2)
#define FEIG_IN2_REDBUZ    (2<<2)
#define FEIG_IN2_REDFLBUZ  (3<<2)

#define FEIG_IN3_BUZ       (0<<4)
#define FEIG_IN3_BUZALT    (1<<4)

/* Note only for async interface */
#define FEIG_IN_MSG_OFF     (0<<6)
#define FEIG_IN_MSG_TOACT   (1<<6)
#define FEIG_IN_MSG_TOINACT (2<<6)
#define FEIG_IN_MSG_CHANGE  (3<<6)

/* p. 35: OFFLINE-STATE */
/* same bits as IDLE-STATE, see above */

/* p. 36: IDLE-FLASH / INPUT-FLASH / OFFLINEL-FLASH */
#define FEIG_FLASH_5HZ    0
#define FEIG_FLASH_2HZ5   1
#define FEIG_FLASH_1HZ25  2
#define FEIG_FLASH_0HZ625 3
#define feig_cnf2_flash(buz,red,grn) (((buz)<<4) | ((red)<<2) | (grn))

/*  Note: CFG2 is all zeros (and unchangeable) for: */
/* p. 37: 4.3.2. ID CPR.M02 */
/* p. 39: 4.3.4. ID CPR04 / ID CPR.M04 */

/* p.40: 4.4. CFG3: RF-Interface; byte numbers */

#define FEIG_CNF3_TAG_DRV_HI   0
#define FEIG_CNF3_TAG_DRV_LO   1
#define FEIG_CNF3_ISO_DRV_HI   2
#define FEIG_CNF3_ISO_DRV_LO   3
#define FEIG_CNF3_MIN_LVL      6
#define FEIG_CNF3_ISO_BITRATE  7
#define FEIG_CNF3_ISO_STUPT   12   
#define FEIG_CNF3_ISO_FTUR    13

/* p. 40: TAG_DRV */
#define FEIG_TAG_DRV_LO_ICODE1    (1<<0)
#define FEIG_TAG_DRV_LO_ISO15693  (1<<3)
#define FEIG_TAG_DRV_LO_ISO14443A (1<<4)
#define FEIG_TAG_DRV_LO_ISO14443B (1<<5
#define FEIG_TAG_DRV_LO_ICODEEPC  (1<<6)

#define FEIG_TAG_DRV_HI_JEWEL  1

/* p. 41: ISO14443-DRV */
#define FEIG_ISO_DRV_LO_MIFARE_STD      (1<<0)
#define FEIG_ISO_DRV_LO_MYD             (1<<1)
#define FEIG_ISO_DRV_LO_MIFARE_UL       (1<<2)
#define FEIG_ISO_DRV_LO_ISO14443A_PART4 (1<<3)

/* p. 41: MIN_LVL */
#define feig_cnf3_min_lvl(man, lvl) (((man) ? (1<<7)) | ((lvl) & 0x0f))
#define FEIG_ISO1443_BITRATE_106KBPS 0
#define FEIG_ISO1443_BITRATE_212KBPS 1
#define FEIG_ISO1443_BITRATE_424KBPS 2
#define FEIG_ISO1443_BITRATE_848KBPS 3

#define feig_cnf3_iso1443_bitrate( tx, rx ) ( ((tx)<<6) | ((rx) <<4) )

/* p. 43: ISO14443 FTUR */
#define feig_ftur( opti, retry, plic, bslct) ( ((opti)?1<<4:0) | ((retry)&3)<<2) | ((plic)?2:0)) | ((bslct)?1:0) )

/* p. 45: 4.5. CFG4: Transponder Parameters; byte numbers */

#define FEIG_CNF4_ISO15693_MODE   4
#define FEIG_CNF4_ISO15693_AFI    5
#define FEIG_CNF4_ISO15693_OPTION 6
#define FEIG_CNF4_CUSTOMER_OPTION 7
#define FEIG_CNF4_ISO1443B_AFI    8
#define FEIG_CNF4_MOD_IDX         9
#define FEIG_CNF4_ISO15693_BLSZ  13

/* p.45: ISO15693-MODE */

#define feig_iso15693_mode(afi_enable, ts1, mod_10) \
  ( ((afi_enable)?1<<5:0) | ((ts1)?1<<4:0) | (1<<3) | (0<<2) | ((mod_10)?1<<2:0) | 0 )

/* p.45/46: CUSTOMER OPTION */

#define FEIG_INFINEON_OPTION 0x01

/* p. 47: ISO15693-OPTION */

#define FEIG_ISO15693_OPTION_AUTO 0
#define FEIG_ISO15693_OPTION_0    (2<<2)
#define FEIG_ISO15693_OPTION_1    (3<<2)

/* p. 47: MOD-IDX */

#define FEIG_MOD_IDX_MAX 0
#define FEIG_MOD_IDX_MED 1
#define FEIG_MOD_IDX_MIN 2

/* p. 48: ISO15693-BLOCKSIZE */

#define FEIG_ISO15693_BLOCKSIZE_MANUAL             (1<<5)

#define FEIG_ISO15693_BLOCKSIZE_READ_MODE_AUTO     0
#define FEIG_ISO15693_BLOCKSIZE_READ_MODE_SINGLE   (1<<6)
#define FEIG_ISO15693_BLOCKSIZE_READ_MODE_MULTIPLE (2<<6)

/* p. 49: 4.6. CFG5: Anticollision, byte numbers */

#define FEIG_CNF5_ONT 11

#define FEIG_ONT( only_new, anti_col_mode, aorb_req ) ( ((only_new)?1:0) | ((anti_col_mode)?1<<2:0) | ((aorb_req)?1<<3:0) )
/* beats me what the aorb_req means, seems bo the same thing */

/* p. 51: 4.7. CFG6: Scan-Mode1; byte numbers */

#define FEIG_CNF6_SCAN_DATA1         3
#define FEIG_CNF6_SCAN_DATA2         4
#define FEIG_CNF6_SCAN_LOCK_TIME_HI  6
#define FEIG_CNF6_SCAN_LOCK_TIME_LO  7
#define FEIG_CNF6_MAD_AID_HI         8
#define FEIG_CNF6_MAD_AID_LO         9
#define FEIG_CNF6_SCAN_KEY_ADR      10
#define FEIG_CNF6_DB_ADR            11
#define FEIG_CNF6_D_LGT             12
#define FEIG_CNF6_D_START           13

/* p. 51: SCAN-DATA1 */

#define feig_scan_data1( output_uid, output_db, in_bcd, uid_lsb_first, mad_on, com_prefix_on, db_lsb_first) (  \
  BT(output_uid, 0)    | BT(output_db, 1) | BT(in_bcd, 2)        | 0                     | \
  BT(uid_lsb_first, 4) | BT(mad_on, 5)    | BT(com_prefix_on, 6) | BT(db_lsb_first, 7) )

/* p. 53: SCAN-DATA2 */

#define feig_scan_data2( indpd ) BT(indpd, 0)

/* p. 56: SCAN-KEY_ADR */

#define FEIG_MIFARE_KEY_A 0
#define FEIG_MIFARE_KEY_B (1<<7)

/* p. 59: 4.8. CFG7: Scan-Mode2 */

#define FEIG_CFG7_DB_USE   0
#define FEIG_CFG7_SEP_CHAR 1
#define FEIG_CFG7_SEP_USR  2
#define FEIG_CFG7_END_CHAR 3
#define FEIG_CFG7_END_USR  4

/* p. 50: DB-USE */

#define FEIG_DB_FORMAT_BINARY 0
#define FEIG_DB_FORMAT_ASCII  2

/* p. 60: SEP-CHAR and END-CHAR */

#define FEIG_CHAR_NONE  0
#define FEIG_CHAR_CRLF  BV(0)
#define FEIG_CHAR_LF    BV(1)
#define FEIG_CHAR_CR    BV(2)
#define FEIG_CHAR_TAB   BV(3)
#define FEIG_CHAR_SEMI  BV(4)
#define FEIG_CHAR_COMMA BV(5)
#define FEIG_CHAR_SPACE BV(6)
#define FEIG_CHAR_USER  BV(7)

/**********************************************************
 * generic packet builders
 * all packet builders returns the length of the packet made, or -length on error (no buf or bufsz to small)
 */

int feig_cmd1_req(  uint8_t *buf, uint8_t bufsz, uint8_t cmd);
int feig_cmd2_req(  uint8_t *buf, uint8_t bufsz, uint8_t cmd, uint8_t data);
int feig_cmd2a_req( uint8_t *buf, uint8_t bufsz, uint8_t cmd, uint8_t data, uint8_t *arr, uint8_t sz);

/************************************************
 * 5. Commands for Reader Configuration
 * p. 61-65
 */

#define FEIG_COMMAND_SZ 19
extern const struct intstr feig_command[FEIG_COMMAND_SZ];

#define feig_read_conf_req(   buf, bufsz, loc,       CFGn ) feig_cmd2_req( buf, bufsz, 0x80, feig_cfg_adr(loc,    0, CFGn))
#define feig_save_conf_req(   buf, bufsz,      mode, CFGn ) feig_cmd2_req( buf, bufsz, 0x82, feig_cfg_adr(  0, mode, CFGn))
#define feig_setdef_conf_req( buf, bufsz, loc, mode, CFGn ) feig_cmd2_req( buf, bufsz, 0x82, feig_cfg_adr(loc, mode, CFGn))

 /* conf_rec[] must contain 14 elements, as in conf_rec[14] */
#define feig_write_conf_req(  buf, bufsz, loc,       CFGn, conf_rec ) \
  feig_cmd2a_req( buf, bufsz, 0x81, feig_cfg_adr(loc, 0, CFGn), conf_rec, 14)

int feig_write_mifare_keys_req( uint8_t *buf, uint8_t bufsz, uint8_t key_type, uint8_t key_adr, uint8_t key[6]);

/************************************************
 * 6. Command for Reader Control
 * p. 66-79
 */

/* p. 70: MODE byte  */
#define FEIG_GETREADERINFO_GENERAL       0x00
/*#define FEIG_GETREADERINFO_ACCONTR 0x01 // not supported */
#define FEIG_GETREADERINFO_USBCONTROLLER 0x02
#define FEIG_GETREADERINFO_RFDECODER     0x03
#define FEIG_GETREADERINFO_ADDFW         0x04
#define FEIG_GETREADERINFO_DEVID         0x80


#define feig_baud_rate_detection( buf, bufsz )  feig_cmd2_req( (buf), (bufsz), 0x52, 0x00 )
#define feig_start_flash_loader( buf, bufsz )   feig_cmd1_req( (buf), (bufsz), 0x55 )
#define feig_cpu_reset( buf, bufsz )            feig_cmd1_req( (buf), (bufsz), 0x63 )
#define feig_get_software_version( buf, bufsz ) feig_cmd1_req( (buf), (bufsz), 0x65 )
#define feig_get_reader_info( buf, bufsz, mode) feig_cmd2_req( (buf), (bufsz), 0x66, (mode) )
#define feig_rf_reset( buf, bufsz )             feig_cmd1_req( (buf), (bufsz), 0x69 )
#define feig_rf_output_power( buf, bufsz, ant ) feig_cmd2_req( (buf), (bufsz), 0x6A, (ant)&3 )
#define feig_get_input( buf, bufsz )            feig_cmd1_req( (buf), (bufsz), 0x74 )

/* p. 76-78 */
/* os: use defines under "// p. 34 IDLE-STATE" above */
/* osf: dito "// p. 36: IDLE-FLASH / INPUT-FLASH / OFFLINEL-FLASH" */
int feig_set_output( uint8_t *buf, uint16_t bufsz, uint16_t os, uint16_t osf, uint16_t os_time, uint16_t out_time );

/************************************************
 * 7. ISO Host Commands for Transponder Communication
 * p. 80-125
 */

#define FEIG_ISO_COMMAND_SZ 24
extern const struct intstr feig_iso_command[FEIG_ISO_COMMAND_SZ];

/************************************************
 * 8. Special Commands for Transponder Communication
 * p. 126-136
 */

/************************************************
 * 9. Supported ISO Host commands9. Supported ISO Host commands
 * p. 137-159
 */

/************************************************
 * ANNEX
 * p. 157-167
 */

/* ANNEX A: Codes of Transponder Types */
/* p. 157 */

#define FEIG_TRANSPONDER_TYPE_SZ 8
extern const struct intstr feig_transponder_type[FEIG_TRANSPONDER_TYPE_SZ];

/* ANNEX B: Codes of Reader Types */
/* p. 158 */

#define FEIG_READER_TYPE_SZ 21
extern const struct intstr feig_reader_type[FEIG_READER_TYPE_SZ];

/* ANNEX C: Index of Status Bytes */
/* p. 159-160 */

#define FEIG_STATUS_BYTE_SZ 21
extern const struct intstr feig_status_byte[FEIG_STATUS_BYTE_SZ];
int feig_check_status(uint8_t status, uint8_t print);

/* ANNEX C1: ISO15693-Error, Error-Codes */
/* p. 160 */

#define FEIG_ISO15693_ERROR_SZ 9
extern const struct intstr feig_iso15693_error[FEIG_ISO15693_ERROR_SZ];

/* ANNEX C2: ISO14433-Error, Error-Codes */
/* p. 161 */

#define FEIG_ISO14433_ERROR_SZ 5
extern const struct intstr feig_iso14433_error[FEIG_ISO14433_ERROR_SZ];


void feig_prtpkg(const char *prefix, const void *pkg, const size_t pkg_len);
int feig_strcmd_usage(void);
int feig_strcmd(uint8_t *buf, size_t bufsz, int argc, char *argv[]);


struct feig_readerinfo_t {
  uint16_t sw_rev;
  uint8_t  d_rev;
  uint8_t  hw_type;
  uint8_t  sw_type;
  uint16_t tr_type;
  uint16_t rx_buf;
  uint16_t tx_buf;
};

int feig_readerinfo_print(const char *prefix, struct feig_readerinfo_t *info);
int feig_get_reader_info_res(uint8_t *buf, uint16_t sz, const char *prefix, struct feig_readerinfo_t *info);
int feig_standard_setup(int fd, uint8_t sw_type, uint8_t com_adr);

int feig_find(struct tty_open_save *save, struct termios *current_termios, useconds_t sleep_time,
	      const char *prefix, struct feig_readerinfo_t *info);

/* write(req), sleep, read(res), verify, check status byte */
/* note all commands returns a status byte except [0x52] Baud Rate Detection (p.66), that one is not supported by this routine */
int feig_simple_io(int fd, const uint8_t *req, int reqsz, uint8_t *res, int ressz, useconds_t sleep_time);

struct termios *termios_feig(struct termios *term);

#endif
