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

#ifndef __S6400_H__
#define __S6400_H__

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

/*
## RFID ######################

 General information on RFID:
http://en.wikipedia.org/wiki/Rfid
http://en.wikipedia.org/wiki/ISO_15693
http://en.wikipedia.org/wiki/ISO/IEC_14443

 Homepage of the working group 8 ISO/IEC JTC1/SC17/WG8
 who deals with "Contactless Integrated Circuit(s) Cards"
http://wg8.de/index.html
 Their public drafts of the 14443 and 15693 standars
 are available at:
http://wg8.de/sd1.html

## UID #######################

14443 uids have three sizes: 4, 7, or 10 bytes
 for details see: http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf
 page 21, 6.5.4 UID contents and cascade levels
15693 uids are 64 bits (8bytes):
 0xE0 + "IC Mfg code" (1Byte) + "IC manufacturer serial number" (6bytes)
 the "IC Mfg code" is said to be available in "ISO/IEC 7816-6:2004"

## Wiegand ###################

(http://www.mercury-security.com/technology/whenyou.htm)
Wiegand protocol in this context are two different things:
1. an electrical interface using two wires (plus GND and power)
2. a data format using 26 bits
   (parity bit, 8-bit facility code, 16-bit user ID, and parity bit)

Unfortunately, as a side effect of being popular in the -80, many
 inconsistent implementations and extensions to the basic format evolved.

## This reader ###############

Ref. S6400 Reference manual (ri-h4r-s5h3_ref_guide.pdf).

Securakey (seems to have taken over the manuf. from ti):
 http://www.securakey.com/pdf/ETag_IV_Com_Protocol_080228.pdf

Page 11, 1.1 Introduction
. based on ISO/IEC 15693
. up to 10 badges can be read simultaneously by a single reader

General form of request/response packet to/from reader (page 21..24) is
from first to last byte:

Pos.| Field name
----+-----------
 0  | SOF                always 0x01 (ascii: SOH)
 1  | length, low  byte
 2  | length, high byte
 3  | device id          always 0x10
 4  | cmd, low  byte     flags (see page 22)
 5  | cmd, high byte     specific instructions
 6  | data byte 1
   ...
l-3 | data byte N
l-2 | lrc                (page 25)
l-1 | ~lrc

 where
   l = length = total number of bytes (SOF ... ~lrc)
   the shortest possible packet is 8 bytes long
   page 21: length_of_data = N <= 1000
   i.e. max allowed request length is 6+1000+2 = 1008 bytes

 Note
   everything is send/received LSB first
   see e.g. page 32

 About the serial number:
 . it is (on the wire) 7 ascii digits
   (unknown if decimal or hex, but all examples only have decimal numbers)

 . page 22, note 1, serial number is 8 bytes (in ASCII) in req
   but on page 61, only 7bytes are returned in "reader version command"
 . page 65, first note, serial is a 7 "digit" serial number
 . page 22, note 1, first byte is 0x00, which in all examples is sent last
 . page 32 example, the used serial# does not match the "LSB first" rule in the
   same paragraph, it is ended by a NUL, so it seems to be a char[8],
   not as an uintXX_t as the UID
 . 7 digits: 0 .. 9999999 (decimal) or 0 .. 0x98967F (hex), i.e. 24bits would suffice
   if each digit is decimal, or 28bits if hex
*/

extern int s6400_serialishex;
void s6400_prpkg(const char *prefix, const void *pkg, const size_t pkg_len);

int s6400_serial2str(uint32_t serial, char str[8]);

/* void * so it accepts char* (argv[]), uint8_t* (response), ... */
int s6400_str2serial(void *str, uint32_t *serial);

/* theese two moved to rfid.[ch] */
/*int s6400_buf2uid(const uint8_t buf[8], uint64_t *uid); */
/*int s6400_uid2buf(uint64_t uid, uint8_t buf[8]); */
/* use instead: */
/*#define s6400_buf2uid(buf, uid) rfid_buf2uid(buf, uid) */
/*#define s6400_uid2buf(uid, buf) rfid_uid2buf(uid, buf) */

