214 lines
5.6 KiB
C
214 lines
5.6 KiB
C
#include <stdio.h>
|
|
|
|
#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]);
|
|
}
|
|
|
|
}
|