Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

USB CCID class with nordic nRF52840

I am developing USB CCID driver class for nordic nRF52840. I used USB CDC-ACM class as reference and tried to implement for USB CCID. I have developed the device descriptor for it.

USB CCID class has 1 interface and 3 endpoints(1 for interrupt, 1 for bulk IN and 1 for bulk OUT). Now the windows is detecting as Microsoft Usbccid smart card reader(WUDF)

In modify the app_usbd_ccid_internal.h, i need to know modification to be done in 

1. class instance data (app_usbd_ccid_inst_t)

2. CCID class specific request handled via control endpoint (app_usbd_ccid_req_t)

3.  ccid context (app_usbd_ccid_ctx_t)

I have attached my app_usbd_ccid_internal.h file with tis for refrence.

app_usbd_ccid_internal.h

Parents
  • Hi,

     

    This is a windows feature, that you cannot fix in firmware.

    See a similar issue here, just for the USBD_CDC_ACM: https://devzone.nordicsemi.com/f/nordic-q-a/52438/usb-cdc-uart-is-recognized-as-teensy-com-port

    If you have another driver, you can manually update the driver, as described in the above link.

     

    Kind regards,

    Håkon

  • Hi Håkon,

    This is not the answer for the issue i described above.

    Pls check above issue i have described. 

  • Hi,

    Mohammad said:
    Now I need to modify further more in order to finish the USB CCID class driver. So i need to know parameter details of

    1. usb class instant data (app_usbd_class_inst_t) (Here class will be cdc or audio or msc or HID, in my case it is ccid, app_usbd_ccid_inst_t).

    2. class context( app_usbd_class_ctx_t,  Here class will be cdc or audio or msc or HID, in my case it is ccid, app_usbd_ccid_ctx_t).

    3. class specific request handled via control endpoint ( app_usbd_class_req_t,  Here class will be cdc or audio or msc or HID, in my case it is ccid, app_usbd_ccid_req_t).

    Unfortunately, we do not have a document/guide specifically on how to create a own usb class.

    The parameters you're asking for is defined in the USB CCID class itself, which you can find here: https://www.usb.org/sites/default/files/DWG_Smart-Card_CCID_Rev110.pdf.

    To implement these into the USBD framework, I would recommend looking at the already present classes, and the documentation for USBD:

    https://infocenter.nordicsemi.com/topic/sdk_nrf5_v16.0.0/lib_usbd.html?cp=6_1_3_60

     

    Kind regards,

    Håkon

  • Hi,

    Thanks for your response.

    Can you let me know how to receive the data from the specific endpoint.

  • Hi,

     

    When using app_usbd, see the event handler, in case of the cdc, cdc_acm_event_handler, case "APP_USBD_EVT_DRV_EPTRANSFER".

    Kind regards,

    Håkon

  • Hi,

    Thanks for your response.

    Can you specify your answer more clearly where i can refer in the cdc code for receive the data from endpoint.

    For example, to send the data in endpoint(EP0), i use the following code,

    ret_code_t ret;
    nrf_drv_usbd_transfer_t transfer =
    {
       .p_data = {.tx = p_data},
       .size = size
    };
    ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPIN0, &transfer);

    As per your above statement, once the NRF_DRV_USBD_EVT_EPTRANSFER event is generated, it calls cdc_acm_endpoint_ev where the type of endpoint is check.

    If it is bulkout endpoint, cdc_acm_rx_block_finished is called once the NRF_USBD_EP_OK is OK.

    But i need to know how to copy the data from the endpoint.

  • Hi,

      

    Mohammad said:
    ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPIN0, &transfer);

    In that function, you check if it is IN or OUT direction, based on the EP.

    In the case of the cdc_acm, it uses the app_usbd_ep_handled_transfer(), which schedules a callback just prior to when the transfer is to occur, as per the header documentation in nrfx_usbd.h:

    /**
     * @brief Start sending data over the endpoint using the transfer handler function.
     *
     * This function initializes an endpoint transmission.
     * Just before data is transmitted, the transfer handler
     * is called and it prepares a data chunk.
     *
     * @param[in] ep        Endpoint number.
     *                      For an IN endpoint, sending is initiated.
     *                      For an OUT endpoint, receiving is initiated.
     * @param[in] p_handler Transfer handler - feeder for IN direction and consumer for
     *                      OUT direction.
     *
     * @retval NRFX_SUCCESS             Transfer queued or started.
     * @retval NRFX_ERROR_BUSY          Selected endpoint is pending.
     * @retval NRFX_ERROR_INVALID_ADDR  Unexpected transfer on EPIN0 or EPOUT0.
     */
    nrfx_err_t nrfx_usbd_ep_handled_transfer(nrfx_usbd_ep_t ep,
                                             nrfx_usbd_handler_desc_t const * p_handler);

    You can also fetch this using app_usbd_ep_transfer() (for both directions, filtered on the input EP).

      

    Mohammad said:

    If it is bulkout endpoint, cdc_acm_rx_block_finished is called once the NRF_USBD_EP_OK is OK.

    But i need to know how to copy the data from the endpoint.

      That specific function has CDC specific buffering logic, which makes it complicated wrt. where the USB data is read. It's essentially the call to "app_usbd_ep_handled_transfer" that handles it. The rest is buffer logic.

     

    Kind regards,

    Håkon

