Change in osmo-ccid-firmware[master]: make it work, async uart (mode 0x1/0x7 does not matter), requires delay

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Hoernchen gerrit-no-reply at lists.osmocom.org
Tue Nov 26 18:39:10 UTC 2019


Hoernchen has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/16235 )


Change subject: make it work, async uart (mode 0x1/0x7 does not matter), requires delay
......................................................................

make it work, async uart (mode 0x1/0x7 does not matter), requires delay

Change-Id: Ia9d3b099181c24feabdb6a5fddb8db6c44efb72d
---
M ccid_common/ccid_slot_fsm.c
M ccid_common/iso7816_fsm.c
M sysmoOCTSIM/config/hpl_sercom_config.h
M sysmoOCTSIM/cuart_driver_asf4_usart_async.c
M sysmoOCTSIM/driver_init.c
M sysmoOCTSIM/gcc/Makefile
M sysmoOCTSIM/libosmo_emb.c
M sysmoOCTSIM/main.c
M sysmoOCTSIM/talloc.c
M sysmoOCTSIM/usb/class/ccid/device/ccid_df.c
M sysmoOCTSIM/usb_descriptors.c
A sysmoOCTSIM/usb_descriptors.h
12 files changed, 1,055 insertions(+), 762 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-ccid-firmware refs/changes/35/16235/1

diff --git a/ccid_common/ccid_slot_fsm.c b/ccid_common/ccid_slot_fsm.c
index 621bef7..870cf35 100644
--- a/ccid_common/ccid_slot_fsm.c
+++ b/ccid_common/ccid_slot_fsm.c
@@ -80,9 +80,10 @@
 	osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_POWER_UP_IND, NULL);
 	cs->icc_powered = true;
 	card_uart_ctrl(ss->cuart, CUART_CTL_CLOCK, true);
-	usleep(10000);
-	card_uart_ctrl(ss->cuart, CUART_CTL_RST, false);
+	delay_us(10000);
+
 	osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_RESET_REL_IND, NULL);
+	card_uart_ctrl(ss->cuart, CUART_CTL_RST, false);
 
 	msgb_free(msg);
 	/* continues in iso_fsm_clot_user_cb once ATR is received */
@@ -151,8 +152,10 @@
 
 	if (enable) {
 		card_uart_ctrl(ss->cuart, CUART_CTL_POWER, true);
+		cs->icc_powered = true;
 	} else {
 		card_uart_ctrl(ss->cuart, CUART_CTL_POWER, false);
+		cs->icc_powered = false;
 	}
 }
 
@@ -185,31 +188,35 @@
 	return 0;
 }
 
-
+extern void *g_tall_ctx;
 static int iso_fsm_slot_init(struct ccid_slot *cs)
 {
-	void *ctx = NULL; /* FIXME */
+	void *ctx = g_tall_ctx; /* FIXME */
 	struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs);
 	struct card_uart *cuart = talloc_zero(ctx, struct card_uart);
-	char id_buf[16];
-	char *devname = NULL;
+	char id_buf[16] = "SIM0";
+	char devname[] = "foobar";
 	int rc;
 
 	LOGPCS(cs, LOGL_DEBUG, "%s\n", __func__);
 
 	/* HACK: make this in some way configurable so it works both in the firmware
 	 * and on the host (functionfs) */
-	if (cs->slot_nr == 0) {
-		cs->icc_present = true;
-		devname = "/dev/ttyUSB5";
-	}
+//	if (cs->slot_nr == 0) {
+//		cs->icc_present = true;
+//		devname = "/dev/ttyUSB5";
+//	}
+	devname[0] = cs->slot_nr +0x30;
+	devname[1] = 0;
+	//sprintf(devname, "%d", cs->slot_nr);
 
 	if (!cuart)
 		return -ENOMEM;
 
-	snprintf(id_buf, sizeof(id_buf), "SIM%d", cs->slot_nr);
+	//snprintf(id_buf, sizeof(id_buf), "SIM%d", cs->slot_nr);
+	id_buf[3] = cs->slot_nr +0x30;
 	if (devname) {
-		rc = card_uart_open(cuart, "tty", devname);
+		rc = card_uart_open(cuart, "asf4", devname);
 		if (rc < 0) {
 			LOGPCS(cs, LOGL_ERROR, "Cannot open UART %s: %d\n", devname, rc);
 			talloc_free(cuart);
diff --git a/ccid_common/iso7816_fsm.c b/ccid_common/iso7816_fsm.c
index 21378e0..beda7ab 100644
--- a/ccid_common/iso7816_fsm.c
+++ b/ccid_common/iso7816_fsm.c
@@ -633,6 +633,10 @@
 					osmo_fsm_inst_state_chg_ms(fi, ATR_S_WAIT_TCK,
 								   guard_time_ms, T_GUARD);
 					break;
+				} else {
+					/* no TCK present, ATR complete; notify parent */
+					osmo_fsm_inst_state_chg(fi, ATR_S_DONE, 0, 0);
+					osmo_fsm_inst_dispatch(fi->proc.parent, ISO7816_E_ATR_DONE_IND, atp->atr);
 				}
 			} else {
 				break;
diff --git a/sysmoOCTSIM/config/hpl_sercom_config.h b/sysmoOCTSIM/config/hpl_sercom_config.h
index beac040..4526665 100644
--- a/sysmoOCTSIM/config/hpl_sercom_config.h
+++ b/sysmoOCTSIM/config/hpl_sercom_config.h
@@ -52,7 +52,7 @@
 // <i> Number of stop bits in USART frame
 // <id> usart_stop_bit
 #ifndef CONF_SERCOM_0_USART_SBMODE
-#define CONF_SERCOM_0_USART_SBMODE 0
+#define CONF_SERCOM_0_USART_SBMODE 1
 #endif
 
 // <o> Baud rate <1-3000000>
@@ -70,7 +70,7 @@
 // <i> Define ISO7816 protocol type as 0.
 // <id> usart_iso7816_type
 #ifndef CONF_SERCOM_0_USART_ISO7816_PROTOCOL_T
-#define CONF_SERCOM_0_USART_ISO7816_PROTOCOL_T 0x1
+#define CONF_SERCOM_0_USART_ISO7816_PROTOCOL_T 0x0
 #endif
 
 // <o> ISO7816 Inhibit Not Acknowledge
diff --git a/sysmoOCTSIM/cuart_driver_asf4_usart_async.c b/sysmoOCTSIM/cuart_driver_asf4_usart_async.c
index 3be0d65..f9856f3 100644
--- a/sysmoOCTSIM/cuart_driver_asf4_usart_async.c
+++ b/sysmoOCTSIM/cuart_driver_asf4_usart_async.c
@@ -47,6 +47,16 @@
 	card_uart_notification(cuart, CUART_E_TX_COMPLETE, io_descr->tx_buffer);
 }
 
+#include <hpl_usart_async.h>
+#include <hpl_usart_sync.h>
+
+
+static void _SIM_error_cb(const struct usart_async_descriptor *const descr){
+	volatile uint32_t status = hri_sercomusart_read_STATUS_reg(descr->device.hw);
+	volatile uint32_t data = hri_sercomusart_read_DATA_reg(descr->device.hw);
+	volatile uint32_t errrs = hri_sercomusart_read_RXERRCNT_reg(descr->device.hw);
+	OSMO_ASSERT(0 == 1)
+}
 
 /* the below ugli-ness is required as the usart_async_descriptor doesn't have
  * some kind of 'private' member that could provide the call-back anty kind of
@@ -124,6 +134,139 @@
 	SIM4_tx_cb, SIM5_tx_cb, SIM6_tx_cb, SIM7_tx_cb,
 };
 
+#include <math.h>
+#include "atmel_start.h"
+#include "atmel_start_pins.h"
+#include "config/hpl_gclk_config.h"
+#include "iso7816_3.h"
+
+/** possible clock sources for the SERCOM peripheral
+ *  warning: the definition must match the GCLK configuration
+ */
+static const uint8_t sercom_glck_sources[] = {GCLK_PCHCTRL_GEN_GCLK2_Val, GCLK_PCHCTRL_GEN_GCLK4_Val, GCLK_PCHCTRL_GEN_GCLK6_Val};
+
+ /** possible clock frequencies in MHz for the SERCOM peripheral
+  *  warning: the definition must match the GCLK configuration
+  */
+static const double sercom_glck_freqs[] = {100E6 / CONF_GCLK_GEN_2_DIV, 100E6 / CONF_GCLK_GEN_4_DIV, 120E6 / CONF_GCLK_GEN_6_DIV};
+
+/** the GCLK ID for the SERCOM SIM peripherals
+ *  @note: used as index for PCHCTRL
+ */
+static const uint8_t SIM_peripheral_GCLK_ID[] = {SERCOM0_GCLK_ID_CORE, SERCOM1_GCLK_ID_CORE, SERCOM2_GCLK_ID_CORE, SERCOM3_GCLK_ID_CORE, SERCOM4_GCLK_ID_CORE, SERCOM5_GCLK_ID_CORE, SERCOM6_GCLK_ID_CORE, SERCOM7_GCLK_ID_CORE};
+
+
+/** change baud rate of card slot
+ *  @param[in] slotnr slot number for which the baud rate should be set
+ *  @param[in] baudrate baud rate in bps to set
+ *  @return if the baud rate has been set, else a parameter is out of range
+ */
+static bool slot_set_baudrate(uint8_t slotnr, uint32_t baudrate)
+{
+	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
+
+	// calculate the error corresponding to the clock sources
+	uint16_t bauds[ARRAY_SIZE(sercom_glck_freqs)];
+	double errors[ARRAY_SIZE(sercom_glck_freqs)];
+	for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {
+		double freq = sercom_glck_freqs[i]; // remember possible SERCOM frequency
+		uint32_t min = freq/16. *  (1. - 65535. / 65536.); // calculate the minimum baud rate for this frequency
+		uint32_t max = freq/16. *  (1. - 1. / 65536.); // calculate the maximum baud rate for this frequency
+		if (baudrate < min || baudrate > max) { // baud rate it out of supported range
+			errors[i] = NAN;
+		} else {
+			uint16_t baud = round(65536. * (1. - 16. * (baudrate/freq)));
+			bauds[i] = baud;
+			double actual = freq/16. *  (1. - baud / 65536.);
+			errors[i] = fabs(1.0 - (actual / baudrate));
+		}
+	}
+
+	// find the smallest error
+	uint8_t best = ARRAY_SIZE(sercom_glck_freqs);
+	for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {
+		if (isnan(errors[i])) {
+			continue;
+		}
+		if (best >= ARRAY_SIZE(sercom_glck_freqs)) {
+			best = i;
+		} else if (errors[i] < errors[best]) {
+			best = i;
+		}
+	}
+	if (best >= ARRAY_SIZE(sercom_glck_freqs)) { // found no clock supporting this baud rate
+		return false;
+	}
+
+	// set clock and baud rate
+	struct usart_async_descriptor* slot = SIM_peripheral_descriptors[slotnr]; // get slot
+	if (NULL == slot) {
+		return false;
+	}
+	printf("(%u) switching SERCOM clock to GCLK%u (freq = %lu kHz) and baud rate to %lu bps (baud = %u)\r\n", slotnr, (best + 1) * 2, (uint32_t)(round(sercom_glck_freqs[best] / 1000)), baudrate, bauds[best]);
+	while (!usart_async_is_tx_empty(slot)); // wait for transmission to complete (WARNING no timeout)
+	usart_async_disable(slot); // disable SERCOM peripheral
+	hri_gclk_clear_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos)); // disable clock for this peripheral
+	while (hri_gclk_get_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos))); // wait until clock is really disabled
+	// it does not seem we need to completely disable the peripheral using hri_mclk_clear_APBDMASK_SERCOMn_bit
+	hri_gclk_write_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], sercom_glck_sources[best] | (1 << GCLK_PCHCTRL_CHEN_Pos)); // set peripheral core clock and re-enable it
+	usart_async_set_baud_rate(slot, bauds[best]); // set the new baud rate
+	usart_async_enable(slot); // re-enable SERCOM peripheral
+
+	return true;
+}
+
+/** change ISO baud rate of card slot
+ *  @param[in] slotnr slot number for which the baud rate should be set
+ *  @param[in] clkdiv can clock divider
+ *  @param[in] f clock rate conversion integer F
+ *  @param[in] d baud rate adjustment factor D
+ *  @return if the baud rate has been set, else a parameter is out of range
+ */
+static bool slot_set_isorate(uint8_t slotnr, enum ncn8025_sim_clkdiv clkdiv, uint16_t f, uint8_t d)
+{
+	// input checks
+	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
+	if (clkdiv != SIM_CLKDIV_1 && clkdiv != SIM_CLKDIV_2 && clkdiv != SIM_CLKDIV_4 && clkdiv != SIM_CLKDIV_8) {
+		return false;
+	}
+	if (!iso7816_3_valid_f(f)) {
+		return false;
+	}
+	if (!iso7816_3_valid_d(d)) {
+		return false;
+	}
+
+	// set clockdiv
+	struct ncn8025_settings settings;
+	ncn8025_get(slotnr, &settings);
+	if (settings.clkdiv != clkdiv) {
+		settings.clkdiv = clkdiv;
+		ncn8025_set(slotnr, &settings);
+	}
+
+	// calculate desired frequency
+	uint32_t freq = 20000000UL; // maximum frequency
+	switch (clkdiv) {
+	case SIM_CLKDIV_1:
+		freq /= 1;
+		break;
+	case SIM_CLKDIV_2:
+		freq /= 2;
+		break;
+	case SIM_CLKDIV_4:
+		freq /= 4;
+		break;
+	case SIM_CLKDIV_8:
+		freq /= 8;
+		break;
+	}
+
+	// set baud rate
+	uint32_t baudrate = (freq * d) / f; // calculate actual baud rate
+	return slot_set_baudrate(slotnr, baudrate); // set baud rate
+}
+
 /***********************************************************************
  * Interface with card_uart (cuart) core
  ***********************************************************************/
