module CCID_Types {

import from General_Types all;
import from Osmocom_Types all;
import from USB_Types all;

/* TTCN-3 data types with TITAN RAW codec annotations for USB CCID
 * "Universal Serial Bus - Device Class: Smart Cad - CCID - Specification
 *  for Integrated Circuit(s) Cards Interface Devices,
 *  Revision 1.1, April 22nd, 2005"
 *
 * (C) 2018 by Harald Welte <laforge@gnumonks.org>
 */

/***********************************************************************
 * CCID Class Descriptor, See section 5.1, Table 5.1-1
 ***********************************************************************/

type record CCID_VoltageSupport {
	BIT5			RFU,
	boolean			voltage_1v8,
	boolean			voltage_3v0,
	boolean			voltage_5v0
};

type record CCID_Protocols {
	BIT30			RFU,
	boolean			protocol_t1,
	boolean			protocol_t0
} with { variant "BYTEORDER(first)" };

type record CCID_SynchProtocols {
	BIT29			RFU,
	boolean			protocol_i2c,
	boolean			protocol_3wire,
	boolean			protocol_2wire
};

type record CCID_Mechanical {
	BIT28			RFU,
	boolean			card_lock_unlock,
	boolean			card_capture,
	boolean			card_ejection,
	boolean			card_accept
};

type enumerated CCID_Level {
	CCID_LEVEL_CHARACTER		(0),
	CCID_LEVEL_TPDU			(1),
	CCID_LEVEL_SHORT_APDU		(2),
	CCID_LEVEL_SHORT_AND_EXTD_APDU	(3)
} with { variant "FIELDLENGTH(3)" };

type record CCID_Features {
	BIT13			RFU,
	CCID_Level		level,
	BIT5			RFU2,
	boolean			automatic_ifsd_t1,
	boolean			nad_other_than_00_t1,
	boolean			icc_clock_stop,
	boolean			automatic_pps_active_pars,
	boolean			automatic_params,
	boolean			automatic_baud_active_pars,
	boolean			automatic_clock,
	boolean			automatic_voltage,
	boolean			automatic_activation,
	boolean			automatic_pars_atr,
	BIT1			RFU3
};

type record CCID_ClassDescriptor {
	uint8_t			bLength,
	uint8_t			bDescriptorType,
	HEX4n			bcdCCID,
	uint8_t			bMaxSlotIndex,
	CCID_VoltageSupport	bVoltageSupport,
	//CCID_Protocols		dwProtocools,
	BIT32			dwProtocools,
	u32le_t			dwDefaultClock,
	u32le_t			dwMaximumClock,
	uint8_t			bNumClockSupported,
	u32le_t			dwDataRate,
	u32le_t			dwMaxDataRate,
	uint8_t			bNumDataRatesSupported,
	u32le_t			dwMaxIFSD,
	//CCID_SynchProtocols		dwSynchProtocols,
	//CCID_Mechanical		dwMechanical,
	//CCID_Features			dwFeatures,
	BIT32			dwSynchProtocols,
	BIT32			dwMechanical,
	BIT32			dwFeatures,
	u32le_t			dwMaxCCIDMessageLength,
	uint8_t			bClassGetResponse,
	uint8_t			bClassEnvelope,
	u16le_t			wLcdLayout,
	uint8_t			bPINSupport,
	uint8_t			bMaxCCIDBusySlots
};

external function enc_CCID_ClassDescriptor(in CCID_ClassDescriptor pdu) return octetstring
with { extension "prototype(convert)"
       extension "encode(RAW)"
     }

external function dec_CCID_ClassDescriptor(in octetstring stream) return CCID_ClassDescriptor
with { extension "prototype(convert)"
       extension "decode(RAW)"
     }



/***********************************************************************
 * Bulk IN
 ***********************************************************************/

/* Section 6.1.1 */
type enumerated CCID_PowerSelect {
	CCID_PWRSEL_AUTO		('00'H),
	CCID_PWRSEL_5V0			('01'H),
	CCID_PWRSEL_3V0			('02'H),
	CCID_PWRSEL_1V8			('03'H)
} with { variant "FIELDLENGTH(8)" };

/* Section 6.1.1 */
type record CCID_PC_to_RDR_IccPowerOn {
	CCID_PowerSelect	bPowerSelect,
	OCT2			abRFU
};

/* Section 6.1.2 */
type record CCID_PC_to_RDR_IccPowerOff {
	OCT3			abRFU
};

/* Section 6.1.3 */
type record CCID_PC_to_RDR_GetSlotStatus {
	OCT3			abRFU
};

/* Section 6.1.4 */
type record CCID_PC_to_RDR_XfrBlock {
	uint8_t			bBWI,
	u16le_t			wLevelParameter,
	octetstring		abData
};

/* Section 6.1.5 */
type record CCID_PC_to_RDR_GetParameters {
	OCT3			abRFU
};

/* Section 6.1.6 */
type record CCID_PC_to_RDR_ResetParameters {
	OCT3			abRFU
};

/* Section 6.1.7 */
type enumerated CCID_ClockStop {
	STOPPING_NOT_ALLOWED	('00'H),
	STOP_WITH_CLK_LOW	('01'H),
	STOP_WITH_CLK_HIGH	('02'H),
	STOP_WITH_CLK_EITHER	('03'H)
} with { variant "FIELDLENGTH(8)" };
type record CCID_ProtocolData_T0 {
	uint4_t			Findex,
	uint4_t			Dindex,

	BIT6			bRFU,
	boolean			inv_convention,
	BIT1			bRFU2,

	uint8_t			bGuardTimeT0,
	uint8_t			bWaitingIntegerT0,
	CCID_ClockStop		bClockStop
};
type record CCID_ProtocolData_T1 {
	uint4_t			Findex,
	uint4_t			Dindex,

	BIT6			bMagic,		/* '000100'B */
	boolean			inv_convention,
	boolean			csum_crc,	/* LRC otherwise */

	uint8_t			bGuardTimeT1,

	CCID_ClockStop		bClockStop
};
type union CCID_ProtocolData {
	CCID_ProtocolData_T0	T0,
	CCID_ProtocolData_T1	T1
};
type record CCID_PC_to_RDR_SetParameters {
	OCT1			bProtocolNum,
	OCT2			abRFU,
	CCID_ProtocolData	abProtocolData
} with { variant (abProtocolData) "CROSSTAG(T0, bProtocolNum = '00'O;
					    T1, bProtocolNum = '01'O)"
};

