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

try to integrate Mult-touch and Keyboard functionalities in a single program, but it only can send Mult-touch information normally, failed to send Key value.

I try to integrate Mult-touch(touch screen) and Keyboard feature in a single program, when I run this program, the phone side(Android8.0 based) can only receive Mult-touch information, it always can't get the key value at all.

my question is:

- is it possible to integrate Mult-touch and Keyboard feature in a single program based on a single 51822 board?

- if it's feasible, could you please to give some suggestions to implement it?

 

some developing detail is as follows:

Softdevice: s130_nrf51_2.0.1_softdevice.hex

SDK: nRF5_SDK_12.2.0_f012efa

HW: nRF51 DK

report_map_data[ ] = {

// ------ MULT_TOUCH_SUPPORT-----

0x05, 0x0D, // USAGE_PAGE(Digitizers)
0x09, 0x04, // USAGE (Touch Screen)
0xA1, 0x01, // COLLECTION(Application)

// define the maximum amount of fingers that the device supports
0x09, 0x55, // USAGE(Contact Count Maximum)
0x25, 0x02, // LOGICAL_MAXIMUM (2) 
0xB1, 0x02, // FEATURE (Data,Var,Abs)

0x85, 0x01, // Report Id 1

// define the actual amount of fingers that are concurrently touching the screen
0x09, 0x54, // USAGE (Contact count)
0x95, 0x01, // REPORT_COUNT(1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x02, // INPUT (Data,Var,Abs)

// declare a finger collection
0x09, 0x22, // USAGE (Finger)
0xA1, 0x02, // COLLECTION (Logical)

// declare an identifier for the finger
0x09, 0x51, // USAGE (Contact Identifier) //touch ID
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)

// declare Tip Switch and In Range
0x09, 0x42, // USAGE (Tip Switch)
0x09, 0x32, // USAGE (In Range)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x02, // REPORT_COUNT(2)
0x81, 0x02, // INPUT (Data,Var,Abs)

// declare the remaining 6 bits of the first data byte as constant -> the driver will ignore them
0x95, 0x06, // REPORT_COUNT (6)
0x81, 0x03, // INPUT (Cnst,Ary,Abs)

// define absolute X and Y coordinates of 16 bit each (percent values multiplied with 100)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x16, 0x00, 0x00, // Logical Minimum (0)
0x26, 0x10, 0x27, // Logical Maximum (10000)
0x36, 0x00, 0x00, // Physical Minimum (0)
0x46, 0x10, 0x27, // Physical Maximum (10000)
0x66, 0x00, 0x00, // UNIT (None)
0x75, 0x10, // Report Size (16),
0x95, 0x02, // Report Count (2),
0x81, 0x02, // Input (Data,Var,Abs)
0xC0, // END_COLLECTION


// declare a finger collection
0xA1, 0x02, // COLLECTION (Logical)
0x05, 0x0D, // USAGE_PAGE(Digitizers)

// declare an identifier for the finger
0x09, 0x51, // USAGE (Contact Identifier) // touch ID
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)

// declare Tip Switch and In Range
0x09, 0x42, // USAGE (Tip Switch)
0x09, 0x32, // USAGE (In Range)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x02, // REPORT_COUNT(2)
0x81, 0x02, // INPUT (Data,Var,Abs)

// declare the remaining 6 bits of the first data byte as constant -> the driver will ignore them
0x95, 0x06, // REPORT_COUNT (6)
0x81, 0x03, // INPUT (Cnst,Ary,Abs)

// define absolute X and Y coordinates of 16 bit each (percent values multiplied with 100)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x16, 0x00, 0x00, // Logical Minimum (0)
0x26, 0x10, 0x27, // Logical Maximum (10000)
0x36, 0x00, 0x00, // Physical Minimum (0)
0x46, 0x10, 0x27, // Physical Maximum (10000)
0x66, 0x00, 0x00, // UNIT (None)
0x75, 0x10, // Report Size (16),
0x95, 0x02, // Report Count (2),
0x81, 0x02, // Input (Data,Var,Abs)
0xC0, // END_COLLECTION
0xC0, // END_COLLECTION

// With this declaration a data packet must be sent as:
// byte 1 -> "contact count" (always == 1)
// byte 2 -> "contact identifier" (any value)
// byte 3 -> "Tip Switch" state (bit 0 = Tip Switch up/down, bit 1 = In Range)
// byte 4,5 -> absolute X coordinate (0...10000)
// byte 6,7 -> absolute Y coordinate (0...10000)

