Merge branch 'merge/default-handler' of scuti/hanvon-linux into libusb-port
This commit is contained in:
commit
bcde62a8ae
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,3 +1,8 @@
|
|||||||
|
#
|
||||||
|
# Project Executable
|
||||||
|
#
|
||||||
|
hvlusb
|
||||||
|
|
||||||
#
|
#
|
||||||
# NOTE! Don't add files that are generated in specific
|
# NOTE! Don't add files that are generated in specific
|
||||||
# subdirectories here. Add them in the ".gitignore" file
|
# subdirectories here. Add them in the ".gitignore" file
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
# Hanvon Tablet Drivers
|
# Hanvon Tablet Drivers
|
||||||
|
|
||||||
Userspace driver for Hanvon pen tablets adapted from the original Linux kernel driver. Supports tablet features such as pen coordinates, x and y tilts, proximity and pressure detection.
|
Userspace driver for Hanvon pen tablets adapted from the original Linux kernel driver. Supports tablet features such as pen coordinates, x and y tilt angle, hover detection, pressure detection, and button input.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
make
|
make
|
||||||
@ -13,11 +13,11 @@ Run the output executable from a terminal with sudo (preferrably in the backgrou
|
|||||||
|
|
||||||
## Supported Hardware
|
## Supported Hardware
|
||||||
|
|
||||||
Currently, only GP0504 is tested and supported.
|
All tablets supported by the original driver should work with this libusb driver but only the GP0504 has been tested.
|
||||||
|
|
||||||
The original series of supported hardware:
|
The original driver supported the following models:
|
||||||
|
|
||||||
Artmaster I: AM3M, AM0605, AM0806, AM1107, AM1209
|
ArtMaster: AM3M, AM0605, AM0806, AM1107, AM1209
|
||||||
|
|
||||||
Rollick: RL0604, RL0504
|
Rollick: RL0604, RL0504
|
||||||
|
|
||||||
|
230
hanvon-libusb.c
230
hanvon-libusb.c
@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
#include <libevdev/libevdev.h>
|
#include <libevdev/libevdev.h>
|
||||||
#include <libevdev/libevdev-uinput.h>
|
#include <libevdev/libevdev-uinput.h>
|
||||||
// #include <asm/unaligned.h>
|
|
||||||
|
|
||||||
#define STATE_SUCCESS 0
|
#define STATE_SUCCESS 0
|
||||||
#define STATE_NOT_FOUND 1
|
#define STATE_NOT_FOUND 1
|
||||||
@ -47,16 +46,26 @@
|
|||||||
#define PRODUCT_ID_APPIV0906 0x8532
|
#define PRODUCT_ID_APPIV0906 0x8532
|
||||||
|
|
||||||
#define AM_PACKET_LEN 10
|
#define AM_PACKET_LEN 10
|
||||||
|
#define AM_RESOLUTION 40
|
||||||
//static int lbuttons[]={BTN_0,BTN_1,BTN_2,BTN_3}; /* reported on all AMs */
|
|
||||||
//static int rbuttons[]={BTN_4,BTN_5,BTN_6,BTN_7}; /* reported on AM1107+ */
|
|
||||||
|
|
||||||
#define AM_WHEEL_THRESHOLD 4
|
#define AM_WHEEL_THRESHOLD 4
|
||||||
|
|
||||||
#define AM_MAX_TILT_X 0x3f
|
#define AM_MAX_ABS_X 0x27DE
|
||||||
#define AM_MAX_TILT_Y 0x7f
|
#define AM_MAX_ABS_Y 0x1CFE
|
||||||
|
#define AM_MAX_TILT_X 0x3F
|
||||||
|
#define AM_MAX_TILT_Y 0x7F
|
||||||
#define AM_MAX_PRESSURE 0x400
|
#define AM_MAX_PRESSURE 0x400
|
||||||
|
|
||||||
|
#define APPIV_MAX_ABS_X 0x5750
|
||||||
|
#define APPIV_MAX_ABS_Y 0x5750
|
||||||
|
|
||||||
|
#define BUTTON_EVENT_GP 0x01
|
||||||
|
#define PEN_EVENT 0x02
|
||||||
|
#define BUTTON_EVENT_0906 0x0C
|
||||||
|
|
||||||
|
|
||||||
|
static int lbuttons[]={BTN_0,BTN_1,BTN_2,BTN_3}; /* reported on all AMs */
|
||||||
|
static int rbuttons[]={BTN_4,BTN_5,BTN_6,BTN_7}; /* reported on AM1107+ */
|
||||||
|
|
||||||
struct hanvon_message {
|
struct hanvon_message {
|
||||||
unsigned char msgtype;
|
unsigned char msgtype;
|
||||||
unsigned char is_move;
|
unsigned char is_move;
|
||||||
@ -67,6 +76,9 @@ struct hanvon_message {
|
|||||||
unsigned char y_tilt;
|
unsigned char y_tilt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// GLOBAL
|
||||||
|
int wheel_position;
|
||||||
|
|
||||||
int find_device(libusb_device **list, unsigned int count) {
|
int find_device(libusb_device **list, unsigned int count) {
|
||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -113,16 +125,54 @@ void callback(struct libusb_transfer *transfer) {
|
|||||||
display_packets(data);
|
display_packets(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_gp0504 (struct libusb_transfer *tx) { // for callback
|
static inline void report_buttons( struct libevdev_uinput *ud,
|
||||||
|
int buttons[],
|
||||||
|
unsigned char data)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
if((data & 0xf0) == 0xa0) {
|
||||||
|
// TODO test that these are the correct buttons and all buttons are covered
|
||||||
|
err = libevdev_uinput_write_event(ud, EV_KEY, buttons[1], (data & 0x02));
|
||||||
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
|
err = libevdev_uinput_write_event(ud, EV_KEY, buttons[2], (data & 0x04));
|
||||||
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
|
err = libevdev_uinput_write_event(ud, EV_KEY, buttons[3], (data & 0x08));
|
||||||
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
|
} else if(data <= 0x3f) { /* slider area active */
|
||||||
|
int delta = data - wheel_position;
|
||||||
|
if(abs(delta) < AM_WHEEL_THRESHOLD) {
|
||||||
|
err = libevdev_uinput_write_event(ud, EV_REL, REL_WHEEL, delta); // TODO test delta as input
|
||||||
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
|
wheel_position = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE:
|
||||||
|
// Judging by the original driver, this should work for all but may not work
|
||||||
|
// for the APPIV0906. Possibly needs little endian for APPIV0906 x and y data
|
||||||
|
// but we don't have any means of testing this without that tablet.
|
||||||
|
// NOTE:
|
||||||
|
// Left and right mouse click should work for all but additional buttons are
|
||||||
|
// not supported by the default handler.
|
||||||
|
void callback_default (struct libusb_transfer *tx) { // for callback
|
||||||
unsigned char *data = tx -> buffer;
|
unsigned char *data = tx -> buffer;
|
||||||
struct hanvon_message *msg = (struct hanvon_message *)tx -> buffer;
|
struct hanvon_message *msg = (struct hanvon_message *)tx -> buffer;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct libevdev_uinput *ud = tx -> user_data;
|
struct libevdev_uinput *ud = tx -> user_data;
|
||||||
switch(msg->msgtype) {
|
switch(msg->msgtype) {
|
||||||
case 0x01:
|
case BUTTON_EVENT_GP:
|
||||||
display_packets(data);
|
if(data[1] == 0x55) { // left side buttons
|
||||||
|
report_buttons(ud, lbuttons, msg->x_movement); // button pressed data in same place as position data
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data[3] == 0xAA) { // right side buttons (am1107, am1209
|
||||||
|
report_buttons(ud, rbuttons, msg->y_movement); // button pressed data in same place as position data
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case PEN_EVENT:
|
||||||
/* is_move values:
|
/* is_move values:
|
||||||
0x80: near, 0x02: button press
|
0x80: near, 0x02: button press
|
||||||
0x10: floating, 0x01: touching */
|
0x10: floating, 0x01: touching */
|
||||||
@ -146,7 +196,7 @@ void callback_gp0504 (struct libusb_transfer *tx) { // for callback
|
|||||||
if(err) { DEBUG("err: %d\n",err); }
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
}
|
}
|
||||||
err = libevdev_uinput_write_event(
|
err = libevdev_uinput_write_event(
|
||||||
ud, EV_ABS, ABS_PRESSURE, msg->pressure
|
ud, EV_ABS, ABS_PRESSURE, msg->pressure * 8 // reference original driver
|
||||||
);
|
);
|
||||||
if(err) { DEBUG("err: %d\n",err); }
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
err = libevdev_uinput_write_event(
|
err = libevdev_uinput_write_event(
|
||||||
@ -168,13 +218,48 @@ void callback_gp0504 (struct libusb_transfer *tx) { // for callback
|
|||||||
// data[1]:
|
// data[1]:
|
||||||
// 0x10 = lift, 0x90 = close, 0x91 = press
|
// 0x10 = lift, 0x90 = close, 0x91 = press
|
||||||
// 0x12 = btn (lift), 0x92 = btn (close), 0x93 = btn (press)
|
// 0x12 = btn (lift), 0x92 = btn (close), 0x93 = btn (press)
|
||||||
display_packets(data);
|
|
||||||
break;
|
break;
|
||||||
|
case BUTTON_EVENT_0906:
|
||||||
|
// TODO confirm this is the byte that contains button flags
|
||||||
|
err = libevdev_uinput_write_event(
|
||||||
|
ud, EV_KEY, BTN_0, (msg->is_move & 0x0100) / 2
|
||||||
|
);
|
||||||
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
|
err = libevdev_uinput_write_event(
|
||||||
|
ud, EV_KEY, BTN_1, (msg->is_move & 0x0200) / 2
|
||||||
|
);
|
||||||
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
|
err = libevdev_uinput_write_event(
|
||||||
|
ud, EV_KEY, BTN_2, (msg->is_move & 0x0400) / 2
|
||||||
|
);
|
||||||
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
|
err = libevdev_uinput_write_event(
|
||||||
|
ud, EV_KEY, BTN_3, (msg->is_move & 0x0800) / 2
|
||||||
|
);
|
||||||
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
|
err = libevdev_uinput_write_event(
|
||||||
|
ud, EV_KEY, BTN_4, (msg->is_move & 0x1000) / 2
|
||||||
|
);
|
||||||
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
|
err = libevdev_uinput_write_event(
|
||||||
|
ud, EV_KEY, BTN_5, (msg->is_move & 0x2000) / 2
|
||||||
|
);
|
||||||
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
|
err = libevdev_uinput_write_event(
|
||||||
|
ud, EV_KEY, BTN_6, (msg->is_move & 0x4000) / 2
|
||||||
|
);
|
||||||
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
|
err = libevdev_uinput_write_event(
|
||||||
|
ud, EV_KEY, BTN_7, (msg->is_move & 0x8000) / 2
|
||||||
|
);
|
||||||
|
if(err) { DEBUG("err: %d\n",err); }
|
||||||
default:
|
default:
|
||||||
display_packets(data);
|
// do nothing
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// always display packets
|
||||||
|
display_packets(data);
|
||||||
|
|
||||||
err += libevdev_uinput_write_event(ud, EV_SYN, SYN_REPORT, 0);
|
err += libevdev_uinput_write_event(ud, EV_SYN, SYN_REPORT, 0);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
printf("error : gp0504, %i\n", err);
|
printf("error : gp0504, %i\n", err);
|
||||||
@ -188,6 +273,7 @@ int init_ctrl(struct libusb_device * const d,
|
|||||||
struct libevdev_uinput **uidev) {
|
struct libevdev_uinput **uidev) {
|
||||||
struct input_absinfo *abs;
|
struct input_absinfo *abs;
|
||||||
printf("init_ctrl: %x\n", uidev);
|
printf("init_ctrl: %x\n", uidev);
|
||||||
|
wheel_position = AM_WHEEL_THRESHOLD - 1; // init global
|
||||||
if (d == NULL) {
|
if (d == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -195,10 +281,11 @@ int init_ctrl(struct libusb_device * const d,
|
|||||||
struct libusb_device_descriptor desc;
|
struct libusb_device_descriptor desc;
|
||||||
libusb_get_device_descriptor(d, &desc);
|
libusb_get_device_descriptor(d, &desc);
|
||||||
(*evdev) = libevdev_new();
|
(*evdev) = libevdev_new();
|
||||||
|
|
||||||
|
// set up inputs all devices have
|
||||||
libevdev_enable_property((*evdev), INPUT_PROP_DIRECT);
|
libevdev_enable_property((*evdev), INPUT_PROP_DIRECT);
|
||||||
libevdev_enable_event_type((*evdev), EV_SYN);
|
libevdev_enable_event_type((*evdev), EV_SYN);
|
||||||
libevdev_enable_event_code((*evdev), EV_SYN, SYN_REPORT, NULL);
|
libevdev_enable_event_code((*evdev), EV_SYN, SYN_REPORT, NULL);
|
||||||
// every tablet has these features
|
|
||||||
libevdev_enable_event_type((*evdev), EV_KEY); // enable pen button
|
libevdev_enable_event_type((*evdev), EV_KEY); // enable pen button
|
||||||
libevdev_enable_event_code((*evdev), EV_KEY, BTN_TOOL_PEN, NULL);
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_TOOL_PEN, NULL);
|
||||||
libevdev_enable_event_code((*evdev), EV_KEY, BTN_LEFT, NULL); // pen tap
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_LEFT, NULL); // pen tap
|
||||||
@ -209,10 +296,17 @@ int init_ctrl(struct libusb_device * const d,
|
|||||||
// set up absolute x coordinate input
|
// set up absolute x coordinate input
|
||||||
abs->value = 0x1000;
|
abs->value = 0x1000;
|
||||||
abs->minimum = 0;
|
abs->minimum = 0;
|
||||||
abs->maximum = 0x27DE;
|
switch(desc.idProduct) {
|
||||||
|
case PRODUCT_ID_APPIV0906:
|
||||||
|
abs->maximum = APPIV_MAX_ABS_X;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abs->maximum = AM_MAX_ABS_X;
|
||||||
|
break;
|
||||||
|
}
|
||||||
abs->fuzz = 0;
|
abs->fuzz = 0;
|
||||||
abs->flat = 0;
|
abs->flat = 0;
|
||||||
abs->resolution = 40;
|
abs->resolution = AM_RESOLUTION;
|
||||||
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_X, abs)<0) {
|
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_X, abs)<0) {
|
||||||
DEBUG("%s","failed to register absolute x\n");
|
DEBUG("%s","failed to register absolute x\n");
|
||||||
is_ok = -1;
|
is_ok = -1;
|
||||||
@ -220,8 +314,15 @@ int init_ctrl(struct libusb_device * const d,
|
|||||||
// set up absolute y coordinate input
|
// set up absolute y coordinate input
|
||||||
abs->value = 0x1000;
|
abs->value = 0x1000;
|
||||||
abs->minimum = 0;
|
abs->minimum = 0;
|
||||||
abs->maximum = 0x1cfe;
|
switch(desc.idProduct) {
|
||||||
abs->resolution = 40;
|
case PRODUCT_ID_APPIV0906:
|
||||||
|
abs->maximum = APPIV_MAX_ABS_Y;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abs->maximum = AM_MAX_ABS_Y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
abs->resolution = AM_RESOLUTION;
|
||||||
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_Y, abs)<0) {
|
if(libevdev_enable_event_code((*evdev), EV_ABS, ABS_Y, abs)<0) {
|
||||||
DEBUG("%s","failed to register absolute y\n");
|
DEBUG("%s","failed to register absolute y\n");
|
||||||
is_ok = -1;
|
is_ok = -1;
|
||||||
@ -253,15 +354,91 @@ int init_ctrl(struct libusb_device * const d,
|
|||||||
DEBUG("%s","failed to register y tilt\n");
|
DEBUG("%s","failed to register y tilt\n");
|
||||||
is_ok = -1;
|
is_ok = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scroll wheel is NOT universal
|
||||||
|
if(libevdev_enable_event_code((*evdev), EV_REL, REL_WHEEL, NULL)<0) {
|
||||||
|
DEBUG("%s","failed to register scroll wheel\n");
|
||||||
|
is_ok = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up device-specific inputs
|
||||||
switch(desc.idProduct) {
|
switch(desc.idProduct) {
|
||||||
case PRODUCT_ID_GP0504:
|
case PRODUCT_ID_AM3M:
|
||||||
libevdev_set_name((*evdev), "Hanvon Graphicpal GP0504");
|
case PRODUCT_ID_AM0806:
|
||||||
|
case PRODUCT_ID_AM0605:
|
||||||
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_0, NULL);
|
||||||
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_1, NULL);
|
||||||
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_2, NULL);
|
||||||
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_3, NULL);
|
||||||
break;
|
break;
|
||||||
case PRODUCT_ID_GP0906:
|
case PRODUCT_ID_AM1107:
|
||||||
|
case PRODUCT_ID_AM1209:
|
||||||
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_0, NULL);
|
||||||
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_1, NULL);
|
||||||
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_2, NULL);
|
||||||
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_3, NULL);
|
||||||
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_4, NULL);
|
||||||
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_5, NULL);
|
||||||
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_6, NULL);
|
||||||
|
libevdev_enable_event_code((*evdev), EV_KEY, BTN_7, NULL);
|
||||||
break;
|
break;
|
||||||
case PRODUCT_ID_APPIV0906:
|
default:
|
||||||
|
// do nothing
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set up libevdev device name strings
|
||||||
|
switch(desc.idProduct) {
|
||||||
|
// cases are in ID order
|
||||||
|
case PRODUCT_ID_AM3M:
|
||||||
|
// space between Art and Master intentional
|
||||||
|
libevdev_set_name((*evdev), "Hanvon Art Master III");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_AM0806:
|
||||||
|
libevdev_set_name((*evdev), "Hanvon ArtMaster AM0806");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_AM0605:
|
||||||
|
libevdev_set_name((*evdev), "Hanvon ArtMaster AM0605");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_AM1107:
|
||||||
|
// space between Art and Master intentional
|
||||||
|
libevdev_set_name((*evdev), "Hanvon Art Master AM1107");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_AM1209:
|
||||||
|
libevdev_set_name((*evdev), "Hanvon ArtMaster AM1209");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_RL0604:
|
||||||
|
libevdev_set_name((*evdev), "Hanvon Rollick 0604");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_RL0504:
|
||||||
|
libevdev_set_name((*evdev), "Hanvon Rollick 0504");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_GP0806:
|
||||||
|
libevdev_set_name((*evdev), "Hanvon Graphicpal 0806");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_GP0806B:
|
||||||
|
libevdev_set_name((*evdev), "Hanvon Graphicpal 0806B");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_GP0605:
|
||||||
|
libevdev_set_name((*evdev), "Hanvon Graphicpal 0605");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_GP0605A:
|
||||||
|
libevdev_set_name((*evdev), "Hanvon Graphicpal 0605A");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_GP0504:
|
||||||
|
libevdev_set_name((*evdev), "Hanvon Graphicpal 0504");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_NXS1513:
|
||||||
|
libevdev_set_name((*evdev), "Hanvon Nilox NXS1513");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_GP0906:
|
||||||
|
libevdev_set_name((*evdev), "Hanvon Graphicpal 0906");
|
||||||
|
break;
|
||||||
|
case PRODUCT_ID_APPIV0906:
|
||||||
|
libevdev_set_name((*evdev), "Hanvon Art Painter Pro APPIV0906");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
int err = libevdev_uinput_create_from_device(
|
int err = libevdev_uinput_create_from_device(
|
||||||
(*evdev), LIBEVDEV_UINPUT_OPEN_MANAGED, uidev
|
(*evdev), LIBEVDEV_UINPUT_OPEN_MANAGED, uidev
|
||||||
);
|
);
|
||||||
@ -294,12 +471,13 @@ int handle_device_lusb(libusb_device *d) {
|
|||||||
|
|
||||||
// Allocate memory for transfer, configure, then submit
|
// Allocate memory for transfer, configure, then submit
|
||||||
tx = libusb_alloc_transfer(0);
|
tx = libusb_alloc_transfer(0);
|
||||||
libusb_fill_interrupt_transfer( tx,
|
libusb_fill_interrupt_transfer(
|
||||||
|
tx,
|
||||||
h,
|
h,
|
||||||
ENDPOINT_ADDR,
|
ENDPOINT_ADDR,
|
||||||
buffer,
|
buffer,
|
||||||
AM_PACKET_LEN,
|
AM_PACKET_LEN,
|
||||||
callback_gp0504,
|
callback_default,
|
||||||
uidev, // extra data to send in tx
|
uidev, // extra data to send in tx
|
||||||
130); // timeout in milliseconds
|
130); // timeout in milliseconds
|
||||||
do {
|
do {
|
||||||
|
Loading…
Reference in New Issue
Block a user