module CCID_Templates {

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

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

template (value) CCID_Header ts_CCID_Header(CCID_MsgType msgt, uint32_t len := 10, uint8_t slot := 0, uint8_t seq := 0) := {
	bMessageType := msgt,
	dwLength := len,
	bSlot := slot,
	bSeq := seq
}

template (present) CCID_Header tr_CCID_Header(template (present) CCID_MsgType msgt,
					      template (present) uint32_t len := ?,
					      template (present) uint8_t slot := ?,
					      template (present) uint8_t seq := ?) := {
	bMessageType := msgt,
	dwLength := len,
	bSlot := slot,
	bSeq := seq
}


template (value) CCID_PDU ts_CCID_IccPowerOn(uint8_t slot, template (value) CCID_PowerSelect psel, uint8_t seq := 0) := {
	hdr := ts_CCID_Header(PC_to_RDR_IccPowerOn, 0, slot, seq),
	hdr_in := omit,
	u := {
		IccPowerOn := {
			bPowerSelect := psel,
			abRFU := '0000'O
		}
	}
}

template (value) CCID_PDU ts_CCID_IccPowerOff(uint8_t slot, uint8_t seq := 0) := {
	hdr := ts_CCID_Header(PC_to_RDR_IccPowerOff, 0, slot, seq),
	hdr_in := omit,
	u := {
		IccPowerOff := {
			abRFU := '000000'O
		}
	}
}

template (value) CCID_PDU ts_CCID_GetSlotStatus(uint8_t slot, uint8_t seq := 0) := {
	hdr := ts_CCID_Header(PC_to_RDR_GetSlotStatus, 0, slot, seq),
	hdr_in := omit,
	u := {
		GetSlotStatus := {
			abRFU := '000000'O
		}
	}
}

template (value) CCID_PDU ts_CCID_XfrBlock(uint8_t slot, template (value) octetstring data,
					   uint8_t seq := 0, uint8_t bwi := 0, uint16_t level:= 0) := {
	hdr := ts_CCID_Header(PC_to_RDR_XfrBlock, lengthof(data), slot, seq),
	hdr_in := omit,
	u := {
		XfrBlock := {
			bBWI := bwi,
			wLevelParameter := level,
			abData := data
		}
	}
}

template (value) CCID_PDU ts_CCID_GetParameters(uint8_t slot, uint8_t seq := 0) := {
	hdr := ts_CCID_Header(PC_to_RDR_GetParameters, 0, slot, seq),
	hdr_in := omit,
	u := {
		GetParameters := {
			abRFU := '000000'O
		}
	}
}

template (value) CCID_PDU ts_CCID_ResetParameters(uint8_t slot, uint8_t seq := 0) := {
	hdr := ts_CCID_Header(PC_to_RDR_ResetParameters, 0, slot, seq),
	hdr_in := omit,
	u := {
		ResetParameters := {
			abRFU := '000000'O
		}
	}
}

private function get_pdata_size(template (value) CCID_ProtocolData pd) return integer {
	if (ischosen(pd.T0)) {
		return 5;
	} else {
		return 7;
	}
}

private function get_setparam_type(template (value) CCID_ProtocolData pd) return octetstring {
	if (ischosen(pd.T0)) {
		return '00'O;
	} else {
		return '01'O;
	}
}

template (value) CCID_PDU ts_CCID_SetParameters(uint8_t slot, template (value) CCID_ProtocolData pd, uint8_t seq := 0) := {
	hdr := ts_CCID_Header(PC_to_RDR_SetParameters, get_pdata_size(pd), slot, seq),
	hdr_in := omit,
	u := {
		SetParameters := {
			bProtocolNum := get_setparam_type(pd),
			abRFU := '0000'O,
			abProtocolData := pd
		}
	}
}

template (value) CCID_PDU ts_CCID_Escape(uint8_t slot, template (value) octetstring data, uint8_t seq := 0) := {
	hdr := ts_CCID_Header(PC_to_RDR_Escape, lengthof(data), slot, seq),
	hdr_in := omit,
	u := {
		EscapeOut := {
			abRFU := '000000'O,
			abData := data
		}
	}
}

template (value) CCID_PDU ts_CCID_ClockCommand(uint8_t slot, template (value) CCID_ClockCommand cmd,
					       uint8_t seq := 0) := {
	hdr := ts_CCID_Header(PC_to_RDR_IccClock, 0, slot, seq),
	hdr_in := omit,
	u := {
		IccClock := {
			bClockCommand := cmd,
			abRFU := '0000'O
		}
	}
}

template (value) CCID_PDU ts_CCID_T0APDU(uint8_t slot, uint8_t changes, uint8_t get_resp,
					 uint8_t envelope, uint8_t seq := 0) := {
	hdr := ts_CCID_Header(PC_to_RDR_T0APDU, 0, slot, seq),
	hdr_in := omit,
	u := {
		T0APDU := {
			bmChanges := changes,
			bClassGetResponse := get_resp,
			bClassEnvelope := envelope
		}
	}
}

template (value) CCID_PDU ts_CCID_Secure(uint8_t slot, uint8_t bwi, uint16_t level,
					 template (value) octetstring data, uint8_t seq := 0) := {
	hdr := ts_CCID_Header(PC_to_RDR_Secure, lengthof(data), slot, seq),
	hdr_in := omit,
	u := {
		Secure := {
			bBWI := bwi,
			wLevelParameter := level,
			abData := data
		}
	}
}

template (value) CCID_PDU ts_CCID_Mechanical(uint8_t slot, template (value) CCID_MechanicalFunction func,
					     uint8_t seq := 0) := {
	hdr := ts_CCID_Header(PC_to_RDR_Mechanical, 10, slot, seq),
	hdr_in := omit,
	u := {
		Mechanical := {
			bFunction := func,
			abRFU := '0000'O
		}
	}
}

template (value) CCID_PDU ts_CCID_Abort(uint8_t slot, uint8_t seq := 0) := {
	hdr := ts_CCID_Header(PC_to_RDR_Mechanical, 10, slot, seq),
	hdr_in := omit,
	u := {
		Abort := {
			abRFU := '000000'O
		}
	}
}


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

template (present) CCID_Header_IN tr_CCID_HeaderIN(template (present) CCID_ICC_Status icc_status := ?,
						   template (present) CCID_CMD_Status cmd_status := ?,
						   template (present) CCID_SlotError slot_error := ?) := {
	bStatus := {
		bmICCStatus := icc_status,
		RFU := ?,
		bmCommandStatus := cmd_status
	},
	bError := slot_error
}
template (present) CCID_Header_IN
tr_CCID_HeaderIN_OK(template (present) CCID_ICC_Status icc_status := ?) :=
	tr_CCID_HeaderIN(icc_status := icc_status, cmd_status := CCID_CMD_STATUS_OK);

template (present) CCID_Header_IN
tr_CCID_HeaderIN_FAIL(template (present) CCID_SlotError err := ?,
		      template (present) CCID_ICC_Status icc_status := ?) :=
	tr_CCID_HeaderIN(cmd_status := CCID_CMD_STATUS_FAILED, slot_error := err);

template (present) CCID_PDU tr_CCID_DataBlock(template (present) uint8_t slot := ?,
					      template (present) uint9_t seq := ?,
					      template (present) CCID_Header_IN hdr_in := ?,
					      template (present) octetstring data := ?) := {
	hdr := tr_CCID_Header(RDR_to_PC_DataBlock, ?, slot, seq),
	hdr_in := hdr_in,
	u := {
		DataBlock := {
			bChainParameter := ?,
			abData := data
		}
	}
}

template (present) CCID_PDU tr_CCID_SlotStatus(template (present) uint8_t slot := ?,
					       template (present) uint8_t seq := ?,
					       template (present) CCID_Header_IN hdr_in := ?,
					       template (present) CCID_ClockStatus csts := ?) := {
	hdr := tr_CCID_Header(RDR_to_PC_SlotStatus, 0, slot, seq),
	hdr_in := hdr_in,
	u := {
		SlotStatus := {
			bClockStatus := csts
		}
	}
}

template (present) CCID_PDU tr_CCID_Parameters(template (present) uint8_t slot := ?,
						template (present) uint8_t seq := ?,
						template (present) CCID_Header_IN hdr_in := ?,
						template (present) CCID_ProtocolData pd := ?) := {
	hdr := tr_CCID_Header(RDR_to_PC_Parameters, ?, slot, seq),
	hdr_in := hdr_in,
	u := {
		Parameters := {
			bProtocolNum := ?,
			abProtocolData := pd
		}
	}
}

template (present) CCID_PDU tr_CCID_EscapeIN(template (present) uint8_t slot := ?,
					     template (present) uint8_t seq := ?,
					     template (present) CCID_Header_IN hdr_in := ?,
					     template (present) octetstring data := ?) := {
	hdr := tr_CCID_Header(RDR_to_PC_Escape, ?, slot, seq),
	hdr_in := hdr_in,
	u := {
		EscapeIn := {
			bRFU := ?,
			abData := data
		}
	}
}

template (present) CCID_PDU tr_CCID_DataRateAndClock(template (present) uint8_t slot := ?,
						     template (present) uint8_t seq := ?,
						     template (present) CCID_Header_IN hdr_in := ?,
						     template (present) uint32_t clock_freq := ?,
						     template (present) uint32_t data_rate := ?) := {
	hdr := tr_CCID_Header(RDR_to_PC_DataRateAndClock, 8, slot, seq),
	hdr_in := hdr_in,
	u := {
		DataRateAndClock := {
			bRFU := ?,
			dwClockFrequency := clock_freq,
			dwDataRate := data_rate
		}
	}
}


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

template (present) CCID_PDU tr_CCID_NotifySlotChange(template (present) uint8_t slot := ?,
						     template (present) uint8_t seq := ?,
						     template (present) bitstring slot_cc_state := ?) := {
	hdr := tr_CCID_Header(RDR_to_PC_NotifySlotChange, ?, slot, seq),
	hdr_in := ?,
	u := {
		NotifySlotChange := {
			bmSlotCCState := slot_cc_state
		}
	}
}

template (present) CCID_PDU tr_CCID_HardwareError(template (present) uint8_t slot := ?,
						  template (present) uint8_t seq := ?,
						  template (present) CCID_HardwareErrorCode code := ?) := {
	hdr := tr_CCID_Header(RDR_to_PC_HardwareError, ?, slot, seq),
	hdr_in := ?,
	u := {
		HardwareError := {
			bHardwareErrorCode := code
		}
	}
}


}
