This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How to process OUT Vendor Request with data stage

Hello, dear experts.
I have a problem with the USB component ver 6.5 of MDK-Professional Middleware.
I'm developing vendor specific device and I use USB0 of the microcontroller LPC4337JBD144. I use USB component ver 6.5.
After sending OUT Vendor Request with data stage it's impossible to process any IN Vendor Request. It looks as if it's processed successfully in my firmware program (it continues to work), but my PC application just freezes and waits for a response of a driver untill I detach my device or reset it using debugger.
I added a file "USBD_User_Device_0.c" to my project and modified it in order to process Vendor specific Requests. I changed a callback function the next way

usbdRequestStatus USBD_Device0_Endpoint0_SetupPacketReceived (const USB_SETUP_PACKET *setup_packet, uint8_t **buf, int32_t *len)
{
  switch (setup_packet->bmRequestType.Type) {
    ...
    case USB_REQUEST_VENDOR:
      switch (setup_packet->bmRequestType.Recipient){
        case USB_REQUEST_TO_DEVICE:
          switch (setup_packet->bRequest){
            ... // some code
            case USB_VEND_REQ_LONG_COMM:   // bRequest = 4
              CommStruct.CommLength = setup_packet->wLength;
              CommStruct.RespLength = setup_packet->wIndex;
              // When I call this function, the problem appears. Without calling it everything works properly
              usbReadStat = USBD_EndpointRead(0,       USB_ENDPOINT_OUT(0), CommStruct.CommBuff, 64/*CommStruct.CommLength*/);
              // Here you can see that I tried different ways to solve the problem. I waited, aborted transition, but nothing helped me.
              //while (USBD_EndpointReadGetResult(0, 0x00) != CommStruct.CommLength);
              //USBD_EndpointAbort(0, USB_ENDPOINT_OUT(0));
              ... // some code
              break;
          }
      }
      break;
  }
}

I have to add, that OUT Vendor Requests without data stage are processed successfully even after OUT Vendor Requests with data stage.
I use the toolchain MDK-ARM Professional version 5.14.0.0 and Windows 7 64-bit.
Thank you for any help.

Parents
  • Finally I've got a solution from technical support. That's what I was advised to do:
    ----------------------------------------------------------
    The USBD_EndpointWrite and USBD_EndpointRead should not be used for Endpoint 0 communication as it is handled by the library itself.
    As it can be seen in a template for custom device handling file USBD_User_Device_SerNum.c communication on Endpoint 0 is done through parameters of this function. So in this case you should do something like below:

    *buf = global_buffer; // Where OUT data will be received
    *len = setup_packet->wLength; // Number of bytes to be received
    return usbdRequestOK; // Return status that custom handling for this request is used

    after that function USBD_Device0_Endpoint0_OutDataReceived will be called by the library when OUT data is received and you should then analyze received data in there.
    ----------------------------------------------------------
    I hope it can help someone.

Reply
  • Finally I've got a solution from technical support. That's what I was advised to do:
    ----------------------------------------------------------
    The USBD_EndpointWrite and USBD_EndpointRead should not be used for Endpoint 0 communication as it is handled by the library itself.
    As it can be seen in a template for custom device handling file USBD_User_Device_SerNum.c communication on Endpoint 0 is done through parameters of this function. So in this case you should do something like below:

    *buf = global_buffer; // Where OUT data will be received
    *len = setup_packet->wLength; // Number of bytes to be received
    return usbdRequestOK; // Return status that custom handling for this request is used

    after that function USBD_Device0_Endpoint0_OutDataReceived will be called by the library when OUT data is received and you should then analyze received data in there.
    ----------------------------------------------------------
    I hope it can help someone.