/* Section 6.1.8 */
type record CCID_PC_to_RDR_Escape {
	OCT3			abRFU,
	octetstring		abData
};

/* Section 6.1.9 */
type enumerated CCID_ClockCommand {
	CCID_CLOCK_CMD_RESTART	('00'H),
	CCID_CLOCK_CMD_STOP	('01'H)
} with { variant "FIELDLENGTH(8)" };
type record CCID_PC_to_RDR_IccClock {
	CCID_ClockCommand	bClockCommand,
	OCT2			abRFU
};

/* Section 6.1.10 */
type record CCID_PC_to_RDR_T0APDU {
	uint8_t			bmChanges,
	uint8_t			bClassGetResponse,
	uint8_t			bClassEnvelope
};

/* Section 6.1.11 */
type record CCID_PC_to_RDR_Secure {
	uint8_t			bBWI,
	u16le_t			wLevelParameter,
	octetstring		abData
};

/* Section 6.1.12 */
type enumerated CCID_MechanicalFunction {
	CCID_MECH_FN_ACCEPT_CARD	('01'H),
	CCID_MECH_FN_EJECT_CARD		('02'H),
	CCID_MECH_FN_CAPTURE_CARD	('03'H),
	CCID_MECH_FN_LOCK_CARD		('04'H),
	CCID_MECH_FN_UNLOCK_CARD	('05'H)
} with { variant "FIELDLENGTH(8)" };
type record CCID_PC_to_RDR_Mechanical {
	CCID_MechanicalFunction	bFunction,
	OCT2			abRFU
};

/* Section 6.1.13 */
type record CCID_PC_to_RDR_Abort {
	OCT3			abRFU
};

/* Section 6.1.14 */
type record CCID_PC_to_RDR_SetRateAndClock {
	OCT3			abRFU,
	u32le_t			dwClockFrequency,
	u32le_t			dwDataRate
};

/***********************************************************************
 * Bulk OUT
 ***********************************************************************/

/* Section 6.2.1 */
type record CCID_RDR_to_PC_DataBlock {
	uint8_t			bChainParameter,
	octetstring		abData
};

/* Section 6.2.2 */
type enumerated CCID_ClockStatus {
	CCID_CLOCK_STATUS_RUNNING	('00'H),
	CCID_CLOCK_STATUS_STOPPED_L	('01'H),
	CCID_CLOCK_STATUS_STOPPED_H	('02'H),
	CCID_CLOCK_STATUS_STOPPED_UNKN	('03'H)
} with { variant "FIELDLENGTH(8)" };
type record CCID_RDR_to_PC_SlotStatus {
	CCID_ClockStatus	bClockStatus
};

/* Section 6.2.3 */
type record CCID_RDR_to_PC_Parameters {
	OCT1			bProtocolNum,
	CCID_ProtocolData	abProtocolData
} with { variant (abProtocolData) "CROSSTAG(T0, bProtocolNum = '00'O;
					    T1, bProtocolNum = '01'O)"
};