// byte 8 -> "contact identifier" (any value)
// byte 9 -> "Tip Switch" state (bit 0 = Tip Switch up/down, bit 1 = In Range)
// byte 10, 11 -> absolute X coordinate (0...10000)
// byte 12,13 -> absolute Y coordinate (0...10000)

// ------ KEYBOARD_SUPPORT-----
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)

0x85, 0x02, // Report ID 2

0x05, 0x07, // Usage Page (Key Codes)
0x19, 0xe0, // Usage Minimum (224)
0x29, 0xe7, // Usage Maximum (231)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data, Variable, Absolute)

0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x01, // Input (Constant) reserved byte(1)

0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (Page# for LEDs)
0x19, 0x01, // Usage Minimum (1)
0x29, 0x05, // Usage Maximum (5)
0x91, 0x02, // Output (Data, Variable, Absolute), Led report
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x01, // Output (Data, Variable, Absolute), Led report padding

0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x65, // Logical Maximum (101)
0x05, 0x07, // Usage Page (Key codes)
0x19, 0x00, // Usage Minimum (0)
0x29, 0x65, // Usage Maximum (101)
0x81, 0x00, // Input (Data, Array) Key array(6 bytes)

0x09, 0x05, // Usage (Vendor Defined)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Count (2)
0x95, 0x02, // Report Size (8 bit)
0xB1, 0x02, // Feature (Data, Variable, Absolute)

0xC0 // End Collection (Application)
};

I have verified report map data of Mult-touch and Keyboard separately, they are functional.

1. send Mult-touch information with the below code

static void mouse_moveto_2xy(uint8_t value,uint16_t x_delta,uint16_t y_delta,
uint16_t x2_delta,uint16_t y2_delta)
{
     // With this declaration a data packet must be sent as:
     // byte 1 -> "contact count" (always == 1)
     // byte 2 -> "contact identifier" (any value)
     // byte 3 -> "Tip Switch" state (bit 0 = Tip Switch up/down, bit 1 = In Range)
     // byte 4,5 -> absolute X coordinate (0...10000)
     // byte 6,7 -> absolute Y coordinate (0...10000)
     uint8_t buffer[INPUT_REP_TOUCH_LEN];
     uint32_t err_code;
     APP_ERROR_CHECK_BOOL(INPUT_REP_TOUCH_LEN == 13);

     x_delta = MIN(x_delta, 0x2710);
     y_delta = MIN(y_delta, 0x2710);

     buffer[0] = CONTACT_COUNT;
     buffer[1] = 1;
     buffer[2] = value;
     buffer[3] = x_delta & 0x00ff;
     buffer[4] = (x_delta>>8)&0x00ff;
     buffer[5] = y_delta & 0x00ff;
     buffer[6] = (y_delta>>8)&0x00ff;

    buffer[7] = 2;
    buffer[8] = value;
    buffer[9] = x2_delta & 0x00ff;
    buffer[10] = (x2_delta>>8)&0x00ff;
    buffer[11] = y2_delta & 0x00ff;
    buffer[12] = (y2_delta>>8)&0x00ff;

     err_code = ble_hids_inp_rep_send(&m_hids,
          INPUT_REP_TOUCH_INDEX,
          INPUT_REP_TOUCH_LEN,
          buffer);
     if ((err_code != NRF_SUCCESS) &&
          (err_code != NRF_ERROR_INVALID_STATE) &&
          (err_code != BLE_ERROR_NO_TX_PACKETS) &&
          (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING))
     {
          APP_ERROR_HANDLER(err_code);
     }
}

static void touch_emulation(bsp_event_t event)
{
     static uint16_t touch_num = 8000;
     static uint16_t touch_num2 = 2000;

     switch (event)
     {
     case BSP_EVENT_KEY_1:
          if (m_conn_handle != BLE_CONN_HANDLE_INVALID) {
               mouse_moveto_2xy(1,touch_num,touch_num, touch_num2, touch_num2);
               touch_num -= 100;
               if(touch_num < 1000)
                    touch_num = 8000;

               touch_num2 += 100;
               if(touch_num2 > 8000)
                    touch_num2 = 1000;
     }
     break;

     case BSP_EVENT_KEY_3:
          if (m_conn_handle != BLE_CONN_HANDLE_INVALID) {
               mouse_moveto_2xy(1,touch_num2,touch_num2, touch_num,touch_num);
               touch_num -= 100;
          if(touch_num < 1000)
               touch_num = 8000;

          touch_num2 += 100;
          if(touch_num2 > 8000)
               touch_num2 = 1000;
     }
     break;

     default:
          // mouse_moveto_2xy(0,5000,5000);
          // touch_num=5000;
     break;
     }
}

