<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/13943">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add debug command to communicate with card<br><br>currently the sim-iccid command only selects MF.<br>this is a proof of concept for card communication.<br>the transmission/reception must be generalized to avoid copying<br>the code multiple times.<br><br>IMPORTANT: the sim-iccid commands only works after the sim-atr<br>command, which sets up the cards correctly<br><br>Change-Id: Icbcde783143694afce23af6e3f26bcd7a9a13b85<br>---<br>M sysmoOCTSIM/main.c<br>1 file changed, 145 insertions(+), 7 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/sysmoOCTSIM/main.c b/sysmoOCTSIM/main.c</span><br><span>index a895c14..11849c7 100644</span><br><span>--- a/sysmoOCTSIM/main.c</span><br><span>+++ b/sysmoOCTSIM/main.c</span><br><span>@@ -38,10 +38,28 @@</span><br><span> // TODO for now SIM7 is not present because used for debug</span><br><span> static struct usart_async_descriptor* SIM_peripheral_descriptors[] = {&SIM0, &SIM1, &SIM2, &SIM3, &SIM4, &SIM5, &SIM6, NULL};</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/** number of bytes transmitted on the SIM peripheral */</span><br><span style="color: hsl(120, 100%, 40%);">+static volatile bool SIM_tx_count[8];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void SIM_rx_cb(const struct usart_async_descriptor *const io_descr)</span><br><span> {</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/** called when the transmission is complete</span><br><span style="color: hsl(120, 100%, 40%);">+ *  e.g. this is when the byte has been sent and there is no data to transmit anymore</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static void SIM_tx_cb(const struct usart_async_descriptor *const io_descr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  // find slotnr for corresponding USART</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t slotnr;</span><br><span style="color: hsl(120, 100%, 40%);">+       for (slotnr = 0; slotnr < ARRAY_SIZE(SIM_peripheral_descriptors) && SIM_peripheral_descriptors[slotnr] != io_descr; slotnr++);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   // set flag</span><br><span style="color: hsl(120, 100%, 40%);">+   if (slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             SIM_tx_count[slotnr] = true;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /** possible clock sources for the SERCOM peripheral</span><br><span>  *  warning: the definition must match the GCLK configuration</span><br><span>  */</span><br><span>@@ -80,6 +98,7 @@</span><br><span>                   continue;</span><br><span>            }</span><br><span>            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</span><br><span style="color: hsl(120, 100%, 40%);">+            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</span><br><span>                usart_async_enable(SIM_peripheral_descriptors[i]);</span><br><span>   }</span><br><span> }</span><br><span>@@ -360,7 +379,7 @@</span><br><span>         // check if card is present (and read current settings)</span><br><span>      ncn8025_get(slotnr, &settings);</span><br><span>  if (!settings.simpres) {</span><br><span style="color: hsl(0, 100%, 40%);">-                printf("no card present in slot %d, aborting\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+         printf("(%d) error: no card present\r\n", slotnr);</span><br><span>                 return;</span><br><span>      }</span><br><span> </span><br><span>@@ -406,19 +425,19 @@</span><br><span>        }</span><br><span>    // verify if one byte has been received</span><br><span>      if (!usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {</span><br><span style="color: hsl(0, 100%, 40%);">-         printf("card in slot %d is not responding, aborting\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+          printf("(%d) error: card not responsive\r\n", slotnr);</span><br><span>             return;</span><br><span>      }</span><br><span> </span><br><span>        // read ATR (just do it until there is no traffic anymore)</span><br><span style="color: hsl(0, 100%, 40%);">-      // TODO the ATR should be parsed to read the right number of bytes</span><br><span style="color: hsl(120, 100%, 40%);">+    // TODO the ATR should be parsed to read the right number of bytes, instead we just wait until to end of WT</span><br><span>  printf("(%d) ATR: ", slotnr);</span><br><span>      uint8_t atr_byte;</span><br><span>    while (usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {</span><br><span>            if (1 == io_read(&SIM_peripheral_descriptors[slotnr]->io, &atr_byte, 1)) {</span><br><span>                        printf("%02x ", atr_byte);</span><br><span>                 }</span><br><span style="color: hsl(0, 100%, 40%);">-               uint16_t wt = 9600; // waiting time in ETU</span><br><span style="color: hsl(120, 100%, 40%);">+            uint16_t wt = ISO7816_3_DEFAULT_WT; // waiting time in ETU</span><br><span>           while (wt && !usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) {</span><br><span>                     delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)</span><br><span>                      wt--;</span><br><span>@@ -426,9 +445,127 @@</span><br><span>        }</span><br><span>    printf("\r\n");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* disable VCC and LED, re-enable RST */</span><br><span style="color: hsl(0, 100%, 40%);">-        settings.cmdvcc = false;</span><br><span style="color: hsl(0, 100%, 40%);">-        settings.rstin = true;</span><br><span style="color: hsl(120, 100%, 40%);">+        /* disable LED */</span><br><span style="color: hsl(120, 100%, 40%);">+     settings.led = false;</span><br><span style="color: hsl(120, 100%, 40%);">+ ncn8025_set(slotnr, &settings);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(sim_iccid, cmd_sim_iccid, "sim-iccid", "Read ICCID from SIM card")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ncn8025_settings settings;</span><br><span style="color: hsl(120, 100%, 40%);">+     int slotnr = validate_slotnr(argc, argv, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (slotnr < 0 || slotnr >= ARRAY_SIZE(SIM_peripheral_descriptors) || NULL == SIM_peripheral_descriptors[slotnr]) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   // read current settings and check if card is present and powered</span><br><span style="color: hsl(120, 100%, 40%);">+     ncn8025_get(slotnr, &settings);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!settings.simpres) {</span><br><span style="color: hsl(120, 100%, 40%);">+              printf("(%d) error: no card present\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!settings.cmdvcc) {</span><br><span style="color: hsl(120, 100%, 40%);">+               printf("(%d) error: card not powered\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (settings.rstin) {</span><br><span style="color: hsl(120, 100%, 40%);">+         printf("(%d) error: card under reset\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   // enable LED</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!settings.led) {</span><br><span style="color: hsl(120, 100%, 40%);">+          settings.led = true;</span><br><span style="color: hsl(120, 100%, 40%);">+          ncn8025_set(slotnr, &settings);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   // read MF</span><br><span style="color: hsl(120, 100%, 40%);">+    printf("(%d) SELECT MF: ", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr];</span><br><span style="color: hsl(120, 100%, 40%);">+      ((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   usart_async_flush_rx_buffer(sim); // flush RX buffer to start from scratch</span><br><span style="color: hsl(120, 100%, 40%);">+    // write SELECT MF APDU</span><br><span style="color: hsl(120, 100%, 40%);">+       const uint8_t select_mf[] = {0xa0, 0xa4, 0x00, 0x00, 0x02, 0x3f, 0x00};</span><br><span style="color: hsl(120, 100%, 40%);">+       SIM_tx_count[slotnr] = false; // reset TX complete</span><br><span style="color: hsl(120, 100%, 40%);">+    for (uint8_t i = 0; i < 5; i++) { // transmit command header</span><br><span style="color: hsl(120, 100%, 40%);">+               printf("%02x ", select_mf[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+              while(!usart_async_is_tx_empty(sim)); // wait for previous byte to be transmitted (WARNING could block)</span><br><span style="color: hsl(120, 100%, 40%);">+               if (1 != io_write(&sim->io, &select_mf[i], 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   printf("(%d) error: could not send command header\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+                    return;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t wt = ISO7816_3_DEFAULT_WT; // waiting time in ETU (actually it can be a lot more after the ATR, but we use the default)</span><br><span style="color: hsl(120, 100%, 40%);">+      while (wt && !SIM_tx_count[slotnr]) { // wait until transmission is complete</span><br><span style="color: hsl(120, 100%, 40%);">+          delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)</span><br><span style="color: hsl(120, 100%, 40%);">+               wt--;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (0 == wt) { // timeout reached</span><br><span style="color: hsl(120, 100%, 40%);">+             printf("(%d) error: could not transmit data\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     ((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+   //usart_async_flush_rx_buffer(sim); // flush RX buffer to start from scratch</span><br><span style="color: hsl(120, 100%, 40%);">+  wt = ISO7816_3_DEFAULT_WT; // reset waiting time</span><br><span style="color: hsl(120, 100%, 40%);">+      while (wt && !usart_async_is_rx_not_empty(sim)) { // wait for procedure byte</span><br><span style="color: hsl(120, 100%, 40%);">+          delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)</span><br><span style="color: hsl(120, 100%, 40%);">+               wt--;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (0 == wt) { // timeout reached</span><br><span style="color: hsl(120, 100%, 40%);">+             printf("(%d) error: card not responsive\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t pb;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (1 != io_read(&sim->io, &pb, 1)) { // read procedure byte</span><br><span style="color: hsl(120, 100%, 40%);">+               printf("(%d) error: could not read data\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (select_mf[1] != pb) { // the header is ACKed when the procedure by is equal to the instruction byte</span><br><span style="color: hsl(120, 100%, 40%);">+               printf("(%d) error: header NACKed\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     SIM_tx_count[slotnr] = false; // reset TX complete</span><br><span style="color: hsl(120, 100%, 40%);">+    for (uint8_t i = 5; i < 7; i++) { // transmit command data</span><br><span style="color: hsl(120, 100%, 40%);">+         printf("%02x ", select_mf[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+              while(!usart_async_is_tx_empty(sim)); // wait for previous byte to be transmitted (WARNING could block)</span><br><span style="color: hsl(120, 100%, 40%);">+               if (1 != io_write(&sim->io, &select_mf[i], 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   printf("(%d) error: could not send command data\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+                      return;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     wt = ISO7816_3_DEFAULT_WT; // waiting time in ETU (actually it can be a lot more after the ATR, but we use the default)</span><br><span style="color: hsl(120, 100%, 40%);">+       while (wt && !SIM_tx_count[slotnr]) { // wait until transmission is complete</span><br><span style="color: hsl(120, 100%, 40%);">+          delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)</span><br><span style="color: hsl(120, 100%, 40%);">+               wt--;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (0 == wt) { // timeout reached</span><br><span style="color: hsl(120, 100%, 40%);">+             printf("(%d) error: could not transmit data\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     usart_async_flush_rx_buffer(sim); // flush RX buffer to start from scratch</span><br><span style="color: hsl(120, 100%, 40%);">+    // read SW</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t sw[2]; // to read the status words</span><br><span style="color: hsl(120, 100%, 40%);">+    wt = ISO7816_3_DEFAULT_WT; // waiting time in ETU (actually it can be a lot more after the ATR, but we use the default)</span><br><span style="color: hsl(120, 100%, 40%);">+       for (uint8_t i = 0; i < ARRAY_SIZE(sw); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             while (wt && !usart_async_is_rx_not_empty(sim)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)</span><br><span style="color: hsl(120, 100%, 40%);">+                       wt--;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (0 == wt) { // timeout reached</span><br><span style="color: hsl(120, 100%, 40%);">+                     printf("(%d) error: card not responsive\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+              } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (1 != io_read(&sim->io, &sw[i], 1)) { // read SW</span><br><span style="color: hsl(120, 100%, 40%);">+                                printf("(%d) error: could not read data\r\n", slotnr);</span><br><span style="color: hsl(120, 100%, 40%);">+                              return;</span><br><span style="color: hsl(120, 100%, 40%);">+                       }</span><br><span style="color: hsl(120, 100%, 40%);">+                     printf("%02x ", sw[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                     wt = ISO7816_3_DEFAULT_WT; // reset WT</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("\r\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   // disable LED</span><br><span>       settings.led = false;</span><br><span>        ncn8025_set(slotnr, &settings);</span><br><span> }</span><br><span>@@ -450,6 +587,7 @@</span><br><span>       command_register(&cmd_sim_voltage);</span><br><span>      command_register(&cmd_sim_led);</span><br><span>  command_register(&cmd_sim_atr);</span><br><span style="color: hsl(120, 100%, 40%);">+   command_register(&cmd_sim_iccid);</span><br><span>        testmode_init();</span><br><span> </span><br><span>         printf("\r\n\r\nsysmocom sysmoOCTSIM\r\n");</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/13943">change 13943</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/13943"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-ccid-firmware </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Icbcde783143694afce23af6e3f26bcd7a9a13b85 </div>
<div style="display:none"> Gerrit-Change-Number: 13943 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: Kévin Redon <kredon@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>