Download client HID sample code
http://anselm.hoffmeister.be/computer/hidclient/hidclient-20120728.tar.bz2
HID report descriptor sample
http://www.instructables.com/id/USB-Wii-Classic-Controller/step13/Bonus-Keyboard-and-Mouse
Register record to SDP sample
http://blog.csdn.net/huipengzhao/article/details/18268201
1.
//////////////////////// close host hid service ////////////////////////
###undefined those lines in (a.) and (b.)###
(a.)
gedit /mnt/projects/victor_mnt/myandroid/external/bluetooth/bluez/android/client/halbt.c
const struct interface *interfaces[] =
{
// &audio_if, // class will show 0x0800000
&bluetooth_if,
// &av_if,
&rc_if,
&gatt_if,
&gatt_client_if,
&gatt_server_if,
// &hf_if, // disable handsfree
// &hh_if, // disable hidhost
// &pan_if, // class will show 0x0200000
&sock_if,
NULL
};
...
...
...
static void init(void)
{
static const char * const inames[] =
{
#if 0
BT_PROFILE_HANDSFREE_ID,
BT_PROFILE_ADVANCED_AUDIO_ID,
BT_PROFILE_AV_RC_ID,
BT_PROFILE_HEALTH_ID,
BT_PROFILE_HIDHOST_ID,
BT_PROFILE_PAN_ID,
#endif
BT_PROFILE_HEALTH_ID,
BT_PROFILE_GATT_ID,
BT_PROFILE_SOCKETS_ID
};
const struct method *m;
const char *argv[4];
char init_audio[] = "audio init";
char init_bt[] = "bluetooth init";
uint32_t i;
process_line(init_audio);
process_line(init_bt);
m = get_interface_method("bluetooth", "get_profile_interface");
for (i = 0; i < NELEM(inames); ++i) {
argv[2] = inames[i];
m->func(3, argv);
}
/* Init what is available to init */
for (i = 2; i < NELEM(interfaces) - 1; ++i)
{
m = get_interface_method(interfaces[i]->name, "init");
if (m != NULL)
m->func(2, argv);
}
}
(b.)
gedit /mnt/projects/victor_mnt/myandroid/external/bluetooth/bluez/android/hal-bluetooth.c
static const void *get_profile_interface(const char *profile_id)
{
DBG("%s", profile_id);
if (!interface_ready())
return NULL;
if (!strcmp(profile_id, BT_PROFILE_SOCKETS_ID))
return bt_get_sock_interface();
#if 0 // disable we don't need socket server.
if (!strcmp(profile_id, BT_PROFILE_HIDHOST_ID))
return bt_get_hidhost_interface();
if (!strcmp(profile_id, BT_PROFILE_PAN_ID))
return bt_get_pan_interface();
if (!strcmp(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID))
return bt_get_a2dp_interface();
if (!strcmp(profile_id, BT_PROFILE_AV_RC_ID))
return bt_get_avrcp_interface();
if (!strcmp(profile_id, BT_PROFILE_HANDSFREE_ID))
return bt_get_handsfree_interface();
#endif
return NULL;
}
2.
//////////////////////// Register record to client SDP ////////////////////////
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <bluetooth/sdp.h>
#include <sdp_lib.h>
#define L2CAP_PSM_HIDP_CTRL 0x11
#define L2CAP_PSM_HIDP_INTR 0x13
#define HIDINFO_NAME "Bluetooth HID Test"
#define HIDINFO_PROV "Huipeng Zhao"
#define HIDINFO_DESC "Test Bluetooth HID"
static unsigned char s_hid_report_desc_keyboard[] =
{
0x05, 0x8c, // USAGE_PAGE (barcode scanner page)
0x09, 0x02, // USAGE (barcode scanner device)
0xa1, 0x01, // COLLECTION (application)
0x09, 0x12, // USAGE (scanned data report)
0xa1, 0x02, // COLLECTION (Logical)
0x85, 0x01, // REPORT_ID (1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x03, // REPORT_COUNT (3)
0x09, 0xfb, //usage symbology 1
0x09, 0xfc, //usage symbology 2
0x09, 0xfd, //usage symbology 3
0x81, 0x02, //input data var abs
0x95, 0x20, //count 32 bytes
0x09, 0xfe, //usage decoded data
0x82, 0x02, 0x01, //input data var abs buf
0x25, 0x01, //logical max,
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x09, 0xff, //usage data continued
0x81, 0x02, //input data var abs
0xc0, // END COLLECTION
0xc0, // END COLLECTION
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x85, 0x02, // REPORT_ID (2)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x05, 0x08, // USAGE_PAGE (LEDs)
0x19, 0x01, // USAGE_MINIMUM (Num Lock)
0x29, 0x05, // USAGE_MAXIMUM (Kana)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x03, // REPORT_SIZE (3)
0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0, // END_COLLECTION
/*0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x85, 0x03, // REPORT_ID (3)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x03, // USAGE_MAXIMUM (Button 3)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x03, // REPORT_COUNT (3)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x05, // REPORT_SIZE (5)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x09, 0x38, // USAGE (Wheel)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x03, // REPORT_COUNT (3)
0x81, 0x06, // INPUT (Data,Var,Rel)
0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
0x0a, 0x38, 0x02, // USAGE (Undefined)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION*/
};
struct hidc_info_t
{
char * service_name;
char * description;
char * provider;
char * desc_data; //USB HID Report Descriptor data
unsigned int desc_len;
unsigned int sub_class;
};
struct hidc_info_t s_hidc_info =
{
.service_name = HIDINFO_NAME,
.description = HIDINFO_DESC,
.provider = HIDINFO_PROV,
.desc_data = (char*)&s_hid_report_desc_keyboard,
.desc_len = sizeof(s_hid_report_desc_keyboard),
.sub_class = 0x80,
};
static void add_lang_attr(sdp_record_t *r)
{
sdp_lang_attr_t base_lang;
sdp_list_t *langs = 0;
/* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
base_lang.encoding = 106;
base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
langs = sdp_list_append(0, &base_lang);
sdp_set_lang_attr(r, langs);
sdp_list_free(langs, 0);
}
//==============================================================================
// Sample code start
//==============================================================================
//ATTR 0x0001
static void Inno_sdp_set_ServiceClassIDList(sdp_record_t *record) {
uuid_t hidsvcls_uuid;
sdp_list_t *svclass_id;
sdp_uuid16_create(&hidsvcls_uuid, HID_SVCLASS_ID);
svclass_id = sdp_list_append(0, &hidsvcls_uuid);
sdp_set_service_classes(record, svclass_id);
}
//ATTR 0x0004
static void Inno_sdp_set_ProtocolDescriptorList(sdp_record_t *record) {
uuid_t hidp_uuid, l2cap_uuid;
sdp_list_t *proto_l2cap, *proto_hidp, *apseq, *aproto;
sdp_data_t *psm;
unsigned short ctrl = L2CAP_PSM_HIDP_CTRL;
sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
proto_l2cap = sdp_list_append(0, &l2cap_uuid);
psm = sdp_data_alloc(SDP_UINT16, &ctrl);
proto_l2cap = sdp_list_append(proto_l2cap, psm);
sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
proto_hidp = sdp_list_append(0, &hidp_uuid);
apseq = sdp_list_append(0, proto_l2cap);
apseq = sdp_list_append(apseq, proto_hidp);
aproto = sdp_list_append(0, apseq);
sdp_set_access_protos(record, aproto);
}
//ATTR 0x0005
static void Inno_sdp_set_BrowseGroupList(sdp_record_t *record) {
uuid_t browsegroup_uuid;
sdp_list_t *browsegroup_seq;
sdp_uuid16_create(&browsegroup_uuid, PUBLIC_BROWSE_GROUP);
browsegroup_seq = sdp_list_append(0, &browsegroup_uuid);
sdp_set_browse_groups(record, browsegroup_seq);
}
//ATTR 0x0006
static void Inno_sdp_set_LanguageBaseAttributeIDList(sdp_record_t *record) {
sdp_lang_attr_t base_lang;
sdp_list_t *langs = 0;
base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
base_lang.encoding = 106;
base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
langs = sdp_list_append(0, &base_lang);
sdp_set_lang_attr(record, langs);
sdp_list_free(langs, 0);
}
//ATTR 0x0009
static void Inno_sdp_set_BluetoothProfileDescriptorList(sdp_record_t *record) {
sdp_profile_desc_t profile;
sdp_list_t *pfseq;
sdp_uuid16_create(&profile.uuid, HID_PROFILE_ID);
profile.version = 0x0100;
pfseq = sdp_list_append(0, &profile);
sdp_set_profile_descs(record, pfseq);
}
//ATTR 0x000d
static void Inno_sdp_set_AdditionalProtocolDescriptorLists(sdp_record_t *record) {
uuid_t hidp_uuid, l2cap_uuid;
sdp_list_t *proto_l2cap, *proto_hidp, *apseq, *aproto;
sdp_data_t *psm;
unsigned short intr = L2CAP_PSM_HIDP_INTR;
sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
proto_l2cap = sdp_list_append(0, &l2cap_uuid);
psm = sdp_data_alloc(SDP_UINT16, &intr);
proto_l2cap = sdp_list_append(proto_l2cap, psm);
sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
proto_hidp = sdp_list_append(0, &hidp_uuid);
apseq = sdp_list_append(0, proto_l2cap);
apseq = sdp_list_append(apseq, proto_hidp);
aproto = sdp_list_append(0, apseq);
sdp_set_add_access_protos(record, aproto);
}
//ATTR 0x0100
static void Inno_sdp_set_ServiceName(sdp_record_t *record, const char *name) {
sdp_attr_add_new(record, SDP_ATTR_SVCNAME_PRIMARY, SDP_TEXT_STR8, name);
}
//ATTR 0x0101
static void Inno_sdp_set_ServiceDescription(sdp_record_t *record, const char *desc) {
sdp_attr_add_new(record, SDP_ATTR_SVCDESC_PRIMARY, SDP_TEXT_STR8, desc);
}
//ATTR 0x0102
static void Inno_sdp_set_ProviderName(sdp_record_t *record, const char *prov) {
sdp_attr_add_new(record, SDP_ATTR_PROVNAME_PRIMARY, SDP_TEXT_STR8, prov);
}
//ATTR 0x0200
static void Inno_sdp_set_HID_DeviceReleaseNumber(sdp_record_t *record, unsigned int val) {
sdp_attr_add_new(record, SDP_ATTR_HID_DEVICE_RELEASE_NUMBER, SDP_UINT16, &val);
}
//ATTR 0x0201
static void Inno_sdp_set_HID_ParserVersion(sdp_record_t *record, unsigned int val) {
sdp_attr_add_new(record, SDP_ATTR_HID_PARSER_VERSION, SDP_UINT16, &val);
}
//ATTR 0x0202
static void Inno_sdp_set_HID_DeviceSubClass(sdp_record_t *record, unsigned int val) {
sdp_attr_add_new(record, SDP_ATTR_HID_DEVICE_SUBCLASS, SDP_UINT8, &val);
}
//ATTR 0x0203
static void Inno_sdp_set_HID_CountryCode(sdp_record_t *record, unsigned int val) {
sdp_attr_add_new(record, SDP_ATTR_HID_COUNTRY_CODE, SDP_UINT8, &val);
}
//ATTR 0x0204
static void Inno_sdp_set_HID_VirtualCable(sdp_record_t *record, unsigned int val) {
sdp_attr_add_new(record, SDP_ATTR_HID_VIRTUAL_CABLE, SDP_BOOL, &val);
}
//ATTR 0x0205
static void Inno_sdp_set_HID_ReconnectInitiate(sdp_record_t *record, unsigned int val) {
sdp_attr_add_new(record, SDP_ATTR_HID_RECONNECT_INITIATE, SDP_BOOL, &val);
}
//ATTR 0x0206
static void Inno_sdp_set_HID_DescriptorList(sdp_record_t *record, void *data, int len) {
void *dtds[2];
void *values[2];
unsigned char dtd2=SDP_UINT8;
unsigned char hid_spec_type=0x22;
unsigned char dtd_data=SDP_TEXT_STR8;
int leng[2];
sdp_data_t *hid_spec_lst;
sdp_data_t *hid_spec_lst2;
dtds[0] = &dtd2;
values[0] = &hid_spec_type;
dtds[1] = &dtd_data;
values[1] = data;
leng[0] = 0;
leng[1] = len;
hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
sdp_attr_add(record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
}
/*
hid_attr_langs - array of uint16.
size - how many elements in the array.
*/
//ATTR 0x0207
static void Inno_sdp_set_HID_LangIdBaseList(sdp_record_t *record, unsigned short *hid_attr_langs, int size)
{
void *dtds2[2];
unsigned char dtd = SDP_UINT16;
void *values2[2];
sdp_data_t *lang_lst;
sdp_data_t *lang_lst2;
int i;
for (i = 0; i < size; i++) {
dtds2[i] = &dtd;
values2[i] = &hid_attr_langs[i];
}
lang_lst = sdp_seq_alloc(dtds2, values2, size);
lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
sdp_attr_add(record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
}
//ATTR 0x0208
static void Inno_sdp_set_HID_SdpDisable(sdp_record_t *record, unsigned int val) {
sdp_attr_add_new(record, SDP_ATTR_HID_SDP_DISABLE, SDP_BOOL, &val);
}
//ATTR 0x0209
static void Inno_sdp_set_HID_BatteryPower(sdp_record_t *record, unsigned int val) {
sdp_attr_add_new(record, SDP_ATTR_HID_BATTERY_POWER, SDP_BOOL, &val);
}
//ATTR 0x020a
static void Inno_sdp_set_HID_RemoteWakeUp(sdp_record_t *record, unsigned int val) {
sdp_attr_add_new(record, SDP_ATTR_HID_REMOTE_WAKEUP, SDP_BOOL, &val);
}
//ATTR 0x020b
static void Inno_sdp_set_HID_ProfileVersion(sdp_record_t *record, unsigned int val) {
sdp_attr_add_new(record, SDP_ATTR_HID_PROFILE_VERSION, SDP_UINT16, &val);
}
//ATTR 0x020c
static void Inno_sdp_set_HID_SuperVersionTimeout(sdp_record_t *record, unsigned int val) {
sdp_attr_add_new(record, SDP_ATTR_HID_SUPERVISION_TIMEOUT, SDP_UINT16, &val);
}
//ATTR 0x020d
static void Inno_sdp_set_HID_NormallyConnectable(sdp_record_t *record, unsigned int val) {
sdp_attr_add_new(record, SDP_ATTR_HID_NORMALLY_CONNECTABLE, SDP_BOOL, &val);
}
//ATTR 0x020e
static void Inno_sdp_set_HID_BootDevice(sdp_record_t *record, unsigned int val) {
sdp_attr_add_new(record, SDP_ATTR_HID_BOOT_DEVICE, SDP_BOOL, &val);
}
// With 0xffffffff, we get assigned the first free record >= 0x10000
// Make HID service visible (add to PUBLIC BROWSE GROUP)
sdp_record_t *SdpCreateRecord(unsigned int handle) {
sdp_record_t *record = calloc(1, sizeof(sdp_record_t));
record->handle = handle;
return record;
}
void SdpDestroyRecord(sdp_record_t *record) {
if (record) free(record);
}
sdp_record_t* SdpMakeUpHidRecord(sdp_record_t *record, struct hidc_info_t *hidc_info)
{
unsigned short hid_attr_lang[] = {0x0409, 0x0100};
Inno_sdp_set_ServiceClassIDList(record);
Inno_sdp_set_ProtocolDescriptorList(record);
Inno_sdp_set_BrowseGroupList(record);
Inno_sdp_set_LanguageBaseAttributeIDList(record);
Inno_sdp_set_BluetoothProfileDescriptorList(record);
Inno_sdp_set_AdditionalProtocolDescriptorLists(record);
Inno_sdp_set_HID_DeviceReleaseNumber(record, 0x0100);
Inno_sdp_set_HID_ParserVersion(record, 0x0111);
Inno_sdp_set_HID_CountryCode(record, 0x21);
Inno_sdp_set_HID_VirtualCable(record, 1);
Inno_sdp_set_HID_ReconnectInitiate(record, 1);
Inno_sdp_set_HID_LangIdBaseList(record, hid_attr_lang,sizeof(hid_attr_lang)/sizeof(hid_attr_lang[0]));
Inno_sdp_set_HID_SdpDisable(record, 0);
Inno_sdp_set_HID_BatteryPower(record, 1);
Inno_sdp_set_HID_RemoteWakeUp(record, 1);
Inno_sdp_set_HID_ProfileVersion(record, 0x0100);
Inno_sdp_set_HID_SuperVersionTimeout(record, 0x0c80);
Inno_sdp_set_HID_NormallyConnectable(record, 0);
Inno_sdp_set_HID_BootDevice(record, 1);
if (hidc_info->service_name)
Inno_sdp_set_ServiceName(record, hidc_info->service_name);
if (hidc_info->description)
Inno_sdp_set_ServiceDescription(record, hidc_info->description);
if (hidc_info->provider)
Inno_sdp_set_ProviderName(record, hidc_info->provider);
Inno_sdp_set_HID_DeviceSubClass(record, hidc_info->sub_class);
Inno_sdp_set_HID_DescriptorList(record, hidc_info->desc_data, hidc_info->desc_len);
return record;
}
int SdpRegisterRecord(sdp_record_t *record) {
sdp_session_t *session;
// Connect to SDP server on localhost, to publish service information
session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
if (!session) {
fprintf(stderr, "Failed to connect to SDP server: %s\n", strerror(errno));
return 1;
}
// Submit our IDEA of a SDP record to the "sdpd"
if (sdp_record_register(session, record, SDP_RECORD_PERSIST) < 0) {
fprintf (stderr, "Service Record registration failed\n");
return -1;
}
fprintf (stdout, "HID keyboard service registered. handle=0x%x\n", record->handle);
sdphandle_hid = record->handle;
sdp_close(session);
return 0;
}
void SdpUnregisterRecord(unsigned int handle) {
unsigned int range=0x0000ffff;
sdp_list_t * attr;
sdp_session_t * session;
sdp_record_t * record;
// Connect to the local SDP server
session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
if (!session) return;
attr = sdp_list_append(0, &range);
record = sdp_service_attr_req(session, handle, SDP_ATTR_REQ_RANGE, attr);
sdp_list_free(attr, 0);
if (!record) {
sdp_close(session);
return;
}
sdp_device_record_unregister(session, BDADDR_ANY, record);
sdp_close(session);
return;
}
int DoSdpRegistration(void)
{
sdp_record_t* record;
record = (sdp_record_t *)SdpCreateRecord(0xffffffff);
SdpMakeUpHidRecord(record, &s_hidc_info);
SdpRegisterRecord(record);
SdpDestroyRecord(record);
return 0;
}
3.
//////////////////////// client hid response and report ////////////////////////
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <linux/input.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
#include <hidp.h>
#include <android/log.h>
#define L2CAP_PSM_HIDP_CTRL 0x11
#define L2CAP_PSM_HIDP_INTR 0x13
// These numbers must also be used in the HID descriptor binary file
#define REPORTID_BARCODE 1
#define REPORTID_KEYBD 2
//#define REPORTID_MOUSE 3
#define HID_VIRTUAL_CABLE_UNPLUG 0x15
#define HID_MSG_RESERVED 0x20
#define HID_MSG_GET_REPORT 0x41
#define HID_MSG_GET_REPORT_INVALID 0x42
#define HID_MSG_SET_REPORT 0x52
#define HID_MSG_GET_PROTOCOL 0x60
#define HID_MSG_SET_PROTOCOL_BOOT 0x70
#define HID_MSG_SET_PROTOCOL_REPORT 0x71
#define HID_MSG_GET_IDLE 0x80
#define HID_MSG_SET_IDLE 0x90
//***************** Global variables
static volatile int s_innohid_loop;
volatile int g_hid_ctrl_sock; // For the one-session-only
volatile int g_hid_intr_sock;
volatile int g_hid_connection = 0;
static volatile int s_hidsend = 0;
static volatile int s_hid_conn_flag = 0;
//***************** Data structures
typedef struct _hidrep_barcode_t
{
unsigned char act_type; // Fixed value for "Data Frame": 0xA1
unsigned char rep_id; // Will be set to REPORTID_KEYBD for "keyboard"
unsigned char symbology1; // Modifier keys (shift, alt, the like)
unsigned char symbology2; // Modifier keys (shift, alt, the like)
unsigned char symbology3; // Modifier keys (shift, alt, the like)
unsigned char data[32]; //0x20
unsigned char reserved; // useless for now
}hidrep_barcode_t;
//http://www.instructables.com/id/USB-Wii-Classic-Controller/step13/Bonus-Keyboard-and-Mouse
typedef struct _hidrep_keyb_t
{
unsigned char act_type; // Fixed value for "Data Frame": 0xA1
unsigned char rep_id; // Will be set to REPORTID_KEYBD for "keyboard"
unsigned char modify; // Modifier keys (shift, alt, the like)
unsigned char reserved; // useless for now
unsigned char key[6]; // Currently pressed keys, max 6 at once
}hidrep_keyb_t;
/*typedef struct _hidrep_mouse_t
{
unsigned char act_type; // Fixed value for "Data Frame": 0xA1
unsigned char rep_id; // Will be set to REPORTID_MOUSE for "mouse"
unsigned char button; // bits 0..2 for left,right,middle, others 0
char x; // mouse x movement
char y; // mouse y movement
char v_wheel; // mouse wheel movement
char h_wheel; // mouse wheel movement
}hidrep_mouse_t;*/
typedef struct _hidrep_protocol_t
{
unsigned char act_type; // Fixed value for "Data Frame": 0xA1
unsigned char reserved_bits; // useless for now
}hidrep_protocol_t;
void* Thread_KeyEvent(void* pparam)
{
int rlen;
hidrep_keyb_t evkeyb;
char ev_buf[256];
int fd_local;
fd_local = *(int*)pparam;
while( s_innohid_loop )
{
memset(ev_buf,0,sizeof(ev_buf));
rlen = read(fd_local, (void*)ev_buf, sizeof(ev_buf));
if( rlen > 0 )
{
memset(&evkeyb, 0, sizeof(struct _hidrep_keyb_t));
evkeyb.act_type = 0xa1; // always this constant value.
evkeyb.rep_id = REPORTID_KEYBD;
if( ev_buf[28] )
{
switch(ev_buf[12])
{
case 0x10: //1 0x10 + 0x0e
evkeyb.key[1] = 0x1e;
break;
case 0x11: //2
evkeyb.key[1] = 0x1f;
break;
case 0x12:
evkeyb.key[1] = 0x20;
break;
case 0x18:
evkeyb.key[1] = 0x21;
break;
case 0x19:
evkeyb.key[1] = 0x22;
break;
case 0x1a:
evkeyb.key[1] = 0x23;
break;
case 0x20:
evkeyb.key[1] = 0x24;
break;
case 0x21:
evkeyb.key[1] = 0x25;
break;
case 0x22:
evkeyb.key[1] = 0x26;
break;
case 0x29:
evkeyb.key[1] = 0x27;
break;
default:
evkeyb.key[1] = ev_buf[12];
break;
}
}
if( g_hid_intr_sock )
send(g_hid_intr_sock, &evkeyb, sizeof(struct _hidrep_keyb_t), 0);
}
}
return NULL;
}
void* innohid_thread_handler(void* pparam)
{
int j;
int rlen;
int sock_ctrl; // For the listening sockets
int sock_intr;
int fd_keyevent;
char bt_buf[16];
char act_type;
char report_id;
char evbuf[sizeof(struct input_event)];
fd_set fds; // fds for listening sockets
struct timeval tv; // Used for "select"
bluez_reply_t reply;
bluez_reply_callback_t result;
struct sockaddr_l2 l2a;
bluez_send_data_t buffer = {0};
socklen_t alen = sizeof(l2a);
pthread_attr_t pattr;
pthread_t pthread_id;
hidrep_barcode_t evbarcode;
hidrep_keyb_t evkeyb;
//hidrep_mouse_t evmouse;
hidrep_protocol_t evprotocol;
struct input_event* inevent;
g_hid_ctrl_sock = 0;
g_hid_intr_sock = 0;
s_innohid_loop = 0;
fd_keyevent = -1;
pthread_attr_init(&pattr);
pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);
while (1)
{
sock_ctrl = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
sock_intr = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if( sock_ctrl < 0 || sock_intr < 0 )
{
DBG("Failed to generate bluetooth sockets");
return 2;
}
if( btbind(sock_ctrl, L2CAP_PSM_HIDP_CTRL) || btbind(sock_intr, L2CAP_PSM_HIDP_INTR) )
{
DBG("Failed to bind sockets (%d/%d) "
"to PSM (%d/%d)", sock_ctrl, sock_intr, L2CAP_PSM_HIDP_CTRL, L2CAP_PSM_HIDP_INTR);
return 3;
}
if( listen(sock_ctrl, 1) || listen(sock_intr, 1) )
{
DBG("Failed to listen on int/ctl BT socket");
close(sock_intr);
close(sock_ctrl);
return 4;
}
DBG("The HID-Client is now ready to accept connections from another machine");
while(1)
{
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(sock_ctrl, &fds);
switch(select(sock_ctrl + 1, &fds, NULL, NULL, &tv))
{
case -1:
if(errno == EINTR)
{
// Ctrl+C ? - handle that elsewhere
DBG("Ctrl+C ");
continue;
}
DBG("select() error on BT socket: %s! "
"Aborting.", strerror(errno));
return 11;
case 0:
continue;
default:
if(FD_ISSET(sock_ctrl, &fds))
{
hid_ctrl_sock = accept(sock_ctrl, (struct sockaddr *)&l2a, &alen);
DBG("hid_ctrl_sock:%d",hid_ctrl_sock);
if(hid_ctrl_sock < 0)
{
if(errno == EAGAIN)
{
continue;
}
DBG("Failed to get a control connection:"
" %s", strerror(errno));
continue;
}
}
}
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(sock_intr, &fds);
switch(select(sock_intr + 1, &fds, NULL, NULL, &tv))
{
case -1:
if(errno == EINTR)
{
// Ctrl+C ? - handle that elsewhere
DBG("Ctrl+C ");
continue;
}
DBG("select() error on BT socket: %s! "
"Aborting.", strerror(errno));
return 12;
case 0:
DBG("Interrupt connection failed to "
"establish (control connection already"
" there), timeout!");
close(hid_ctrl_sock);
continue;
default:
if(FD_ISSET(sock_intr, &fds))
{
//DBG( "accept() hid_ctrl_sock %d ", hid_ctrl_sock);
hid_intr_sock = accept(sock_intr, (struct sockaddr *)&l2a, &alen);
DBG("hid_intr_sock:%d",hid_intr_sock);
if(hid_intr_sock < 0)
{
close(hid_intr_sock);
close(hid_ctrl_sock);
if(errno == EAGAIN)
{
continue;
}
DBG("Failed to get an interrupt "
"connection: %s", strerror(errno));
continue;
}
}
}
s_innohid_loop = 1;
fd_keyevent = open("/dev/input/event0", O_RDWR);
pthread_create(&pthread_id, &pattr, Thread_KeyEvent, &fd_keyevent);
memset(bt_buf,0,sizeof(bt_buf));
rlen = recv(g_hid_ctrl_sock, bt_buf, sizeof(bt_buf), 0);
if( rlen <= 0 )
bt_buf[0] = HID_VIRTUAL_CABLE_UNPLUG;
while( s_innohid_loop )
{
act_type = bt_buf[0];
switch(act_type)
{
case HID_VIRTUAL_CABLE_UNPLUG:
s_innohid_loop = 0;
if( fd_keyevent != -1 )
{
shutdown(fd_keyevent, SHUT_RDWR);
usleep(100000);
close(fd_keyevent);
usleep(100000);
fd_keyevent = -1;
}
if( g_hid_intr_sock )
{
close(g_hid_intr_sock);
g_hid_intr_sock = 0;
}
if( g_hid_ctrl_sock )
{
usleep(200000);
close(g_hid_ctrl_sock);
g_hid_ctrl_sock = 0;
}
break;
case HID_MSG_RESERVED:
report_id = 0x03; //UNSUPPORTED ID
send(g_hid_ctrl_sock, &report_id, sizeof(char), 0);
break;
//GET_REPORT
case HID_MSG_GET_REPORT:
report_id = bt_buf[1];
switch(report_id)
{
case 0x01:
memset(&evbarcode, 0, sizeof(struct _hidrep_barcode_t));
evbarcode.act_type = 0xa1; // always this constant value.
evbarcode.rep_id = REPORTID_BARCODE;
send(g_hid_ctrl_sock, &evbarcode, sizeof(struct _hidrep_barcode_t), 0);
break;
case 0x02:
memset(&evbarcode, 0, sizeof(struct _hidrep_keyb_t));
evkeyb.act_type = 0xa1; // always this constant value.
evkeyb.rep_id = REPORTID_KEYBD;
send(g_hid_ctrl_sock, &evkeyb, sizeof(struct _hidrep_keyb_t), 0);
break;
/*case 0x03:
memset(&evmouse, 0, sizeof(struct _hidrep_mouse_t));
evmouse.act_type = 0xa1; // always this constant value.
evmouse.rep_id = REPORTID_MOUSE;
send(g_hid_ctrl_sock, &evmouse, sizeof(struct _hidrep_mouse_t), 0);
break;*/
}
break;
case HID_MSG_GET_REPORT_INVALID:
report_id = bt_buf[1];
switch(report_id)
{
case 0xff:
default:
report_id = 0x02; //INVALID ID
send(g_hid_ctrl_sock, &report_id, sizeof(char), 0);
break;
}
break;
case HID_MSG_SET_REPORT:
report_id = 0;
send(g_hid_ctrl_sock, &report_id, sizeof(char), 0);
break;
case HID_MSG_GET_PROTOCOL:
evprotocol.act_type = 0xa0;
evprotocol.reserved_bits = 0x00;
send(g_hid_ctrl_sock, &evprotocol, sizeof(struct _hidrep_protocol_t), 0);
break;
case HID_MSG_SET_PROTOCOL_BOOT:
report_id = 0;
send(g_hid_ctrl_sock, &report_id, sizeof(char), 0);
//usleep(3000000);
/*memset(&evkeyb, 0, sizeof(struct _hidrep_keyb_t));
evkeyb.act_type = 0xa1; // always this constant value.
evkeyb.rep_id = REPORTID_KEYBD;
send(g_hid_intr_sock, &evkeyb, sizeof(struct _hidrep_keyb_t), 0);*/
/*memset(&evbarcode, 0, sizeof(struct _hidrep_barcode_t));
evbarcode.act_type = 0xa1; // always this constant value.
evbarcode.rep_id = REPORTID_BARCODE;
send(g_hid_intr_sock, &evbarcode, sizeof(struct _hidrep_barcode_t), 0);*/
break;
case HID_MSG_SET_PROTOCOL_REPORT:
report_id = 0;
send(g_hid_ctrl_sock, &report_id, sizeof(char), 0);
rlen = recv(g_hid_ctrl_sock, bt_buf, sizeof(bt_buf), 0);
evprotocol.act_type = 0xa0;
evprotocol.reserved_bits = 0x01;
send(g_hid_ctrl_sock, &evprotocol, sizeof(struct _hidrep_protocol_t), 0);
break;
case HID_MSG_GET_IDLE:
evprotocol.act_type = 0xa0;
evprotocol.reserved_bits = 0x00;
send(g_hid_ctrl_sock, &evprotocol, sizeof(struct _hidrep_protocol_t), 0);
break;
case HID_MSG_SET_IDLE:
report_id = 0;
send(g_hid_ctrl_sock, &report_id, sizeof(char), 0);
break;
}
//recv remote unplug msg
if( s_innohid_loop )
{
if( g_hid_ctrl_sock )
rlen = recv(g_hid_ctrl_sock, bt_buf, sizeof(bt_buf), 0);
}
} //while( s_innohid_loop )
DBG("HID Connection closed");
}
close(sock_intr);
close(sock_ctrl);
DBG("Stopped hidclient.");
}//end while
pthread_attr_destroy(&pattr);
return NULL;
}
4.
//////////////////////// start thread ////////////////////////
int main(int argc, char ** argv)
{
int err;
pthread_attr_t pattr;
DoSdpRegistration();
pthread_attr_init(&pattr);
pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);
err = pthread_create(&pInnoHidThread, &pattr, innohid_thread_handler, NULL);
pthread_attr_destroy(&pattr);
while(1)
{
usleep(10000); //10ms
}
}
沒有留言:
張貼留言