2. send Key value with the below code

static void keys_send(uint8_t key_pattern_len, uint8_t * p_key_pattern)
{
      uint32_t err_code;
      uint16_t actual_len;

      err_code = send_key_scan_press_release(&m_hids,
            p_key_pattern,
            key_pattern_len,
            0,
            &actual_len);
      // An additional notification is needed for release of all keys, therefore check
      // is for actual_len <= key_pattern_len and not actual_len < key_pattern_len.
      if ((err_code == BLE_ERROR_NO_TX_PACKETS) && (actual_len <= key_pattern_len))
      {
            // Buffer enqueue routine return value is not intentionally checked.
            // Rationale: Its better to have a a few keys missing than have a system
            // reset. Recommendation is to work out most optimal value for
            // MAX_BUFFER_ENTRIES to minimize chances of buffer queue full condition
            UNUSED_VARIABLE(buffer_enqueue(&m_hids, p_key_pattern, key_pattern_len, actual_len));
      }


      if ((err_code != NRF_SUCCESS) &&
            (err_code != NRF_ERROR_INVALID_STATE) &&
            (err_code != BLE_ERROR_NO_TX_PACKETS) &&
            (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
      )
      {
            APP_ERROR_HANDLER(err_code);
      }
}

Parents
  • Hi,

    The function "send_key_scan_press_release" uses index INPUT_REPORT_KEYS_INDEX, which needs to be concise with your configuration (in your specific case; should be set to 1).

    An easier way to send keyboard data is to send it directly without using the added buffering logic in the example, for instance like this:
    // Send "hi"
    uint8_t temp_buf[INPUT_REPORT_KEYS_MAX_LEN] = {0x00, 0x00, 0xb, 0xc, 0x2c, 0x0, 0x0, 0x0};
    ble_hids_inp_rep_send(&m_hids, INPUT_REPORT_KEYS_INDEX, INPUT_REPORT_KEYS_MAX_LEN, (uint8_t*)temp_buf, m_conn_handle);

    Could you check your index values and report them here if it still does not work?

    Kind regards,
    Håkon

  • Hi Hakon Alseth,

    I confirmed that the INPUT_REPORT_KEYS_INDEX is 1. Actually I have configured input and output report in hids_init( ) as follows:

    {

    ...

    ble_hids_inp_rep_init_t input_report_array[2];
    ble_hids_outp_rep_init_t output_report_array[1];

    p_input_report = &input_report_array[INPUT_REP_TOUCH_INDEX];
    p_input_report->max_len = INPUT_REP_TOUCH_LEN;
    p_input_report->rep_ref.report_id = INPUT_REP_TOUCH_ID;
    p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;

    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.cccd_write_perm);
    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.write_perm);

    p_input_report = &input_report_array[INPUT_REPORT_KEYS_INDEX ];
    p_input_report->max_len = INPUT_REPORT_KEYS_MAX_LEN;
    p_input_report->rep_ref.report_id = INPUT_REPORT_KEYS_ID;
    p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;

    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.cccd_write_perm);
    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.write_perm);

    p_output_report = &output_report_array[OUTPUT_REPORT_INDEX];
    p_output_report->max_len = OUTPUT_REPORT_MAX_LEN;
    p_output_report->rep_ref.report_id = OUTPUT_REP_REF_ID;
    p_output_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_OUTPUT;

    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_output_report->security_mode.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_output_report->security_mode.write_perm);

    hid_info_flags = HID_INFO_FLAG_REMOTE_WAKE_MSK | HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK;

    memset(&hids_init_obj, 0, sizeof(hids_init_obj));

    hids_init_obj.evt_handler = on_hids_evt;
    hids_init_obj.error_handler = service_error_handler;
    hids_init_obj.is_kb = false;
    hids_init_obj.is_mouse = false;
    hids_init_obj.inp_rep_count = 2;
    hids_init_obj.p_inp_rep_array = input_report_array;
    hids_init_obj.outp_rep_count = 1;
    hids_init_obj.p_outp_rep_array = output_report_array;

    hids_init_obj.feature_rep_count = 0;
    hids_init_obj.p_feature_rep_array = NULL;

    hids_init_obj.rep_map.data_len = sizeof(report_map_data);
    hids_init_obj.rep_map.p_data = report_map_data;

    hids_init_obj.hid_information.bcd_hid = BASE_USB_HID_SPEC_VERSION;
    hids_init_obj.hid_information.b_country_code = 0;
    hids_init_obj.hid_information.flags = hid_info_flags;
    hids_init_obj.included_services_count = 0;
    hids_init_obj.p_included_services_array = NULL;

    ...

    }

    some macro defines as follows:

    #define INPUT_REP_TOUCH_INDEX  0
    #define INPUT_REP_TOUCH_LEN     13
    #define INPUT_REP_TOUCH_ID         1 

    #define INPUT_REPORT_KEYS_INDEX          1

    #define OUTPUT_REPORT_MAX_LEN            8

    #define INPUT_REPORT_KEYS_ID                 2

    #define OUTPUT_REPORT_INDEX                  0

    #define OUTPUT_REPORT_MAX_LEN            1

    #define OUTPUT_REP_REF_ID                        0

    In addition, I have set the appearance to BLE_APPEARANCE_GENERIC_HID. If I keep the appearance as BLE_APPEARANCE_HID_KEYBOARD, it can't send any information to phone side.

    Best Regards,

    QiangHuang

