blob: 47d1cd10f2d86b40dfa8a3916d5e4b2c4156c8fa [file] [log] [blame]
Kévin Redon69b92d92019-01-24 16:39:20 +01001/*
Kévin Redon78d2f442019-01-24 18:45:59 +01002 * Copyright (C) 2019 sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
Kévin Redon69b92d92019-01-24 16:39:20 +010018
Harald Welte1b9a5b82019-02-24 23:04:45 +010019#include <stdlib.h>
20#include <stdio.h>
Harald Weltef53f2262019-02-24 11:01:08 +010021#include <parts.h>
22#include <hal_cache.h>
Harald Welte93f628a2019-02-24 14:32:30 +010023#include <hri_port_e54.h>
Harald Weltef53f2262019-02-24 11:01:08 +010024
Kévin Redon69b92d92019-01-24 16:39:20 +010025#include "atmel_start.h"
26#include "atmel_start_pins.h"
27
Harald Weltec3f170d2019-02-24 09:06:59 +010028#include "i2c_bitbang.h"
29#include "octsim_i2c.h"
30#include "ncn8025.h"
31
Harald Welteff9f4ce2019-02-24 22:51:09 +010032#include "command.h"
33
Kévin Redonc89bb8c2019-04-17 01:20:23 +020034// TODO put declaration in more global file
35// TODO for now SIM7 is not present because used for debug
36static struct usart_async_descriptor* SIM_peripheral_descriptors[] = {&SIM0, &SIM1, &SIM2, &SIM3, &SIM4, &SIM5, &SIM6, NULL};
37
38static void SIM_rx_cb(const struct usart_async_descriptor *const io_descr)
39{
40}
Kévin Redon78d2f442019-01-24 18:45:59 +010041
Harald Weltec3f170d2019-02-24 09:06:59 +010042static void board_init()
43{
44 int i;
45
46 for (i = 0; i < 4; i++)
47 i2c_init(&i2c[i]);
48
Harald Welte255da5e2019-04-16 18:19:53 +020049 for (i = 0; i < 8; i++)
Harald Weltec3f170d2019-02-24 09:06:59 +010050 ncn8025_init(i);
Harald Weltef53f2262019-02-24 11:01:08 +010051
52 cache_init();
53 cache_enable(CMCC);
Harald Welte93f628a2019-02-24 14:32:30 +010054
55 /* increase drive strength of 20Mhz SIM clock output to 8mA
56 * (there are 8 inputs + traces to drive!) */
57 hri_port_set_PINCFG_DRVSTR_bit(PORT, 0, 11);
Kévin Redonc89bb8c2019-04-17 01:20:23 +020058
59 // enable SIM interfaces
60 for (uint8_t i = 0; i < ARRAY_SIZE(SIM_peripheral_descriptors); i++) {
61 if (NULL == SIM_peripheral_descriptors[i]) {
62 continue;
63 }
64 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
65 usart_async_enable(SIM_peripheral_descriptors[i]);
66 }
Harald Weltec3f170d2019-02-24 09:06:59 +010067}
68
Harald Welte1b9a5b82019-02-24 23:04:45 +010069static int validate_slotnr(int argc, char **argv, int idx)
70{
71 int slotnr;
72 if (argc < idx+1) {
73 printf("You have to specify the slot number (0..7)\r\n");
74 return -1;
75 }
76 slotnr = atoi(argv[idx]);
77 if (slotnr < 0 || slotnr > 7) {
78 printf("You have to specify the slot number (0..7)\r\n");
79 return -1;
80 }
81 return slotnr;
82}
83
84DEFUN(sim_status, cmd_sim_status, "sim-status", "Get state of specified NCN8025")
85{
86 struct ncn8025_settings settings;
87 int slotnr = validate_slotnr(argc, argv, 1);
88 if (slotnr < 0)
89 return;
90 ncn8025_get(slotnr, &settings);
91 printf("SIM%d: ", slotnr);
92 ncn8025_dump(&settings);
93 printf("\r\n");
94}
95
96DEFUN(sim_power, cmd_sim_power, "sim-power", "Enable/disable SIM card power")
97{
98 struct ncn8025_settings settings;
99 int slotnr = validate_slotnr(argc, argv, 1);
100 int enable;
101
102 if (slotnr < 0)
103 return;
104
105 if (argc < 3) {
106 printf("You have to specify 0=disable or 1=enable\r\n");
107 return;
108 }
109 enable = atoi(argv[2]);
110 ncn8025_get(slotnr, &settings);
111 if (enable)
112 settings.cmdvcc = true;
113 else
114 settings.cmdvcc = false;
115 ncn8025_set(slotnr, &settings);
116}
117
118DEFUN(sim_reset, cmd_sim_reset, "sim-reset", "Enable/disable SIM reset")
119{
120 struct ncn8025_settings settings;
121 int slotnr = validate_slotnr(argc, argv, 1);
122 int enable;
123
124 if (slotnr < 0)
125 return;
126
127 if (argc < 3) {
128 printf("You have to specify 0=disable or 1=enable\r\n");
129 return;
130 }
131 enable = atoi(argv[2]);
132 ncn8025_get(slotnr, &settings);
133 if (enable)
134 settings.rstin = true;
135 else
136 settings.rstin = false;
137 ncn8025_set(slotnr, &settings);
138}
139
140DEFUN(sim_clkdiv, cmd_sim_clkdiv, "sim-clkdiv", "Set SIM clock divider (1,2,4,8)")
141{
142 struct ncn8025_settings settings;
143 int slotnr = validate_slotnr(argc, argv, 1);
144 int clkdiv;
145
146 if (slotnr < 0)
147 return;
148
149 if (argc < 3) {
150 printf("You have to specify a valid divider (1,2,4,8)\r\n");
151 return;
152 }
153 clkdiv = atoi(argv[2]);
154 if (clkdiv != 1 && clkdiv != 2 && clkdiv != 4 && clkdiv != 8) {
155 printf("You have to specify a valid divider (1,2,4,8)\r\n");
156 return;
157 }
158 ncn8025_get(slotnr, &settings);
159 switch (clkdiv) {
160 case 1:
161 settings.clkdiv = SIM_CLKDIV_1;
162 break;
163 case 2:
164 settings.clkdiv = SIM_CLKDIV_2;
165 break;
166 case 4:
167 settings.clkdiv = SIM_CLKDIV_4;
168 break;
169 case 8:
170 settings.clkdiv = SIM_CLKDIV_8;
171 break;
172 }
173 ncn8025_set(slotnr, &settings);
174}
175
176DEFUN(sim_voltage, cmd_sim_voltage, "sim-voltage", "Set SIM voltage (5/3/1.8)")
177{
178 struct ncn8025_settings settings;
179 int slotnr = validate_slotnr(argc, argv, 1);
180
181 if (slotnr < 0)
182 return;
183
184 if (argc < 3) {
185 printf("You have to specify a valid voltage (5/3/1.8)\r\n");
186 return;
187 }
188 ncn8025_get(slotnr, &settings);
189 if (!strcmp(argv[2], "5"))
190 settings.vsel = SIM_VOLT_5V0;
191 else if (!strcmp(argv[2], "3"))
192 settings.vsel = SIM_VOLT_3V0;
193 else if (!strcmp(argv[2], "1.8"))
194 settings.vsel = SIM_VOLT_1V8;
195 else {
196 printf("You have to specify a valid voltage (5/3/1.8)\r\n");
197 return;
198 }
199 ncn8025_set(slotnr, &settings);
200}
201
202DEFUN(sim_led, cmd_sim_led, "sim-led", "Set SIM LED (1=on, 0=off)")
203{
204 struct ncn8025_settings settings;
205 int slotnr = validate_slotnr(argc, argv, 1);
206
207 if (slotnr < 0)
208 return;
209
210 if (argc < 3) {
211 printf("You have to specify 0=disable or 1=enable\r\n");
212 return;
213 }
214 ncn8025_get(slotnr, &settings);
215 if (atoi(argv[2]))
216 settings.led = true;
217 else
218 settings.led = false;
219 ncn8025_set(slotnr, &settings);
220}
221
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200222DEFUN(sim_atr, cmd_sim_atr, "sim-atr", "Read ATR from SIM card")
223{
224 struct ncn8025_settings settings;
225 int slotnr = validate_slotnr(argc, argv, 1);
Harald Welte1b9a5b82019-02-24 23:04:45 +0100226
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200227 if (slotnr < 0 || slotnr >= ARRAY_SIZE(SIM_peripheral_descriptors) || NULL == SIM_peripheral_descriptors[slotnr]) {
228 return;
229 }
230
231 // check if card is present (and read current settings)
232 ncn8025_get(slotnr, &settings);
233 if (!settings.simpres) {
234 printf("no card present in slot %d, aborting\r\n", slotnr);
235 return;
236 }
237
238 // switch card off (assert reset and disable power)
239 // note: ISO/IEC 7816-3:2006 section 6.4 provides the deactivation sequence, but not the minimum corresponding times
240 settings.rstin = true;
241 settings.cmdvcc = false;
Harald Weltedcf57832019-04-17 17:29:41 +0200242 settings.led = true;
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200243 ncn8025_set(slotnr, &settings);
244
245 // TODO wait some time for card to be completely deactivated
246 usart_async_flush_rx_buffer(SIM_peripheral_descriptors[slotnr]); // flush RX buffer to start from scratch
247
248 //usart_async_set_baud_rate(SIM_peripheral_descriptors[slotnr], 2500000 / (372 / 1)); // set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1)
249 // set clock to lowest frequency (20 MHz / 8 = 2.5 MHz)
250 // 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
251 settings.clkdiv = SIM_CLKDIV_8;
252 // set card voltage to 3.0 V (the most supported)
253 // note: according to ISO/IEC 7816-3:2006 no voltage should damage the card, and you should cycle from low to high
254 settings.vsel = SIM_VOLT_3V0;
255 // provide power (the NCN8025 should perform the activation according to spec)
256 // note: activation sequence is documented in ISO/IEC 7816-3:2006 section 6.2
257 settings.cmdvcc = true;
258 ncn8025_set(slotnr, &settings);
259
260 // wait for Tb=400 cycles before re-asserting reset
261 delay_us(400 * 10000 / 2500); // 400 cycles * 1000 for us, 2.5 MHz / 1000 for us
262
263 // de-assert reset to switch card back on
264 settings.rstin = false;
265 ncn8025_set(slotnr, &settings);
266
267 // wait for Tc=40000 cycles for transmission to start
268 uint32_t cycles = 40000;
269 while (cycles && !usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
270 delay_us(10);
271 cycles -= 25; // 10 us = 25 cycles at 2.5 MHz
272 }
273 if (!usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
274 delay_us(12 * 372 / 1 / 2); // wait more than one byte (approximate freq down to 2 MHz)
275 }
276 // verify if one byte has been received
277 if (!usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
278 printf("card in slot %d is not responding, aborting\r\n", slotnr);
279 return;
280 }
281
282 // read ATR (just do it until there is no traffic anymore)
283 // TODO the ATR should be parsed to read the right number of bytes
Harald Welte07725812019-04-17 17:30:28 +0200284 printf("(%d) ATR: ", slotnr);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200285 uint8_t atr_byte;
286 while (usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
287 if (1 == io_read(&SIM_peripheral_descriptors[slotnr]->io, &atr_byte, 1)) {
288 printf("%02x ", atr_byte);
289 }
290 uint16_t wt = 9600; // waiting time in ETU
291 while (wt && !usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
292 delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
293 wt--;
294 }
295 }
296 printf("\r\n");
Harald Weltedcf57832019-04-17 17:29:41 +0200297
298 /* disable VCC and LED, re-enable RST */
299 settings.cmdvcc = false;
300 settings.rstin = true;
301 settings.led = false;
302 ncn8025_set(slotnr, &settings);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200303}
Harald Welte1b9a5b82019-02-24 23:04:45 +0100304
Harald Welte67b2aba2019-04-16 20:47:22 +0200305extern void testmode_init(void);
Harald Welte1b9a5b82019-02-24 23:04:45 +0100306
Kévin Redon69b92d92019-01-24 16:39:20 +0100307int main(void)
308{
309 atmel_start_init();
Kévin Redon78d2f442019-01-24 18:45:59 +0100310
Kévin Redon8e538002019-01-30 11:19:19 +0100311 usb_start();
312
Harald Weltec3f170d2019-02-24 09:06:59 +0100313 board_init();
Harald Welteff9f4ce2019-02-24 22:51:09 +0100314 command_init("sysmoOCTSIM> ");
Harald Welte1b9a5b82019-02-24 23:04:45 +0100315 command_register(&cmd_sim_status);
316 command_register(&cmd_sim_power);
317 command_register(&cmd_sim_reset);
318 command_register(&cmd_sim_clkdiv);
319 command_register(&cmd_sim_voltage);
320 command_register(&cmd_sim_led);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200321 command_register(&cmd_sim_atr);
Harald Welte67b2aba2019-04-16 20:47:22 +0200322 testmode_init();
Harald Weltec3f170d2019-02-24 09:06:59 +0100323
Harald Welte361ed202019-02-24 21:15:39 +0100324 printf("\r\n\r\nsysmocom sysmoOCTSIM\r\n");
Harald Weltee7aa5342019-04-16 21:11:14 +0200325
326 command_print_prompt();
Kévin Redon8e538002019-01-30 11:19:19 +0100327 while (true) { // main loop
Harald Welteff9f4ce2019-02-24 22:51:09 +0100328 command_try_recv();
Kévin Redon8e538002019-01-30 11:19:19 +0100329 }
Kévin Redon69b92d92019-01-24 16:39:20 +0100330}