This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

HID Finger Swipe Functionality (iPhone)

I’m very familiar with the HID keyboard and mouse profile and have built products using it but need direction on how to replicate the functionality of a up/down/left/right finger swipe on a iPhone. Any guidance will be valuable.  Thanks 

Parents
  • What I'm trying to accomplish is exactly what this remote is doing but not sure what type of Bluetooth HID profile it's working with. What it's doing is performing up/down/left/right scroll as if it was a finger swipe.  I think it is acting like a digitizer but it shows up as a keyboard profile and not a mouse.  There is another thread that talks about HID digitizer and has an example project to go with it but its base is on top of mouse. So I'm little confused on what HID profile to focus on.  I do have the packet logs captured from this remote.  Is there a way to capture the report profile from a device?

    www.aliexpress.com/.../4000061114207.html

  • Hi Matthew

    If you have access to the device in question you should be able to connect to it from the nRF Connect mobile app, and read out the HID report descriptor from there. 

    Then you can try to replicate that HID descriptor in your own peripheral implementation. 

    Best regards
    Torbjørn

  • Hi Ovrebekk,

    I'm still having issues with not all packets are being sent.  Like I mentioned before I think it's a timing issue and I'm guessing there is a required delay or acknowledgement that is required before sending another.  Still no solution for this.  Also,  been working on building a packet structure from the report descriptor.  Have taken my best guess since it's the first time ever doing it.  I'm unable to get the correct values sent to the phone with the current packet structure that I tried creating from the report.  Your expert advice will be helpful thanks.

    byte[0] = Tip Switch, Range, Contact Id
    bit 0 = Tip Switch
    bit 1 = In Range
    bit 2 = Not Used
    bit 3 = Not Used
    bit 4 = Contact Id
    bit 5 = Contact Id
    bit 6 = Contact Id
    bit 7 = Contact Id
    byte[1] = X Coordinate LSB
    byte[2] = X and Y Axis Combined
    bit 0 = X Coordinate
    bit 1 = X Coordinate
    bit 2 = X Coordinate
    bit 3 = X Coordinate MSB
    bit 4 = Y Coordinate LSB
    bit 5 = Y Coordinate
    bit 6 = Y Coordinate
    bit 7 = Y Coordinate
    byte[3] = Y Coordinate MSB

    typedef PACKED_STRUCT { uint8_t tip_switch : 1; uint8_t range : 1; uint8_t contact_id : 4; uint16_t x : 12; uint16_t y : 12; } stylus_report_t;

    ## UP Packet 1 Decode ##
    0x03 0xF4 0x01 0x32
    00000011 11110100 00000001 00110010

    tip_switch = 1
    range = 1
    contact_id = 0
    x = 111101000000 = 801 ??
    y = 000100110010 = 306 ??

    Logged Packet Value: 43C8 C804
    
    typedef PACKED_STRUCT
    {
        uint8_t  tip_switch : 1;
        uint8_t  range      : 1;
        uint8_t  contact_id : 4;
        uint16_t x          : 12;
        uint16_t y          : 12;
    } stylus_report_t;
    
    static void digitizer_send_test() {
      stylus_report_t report = {0};
      report.tip_switch = 1;
      report.range = 1;
      report.contact_id = 0;
      report.x = 801;
      report.y = 306;
    
      uint32_t err_code;
      err_code = ble_hids_inp_rep_send(&m_hids, 
                                       INPUT_REPORT_DIG_INDEX,
                                       INPUT_REPORT_DIG_MAX_LEN,
                                       (uint8_t *)&report,
                                       m_conn_handle);
      APP_ERROR_CHECK(err_code);
    }
  • Check for errors by not commenting out this line:

    //APP_ERROR_CHECK(err_code);

    I am never able to send 8 notifications back-to-back in my own applications using the default configuration.  I will get the NRF_ERROR_RESOURCES error and then I wait for BLE_GATTS_EVT_HVN_TX_COMPLETE to send the next notification.  I think you can also increase the queue size:

    https://devzone.nordicsemi.com/f/nordic-q-a/53941/nrf_error_resources

  • Hi Jefferson,

    Thanks for the feedback.  You might be right about the queue size.  I tried changing a few settings but with no luck.  I noticed that the keyboard example has a key buffer that it uses. Not sure how it all works and what is unloading the buffer.  Not sure that is the same way I want to do it. I would think not.

    app_error_fault_handler (id=0x00004001, info=0x2000fe10, pc=0x00028553)
  • I think the correct way is to wait for the event BLE_GATTS_EVT_HVN_TX_COMPLETE before sending the next packet if you get the error NRF_ERROR_RESOURCES.  If you just want to see something working quickly, maybe just put a delay after each packet or when you get NRF_ERROR_RESOURCES:

    err_code = ble_hids_inp_rep_send(&m_hids, INPUT_REPORT_DIG_INDEX, INPUT_REPORT_DIG_MAX_LEN, packet_1_data, m_conn_handle);

    nrf_delay_ms(50);

    err_code = ble_hids_inp_rep_send(&m_hids, INPUT_REPORT_DIG_INDEX, INPUT_REPORT_DIG_MAX_LEN, packet_1_data, m_conn_handle);

    nrf_delay_ms(50);

    ...

  • Hi

    I agree with Jefferson's comment. When the NRF_ERROR_RESOURCES error occurs you should wait for the next BLE_GATTS_EVT_HVN_TX_COMPLETE event, and then you can continue uploading packets until the error occurs again (and then rinse and repeat). 

    In order to try sending more packets pr connection event you can try increasing the NRF_SDH_BLE_GAP_EVENT_LENGTH define in sdk_config.h, but as the phone also has it's own limit there is no guarantee that increasing the GAP event length will increase the total number of packets. 

    Best regards
    Torbjørn