Reply
  • Hi,

      

    Mohammad said:
    ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPIN0, &transfer);

    In that function, you check if it is IN or OUT direction, based on the EP.

    In the case of the cdc_acm, it uses the app_usbd_ep_handled_transfer(), which schedules a callback just prior to when the transfer is to occur, as per the header documentation in nrfx_usbd.h:

    /**
     * @brief Start sending data over the endpoint using the transfer handler function.
     *
     * This function initializes an endpoint transmission.
     * Just before data is transmitted, the transfer handler
     * is called and it prepares a data chunk.
     *
     * @param[in] ep        Endpoint number.
     *                      For an IN endpoint, sending is initiated.
     *                      For an OUT endpoint, receiving is initiated.
     * @param[in] p_handler Transfer handler - feeder for IN direction and consumer for
     *                      OUT direction.
     *
     * @retval NRFX_SUCCESS             Transfer queued or started.
     * @retval NRFX_ERROR_BUSY          Selected endpoint is pending.
     * @retval NRFX_ERROR_INVALID_ADDR  Unexpected transfer on EPIN0 or EPOUT0.
     */
    nrfx_err_t nrfx_usbd_ep_handled_transfer(nrfx_usbd_ep_t ep,
                                             nrfx_usbd_handler_desc_t const * p_handler);

    You can also fetch this using app_usbd_ep_transfer() (for both directions, filtered on the input EP).

      

    Mohammad said:

    If it is bulkout endpoint, cdc_acm_rx_block_finished is called once the NRF_USBD_EP_OK is OK.

    But i need to know how to copy the data from the endpoint.

      That specific function has CDC specific buffering logic, which makes it complicated wrt. where the USB data is read. It's essentially the call to "app_usbd_ep_handled_transfer" that handles it. The rest is buffer logic.

     

    Kind regards,

    Håkon

