blob: e3520f2f85f7621df256512383f13d7c83e38ee8 [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>
Harald Welte5a8af4d2019-05-12 15:57:20 +020020#include <inttypes.h>
Harald Welte1b9a5b82019-02-24 23:04:45 +010021#include <stdio.h>
Kévin Redon072951b2019-05-02 15:17:46 +020022#include <math.h>
Harald Weltef53f2262019-02-24 11:01:08 +010023#include <parts.h>
Harald Welte65101be2019-04-18 18:30:49 +020024#include <errno.h>
Harald Weltec7a58ba2019-04-18 17:59:19 +020025
26#include <osmocom/core/utils.h>
27
Harald Weltef53f2262019-02-24 11:01:08 +010028#include <hal_cache.h>
Harald Welte93f628a2019-02-24 14:32:30 +010029#include <hri_port_e54.h>
Harald Weltef53f2262019-02-24 11:01:08 +010030
Kévin Redon69b92d92019-01-24 16:39:20 +010031#include "atmel_start.h"
32#include "atmel_start_pins.h"
Kévin Redon072951b2019-05-02 15:17:46 +020033#include "config/hpl_gclk_config.h"
Kévin Redon69b92d92019-01-24 16:39:20 +010034
Harald Weltec3f170d2019-02-24 09:06:59 +010035#include "i2c_bitbang.h"
36#include "octsim_i2c.h"
37#include "ncn8025.h"
Kévin Redon0f050722019-05-02 15:56:25 +020038#include "iso7816_3.h"
Harald Weltec3f170d2019-02-24 09:06:59 +010039
Harald Welteff9f4ce2019-02-24 22:51:09 +010040#include "command.h"
41
Kévin Redonc89bb8c2019-04-17 01:20:23 +020042// TODO put declaration in more global file
43// TODO for now SIM7 is not present because used for debug
44static struct usart_async_descriptor* SIM_peripheral_descriptors[] = {&SIM0, &SIM1, &SIM2, &SIM3, &SIM4, &SIM5, &SIM6, NULL};
45
Kévin Redon096c5052019-05-09 15:01:17 +020046/** number of bytes transmitted on the SIM peripheral */
47static volatile bool SIM_tx_count[8];
48
Kévin Redonc89bb8c2019-04-17 01:20:23 +020049static void SIM_rx_cb(const struct usart_async_descriptor *const io_descr)
50{
51}
Kévin Redon78d2f442019-01-24 18:45:59 +010052
Kévin Redon096c5052019-05-09 15:01:17 +020053/** called when the transmission is complete
54 * e.g. this is when the byte has been sent and there is no data to transmit anymore
55 */
56static void SIM_tx_cb(const struct usart_async_descriptor *const io_descr)
57{
58 // find slotnr for corresponding USART
59 uint8_t slotnr;
60 for (slotnr = 0; slotnr < ARRAY_SIZE(SIM_peripheral_descriptors) && SIM_peripheral_descriptors[slotnr] != io_descr; slotnr++);
61
62 // set flag
63 if (slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)) {
64 SIM_tx_count[slotnr] = true;
65 }
66}
67
Kévin Redon072951b2019-05-02 15:17:46 +020068/** possible clock sources for the SERCOM peripheral
69 * warning: the definition must match the GCLK configuration
70 */
71static const uint8_t sercom_glck_sources[] = {GCLK_PCHCTRL_GEN_GCLK2_Val, GCLK_PCHCTRL_GEN_GCLK4_Val, GCLK_PCHCTRL_GEN_GCLK6_Val};
72
73/** possible clock frequencies in MHz for the SERCOM peripheral
74 * warning: the definition must match the GCLK configuration
75 */
76static const double sercom_glck_freqs[] = {100E6 / CONF_GCLK_GEN_2_DIV, 100E6 / CONF_GCLK_GEN_4_DIV, 120E6 / CONF_GCLK_GEN_6_DIV};
77
78/** the GCLK ID for the SERCOM SIM peripherals
79 * @note: used as index for PCHCTRL
80 */
81static 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};
82
Harald Weltec7a58ba2019-04-18 17:59:19 +020083static void ccid_app_init(void);
84
Harald Weltec3f170d2019-02-24 09:06:59 +010085static void board_init()
86{
87 int i;
88
89 for (i = 0; i < 4; i++)
90 i2c_init(&i2c[i]);
91
Harald Welte255da5e2019-04-16 18:19:53 +020092 for (i = 0; i < 8; i++)
Harald Weltec3f170d2019-02-24 09:06:59 +010093 ncn8025_init(i);
Harald Weltef53f2262019-02-24 11:01:08 +010094
95 cache_init();
96 cache_enable(CMCC);
Harald Welted1bd5c42019-05-17 16:38:30 +020097 calendar_enable(&CALENDAR_0);
Harald Welte93f628a2019-02-24 14:32:30 +010098
99 /* increase drive strength of 20Mhz SIM clock output to 8mA
100 * (there are 8 inputs + traces to drive!) */
101 hri_port_set_PINCFG_DRVSTR_bit(PORT, 0, 11);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200102
103 // enable SIM interfaces
104 for (uint8_t i = 0; i < ARRAY_SIZE(SIM_peripheral_descriptors); i++) {
105 if (NULL == SIM_peripheral_descriptors[i]) {
106 continue;
107 }
108 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 +0200109 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 +0200110 usart_async_enable(SIM_peripheral_descriptors[i]);
111 }
Harald Weltec7a58ba2019-04-18 17:59:19 +0200112
113 ccid_app_init();
Harald Weltec3f170d2019-02-24 09:06:59 +0100114}
115
Harald Weltec7a58ba2019-04-18 17:59:19 +0200116/***********************************************************************
117 * CCID Driver integration
118 ***********************************************************************/
119
120#include <osmocom/core/linuxlist.h>
121#include <osmocom/core/msgb.h>
122#include "linuxlist_atomic.h"
123#include "ccid_df.h"
124
125struct usb_ep_q {
126 const char *name;
127 /* msgb queue of pending to-be-transmitted (IN/IRQ) or completed received (OUT)
128 * USB transfers */
129 struct llist_head list;
130 /* currently ongoing/processed msgb (USB transmit or receive */
131 struct msgb *in_progress;
132};
133
134struct ccid_state {
135 /* msgb queue of free msgs */
136 struct llist_head free_q;
137
138 /* msgb queue of pending to-be-transmitted (IN EP) */
139 struct usb_ep_q in_ep;
140 /* msgb queue of pending to-be-transmitted (IRQ EP) */
141 struct usb_ep_q irq_ep;
142 /* msgb queue of completed received (OUT EP) */
143 struct usb_ep_q out_ep;
Harald Welte5a8af4d2019-05-12 15:57:20 +0200144
145 /* bit-mask of card-insert status, as determined from NCN8025 IRQ output */
146 uint8_t card_insert_mask;
Harald Weltec7a58ba2019-04-18 17:59:19 +0200147};
148static struct ccid_state g_ccid_s;
149
150static void ccid_out_read_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred);
151static void ccid_in_write_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred);
152static void ccid_irq_write_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred);
153
154static void usb_ep_q_init(struct usb_ep_q *ep_q, const char *name)
155{
156 ep_q->name = name;
157 INIT_LLIST_HEAD(&ep_q->list);
158 ep_q->in_progress = NULL;
159}
160
161static void ccid_app_init(void)
162{
163 /* initialize data structures */
164 INIT_LLIST_HEAD(&g_ccid_s.free_q);
165 usb_ep_q_init(&g_ccid_s.in_ep, "IN");
166 usb_ep_q_init(&g_ccid_s.irq_ep, "IRQ");
167 usb_ep_q_init(&g_ccid_s.out_ep, "OUT");
168
169 /* OUT endpoint read complete callback (irq context) */
170 ccid_df_register_callback(CCID_DF_CB_READ_OUT, (FUNC_PTR)&ccid_out_read_compl);
171 /* IN endpoint write complete callback (irq context) */
172 ccid_df_register_callback(CCID_DF_CB_WRITE_IN, (FUNC_PTR)&ccid_in_write_compl);
173 /* IRQ endpoint write complete callback (irq context) */
174 ccid_df_register_callback(CCID_DF_CB_WRITE_IRQ, (FUNC_PTR)&ccid_irq_write_compl);
175}
176
177/* irqsafe version of msgb_enqueue */
178struct msgb *msgb_dequeue_irqsafe(struct llist_head *q)
179{
180 struct msgb *msg;
181 CRITICAL_SECTION_ENTER()
182 msg = msgb_dequeue(q);
183 CRITICAL_SECTION_LEAVE()
184 return msg;
185}
186
Harald Welte5a8af4d2019-05-12 15:57:20 +0200187void msgb_enqueue_irqsafe(struct llist_head *q, struct msgb *msg)
188{
189 CRITICAL_SECTION_ENTER()
190 msgb_enqueue(q, msg);
191 CRITICAL_SECTION_LEAVE()
192}
193
Harald Weltec7a58ba2019-04-18 17:59:19 +0200194/* submit the next pending (if any) message for the IN EP */
195static int submit_next_in(void)
196{
197 struct usb_ep_q *ep_q = &g_ccid_s.in_ep;
198 struct msgb *msg;
199 int rc;
200
201 OSMO_ASSERT(!ep_q->in_progress);
202 msg = msgb_dequeue_irqsafe(&ep_q->list);
203 if (!msg)
204 return 0;
205
206 ep_q->in_progress = msg;
207 rc = ccid_df_write_in(msgb_data(msg), msgb_length(msg));
208 if (rc != ERR_NONE) {
209 printf("EP %s failed: %d\r\n", ep_q->name, rc);
210 return -1;
211 }
212 return 1;
213
214}
215
216/* submit the next pending (if any) message for the IRQ EP */
217static int submit_next_irq(void)
218{
219 struct usb_ep_q *ep_q = &g_ccid_s.irq_ep;
220 struct msgb *msg;
221 int rc;
222
Eric Wildab193652019-08-27 01:50:10 +0200223 if(ep_q->in_progress)
224 return 0;
225
Harald Weltec7a58ba2019-04-18 17:59:19 +0200226 msg = msgb_dequeue_irqsafe(&ep_q->list);
227 if (!msg)
228 return 0;
229
230 ep_q->in_progress = msg;
231 rc = ccid_df_write_irq(msgb_data(msg), msgb_length(msg));
232 /* may return HALTED/ERROR/DISABLED/BUSY/ERR_PARAM/ERR_FUNC/ERR_DENIED */
233 if (rc != ERR_NONE) {
234 printf("EP %s failed: %d\r\n", ep_q->name, rc);
235 return -1;
236 }
237 return 1;
238}
239
240static int submit_next_out(void)
241{
242 struct usb_ep_q *ep_q = &g_ccid_s.out_ep;
243 struct msgb *msg;
244 int rc;
245
246 OSMO_ASSERT(!ep_q->in_progress);
247 msg = msgb_dequeue_irqsafe(&g_ccid_s.free_q);
248 if (!msg)
249 return -1;
250 ep_q->in_progress = msg;
251
252 rc = ccid_df_read_out(msgb_data(msg), msgb_tailroom(msg));
253 if (rc != ERR_NONE) {
254 /* re-add to the list of free msgb's */
255 llist_add_tail_at(&g_ccid_s.free_q, &msg->list);
256 return 0;
257 }
258 return 1;
259}
260
261/* OUT endpoint read complete callback (irq context) */
262static void ccid_out_read_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred)
263{
264 struct msgb *msg = g_ccid_s.out_ep.in_progress;
265
266 /* add just-received msg to tail of endpoint queue */
267 OSMO_ASSERT(msg);
268 /* update msgb with the amount of data received */
269 msgb_put(msg, transferred);
270 /* append to list of pending-to-be-handed messages */
271 llist_add_tail_at(&msg->list, &g_ccid_s.out_ep.list);
272
273 /* submit another [free] msgb to receive the next transfer */
274 submit_next_out();
275}
276
277/* IN endpoint write complete callback (irq context) */
278static void ccid_in_write_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred)
279{
280 struct msgb *msg = g_ccid_s.in_ep.in_progress;
281
282 OSMO_ASSERT(msg);
283 /* return the message back to the queue of free message buffers */
284 llist_add_tail_at(&msg->list, &g_ccid_s.free_q);
285 g_ccid_s.in_ep.in_progress = NULL;
286
287 /* submit the next pending to-be-transmitted msgb (if any) */
288 submit_next_in();
289}
290
291/* IRQ endpoint write complete callback (irq context) */
292static void ccid_irq_write_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred)
293{
294 struct msgb *msg = g_ccid_s.irq_ep.in_progress;
295
296 OSMO_ASSERT(msg);
297 /* return the message back to the queue of free message buffers */
298 llist_add_tail_at(&msg->list, &g_ccid_s.free_q);
299 g_ccid_s.irq_ep.in_progress = NULL;
300
301 /* submit the next pending to-be-transmitted msgb (if any) */
302 submit_next_irq();
303}
304
Harald Welte5a8af4d2019-05-12 15:57:20 +0200305#include "ccid_proto.h"
Eric Wildab193652019-08-27 01:50:10 +0200306static struct msgb *ccid_gen_notify_slot_status(uint8_t old_bm, uint8_t new_bm)
Harald Welte5a8af4d2019-05-12 15:57:20 +0200307{
Eric Wildab193652019-08-27 01:50:10 +0200308 uint8_t statusbytes[2] = {0};
Harald Welte5a8af4d2019-05-12 15:57:20 +0200309 //struct msgb *msg = ccid_msgb_alloc();
310 struct msgb *msg = msgb_alloc(64, "IRQ");
Eric Wildab193652019-08-27 01:50:10 +0200311 struct ccid_rdr_to_pc_notify_slot_change *nsc = msgb_put(msg, sizeof(*nsc) + sizeof(statusbytes));
Harald Welte5a8af4d2019-05-12 15:57:20 +0200312 nsc->bMessageType = RDR_to_PC_NotifySlotChange;
Eric Wildab193652019-08-27 01:50:10 +0200313
314 for(int i = 0; i <8; i++) {
315 uint8_t byteidx = i >> 2;
316 uint8_t old_bit = old_bm & (1 << i);
317 uint8_t new_bit = new_bm & (1 << i);
318 uint8_t bv;
319 if (old_bit == new_bit && new_bit == 0)
320 bv = 0x00;
321 else if (old_bit == new_bit && new_bit == 1)
322 bv = 0x01;
323 else if (old_bit != new_bit && new_bit == 0)
324 bv = 0x02;
325 else
326 bv = 0x03;
327
328 statusbytes[byteidx] |= bv << ((i % 4) << 1);
329 }
330
331 memcpy(&nsc->bmSlotCCState, statusbytes, sizeof(statusbytes));
Harald Welte5a8af4d2019-05-12 15:57:20 +0200332
333 return msg;
334}
335
336/* check if any card detect state has changed */
337static void poll_card_detect(void)
338{
339 uint8_t new_mask = 0;
340 struct msgb *msg;
341 unsigned int i;
342
Eric Wildab193652019-08-27 01:50:10 +0200343 for (i = 0; i < 8; i++)
344 new_mask |= ncn8025_interrupt_level(i) << i;
Harald Welte5a8af4d2019-05-12 15:57:20 +0200345
346 /* notify the user/host about any changes */
347 if (g_ccid_s.card_insert_mask != new_mask) {
348 printf("CARD_DET 0x%02x -> 0x%02x\r\n",
349 g_ccid_s.card_insert_mask, new_mask);
Eric Wildab193652019-08-27 01:50:10 +0200350 msg = ccid_gen_notify_slot_status(g_ccid_s.card_insert_mask, new_mask);
Harald Welte5a8af4d2019-05-12 15:57:20 +0200351 msgb_enqueue_irqsafe(&g_ccid_s.irq_ep.list, msg);
352
353 g_ccid_s.card_insert_mask = new_mask;
354 }
355}
356
357
Harald Weltec7a58ba2019-04-18 17:59:19 +0200358
359/***********************************************************************
360 * Command Line interface
361 ***********************************************************************/
362
Harald Welte1b9a5b82019-02-24 23:04:45 +0100363static int validate_slotnr(int argc, char **argv, int idx)
364{
365 int slotnr;
366 if (argc < idx+1) {
367 printf("You have to specify the slot number (0..7)\r\n");
368 return -1;
369 }
370 slotnr = atoi(argv[idx]);
371 if (slotnr < 0 || slotnr > 7) {
372 printf("You have to specify the slot number (0..7)\r\n");
373 return -1;
374 }
375 return slotnr;
376}
377
Kévin Redon072951b2019-05-02 15:17:46 +0200378/** change baud rate of card slot
379 * @param[in] slotnr slot number for which the baud rate should be set
380 * @param[in] baudrate baud rate in bps to set
381 * @return if the baud rate has been set, else a parameter is out of range
382 */
383static bool slot_set_baudrate(uint8_t slotnr, uint32_t baudrate)
384{
385 ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
386
387 // calculate the error corresponding to the clock sources
388 uint16_t bauds[ARRAY_SIZE(sercom_glck_freqs)];
389 double errors[ARRAY_SIZE(sercom_glck_freqs)];
390 for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {
391 double freq = sercom_glck_freqs[i]; // remember possible SERCOM frequency
392 uint32_t min = freq / (2 * (255 + 1)); // calculate the minimum baud rate for this frequency
393 uint32_t max = freq / (2 * (0 + 1)); // calculate the maximum baud rate for this frequency
394 if (baudrate < min || baudrate > max) { // baud rate it out of supported range
395 errors[i] = NAN;
396 } else {
397 uint16_t baud = round(freq / (2 * baudrate) - 1);
398 bauds[i] = baud;
399 double actual = freq / (2 * (baud + 1));
400 errors[i] = fabs(1.0 - (actual / baudrate));
401 }
402 }
403
404 // find the smallest error
405 uint8_t best = ARRAY_SIZE(sercom_glck_freqs);
406 for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) {
407 if (isnan(errors[i])) {
408 continue;
409 }
410 if (best >= ARRAY_SIZE(sercom_glck_freqs)) {
411 best = i;
412 } else if (errors[i] < errors[best]) {
413 best = i;
414 }
415 }
416 if (best >= ARRAY_SIZE(sercom_glck_freqs)) { // found no clock supporting this baud rate
417 return false;
418 }
419
420 // set clock and baud rate
421 struct usart_async_descriptor* slot = SIM_peripheral_descriptors[slotnr]; // get slot
422 if (NULL == slot) {
423 return false;
424 }
425 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]);
426 while (!usart_async_is_tx_empty(slot)); // wait for transmission to complete (WARNING no timeout)
427 usart_async_disable(slot); // disable SERCOM peripheral
428 hri_gclk_clear_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos)); // disable clock for this peripheral
429 while (hri_gclk_get_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos))); // wait until clock is really disabled
430 // it does not seem we need to completely disable the peripheral using hri_mclk_clear_APBDMASK_SERCOMn_bit
431 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
432 usart_async_set_baud_rate(slot, bauds[best]); // set the new baud rate
433 usart_async_enable(slot); // re-enable SERCOM peripheral
434
435 return true;
436}
437
Kévin Redon0f050722019-05-02 15:56:25 +0200438/** change ISO baud rate of card slot
439 * @param[in] slotnr slot number for which the baud rate should be set
440 * @param[in] clkdiv can clock divider
441 * @param[in] f clock rate conversion integer F
442 * @param[in] d baud rate adjustment factor D
443 * @return if the baud rate has been set, else a parameter is out of range
444 */
445static bool slot_set_isorate(uint8_t slotnr, enum ncn8025_sim_clkdiv clkdiv, uint16_t f, uint8_t d)
446{
447 // input checks
448 ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
449 if (clkdiv != SIM_CLKDIV_1 && clkdiv != SIM_CLKDIV_2 && clkdiv != SIM_CLKDIV_4 && clkdiv != SIM_CLKDIV_8) {
450 return false;
451 }
452 if (!iso7816_3_valid_f(f)) {
453 return false;
454 }
455 if (!iso7816_3_valid_d(d)) {
456 return false;
457 }
458
459 // set clockdiv
460 struct ncn8025_settings settings;
461 ncn8025_get(slotnr, &settings);
462 if (settings.clkdiv != clkdiv) {
463 settings.clkdiv = clkdiv;
464 ncn8025_set(slotnr, &settings);
465 }
466
467 // calculate desired frequency
468 uint32_t freq = 20000000UL; // maximum frequency
469 switch (clkdiv) {
470 case SIM_CLKDIV_1:
471 freq /= 1;
472 break;
473 case SIM_CLKDIV_2:
474 freq /= 2;
475 break;
476 case SIM_CLKDIV_4:
477 freq /= 4;
478 break;
479 case SIM_CLKDIV_8:
480 freq /= 8;
481 break;
482 }
483
484 // set baud rate
485 uint32_t baudrate = (freq * d) / f; // calculate actual baud rate
Kévin Redon5188e9f2019-05-09 17:34:55 +0200486 return slot_set_baudrate(slotnr, baudrate); // set baud rate
487}
488
489/** write data to card
490 * @param[in] slotnr slot number on which to send data
491 * @param[in] data data to be transmitted
492 * @param[in] length length of data to be transmitted
493 * @return error code
494 */
495static int slot_card_write(uint8_t slotnr, const uint8_t* data, uint16_t length)
496{
497 // input checks
498 ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
499 if (0 == length || NULL == data) {
500 return ERR_INVALID_ARG;
501 }
502
503 struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr];
504 ((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 0; // disable receive (to avoid the echo back)
505 SIM_tx_count[slotnr] = false; // reset TX complete
506 for (uint16_t i = 0; i < length; i++) { // transmit data
507 while(!usart_async_is_tx_empty(sim)); // wait for previous byte to be transmitted (WARNING blocking)
508 if (1 != io_write(&sim->io, &data[i], 1)) { // put but in transmit buffer
509 return ERR_IO;
510 }
511 }
512 while (!SIM_tx_count[slotnr]); // wait until transmission is complete (WARNING blocking)
513 ((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1; // enable receive again
514
515 return ERR_NONE;
516}
517
518/** read data from card
519 * @param[in] slotnr slot number on which to send data
520 * @param[out] data buffer for read data to be stored
521 * @param[in] length length of data to be read
522 * @param[in] wt Waiting Time in ETU
523 * @return error code
524 * TODO fix WT/ETU duration
525 */
526static int slot_card_read(uint8_t slotnr, uint8_t* data, uint16_t length, uint32_t wt)
527{
528 // input checks
529 ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
530 if (0 == length || NULL == data) {
531 return ERR_INVALID_ARG;
532 }
533
534 struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr];
535
536 ((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1; // ensure RX is enabled
537 uint32_t timeout = wt; // reset waiting time
538 for (uint16_t i = 0; i < length; i++) { // read all data
539 while (timeout && !usart_async_is_rx_not_empty(sim)) { // verify if data is present
540 delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
541 timeout--;
542 }
543 if (0 == timeout) { // timeout reached
544 return ERR_TIMEOUT;
545 }
546 timeout = wt; // reset waiting time
547 if (1 != io_read(&sim->io, &data[i], 1)) { // read one byte
548 return ERR_IO;
549 }
550 }
551
552 return ERR_NONE;
553}
554
555/** transfer TPDU
556 * @param[in] slotnr slot number on which to transfer the TPDU
557 * @param[in] header TPDU header to send
558 * @param[io] data TPDU data to transfer
559 * @param[in] data_length length of TPDU data to transfer
560 * @param[in] write if the data should be written (true) or read (false)
561 * TODO fix WT
562 * TODO the data length can be deduce from the header
563 */
564static int slot_tpdu_xfer(uint8_t slotnr, const uint8_t* header, uint8_t* data, uint16_t data_length, bool write)
565{
566 // input checks
567 ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
568 if (NULL == header || (data_length > 0 && NULL == data)) {
569 return ERR_INVALID_ARG;
570 }
571
572 int rc;
573 struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr]; // get USART peripheral
574 usart_async_flush_rx_buffer(sim); // flush RX buffer to start from scratch
575
576 // send command header
577 printf("(%d) TPDU: ", slotnr);
578 for (uint8_t i = 0; i < 5; i++) {
579 printf("%02x ", header[i]);
580 }
581 rc = slot_card_write(slotnr, header, 5); // transmit header
582 if (ERR_NONE != rc) {
583 printf("error in command header transmit (errno = %d)\r\n", rc);
584 return rc;
585 }
586
587 // read procedure byte, and handle data
588 uint8_t pb = 0x60; // wait more procedure byte
589 uint16_t data_i = 0; // progress in the data transfer
590 while (0x60 == pb) { // wait for SW
591 rc = slot_card_read(slotnr, &pb, 1, ISO7816_3_DEFAULT_WT);
592 if (ERR_NONE != rc) {
593 printf("error while receiving PB/SW1 (errno = %d)\r\n", rc);
594 return rc;
595 }
596 printf("%02x ", pb);
597 if (0x60 == pb) { // NULL byte
598 // just wait more time
599 } else if ((0x60 == (pb & 0xf0)) || (0x90 == (pb & 0xf0))) { // SW1 byte
600 // left the rest of the code handle it
601 } else if (header[1] == pb) { // ACK byte
602 // transfer rest of the data
603 if (data_i >= data_length) {
604 printf("error no more data to transfer\r\n");
605 return ERR_INVALID_DATA;
606 }
607 if (write) { // transmit remaining command data
608 rc = slot_card_write(slotnr, &data[data_i], data_length - data_i); // transmit command data
609 if (ERR_NONE != rc) {
610 printf("error in command data transmit (errno = %d)\r\n", rc);
611 return rc;
612 }
613 } else { // receive remaining command data
614 rc = slot_card_read(slotnr, &data[data_i], data_length - data_i, ISO7816_3_DEFAULT_WT);
615 if (ERR_NONE != rc) {
616 printf("error in command data receive (errno = %d)\r\n", rc);
617 return rc;
618 }
619 }
620 for (uint16_t i = data_i; i < data_length; i++) {
621 printf("%02x ", data[i]);
622 }
623 data_i = data_length; // remember we transferred the data
624 pb = 0x60; // wait for SW1
625 } else if (header[1] == (pb ^ 0xff)) { // ACK byte
626 // transfer only one byte
627 if (data_i >= data_length) {
628 printf("error no more data to transfer\r\n");
629 return ERR_INVALID_DATA;
630 }
631 if (write) { // transmit command data byte
632 rc = slot_card_write(slotnr, &data[data_i], 1); // transmit command data
633 if (ERR_NONE != rc) {
634 printf("error in command data transmit (errno = %d)\r\n", rc);
635 return rc;
636 }
637 } else { // receive command data byte
638 rc = slot_card_read(slotnr, &data[data_i], 1, ISO7816_3_DEFAULT_WT);
639 if (ERR_NONE != rc) {
640 printf("error in command data receive (errno = %d)\r\n", rc);
641 return rc;
642 }
643 }
644 printf("%02x ", data[data_i]);
645 data_i += 1; // remember we transferred one data byte
646 pb = 0x60; // wait for SW1
647 } else { // invalid byte
648 return ERR_INVALID_DATA;
649 }
650 }
651
652 // read SW2
653 uint8_t sw2;
654 rc = slot_card_read(slotnr, &sw2, 1, ISO7816_3_DEFAULT_WT);
655 if (ERR_NONE != rc) {
656 printf("error in receiving SW2 (errno = %d)\r\n", rc);
657 return rc;
658 }
659 printf("%02x", sw2);
660
661 printf("\r\n");
662 return ERR_NONE;
Kévin Redon0f050722019-05-02 15:56:25 +0200663}
664
Harald Welte1b9a5b82019-02-24 23:04:45 +0100665DEFUN(sim_status, cmd_sim_status, "sim-status", "Get state of specified NCN8025")
666{
667 struct ncn8025_settings settings;
668 int slotnr = validate_slotnr(argc, argv, 1);
669 if (slotnr < 0)
670 return;
671 ncn8025_get(slotnr, &settings);
672 printf("SIM%d: ", slotnr);
673 ncn8025_dump(&settings);
674 printf("\r\n");
675}
676
677DEFUN(sim_power, cmd_sim_power, "sim-power", "Enable/disable SIM card power")
678{
679 struct ncn8025_settings settings;
680 int slotnr = validate_slotnr(argc, argv, 1);
681 int enable;
682
683 if (slotnr < 0)
684 return;
685
686 if (argc < 3) {
687 printf("You have to specify 0=disable or 1=enable\r\n");
688 return;
689 }
690 enable = atoi(argv[2]);
691 ncn8025_get(slotnr, &settings);
692 if (enable)
693 settings.cmdvcc = true;
694 else
695 settings.cmdvcc = false;
696 ncn8025_set(slotnr, &settings);
697}
698
699DEFUN(sim_reset, cmd_sim_reset, "sim-reset", "Enable/disable SIM reset")
700{
701 struct ncn8025_settings settings;
702 int slotnr = validate_slotnr(argc, argv, 1);
703 int enable;
704
705 if (slotnr < 0)
706 return;
707
708 if (argc < 3) {
709 printf("You have to specify 0=disable or 1=enable\r\n");
710 return;
711 }
712 enable = atoi(argv[2]);
713 ncn8025_get(slotnr, &settings);
714 if (enable)
715 settings.rstin = true;
716 else
717 settings.rstin = false;
718 ncn8025_set(slotnr, &settings);
719}
720
721DEFUN(sim_clkdiv, cmd_sim_clkdiv, "sim-clkdiv", "Set SIM clock divider (1,2,4,8)")
722{
723 struct ncn8025_settings settings;
724 int slotnr = validate_slotnr(argc, argv, 1);
725 int clkdiv;
726
727 if (slotnr < 0)
728 return;
729
730 if (argc < 3) {
731 printf("You have to specify a valid divider (1,2,4,8)\r\n");
732 return;
733 }
734 clkdiv = atoi(argv[2]);
735 if (clkdiv != 1 && clkdiv != 2 && clkdiv != 4 && clkdiv != 8) {
736 printf("You have to specify a valid divider (1,2,4,8)\r\n");
737 return;
738 }
739 ncn8025_get(slotnr, &settings);
740 switch (clkdiv) {
741 case 1:
742 settings.clkdiv = SIM_CLKDIV_1;
743 break;
744 case 2:
745 settings.clkdiv = SIM_CLKDIV_2;
746 break;
747 case 4:
748 settings.clkdiv = SIM_CLKDIV_4;
749 break;
750 case 8:
751 settings.clkdiv = SIM_CLKDIV_8;
752 break;
753 }
754 ncn8025_set(slotnr, &settings);
755}
756
757DEFUN(sim_voltage, cmd_sim_voltage, "sim-voltage", "Set SIM voltage (5/3/1.8)")
758{
759 struct ncn8025_settings settings;
760 int slotnr = validate_slotnr(argc, argv, 1);
761
762 if (slotnr < 0)
763 return;
764
765 if (argc < 3) {
766 printf("You have to specify a valid voltage (5/3/1.8)\r\n");
767 return;
768 }
769 ncn8025_get(slotnr, &settings);
770 if (!strcmp(argv[2], "5"))
771 settings.vsel = SIM_VOLT_5V0;
772 else if (!strcmp(argv[2], "3"))
773 settings.vsel = SIM_VOLT_3V0;
774 else if (!strcmp(argv[2], "1.8"))
775 settings.vsel = SIM_VOLT_1V8;
776 else {
777 printf("You have to specify a valid voltage (5/3/1.8)\r\n");
778 return;
779 }
780 ncn8025_set(slotnr, &settings);
781}
782
783DEFUN(sim_led, cmd_sim_led, "sim-led", "Set SIM LED (1=on, 0=off)")
784{
785 struct ncn8025_settings settings;
786 int slotnr = validate_slotnr(argc, argv, 1);
787
788 if (slotnr < 0)
789 return;
790
791 if (argc < 3) {
792 printf("You have to specify 0=disable or 1=enable\r\n");
793 return;
794 }
795 ncn8025_get(slotnr, &settings);
796 if (atoi(argv[2]))
797 settings.led = true;
798 else
799 settings.led = false;
800 ncn8025_set(slotnr, &settings);
801}
802
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200803DEFUN(sim_atr, cmd_sim_atr, "sim-atr", "Read ATR from SIM card")
804{
805 struct ncn8025_settings settings;
806 int slotnr = validate_slotnr(argc, argv, 1);
Harald Welte1b9a5b82019-02-24 23:04:45 +0100807
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200808 if (slotnr < 0 || slotnr >= ARRAY_SIZE(SIM_peripheral_descriptors) || NULL == SIM_peripheral_descriptors[slotnr]) {
809 return;
810 }
811
812 // check if card is present (and read current settings)
813 ncn8025_get(slotnr, &settings);
814 if (!settings.simpres) {
Kévin Redon096c5052019-05-09 15:01:17 +0200815 printf("(%d) error: no card present\r\n", slotnr);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200816 return;
817 }
818
819 // switch card off (assert reset and disable power)
820 // note: ISO/IEC 7816-3:2006 section 6.4 provides the deactivation sequence, but not the minimum corresponding times
821 settings.rstin = true;
822 settings.cmdvcc = false;
Harald Weltedcf57832019-04-17 17:29:41 +0200823 settings.led = true;
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200824 ncn8025_set(slotnr, &settings);
825
826 // TODO wait some time for card to be completely deactivated
827 usart_async_flush_rx_buffer(SIM_peripheral_descriptors[slotnr]); // flush RX buffer to start from scratch
828
Kévin Redon0f050722019-05-02 15:56:25 +0200829
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200830 // set clock to lowest frequency (20 MHz / 8 = 2.5 MHz)
831 // 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
832 settings.clkdiv = SIM_CLKDIV_8;
Kévin Redon0f050722019-05-02 15:56:25 +0200833 // set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1)
834 slot_set_isorate(slotnr, settings.clkdiv, ISO7816_3_DEFAULT_FD, ISO7816_3_DEFAULT_DD);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200835 // set card voltage to 3.0 V (the most supported)
836 // note: according to ISO/IEC 7816-3:2006 no voltage should damage the card, and you should cycle from low to high
837 settings.vsel = SIM_VOLT_3V0;
838 // provide power (the NCN8025 should perform the activation according to spec)
839 // note: activation sequence is documented in ISO/IEC 7816-3:2006 section 6.2
840 settings.cmdvcc = true;
841 ncn8025_set(slotnr, &settings);
842
843 // wait for Tb=400 cycles before re-asserting reset
844 delay_us(400 * 10000 / 2500); // 400 cycles * 1000 for us, 2.5 MHz / 1000 for us
845
846 // de-assert reset to switch card back on
847 settings.rstin = false;
848 ncn8025_set(slotnr, &settings);
849
850 // wait for Tc=40000 cycles for transmission to start
851 uint32_t cycles = 40000;
852 while (cycles && !usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
853 delay_us(10);
854 cycles -= 25; // 10 us = 25 cycles at 2.5 MHz
855 }
856 if (!usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
857 delay_us(12 * 372 / 1 / 2); // wait more than one byte (approximate freq down to 2 MHz)
858 }
859 // verify if one byte has been received
860 if (!usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
Kévin Redon096c5052019-05-09 15:01:17 +0200861 printf("(%d) error: card not responsive\r\n", slotnr);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200862 return;
863 }
864
865 // read ATR (just do it until there is no traffic anymore)
Kévin Redon096c5052019-05-09 15:01:17 +0200866 // 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 +0200867 printf("(%d) ATR: ", slotnr);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200868 uint8_t atr_byte;
869 while (usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
870 if (1 == io_read(&SIM_peripheral_descriptors[slotnr]->io, &atr_byte, 1)) {
871 printf("%02x ", atr_byte);
872 }
Kévin Redon096c5052019-05-09 15:01:17 +0200873 uint16_t wt = ISO7816_3_DEFAULT_WT; // waiting time in ETU
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200874 while (wt && !usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {
875 delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
876 wt--;
877 }
878 }
879 printf("\r\n");
Harald Weltedcf57832019-04-17 17:29:41 +0200880
Kévin Redon096c5052019-05-09 15:01:17 +0200881 /* disable LED */
882 settings.led = false;
883 ncn8025_set(slotnr, &settings);
884}
885
886DEFUN(sim_iccid, cmd_sim_iccid, "sim-iccid", "Read ICCID from SIM card")
887{
888 struct ncn8025_settings settings;
889 int slotnr = validate_slotnr(argc, argv, 1);
890
891 if (slotnr < 0 || slotnr >= ARRAY_SIZE(SIM_peripheral_descriptors) || NULL == SIM_peripheral_descriptors[slotnr]) {
892 return;
893 }
894
895 // read current settings and check if card is present and powered
896 ncn8025_get(slotnr, &settings);
897 if (!settings.simpres) {
898 printf("(%d) error: no card present\r\n", slotnr);
899 return;
900 }
901 if (!settings.cmdvcc) {
902 printf("(%d) error: card not powered\r\n", slotnr);
903 return;
904 }
905 if (settings.rstin) {
906 printf("(%d) error: card under reset\r\n", slotnr);
907 return;
908 }
909
910 // enable LED
911 if (!settings.led) {
912 settings.led = true;
913 ncn8025_set(slotnr, &settings);
914 }
915
Kévin Redon5188e9f2019-05-09 17:34:55 +0200916 // select MF
917 printf("(%d) SELECT MF\r\n", slotnr);
Kévin Redon36efc6d2019-05-09 18:03:20 +0200918 const uint8_t select_header[] = {0xa0, 0xa4, 0x00, 0x00, 0x02}; // see TS 102.221 sec. 11.1.1
919 const uint8_t select_data_mf[] = {0x3f, 0x00}; // see TS 102.221 sec. 13.1
920 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 +0200921 if (ERR_NONE != rc) {
922 printf("error while SELECT MF (errno = %d)\r\n", rc);
Kévin Redon096c5052019-05-09 15:01:17 +0200923 }
Kévin Redon36efc6d2019-05-09 18:03:20 +0200924 // ignore response data
925
926 // select EF_ICCID
927 printf("(%d) SELECT EF_ICCID\r\n", slotnr);
928 const uint8_t select_data_ef_iccid[] = {0x2f, 0xe2}; // see TS 102.221 sec. 13.2
929 rc = slot_tpdu_xfer(slotnr, select_header, (uint8_t*)select_data_ef_iccid, ARRAY_SIZE(select_data_ef_iccid), true); // transfer TPDU
930 if (ERR_NONE != rc) {
931 printf("error while SELECT EF_ICCID (errno = %d)\r\n", rc);
932 }
933 // ignore response data
934
935 // read EF_ICCID
936 printf("(%d) READ EF_ICCID\r\n", slotnr);
937 uint8_t iccid[10];
938 uint8_t read_binary[] = {0xa0, 0xb0, 0x00, 0x00, ARRAY_SIZE(iccid)}; // see TS 102.221 sec. 11.1.3
939 rc = slot_tpdu_xfer(slotnr, read_binary, iccid, ARRAY_SIZE(iccid), false); // transfer TPDU
940 if (ERR_NONE != rc) {
941 printf("error while READ ICCID (errno = %d)\r\n", rc);
942 }
943 // ignore response data
944
945 printf("(%d) ICCID: ", slotnr);
946 for (uint8_t i = 0; i < ARRAY_SIZE(iccid); i++) {
947 uint8_t nibble = iccid[i] & 0xf;
948 if (0xf == nibble) {
949 break;
950 }
951 printf("%x", nibble);
952 nibble = iccid[i] >> 4;
953 if (0xf == nibble) {
954 break;
955 }
956 printf("%x", nibble);
957 }
958 printf("\r\n");
Kévin Redon096c5052019-05-09 15:01:17 +0200959
960 // disable LED
Harald Weltedcf57832019-04-17 17:29:41 +0200961 settings.led = false;
962 ncn8025_set(slotnr, &settings);
Kévin Redonc89bb8c2019-04-17 01:20:23 +0200963}
Harald Welte1b9a5b82019-02-24 23:04:45 +0100964
Harald Welte2dc67e92019-05-17 18:01:46 +0200965DEFUN(get_time, cmd_get_time, "get-time", "Read Time from RTC")
966{
967 struct calendar_date_time dt;
968 calendar_get_date_time(&CALENDAR_0, &dt);
969 printf("%04u-%02u-%02u %02u:%02u:%02u\r\n", dt.date.year, dt.date.month, dt.date.day,
970 dt.time.hour, dt.time.min, dt.time.sec);
971}
972
Harald Welte1017a752019-05-17 20:39:49 +0200973#include <osmocom/core/timer.h>
974static struct osmo_timer_list t;
975static void tmr_cb(void *data)
976{
977 printf("timer fired!\r\n");
978}
979DEFUN(test_timer, cmd_test_timer, "test-timer", "Test osmo_timer")
980{
981 printf("Setting up timer for 3s...\n\r");
982 osmo_timer_setup(&t, &tmr_cb, NULL);
983 osmo_timer_schedule(&t, 3, 0);
984}
985
Harald Welte2dc67e92019-05-17 18:01:46 +0200986
Harald Welte67b2aba2019-04-16 20:47:22 +0200987extern void testmode_init(void);
Harald Weltebdf1b352019-05-17 10:21:45 +0200988extern void libosmo_emb_init(void);
Harald Welte1017a752019-05-17 20:39:49 +0200989extern void libosmo_emb_mainloop(void);
Harald Welte1b9a5b82019-02-24 23:04:45 +0100990
Harald Welte8049d662019-04-17 21:19:18 +0200991#include "talloc.h"
Harald Weltebdf1b352019-05-17 10:21:45 +0200992#include "logging.h"
Harald Welte3304ca22019-04-17 22:08:57 +0200993#include <osmocom/core/msgb.h>
Harald Welte8049d662019-04-17 21:19:18 +0200994void *g_tall_ctx;
995
996DEFUN(_talloc_report, cmd_talloc_report, "talloc-report", "Generate a talloc report")
997{
998 talloc_report_full(g_tall_ctx, stdout);
999}
1000
1001DEFUN(talloc_test, cmd_talloc_test, "talloc-test", "Test the talloc allocator")
1002{
1003 for (int i = 0; i < 10; i++)
1004 talloc_named_const(g_tall_ctx, 10, "sibling");
1005}
1006
1007DEFUN(v_talloc_free, cmd_talloc_free, "talloc-free", "Release all memory")
1008{
1009 talloc_free(g_tall_ctx);
1010 g_tall_ctx = NULL;
1011}
1012
Harald Welte65101be2019-04-18 18:30:49 +02001013/* Section 9.6 of SAMD5x/E5x Family Data Sheet */
1014static int get_chip_unique_serial(uint8_t *out, size_t len)
1015{
1016 uint32_t *out32 = (uint32_t *)out;
1017 if (len < 16)
1018 return -EINVAL;
1019
1020 out32[0] = *(uint32_t *)0x008061fc;
1021 out32[1] = *(uint32_t *)0x00806010;
1022 out32[2] = *(uint32_t *)0x00806014;
1023 out32[3] = *(uint32_t *)0x00806018;
1024
1025 return 0;
1026}
1027
1028/* same as get_chip_unique_serial but in hex-string format */
1029static int get_chip_unique_serial_str(char *out, size_t len)
1030{
1031 uint8_t buf[16];
1032 int rc;
1033
1034 if (len < 16*2 + 1)
1035 return -EINVAL;
1036
1037 rc = get_chip_unique_serial(buf, sizeof(buf));
1038 if (rc < 0)
1039 return rc;
1040 osmo_hexdump_buf(out, len, buf, sizeof(buf), NULL, false);
1041 return 0;
1042}
1043
Harald Welte9ab4bc82019-05-17 18:36:01 +02001044#define RSTCAUSE_STR_SIZE 64
1045static void get_rstcause_str(char *out)
1046{
1047 uint8_t val = hri_rstc_read_RCAUSE_reg(RSTC);
1048 *out = '\0';
1049 if (val & RSTC_RCAUSE_POR)
1050 strcat(out, "POR ");
1051 if (val & RSTC_RCAUSE_BODCORE)
1052 strcat(out, "BODCORE ");
1053 if (val & RSTC_RCAUSE_BODVDD)
1054 strcat(out, "BODVDD ");
1055 if (val & RSTC_RCAUSE_NVM)
1056 strcat(out, "NVM ");
1057 if (val & RSTC_RCAUSE_EXT)
1058 strcat(out, "EXT ");
1059 if (val & RSTC_RCAUSE_WDT)
1060 strcat(out, "WDT ");
1061 if (val & RSTC_RCAUSE_SYST)
1062 strcat(out, "SYST ");
1063 if (val & RSTC_RCAUSE_BACKUP)
1064 strcat(out, "BACKUP ");
1065}
1066
Eric Wildab193652019-08-27 01:50:10 +02001067extern void initialise_monitor_handles(void);
1068
Kévin Redon69b92d92019-01-24 16:39:20 +01001069int main(void)
1070{
Harald Welte65101be2019-04-18 18:30:49 +02001071 char sernr_buf[16*2+1];
Harald Welte9ab4bc82019-05-17 18:36:01 +02001072 char rstcause_buf[RSTCAUSE_STR_SIZE];
Harald Welte65101be2019-04-18 18:30:49 +02001073
Eric Wildab193652019-08-27 01:50:10 +02001074 //initialise_monitor_handles();
1075 //printf("hello world!\n");
1076
Kévin Redon69b92d92019-01-24 16:39:20 +01001077 atmel_start_init();
Harald Welte65101be2019-04-18 18:30:49 +02001078 get_chip_unique_serial_str(sernr_buf, sizeof(sernr_buf));
Harald Welte9ab4bc82019-05-17 18:36:01 +02001079 get_rstcause_str(rstcause_buf);
Kévin Redon78d2f442019-01-24 18:45:59 +01001080
Kévin Redon8e538002019-01-30 11:19:19 +01001081 usb_start();
1082
Harald Weltec3f170d2019-02-24 09:06:59 +01001083 board_init();
Harald Welteff9f4ce2019-02-24 22:51:09 +01001084 command_init("sysmoOCTSIM> ");
Harald Welte1b9a5b82019-02-24 23:04:45 +01001085 command_register(&cmd_sim_status);
1086 command_register(&cmd_sim_power);
1087 command_register(&cmd_sim_reset);
1088 command_register(&cmd_sim_clkdiv);
1089 command_register(&cmd_sim_voltage);
1090 command_register(&cmd_sim_led);
Kévin Redonc89bb8c2019-04-17 01:20:23 +02001091 command_register(&cmd_sim_atr);
Kévin Redon096c5052019-05-09 15:01:17 +02001092 command_register(&cmd_sim_iccid);
Harald Welte67b2aba2019-04-16 20:47:22 +02001093 testmode_init();
Harald Welte8049d662019-04-17 21:19:18 +02001094 command_register(&cmd_talloc_test);
1095 command_register(&cmd_talloc_report);
1096 command_register(&cmd_talloc_free);
Harald Welte2dc67e92019-05-17 18:01:46 +02001097 command_register(&cmd_get_time);
Harald Welte1017a752019-05-17 20:39:49 +02001098 command_register(&cmd_test_timer);
Harald Weltec3f170d2019-02-24 09:06:59 +01001099
Harald Welte729a7622019-05-17 11:02:11 +02001100 printf("\r\n\r\n"
1101 "=============================================================================\n\r"
1102 "sysmoOCTSIM firmware " GIT_VERSION "\n\r"
1103 "(C) 2018-2019 by sysmocom - s.f.m.c. GmbH and contributors\n\r"
1104 "=============================================================================\n\r");
1105 printf("Chip ID: %s\r\n", sernr_buf);
Harald Welte9ab4bc82019-05-17 18:36:01 +02001106 printf("Reset cause: %s\r\n", rstcause_buf);
Harald Weltee7aa5342019-04-16 21:11:14 +02001107
Harald Welte8049d662019-04-17 21:19:18 +02001108 talloc_enable_null_tracking();
1109 g_tall_ctx = talloc_named_const(NULL, 0, "global");
1110 printf("g_tall_ctx=%p\r\n", g_tall_ctx);
Harald Weltebdf1b352019-05-17 10:21:45 +02001111
1112 libosmo_emb_init();
1113
1114 LOGP(DUSB, LOGL_ERROR, "foobar usb\n");
Harald Welte8049d662019-04-17 21:19:18 +02001115
Harald Weltee7aa5342019-04-16 21:11:14 +02001116 command_print_prompt();
Kévin Redon8e538002019-01-30 11:19:19 +01001117 while (true) { // main loop
Harald Welteff9f4ce2019-02-24 22:51:09 +01001118 command_try_recv();
Harald Welte5a8af4d2019-05-12 15:57:20 +02001119 poll_card_detect();
Eric Wildab193652019-08-27 01:50:10 +02001120 submit_next_irq();
Harald Welte1017a752019-05-17 20:39:49 +02001121 osmo_timers_update();
Kévin Redon8e538002019-01-30 11:19:19 +01001122 }
Kévin Redon69b92d92019-01-24 16:39:20 +01001123}