Reply
  • Hi Hakon Alseth,

    I confirmed that the INPUT_REPORT_KEYS_INDEX is 1. Actually I have configured input and output report in hids_init( ) as follows:

    {

    ...

    ble_hids_inp_rep_init_t input_report_array[2];
    ble_hids_outp_rep_init_t output_report_array[1];

    p_input_report = &input_report_array[INPUT_REP_TOUCH_INDEX];
    p_input_report->max_len = INPUT_REP_TOUCH_LEN;
    p_input_report->rep_ref.report_id = INPUT_REP_TOUCH_ID;
    p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;

    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.cccd_write_perm);
    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.write_perm);

    p_input_report = &input_report_array[INPUT_REPORT_KEYS_INDEX ];
    p_input_report->max_len = INPUT_REPORT_KEYS_MAX_LEN;
    p_input_report->rep_ref.report_id = INPUT_REPORT_KEYS_ID;
    p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;

    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.cccd_write_perm);
    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.write_perm);

    p_output_report = &output_report_array[OUTPUT_REPORT_INDEX];
    p_output_report->max_len = OUTPUT_REPORT_MAX_LEN;
    p_output_report->rep_ref.report_id = OUTPUT_REP_REF_ID;
    p_output_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_OUTPUT;

    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_output_report->security_mode.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_output_report->security_mode.write_perm);

    hid_info_flags = HID_INFO_FLAG_REMOTE_WAKE_MSK | HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK;

    memset(&hids_init_obj, 0, sizeof(hids_init_obj));

    hids_init_obj.evt_handler = on_hids_evt;
    hids_init_obj.error_handler = service_error_handler;
    hids_init_obj.is_kb = false;
    hids_init_obj.is_mouse = false;
    hids_init_obj.inp_rep_count = 2;
    hids_init_obj.p_inp_rep_array = input_report_array;
    hids_init_obj.outp_rep_count = 1;
    hids_init_obj.p_outp_rep_array = output_report_array;

    hids_init_obj.feature_rep_count = 0;
    hids_init_obj.p_feature_rep_array = NULL;

    hids_init_obj.rep_map.data_len = sizeof(report_map_data);
    hids_init_obj.rep_map.p_data = report_map_data;

    hids_init_obj.hid_information.bcd_hid = BASE_USB_HID_SPEC_VERSION;
    hids_init_obj.hid_information.b_country_code = 0;
    hids_init_obj.hid_information.flags = hid_info_flags;
    hids_init_obj.included_services_count = 0;
    hids_init_obj.p_included_services_array = NULL;

    ...

    }

    some macro defines as follows:

    #define INPUT_REP_TOUCH_INDEX  0
    #define INPUT_REP_TOUCH_LEN     13
    #define INPUT_REP_TOUCH_ID         1 

    #define INPUT_REPORT_KEYS_INDEX          1

    #define OUTPUT_REPORT_MAX_LEN            8

    #define INPUT_REPORT_KEYS_ID                 2

    #define OUTPUT_REPORT_INDEX                  0

    #define OUTPUT_REPORT_MAX_LEN            1

    #define OUTPUT_REP_REF_ID                        0

    In addition, I have set the appearance to BLE_APPEARANCE_GENERIC_HID. If I keep the appearance as BLE_APPEARANCE_HID_KEYBOARD, it can't send any information to phone side.

    Best Regards,

    QiangHuang

Children
Related