Children
  • Hi,

    Thanks for your reply.

    Now i can send and receive the data through the endpoints.

    I have tested the following CCID message functions working good

    PC_TO_RDR_GETSLOTSTATUS
    PC_TO_RDR_ICCPOWERON
    PC_TO_RDR_ICCPOWEROFF

    RDR_to_PC_DataBlock
    RDR_to_PC_SlotStatus
    RDR_to_PC_NotifySlotChange

    But i have problem that the program stucks in infinte loop at this part

    while (app_usbd_event_queue_process())
    {
    /* Nothing to do */
    }

    Help me to solve this issue.

    Ouput:

    <info> app: USBD CCID example started.
    <info> usbd_ccid: ccid_event_handler = 11
    <info> app: USB power detected
    <info> usbd_ccid: ccid_event_handler = 8
    <info> app: USB ready
    <info> usbd_ccid: ccid_event_handler = 10
    <info> usbd_ccid: ccid_event_handler = 15
    <info> usbd_ccid: ccid_event_handler = 13
    <info> usbd_ccid: ccid_event_handler = 2
    <info> usbd_ccid: ccid_event_handler = 3
    <info> usbd_ccid: ccid_event_handler = 15
    <info> usbd_ccid: ccid_event_handler = 1
    <info> usbd_ccid: ccid_event_handler = 1
    <info> usbd_ccid: ccid_event_handler = 15
    <info> usbd_ccid: ccid_event_handler = 5
    <info> usbd_ccid: setup_event_handler
    <info> usbd_ccid: setup_req_std_in
    <info> usbd_ccid: NRF_ERROR_NOT_SUPPORTED
    <info> usbd_ccid: ccid_event_handler = 15
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x2
    <info> usbd_ccid: NRF_USBD_EP_WAITING
    <info> usbd_ccid: Length of the data received = 10
    <info> usbd_ccid: CCID Message type = 65 and bseq = 1
    <info> usbd_ccid: PC_TO_RDR_GETSLOTSTATUS
    <info> usbd_ccid: OK = 0
    <info> usbd_ccid: EPOUT_DATA: 02 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x2
    <info> usbd_ccid: Length of the data received = 10
    <info> usbd_ccid: CCID Message type = 81 and bseq = 1
    <info> usbd_ccid: OK = 1
    <info> usbd_ccid: EPOUT_DATA: 02 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x82
    <info> usbd_ccid: EPIN_DATA: 82 done
    <info> usbd_ccid: RDR_to_PC_NotifySlotChange = 50, 03
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x81
    <info> usbd_ccid: EPIN_CON: notify
    <info> usbd_ccid: EPIN_CON: 81 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x2
    <info> usbd_ccid: Length of the data received = 10
    <info> usbd_ccid: CCID Message type = 63 and bseq = 2
    <info> usbd_ccid: PC_TO_RDR_ICCPOWEROFF
    <info> usbd_ccid: OK = 0
    <info> usbd_ccid: EPOUT_DATA: 02 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x82
    <info> usbd_ccid: EPIN_DATA: 82 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x2
    <info> usbd_ccid: Length of the data received = 10
    <info> usbd_ccid: CCID Message type = 62 and bseq = 3
    <info> usbd_ccid: PC_TO_RDR_ICCPOWERON
    <info> usbd_ccid: OK = 0
    <info> usbd_ccid: EPOUT_DATA: 02 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x82
    <info> usbd_ccid: EPIN_DATA: 82 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x2
    <info> usbd_ccid: Length of the data received = 10
    <info> usbd_ccid: CCID Message type = 63 and bseq = 4
    <info> usbd_ccid: PC_TO_RDR_ICCPOWEROFF
    <info> usbd_ccid: OK = 0
    <info> usbd_ccid: EPOUT_DATA: 02 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x82
    <info> usbd_ccid: EPIN_DATA: 82 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x2
    <info> usbd_ccid: Length of the data received = 10
    <info> usbd_ccid: CCID Message type = 62 and bseq = 5
    <info> usbd_ccid: PC_TO_RDR_ICCPOWERON
    <info> usbd_ccid: OK = 0
    <info> usbd_ccid: EPOUT_DATA: 02 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x82
    <info> usbd_ccid: EPIN_DATA: 82 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x2
    <info> usbd_ccid: Length of the data received = 10
    <info> usbd_ccid: CCID Message type = 63 and bseq = 6
    <info> usbd_ccid: PC_TO_RDR_ICCPOWEROFF
    <info> usbd_ccid: OK = 0
    <info> usbd_ccid: EPOUT_DATA: 02 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x82
    <info> usbd_ccid: EPIN_DATA: 82 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x2
    <info> usbd_ccid: Length of the data received = 10
    <info> usbd_ccid: CCID Message type = 62 and bseq = 7
    <info> usbd_ccid: PC_TO_RDR_ICCPOWERON
    <info> usbd_ccid: OK = 0
    <info> usbd_ccid: EPOUT_DATA: 02 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 6
    <info> usbd_ccid: ccid_endpoint_ev
    <info> usbd_ccid: Current EP address = 0x82
    <info> usbd_ccid: EPIN_DATA: 82 done
    <info> usbd_ccid: ------------------------
    <info> usbd_ccid: ccid_event_handler = 5
    <info> usbd_ccid: setup_event_handler
    <info> usbd_ccid: setup_req_std_in
    <info> usbd_ccid: NRF_ERROR_NOT_SUPPORTED
    <info> usbd_ccid: ccid_event_handler = 5
    <info> usbd_ccid: setup_event_handler
    <info> usbd_ccid: setup_req_std_in
    <info> usbd_ccid: NRF_ERROR_NOT_SUPPORTED
    <info> usbd_ccid: ccid_event_handler = 5
    <info> usbd_ccid: setup_event_handler
    <info> usbd_ccid: setup_req_std_in
    <info> usbd_ccid: NRF_ERROR_NOT_SUPPORTED

  • Hi,

     

    Mohammad said:
    <info> usbd_ccid: ccid_event_handler = 5
    <info> usbd_ccid: setup_event_handler
    <info> usbd_ccid: setup_req_std_in
    <info> usbd_ccid: NRF_ERROR_NOT_SUPPORTED

     What is '5' in this case? Is that the p_event->app_evt.type? If yes, then that is the setup APP_USBD_EVT_DRV_SETUP, which should handle class specific requests. I do not have extensive knowledge about CCID, unfortunately, so I cannot state what should be implemented for this specific USB class.

     

    Mohammad said:
    But i have problem that the program stucks in infinte loop at this part

    while (app_usbd_event_queue_process())
    {
    /* Nothing to do */
    }

     Is it stuck inside there, or just not processing any events? It sounds like there's some CCID specific events that are not implemented?

     

    Kind regards,

    Håkon

  • Hi,

    Yes, it is  p_event->app_evt.type.

    NRF_LOG_INFO("ccid_event_handler = %d", p_event->app_evt.type);

     Is it stuck inside there, or just not processing any events? It sounds like there's some CCID specific events that are not implemented?

    Yes, it processes the events.

  • Mohammad said:

     Is it stuck inside there, or just not processing any events? It sounds like there's some CCID specific events that are not implemented?

    Yes, it processes the events.

    Have you checked if the CCID class documentation has specific setup requests? Because it looks like there are unhandled/unimplemented cases in your implementation of the class.

     

    Kind regards,

    Håkon

  • Hi,

    I have a problem with static ret_code_t setup_req_std_in(app_usbd_class_inst_t const * p_inst,
    app_usbd_setup_evt_t const * p_setup_ev)

    static ret_code_t setup_req_std_in(app_usbd_class_inst_t const * p_inst,
    app_usbd_setup_evt_t const * p_setup_ev)
    {
      NRF_LOG_INFO("setup_req_std_in ");

      /* Only Get Descriptor standard IN request is supported by CCID class */
      if ((app_usbd_setup_req_rec(p_setup_ev->setup.bmRequestType) == APP_USBD_SETUP_REQREC_DEVICE) &&
    (p_setup_ev->setup.bRequest == APP_USBD_SETUP_STDREQ_GET_DESCRIPTOR)) 
      {
         NRF_LOG_INFO("Inside setup_req_std_in ");

         size_t dsc_len = 0;
         size_t max_size;

         uint8_t * p_trans_buff = app_usbd_core_setup_transfer_buff_get(&max_size);

         /* Try to find descriptor in class internals*/
         ret_code_t ret = app_usbd_class_descriptor_find(p_inst, p_setup_ev->setup.wValue.hb,
    p_setup_ev->setup.wValue.lb, p_trans_buff, &dsc_len);

          if (ret != NRF_ERROR_NOT_FOUND) 
         {
              ASSERT(dsc_len < NRF_DRV_USBD_EPSIZE);
              return app_usbd_core_setup_rsp(&(p_setup_ev->setup), p_trans_buff, dsc_len);
          }
       }

       NRF_LOG_INFO("NRF_ERROR_NOT_SUPPORTED");
       return NRF_ERROR_NOT_SUPPORTED;
    }

    ret_code_t ret = app_usbd_class_descriptor_find(p_inst,p_setup_ev->setup.wValue.hb,p_setup_ev->setup.wValue.lb,p_trans_buff,&dsc_len);

    It returns ret = NRF_ERROR_NOT_FOUND;

    In the above p_setup_ev->setup.wValue.hb = 6; (desc_type)

    p_setup_ev->setup.wValue.lb = 0;

    p_trans_buff = 26 03 48 00 53 00 49 00 44 00 36 (Here I dont now the actual length of p_trans_buff)

    dsc_len = 0;

    I find the above value by debugging the code.

    Inside the app_usbd_class_descriptor_find() function , the value of type as follows,

    4, 33, 5, 5, 5 (4 for interface, 33 for CCID, 5 for endpoint)

    So if(type == desc_type) condition is not satisfied. 

    t returns ret = NRF_ERROR_NOT_FOUND; from app_usbd_class_descriptor_find

    Help me to solve this issue

Related