@@ -146,10 +289,15 @@
 	cuart->u.asf4.usa_pd = usa_pd;
 	cuart->u.asf4.slot_nr = slot_nr;
 
+
 	usart_async_register_callback(usa_pd, USART_ASYNC_RXC_CB, SIM_rx_cb[slot_nr]);
 	usart_async_register_callback(usa_pd, USART_ASYNC_TXC_CB, SIM_tx_cb[slot_nr]);
+	usart_async_register_callback(usa_pd, USART_ASYNC_ERROR_CB, _SIM_error_cb);
 	usart_async_enable(usa_pd);
 
+	// set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1)
+	slot_set_isorate(cuart->u.asf4.slot_nr, SIM_CLKDIV_8, ISO7816_3_DEFAULT_FD, ISO7816_3_DEFAULT_DD);
+
         return 0;
 }
 
@@ -197,19 +345,31 @@
 
 	switch (ctl) {
 	case CUART_CTL_RX:
-		if (arg)
+		if (arg){
 			sercom->USART.CTRLB.bit.RXEN = 1;
-		else
+			sercom->USART.CTRLB.bit.TXEN = 0;
+		} else {
+			delay_us(100);
 			sercom->USART.CTRLB.bit.RXEN = 0;
+			sercom->USART.CTRLB.bit.TXEN = 1;
+		}
 		break;
 	case CUART_CTL_RST:
 		ncn8025_get(cuart->u.asf4.slot_nr, &settings);
 		settings.rstin = arg ? true : false;
 		ncn8025_set(cuart->u.asf4.slot_nr, &settings);
+		usart_async_flush_rx_buffer(cuart->u.asf4.usa_pd);
 		break;
 	case CUART_CTL_POWER:
 		ncn8025_get(cuart->u.asf4.slot_nr, &settings);
 		settings.cmdvcc = arg ? true : false;
+		settings.led = arg ? true : false;
+		settings.vsel = SIM_VOLT_5V0;
+
+		// set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1)
+		if(arg)
+			slot_set_isorate(cuart->u.asf4.slot_nr, SIM_CLKDIV_8, ISO7816_3_DEFAULT_FD, ISO7816_3_DEFAULT_DD);
+
 		ncn8025_set(cuart->u.asf4.slot_nr, &settings);
 		break;
 	case CUART_CTL_WTIME:
diff --git a/sysmoOCTSIM/driver_init.c b/sysmoOCTSIM/driver_init.c
index 620ed6c..c373dc2 100644
--- a/sysmoOCTSIM/driver_init.c
+++ b/sysmoOCTSIM/driver_init.c
@@ -12,25 +12,25 @@
 #include <hal_init.h>
 
 /*! The buffer size for USART */
-#define SIM0_BUFFER_SIZE 16
+#define SIM0_BUFFER_SIZE 512
 
 /*! The buffer size for USART */
-#define SIM1_BUFFER_SIZE 16
+#define SIM1_BUFFER_SIZE 512
 
 /*! The buffer size for USART */
-#define SIM2_BUFFER_SIZE 16
+#define SIM2_BUFFER_SIZE 512
 
 /*! The buffer size for USART */
-#define SIM3_BUFFER_SIZE 16
+#define SIM3_BUFFER_SIZE 512
 
 /*! The buffer size for USART */
-#define SIM4_BUFFER_SIZE 16
+#define SIM4_BUFFER_SIZE 512
 
 /*! The buffer size for USART */
-#define SIM5_BUFFER_SIZE 16
+#define SIM5_BUFFER_SIZE 512
 
 /*! The buffer size for USART */
-#define SIM6_BUFFER_SIZE 16
+#define SIM6_BUFFER_SIZE 512
 
 /*! The buffer size for USART */
 #define UART_DEBUG_BUFFER_SIZE 256
diff --git a/sysmoOCTSIM/gcc/Makefile b/sysmoOCTSIM/gcc/Makefile
index 4840fea..9873159 100644
--- a/sysmoOCTSIM/gcc/Makefile
+++ b/sysmoOCTSIM/gcc/Makefile
@@ -8,7 +8,7 @@
 CROSS_COMPILE= arm-none-eabi-
 
 CFLAGS_CPU=-D__SAME54N19A__ -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16
-CFLAGS=-x c -mthumb -DDEBUG -Os -ffunction-sections -fdata-sections -mlong-calls \
+CFLAGS=-x c -mthumb -DDEBUG -O0 -ffunction-sections -fdata-sections -mlong-calls \
        -g3 -Wall -c -std=gnu99 $(CFLAGS_CPU)
 
 CC = $(CROSS_COMPILE)gcc
diff --git a/sysmoOCTSIM/libosmo_emb.c b/sysmoOCTSIM/libosmo_emb.c
index 1914568..5209e20 100644
--- a/sysmoOCTSIM/libosmo_emb.c
+++ b/sysmoOCTSIM/libosmo_emb.c
@@ -157,8 +157,8 @@
 	/* logging */
 	log_init(&log_info, g_tall_ctx);
 	stderr_target = log_target_create_stderr_raw();
-	log_add_target(stderr_target);
-	log_set_all_filter(stderr_target, 1);
+	//log_add_target(stderr_target);
+	//log_set_all_filter(stderr_target, 1);
 
 	/* timer */
 	SysTick_Config(SystemCoreClock / 1000);
diff --git a/sysmoOCTSIM/main.c b/sysmoOCTSIM/main.c
index 15e2004..e27e3dd 100644
--- a/sysmoOCTSIM/main.c
+++ b/sysmoOCTSIM/main.c
@@ -40,46 +40,51 @@
 
 #include "command.h"
 
-// TODO put declaration in more global file
-// TODO for now SIM7 is not present because used for debug
-static struct usart_async_descriptor* SIM_peripheral_descriptors[] = {&SIM0, &SIM1, &SIM2, &SIM3, &SIM4, &SIM5, &SIM6, NULL};
+#include "ccid_device.h"
+#include "usb_descriptors.h"
+extern struct ccid_slot_ops iso_fsm_slot_ops;
+static struct ccid_instance g_ci;
 
-/** number of bytes transmitted on the SIM peripheral */
-static volatile bool SIM_tx_count[8];
+//// TODO put declaration in more global file
+//// TODO for now SIM7 is not present because used for debug
+//static struct usart_async_descriptor* SIM_peripheral_descriptors[] = {&SIM0, &SIM1, &SIM2, &SIM3, &SIM4, &SIM5, &SIM6, NULL};
+//
+///** number of bytes transmitted on the SIM peripheral */
+//static volatile bool SIM_tx_count[8];
+//
+//static void SIM_rx_cb(const struct usart_async_descriptor *const io_descr)
+//{
+//}
+//
+///** called when the transmission is complete
+// *  e.g. this is when the byte has been sent and there is no data to transmit anymore
+// */
+//static void SIM_tx_cb(const struct usart_async_descriptor *const io_descr)
+//{
+//	// find slotnr for corresponding USART
+//	uint8_t slotnr;
+//	for (slotnr = 0; slotnr < ARRAY_SIZE(SIM_peripheral_descriptors) && SIM_peripheral_descriptors[slotnr] != io_descr; slotnr++);
+//
+//	// set flag
+//	if (slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)) {
+//		SIM_tx_count[slotnr] = true;
+//	}
+//}
 
-static void SIM_rx_cb(const struct usart_async_descriptor *const io_descr)
-{
-}
-
-/** called when the transmission is complete
- *  e.g. this is when the byte has been sent and there is no data to transmit anymore
- */
-static void SIM_tx_cb(const struct usart_async_descriptor *const io_descr)
-{
-	// find slotnr for corresponding USART
-	uint8_t slotnr;
-	for (slotnr = 0; slotnr < ARRAY_SIZE(SIM_peripheral_descriptors) && SIM_peripheral_descriptors[slotnr] != io_descr; slotnr++);
-
-	// set flag
-	if (slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)) {
-		SIM_tx_count[slotnr] = true;
-	}
-}
-
-/** possible clock sources for the SERCOM peripheral
- *  warning: the definition must match the GCLK configuration
- */
-static const uint8_t sercom_glck_sources[] = {GCLK_PCHCTRL_GEN_GCLK2_Val, GCLK_PCHCTRL_GEN_GCLK4_Val, GCLK_PCHCTRL_GEN_GCLK6_Val};
-
-/** possible clock frequencies in MHz for the SERCOM peripheral
- *  warning: the definition must match the GCLK configuration
- */
-static const double sercom_glck_freqs[] = {100E6 / CONF_GCLK_GEN_2_DIV, 100E6 / CONF_GCLK_GEN_4_DIV, 120E6 / CONF_GCLK_GEN_6_DIV};
-
-/** the GCLK ID for the SERCOM SIM peripherals
- *  @note: used as index for PCHCTRL
- */
-static const uint8_t SIM_peripheral_GCLK_ID[] = {SERCOM0_GCLK_ID_CORE, SERCOM1_GCLK_ID_CORE, SERCOM2_GCLK_ID_CORE, SERCOM3_GCLK_ID_CORE, SERCOM4_GCLK_ID_CORE, SERCOM5_GCLK_ID_CORE, SERCOM6_GCLK_ID_CORE, SERCOM7_GCLK_ID_CORE};
+///** possible clock sources for the SERCOM peripheral
+// *  warning: the definition must match the GCLK configuration
+// */
+//static const uint8_t sercom_glck_sources[] = {GCLK_PCHCTRL_GEN_GCLK2_Val, GCLK_PCHCTRL_GEN_GCLK4_Val, GCLK_PCHCTRL_GEN_GCLK6_Val};
+//
+///** possible clock frequencies in MHz for the SERCOM peripheral
+// *  warning: the definition must match the GCLK configuration
+// */
+//static const double sercom_glck_freqs[] = {100E6 / CONF_GCLK_GEN_2_DIV, 100E6 / CONF_GCLK_GEN_4_DIV, 120E6 / CONF_GCLK_GEN_6_DIV};
+//
+///** the GCLK ID for the SERCOM SIM peripherals
+// *  @note: used as index for PCHCTRL
+// */
+//static const uint8_t SIM_peripheral_GCLK_ID[] = {SERCOM0_GCLK_ID_CORE, SERCOM1_GCLK_ID_CORE, SERCOM2_GCLK_ID_CORE, SERCOM3_GCLK_ID_CORE, SERCOM4_GCLK_ID_CORE, SERCOM5_GCLK_ID_CORE, SERCOM6_GCLK_ID_CORE, SERCOM7_GCLK_ID_CORE};
 
 static void ccid_app_init(void);
 