Children
  • That post already made things cleare to me. Thank you.
    I still have a question regarding the CTRL OUT transfer.

    When the host issues a CTRL OUT transfer with a data stage does that mean that:

    1. The USBD_Device0_Endpoint0_SetupPacketReceived() function is called by the middleware, and you have to detect that a data stage is following and prepare yourself to process the data, e.g. with a flag similar to the handle_request flag of the example.

    2. Wait until USBD_Device0_Endpoint0_OutDataReceived() is called some time later, then process tha data and reset the flag?

    I yes, a confirmation would be fine, if no please provide more code.

    Thanks a lot
    regards
    Lutz

  • Hello, Lutz.
    I've done it next way:
    1. I have only ONE Vendor Request with data stage. My callback function USBD_Device0_Endpoint0_SetupPacketReceived looks like this:

    usbdRequestStatus USBD_Device0_Endpoint0_SetupPacketReceived (const USB_SETUP_PACKET *setup_packet, uint8_t **buf, int32_t *len)
    {
      switch (setup_packet->bmRequestType.Type) {
        ...
        case USB_REQUEST_VENDOR:
          switch (setup_packet->bmRequestType.Recipient){
            case USB_REQUEST_TO_DEVICE:
              switch (setup_packet->bRequest){
                ... // some code
                case USB_VEND_REQ_LONG_COMM:   // This is my Vend Req bRequest = 5
                  *buf = myBuff;
                  *len = myBuffLength;
                  return usbdRequestOK;
                  break;
              }
          }
          break;
      }
    }
    


    2. Then a callback USBD_Device0_Endpoint0_OutDataReceived is called and it looks like this:

    usbdRequestStatus USBD_Device0_Endpoint0_OutDataReceived (uint32_t len)
    {
       // Here I process data storing in myBuff.
    }
    

    As you can see, I don't use any flags because the callback USBD_Device0_Endpoint0_OutDataReceived is always called if you return usbdRequestOK from USBD_Device0_Endpoint0_SetupPacketReceived for Vendor Request with data stage. But I guess using some flag as you described is a good idea.

  • The only time you need some flag is when you have multiple different request handling so you can differentiate for which request OUT data was received, for single request handling you can basically work without any flags as USBD_Device0_Endpoint0_OutDataReceived will only be called if function USBD_Device0_Endpoint0_SetupPacketReceived returned usbdRequestOK.

  • Hello again,
    still I have some questions, or let me express it the other way: I need a more detailed documentation of the API to the middleware.

    Let me explain how far I can follow the examples shown here:

    For a CTRL OUT tranfer, i.e. the host sends not only a setup packet but additional data to the device ('data stage').

    --> Middleware calls

    USBD_Device0_Endpoint0_SetupPacketReceived (const USB_SETUP_PACKET *setup_packet, uint8_t **buf, int32_t *len)
    

    --> User (me) has to check if the request is for the user (me) If yes, user can set an optional flag and has to return usbdRequestOK, user has to provide a buffer for the data stage to be received

    *buf = myBuffer;
    

    The parameter len has to be set to what? My understanding is that len has to be set to buffer size or to setup_packet->wLength, whichever is lower. Please advise.

    *len = sizeof(myBuffer);
    if(*len > setup_packet->wLength) *len = setup_packet->wLength
    

    --> A few 100us later the Middleware will call

    USBD_Device0_Endpoint0_OutDataReceived(int32_t len)
    

    Middleware meanwhile has copied (written) the data from the data stage to the given buffer. Correct?

    Now user (me) can read and process the data, the amount of data I can use is given in parameter len. Correct? When I use the data I shall return usbdRequestOK. Correct? Under what circumstances shall I return usbdRequestNotProcessed, usbdRequestOK, usbdRequestStall, usbdRequestNAK? In my code it seemed to be of no meaning wheter I returned usbdRequestNotProcessed or usbdRequestOK.

    .

    For a CTRL IN tranfer, i.e. the host sends a setup packet and requests data to be sent from the device to the host.

    --> Middleware calls

    USBD_Device0_Endpoint0_SetupPacketReceived (const USB_SETUP_PACKET *setup_packet, uint8_t **buf, int32_t *len)
    

    --> User (me) has to check if the request is for the user (me) If yes, user (me) has to provide the data in a buffer and point **buf to this buffer, the return value for len has to be set to the buffer size or the size of setup_packet->wLength, whichever is lower. Please advise. An optional flag can be set from the user for the user for later use in

    USBD_Device0_Endpoint0_InDataSent(int32_t len)
    

    --> A few 100us later the Middleware will call

    USBD_Device0_Endpoint0_InDataSent(int32_t len)
    

    Now user (me) knows that the data is read from the buffer and sent over the USB so that user can reuse the buffer again. Correct? The parameter len provides information on how much bytes were sent this time? Please advise. What do I do when len is smaller than the buffer I wanted to send?

    There is nothing else to do at this moment from the point of view of the middleware. Correct?

    The return value shall be usbdRequestOK. Correct? Again the question: Under what circumstances shall I return usbdRequestNotProcessed, usbdRequestOK, usbdRequestStall, usbdRequestNAK?

    Please point out what is the idea behind the concept of the middleware, a simple function reference without having an idea how an when to use the functions with what parameters and what return values is not enough, at least for me.

    Best regards
    Lutz

  • Hi Lutz,

    > still I have some questions, or let me express it the other way: I need a more detailed
    > documentation of the API to the middleware.
    Only available documents regarding custom device/class handling are here:
    www.keil.com/.../group__usbd__class_functions.html
    www.keil.com/.../group__usbd__core_functions__api.html
    www.keil.com/.../group__usbd__class_functions__api.html

    > Let me explain how far I can follow the examples shown here:
    >
    > For a CTRL OUT transfer, i.e. the host sends not only a setup packet but additional data to
    > the device ('data stage').
    >
    > --> Middleware calls

    USBD_Device0_Endpoint0_SetupPacketReceived (const USB_SETUP_PACKET *setup_packet, uint8_t **buf, int32_t *len)
    

    > --> User (me) has to check if the request is for the user (me) If yes, user can set an
    > optional flag and has to return usbdRequestOK, user has to provide a buffer for the data
    > stage to be received

    *buf = myBuffer;
    

    > The parameter len has to be set to what? My understanding is that len has to be set to
    > buffer size or to setup_packet->wLength, whichever is lower. Please advise.
    As a matter of fact is should be setup_packet->wLength or at least that, not less as Host
    knows how many bytes it wants to send and if you provide a smaller buffer than this might fail.

    *len = sizeof(myBuffer);
    if(*len > setup_packet->wLength) *len = setup_packet->wLength;
    


    No. myBuffer should be at least as maximum data stage request.

    > --> A few 100us later the Middleware will call
    When it receives all expected OUT data.

    USBD_Device0_Endpoint0_OutDataReceived(int32_t len)
    

    > Middleware meanwhile has copied (written) the data from the data stage to the given buffer.
    > Correct?
    It has actually received it directly there from the driver, and it is available there.

    > Now user (me) can read and process the data, the amount of data I can use is given in
    > parameter len. Correct?
    Yes.

    > When I use the data I shall return usbdRequestOK. Correct?
    Yes.

    > Under what circumstances shall I return usbdRequestNotProcessed, usbdRequestOK,
    > usbdRequestStall, usbdRequestNAK?
    This is written in the documentation and it says:
    - usbdRequestNotProcessed:request was not processed; processing will be done by USB library
    -> meaning: if you handle it in setup stage then you will probably not return this
    - usbdRequestOK: request was processed successfully (send Zero-Length Packet)
    -> meaning: you will do that to tell the library to send status stage ZLP
    - usbdRequestStall: request was processed but is not supported (stall Endpoint 0)
    -> meaning: you will do that to stall the status stage
    - usbdRequestNAK: request was processed but the device is busy (return NAK)
    -> meaning: you will do that to NAK the status stage
    So each of status stage responses signals different thing to Host.
    But it seems that usbdRequestNotProcessed on data stage is meaningless as if you handle the request then you need to say you handled it OK, you did not manage to handle it with NAK or you do not understand the request by returning STALL.

    > In my code it seemed to be of no meaning whether I returned usbdRequestNotProcessed or
    > usbdRequestOK.
    Yes, they behave the same on the data stage, as mentioned usbdRequestNotProcessed is meaningless here.

  • Continuation of previous post as it was too long ...

    > For a CTRL IN transfer, i.e. the host sends a setup packet and requests data to be sent from
    > the device to the host.
    >
    > --> Middleware calls

    USBD_Device0_Endpoint0_SetupPacketReceived (const USB_SETUP_PACKET *setup_packet, uint8_t
    **buf, int32_t *len)
    

    > --> User (me) has to check if the request is for the user (me) If yes, user (me) has to
    > provide the data in a buffer and point **buf to this buffer, the return value for len has to
    > be set to the buffer size or the size of setup_packet->wLength, whichever is lower. Please
    > advise.
    Yes. If you handle more requests you need to store that information in setup stage so that on
    data stage you know for which request that data is for.

    > An optional flag can be set from the user for the user for later use in

    USBD_Device0_Endpoint0_InDataSent(int32_t len)
    


    Yes, as mentioned to determine which request is being handled.

    > --> A few 100us later the Middleware will call
    When the data was actually sent.

    USBD_Device0_Endpoint0_InDataSent(int32_t len)
    


    Yes.

    > Now user (me) knows that the data is read from the buffer and sent over the USB so that user
    > can reuse the buffer again. Correct?
    Yes.

    > The parameter len provides information on how much bytes were sent this time? Please advise.
    > What do I do when len is smaller than the buffer I wanted to send?
    This should not happen as Host will poll for all the data it expects to get unless transfer is terminated with short packet, ZLP or STALL, and it should get all the data you provided in your buffer. This situation only is produced by Windows when it first requests Device descriptor and if max packet size of device is less than 18 bytes which is size of device descriptor then it terminates that request by OUT ZLP and resets the device.

    > There is nothing else to do at this moment from the point of view of the middleware. Correct?
    Yes.

    > The return value shall be usbdRequestOK. Correct? Again the question: Under what
    > circumstances shall I return usbdRequestNotProcessed, usbdRequestOK, usbdRequestStall,
    > usbdRequestNAK?
    Same as in case of before-mentioned OUT callback to provide response for the status stage.

    > Please point out what is the idea behind the concept of the middleware, a simple function
    > reference without having an idea how an when to use the functions with what parameters and
    > what return values is not enough, at least for me.
    The idea is to allow users to tailor and implement any kind of device and answer any requests coming to device, with hiding the complexity of generating descriptors handling standard requests and interacting with low level driver that is standardized (by CMSIS) so interchangeable.
    Unfortunately, custom class implementation requires deep understanding of the USB itself and is generally meant to be used in rare occasions.

    Best regards, Milorad