blob: 4bda38acced84fc68325f9e8568fc439c59266ae [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>
Kévin Redon072951b2019-05-02 15:17:46 +020021#include <math.h>
Harald Weltef53f2262019-02-24 11:01:08 +010022#include <parts.h>
23#include <hal_cache.h>
Harald Welte93f628a2019-02-24 14:32:30 +010024#include <hri_port_e54.h>
Harald Weltef53f2262019-02-24 11:01:08 +010025
Kévin Redon69b92d92019-01-24 16:39:20 +010026#include "atmel_start.h"
27#include "atmel_start_pins.h"
Kévin Redon072951b2019-05-02 15:17:46 +020028#include "config/hpl_gclk_config.h"
Kévin Redon69b92d92019-01-24 16:39:20 +010029
Harald Weltec3f170d2019-02-24 09:06:59 +010030#include "i2c_bitbang.h"
31#include "octsim_i2c.h"
32#include "ncn8025.h"
Kévin Redon0f050722019-05-02 15:56:25 +020033#include "iso7816_3.h"
Harald Weltec3f170d2019-02-24 09:06:59 +010034
Harald Welteff9f4ce2019-02-24 22:51:09 +010035#include "command.h"
36
Kévin Redonc89bb8c2019-04-17 01:20:23 +020037// TODO put declaration in more global file
38// TODO for now SIM7 is not present because used for debug
39static struct usart_async_descriptor* SIM_peripheral_descriptors[] = {&SIM0, &SIM1, &SIM2, &SIM3, &SIM4, &SIM5, &SIM6, NULL};
40
Kévin Redon096c5052019-05-09 15:01:17 +020041/** number of bytes transmitted on the SIM peripheral */
42static volatile bool SIM_tx_count[8];
43
Kévin Redonc89bb8c2019-04-17 01:20:23 +020044static void SIM_rx_cb(const struct usart_async_descriptor *const io_descr)
45{
46}
Kévin Redon78d2f442019-01-24 18:45:59 +010047
Kévin Redon096c5052019-05-09 15:01:17 +020048/** called when the transmission is complete
49 * e.g. this is when the byte has been sent and there is no data to transmit anymore
50 */
51static void SIM_tx_cb(const struct usart_async_descriptor *const io_descr)
52{
53 // find slotnr for corresponding USART
54 uint8_t slotnr;
55 for (slotnr = 0; slotnr < ARRAY_SIZE(SIM_peripheral_descriptors) && SIM_peripheral_descriptors[slotnr] != io_descr; slotnr++);
56
57 // set flag
58 if (slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)) {
59 SIM_tx_count[slotnr] = true;
60 }
61}
62
Kévin Redon072951b2019-05-02 15:17:46 +020063/** possible clock sources for the SERCOM peripheral
64 * warning: the definition must match the GCLK configuration
65 */
66static const uint8_t sercom_glck_sources[] = {GCLK_PCHCTRL_GEN_GCLK2_Val, GCLK_PCHCTRL_GEN_GCLK4_Val, GCLK_PCHCTRL_GEN_GCLK6_Val};
67
68/** possible clock frequencies in MHz for the SERCOM peripheral
69 * warning: the definition must match the GCLK configuration
70 */
71static const double sercom_glck_freqs[] = {100E6 / CONF_GCLK_GEN_2_DIV, 100E6 / CONF_GCLK_GEN_4_DIV, 120E6 / CONF_GCLK_GEN_6_DIV};
72
73/** the GCLK ID for the SERCOM SIM peripherals
74 * @note: used as index for PCHCTRL
75 */
76static 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};
77
Harald Weltec3f170d2019-02-24 09:06:59 +010078static void board_init()
79{
80 int i;
81
82 for (i = 0; i < 4; i++)
83 i2c_init(&i2c[i]);
84
Harald Welte255da5e2019-04-16 18:19:53 +020085 for (i = 0; i < 8; i++)
Harald Weltec3f170d2019-02-24 09:06:59 +010086 ncn8025_init(i);
Harald Weltef53f2262019-02-24 11:01:08 +010087
88 cache_init();
89 cache_enable(CMCC);
Harald Welte93f628a2019-02-24 14:32:30 +010090
91 /* increase drive strength of 20Mhz SIM clock output to 8mA
92 * (there are 8 inputs + traces to drive!) */
93 hri_port_set_PINCFG_DRVSTR_bit(PORT, 0, 11);
Kévin Redonc89bb8c2019-04-17 01:20:23 +020094
95 // enable SIM interfaces
96 for (uint8_t i = 0; i < ARRAY_SIZE(SIM_peripheral_descriptors); i++) {
97 if (NULL == SIM_peripheral_descriptors[i]) {
98 continue;
99 }
100 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
Kévin Redon096c5052019-05-09 15:01:17 +0200101 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
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200102 usart_async_enable(SIM_peripheral_descriptors[i]);
103 }
Harald Weltec3f170d2019-02-24 09:06:59 +0100104}
105
Harald Welte1b9a5b82019-02-24 23:04:45 +0100106static int validate_slotnr(int argc, char **argv, int idx)
107{
108 int slotnr;
109 if (argc < idx+1) {
110 printf("You have to specify the slot number (0..7)\r\n");
111 return -1;
112 }
113 slotnr = atoi(argv[idx]);
114 if (slotnr < 0 || slotnr > 7) {
115 printf("You have to specify the slot number (0..7)\r\n");
116 return -1;
117 }
118 return slotnr;
119}
120
Kévin Redon072951b2019-05-02 15:17:46 +0200121/** change baud rate of card slot
122 * @param[in] slotnr slot number for which the baud rate should be set
123 * @param[in] baudrate baud rate in bps to set
124 * @return if the baud rate has been set, else a parameter is out of range
125 */
126static bool slot_set_baudrate(uint8_t slotnr, uint32_t baudrate)
127{
128 ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
129
130 // calculate the error corresponding to the clock sources
131 uint16_t bauds[ARRAY_SIZE(sercom_glck_freqs)];
132 double errors[ARRAY_SIZE(sercom_glck_freqs)];
133 for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {
134 double freq = sercom_glck_freqs[i]; // remember possible SERCOM frequency
135 uint32_t min = freq / (2 * (255 + 1)); // calculate the minimum baud rate for this frequency
136 uint32_t max = freq / (2 * (0 + 1)); // calculate the maximum baud rate for this frequency
137 if (baudrate < min || baudrate > max) { // baud rate it out of supported range
138 errors[i] = NAN;
139 } else {
140 uint16_t baud = round(freq / (2 * baudrate) - 1);
141 bauds[i] = baud;
142 double actual = freq / (2 * (baud + 1));
143 errors[i] = fabs(1.0 - (actual / baudrate));
144 }
145 }
146
147 // find the smallest error
148 uint8_t best = ARRAY_SIZE(sercom_glck_freqs);
149 for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {
150 if (isnan(errors[i])) {
151 continue;
152 }
153 if (best >= ARRAY_SIZE(sercom_glck_freqs)) {
154 best = i;
155 } else if (errors[i] < errors[best]) {
156 best = i;
157 }
158 }
159 if (best >= ARRAY_SIZE(sercom_glck_freqs)) { // found no clock supporting this baud rate
160 return false;
161 }
162
163 // set clock and baud rate
164 struct usart_async_descriptor* slot = SIM_peripheral_descriptors[slotnr]; // get slot
165 if (NULL == slot) {
166 return false;
167 }
168 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]);
169 while (!usart_async_is_tx_empty(slot)); // wait for transmission to complete (WARNING no timeout)
170 usart_async_disable(slot); // disable SERCOM peripheral
171 hri_gclk_clear_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos)); // disable clock for this peripheral
172 while (hri_gclk_get_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos))); // wait until clock is really disabled
173 // it does not seem we need to completely disable the peripheral using hri_mclk_clear_APBDMASK_SERCOMn_bit
174 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
175 usart_async_set_baud_rate(slot, bauds[best]); // set the new baud rate
176 usart_async_enable(slot); // re-enable SERCOM peripheral
177
178 return true;
179}
180
Kévin Redon0f050722019-05-02 15:56:25 +0200181/** change ISO baud rate of card slot
182 * @param[in] slotnr slot number for which the baud rate should be set
183 * @param[in] clkdiv can clock divider
184 * @param[in] f clock rate conversion integer F
185 * @param[in] d baud rate adjustment factor D
186 * @return if the baud rate has been set, else a parameter is out of range
187 */
188static bool slot_set_isorate(uint8_t slotnr, enum ncn8025_sim_clkdiv clkdiv, uint16_t f, uint8_t d)
189{
190 // input checks
191 ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
192 if (clkdiv != SIM_CLKDIV_1 && clkdiv != SIM_CLKDIV_2 && clkdiv != SIM_CLKDIV_4 && clkdiv != SIM_CLKDIV_8) {
193 return false;
194 }
195 if (!iso7816_3_valid_f(f)) {
196 return false;
197 }
198 if (!iso7816_3_valid_d(d)) {
199 return false;
200 }
201
202 // set clockdiv
203 struct ncn8025_settings settings;
204 ncn8025_get(slotnr, &settings);
205 if (settings.clkdiv != clkdiv) {
206 settings.clkdiv = clkdiv;
207 ncn8025_set(slotnr, &settings);
208 }
209
210 // calculate desired frequency
211 uint32_t freq = 20000000UL; // maximum frequency
212 switch (clkdiv) {
213 case SIM_CLKDIV_1:
214 freq /= 1;
215 break;
216 case SIM_CLKDIV_2:
217 freq /= 2;
218 break;
219 case SIM_CLKDIV_4:
220 freq /= 4;
221 break;
222 case SIM_CLKDIV_8:
223 freq /= 8;
224 break;
225 }
226
227 // set baud rate
228 uint32_t baudrate = (freq * d) / f; // calculate actual baud rate
Kévin Redon5188e9f2019-05-09 17:34:55 +0200229 return slot_set_baudrate(slotnr, baudrate); // set baud rate
230}
231
232/** write data to card
233 * @param[in] slotnr slot number on which to send data
234 * @param[in] data data to be transmitted
235 * @param[in] length length of data to be transmitted
236 * @return error code
237 */
238static int slot_card_write(uint8_t slotnr, const uint8_t* data, uint16_t length)
239{
240 // input checks
241 ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
242 if (0 == length || NULL == data) {
243 return ERR_INVALID_ARG;
244 }
245
246 struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr];
247 ((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 0; // disable receive (to avoid the echo back)
248 SIM_tx_count[slotnr] = false; // reset TX complete
249 for (uint16_t i = 0; i < length; i++) { // transmit data
250 while(!usart_async_is_tx_empty(sim)); // wait for previous byte to be transmitted (WARNING blocking)
251 if (1 != io_write(&sim->io, &data[i], 1)) { // put but in transmit buffer
252 return ERR_IO;
253 }
254 }
255 while (!SIM_tx_count[slotnr]); // wait until transmission is complete (WARNING blocking)
256 ((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1; // enable receive again
257
258 return ERR_NONE;
259}
260
261/** read data from card
262 * @param[in] slotnr slot number on which to send data
263 * @param[out] data buffer for read data to be stored
264 * @param[in] length length of data to be read
265 * @param[in] wt Waiting Time in ETU
266 * @return error code
267 * TODO fix WT/ETU duration
268 */
269static int slot_card_read(uint8_t slotnr, uint8_t* data, uint16_t length, uint32_t wt)
270{
271 // input checks
272 ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
273 if (0 == length || NULL == data) {
274 return ERR_INVALID_ARG;
275 }
276
277 struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr];
278
279 ((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1; // ensure RX is enabled
280 uint32_t timeout = wt; // reset waiting time
281 for (uint16_t i = 0; i < length; i++) { // read all data
282 while (timeout && !usart_async_is_rx_not_empty(sim)) { // verify if data is present
283 delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
284 timeout--;
285 }
286 if (0 == timeout) { // timeout reached
287 return ERR_TIMEOUT;
288 }
289 timeout = wt; // reset waiting time
290 if (1 != io_read(&sim->io, &data[i], 1)) { // read one byte
291 return ERR_IO;
292 }
293 }
294
295 return ERR_NONE;
296}
297
298/** transfer TPDU
299 * @param[in] slotnr slot number on which to transfer the TPDU
300 * @param[in] header TPDU header to send
301 * @param[io] data TPDU data to transfer
302 * @param[in] data_length length of TPDU data to transfer
303 * @param[in] write if the data should be written (true) or read (false)
304 * TODO fix WT
305 * TODO the data length can be deduce from the header
306 */
307static int slot_tpdu_xfer(uint8_t slotnr, const uint8_t* header, uint8_t* data, uint16_t data_length, bool write)
308{
309 // input checks
310 ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
311 if (NULL == header || (data_length > 0 && NULL == data)) {
312 return ERR_INVALID_ARG;
313 }
314
315 int rc;
316 struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr]; // get USART peripheral
317 usart_async_flush_rx_buffer(sim); // flush RX buffer to start from scratch
318
319 // send command header
320 printf("(%d) TPDU: ", slotnr);
321 for (uint8_t i = 0; i < 5; i++) {
322 printf("%02x ", header[i]);
323 }
324 rc = slot_card_write(slotnr, header, 5); // transmit header
325 if (ERR_NONE != rc) {
326 printf("error in command header transmit (errno = %d)\r\n", rc);
327 return rc;
328 }
329
330 // read procedure byte, and handle data
331 uint8_t pb = 0x60; // wait more procedure byte
332 uint16_t data_i = 0; // progress in the data transfer
333 while (0x60 == pb) { // wait for SW
334 rc = slot_card_read(slotnr, &pb, 1, ISO7816_3_DEFAULT_WT);
335 if (ERR_NONE != rc) {
336 printf("error while receiving PB/SW1 (errno = %d)\r\n", rc);
337 return rc;
338 }
339 printf("%02x ", pb);
340 if (0x60 == pb) { // NULL byte
341 // just wait more time
342 } else if ((0x60 == (pb & 0xf0)) || (0x90 == (pb & 0xf0))) { // SW1 byte
343 // left the rest of the code handle it
344 } else if (header[1] == pb) { // ACK byte
345 // transfer rest of the data
346 if (data_i >= data_length) {
347 printf("error no more data to transfer\r\n");
348 return ERR_INVALID_DATA;
349 }
350 if (write) { // transmit remaining command data
351 rc = slot_card_write(slotnr, &data[data_i], data_length - data_i); // transmit command data
352 if (ERR_NONE != rc) {
353 printf("error in command data transmit (errno = %d)\r\n", rc);
354 return rc;
355 }
356 } else { // receive remaining command data
357 rc = slot_card_read(slotnr, &data[data_i], data_length - data_i, ISO7816_3_DEFAULT_WT);
358 if (ERR_NONE != rc) {
359 printf("error in command data receive (errno = %d)\r\n", rc);
360 return rc;
361 }
362 }
363 for (uint16_t i = data_i; i < data_length; i++) {
364 printf("%02x ", data[i]);
365 }
366 data_i = data_length; // remember we transferred the data
367 pb = 0x60; // wait for SW1
368 } else if (header[1] == (pb ^ 0xff)) { // ACK byte
369 // transfer only one byte
370 if (data_i >= data_length) {
371 printf("error no more data to transfer\r\n");
372 return ERR_INVALID_DATA;
373 }
374 if (write) { // transmit command data byte
375 rc = slot_card_write(slotnr, &data[data_i], 1); // transmit command data
376 if (ERR_NONE != rc) {
377 printf("error in command data transmit (errno = %d)\r\n", rc);
378 return rc;
379 }
380 } else { // receive command data byte
381 rc = slot_card_read(slotnr, &data[data_i], 1, ISO7816_3_DEFAULT_WT);
382 if (ERR_NONE != rc) {
383 printf("error in command data receive (errno = %d)\r\n", rc);
384 return rc;
385 }
386 }
387 printf("%02x ", data[data_i]);
388 data_i += 1; // remember we transferred one data byte
389 pb = 0x60; // wait for SW1
390 } else { // invalid byte
391 return ERR_INVALID_DATA;
392 }
393 }
394
395 // read SW2
396 uint8_t sw2;
397 rc = slot_card_read(slotnr, &sw2, 1, ISO7816_3_DEFAULT_WT);
398 if (ERR_NONE != rc) {
399 printf("error in receiving SW2 (errno = %d)\r\n", rc);
400 return rc;
401 }
402 printf("%02x", sw2);
403
404 printf("\r\n");
405 return ERR_NONE;
Kévin Redon0f050722019-05-02 15:56:25 +0200406}
407
Harald Welte1b9a5b82019-02-24 23:04:45 +0100408DEFUN(sim_status, cmd_sim_status, "sim-status", "Get state of specified NCN8025")
409{
410 struct ncn8025_settings settings;
411 int slotnr = validate_slotnr(argc, argv, 1);
412 if (slotnr < 0)
413 return;
414 ncn8025_get(slotnr, &settings);
415 printf("SIM%d: ", slotnr);
416 ncn8025_dump(&settings);
417 printf("\r\n");
418}
419
420DEFUN(sim_power, cmd_sim_power, "sim-power", "Enable/disable SIM card power")
421{
422 struct ncn8025_settings settings;
423 int slotnr = validate_slotnr(argc, argv, 1);
424 int enable;
425
426 if (slotnr < 0)
427 return;
428
429 if (argc < 3) {
430 printf("You have to specify 0=disable or 1=enable\r\n");
431 return;
432 }
433 enable = atoi(argv[2]);
434 ncn8025_get(slotnr, &settings);
435 if (enable)
436 settings.cmdvcc = true;
437 else
438 settings.cmdvcc = false;
439 ncn8025_set(slotnr, &settings);
440}
441
442DEFUN(sim_reset, cmd_sim_reset, "sim-reset", "Enable/disable SIM reset")
443{
444 struct ncn8025_settings settings;
445 int slotnr = validate_slotnr(argc, argv, 1);
446 int enable;
447
448 if (slotnr < 0)
449 return;
450
451 if (argc < 3) {
452 printf("You have to specify 0=disable or 1=enable\r\n");
453 return;
454 }
455 enable = atoi(argv[2]);
456 ncn8025_get(slotnr, &settings);
457 if (enable)
458 settings.rstin = true;
459 else
460 settings.rstin = false;
461 ncn8025_set(slotnr, &settings);
462}
463
464DEFUN(sim_clkdiv, cmd_sim_clkdiv, "sim-clkdiv", "Set SIM clock divider (1,2,4,8)")
465{
466 struct ncn8025_settings settings;
467 int slotnr = validate_slotnr(argc, argv, 1);
468 int clkdiv;
469
470 if (slotnr < 0)
471 return;
472
473 if (argc < 3) {
474 printf("You have to specify a valid divider (1,2,4,8)\r\n");
475 return;
476 }
477 clkdiv = atoi(argv[2]);
478 if (clkdiv != 1 && clkdiv != 2 && clkdiv != 4 && clkdiv != 8) {
479 printf("You have to specify a valid divider (1,2,4,8)\r\n");
480 return;
481 }
482 ncn8025_get(slotnr, &settings);
483 switch (clkdiv) {
484 case 1:
485 settings.clkdiv = SIM_CLKDIV_1;
486 break;
487 case 2:
488 settings.clkdiv = SIM_CLKDIV_2;
489 break;
490 case 4:
491 settings.clkdiv = SIM_CLKDIV_4;
492 break;
493 case 8:
494 settings.clkdiv = SIM_CLKDIV_8;
495 break;
496 }
497 ncn8025_set(slotnr, &settings);
498}
499
500DEFUN(sim_voltage, cmd_sim_voltage, "sim-voltage", "Set SIM voltage (5/3/1.8)")
501{
502 struct ncn8025_settings settings;
503 int slotnr = validate_slotnr(argc, argv, 1);
504
505 if (slotnr < 0)
506 return;
507
508 if (argc < 3) {
509 printf("You have to specify a valid voltage (5/3/1.8)\r\n");
510 return;
511 }
512 ncn8025_get(slotnr, &settings);
513 if (!strcmp(argv[2], "5"))
514 settings.vsel = SIM_VOLT_5V0;
515 else if (!strcmp(argv[2], "3"))
516 settings.vsel = SIM_VOLT_3V0;
517 else if (!strcmp(argv[2], "1.8"))
518 settings.vsel = SIM_VOLT_1V8;
519 else {
520 printf("You have to specify a valid voltage (5/3/1.8)\r\n");
521 return;
522 }
523 ncn8025_set(slotnr, &settings);
524}
525
526DEFUN(sim_led, cmd_sim_led, "sim-led", "Set SIM LED (1=on, 0=off)")
527{
528 struct ncn8025_settings settings;
529 int slotnr = validate_slotnr(argc, argv, 1);
530
531 if (slotnr < 0)
532 return;
533
534 if (argc < 3) {
535 printf("You have to specify 0=disable or 1=enable\r\n");
536 return;
537 }
538 ncn8025_get(slotnr, &settings);
539 if (atoi(argv[2]))
540 settings.led = true;
541 else
542 settings.led = false;
543 ncn8025_set(slotnr, &settings);
544}
545
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200546DEFUN(sim_atr, cmd_sim_atr, "sim-atr", "Read ATR from SIM card")
547{
548 struct ncn8025_settings settings;
549 int slotnr = validate_slotnr(argc, argv, 1);
Harald Welte1b9a5b82019-02-24 23:04:45 +0100550
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200551 if (slotnr < 0 || slotnr >= ARRAY_SIZE(SIM_peripheral_descriptors) || NULL == SIM_peripheral_descriptors[slotnr]) {
552 return;
553 }
554
555 // check if card is present (and read current settings)
556 ncn8025_get(slotnr, &settings);
557 if (!settings.simpres) {
Kévin Redon096c5052019-05-09 15:01:17 +0200558 printf("(%d) error: no card present\r\n", slotnr);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200559 return;
560 }
561
562 // switch card off (assert reset and disable power)
563 // note: ISO/IEC 7816-3:2006 section 6.4 provides the deactivation sequence, but not the minimum corresponding times
564 settings.rstin = true;
565 settings.cmdvcc = false;
Harald Weltedcf57832019-04-17 17:29:41 +0200566 settings.led = true;
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200567 ncn8025_set(slotnr, &settings);
568
569 // TODO wait some time for card to be completely deactivated
570 usart_async_flush_rx_buffer(SIM_peripheral_descriptors[slotnr]); // flush RX buffer to start from scratch
571
Kévin Redon0f050722019-05-02 15:56:25 +0200572
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200573 // set clock to lowest frequency (20 MHz / 8 = 2.5 MHz)
574 // 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
575 settings.clkdiv = SIM_CLKDIV_8;
Kévin Redon0f050722019-05-02 15:56:25 +0200576 // set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1)
577 slot_set_isorate(slotnr, settings.clkdiv, ISO7816_3_DEFAULT_FD, ISO7816_3_DEFAULT_DD);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200578 // set card voltage to 3.0 V (the most supported)
579 // note: according to ISO/IEC 7816-3:2006 no voltage should damage the card, and you should cycle from low to high
580 settings.vsel = SIM_VOLT_3V0;
581 // provide power (the NCN8025 should perform the activation according to spec)
582 // note: activation sequence is documented in ISO/IEC 7816-3:2006 section 6.2
583 settings.cmdvcc = true;
584 ncn8025_set(slotnr, &settings);
585
586 // wait for Tb=400 cycles before re-asserting reset
587 delay_us(400 * 10000 / 2500); // 400 cycles * 1000 for us, 2.5 MHz / 1000 for us
588
589 // de-assert reset to switch card back on
590 settings.rstin = false;
591 ncn8025_set(slotnr, &settings);
592
593 // wait for Tc=40000 cycles for transmission to start
594 uint32_t cycles = 40000;
595 while (cycles && !usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
596 delay_us(10);
597 cycles -= 25; // 10 us = 25 cycles at 2.5 MHz
598 }
599 if (!usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
600 delay_us(12 * 372 / 1 / 2); // wait more than one byte (approximate freq down to 2 MHz)
601 }
602 // verify if one byte has been received
603 if (!usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
Kévin Redon096c5052019-05-09 15:01:17 +0200604 printf("(%d) error: card not responsive\r\n", slotnr);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200605 return;
606 }
607
608 // read ATR (just do it until there is no traffic anymore)
Kévin Redon096c5052019-05-09 15:01:17 +0200609 // TODO the ATR should be parsed to read the right number of bytes, instead we just wait until to end of WT
Harald Welte07725812019-04-17 17:30:28 +0200610 printf("(%d) ATR: ", slotnr);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200611 uint8_t atr_byte;
612 while (usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
613 if (1 == io_read(&SIM_peripheral_descriptors[slotnr]->io, &atr_byte, 1)) {
614 printf("%02x ", atr_byte);
615 }
Kévin Redon096c5052019-05-09 15:01:17 +0200616 uint16_t wt = ISO7816_3_DEFAULT_WT; // waiting time in ETU
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200617 while (wt && !usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
618 delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
619 wt--;
620 }
621 }
622 printf("\r\n");
Harald Weltedcf57832019-04-17 17:29:41 +0200623
Kévin Redon096c5052019-05-09 15:01:17 +0200624 /* disable LED */
625 settings.led = false;
626 ncn8025_set(slotnr, &settings);
627}
628
629DEFUN(sim_iccid, cmd_sim_iccid, "sim-iccid", "Read ICCID from SIM card")
630{
631 struct ncn8025_settings settings;
632 int slotnr = validate_slotnr(argc, argv, 1);
633
634 if (slotnr < 0 || slotnr >= ARRAY_SIZE(SIM_peripheral_descriptors) || NULL == SIM_peripheral_descriptors[slotnr]) {
635 return;
636 }
637
638 // read current settings and check if card is present and powered
639 ncn8025_get(slotnr, &settings);
640 if (!settings.simpres) {
641 printf("(%d) error: no card present\r\n", slotnr);
642 return;
643 }
644 if (!settings.cmdvcc) {
645 printf("(%d) error: card not powered\r\n", slotnr);
646 return;
647 }
648 if (settings.rstin) {
649 printf("(%d) error: card under reset\r\n", slotnr);
650 return;
651 }
652
653 // enable LED
654 if (!settings.led) {
655 settings.led = true;
656 ncn8025_set(slotnr, &settings);
657 }
658
Kévin Redon5188e9f2019-05-09 17:34:55 +0200659 // select MF
660 printf("(%d) SELECT MF\r\n", slotnr);
Kévin Redon36efc6d2019-05-09 18:03:20 +0200661 const uint8_t select_header[] = {0xa0, 0xa4, 0x00, 0x00, 0x02}; // see TS 102.221 sec. 11.1.1
662 const uint8_t select_data_mf[] = {0x3f, 0x00}; // see TS 102.221 sec. 13.1
663 int rc = slot_tpdu_xfer(slotnr, select_header, (uint8_t*)select_data_mf, ARRAY_SIZE(select_data_mf), true); // transfer TPDU
Kévin Redon5188e9f2019-05-09 17:34:55 +0200664 if (ERR_NONE != rc) {
665 printf("error while SELECT MF (errno = %d)\r\n", rc);
Kévin Redon096c5052019-05-09 15:01:17 +0200666 }
Kévin Redon36efc6d2019-05-09 18:03:20 +0200667 // ignore response data
668
669 // select EF_ICCID
670 printf("(%d) SELECT EF_ICCID\r\n", slotnr);
671 const uint8_t select_data_ef_iccid[] = {0x2f, 0xe2}; // see TS 102.221 sec. 13.2
672 rc = slot_tpdu_xfer(slotnr, select_header, (uint8_t*)select_data_ef_iccid, ARRAY_SIZE(select_data_ef_iccid), true); // transfer TPDU
673 if (ERR_NONE != rc) {
674 printf("error while SELECT EF_ICCID (errno = %d)\r\n", rc);
675 }
676 // ignore response data
677
678 // read EF_ICCID
679 printf("(%d) READ EF_ICCID\r\n", slotnr);
680 uint8_t iccid[10];
681 uint8_t read_binary[] = {0xa0, 0xb0, 0x00, 0x00, ARRAY_SIZE(iccid)}; // see TS 102.221 sec. 11.1.3
682 rc = slot_tpdu_xfer(slotnr, read_binary, iccid, ARRAY_SIZE(iccid), false); // transfer TPDU
683 if (ERR_NONE != rc) {
684 printf("error while READ ICCID (errno = %d)\r\n", rc);
685 }
686 // ignore response data
687
688 printf("(%d) ICCID: ", slotnr);
689 for (uint8_t i = 0; i < ARRAY_SIZE(iccid); i++) {
690 uint8_t nibble = iccid[i] & 0xf;
691 if (0xf == nibble) {
692 break;
693 }
694 printf("%x", nibble);
695 nibble = iccid[i] >> 4;
696 if (0xf == nibble) {
697 break;
698 }
699 printf("%x", nibble);
700 }
701 printf("\r\n");
Kévin Redon096c5052019-05-09 15:01:17 +0200702
703 // disable LED
Harald Weltedcf57832019-04-17 17:29:41 +0200704 settings.led = false;
705 ncn8025_set(slotnr, &settings);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200706}
Harald Welte1b9a5b82019-02-24 23:04:45 +0100707
Harald Welte67b2aba2019-04-16 20:47:22 +0200708extern void testmode_init(void);
Harald Welte1b9a5b82019-02-24 23:04:45 +0100709
Harald Welte8049d662019-04-17 21:19:18 +0200710#include "talloc.h"
Harald Welte3304ca22019-04-17 22:08:57 +0200711#include <osmocom/core/msgb.h>
Harald Welte8049d662019-04-17 21:19:18 +0200712void *g_tall_ctx;
713
714DEFUN(_talloc_report, cmd_talloc_report, "talloc-report", "Generate a talloc report")
715{
716 talloc_report_full(g_tall_ctx, stdout);
717}
718
719DEFUN(talloc_test, cmd_talloc_test, "talloc-test", "Test the talloc allocator")
720{
721 for (int i = 0; i < 10; i++)
722 talloc_named_const(g_tall_ctx, 10, "sibling");
Harald Welte3304ca22019-04-17 22:08:57 +0200723 msgb_alloc_c(g_tall_ctx, 1024, "foo");
Harald Welte8049d662019-04-17 21:19:18 +0200724}
725
726DEFUN(v_talloc_free, cmd_talloc_free, "talloc-free", "Release all memory")
727{
728 talloc_free(g_tall_ctx);
729 g_tall_ctx = NULL;
730}
731
Harald Welte3304ca22019-04-17 22:08:57 +0200732/* dependency of libosmocore. FIXME: Implement it bsed on jiffies and/or RTC! */
733#include <sys/time.h>
734int _gettimeofday(struct timeval *tv, void *tz)
735{
736 tv->tv_sec = 0;
737 tv->tv_usec = 0;
738 return 0;
739}
740
Kévin Redon69b92d92019-01-24 16:39:20 +0100741int main(void)
742{
743 atmel_start_init();
Kévin Redon78d2f442019-01-24 18:45:59 +0100744
Kévin Redon8e538002019-01-30 11:19:19 +0100745 usb_start();
746
Harald Weltec3f170d2019-02-24 09:06:59 +0100747 board_init();
Harald Welteff9f4ce2019-02-24 22:51:09 +0100748 command_init("sysmoOCTSIM> ");
Harald Welte1b9a5b82019-02-24 23:04:45 +0100749 command_register(&cmd_sim_status);
750 command_register(&cmd_sim_power);
751 command_register(&cmd_sim_reset);
752 command_register(&cmd_sim_clkdiv);
753 command_register(&cmd_sim_voltage);
754 command_register(&cmd_sim_led);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200755 command_register(&cmd_sim_atr);
Kévin Redon096c5052019-05-09 15:01:17 +0200756 command_register(&cmd_sim_iccid);
Harald Welte67b2aba2019-04-16 20:47:22 +0200757 testmode_init();
Harald Welte8049d662019-04-17 21:19:18 +0200758 command_register(&cmd_talloc_test);
759 command_register(&cmd_talloc_report);
760 command_register(&cmd_talloc_free);
Harald Weltec3f170d2019-02-24 09:06:59 +0100761
Harald Welte361ed202019-02-24 21:15:39 +0100762 printf("\r\n\r\nsysmocom sysmoOCTSIM\r\n");
Harald Weltee7aa5342019-04-16 21:11:14 +0200763
Harald Welte8049d662019-04-17 21:19:18 +0200764 talloc_enable_null_tracking();
765 g_tall_ctx = talloc_named_const(NULL, 0, "global");
766 printf("g_tall_ctx=%p\r\n", g_tall_ctx);
767
Harald Weltee7aa5342019-04-16 21:11:14 +0200768 command_print_prompt();
Kévin Redon8e538002019-01-30 11:19:19 +0100769 while (true) { // main loop
Harald Welteff9f4ce2019-02-24 22:51:09 +0100770 command_try_recv();
Kévin Redon8e538002019-01-30 11:19:19 +0100771 }
Kévin Redon69b92d92019-01-24 16:39:20 +0100772}