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.orgHoernchen 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>