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>