#include #include "pico/stdlib.h" #include "pico/multicore.h" #include "hardware/pio.h" #include "hardware/uart.h" #include "hardware/clocks.h" #include "tusb.h" #include "iso7816_tx.pio.h" #define GPIO_SIM_VCC 18 /* pico pin 24 */ #define GPIO_SIM_RST 19 /* pico pin 25 */ #define GPIO_SIM_IO 21 /* pico pin 27 */ #define GPIO_SIM_CLK 20 /* must be at GP20 due to the GPIN0 function; pico pin 26 */ enum cardem_state { CST_WAIT_VCC, CST_VCC_WAIT_CLK, CST_VCC_CLK_WAIT_RST, CST_DELAY_BEFORE_ATR, CST_IN_ATR, CST_WAIT_TPDU_HDR, CST_IN_TPDU_HDR, }; struct cardem_uart_instance { enum cardem_state state; uint32_t vcc_freq_khz; volatile bool vcc_present; volatile bool rst_active; PIO pio; uint sm; uint tx_prog_offset; }; static struct cardem_uart_instance g_cst[1]; const uint8_t g_atr[] = { 0x3B, 0x80, 0x80, 0x81, 0x1F, 0xC7, 0x59 }; static void gpio_callback(uint gpio, uint32_t events) { switch (gpio) { case GPIO_SIM_VCC: if (events & GPIO_IRQ_EDGE_RISE) g_cst[0].vcc_present = true; #if 1 if (events & GPIO_IRQ_EDGE_FALL) g_cst[0].vcc_present = false; #endif //printf("VCC=%d\n", g_cst[0].vcc_present); break; case GPIO_SIM_RST: if (events & GPIO_IRQ_EDGE_RISE) g_cst[0].rst_active = false; #if 1 if (events & GPIO_IRQ_EDGE_FALL) g_cst[0].rst_active = true; #endif //printf("RST=%d\n", g_cst[0].rst_active); break; default: printf("unhandled GP%u: 0x%x\n", gpio, events); break; } } static void cardem_main_state_chg(struct cardem_uart_instance *cst, enum cardem_state new_st) { //printf("State %u -> %u\n", cst->state, new_st); cst->state = new_st; } static void cardem_main_loop(struct cardem_uart_instance *cst) { /* global reset on power-off */ if (cst->state != CST_WAIT_VCC && !cst->vcc_present ) { cardem_main_state_chg(cst, CST_WAIT_VCC); return; } switch (cst->state) { case CST_WAIT_VCC: if (cst->vcc_present) cardem_main_state_chg(cst, CST_VCC_WAIT_CLK); break; case CST_VCC_WAIT_CLK: /* determine CLK frequency */ cst->vcc_freq_khz = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLKSRC_GPIN0); if (cst->vcc_freq_khz) { //printf("Determined CLK freq: %u kHz\n", cst->vcc_freq_khz); cardem_main_state_chg(cst, CST_VCC_CLK_WAIT_RST); } break; case CST_VCC_CLK_WAIT_RST: #if 1 if (!cst->rst_active) cardem_main_state_chg(cst, CST_DELAY_BEFORE_ATR); break; #endif case CST_DELAY_BEFORE_ATR: /* FIXME: actually delay */ if (true) { cardem_main_state_chg(cst, CST_IN_ATR); /* configure the clock divider for the "correct" baud rate */ iso7816_tx_program_init(cst->pio, cst->sm, cst->tx_prog_offset, GPIO_SIM_IO, (cst->vcc_freq_khz * 1000) / 372); /* FIXME: actually start transmission via PIO */ iso7816_tx_program_puts(cst->pio, cst->sm, g_atr, sizeof(g_atr)); printf("ATR sent\n"); cardem_main_state_chg(cst, CST_WAIT_TPDU_HDR); } break; case CST_IN_ATR: break; case CST_WAIT_TPDU_HDR: break; case CST_IN_TPDU_HDR: break; } } static void cardem_inst_init(struct cardem_uart_instance *cst) { cst->state = CST_WAIT_VCC; cst->vcc_freq_khz = 0; cst->vcc_present = false; cst->rst_active = false; cst->pio = pio0; cst->sm = 0; cst->tx_prog_offset = pio_add_program(cst->pio, &iso7816_tx_program); } static void measure_freqs(void) { uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY); uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY); uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC); uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS); uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI); uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB); uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC); uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC); printf("pll_sys = %dkHz\n", f_pll_sys); printf("pll_usb = %dkHz\n", f_pll_usb); printf("rosc = %dkHz\n", f_rosc); printf("clk_sys = %dkHz\n", f_clk_sys); printf("clk_peri = %dkHz\n", f_clk_peri); printf("clk_usb = %dkHz\n", f_clk_usb); printf("clk_adc = %dkHz\n", f_clk_adc); printf("clk_rtc = %dkHz\n", f_clk_rtc); // Can't measure clk_ref / xosc as it is the ref } int main() { gpio_debug_pins_init(); #if 1 //stdio_init_all(); stdio_usb_init(); while (!tud_cdc_connected()) { printf("."); sleep_ms(500); } #else /* 115200 bps on GP0/GP1 of RP2040 (at least on pico) */ setup_default_uart(); #endif printf("Starting ISO7816 cardem playground\n"); measure_freqs(); cardem_inst_init(&g_cst[0]); gpio_set_irq_callback(gpio_callback); irq_set_enabled(IO_IRQ_BANK0, true); /* GP20 (CLK) as external clock input GPIN0 */ gpio_set_function(GPIO_SIM_CLK, GPIO_FUNC_GPCK); gpio_pull_down(GPIO_SIM_CLK); /* GPIO_SIM_VCC as input; edge-triggered interrupts */ gpio_init(GPIO_SIM_VCC); gpio_set_dir(GPIO_SIM_VCC, false); gpio_set_slew_rate(GPIO_SIM_VCC, GPIO_SLEW_RATE_SLOW); gpio_pull_down(GPIO_SIM_VCC); gpio_set_input_enabled(GPIO_SIM_VCC, true); gpio_set_irq_enabled(GPIO_SIM_VCC, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true); /* GPIO_SIM_RST as input; edge-triggered interrupts */ gpio_init(GPIO_SIM_RST); gpio_set_dir(GPIO_SIM_RST, false); gpio_set_slew_rate(GPIO_SIM_RST, GPIO_SLEW_RATE_SLOW); gpio_pull_up(GPIO_SIM_RST); gpio_set_input_enabled(GPIO_SIM_RST, true); gpio_set_irq_enabled(GPIO_SIM_RST, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true); gpio_pull_up(GPIO_SIM_IO); gpio_pull_up(GPIO_SIM_IO); gpio_set_function(GPIO_SIM_IO, GPIO_FUNC_PIO0); printf("Entering main loop\n"); while (true) { cardem_main_loop(&g_cst[0]); } }