@@ -101,15 +106,15 @@
 	 * (there are 8 inputs + traces to drive!) */
 	hri_port_set_PINCFG_DRVSTR_bit(PORT, 0, 11);
 
-	// enable SIM interfaces
-	for (uint8_t i = 0; i < ARRAY_SIZE(SIM_peripheral_descriptors); i++) {
-		if (NULL == SIM_peripheral_descriptors[i]) {
-			continue;
-		}
-		usart_async_register_callback(SIM_peripheral_descriptors[i], USART_ASYNC_RXC_CB, SIM_rx_cb); // required for RX to work, even if the callback does nothing
-		usart_async_register_callback(SIM_peripheral_descriptors[i], USART_ASYNC_TXC_CB, SIM_tx_cb); // to count the number of bytes transmitted since we are using it asynchronously
-		usart_async_enable(SIM_peripheral_descriptors[i]);
-	}
+//	// enable SIM interfaces
+//	for (uint8_t i = 0; i < ARRAY_SIZE(SIM_peripheral_descriptors); i++) {
+//		if (NULL == SIM_peripheral_descriptors[i]) {
+//			continue;
+//		}
+//		usart_async_register_callback(SIM_peripheral_descriptors[i], USART_ASYNC_RXC_CB, SIM_rx_cb); // required for RX to work, even if the callback does nothing
+//		usart_async_register_callback(SIM_peripheral_descriptors[i], USART_ASYNC_TXC_CB, SIM_tx_cb); // to count the number of bytes transmitted since we are using it asynchronously
+//		usart_async_enable(SIM_peripheral_descriptors[i]);
+//	}
 
 	ccid_app_init();
 }
@@ -199,7 +204,9 @@
 	struct msgb *msg;
 	int rc;
 
-	OSMO_ASSERT(!ep_q->in_progress);
+	if (ep_q->in_progress)
+		return 0;
+
 	msg = msgb_dequeue_irqsafe(&ep_q->list);
 	if (!msg)
 		return 0;
@@ -248,6 +255,7 @@
 	msg = msgb_dequeue_irqsafe(&g_ccid_s.free_q);
 	if (!msg)
 		return -1;
+	msgb_reset(msg);
 	ep_q->in_progress = msg;
 
 	rc = ccid_df_read_out(msgb_data(msg), msgb_tailroom(msg));
@@ -270,6 +278,7 @@
 	msgb_put(msg, transferred);
 	/* append to list of pending-to-be-handed messages */
 	llist_add_tail_at(&msg->list, &g_ccid_s.out_ep.list);
+	g_ccid_s.out_ep.in_progress = NULL;
 
 	/* submit another [free] msgb to receive the next transfer */
 	submit_next_out();
@@ -341,8 +350,11 @@
 	struct msgb *msg;
 	unsigned int i;
 
-	for (i = 0; i < 8; i++)
-		new_mask |= ncn8025_interrupt_level(i) << i;
+	for (i = 0; i < 8; i++){
+		bool level = ncn8025_interrupt_level(i);
+		new_mask |= level << i;
+		g_ci.slot[i].icc_present = level;
+	}
 
 	/* notify the user/host about any changes */
 	if (g_ccid_s.card_insert_mask != new_mask) {
@@ -375,614 +387,614 @@
 	}
 	return slotnr;
 }