/* Section 6.2.4 */
type record CCID_RDR_to_PC_Escape {
	OCT1			bRFU,
	octetstring		abData
};

/* Section 6.2.5 */
type record CCID_RDR_to_PC_DataRateAndClock {
	OCT1			bRFU,
	u32le_t			dwClockFrequency,
	u32le_t			dwDataRate
};

/* Section 6.2.6 */
// FIXME

/***********************************************************************
 * Interrupt IN
 ***********************************************************************/

/* Section 6.3.1 */
type record CCID_RDR_to_PC_NotifySlotChange {
	bitstring		bmSlotCCState
};

/* Section 6.3.2 */
type record CCID_HardwareErrorCode {
	BIT7 bRFU,
	boolean overcurrent
};
type record CCID_RDR_to_PC_HardwareError {
	CCID_HardwareErrorCode	bHardwareErrorCode
};

/***********************************************************************
 * Stitching it together
 ***********************************************************************/

type enumerated CCID_MsgType {
	/* Section 6.1 */
	PC_to_RDR_IccPowerOn			('62'H),
	PC_to_RDR_IccPowerOff			('63'H),
	PC_to_RDR_GetSlotStatus			('65'H),
	PC_to_RDR_XfrBlock			('6f'H),
	PC_to_RDR_GetParameters			('6c'H),
	PC_to_RDR_ResetParameters		('6d'H),
	PC_to_RDR_SetParameters			('61'H),
	PC_to_RDR_Escape			('6B'H),
	PC_to_RDR_IccClock			('6E'H),
	PC_to_RDR_T0APDU			('6A'H),
	PC_to_RDR_Secure			('69'H),
	PC_to_RDR_Mechanical			('71'H),
	PC_to_RDR_Abort				('72'H),
	PC_to_RDR_SetRateAndClock		('73'H),

	/* Section 6.2 */
	RDR_to_PC_DataBlock			('80'H),
	RDR_to_PC_SlotStatus			('81'H),
	RDR_to_PC_Parameters			('82'H),
	RDR_to_PC_Escape			('83'H),
	RDR_to_PC_DataRateAndClock		('84'H),

	/* Section 6.3 */
	RDR_to_PC_NotifySlotChange		('50'H),
	RDR_to_PC_HardwareError			('51'H)
} with { variant "FIELDLENGTH(8)" };

type record CCID_Header {
	CCID_MsgType	bMessageType,
	u32le_t		dwLength,
	uint8_t		bSlot,
	uint8_t		bSeq
};

/* Table 6.2-3 Slot Status Register */
type enumerated CCID_ICC_Status {
	CCID_ICC_STATUS_PRES_ACT		(0),
	CCID_ICC_STATUS_PRES_INACT		(1),
	CCID_ICC_STATUS_NO_ICC			(2),
	CCID_ICC_STATUS_RFU			(3)
} with { variant "FIELDLENGTH(2)" };
type enumerated CCID_CMD_Status {
	CCID_CMD_STATUS_OK			(0),
	CCID_CMD_STATUS_FAILED			(1),
	CCID_CMD_STATUS_TIME_EXT		(2),
	CCID_CMD_STATUS_RFU			(3)
} with { variant "FIELDLENGTH(2)" };
type record CCID_SlotStatus {
	CCID_ICC_Status	bmICCStatus,
	BIT4		RFU,
	CCID_CMD_Status	bmCommandStatus
};

/* Table 6.2-2 Slot erro rregister when bmCommandStatus = 1 */
type enumerated CCID_SlotError {
	CCID_ERR_CMD_ABORTED			('FF'H),
	CCID_ERR_ICC_MUTE			('FE'H),
	CCID_ERR_XFR_PARITY_ERROR		('FD'H),
	CCID_ERR_XFR_OVERRUN			('FC'H),
	CCID_ERR_HW_ERROR			('FB'H),
	CCID_ERR_BAD_ATR_TS			('F8'H),
	CCID_ERR_BAD_ATR_TCK			('F7'H),
	CCID_ERR_ICC_PROTOCOL_NOT_SUPPORTED	('F6'H),
	CCID_ERR_ICC_CLASS_NOT_SUPPORTED	('F5'H),
	CCID_ERR_PROCEDURE_BYTE_CONFLICT	('F4'H),
	CCID_ERR_DEACTIVATED_PROTOCOL		('F3'H),
	CCID_ERR_BUSY_WITH_AUTO_SEQUENCE	('F2'H),
	CCID_ERR_PIN_TIMEOUT			('F0'H),
	CCID_ERR_PIN_CANCELLED			('EF'H),
	CCID_ERR_CMD_SLOT_BUSY			('E0'H),
	CCID_ERR_BAD_WLEVEL_PARAM		(8),		// 6.1.4
	CCID_ERR_BPOWERSELECT_ERROR		(7),		// Table 6.1-2
	CCID_ERR_SLOT_NOT_EXIST			(5),		// Table 6.1-2
	CCID_ERR_BAD_WLENGTH			(1),		// 6.1.4
	CCID_ERR_CMD_NOT_SUPPORTED		('00'H)
} with { variant "FIELDLENGTH(8)" };

