// // // // // Note hpusb opens an interface but can have multiple usb ports // open. Hence handle information is stored else where #include "hpusb.h" #include "hpdata.h" #include #include #include "global.h" #include //return 0 = success //return > err hpusb::hpusb() { lb_init=0; } // Initialise libusb // returns 0 if succesfull int hpusb::hp_init() { int ret=0; if(!lb_init) { log("Initialising usb interface"); if(!(ret=libusb_init(&ctx))) { log("libusb init ok"); libusb_set_debug(ctx,LIBUSB_LOG_LEVEL_DEBUG); lb_init=1; return ret; } else err(L3,ret,QString(QString().sprintf("Could not open libusb: %d",ret))); } return ret; } //open usb and claim it int hpusb::hp_open(hp_Handle * handle) { int ret=0; // discover devices libusb_device **list; libusb_device *found = nullptr; libusb_device_handle * devh; if(!lb_init) hp_init(); if ((!handle->dev_open)&&(lb_init)) { ssize_t cnt = libusb_get_device_list(nullptr, &list); ssize_t i = 0; if (cnt < 0) err(L3,0,"Could not get a device list"); for (i = 0; i < cnt; i++) { libusb_device *device = list[i]; if (is_device(device)) { found = device; log("Device found"); break; } } if (found) { ret= libusb_open(found, &devh); if (ret) { err(L3,ret,"Could not open usb device"); goto endfunc; } qDebug()<<"set handle"; if (handle!=nullptr) { handle->usbhandle = devh; handle->usbdevice = found; } else { err(L3,0,"handle null"); } log("Device opened"); //claim interface ret = libusb_kernel_driver_active ( handle->usbhandle, 0x0) ; if (ret==1) { log(QString().sprintf("Keneral active")); ret = libusb_detach_kernel_driver( handle->usbhandle, 0x0) ; log(QString().sprintf("Keneral detach: %s\n", libusb_error_name(ret))); if (ret!=0) { log(QString().sprintf("Keneral detach error: %s\n", libusb_error_name(ret))); goto endfunc; } } else if (ret!=0) { log(QString().sprintf("Kernal error %s\n", libusb_error_name(ret))); goto endfunc; } //Note: Configuration 0 causes calculator to reboot // 1 ok // // ret=libusb_set_configuration(handle->usbhandle,0x1); // if (ret!=0) { // log(QString().sprintf("Set Configuration: %s\n", libusb_error_name(ret))); // goto endfunc; // } handle->dev_open=1; ret = libusb_claim_interface(handle->usbhandle, 0x0); if (ret!=0) { log(QString().sprintf("Claim interface Error: %s\n", libusb_error_name(ret))); return -1; } } else { ret=-1; } endfunc: libusb_free_device_list(list, 1); } return ret; } //replace with libusb_open_device_with_vid_pid int hpusb::is_device(libusb_device * device) { libusb_device_descriptor desc = {0}; int rc=0; rc = libusb_get_device_descriptor(device, &desc); if (rc!=0) { err(L3,rc,QString(__FUNCTION__) + QString(" Could not get device descriptor ")); } else { // log(QString().sprintf("Vendor:Device = %04x:%04x", desc.idVendor, desc.idProduct)); if ((desc.idVendor==USB_VID_HP)&&(desc.idProduct==USB_PID_PRIME3)) { return 1; } } return 0; } int hpusb::submit_sync_transfer(hp_Handle * handle, hp_pkt_in * pktin, hp_pkt_out * pktout) { log("In sync transfer"); if (!handle) return -1; libusb_device_handle * devh = handle->usbhandle; qDebug()<usbhandle); int ret; int trans=0; if (!devh) return -1; //write log("Send.."); ret = libusb_interrupt_transfer(devh, 0x02, pktin->buffer, pktin->size, &trans,10000); log(QString().sprintf("Write Error: %s\n", libusb_error_name(ret))); log(QString().sprintf("Write bytes: %d\n", trans)); //read log("Recieve..."); ret = libusb_interrupt_transfer(devh,0x81,pktout->buffer,pktout->size-8,&trans,10000); log(QString().sprintf("read: %d\n", trans)); if (ret){ log(QString().sprintf("ERROR in interrupt read: %s\n", libusb_error_name(ret))); } else{ //printf("%d receive %d bytes from device: %s\n"); log(QString().sprintf("%d bytes received",trans)); main_err-> dump(pktout->buffer,trans); } return ret; } //send a submission int hpusb::submit_async_transfer(hp_Handle * handle, hp_pkt_in * pktin, hp_pkt_out *pktout) { // static uint8_t in_buffer[LEN_IN_BUFFER]; int buffer_len; buffer_len=pktin->size; struct sigaction sigact; int r = 1; // result int i; do_exit = 0; libusb_device_handle * devh = handle->usbhandle; //Allocation // allocate transfer of data IN (IN to host PC from USB-device) transfer_in = libusb_alloc_transfer(0); //Filling //libusb_fill_interrupt_setup(in_buffer,LIBUSB_RECIPIENT_DEVICE ,LIBUSB_REQUEST_TYPE_STANDARD,0,0,16); libusb_fill_control_transfer( transfer_in, devh, pktin->buffer, // Note: in_buffer is where input data written. cb_in, nullptr, 1000); // no user data //take the initial time measurement clock_gettime(CLOCK_REALTIME, &t1); //Submission //submit the transfer, all following transfers are initiated from the CB r = libusb_submit_transfer(transfer_in); // Define signal handler to catch system generated signals // (If user hits CTRL+C, this will deal with it.) sigact.sa_handler = sighandler; // sighandler is defined below. It just sets do_exit. sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); sigaction(SIGQUIT, &sigact, NULL); printf("Entering loop to process callbacks...\n"); /* The implementation of the following while loop makes a huge difference. * Since libUSB asynchronous mode doesn't create a background thread, * libUSB can't create a callback out of nowhere. This loop calls the event handler. * In real applications you might want to create a background thread or call the event * handler from your main event hanlder. * For a proper description see: * http://libusbx.sourceforge.net/api-1.0/group__asyncio.html#asyncevent * http://libusbx.sourceforge.net/api-1.0/group__poll.html * http://libusbx.sourceforge.net/api-1.0/mtasync.html */ int c=0; if(0){ qDebug()<<"At loop"; // This implementation uses a blocking call while (!do_exit) { c++; r = libusb_handle_events_completed(ctx, NULL); if ((r < 0)||(c>100000)){ // negative values are errors qDebug()<<"At break"; exitflag = out_deinit; break; } } } else{ // This implementation uses a blocking call and aquires a lock to the event handler struct timeval timeout; timeout.tv_sec = 0; // seconds timeout.tv_usec = 100000; // ( .1 sec) libusb_lock_events(ctx); c=0; while (!do_exit) { c++; r = libusb_handle_events_locked(ctx, &timeout); if ((r < 0)||(c>10000)){ // negative values are errors exitflag = out_deinit; qDebug()<<"At break 2"; break; } } libusb_unlock_events(ctx); } // If these transfers did not complete then we cancel them. // Unsure if this is correct... if (transfer_out) { r = libusb_cancel_transfer(transfer_out); if (0 == r){ printf("transfer_out successfully cancelled\n"); } if (r < 0){ exitflag = out_deinit; } } if (transfer_in) { r = libusb_cancel_transfer(transfer_in); if (0 == r){ printf("transfer_in successfully cancelled\n"); } if (r < 0){ exitflag = out_deinit; } } //Completion Handling //Deallocation switch(exitflag){ case out_deinit: printf("at out_deinit\n"); libusb_free_transfer(transfer_out); libusb_free_transfer(transfer_in); case out_release: libusb_release_interface(devh, 0); } } // This will catch user initiated CTRL+C type events and allow the program to exit void sighandler(int signum) { printf("sighandler\n"); } //submission callback // Out Callback // - This is called after the Out transfer has been received by libusb void cb_out(struct libusb_transfer *transfer) { QString().sprintf("status =%d, actual_length=%d\n", transfer->status, transfer->actual_length); } // In Callback // - This is called after the command for version is processed. // That is, the data for in_buffer IS AVAILABLE. void cb_in(struct libusb_transfer *transfer) { qDebug()<<"in cb_in"; uint32_t benchPackets=1; uint32_t benchBytes=0; struct timespec t1, t2; uint32_t diff=0; //measure the time clock_gettime(CLOCK_REALTIME, &t2); //submit the next transfer //libusb_submit_transfer(transfer_in); benchBytes += transfer->actual_length; //this averages the bandwidth over many transfers if(++benchPackets%100==0){ //Warning: uint32_t has a max value of 4294967296 so this will overflow over 4secs diff = (t2.tv_sec-t1.tv_sec)*1000000000L+(t2.tv_nsec-t1.tv_nsec); t1.tv_sec = t2.tv_sec; t1.tv_nsec = t2.tv_nsec; printf("\rreceived %5d transfers and %8d bytes in %8d us, %8.1f B/s", benchPackets, benchBytes, diff/1000, benchBytes*1000000.0/(diff/1000)); fflush(stdout); benchPackets=0; benchBytes=0; } } int hpusb::hp_func() { return 0; } int hpusb::is_ready() { return 0; } int hpusb::load_info(hp_Handle * handle, hp_Information * hpinfo) { uint8_t transferbuffer[PRIME_RAW_HID_DATA_SIZE ]; uint8_t out_buffer[LEN_IN_BUFFER+8]; hp_pkt_in pktin; hp_pkt_out pktout; transferbuffer[0]=0x0; transferbuffer[1]=CMD_PRIME_GET_INFOS; pktin.buffer=transferbuffer; pktin.size=2; pktout.buffer=out_buffer; pktout.size=sizeof(out_buffer); // pktout.size=PRIME_RAW_HID_DATA_SIZE+16; if (!submit_sync_transfer(handle,&pktin,&pktout)){ //unpack data log("unpacking data"); int ind=0; qDebug()<<"start"; QTextCodec * codec = QTextCodec::codecForName("UTF-8"); QByteArray rd= QByteArray(reinterpret_cast(pktout.buffer), pktout.size); //find name ind=rd.indexOf(QChar(0x6c),0)+1; QByteArray str1 =rd.mid(ind,64); qDebug()<toUnicode(str1); hpinfo->name=name; qDebug()<toUnicode(str1); hpinfo->osver=osv; qDebug()<toUnicode(str1); hpinfo->serialnum=serial; qDebug()<toUnicode(str1); //hpinfo->appver=app; qDebug()<dev_open) { libusb_release_interface(handle->usbhandle, 0); libusb_close(handle->usbhandle); handle->dev_open =0; } } return 0; } // debugging function to display libusb_transfer void hpusb::print_libusb_transfer(struct libusb_transfer *p_t) { int i; if ( NULL == p_t){ log("No libusb_transfer...\n"); } else { log("libusb_transfer structure:\n"); log(QString().sprintf("flags =%x \n", p_t->flags)); log(QString().sprintf("endpoint=%x \n", p_t->endpoint)); log(QString().sprintf("type =%x \n", p_t->type)); log(QString().sprintf("timeout =%d \n", p_t->timeout)); // length, and buffer are commands sent to the device log(QString().sprintf("length =%d \n", p_t->length)); log(QString().sprintf("actual_length =%d \n", p_t->actual_length)); log(QString().sprintf("buffer =%p \n", p_t->buffer)); for (i=0; i < p_t->length; i++){ log(QString().sprintf(" %x", i, p_t->buffer[i])); } } return; } hpusb::~hpusb() { libusb_exit(ctx); }