+//
+///** change baud rate of card slot
+// *  @param[in] slotnr slot number for which the baud rate should be set
+// *  @param[in] baudrate baud rate in bps to set
+// *  @return if the baud rate has been set, else a parameter is out of range
+// */
+//static bool slot_set_baudrate(uint8_t slotnr, uint32_t baudrate)
+//{
+//	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
+//
+//	// calculate the error corresponding to the clock sources
+//	uint16_t bauds[ARRAY_SIZE(sercom_glck_freqs)];
+//	double errors[ARRAY_SIZE(sercom_glck_freqs)];
+//	for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {
+//		double freq = sercom_glck_freqs[i]; // remember possible SERCOM frequency
+//		uint32_t min = freq / (2 * (255 + 1)); // calculate the minimum baud rate for this frequency
+//		uint32_t max = freq / (2 * (0 + 1)); // calculate the maximum baud rate for this frequency
+//		if (baudrate < min || baudrate > max) { // baud rate it out of supported range
+//			errors[i] = NAN;
+//		} else {
+//			uint16_t baud = round(freq / (2 * baudrate) - 1);
+//			bauds[i] = baud;
+//			double actual = freq / (2 * (baud + 1));
+//			errors[i] = fabs(1.0 - (actual / baudrate));
+//		}
+//	}
+//
+//	// find the smallest error
+//	uint8_t best = ARRAY_SIZE(sercom_glck_freqs);
+//	for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {
+//		if (isnan(errors[i])) {
+//			continue;
+//		}
+//		if (best >= ARRAY_SIZE(sercom_glck_freqs)) {
+//			best = i;
+//		} else if (errors[i] < errors[best]) {
+//			best = i;
+//		}
+//	}
+//	if (best >= ARRAY_SIZE(sercom_glck_freqs)) { // found no clock supporting this baud rate
+//		return false;
+//	}
+//
+//	// set clock and baud rate
+//	struct usart_async_descriptor* slot = SIM_peripheral_descriptors[slotnr]; // get slot
+//	if (NULL == slot) {
+//		return false;
+//	}
+//	printf("(%u) switching SERCOM clock to GCLK%u (freq = %lu kHz) and baud rate to %lu bps (baud = %u)\r\n", slotnr, (best + 1) * 2, (uint32_t)(round(sercom_glck_freqs[best] / 1000)), baudrate, bauds[best]);
+//	while (!usart_async_is_tx_empty(slot)); // wait for transmission to complete (WARNING no timeout)
+//	usart_async_disable(slot); // disable SERCOM peripheral
+//	hri_gclk_clear_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos)); // disable clock for this peripheral
+//	while (hri_gclk_get_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos))); // wait until clock is really disabled
+//	// it does not seem we need to completely disable the peripheral using hri_mclk_clear_APBDMASK_SERCOMn_bit
+//	hri_gclk_write_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], sercom_glck_sources[best] | (1 << GCLK_PCHCTRL_CHEN_Pos)); // set peripheral core clock and re-enable it
+//	usart_async_set_baud_rate(slot, bauds[best]); // set the new baud rate
+//	usart_async_enable(slot); // re-enable SERCOM peripheral
+//
+//	return true;
+//}
+//
+///** change ISO baud rate of card slot
+// *  @param[in] slotnr slot number for which the baud rate should be set
+// *  @param[in] clkdiv can clock divider
+// *  @param[in] f clock rate conversion integer F
+// *  @param[in] d baud rate adjustment factor D
+// *  @return if the baud rate has been set, else a parameter is out of range
+// */
+//static bool slot_set_isorate(uint8_t slotnr, enum ncn8025_sim_clkdiv clkdiv, uint16_t f, uint8_t d)
+//{
+//	// input checks
+//	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
+//	if (clkdiv != SIM_CLKDIV_1 && clkdiv != SIM_CLKDIV_2 && clkdiv != SIM_CLKDIV_4 && clkdiv != SIM_CLKDIV_8) {
+//		return false;
+//	}
+//	if (!iso7816_3_valid_f(f)) {
+//		return false;
+//	}
+//	if (!iso7816_3_valid_d(d)) {
+//		return false;
+//	}
+//
+//	// set clockdiv
+//	struct ncn8025_settings settings;
+//	ncn8025_get(slotnr, &settings);
+//	if (settings.clkdiv != clkdiv) {
+//		settings.clkdiv = clkdiv;
+//		ncn8025_set(slotnr, &settings);
+//	}
+//
+//	// calculate desired frequency
+//	uint32_t freq = 20000000UL; // maximum frequency
+//	switch (clkdiv) {
+//	case SIM_CLKDIV_1:
+//		freq /= 1;
+//		break;
+//	case SIM_CLKDIV_2:
+//		freq /= 2;
+//		break;
+//	case SIM_CLKDIV_4:
+//		freq /= 4;
+//		break;
+//	case SIM_CLKDIV_8:
+//		freq /= 8;
+//		break;
+//	}
+//
+//	// set baud rate
+//	uint32_t baudrate = (freq * d) / f; // calculate actual baud rate
+//	return slot_set_baudrate(slotnr, baudrate); // set baud rate
+//}
+//
+///** write data to card
+// *  @param[in] slotnr slot number on which to send data
+// *  @param[in] data data to be transmitted
+// *  @param[in] length length of data to be transmitted
+// *  @return error code
+// */
+//static int slot_card_write(uint8_t slotnr, const uint8_t* data, uint16_t length)
+//{
+//	// input checks
+//	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
+//	if (0 == length || NULL == data) {
+//		return ERR_INVALID_ARG;
+//	}
+//
+//	struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr];
+//	((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 0; // disable receive (to avoid the echo back)
+//	SIM_tx_count[slotnr] = false; // reset TX complete
+//	for (uint16_t i = 0; i < length; i++) { // transmit data
+//		while(!usart_async_is_tx_empty(sim)); // wait for previous byte to be transmitted (WARNING blocking)
+//		if (1 != io_write(&sim->io, &data[i], 1)) { // put but in transmit buffer
+//			return ERR_IO;
+//		}
+//	}
+//	while (!SIM_tx_count[slotnr]); // wait until transmission is complete (WARNING blocking)
+//	((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1; // enable receive again
+//
+//	return ERR_NONE;
+//}
+//
+///** read data from card
+// *  @param[in] slotnr slot number on which to send data
+// *  @param[out] data buffer for read data to be stored
+// *  @param[in] length length of data to be read
+// *  @param[in] wt Waiting Time in ETU
+// *  @return error code
+// *  TODO fix WT/ETU duration
+// */
+//static int slot_card_read(uint8_t slotnr, uint8_t* data, uint16_t length, uint32_t wt)
+//{
+//	// input checks
+//	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
+//	if (0 == length || NULL == data) {
+//		return ERR_INVALID_ARG;
+//	}
+//
+//	struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr];
+//
+//	((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1; // ensure RX is enabled
+//	uint32_t timeout = wt; // reset waiting time
+//	for (uint16_t i = 0; i < length; i++) { // read all data
+//		while (timeout && !usart_async_is_rx_not_empty(sim)) { // verify if data is present
+//			delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
+//			timeout--;
+//		}
+//		if (0 == timeout) { // timeout reached
+//			return ERR_TIMEOUT;
+//		}
+//		timeout = wt; // reset waiting time
+//		if (1 != io_read(&sim->io, &data[i], 1)) { // read one byte
+//			return ERR_IO;
+//		}
+//	}
+//
+//	return ERR_NONE;
+//}
+//
+///** transfer TPDU
+// *  @param[in] slotnr slot number on which to transfer the TPDU
+// *  @param[in] header TPDU header to send
+// *  @param[io] data TPDU data to transfer
+// *  @param[in] data_length length of TPDU data to transfer
+// *  @param[in] write if the data should be written (true) or read (false)
+// * TODO fix WT
+// * TODO the data length can be deduce from the header
+// */
+//static int slot_tpdu_xfer(uint8_t slotnr, const uint8_t* header, uint8_t* data, uint16_t data_length, bool write)
+//{
+//	// input checks
+//	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
+//	if (NULL == header || (data_length > 0 && NULL == data)) {
+//		return ERR_INVALID_ARG;
+//	}
+//
+//	int rc;
+//	struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr]; // get USART peripheral
+//	usart_async_flush_rx_buffer(sim); // flush RX buffer to start from scratch
+//
+//	// send command header
+//	printf("(%d) TPDU: ", slotnr);
+//	for (uint8_t i = 0; i < 5; i++) {
+//		printf("%02x ", header[i]);
+//	}
+//	rc = slot_card_write(slotnr, header, 5); // transmit header
+//	if (ERR_NONE != rc) {
+//		printf("error in command header transmit (errno = %d)\r\n", rc);
+//		return rc;
+//	}
+//
+//	// read procedure byte, and handle data
+//	uint8_t pb = 0x60; // wait more procedure byte
+//	uint16_t data_i = 0; // progress in the data transfer
+//	while (0x60 == pb) { // wait for SW
+//		rc = slot_card_read(slotnr, &pb, 1, ISO7816_3_DEFAULT_WT);
+//		if (ERR_NONE != rc) {
+//			printf("error while receiving PB/SW1 (errno = %d)\r\n", rc);
+//			return rc;
+//		}
+//		printf("%02x ", pb);
+//		if (0x60 == pb) { // NULL byte
+//			// just wait more time
+//		} else if ((0x60 == (pb & 0xf0)) || (0x90 == (pb & 0xf0))) { // SW1 byte
+//			// left the rest of the code handle it
+//		} else if (header[1] == pb) { // ACK byte
+//			// transfer rest of the data
+//			if (data_i >= data_length) {
+//				printf("error no more data to transfer\r\n");
+//				return ERR_INVALID_DATA;
+//			}
+//			if (write) { // transmit remaining command data
+//				rc = slot_card_write(slotnr, &data[data_i], data_length - data_i); // transmit command data
+//				if (ERR_NONE != rc) {
+//					printf("error in command data transmit (errno = %d)\r\n", rc);
+//					return rc;
+//				}
+//			} else { // receive remaining command data
+//				rc = slot_card_read(slotnr, &data[data_i], data_length - data_i, ISO7816_3_DEFAULT_WT);
+//				if (ERR_NONE != rc) {
+//					printf("error in command data receive (errno = %d)\r\n", rc);
+//					return rc;
+//				}
+//			}
+//			for (uint16_t i = data_i; i < data_length; i++) {
+//				printf("%02x ", data[i]);
+//			}
+//			data_i = data_length; // remember we transferred the data
+//			pb = 0x60; // wait for SW1
+//		} else if (header[1] == (pb ^ 0xff)) { // ACK byte
+//			// transfer only one byte
+//			if (data_i >= data_length) {
+//				printf("error no more data to transfer\r\n");
+//				return ERR_INVALID_DATA;
+//			}
+//			if (write) { // transmit command data byte
+//				rc = slot_card_write(slotnr, &data[data_i], 1); // transmit command data
+//				if (ERR_NONE != rc) {
+//					printf("error in command data transmit (errno = %d)\r\n", rc);
+//					return rc;
+//				}
+//			} else { // receive command data byte
+//				rc = slot_card_read(slotnr, &data[data_i], 1, ISO7816_3_DEFAULT_WT);
+//				if (ERR_NONE != rc) {
+//					printf("error in command data receive (errno = %d)\r\n", rc);
+//					return rc;
+//				}
+//			}
+//			printf("%02x ", data[data_i]);
+//			data_i += 1; // remember we transferred one data byte
+//			pb = 0x60; // wait for SW1
+//		} else { // invalid byte
+//			return ERR_INVALID_DATA;
+//		}
+//	}
+//
+//	// read SW2
+//	uint8_t sw2;
+//	rc = slot_card_read(slotnr, &sw2, 1, ISO7816_3_DEFAULT_WT);
+//	if (ERR_NONE != rc) {
+//		printf("error in receiving SW2 (errno = %d)\r\n", rc);
+//		return rc;
+//	}
+//	printf("%02x", sw2);
+//
+//	printf("\r\n");
+//	return ERR_NONE;
+//}
+//
+//DEFUN(sim_status, cmd_sim_status, "sim-status", "Get state of specified NCN8025")
+//{
+//	struct ncn8025_settings settings;
+//	int slotnr = validate_slotnr(argc, argv, 1);
+//	if (slotnr < 0)
+//		return;
+//	ncn8025_get(slotnr, &settings);
+//	printf("SIM%d: ", slotnr);
+//	ncn8025_dump(&settings);
+//	printf("\r\n");
+//}
+//
+//DEFUN(sim_power, cmd_sim_power, "sim-power", "Enable/disable SIM card power")
+//{
+//	struct ncn8025_settings settings;
+//	int slotnr = validate_slotnr(argc, argv, 1);
+//	int enable;
+//
+//	if (slotnr < 0)
+//		return;
+//
+//	if (argc < 3) {
+//		printf("You have to specify 0=disable or 1=enable\r\n");
+//		return;
+//	}
+//	enable = atoi(argv[2]);
+//	ncn8025_get(slotnr, &settings);
+//	if (enable)
+//		settings.cmdvcc = true;
+//	else
+//		settings.cmdvcc = false;
+//	ncn8025_set(slotnr, &settings);
+//}
+//
+//DEFUN(sim_reset, cmd_sim_reset, "sim-reset", "Enable/disable SIM reset")
+//{
+//	struct ncn8025_settings settings;
+//	int slotnr = validate_slotnr(argc, argv, 1);
+//	int enable;
+//
+//	if (slotnr < 0)
+//		return;
+//
+//	if (argc < 3) {
+//		printf("You have to specify 0=disable or 1=enable\r\n");
+//		return;
+//	}
+//	enable = atoi(argv[2]);
+//	ncn8025_get(slotnr, &settings);
+//	if (enable)
+//		settings.rstin = true;
+//	else
+//		settings.rstin = false;
+//	ncn8025_set(slotnr, &settings);
+//}
+//
+//DEFUN(sim_clkdiv, cmd_sim_clkdiv, "sim-clkdiv", "Set SIM clock divider (1,2,4,8)")
+//{
+//	struct ncn8025_settings settings;
+//	int slotnr = validate_slotnr(argc, argv, 1);
+//	int clkdiv;
+//
+//	if (slotnr < 0)
+//		return;
+//
+//	if (argc < 3) {
+//		printf("You have to specify a valid divider (1,2,4,8)\r\n");
+//		return;
+//	}
+//	clkdiv = atoi(argv[2]);
+//	if (clkdiv != 1 && clkdiv != 2 && clkdiv != 4 && clkdiv != 8) {
+//		printf("You have to specify a valid divider (1,2,4,8)\r\n");
+//		return;
+//	}
+//	ncn8025_get(slotnr, &settings);
+//	switch (clkdiv) {
+//	case 1:
+//		settings.clkdiv = SIM_CLKDIV_1;
+//		break;
+//	case 2:
+//		settings.clkdiv = SIM_CLKDIV_2;
+//		break;
+//	case 4:
+//		settings.clkdiv = SIM_CLKDIV_4;
+//		break;
+//	case 8:
+//		settings.clkdiv = SIM_CLKDIV_8;
+//		break;
+//	}
+//	ncn8025_set(slotnr, &settings);
+//}
+//
+//DEFUN(sim_voltage, cmd_sim_voltage, "sim-voltage", "Set SIM voltage (5/3/1.8)")
+//{
+//	struct ncn8025_settings settings;
+//	int slotnr = validate_slotnr(argc, argv, 1);
+//
+//	if (slotnr < 0)
+//		return;
+//
+//	if (argc < 3) {
+//		printf("You have to specify a valid voltage (5/3/1.8)\r\n");
+//		return;
+//	}
+//	ncn8025_get(slotnr, &settings);
+//	if (!strcmp(argv[2], "5"))
+//		settings.vsel = SIM_VOLT_5V0;
+//	else if (!strcmp(argv[2], "3"))
+//		settings.vsel = SIM_VOLT_3V0;
+//	else if (!strcmp(argv[2], "1.8"))
+//		settings.vsel = SIM_VOLT_1V8;
+//	else {
+//		printf("You have to specify a valid voltage (5/3/1.8)\r\n");
+//		return;
+//	}
+//	ncn8025_set(slotnr, &settings);
+//}
+//
+//DEFUN(sim_led, cmd_sim_led, "sim-led", "Set SIM LED (1=on, 0=off)")
+//{
+//	struct ncn8025_settings settings;
+//	int slotnr = validate_slotnr(argc, argv, 1);
+//
+//	if (slotnr < 0)
+//		return;
+//
+//	if (argc < 3) {
+//		printf("You have to specify 0=disable or 1=enable\r\n");
+//		return;
+//	}
+//	ncn8025_get(slotnr, &settings);
+//	if (atoi(argv[2]))
+//		settings.led = true;
+//	else
+//		settings.led = false;
+//	ncn8025_set(slotnr, &settings);
+//}
+//
+//DEFUN(sim_atr, cmd_sim_atr, "sim-atr", "Read ATR from SIM card")
+//{
+//	struct ncn8025_settings settings;
+//	int slotnr = validate_slotnr(argc, argv, 1);
+//
+//	if (slotnr < 0 || slotnr >= ARRAY_SIZE(SIM_peripheral_descriptors) || NULL == SIM_peripheral_descriptors[slotnr]) {
+//		return;
+//	}
+//
+//	// check if card is present (and read current settings)
+//	ncn8025_get(slotnr, &settings);
+//	if (!settings.simpres) {
+//		printf("(%d) error: no card present\r\n", slotnr);
+//		return;
+//	}
+//
+//	// switch card off (assert reset and disable power)
+//	// note: ISO/IEC 7816-3:2006 section 6.4 provides the deactivation sequence, but not the minimum corresponding times
+//	settings.rstin = true;
+//	settings.cmdvcc = false;
+//	settings.led = true;
+//	ncn8025_set(slotnr, &settings);
+//
+//	// TODO wait some time for card to be completely deactivated
+//	usart_async_flush_rx_buffer(SIM_peripheral_descriptors[slotnr]); // flush RX buffer to start from scratch
+//
+//
+//	// set clock to lowest frequency (20 MHz / 8 = 2.5 MHz)
+//	// note: according to ISO/IEC 7816-3:2006 section 5.2.3 the minimum value is 1 MHz, and maximum is 5 MHz during activation
+//	settings.clkdiv = SIM_CLKDIV_8;
+//	// set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1)
+//	slot_set_isorate(slotnr, settings.clkdiv, ISO7816_3_DEFAULT_FD, ISO7816_3_DEFAULT_DD);
+//	// set card voltage to 3.0 V (the most supported)
+//	// note: according to ISO/IEC 7816-3:2006 no voltage should damage the card, and you should cycle from low to high
+//	settings.vsel = SIM_VOLT_3V0;
+//	// provide power (the NCN8025 should perform the activation according to spec)
+//	// note: activation sequence is documented in ISO/IEC 7816-3:2006 section 6.2
+//	settings.cmdvcc = true;
+//	ncn8025_set(slotnr, &settings);
+//
+//	// wait for Tb=400 cycles before re-asserting reset
+//	delay_us(400 * 10000 / 2500); // 400 cycles * 1000 for us, 2.5 MHz / 1000 for us
+//
+//	// de-assert reset to switch card back on
+//	settings.rstin = false;
+//	ncn8025_set(slotnr, &settings);
+//
+//	// wait for Tc=40000 cycles for transmission to start
+//	uint32_t cycles = 40000;
+//	while (cycles && !usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
+//		delay_us(10);
+//		cycles -= 25; // 10 us = 25 cycles at 2.5 MHz
+//	}
+//	if (!usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
+//		delay_us(12 * 372 / 1 / 2); // wait more than one byte (approximate freq down to 2 MHz)
+//	}
+//	// verify if one byte has been received
+//	if (!usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
+//		printf("(%d) error: card not responsive\r\n", slotnr);
+//		return;
+//	}
+//
+//	// read ATR (just do it until there is no traffic anymore)
+//	// TODO the ATR should be parsed to read the right number of bytes, instead we just wait until to end of WT
+//	printf("(%d) ATR: ", slotnr);
+//	uint8_t atr_byte;
+//	while (usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
+//		if (1 == io_read(&SIM_peripheral_descriptors[slotnr]->io, &atr_byte, 1)) {
+//			printf("%02x ", atr_byte);
+//		}
+//		uint16_t wt = ISO7816_3_DEFAULT_WT; // waiting time in ETU
+//		while (wt && !usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
+//			delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
+//			wt--;
+//		}
+//	}
+//	printf("\r\n");
+//
+//	/* disable LED */
+//	settings.led = false;
+//	ncn8025_set(slotnr, &settings);
+//}
+//
+//DEFUN(sim_iccid, cmd_sim_iccid, "sim-iccid", "Read ICCID from SIM card")
+//{
+//	struct ncn8025_settings settings;
+//	int slotnr = validate_slotnr(argc, argv, 1);
+//
+//	if (slotnr < 0 || slotnr >= ARRAY_SIZE(SIM_peripheral_descriptors) || NULL == SIM_peripheral_descriptors[slotnr]) {
+//		return;
+//	}
+//
+//	// read current settings and check if card is present and powered
+//	ncn8025_get(slotnr, &settings);
+//	if (!settings.simpres) {
+//		printf("(%d) error: no card present\r\n", slotnr);
+//		return;
+//	}
+//	if (!settings.cmdvcc) {
+//		printf("(%d) error: card not powered\r\n", slotnr);
+//		return;
+//	}
+//	if (settings.rstin) {
+//		printf("(%d) error: card under reset\r\n", slotnr);
+//		return;
+//	}
+//
+//	// enable LED
+//	if (!settings.led) {
+//		settings.led = true;
+//		ncn8025_set(slotnr, &settings);
+//	}
+//
+//	// select MF
+//	printf("(%d) SELECT MF\r\n", slotnr);
+//	const uint8_t select_header[] = {0xa0, 0xa4, 0x00, 0x00, 0x02}; // see TS 102.221 sec. 11.1.1
+//	const uint8_t select_data_mf[] = {0x3f, 0x00}; // see TS 102.221 sec. 13.1
+//	int rc = slot_tpdu_xfer(slotnr, select_header, (uint8_t*)select_data_mf, ARRAY_SIZE(select_data_mf), true); // transfer TPDU
+//	if (ERR_NONE != rc) {
+//		printf("error while SELECT MF (errno = %d)\r\n", rc);
+//	}
+//	// ignore response data
+//
+//	// select EF_ICCID
+//	printf("(%d) SELECT EF_ICCID\r\n", slotnr);
+//	const uint8_t select_data_ef_iccid[] = {0x2f, 0xe2}; // see TS 102.221 sec. 13.2
+//	rc = slot_tpdu_xfer(slotnr, select_header, (uint8_t*)select_data_ef_iccid, ARRAY_SIZE(select_data_ef_iccid), true); // transfer TPDU
+//	if (ERR_NONE != rc) {
+//		printf("error while SELECT EF_ICCID (errno = %d)\r\n", rc);
+//	}
+//	// ignore response data
+//
+//	// read EF_ICCID
+//	printf("(%d) READ EF_ICCID\r\n", slotnr);
+//	uint8_t iccid[10];
+//	uint8_t read_binary[] = {0xa0, 0xb0, 0x00, 0x00, ARRAY_SIZE(iccid)}; // see TS 102.221 sec. 11.1.3
+//	rc = slot_tpdu_xfer(slotnr, read_binary, iccid, ARRAY_SIZE(iccid), false); // transfer TPDU
+//	if (ERR_NONE != rc) {
+//		printf("error while READ ICCID (errno = %d)\r\n", rc);
+//	}
+//	// ignore response data
+//
+//	printf("(%d) ICCID: ", slotnr);
+//	for (uint8_t i = 0; i < ARRAY_SIZE(iccid); i++) {
+//		uint8_t nibble = iccid[i] & 0xf;
+//		if (0xf == nibble) {
+//			break;
+//		}
+//		printf("%x", nibble);
+//		nibble = iccid[i] >> 4;
+//		if (0xf == nibble) {
+//			break;
+//		}
+//		printf("%x", nibble);
+//	}
+//	printf("\r\n");
+//
+//	// disable LED
+//	settings.led = false;
+//	ncn8025_set(slotnr, &settings);
+//}
+//
+//DEFUN(get_time, cmd_get_time, "get-time", "Read Time from RTC")
+//{
+//	struct calendar_date_time dt;
+//	calendar_get_date_time(&CALENDAR_0, &dt);
+//	printf("%04u-%02u-%02u %02u:%02u:%02u\r\n", dt.date.year, dt.date.month, dt.date.day,
+//		dt.time.hour, dt.time.min, dt.time.sec);
+//}
 
