Using PTP to control camera on M0 board

Hey everyone, long time no see.
For about a week now, I am trying to get PTP (picture transfer protocol) on M0 board (Trinket M0) working using USB host library (for SAMD). But no matter what, it just never works. Here is a function I use to setup the camera (endpoints and configs):

void camInit() {
    //zero structs
    for (int i = 0; i < 4; i++) {
        ep_info[i].bmAttribs = 0;
        ep_info[i].bmNakPower = 0;
        ep_info[i].bmRcvToggle = 0;
        ep_info[i].bmSndToggle = 0;
        ep_info[i].epAddr = 0;
        ep_info[i].epAttribs = 0;
        ep_info[i].maxPktSize = 0;

    //setup endpoints (retrieved from descriptors manually)
    ep_info[0] = *(UsbH.getEpInfoEntry(0, 0));
    ep_info[1].maxPktSize   = 64;
    ep_info[1].bmAttribs    = 2;
    ep_info[1].bmNakPower   = 1;
    ep_info[1].epAddr       = 0x81;
    ep_info[2].maxPktSize  = 64;
    ep_info[2].bmAttribs   = 2;
    ep_info[2].bmNakPower  = 1;
    ep_info[2].epAddr      = 0x02; //0x82 but PTP
    ep_info[3].maxPktSize = 64;
    ep_info[3].bmAttribs  = 3;
    ep_info[3].bmNakPower = 1;
    ep_info[3].epAddr     = 0x83;
    //set endpoints entry (camera has 4 nedpoints - control, in, out, interrupt)
    int rcode;
    rcode = UsbH.setEpInfoEntry(1, 4, ep_info);
    u8x8log.printf("RC: %d\n", rcode);

    //set config (my camera has only 1)
    rcode = UsbH.setConf(1, 0, 1);
    u8x8log.printf("RC: %d\n", rcode);

And here is a function that is supposed to send "GetDeviceInfo" command and retrieve at least some data:

void camPoll() {
    int rcode;
    uint16_t length = (sizeof(uint16_t)*2 + sizeof(uint32_t)*2); //dont care about the rest of the container
    uint8_t data[length];
    memset(data, 0, length);
    //little endian
    data[0] = 0x0C;   //len 0
    data[4] = 0x01;   //type 0
    data[6] = 0x01;   //code 1
    data[7] = 0x10;   //code 0

    //send command container
    rcode = UsbH.outTransfer(1, 0x02, length, data);
    u8x8log.printf("RC: %d\n", rcode);
    //receive data
    uint16_t read = 64;
    uint8_t in_data[64];
    memset(in_data, 0, 64);
    rcode = UsbH.inTransfer(1, 0x81, &read, in_data);
    u8x8log.printf("RC: %d\n", rcode);

    //print data
    for (int i = 0; i < 64; i++) {
        u8x8log.printf("%02x", in_data[i]);
        if ((i + 1) % 8 == 0) u8x8log.printf("\n");
  • Device address is 1
  • bulk out endpoint is 0x82, but PTP protocol requires out to be between 0x01 and 0x0f -> 0x02
  • bulk in endpoint is 0x81
  • max packet size is 64 (that's why read is 64)

The container I am sending is from here and is as follows:

size   name
 4B    length         - 12B as I don't have a payload
 2B    type           - 0x0001 = command block
 2B    code           - 0x1001 = GetDeviceInfo PTP command
 4B    transaction ID - 0x00000000 - GetDeviceInfo should have 0
 ?B    payload        - not used here

But no matter what, I always get return code 0 from both out and in transfers, yet no data from in (in_data is still zeroed). Also when sending the command for the third time, it then starts to return 2 instead of 0 (which is "USB_ERRORFLOW").

Do you guys have any idea what to do to make this work?

I only skimmed your code and I'm not familiar with your device, but judging by your tale, it may well be that your device is too slow to keep up with what's going on and can't digest the inputs in time. Try adding a few, short delays after the commands. If you have the datasheet, you should be able to look up the minimum reaction time there.

Easy way to complete the code by using a new rule.

As far as I am aware, PTP does name any specific delay/response time. But there is already a 20ms delay from the USB standard.
And adding delays (200ms) sadly did not change anything.
Also, I guess that the device has to respond in time as otherwise, the RC on inTransfer wouldn't return 0.