29 #if defined(HAVE_HIDAPI) 31 #include <boost/scope_exit.hpp> 38 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY 39 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "device.io" 41 #define ASSERT_X(exp,msg) CHECK_AND_ASSERT_THROW_MES(exp, msg); 45 static std::string safe_hid_error(hid_device *hwdev) {
52 static std::string safe_hid_path(
const hid_device_info *hwdev_info) {
53 if (hwdev_info && hwdev_info->path) {
59 device_io_hid::device_io_hid(
unsigned short c,
unsigned char t,
unsigned int ps,
unsigned int to) :
69 device_io_hid::device_io_hid() : device_io_hid(DEFAULT_CHANNEL, DEFAULT_TAG, DEFAULT_PACKET_SIZE, DEFAULT_TIMEOUT) {
72 void device_io_hid::io_hid_log(
int read,
unsigned char* buffer,
int block_len) {
76 MDEBUG(
"HID " << (read?
"<":
">") <<
" : "<<strbuffer);
83 ASSERT_X(r>=0,
"Unable to init hidapi library. Error "+
std::to_string(r)+
": "+safe_hid_error(this->usb_device));
86 void device_io_hid::connect(
void *params) {
87 hid_conn_params *p = (
struct hid_conn_params*)params;
88 if (!this->connect(p->vid, p->pid, p->interface_number, p->usage_page)) {
89 ASSERT_X(
false,
"No device found");
93 void device_io_hid::connect(
const std::vector<hid_conn_params> &hcpV) {
95 if (this->connect(p.vid, p.pid, p.interface_number, p.usage_page)) {
99 ASSERT_X(
false,
"No device found");
102 hid_device_info *device_io_hid::find_device(hid_device_info *devices_list, boost::optional<int> interface_number, boost::optional<unsigned short> usage_page) {
103 bool select_any = !interface_number && !usage_page;
106 (select_any ?
"any HID Device" :
"HID Device with") <<
107 (interface_number ? (
" interface_number " +
std::to_string(interface_number.value())) :
"") <<
108 ((interface_number && usage_page) ?
" or" :
"") <<
111 hid_device_info *result =
nullptr;
112 for (; devices_list !=
nullptr; devices_list = devices_list->next) {
113 BOOST_SCOPE_EXIT(&devices_list, &result) {
114 MDEBUG( (result == devices_list ?
"SELECTED" :
"SKIPPED ") <<
116 " path " << safe_hid_path(devices_list) <<
117 " interface_number " << devices_list->interface_number <<
118 " usage_page " << devices_list->usage_page);
122 if (result !=
nullptr) {
127 result = devices_list;
128 }
else if (interface_number && devices_list->interface_number == interface_number.value()) {
129 result = devices_list;
130 }
else if (usage_page && devices_list->usage_page == usage_page.value()) {
131 result = devices_list;
138 hid_device *device_io_hid::connect(
unsigned int vid,
unsigned int pid, boost::optional<int> interface_number, boost::optional<unsigned short> usage_page) {
139 hid_device_info *hwdev_info_list;
144 hwdev_info_list = hid_enumerate(vid, pid);
145 if (!hwdev_info_list) {
150 if (hid_device_info *device = find_device(hwdev_info_list, interface_number, usage_page)) {
151 hwdev = hid_open_path(device->path);
153 hid_free_enumeration(hwdev_info_list);
157 this->usb_device = hwdev;
162 bool device_io_hid::connected()
const {
163 return this->usb_device != NULL;
166 int device_io_hid::exchange(
unsigned char *command,
unsigned int cmd_len,
unsigned char *
response,
unsigned int max_resp_len,
bool user_input) {
167 unsigned char buffer[400];
168 unsigned char padding_buffer[MAX_BLOCK+1];
171 unsigned int sw_offset;
172 unsigned int remaining;
173 unsigned int offset = 0;
175 ASSERT_X(this->usb_device,
"No device opened");
178 memset(buffer, 0,
sizeof(buffer));
179 result = this->wrapCommand(command, cmd_len, buffer,
sizeof(buffer));
182 while (remaining > 0) {
183 int block_size = (remaining > MAX_BLOCK ? MAX_BLOCK : remaining);
184 memset(padding_buffer, 0,
sizeof(padding_buffer));
185 memcpy(padding_buffer+1, buffer + offset, block_size);
186 io_hid_log(0, padding_buffer, block_size+1);
187 hid_ret = hid_write(this->usb_device, padding_buffer, block_size+1);
188 ASSERT_X(hid_ret>=0,
"Unable to send hidapi command. Error "+
std::to_string(result)+
": "+ safe_hid_error(this->usb_device));
189 offset += block_size;
190 remaining -= block_size;
194 memset(buffer, 0,
sizeof(buffer));
196 hid_ret = hid_read_timeout(this->usb_device, buffer, MAX_BLOCK, this->timeout);
198 hid_ret = hid_read(this->usb_device, buffer, MAX_BLOCK);
200 ASSERT_X(hid_ret>=0,
"Unable to read hidapi response. Error "+
std::to_string(result)+
": "+ safe_hid_error(this->usb_device));
201 result = (
unsigned int)hid_ret;
202 io_hid_log(1, buffer, result);
206 result = this->unwrapReponse(buffer, offset,
response, max_resp_len);
210 hid_ret = hid_read_timeout(this->usb_device, buffer + offset, MAX_BLOCK, this->timeout);
211 ASSERT_X(hid_ret>=0,
"Unable to receive hidapi response. Error "+
std::to_string(result)+
": "+ safe_hid_error(this->usb_device));
212 result = (
unsigned int)hid_ret;
213 io_hid_log(1, buffer + offset, result);
219 void device_io_hid::disconnect(
void) {
220 if (this->usb_device) {
221 hid_close(this->usb_device);
225 this->usb_device = NULL;
228 void device_io_hid::release() {
233 unsigned int device_io_hid::wrapCommand(
const unsigned char *command,
size_t command_len,
unsigned char *out,
size_t out_len) {
234 unsigned int sequence_idx = 0;
235 unsigned int offset = 0;
236 unsigned int offset_out = 0;
237 unsigned int block_size;
239 ASSERT_X(this->packet_size >= 3,
"Invalid Packet size: "+
std::to_string(this->packet_size)) ;
240 ASSERT_X(out_len >= 7,
"out_len too short: "+
std::to_string(out_len));
243 out[offset_out++] = ((this->channel >> 8) & 0xff);
244 out[offset_out++] = (this->channel & 0xff);
245 out[offset_out++] = this->tag;
246 out[offset_out++] = ((sequence_idx >> 8) & 0xff);
247 out[offset_out++] = (sequence_idx & 0xff);
249 out[offset_out++] = ((command_len >> 8) & 0xff);
250 out[offset_out++] = (command_len & 0xff);
251 block_size = (command_len > this->packet_size - 7 ? this->packet_size - 7 : command_len);
252 ASSERT_X(out_len >= block_size,
"out_len too short: "+
std::to_string(out_len));
253 out_len -= block_size;
254 memcpy(out + offset_out, command + offset, block_size);
255 offset_out += block_size;
256 offset += block_size;
257 while (offset != command_len) {
258 ASSERT_X(out_len >= 5,
"out_len too short: "+
std::to_string(out_len));
260 out[offset_out++] = ((this->channel >> 8) & 0xff);
261 out[offset_out++] = (this->channel & 0xff);
262 out[offset_out++] = this->tag;
263 out[offset_out++] = ((sequence_idx >> 8) & 0xff);
264 out[offset_out++] = (sequence_idx & 0xff);
266 block_size = ((command_len - offset) > this->packet_size - 5 ? this->packet_size - 5 : command_len - offset);
267 ASSERT_X(out_len >= block_size,
"out_len too short: "+
std::to_string(out_len));
268 out_len -= block_size;
269 memcpy(out + offset_out, command + offset, block_size);
270 offset_out += block_size;
271 offset += block_size;
273 while ((offset_out % this->packet_size) != 0) {
274 ASSERT_X(out_len >= 1,
"out_len too short: "+
std::to_string(out_len));
276 out[offset_out++] = 0;
285 unsigned int device_io_hid::unwrapReponse(
const unsigned char *data,
size_t data_len,
unsigned char *out,
size_t out_len) {
286 unsigned int sequence_idx = 0;
287 unsigned int offset = 0;
288 unsigned int offset_out = 0;
289 unsigned int response_len;
290 unsigned int block_size;
294 if ((data == NULL) || (data_len < 7 + 5)) {
299 val = (data[offset]<<8) + data[offset+1];
301 ASSERT_X(val == this->channel,
"Wrong Channel");
304 ASSERT_X(val == this->tag,
"Wrong TAG");
305 val = (data[offset]<<8) + data[offset+1];
307 ASSERT_X(val == sequence_idx,
"Wrong sequence_idx");
310 response_len = (data[offset++] << 8);
311 response_len |= data[offset++];
312 ASSERT_X(out_len >= response_len,
"Out Buffer too short");
313 if (data_len < (7 + response_len)) {
316 block_size = (response_len > (this->packet_size - 7) ? this->packet_size - 7 : response_len);
317 memcpy(out + offset_out, data + offset, block_size);
318 offset += block_size;
319 offset_out += block_size;
320 while (offset_out != response_len) {
322 if (offset == data_len) {
325 val = (data[offset]<<8) + data[offset+1];
327 ASSERT_X(val == this->channel,
"Wrong Channel");
330 ASSERT_X(val == this->tag,
"Wrong TAG");
331 val = (data[offset]<<8) + data[offset+1];
333 ASSERT_X(val == sequence_idx,
"Wrong sequence_idx");
335 block_size = ((response_len - offset_out) > this->packet_size - 5 ? this->packet_size - 5 : response_len - offset_out);
336 if (block_size > (data_len - offset)) {
339 memcpy(out + offset_out, data + offset, block_size);
340 offset += block_size;
341 offset_out += block_size;
350 #endif //#if defined(HAVE_HIDAPI)
epee::misc_utils::struct_init< response_t > response
void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len)
const GenericPointer< typename T::ValueType > T2 value
void * memcpy(void *a, const void *b, size_t c)
std::string to_string(t_connection_type type)