-/** change baud rate of card slot
- *  @param[in] slotnr slot number for which the baud rate should be set
- *  @param[in] baudrate baud rate in bps to set
- *  @return if the baud rate has been set, else a parameter is out of range
- */
-static bool slot_set_baudrate(uint8_t slotnr, uint32_t baudrate)
-{
-	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
-
-	// calculate the error corresponding to the clock sources
-	uint16_t bauds[ARRAY_SIZE(sercom_glck_freqs)];
-	double errors[ARRAY_SIZE(sercom_glck_freqs)];
-	for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {
-		double freq = sercom_glck_freqs[i]; // remember possible SERCOM frequency
-		uint32_t min = freq / (2 * (255 + 1)); // calculate the minimum baud rate for this frequency
-		uint32_t max = freq / (2 * (0 + 1)); // calculate the maximum baud rate for this frequency
-		if (baudrate < min || baudrate > max) { // baud rate it out of supported range
-			errors[i] = NAN;
-		} else {
-			uint16_t baud = round(freq / (2 * baudrate) - 1);
-			bauds[i] = baud;
-			double actual = freq / (2 * (baud + 1));
-			errors[i] = fabs(1.0 - (actual / baudrate));
-		}
-	}
-
-	// find the smallest error
-	uint8_t best = ARRAY_SIZE(sercom_glck_freqs);
-	for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {
-		if (isnan(errors[i])) {
-			continue;
-		}
-		if (best >= ARRAY_SIZE(sercom_glck_freqs)) {
-			best = i;
-		} else if (errors[i] < errors[best]) {
-			best = i;
-		}
-	}
-	if (best >= ARRAY_SIZE(sercom_glck_freqs)) { // found no clock supporting this baud rate
-		return false;
-	}
-
-	// set clock and baud rate
-	struct usart_async_descriptor* slot = SIM_peripheral_descriptors[slotnr]; // get slot
-	if (NULL == slot) {
-		return false;
-	}
-	printf("(%u) switching SERCOM clock to GCLK%u (freq = %lu kHz) and baud rate to %lu bps (baud = %u)\r\n", slotnr, (best + 1) * 2, (uint32_t)(round(sercom_glck_freqs[best] / 1000)), baudrate, bauds[best]);
-	while (!usart_async_is_tx_empty(slot)); // wait for transmission to complete (WARNING no timeout)
-	usart_async_disable(slot); // disable SERCOM peripheral
-	hri_gclk_clear_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos)); // disable clock for this peripheral
-	while (hri_gclk_get_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos))); // wait until clock is really disabled
-	// it does not seem we need to completely disable the peripheral using hri_mclk_clear_APBDMASK_SERCOMn_bit
-	hri_gclk_write_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], sercom_glck_sources[best] | (1 << GCLK_PCHCTRL_CHEN_Pos)); // set peripheral core clock and re-enable it
-	usart_async_set_baud_rate(slot, bauds[best]); // set the new baud rate
-	usart_async_enable(slot); // re-enable SERCOM peripheral
-
-	return true;
-}
-
-/** change ISO baud rate of card slot
- *  @param[in] slotnr slot number for which the baud rate should be set
- *  @param[in] clkdiv can clock divider
- *  @param[in] f clock rate conversion integer F
- *  @param[in] d baud rate adjustment factor D
- *  @return if the baud rate has been set, else a parameter is out of range
- */
-static bool slot_set_isorate(uint8_t slotnr, enum ncn8025_sim_clkdiv clkdiv, uint16_t f, uint8_t d)
-{
-	// input checks
-	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
-	if (clkdiv != SIM_CLKDIV_1 && clkdiv != SIM_CLKDIV_2 && clkdiv != SIM_CLKDIV_4 && clkdiv != SIM_CLKDIV_8) {
-		return false;
-	}
-	if (!iso7816_3_valid_f(f)) {
-		return false;
-	}
-	if (!iso7816_3_valid_d(d)) {
-		return false;
-	}
-
-	// set clockdiv
-	struct ncn8025_settings settings;
-	ncn8025_get(slotnr, &settings);
-	if (settings.clkdiv != clkdiv) {
-		settings.clkdiv = clkdiv;
-		ncn8025_set(slotnr, &settings);
-	}
-
-	// calculate desired frequency
-	uint32_t freq = 20000000UL; // maximum frequency
-	switch (clkdiv) {
-	case SIM_CLKDIV_1:
-		freq /= 1;
-		break;
-	case SIM_CLKDIV_2:
-		freq /= 2;
-		break;
-	case SIM_CLKDIV_4:
-		freq /= 4;
-		break;
-	case SIM_CLKDIV_8:
-		freq /= 8;
-		break;
-	}
-
-	// set baud rate
-	uint32_t baudrate = (freq * d) / f; // calculate actual baud rate
-	return slot_set_baudrate(slotnr, baudrate); // set baud rate
-}
-
-/** write data to card
- *  @param[in] slotnr slot number on which to send data
- *  @param[in] data data to be transmitted
- *  @param[in] length length of data to be transmitted
- *  @return error code
- */
-static int slot_card_write(uint8_t slotnr, const uint8_t* data, uint16_t length)
-{
-	// input checks
-	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
-	if (0 == length || NULL == data) {
-		return ERR_INVALID_ARG;
-	}
-
-	struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr];
-	((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 0; // disable receive (to avoid the echo back)
-	SIM_tx_count[slotnr] = false; // reset TX complete
-	for (uint16_t i = 0; i < length; i++) { // transmit data
-		while(!usart_async_is_tx_empty(sim)); // wait for previous byte to be transmitted (WARNING blocking)
-		if (1 != io_write(&sim->io, &data[i], 1)) { // put but in transmit buffer
-			return ERR_IO;
-		}
-	}
-	while (!SIM_tx_count[slotnr]); // wait until transmission is complete (WARNING blocking)
-	((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1; // enable receive again
-
-	return ERR_NONE;
-}
-
-/** read data from card
- *  @param[in] slotnr slot number on which to send data
- *  @param[out] data buffer for read data to be stored
- *  @param[in] length length of data to be read
- *  @param[in] wt Waiting Time in ETU
- *  @return error code
- *  TODO fix WT/ETU duration
- */
-static int slot_card_read(uint8_t slotnr, uint8_t* data, uint16_t length, uint32_t wt)
-{
-	// input checks
-	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
-	if (0 == length || NULL == data) {
-		return ERR_INVALID_ARG;
-	}
-
-	struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr];
-
-	((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1; // ensure RX is enabled
-	uint32_t timeout = wt; // reset waiting time
-	for (uint16_t i = 0; i < length; i++) { // read all data
-		while (timeout && !usart_async_is_rx_not_empty(sim)) { // verify if data is present
-			delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
-			timeout--;
-		}
-		if (0 == timeout) { // timeout reached
-			return ERR_TIMEOUT;
-		}
-		timeout = wt; // reset waiting time
-		if (1 != io_read(&sim->io, &data[i], 1)) { // read one byte
-			return ERR_IO;
-		}
-	}
-
-	return ERR_NONE;
-}
-
-/** transfer TPDU
- *  @param[in] slotnr slot number on which to transfer the TPDU
- *  @param[in] header TPDU header to send
- *  @param[io] data TPDU data to transfer
- *  @param[in] data_length length of TPDU data to transfer
- *  @param[in] write if the data should be written (true) or read (false)
- * TODO fix WT
- * TODO the data length can be deduce from the header
- */
-static int slot_tpdu_xfer(uint8_t slotnr, const uint8_t* header, uint8_t* data, uint16_t data_length, bool write)
-{
-	// input checks
-	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
-	if (NULL == header || (data_length > 0 && NULL == data)) {
-		return ERR_INVALID_ARG;
-	}
-
-	int rc;
-	struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr]; // get USART peripheral
-	usart_async_flush_rx_buffer(sim); // flush RX buffer to start from scratch
-
-	// send command header
-	printf("(%d) TPDU: ", slotnr);
-	for (uint8_t i = 0; i < 5; i++) {
-		printf("%02x ", header[i]);
-	}
-	rc = slot_card_write(slotnr, header, 5); // transmit header
-	if (ERR_NONE != rc) {
-		printf("error in command header transmit (errno = %d)\r\n", rc);
-		return rc;
-	}
-
-	// read procedure byte, and handle data
-	uint8_t pb = 0x60; // wait more procedure byte
-	uint16_t data_i = 0; // progress in the data transfer
-	while (0x60 == pb) { // wait for SW
-		rc = slot_card_read(slotnr, &pb, 1, ISO7816_3_DEFAULT_WT);
-		if (ERR_NONE != rc) {
-			printf("error while receiving PB/SW1 (errno = %d)\r\n", rc);
-			return rc;
-		}
-		printf("%02x ", pb);
-		if (0x60 == pb) { // NULL byte
-			// just wait more time
-		} else if ((0x60 == (pb & 0xf0)) || (0x90 == (pb & 0xf0))) { // SW1 byte
-			// left the rest of the code handle it
-		} else if (header[1] == pb) { // ACK byte
-			// transfer rest of the data
-			if (data_i >= data_length) {
-				printf("error no more data to transfer\r\n");
-				return ERR_INVALID_DATA;
-			}
-			if (write) { // transmit remaining command data
-				rc = slot_card_write(slotnr, &data[data_i], data_length - data_i); // transmit command data
-				if (ERR_NONE != rc) {
-					printf("error in command data transmit (errno = %d)\r\n", rc);
-					return rc;
-				}
-			} else { // receive remaining command data
-				rc = slot_card_read(slotnr, &data[data_i], data_length - data_i, ISO7816_3_DEFAULT_WT);
-				if (ERR_NONE != rc) {
-					printf("error in command data receive (errno = %d)\r\n", rc);
-					return rc;
-				}
-			}
-			for (uint16_t i = data_i; i < data_length; i++) {
-				printf("%02x ", data[i]);
-			}
-			data_i = data_length; // remember we transferred the data
-			pb = 0x60; // wait for SW1
-		} else if (header[1] == (pb ^ 0xff)) { // ACK byte
-			// transfer only one byte
-			if (data_i >= data_length) {
-				printf("error no more data to transfer\r\n");
-				return ERR_INVALID_DATA;
-			}
-			if (write) { // transmit command data byte
-				rc = slot_card_write(slotnr, &data[data_i], 1); // transmit command data
-				if (ERR_NONE != rc) {
-					printf("error in command data transmit (errno = %d)\r\n", rc);
-					return rc;
-				}
-			} else { // receive command data byte
-				rc = slot_card_read(slotnr, &data[data_i], 1, ISO7816_3_DEFAULT_WT);
-				if (ERR_NONE != rc) {
-					printf("error in command data receive (errno = %d)\r\n", rc);
-					return rc;
-				}
-			}
-			printf("%02x ", data[data_i]);
-			data_i += 1; // remember we transferred one data byte
-			pb = 0x60; // wait for SW1
-		} else { // invalid byte
-			return ERR_INVALID_DATA;
-		}
-	}
-
-	// read SW2
-	uint8_t sw2;
-	rc = slot_card_read(slotnr, &sw2, 1, ISO7816_3_DEFAULT_WT);
-	if (ERR_NONE != rc) {
-		printf("error in receiving SW2 (errno = %d)\r\n", rc);
-		return rc;
-	}
-	printf("%02x", sw2);
-
-	printf("\r\n");
-	return ERR_NONE;
-}
-
-DEFUN(sim_status, cmd_sim_status, "sim-status", "Get state of specified NCN8025")
-{
-	struct ncn8025_settings settings;
-	int slotnr = validate_slotnr(argc, argv, 1);
-	if (slotnr < 0)
-		return;
-	ncn8025_get(slotnr, &settings);
-	printf("SIM%d: ", slotnr);
-	ncn8025_dump(&settings);
-	printf("\r\n");
-}
-
-DEFUN(sim_power, cmd_sim_power, "sim-power", "Enable/disable SIM card power")
-{
-	struct ncn8025_settings settings;
-	int slotnr = validate_slotnr(argc, argv, 1);
-	int enable;
-
-	if (slotnr < 0)
-		return;
-
-	if (argc < 3) {
-		printf("You have to specify 0=disable or 1=enable\r\n");
-		return;
-	}
-	enable = atoi(argv[2]);
-	ncn8025_get(slotnr, &settings);
-	if (enable)
-		settings.cmdvcc = true;
-	else
-		settings.cmdvcc = false;
-	ncn8025_set(slotnr, &settings);
-}
-
-DEFUN(sim_reset, cmd_sim_reset, "sim-reset", "Enable/disable SIM reset")
-{
-	struct ncn8025_settings settings;
-	int slotnr = validate_slotnr(argc, argv, 1);
-	int enable;
-
-	if (slotnr < 0)
-		return;
-
-	if (argc < 3) {
-		printf("You have to specify 0=disable or 1=enable\r\n");
-		return;
-	}
-	enable = atoi(argv[2]);
-	ncn8025_get(slotnr, &settings);
-	if (enable)
-		settings.rstin = true;
-	else
-		settings.rstin = false;
-	ncn8025_set(slotnr, &settings);
-}
-
-DEFUN(sim_clkdiv, cmd_sim_clkdiv, "sim-clkdiv", "Set SIM clock divider (1,2,4,8)")
-{
-	struct ncn8025_settings settings;
-	int slotnr = validate_slotnr(argc, argv, 1);
-	int clkdiv;
-
-	if (slotnr < 0)
-		return;
-
-	if (argc < 3) {
-		printf("You have to specify a valid divider (1,2,4,8)\r\n");
-		return;
-	}
-	clkdiv = atoi(argv[2]);
-	if (clkdiv != 1 && clkdiv != 2 && clkdiv != 4 && clkdiv != 8) {
-		printf("You have to specify a valid divider (1,2,4,8)\r\n");
-		return;
-	}
-	ncn8025_get(slotnr, &settings);
-	switch (clkdiv) {
-	case 1:
-		settings.clkdiv = SIM_CLKDIV_1;
-		break;
-	case 2:
-		settings.clkdiv = SIM_CLKDIV_2;
-		break;
-	case 4:
-		settings.clkdiv = SIM_CLKDIV_4;
-		break;
-	case 8:
-		settings.clkdiv = SIM_CLKDIV_8;
-		break;
-	}
-	ncn8025_set(slotnr, &settings);
-}
-
-DEFUN(sim_voltage, cmd_sim_voltage, "sim-voltage", "Set SIM voltage (5/3/1.8)")
-{
-	struct ncn8025_settings settings;
-	int slotnr = validate_slotnr(argc, argv, 1);
-
-	if (slotnr < 0)
-		return;
-
-	if (argc < 3) {
-		printf("You have to specify a valid voltage (5/3/1.8)\r\n");
-		return;
-	}
-	ncn8025_get(slotnr, &settings);
-	if (!strcmp(argv[2], "5"))
-		settings.vsel = SIM_VOLT_5V0;
-	else if (!strcmp(argv[2], "3"))
-		settings.vsel = SIM_VOLT_3V0;
-	else if (!strcmp(argv[2], "1.8"))
-		settings.vsel = SIM_VOLT_1V8;
-	else {
-		printf("You have to specify a valid voltage (5/3/1.8)\r\n");
-		return;
-	}
-	ncn8025_set(slotnr, &settings);
-}
-
-DEFUN(sim_led, cmd_sim_led, "sim-led", "Set SIM LED (1=on, 0=off)")
-{
-	struct ncn8025_settings settings;
-	int slotnr = validate_slotnr(argc, argv, 1);
-
-	if (slotnr < 0)
-		return;
-
-	if (argc < 3) {
-		printf("You have to specify 0=disable or 1=enable\r\n");
-		return;
-	}
-	ncn8025_get(slotnr, &settings);
-	if (atoi(argv[2]))
-		settings.led = true;
-	else
-		settings.led = false;
-	ncn8025_set(slotnr, &settings);
-}
-
-DEFUN(sim_atr, cmd_sim_atr, "sim-atr", "Read ATR from SIM card")
-{
-	struct ncn8025_settings settings;
-	int slotnr = validate_slotnr(argc, argv, 1);
-
-	if (slotnr < 0 || slotnr >= ARRAY_SIZE(SIM_peripheral_descriptors) || NULL == SIM_peripheral_descriptors[slotnr]) {
-		return;
-	}
-
-	// check if card is present (and read current settings)
-	ncn8025_get(slotnr, &settings);
-	if (!settings.simpres) {
-		printf("(%d) error: no card present\r\n", slotnr);
-		return;
-	}
-
-	// switch card off (assert reset and disable power)
-	// note: ISO/IEC 7816-3:2006 section 6.4 provides the deactivation sequence, but not the minimum corresponding times
-	settings.rstin = true;
-	settings.cmdvcc = false;
-	settings.led = true;
-	ncn8025_set(slotnr, &settings);
-
-	// TODO wait some time for card to be completely deactivated
-	usart_async_flush_rx_buffer(SIM_peripheral_descriptors[slotnr]); // flush RX buffer to start from scratch
-
-	
-	// set clock to lowest frequency (20 MHz / 8 = 2.5 MHz)
-	// note: according to ISO/IEC 7816-3:2006 section 5.2.3 the minimum value is 1 MHz, and maximum is 5 MHz during activation
-	settings.clkdiv = SIM_CLKDIV_8;
-	// set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1)
-	slot_set_isorate(slotnr, settings.clkdiv, ISO7816_3_DEFAULT_FD, ISO7816_3_DEFAULT_DD);
-	// set card voltage to 3.0 V (the most supported)
-	// note: according to ISO/IEC 7816-3:2006 no voltage should damage the card, and you should cycle from low to high
-	settings.vsel = SIM_VOLT_3V0;
-	// provide power (the NCN8025 should perform the activation according to spec)
-	// note: activation sequence is documented in ISO/IEC 7816-3:2006 section 6.2
-	settings.cmdvcc = true;
-	ncn8025_set(slotnr, &settings);
-
-	// wait for Tb=400 cycles before re-asserting reset
-	delay_us(400 * 10000 / 2500); // 400 cycles * 1000 for us, 2.5 MHz / 1000 for us
-
-	// de-assert reset to switch card back on
-	settings.rstin = false;
-	ncn8025_set(slotnr, &settings);
-
-	// wait for Tc=40000 cycles for transmission to start
-	uint32_t cycles = 40000;
-	while (cycles && !usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
-		delay_us(10);
-		cycles -= 25; // 10 us = 25 cycles at 2.5 MHz
-	}
-	if (!usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
-		delay_us(12 * 372 / 1 / 2); // wait more than one byte (approximate freq down to 2 MHz)
-	}
-	// verify if one byte has been received
-	if (!usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
-		printf("(%d) error: card not responsive\r\n", slotnr);
-		return;
-	}
-
-	// read ATR (just do it until there is no traffic anymore)
-	// TODO the ATR should be parsed to read the right number of bytes, instead we just wait until to end of WT
-	printf("(%d) ATR: ", slotnr);
-	uint8_t atr_byte;
-	while (usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
-		if (1 == io_read(&SIM_peripheral_descriptors[slotnr]->io, &atr_byte, 1)) {
-			printf("%02x ", atr_byte);
-		}
-		uint16_t wt = ISO7816_3_DEFAULT_WT; // waiting time in ETU
-		while (wt && !usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
-			delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
-			wt--;
-		}
-	}
-	printf("\r\n");
-
-	/* disable LED */
-	settings.led = false;
-	ncn8025_set(slotnr, &settings);
-}
-
-DEFUN(sim_iccid, cmd_sim_iccid, "sim-iccid", "Read ICCID from SIM card")
-{
-	struct ncn8025_settings settings;
-	int slotnr = validate_slotnr(argc, argv, 1);
-
-	if (slotnr < 0 || slotnr >= ARRAY_SIZE(SIM_peripheral_descriptors) || NULL == SIM_peripheral_descriptors[slotnr]) {
-		return;
-	}
-
-	// read current settings and check if card is present and powered
-	ncn8025_get(slotnr, &settings);
-	if (!settings.simpres) {
-		printf("(%d) error: no card present\r\n", slotnr);
-		return;
-	}
-	if (!settings.cmdvcc) {
-		printf("(%d) error: card not powered\r\n", slotnr);
-		return;
-	}
-	if (settings.rstin) {
-		printf("(%d) error: card under reset\r\n", slotnr);
-		return;
-	}
-
-	// enable LED
-	if (!settings.led) {
-		settings.led = true;
-		ncn8025_set(slotnr, &settings);
-	}
-
-	// select MF
-	printf("(%d) SELECT MF\r\n", slotnr);
-	const uint8_t select_header[] = {0xa0, 0xa4, 0x00, 0x00, 0x02}; // see TS 102.221 sec. 11.1.1
-	const uint8_t select_data_mf[] = {0x3f, 0x00}; // see TS 102.221 sec. 13.1
-	int rc = slot_tpdu_xfer(slotnr, select_header, (uint8_t*)select_data_mf, ARRAY_SIZE(select_data_mf), true); // transfer TPDU
-	if (ERR_NONE != rc) {
-		printf("error while SELECT MF (errno = %d)\r\n", rc);
-	}
-	// ignore response data
-
-	// select EF_ICCID
-	printf("(%d) SELECT EF_ICCID\r\n", slotnr);
-	const uint8_t select_data_ef_iccid[] = {0x2f, 0xe2}; // see TS 102.221 sec. 13.2
-	rc = slot_tpdu_xfer(slotnr, select_header, (uint8_t*)select_data_ef_iccid, ARRAY_SIZE(select_data_ef_iccid), true); // transfer TPDU
-	if (ERR_NONE != rc) {
-		printf("error while SELECT EF_ICCID (errno = %d)\r\n", rc);
-	}
-	// ignore response data
-
-	// read EF_ICCID
-	printf("(%d) READ EF_ICCID\r\n", slotnr);
-	uint8_t iccid[10];
-	uint8_t read_binary[] = {0xa0, 0xb0, 0x00, 0x00, ARRAY_SIZE(iccid)}; // see TS 102.221 sec. 11.1.3
-	rc = slot_tpdu_xfer(slotnr, read_binary, iccid, ARRAY_SIZE(iccid), false); // transfer TPDU
-	if (ERR_NONE != rc) {
-		printf("error while READ ICCID (errno = %d)\r\n", rc);
-	}
-	// ignore response data
-
-	printf("(%d) ICCID: ", slotnr);
-	for (uint8_t i = 0; i < ARRAY_SIZE(iccid); i++) {
-		uint8_t nibble = iccid[i] & 0xf;
-		if (0xf == nibble) {
-			break;
-		}
-		printf("%x", nibble);
-		nibble = iccid[i] >> 4;
-		if (0xf == nibble) {
-			break;
-		}
-		printf("%x", nibble);
-	}
-	printf("\r\n");
-
-	// disable LED
-	settings.led = false;
-	ncn8025_set(slotnr, &settings);
-}
-
-DEFUN(get_time, cmd_get_time, "get-time", "Read Time from RTC")
-{
-	struct calendar_date_time dt;
-	calendar_get_date_time(&CALENDAR_0, &dt);
-	printf("%04u-%02u-%02u %02u:%02u:%02u\r\n", dt.date.year, dt.date.month, dt.date.day,
-		dt.time.hour, dt.time.min, dt.time.sec);
-}
-
-#include <osmocom/core/timer.h>
-static struct osmo_timer_list t;
-static void tmr_cb(void *data)
-{
-	printf("timer fired!\r\n");
-}
-DEFUN(test_timer, cmd_test_timer, "test-timer", "Test osmo_timer")
-{
-	printf("Setting up timer for 3s...\n\r");
-	osmo_timer_setup(&t, &tmr_cb, NULL);
-	osmo_timer_schedule(&t, 3, 0);
-}
+//#include <osmocom/core/timer.h>
+//static struct osmo_timer_list t;
+//static void tmr_cb(void *data)
+//{
+//	printf("timer fired!\r\n");
+//}
+//DEFUN(test_timer, cmd_test_timer, "test-timer", "Test osmo_timer")
+//{
+//	printf("Setting up timer for 3s...\n\r");
+//	osmo_timer_setup(&t, &tmr_cb, NULL);
+//	osmo_timer_schedule(&t, 3, 0);
+//}
 
 
 extern void testmode_init(void);
@@ -991,25 +1003,25 @@
 
 #include "talloc.h"
 #include "logging.h"
-#include <osmocom/core/msgb.h>
+//#include <osmocom/core/msgb.h>
 void *g_tall_ctx;
 
-DEFUN(_talloc_report, cmd_talloc_report, "talloc-report", "Generate a talloc report")
-{
-	talloc_report_full(g_tall_ctx, stdout);
-}
-
-DEFUN(talloc_test, cmd_talloc_test, "talloc-test", "Test the talloc allocator")
-{
-	for (int i = 0; i < 10; i++)
-		talloc_named_const(g_tall_ctx, 10, "sibling");
-}
-
-DEFUN(v_talloc_free, cmd_talloc_free, "talloc-free", "Release all memory")
-{
-	talloc_free(g_tall_ctx);
-	g_tall_ctx = NULL;
-}
+//DEFUN(_talloc_report, cmd_talloc_report, "talloc-report", "Generate a talloc report")
+//{
+//	talloc_report_full(g_tall_ctx, stdout);
+//}
+//
+//DEFUN(talloc_test, cmd_talloc_test, "talloc-test", "Test the talloc allocator")
+//{
+//	for (int i = 0; i < 10; i++)
+//		talloc_named_const(g_tall_ctx, 10, "sibling");
+//}
+//
+//DEFUN(v_talloc_free, cmd_talloc_free, "talloc-free", "Release all memory")
+//{
+//	talloc_free(g_tall_ctx);
+//	g_tall_ctx = NULL;
+//}
 
 /* Section 9.6 of SAMD5x/E5x Family Data Sheet */
 static int get_chip_unique_serial(uint8_t *out, size_t len)
@@ -1065,6 +1077,55 @@
 		strcat(out, "BACKUP ");
 }
 
+//#######################
+
+
+
+static uint32_t clock_freqs[] = {
+	2500000
+};
+
+static uint32_t data_rates[] = {
+	9600
+};
+extern struct usb_desc_collection usb_fs_descs;
+
+
+
+static int feed_ccid(void)
+{
+	struct usb_ep_q *ep_q = &g_ccid_s.out_ep;
+	struct msgb *msg;
+	int rc;
+
+	msg = msgb_dequeue_irqsafe(&g_ccid_s.out_ep.list);
+	if (!msg)
+		return -1;
+
+	ccid_handle_out(&g_ci, msg);
+	return 1;
+}
+
+static int ccid_ops_send_in(struct ccid_instance *ci, struct msgb *msg)
+{
+	/* add just-received msg to tail of endpoint queue */
+	OSMO_ASSERT(msg);
+
+	/* append to list of pending-to-be-handed messages */
+	llist_add_tail_at(&msg->list, &g_ccid_s.in_ep.list);
+	submit_next_in();
+	return 0;
+}
+
+static const struct ccid_ops c_ops = {
+	.send_in = ccid_ops_send_in,
+	.send_int = 0,
+};
+
+//#######################
+
+#define NUM_OUT_BUF 7
+
 int main(void)
 {
 	char sernr_buf[16*2+1];
@@ -1077,21 +1138,21 @@
 	usb_start();
 
 	board_init();
-	command_init("sysmoOCTSIM> ");
-	command_register(&cmd_sim_status);
-	command_register(&cmd_sim_power);
-	command_register(&cmd_sim_reset);
-	command_register(&cmd_sim_clkdiv);
-	command_register(&cmd_sim_voltage);
-	command_register(&cmd_sim_led);
-	command_register(&cmd_sim_atr);
-	command_register(&cmd_sim_iccid);
-	testmode_init();
-	command_register(&cmd_talloc_test);
-	command_register(&cmd_talloc_report);
-	command_register(&cmd_talloc_free);
-	command_register(&cmd_get_time);
-	command_register(&cmd_test_timer);
+//	command_init("sysmoOCTSIM> ");
+//	command_register(&cmd_sim_status);
+//	command_register(&cmd_sim_power);
+//	command_register(&cmd_sim_reset);
+//	command_register(&cmd_sim_clkdiv);
+//	command_register(&cmd_sim_voltage);
+//	command_register(&cmd_sim_led);
+//	command_register(&cmd_sim_atr);
+//	command_register(&cmd_sim_iccid);
+//	testmode_init();
+//	command_register(&cmd_talloc_test);
+//	command_register(&cmd_talloc_report);
+//	command_register(&cmd_talloc_free);
+//	command_register(&cmd_get_time);
+//	command_register(&cmd_test_timer);
 
 	printf("\r\n\r\n"
 		"=============================================================================\n\r"
@@ -1109,11 +1170,42 @@
 
 	LOGP(DUSB, LOGL_ERROR, "foobar usb\n");
 
-	command_print_prompt();
+	//FIXME osmo_emb has a pool?
+	msgb_set_talloc_ctx(g_tall_ctx);
+
+	ccid_instance_init(&g_ci, &c_ops, &iso_fsm_slot_ops, &usb_fs_descs.ccid.class,
+			   data_rates, clock_freqs, "", 0);
+
+	for(int i =0; i < NUM_OUT_BUF; i++){
+		struct msgb *msg = msgb_alloc(300, "ccid");
+		OSMO_ASSERT(msg);
+		/* return the message back to the queue of free message buffers */
+		llist_add_tail_at(&msg->list, &g_ccid_s.free_q);
+	}
+	submit_next_out();
+
+//	command_print_prompt();
 	while (true) { // main loop
 		command_try_recv();
 		poll_card_detect();
 		submit_next_irq();
+		feed_ccid();
 		osmo_timers_update();
+		int qs = llist_count_at(&g_ccid_s.free_q);
+		if(qs > NUM_OUT_BUF)
+			for (int i= 0; i < qs-NUM_OUT_BUF; i++){
+				struct msgb *msg = msgb_dequeue_irqsafe(&g_ccid_s.free_q);
+				if (msg)
+				msgb_free(msg);
+			}
+		if(qs < NUM_OUT_BUF)
+			for (int i= 0; i < qs-NUM_OUT_BUF; i++){
+				struct msgb *msg = msgb_alloc(300,"ccid");
+				OSMO_ASSERT(msg);
+				/* return the message back to the queue of free message buffers */
+				llist_add_tail_at(&msg->list, &g_ccid_s.free_q);
+			}
+
+
 	}
 }
diff --git a/sysmoOCTSIM/talloc.c b/sysmoOCTSIM/talloc.c
index c5c9062..790f657 100644
--- a/sysmoOCTSIM/talloc.c
+++ b/sysmoOCTSIM/talloc.c
@@ -30,6 +30,10 @@
   inspired by http://swapped.cc/halloc/
 */
 
+#include <parts.h>
+#include <assert.h>
+#include <osmocom/core/utils.h>
+
 #include "replace.h"
 #include "talloc.h"
 
@@ -727,6 +731,9 @@
 	size_t total_len = TC_HDR_SIZE + size + prefix_len;
 	struct talloc_chunk *parent = NULL;
 
+	// do not allocate while handling interrupts!
+	OSMO_ASSERT( !(SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) )
+
 	if (unlikely(context == NULL)) {
 		context = null_context;
 	}
diff --git a/sysmoOCTSIM/usb/class/ccid/device/ccid_df.c b/sysmoOCTSIM/usb/class/ccid/device/ccid_df.c
index 65d3499..665f0fc 100644
--- a/sysmoOCTSIM/usb/class/ccid/device/ccid_df.c
+++ b/sysmoOCTSIM/usb/class/ccid/device/ccid_df.c
@@ -24,6 +24,9 @@
 #include "ccid_proto.h"
 #include "usb_includes.h"
 
+#include "cdcdf_acm_desc.h"
+#include "usb_descriptors.h"
+
 #ifndef USB_CLASS_CCID
 #define	USB_CLASS_CCID	11
 #endif
@@ -40,9 +43,11 @@
 static struct usbdf_driver _ccid_df;
 static struct ccid_df_func_data _ccid_df_funcd;
 
+extern const struct usb_desc_collection usb_fs_descs;
+
 /* FIXME: make those configurable, ensure they're sized according to
  * bNumClockSupported / bNumDataRatesSupported */
-static uint32_t ccid_clock_frequencies[] = { LE32(20000) };
+static uint32_t ccid_clock_frequencies[CCID_NUM_CLK_SUPPORTED] = { LE32(2500),LE32(5000),LE32(10000),LE32(20000) };
 static uint32_t ccid_baud_rates[] = { LE32(9600) };
 
 static int32_t ccid_df_enable(struct usbdf_driver *drv, struct usbd_descriptors *desc)
diff --git a/sysmoOCTSIM/usb_descriptors.c b/sysmoOCTSIM/usb_descriptors.c
index 944e43b..f0d1a5c 100644
--- a/sysmoOCTSIM/usb_descriptors.c
+++ b/sysmoOCTSIM/usb_descriptors.c
@@ -4,51 +4,11 @@
 #include "usb_protocol_cdc.h"
 #include "ccid_proto.h"
 #include "cdcdf_acm_desc.h"
+#include "usb_descriptors.h"
 
-/* aggregate descriptors for the combined CDC-ACM + CCID device that we expose
- * from sysmoQMOD */
 
-enum str_desc_num {
-	STR_DESC_MANUF = 1,
-	STR_DESC_PRODUCT,
-	STR_DESC_CONFIG,
-	STR_DESC_INTF_ACM_COMM,
-	STR_DESC_INTF_ACM_DATA,
-	STR_DESC_INTF_CCID,
-	STR_DESC_SERIAL,
-};
 
-/* a struct of structs representing the concatenated collection of USB descriptors */
-struct usb_desc_collection {
-	struct usb_dev_desc dev;
-	struct usb_config_desc cfg;
-
-	/* CDC-ACM: Two interfaces, one with IRQ EP and one with BULK IN + OUT */
-	struct {
-		struct {
-			struct usb_iface_desc iface;
-			struct usb_cdc_hdr_desc cdc_hdr;
-			struct usb_cdc_call_mgmt_desc cdc_call_mgmt;
-			struct usb_cdc_acm_desc cdc_acm;
-			struct usb_cdc_union_desc cdc_union;
-			struct usb_ep_desc ep[1];
-		} comm;
-		struct {
-			struct usb_iface_desc iface;
-			struct usb_ep_desc ep[2];
-		} data;
-	} cdc;
-
-	/* CCID: One interface with CCID class descriptor and three endpoints */
-	struct {
-		struct usb_iface_desc iface;
-		struct usb_ccid_class_descriptor class;
-		struct usb_ep_desc ep[3];
-	} ccid;
-	uint8_t str[116];
-} __attribute__((packed));
-
-static const struct usb_desc_collection usb_fs_descs = {
+const struct usb_desc_collection usb_fs_descs = {
 	.dev = {
 		.bLength = sizeof(struct usb_dev_desc),
 		.bDescriptorType = USB_DT_DEVICE,
@@ -176,17 +136,19 @@
 			.bcdCCID = LE16(0x0110),
 			.bMaxSlotIndex = 7,
 			.bVoltageSupport = 0x07, /* 5/3/1.8V */
-			.dwProtocols = 0x03,
+//			.dwProtocols = 0x03,
+			.dwProtocols = 0x01,
 			.dwDefaultClock = LE32(2500),
 			.dwMaximumClock = LE32(20000),
-			.bNumClockSupported = 4,
+			.bNumClockSupported = CCID_NUM_CLK_SUPPORTED,
 			.dwDataRate = LE32(9600),
 			.dwMaxDataRate = LE32(921600),
 			.bNumDataRatesSupported = 0,
 			.dwMaxIFSD = LE32(0),
 			.dwSynchProtocols = LE32(0),
 			.dwMechanical = LE32(0),
-			.dwFeatures = LE32(0x10 | 0x00010000),
+			.dwFeatures = LE32(0x10 | 0x00010080),
+//			.dwFeatures = LE32(0x2 | 0x40),
 			.dwMaxCCIDMessageLength = 272,
 			.bClassGetResponse = 0xff,
 			.bClassEnvelope = 0xff,
diff --git a/sysmoOCTSIM/usb_descriptors.h b/sysmoOCTSIM/usb_descriptors.h
new file mode 100644
index 0000000..75b9e01
--- /dev/null
+++ b/sysmoOCTSIM/usb_descriptors.h
@@ -0,0 +1,56 @@
+/*
+ * usb_descriptors.h
+ *
+ *  Created on: Oct 11, 2019
+ *      Author: phi
+ */
+
+#ifndef USB_DESCRIPTORS_H_
+#define USB_DESCRIPTORS_H_
+
+#define CCID_NUM_CLK_SUPPORTED 4
+
+/* aggregate descriptors for the combined CDC-ACM + CCID device that we expose
+ * from sysmoQMOD */
+
+enum str_desc_num {
+	STR_DESC_MANUF = 1,
+	STR_DESC_PRODUCT,
+	STR_DESC_CONFIG,
+	STR_DESC_INTF_ACM_COMM,
+	STR_DESC_INTF_ACM_DATA,
+	STR_DESC_INTF_CCID,
+	STR_DESC_SERIAL,
+};
+
+/* a struct of structs representing the concatenated collection of USB descriptors */
+struct usb_desc_collection {
+	struct usb_dev_desc dev;
+	struct usb_config_desc cfg;
+
+	/* CDC-ACM: Two interfaces, one with IRQ EP and one with BULK IN + OUT */
+	struct {
+		struct {
+			struct usb_iface_desc iface;
+			struct usb_cdc_hdr_desc cdc_hdr;
+			struct usb_cdc_call_mgmt_desc cdc_call_mgmt;
+			struct usb_cdc_acm_desc cdc_acm;
+			struct usb_cdc_union_desc cdc_union;
+			struct usb_ep_desc ep[1];
+		} comm;
+		struct {
+			struct usb_iface_desc iface;
+			struct usb_ep_desc ep[2];
+		} data;
+	} cdc;
+
+	/* CCID: One interface with CCID class descriptor and three endpoints */
+	struct {
+		struct usb_iface_desc iface;
+		struct usb_ccid_class_descriptor class;
+		struct usb_ep_desc ep[3];
+	} ccid;
+	uint8_t str[116];
+} __attribute__((packed));
+
+#endif /* USB_DESCRIPTORS_H_ */

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/16235
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-ccid-firmware
Gerrit-Branch: master
Gerrit-Change-Id: Ia9d3b099181c24feabdb6a5fddb8db6c44efb72d
Gerrit-Change-Number: 16235
Gerrit-PatchSet: 1
Gerrit-Owner: Hoernchen <ewild at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20191126/1a4980b4/attachment.htm>


More information about the gerrit-log mailing list