type record CCID_Header_IN {
	CCID_SlotStatus			bStatus,
	CCID_SlotError			bError
};

type union CCID_Union {
	CCID_PC_to_RDR_IccPowerOn	IccPowerOn,
	CCID_PC_to_RDR_IccPowerOff	IccPowerOff,
	CCID_PC_to_RDR_GetSlotStatus	GetSlotStatus,
	CCID_PC_to_RDR_XfrBlock		XfrBlock,
	CCID_PC_to_RDR_GetParameters	GetParameters,
	CCID_PC_to_RDR_ResetParameters	ResetParameters,
	CCID_PC_to_RDR_SetParameters	SetParameters,
	CCID_PC_to_RDR_Escape		EscapeOut,
	CCID_PC_to_RDR_IccClock		IccClock,
	CCID_PC_to_RDR_T0APDU		T0APDU,
	CCID_PC_to_RDR_Secure		Secure,
	CCID_PC_to_RDR_Mechanical	Mechanical,
	CCID_PC_to_RDR_Abort		Abort,
	CCID_PC_to_RDR_SetRateAndClock	SetRateAndClock,

	CCID_RDR_to_PC_DataBlock	DataBlock,
	CCID_RDR_to_PC_SlotStatus	SlotStatus,
	CCID_RDR_to_PC_Parameters	Parameters,
	CCID_RDR_to_PC_Escape		EscapeIn,
	CCID_RDR_to_PC_DataRateAndClock	DataRateAndClock,

	CCID_RDR_to_PC_NotifySlotChange	NotifySlotChange,
	CCID_RDR_to_PC_HardwareError	HardwareError
};

type record CCID_PDU {
	CCID_Header		hdr,
	CCID_Header_IN		hdr_in optional,
	CCID_Union		u
} with { variant (hdr_in) "PRESENCE(hdr.bMessageType = RDR_to_PC_DataBlock,
				    hdr.bMessageType = RDR_to_PC_SlotStatus,
				    hdr.bMessageType = RDR_to_PC_Parameters,
				    hdr.bMessageType = RDR_to_PC_Escape,
				    hdr.bMessageType = RDR_to_PC_DataRateAndClock)"
	 variant (u) "CROSSTAG(
				IccPowerOn,		hdr.bMessageType = PC_to_RDR_IccPowerOn;
				IccPowerOff,		hdr.bMessageType = PC_to_RDR_IccPowerOff;
				GetSlotStatus,		hdr.bMessageType = PC_to_RDR_GetSlotStatus;
				XfrBlock,		hdr.bMessageType = PC_to_RDR_XfrBlock;
				GetParameters,		hdr.bMessageType = PC_to_RDR_GetParameters;
				ResetParameters,	hdr.bMessageType = PC_to_RDR_ResetParameters;
				SetParameters,		hdr.bMessageType = PC_to_RDR_SetParameters;
				EscapeOut,		hdr.bMessageType = PC_to_RDR_Escape;
				IccClock,		hdr.bMessageType = PC_to_RDR_IccClock;
				T0APDU,			hdr.bMessageType = PC_to_RDR_T0APDU;
				Secure,			hdr.bMessageType = PC_to_RDR_Secure;
				Mechanical,		hdr.bMessageType = PC_to_RDR_Mechanical;
				Abort,			hdr.bMessageType = PC_to_RDR_Abort;
				SetRateAndClock,	hdr.bMessageType = PC_to_RDR_SetRateAndClock;

				DataBlock,		hdr.bMessageType = RDR_to_PC_DataBlock;
				SlotStatus,		hdr.bMessageType = RDR_to_PC_SlotStatus;
				Parameters,		hdr.bMessageType = RDR_to_PC_Parameters;
				EscapeIn,		hdr.bMessageType = RDR_to_PC_Escape;
				DataRateAndClock,	hdr.bMessageType = RDR_to_PC_DataRateAndClock;

				NotifySlotChange,	hdr.bMessageType = RDR_to_PC_NotifySlotChange;
				HardwareError,		hdr.bMessageType = RDR_to_PC_HardwareError
			)"
};

external function enc_CCID_PDU(in CCID_PDU pdu) return octetstring
with { extension "prototype(convert)"
       extension "encode(RAW)"
     }

external function dec_CCID_PDU(in octetstring stream) return CCID_PDU
with { extension "prototype(convert)"
       extension "decode(RAW)"
     }


} with { encode "RAW"; variant "FIELDORDER(msb)" }