#define S6400_MAXREQLEN 1008
#define S6400_PACKETLENGTH(x) ( (x)[1] | (x)[2] << 8 )
#define S6400_FLAGBYTE(x)     ( (x)[4] )
#define S6400_CMDBYTE(x)      ( (x)[5] )
#define S6400_DATAOFFSET      6

/* **************************************** */
/* page 22, 3.2.1.1 Request Packet Command Flags */
/* s6400_generic_req() uses the low half byte of this to set the flag
   bit 4: 0x08: 0 FSK,   1 ASK  (Frequency vs. Amplitude Shift Keying)
   bit 3: 0x04: 0 100%,  1 10%  (see page 4 http://wg8.de/17n3027.pdf)
   bit 2: 0x02: 0 slow,  1 fast read
   bit 1: 0x01: 0 1/256, 1 1/4  (1 of 4 is the faster one)

 According draft ISO/IEC 15693-2:2006 (2nd Edition) http://wg8.de/17n3027.pdf:
ASK is used (page 3, 7.1 Modulation)
the tag shall decode both 10% and 100% modulation (page 3, 7.1 Modulation)
the tag shall support both 1 of 4 and 1 of 256 data coding (page 5, 7.2 Data rate and data coding)
the tag shall support both high and low data rates (page 8, 8.3 Data rates)

 http://wg8.de/wg8n1495_17n3615_Ballot_FCD14443-2.pdf, page 12, 7 Signal interface:
14443 have two signal types, Type A and B, and four bit rates.

 Our test with inventory (0x01) command gives:
ASK modulation does not work
10% modulation does not work with newer tags, but ok with older
fast vs. slow read seems to be egal
1 of 4 vs. 1 of 256  seems to be egal

fast and 1/4 is the preferred according to a Securakey representative.
*/
extern uint8_t s6400_default_flags;

/* **************************************** */
/* page 25, 3.2.4 BCC */
int s6400_addlrc( uint8_t *buf);

/* page 25, 3.2.5 Packet reception and validation */
int s6400_validate( const uint8_t *buf, const size_t bufsize);

/* **************************************** */
/* page 26..58, ISO 15693 Commands */
/* iec15693: also have  */
/*  0x02 Mandatory Stay quiet */
/*  0x24 Optional  Write multiple blocks */
/*  0x25 Optional  Select */
/*  0x26 Optional  Reset to ready */

/* page 27, 3.3.3.1 Read Single Block Command (20h) */
#define s6400_read_single_block_req( buf, bufsize, serial, uid, num) \
	s6400_generic1_req( buf, bufsize, 0x20, serial, uid, num)

/* page 30, 3.3.3.2 Write Single Block (21h) */
#define s6400_write_single_block_req( buf, bufsize, serial, uid, data, data_len) \
	s6400_generic_req( buf, bufsize, 0x21, serial, uid, data, data_len)

/* page 33, 3.3.3.3 Lock Single Block Command (22h) */
#define s6400_lock_single_block_req( buf, bufsize, serial, uid, num) \
	s6400_generic1_req( buf, bufsize, 0x22, serial, uid, num)

/* page 36, 3.3.3.4 Read Multi-block Command (23h) */
#define s6400_read_multiblock_req(buf, bufsize, serial, uid, start, cnt) \
	s6400_generic2_req( buf, bufsize, 0x23, serial, uid, start, cnt)

/* page 39, 3.3.3.5 Write AFI Command (27h) */
#define s6400_write_afi_req( buf, bufsize, serial, uid, afi) \
	s6400_generic1_req( buf, bufsize, 0x27, serial, uid, afi)

/* page 42, 3.3.3.6 Lock AFI Command (28h) */
#define s6400_lock_afi_req( buf, bufsize, serial, uid) \
	s6400_generic_req( buf, bufsize, 0x28, serial, uid, NULL, 0)

/* page 45, 3.3.3.7 Write DSFID Command (29h) */
/* Note about DSFID: */
/* page 27 says: Data Storage Format Identifier (DSFID) is used for revision on functionality features of the firmware. */
/* http://wg8.de/wg8n1364_17n3316_FCDBallot_15693-3.pdf page 5 says: */
/*  The Data storage format identifier indicates how the data is structured in the VICC memory. */
#define s6400_write_dsfid_req( buf, bufsize, serial, uid, dsfid) \
	s6400_generic1_req( buf, bufsize, 0x29, serial, uid, dsfid)