Reply
  • Hi

    I agree with Jefferson's comment. When the NRF_ERROR_RESOURCES error occurs you should wait for the next BLE_GATTS_EVT_HVN_TX_COMPLETE event, and then you can continue uploading packets until the error occurs again (and then rinse and repeat). 

    In order to try sending more packets pr connection event you can try increasing the NRF_SDH_BLE_GAP_EVENT_LENGTH define in sdk_config.h, but as the phone also has it's own limit there is no guarantee that increasing the GAP event length will increase the total number of packets. 

    Best regards
    Torbjørn

Children
  • Torbjørn & Jefferson,

    I was able to successfully get my test code to work.  It's not pretty but the concept has been proven.  I was able to reverse engineer the remote and combine it with the keyboard report.  The solution was to queue up the packets and send them sequentially after each success TX response.  If I had time I would use the nrf_queue or nrf_ringbuffer library for this solution.

    The final functionality is when you press one of the 4 buttons it will send a stylus/pen swipe sequence.  You can see this in action if you are in a drawing app.

    I want to thank you Torbjørn for taking the time to answer my questions that lead me to the answers I was seeking.  I learned a great deal from this exercise.  I have attached the final code for others to reference if desired.

    All that is left is to break down the packet structure and build a data structure for.  If I get that working I will post the final structure.  All I have to go on is what I wrote in a few post back.

    0167.main.c

  • Hi guys,

    I was facing the same issue than matt_wilson: emulate swipe movement from a custom HID Device.

    From this HID Report (https://devzone.nordicsemi.com/f/nordic-q-a/38587/is-multi-touch-hid-possible-with-nrf51822-chip), i'm able to "customise" my swipe movements. It's a quick fix but it actually works. 

    I start a timer when buttons are pressed, and send the report as this:

    static void swipe_timeout_handler(void * p_context)
    {
    
      switch (swipe_type)
        {
            case LEFT:
                y = 15000;
                x = (30000) - cpt*2500;
                cpt++;
                digitizer_send3(0, 1, x, y, true);
                if(cpt == 5) {
                    digitizer_send3(0, 1, x, y, false);
                    timers_stop();
                    cpt = 0;
                }
                break;
    
            case RIGHT:
                y = 15000;
                x = cpt*2500;
                cpt++;
                digitizer_send3(0, 1, x, y, true);
                if(cpt == 5) {
                    digitizer_send3(0, 1, x, y, false);
                    timers_stop();
                    cpt = 0;
                }
                break;
    
            case UP:
                y = (30000) - cpt*2500;
                x = 0;
                cpt++;
                digitizer_send3(0, 1, x, y, true);
                if(cpt == 5) {
                    digitizer_send3(0, 1, x, y, false);
                    timers_stop();
                    cpt = 0;
                }
                break;
    
            case DOWN:
                y = cpt*2500;
                x = 0;
                cpt++;
                digitizer_send3(0, 1, x, y, true);
                if(cpt == 10) {
                    digitizer_send3(0, 1, x, y, false);
                    timers_stop();
                    cpt = 0;
                }
                break;
    
            default:
                // No implementation needed.
                break;
        }
       
    }

    By doing this way, it is possible to emulate differents kinds of swipe by changing timer, cpt, x, y.

    While writing, i've see the matt solution with queuing. Will try this later...

  • Hi 

    Good to hear you found a working solution Matthew, and thanks for sharing the code Slight smile

    Same to the others chiming in as well, clearly this is something many are trying to do.

    Once you share your final code you can mark you reply as the answer, making it easy for other to find also.  

    Best regards
    Torbjørn

  • Torbjorn,

    Thanks for all your help.  I have been in the process of migrating my work to my project code base.  I have been using the Adafruit Bluefruit52 library because it has simplified my development time.  I would rather do it in Segger Studio but right now I prefer to use this 3rd party library because it handles most of the basic/core functionality of an application.  Of course I ran into issues and if you have time please review this other ticket.  I'm so close to getting this working but reaching out for some final help because I hit a hard wall...

    https://devzone.nordicsemi.com/f/nordic-q-a/58116/hid-digitizer-stylus-integration---adafruit-bluefruit52

  • Hi Matthew

    The case was given to me already, I will take a look next week. 

    I have to warn you that we can't really support software libraries not released by us. Bluefruit52 is an Arduino API I assume and would have to be supported by them, but I will try to help if it's not too time consuming. 

    Best regards
    Torbjørn

Related