/* page 48, 3.3.3.8 Lock DSFID Command (2Ah) */
#define s6400_lock_dsfid_req(buf, bufsize, serial, uid) \
	s6400_generic_req(buf, bufsize, 0x2A, serial, uid, NULL, 0)

/* page 51, 3.3.3.9 Read Tag Information Command (2Bh) */
/* iec15693: Get system information */
/* Note: The meaning of the IC reference is defined by the IC manufacturer */
#define s6400_read_tag_information_req(buf, bufsize, serial, uid) \
	s6400_generic_req(buf, bufsize, 0x2B, serial, uid, NULL, 0)

/* data_flag bits, they tell us what is present in the response */
#define S6400_DATA_FLAG_DSFID 0x01
#define S6400_DATA_FLAG_AFI 0x02
#define S6400_DATA_FLAG_VICC 0x04
#define S6400_DATA_FLAG_IC 0x08
/* contains { S6400_DATA_FLAG_DSFID, "DSFID field present"} etc. */
extern const struct intstr s6400_data_flag[];
int s6400_read_tag_information_res(uint8_t *buf, uint8_t *data_flag, uint64_t *uid, uint8_t *dsfid, uint8_t *afi, uint8_t *nblocks, uint8_t *block_sz, uint8_t *ic_ref);

/* page 54, 3.3.3.10 Read Multi-block Security Status Command (2Ch) */
#define s6400_read_multiblock_security_status_req(buf, bufsize, serial, uid, start, cnt) \
	s6400_generic2_req( buf, bufsize, 0x2C, serial, uid, start, cnt)

/* page 57, 3.3.3.11 Inventory Command (01h) */
#define s6400_inventory_req( buf, bufsize, serial, uid, afi) \
	s6400_generic1_req( buf, bufsize, 0x01, serial, uid, afi)

/* returns # of uid's found (uid_cnd), but saves at max uid_sz */
/* status should be 0x00, don't know what other values vould mean */
int s6400_inventory_res(uint8_t *buf, uint8_t *status, uint8_t *uid_cnt, size_t uid_sz, uint64_t *uid);

/* **************************************** */
/* page 59..60, 3.4 ISO 14443A Commands */
/* page 59, 3.4.1 View UID (40h) */
#define s6400_view_uid_req( buf, bufsize, serial) \
	s6400_generic1_req( buf, bufsize, 0x40, serial, 0, 0)

/* **************************************** */
/* page 61..82, 3.5 Reader Commands */

/* page 61, 3.5.2.1 Reader Version Command (E0h) */
#define s6400_reader_version_req(buf, bufsize, serial) \
	s6400_generic_req(buf, bufsize, 0xE0, serial, 0, NULL, 0)

int s6400_reader_version_res(uint8_t *buf, uint16_t *version, uint8_t *prod_id, uint32_t *serial);

/* page 64, 3.5.2.2 Reader Reset Command (E5h) */
#define s6400_reader_reset_req(buf, bufsize, serial) \
	s6400_generic_req(buf, bufsize, 0xE5, serial, 0, NULL, 0)

/* page 65, 3.5.2.3 Reader Set-up Command (E7h) */
#define s6400_reader_setup_req(buf, bufsize, serial) \
	s6400_generic_req(buf, bufsize, 0xE7, serial, 0, NULL, 0)
int s6400_reader_setup_res(uint8_t *buf, uint8_t *mode1, uint8_t *mode2, uint8_t *baud, uint8_t *afi, uint8_t *encr);

/* page 69, 3.5.2.4 Get Reader Information Command (EBh) */
#define s6400_get_reader_information_req(buf, bufsize, serial) \
	s6400_generic_req(buf, bufsize, 0xEB, serial, 0, NULL, 0)

/* page 70, 3.5.2.5 Set Custom DES Key (ECh) */
/* ?? can one use serial and/or uid in request ?? */
#define s6400_set_custom_des_key_req(buf, bufsize, serial, uid, data) \
	s6400_generic_req(buf, bufsize, 0xEC, serial, uid, data, 8)

/* page 71, 3.5.2.6 Reader Mode (EDh) */
/* data = { mode1, mode2, optional afi } */
/* mode 1 values */
#define S6400_MODE_RFOFF     0x03
#define S6400_MODE_RFON      0x04
#define S6400_MODE_LEDAUDIO  0x07
#define S6400_MODE_WIEG14443 0x09
#define S6400_MODE_WIEG15693 0x0A
#define S6400_MODE_WIEGTAGIT 0x0B
#define S6400_MODE_WIEGOFF   0x0C
#define S6400_MODE_9600      0x0E
#define S6400_MODE_19200     0x0F
#define S6400_MODE_38400     0x10
/* mode 2 is zero unless mode 1 == 0x07 or 0x0A */
/* mode 2 bits, when mode 1 = 0x07 */
#define S6400_MODE_LED       0x04 /* bit "2" */
#define S6400_MODE_AUDIO     0x08 /* bit "3" */
/* mode 2 bits, when mode 1 = 0x0A */
#define S6400_MODE_26BITS    0x00
#define S6400_MODE_ENCRYPT   0x01
#define S6400_MODE_32BITS    0x02
#define S6400_MODE_36BITS    0x03
#define S6400_MODE_64BITS    0x04

#define s6400_reader_mode_req( buf, bufsize, serial, mode1, mode2) \
	s6400_generic2_req( buf, bufsize, 0xED, serial, 0, mode1, mode2)

#define s6400_reader_mode_wieg_req( buf, bufsize, serial, mode2, afi) \
	s6400_generic3_req( buf, bufsize, 0xED, serial, 0, 0x0A, mode2, afi)

/* page 79, 3.5.2.7 Activate LED (EEh) */
/* ?? serial possible ?? duration in ms */
#define s6400_activate_led_req(buf, bufsize, serial, colour, duration) \
	s6400_generic3_req( buf, bufsize, 0xEE, serial, 0, 0, colour, duration)

/* page 80, 3.5.2.8 Activate Audio (EFh) (misspelled header "Active"?) */
/* ?? serial possible ?? duration in ms */
#define s6400_activate_audio_req( buf, bufsize, serial, duration) \
	s6400_generic2_req( buf, bufsize, 0xEF, serial, 0, 0, duration)

/* **************************************** */
/* page 81..82, 3.5.3 Error Codes */
extern const struct intstr s6400_err_flag[];

/* page 81, 3.5.3.1 Error Codes from the Transponder */
extern const struct intstr s6400_err_transponder[];

/* page 82, 3.5.3.2 Error Codes from the Reader */
extern const struct intstr s6400_err_reader[];

/* returns 0 if found no error or if it is a valid error response packet */
/*  in which case err_code etc. tells us the reported error */
/*  err_code = flag_byte << 8 || code_byte; */
/* NOTE: the packet itself must have passed s6400_validate() */
int s6400_check_error_res(uint8_t *buf, uint16_t *err_code, const char **err1, const char **err2);
int s6400_check_error_report(uint16_t err_code, const char *err1, const char *err2);

/* **************************************** */
/* helper routines */
/*
  When
  . serial == 0
  . uid    == 0
  . data == NULL || data_len == 0
  the respective value is not written to the request
 */
int s6400_generic_req( uint8_t *buf, size_t bufsize, uint8_t cmd, uint32_t serial, uint64_t uid,
	 uint8_t *data, size_t data_len);
/* teese three below takes 1..3 values, builds a data array, and calls the above function */
int s6400_generic1_req(uint8_t *buf, size_t bufsize, uint8_t cmd, uint32_t serial, uint64_t uid,
	 uint8_t a);
int s6400_generic2_req(uint8_t *buf, size_t bufsize, uint8_t cmd, uint32_t serial, uint64_t uid,
	 uint8_t a, uint8_t b);
int s6400_generic3_req(uint8_t *buf, size_t bufsize, uint8_t cmd, uint32_t serial, uint64_t uid,
	 uint8_t a, uint8_t b, uint8_t c);

/* **************************************** */
/* Debugging related */

/* usable command names for s6400_strcmd */
extern struct intstr s6400_cmd[];

/* argv[]: cmd_name mode serial uid data... */
int s6400_strcmd(uint8_t *buf, size_t bufsize, int argc, char *argv[]);

#endif
