#include "stdafx.h" #include "GScanO200.h" #include "UsbScanEx.h" #include "StopWatch.h" #include "scn_config.h" #include "ImageMatQueue.h" #include "ImageProcess/ImageApplyDogEarDetection.h" #include "filetools.h" #include "GetMemoryUsage.h" //u32_CMD typedef enum tagUsbKeyWords : UINT32 { //无命令 NO_COMMAND = 0, //获取dsp 状态 GET_DSP_STATUS = 1, //取图 GET_IMAGE = 2, //销毁DSP中驻存的图 POP_IMAGE = 3, //开始扫描命令 START_COMMAND = 4, //停止扫描命令 STOP = 5, //获取扫描仪扫描模式 GET_SCAN_MODE = 6, //获取固件版本号 GET_FW_VERSION = 7, //返回PC端的状态 SEND_STATUS_PC = 8, //下发扫描配置参数 CONFIGURED_DATA = 9, //下发固件信息 SEND_FW = 10, //获取扫描参数 GET_CONFIG_DATA = 11, //获取扫描总张数 GET_SCANN_NUM = 12, //获取有无纸的状态 GET_PAPERFEEDER_STATUS = 13, //DSP初始化 INIT_HARDWARE_SYS = 14, //获取有无纸的状态 GET_PAPER_STATUS = 0x0d, //下发元器件配置参数(灰度,LED R曝光时间) SEND_COMPONENTS_GR = 15, //下发元器件配置参数(LED G/B曝光时间) SEND_COMPONENTS_GB = 16, //下发扫描模式 SEND_SCAN_MODE = 17, //开始进行平场矫正 START_FLAT = 18, //停止平场矫正 STOP_FLAT = 19, //下发200dpi彩色平场矫正参数 SEND_200_COLOR_FLAT_DATA = 20, //下发300dpi彩色平场矫正参数 SEND_300_COLOR_FLAT_DATA = 21, //获取200dpi彩色平场矫正参数 GET_200_COLOR_FLAT_DATA = 22, //获取300dpi彩色平场矫正参数 GET_300_COLOR_FLAT_DATA = 23, //下发200dpi灰度平场校正参数 SEND_200_GRAY_FLAT_DATA = 24, //下发300dpi灰度平场校正参数 SEND_300_GRAY_FLAT_DATA = 25, //获取200DPI灰度平场校正参数 GET_200_GRAY_FLAT_DATA = 26, //获取300DPI灰度平场校正参数 GET_300_GRAY_FLAT_DATA = 27, //下发序列号命令 SEND_SERIAL = 28, //获取序列号命令 GET_SERIAL = 29, //获取滚轴数 GET_ROLLER_NUM = 0x1e, //清零滚轴数 CLR_ROLLER_NUM = 0x1f, //清除扫描总张数 CLR_SCAN_NUM = 0x20, //准备更新固件 PRE_UPGRADE = 0X21, //开始更新固件 START_UPGRADE = 0x22, //彩色的AD参数 RGB_ADI_PARA = 0x23, //灰度的AD参数 ADI_PARA = 0x24, //获取CIS参数(曝光时间,ad参数) GET_CIS_PARA = 0x25, //扫描张数 START_COMMAND_COUNT = 0x26, //下发休眠时间 SET_SLEEP_TIME = 0x27, //获取休眠时间 GET_SLEEP_TIME = 0x28, //清除缓存 CLR_CACHE = 0x29, //下发速度模式 SET_SPEED_MODE = 0x2a, //获取扫描速度模式 GET_SPEED_MODE = 0X2b, //设置固件版本一共8个字节 SET_FW_VERSION = 0X2c, //获取DSP版本 GET_DSP_VERSION = 0X2d, //采集板FPGA固件版本 GET_SCANFPGA_VERSION = 0x2e, //电机板FPGA固件版本 GET_MOTORFPGA_VERSION = 0X2f, //设置制造商信息 SET_USB_INFOR_MANUFACTURE = 0X30, //获取制造商信息 GET_USB_INFOR_MANUFACTURE = 0X31, //设置产品型号信息 SET_USB_INFOR_MODEL_NAME = 0X32, //获取产品型号信息 GET_USB_INFOR_MODEL_NAME = 0X33, //设置USB PID / VID信息 SET_USB_INFOR_VIDPID = 0X34, GET_USB_INFOR_VIDPID = 0X35, //设置卡纸急停检测灵敏度 SET_JAM_DETECT_SENSITIVE = 0X36, //获取卡纸急停检测灵敏度 GET_JAM_DETECT_SENSITIVE = 0X37, //设置横向畸变系数 SET_JUST_COF_H = 0x38, //读取横向畸变系数 GET_JUST_COF_H = 0x39, //设置纵向畸变系数 SET_JUST_COF_V = 0x41, //读取纵向畸变系数 GET_JUST_COF_V=0x42, //设置扫描仪编码 GET_CODE_G400 = 0x59, //读取扫描仪编码 SET_CODE_G400 = 0x5A, //设置扫描仪编码 SET_CODE_G200=0x63, //读取扫描仪编码 GET_CODE_G200=0x64, } UsbKeyWords, * PUsbKeyWords; GScanO200::GScanO200() : huagods(NULL), image_num(0), m_bread_fixed_ratio_fromDSP(false), is_orginimgcount(true) { m_pImages.reset(new ImageMatQueue()); m_pImages->Getimagenumber = std::bind(&GScanO200::Getimagenumber,this, std::placeholders::_1); } GScanO200::~GScanO200() { if (m_threadUsb && m_threadUsb->joinable()) { devState = DEV_STOP; m_threadUsb->join(); m_threadUsb.reset(); } if (m_usb.get()) m_usb.reset(); } void GScanO200::Getimagenumber(bool isadd) { if (isadd) { image_num++; } else { image_num--; } } void GScanO200::DogEar_callback(std::function fun) { m_pImages->DogEarDetection_callback = fun; } void GScanO200::open(int vid, int pid) { auto usbs = UsbScan_List::find_vid_pid(vid, pid); if (!usbs.empty()) { m_usb = *usbs.begin(); m_usb->set_usbhotplug_callback(usbhotplug_callback, this); bool ret = m_usb->open(); USBCB status = { GET_DSP_STATUS ,0,0 }; if (m_usb.get() && m_usb->is_connected()) m_usb->write_bulk(&status, sizeof(status)); if (m_usb.get() && m_usb->is_connected()) m_usb->read_bulk(&status, sizeof(status)); } if (this->IsConnected()) GetFWVersion(); } void GScanO200::regist_deviceevent_callback(deviceevent_callback callback, void* usrdata) { huagods = usrdata; dev_callback = callback; } #ifdef LOG_NORMAL fstream fsaquire; static int aquiretimes = 1; #endif // LOG int GScanO200::aquire_bmpdata(std::vector& bmpdata) { StopWatch sw; while (true) { if (m_pImages->empty()) { DoEvents(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); if (sw.elapsed_s() > 30.00) { if (m_threadUsb && m_threadUsb->joinable()) { devState = DEV_STOP; m_threadUsb->join(); m_threadUsb.reset(); //writelog("aquire_bmpdata m_threadUsb.reset();"); } Stop_scan();//停止扫描 ResetScanner(); auto rollernew = Get_Roller_num(); if (get_aquire_image_count() != (rollernew - roller_num)) set_lose_image_num(std::abs((rollernew - roller_num) - get_aquire_image_count())); return HARDWARE_ERROR; } if (!is_scan()) { if (devState == DEV_WRONG) { return get_ErrorCode(); } return -1; } } else { if (m_pImages->valid()) { bmpdata = *(m_pImages->popBmpdata()); //static int aqimgindex = 0; //writelog("aquireed image " + to_string(++aqimgindex)); //FileTools::write_log("C:\\Users\\huagao\\Desktop\\out.txt", "aquired procced image "+ to_string(++aqimgindex)); set_aquire_image_count(get_aquire_image_count(), get_updata_image_count() + 1); #ifdef LOG_NORMAL static int aquireindex = 0; FileTools::write_log("out.txt", "aquire image index " + std::to_string(++aquireindex)); #endif // LOG return 0; } DoEvents(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); } } } BOOL GScanO200::IsConnected() { return m_usb.get() && m_usb->is_connected(); } std::string GScanO200::GetFWVersion() { if (m_usb.get() && m_usb->is_connected()) { lock_guard< mutex> lock(m_imgLocker); if (fwVersion.empty()) { fwVersion.resize(8); USBCB cmd = { GET_FW_VERSION,fwVersion.size(),0, }; m_usb->write_bulk(&cmd, sizeof(cmd)); m_usb->read_bulk(&fwVersion[0], fwVersion.size()); std::string ver = fwVersion.substr((fwVersion.length() - 2), 2); int verValue = atoi(ver.c_str()); m_bread_fixed_ratio_fromDSP = verValue >= 15; FileTools::writelog(log_ERROR,m_bread_fixed_ratio_fromDSP ? "can get ratio from dsp" : "can not get dsp ratio"); updateHVRatio(); } return fwVersion; } return ""; } std::string GScanO200::GetSerialNum() { //return "G20018000298"; if (m_usb.get() && m_usb->is_connected()) { std::lock_guard lck(m_imgLocker); if (SerialNum.empty()) { SerialNum.resize(12); USBCB usbcb = { GET_SERIAL,SerialNum.size(),0 }; m_usb->write_bulk(&usbcb, sizeof(usbcb)); m_usb->read_bulk(&SerialNum[0], SerialNum.size()); } return SerialNum; } return ""; } std::uint32_t GScanO200::GetMotorFPGA() { if (m_usb.get() && m_usb->is_connected()) { std::lock_guard lck(m_imgLocker); USBCB usbcb = { GET_MOTORFPGA_VERSION,0,sizeof(MotorFpga) }; m_usb->write_bulk(&usbcb, sizeof(usbcb)); m_usb->read_bulk(&usbcb, sizeof(usbcb)); MotorFpga = usbcb.u32_Data; return MotorFpga; } return 0; } std::uint32_t GScanO200::GetScanFPGA() { if (m_usb.get() && m_usb->is_connected()) { std::lock_guard lck(m_imgLocker); USBCB usbcb = { GET_SCANFPGA_VERSION,0,4 }; m_usb->write_bulk(&usbcb, sizeof(usbcb)); m_usb->read_bulk(&usbcb, sizeof(usbcb)); ScanFpga = usbcb.u32_Data; return ScanFpga; } return 0; } bool GScanO200::is_scan() { //std::lock_guard lck(m_imgLocker); return devState == DEV_ISRUNNING; } BOOL GScanO200::Get_Scanner_PaperOn() { if (!(m_usb.get() && m_usb->is_open())) return false; USBCB usbcb = { GET_PAPER_STATUS ,0,0 }; usbcb.u32_Data = 1;//修改初始值防止通信异常时默认初始值为0报无纸 std::lock_guard lck(m_imgLocker); m_usb->write_bulk(&usbcb, sizeof(usbcb)); if (0 == m_usb->read_bulk(&usbcb, sizeof(usbcb))) { Set_ErrorCode(USB_DISCONNECTED); return true; } return usbcb.u32_Data != 0; } int GScanO200::Get_Roller_num() { if (!(m_usb.get() && m_usb->is_open())) return 0; USBCB usbcb = { GET_ROLLER_NUM ,0,4 }; std::lock_guard lck(m_imgLocker); m_usb->write_bulk(&usbcb, sizeof(usbcb)); std::this_thread::sleep_for(std::chrono::milliseconds(50)); m_usb->read_bulk(&usbcb, sizeof(usbcb)); if (usbcb.u32_CMD != GET_ROLLER_NUM) { FileTools::writelog(log_ERROR, "get roller usb bulk error"); } FileTools::writelog(log_INFO, "get roller num " + to_string(usbcb.u32_Data)); return usbcb.u32_Data; } void GScanO200::config_params(GScanCap& params) { if (m_usb.get() && m_usb->is_connected()) { hgConfigClass cfg = hgConfigClass(params); gcap = params; UINT32 cfgdata = cfg.GetData(); USBCB usbcb = { CONFIGURED_DATA,cfgdata,0 }; FileTools::writelog(log_INFO, "config hardware param"+to_string(cfgdata)); m_usb->write_bulk(&usbcb, sizeof(USBCB)); this_thread::sleep_for(std::chrono::milliseconds(200)); m_pImages->setparam(params); } } void GScanO200::Scanner_StartScan(UINT16 count) { if (fwVersion.size() > 1) { if ((atoi(fwVersion.substr(2, 6).c_str()) > 211132) && ((MotorFpga >= 25210514)&&(MotorFpga<100000000))) is_orginimgcount = true; else is_orginimgcount = false; } roller_num = Get_Roller_num(); std::lock_guard lck(m_imgLocker); if (m_threadUsb && m_threadUsb->joinable()) { devState = DEV_STOP; m_threadUsb->join(); } USBCB status = { GET_DSP_STATUS ,0,0 }; if (m_usb.get() && m_usb->is_connected()) m_usb->write_bulk(&status, sizeof(status)); if (m_usb.get() && m_usb->is_connected()) m_usb->read_bulk(&status, sizeof(status)); switch (status.u32_Data) { case COUNT_MODE: case NO_FEED: case OPEN_COVER: case FEED_IN_ERROR: case PAPER_JAM: case DETECT_DOUBLE_FEED: case DETECT_STAPLE: case PAPER_SKEW: case HARDWARE_ERROR: case PC_SCAN_BUSY_or_ERROR: m_pImages->setscanflags(false); devState = DEV_WRONG; Set_ErrorCode(status.u32_Data); if (huagods) dev_callback(status.u32_Data, huagods); return; default: break; } //#ifndef G200 // // USBCB paperstatus = { GET_PAPER_STATUS ,0,0 }; // paperstatus.u32_Data = 1; // if (m_usb.get() && m_usb->is_connected()) // m_usb->write_bulk(&paperstatus, sizeof(paperstatus)); // if (m_usb.get() && m_usb->is_connected()) // m_usb->read_bulk(&paperstatus, sizeof(paperstatus)); // if (paperstatus.u32_Data == 0) { // m_pImages->setscanflags(false); // devState = DEV_WRONG; // Set_ErrorCode(NO_FEED); // if (huagods) // dev_callback(NO_FEED, huagods); // return; // } //#endif // !G200 m_pImages->reset_DogEar(); if (gcap.is_duplex) count = count == 65535 ? 65535 : count / 2; USBCB usbcb = { START_COMMAND,(UINT32)count ,0 }; if (m_usb.get() && m_usb->is_connected()) m_usb->write_bulk(&usbcb, sizeof(usbcb)); this_thread::sleep_for(std::chrono::milliseconds(500)); if (m_usb.get() && m_usb->is_connected()) { m_pImages->setscanflags(true); m_threadUsb.reset(new std::thread(&GScanO200::usbmain, this)); m_pImages->run(); } } int GScanO200::notifyscan() { return -1; } void GScanO200::Stop_scan() { std::lock_guard lck(m_imgLocker); USBCB usbcb = { STOP ,0,0 }; if (m_usb.get() && m_usb->is_connected()) m_usb->write_bulk(&usbcb, sizeof(usbcb)); } void GScanO200::ResetScanner() { if (!(m_usb.get() && m_usb->is_connected())) return; std::lock_guard lck(m_imgLocker); USBCB usbcb = { INIT_HARDWARE_SYS ,0,0 }; if (m_usb.get() && m_usb->is_connected()) m_usb->write_bulk(&usbcb, sizeof(usbcb)); while (!m_pImages->m_imagepath.empty()) { string path = m_pImages->m_imagepath.front(); if (isFileExist(path)) remove(path.c_str()); m_pImages->m_imagepath.pop(); } } bool GScanO200::Get_IsImageQueueEmpty() { return m_pImages->empty(); } void GScanO200::reset() { while (!m_pImages->empty()) m_pImages->clear(); } void GScanO200::setdecodepixtype(int twpixtype) { } UINT32 GScanO200::get_ErrorCode() { return Error_Code; } void GScanO200::Set_ErrorCode(UINT32 value) { Error_Code = value; } int GScanO200::get_scanned_num() { std::lock_guard lck(m_imgLocker); USBCB usbcb = { GET_SCANN_NUM ,0,0 }; if (m_usb.get() && m_usb->is_connected()) m_usb->write_bulk(&usbcb, sizeof(usbcb)); return usbcb.u32_Count; } void GScanO200::clear_hwerror() { ; } void GScanO200::set_sleep_time(int mode) { if (!(m_usb.get() && m_usb->is_connected())) return ; USBCB usbcb = { SET_SLEEP_TIME ,mode&0x7,0 }; m_usb->write_bulk(&usbcb, sizeof(usbcb)); m_usb->read_bulk(&usbcb, sizeof(usbcb)); usbcb = { GET_SLEEP_TIME ,0,0 }; m_usb->write_bulk(&usbcb, sizeof(usbcb)); m_usb->read_bulk(&usbcb, sizeof(usbcb)); } bool GScanO200::set_scannercode(std::string str) { if (str.size() != 32) return false; if (!(m_usb.get() && m_usb->is_connected())) return false; for (int i = 0; i < str.size(); i += 4) { USBCB usbcb = { SET_CODE_G200,UINT32(str[i]) + ((UINT32(str[i + 1])) << 8) + (((UINT32)str[i + 2]) << 16) + (((UINT32)str[i + 3]) << 24),i }; m_usb->write_bulk(&usbcb, sizeof(usbcb)); } return true; } std::string GScanO200::get_scannercode() { if (!(m_usb.get() && m_usb->is_connected())) return NULL; USBCB usb{ GET_CODE_G200,0,32 }; m_usb->write_bulk(&usb, sizeof(USBCB)); std::this_thread::sleep_for(std::chrono::milliseconds(20)); scannercode.resize(32); m_usb->read_bulk(&scannercode[0], 32); return scannercode.c_str(); } void GScanO200::usbhotplug_callback(bool isconnect, void* userdata) { GScanO200* This = (GScanO200*)userdata; This->usbhotplug(isconnect); } void GScanO200::usbhotplug(bool isleft) { FileTools::writelog(log_ERROR, "enable usb callback "); if (isleft) { devState = DEV_WRONG; Error_Code = USB_DISCONNECTED; m_pImages->setscanflags(false); if (m_usb.get()) m_usb.reset(); if (huagods) dev_callback(USB_DISCONNECTED, huagods); } } void GScanO200::updateHVRatio() { if (!(m_usb.get() && m_usb->is_connected())) return; if (m_bread_fixed_ratio_fromDSP) { USBCB usbcb = { GET_JUST_COF_H ,0,0 }; m_usb->write_bulk(&usbcb, sizeof(usbcb)); m_usb->read_bulk(&usbcb, sizeof(usbcb)); float hratio = *((float*)(&usbcb.u32_Data)); usbcb = { GET_JUST_COF_V ,0,0 }; m_usb->write_bulk(&usbcb, sizeof(usbcb)); m_usb->read_bulk(&usbcb, sizeof(usbcb)); float vratio = *((float*)(&usbcb.u32_Data)); m_pImages->updatefixratio(hratio, vratio); } } void GScanO200::usbmain() { std::shared_ptr> imgData; devState = DEV_ISRUNNING; bool haveError = false; try { StopWatch sw; while (devState == DEV_ISRUNNING) { if (!(m_usb.get() && m_usb->is_connected())) { this_thread::sleep_for(chrono::milliseconds(200)); break; } if (sw.elapsed_ms() > 30000) { m_pImages->setscanflags(false); //devState = haveError ? DevState::DEV_WRONG : DevState::DEV_STOP; devState = DevState::DEV_WRONG; Set_ErrorCode(AQUIRE_IMAGE_TIMEOUT); FileTools::writelog(log_ERROR, "USBmain aquire image timeout"); return; } //if(gcap.resolution_dst>200.0f) //{ // if (m_pImages->orginimgcount() > 2) // { // this_thread::sleep_for(chrono::milliseconds(10)); // continue; // } //} //else { // if ((m_pImages->orginimgcount() > 15)&&(is_orginimgcount)) // { // this_thread::sleep_for(chrono::milliseconds(10)); // continue; // } //} USBCB usbcb = Get_Scanner_Status(); switch (usbcb.u32_Data) { case HAVE_IMAGE: { int totalNum = usbcb.u32_Count; m_usb->set_timeout(2000); imgData = Get_Img_Data(totalNum); if (!imgData->size()) { Stop_scan(); FileTools::writelog(log_ERROR,"imgData->size() error send stop scan"); break; } m_usb->set_timeout(200); //if(!m_pImages->get_isDogEar()) // m_pImages->pushMat(std::shared_ptr(new G200Decode(imgData))); //string path = cv::tempfile(); m_pImages->m_data.push(imgData); //string path = FileTools::get_appdata_path() + "image"+to_string(get_aquire_image_count())+".tmp"; //if (!access(path.c_str(), 0)) // remove(path.c_str()); //FILE* fd = fopen(path.c_str(), "wb+"); //if (fd) //{ // fwrite(imgData->data(), imgData->size(), 1, fd); // fclose(fd); // m_pImages->m_imagepath.push(path); //} Pop_Image(); set_aquire_image_count(get_aquire_image_count() + 1,get_updata_image_count()); FileTools::writelog(log_INFO, "从扫描仪接收"+to_string(get_aquire_image_count())+"份文件。"); sw.reset(); break; } case STOP_SCAN: { m_pImages->setscanflags(false); std::this_thread::sleep_for(std::chrono::milliseconds(1500)); auto rollernew= Get_Roller_num(); if (get_aquire_image_count() != (rollernew - roller_num)) { Set_ErrorCode(LOSE_IMAGE); set_lose_image_num(std::abs((rollernew - roller_num) - get_aquire_image_count())); haveError = true; } devState = haveError ? DevState::DEV_WRONG : DevState::DEV_STOP; //m_pImages->setscanflags(false); //devState = DEV_STOP; break; } case COUNT_MODE: case NO_FEED: case OPEN_COVER: case FEED_IN_ERROR: case PAPER_JAM: case DETECT_DOUBLE_FEED: case DETECT_STAPLE: case PAPER_SKEW: case HARDWARE_ERROR: case PC_SCAN_BUSY_or_ERROR: case SIZE_ERROR: case USB_BULK_ERROR: { if (usbcb.u32_Data == USB_BULK_ERROR) Stop_scan(); Set_ErrorCode(usbcb.u32_Data); m_pImages->setscanflags(false); devState = DEV_WRONG; std::this_thread::sleep_for(std::chrono::milliseconds(1500)); auto rollernew = Get_Roller_num(); if (get_aquire_image_count() != (rollernew - roller_num)) set_lose_image_num(std::abs((rollernew - roller_num) - get_aquire_image_count())); if (huagods) dev_callback(usbcb.u32_Data, huagods); break; } case NORMAL: break; default: break; } this_thread::sleep_for(chrono::milliseconds(10)); } } catch (const std::exception& e) { //writelog(e.what()); FileTools::writelog(log_ERROR, e.what()); } } /////////////////////////////////////////////////////////////////////////// USBCB GScanO200::Get_Scanner_Status() { if (!(m_usb.get() && m_usb->is_connected())) { return { NO_COMMAND ,PC_SCAN_BUSY_or_ERROR ,0 }; } USBCB usbcb = { GET_DSP_STATUS ,0,0 }; if (m_usb.get() && m_usb->is_connected()) m_usb->write_bulk(&usbcb, sizeof(usbcb)); if (m_usb.get() && m_usb->is_connected()) m_usb->read_bulk(&usbcb, sizeof(usbcb)); //if (usbcb.u32_CMD != GET_DSP_STATUS) //{ // FileTools::writelog(log_ERROR, "get dsp status usb bulk error"); // return { NO_COMMAND,USB_BULK_ERROR,0 }; //} return usbcb; } std::shared_ptr> GScanO200::Get_Img_Data(int bufferSize) { try { if (!(m_usb.get() && m_usb->is_connected())) return std::shared_ptr>(new std::vector()); std::shared_ptr> imData(new std::vector(bufferSize)); StopWatch sw; int readed = 0; USBCB usbcb = { GET_IMAGE,0,bufferSize }; m_usb->write_bulk(&usbcb, sizeof(usbcb)); int totalength = bufferSize; int startindex = 0; while (totalength > 0) { int dstlength = 512 * 1024; if (totalength <= dstlength) { dstlength = totalength; totalength = 0; } else totalength -= dstlength; int tt = m_usb->read_bulk(imData->data() + startindex, dstlength); startindex += dstlength; } if (sw.elapsed_ms() > 5000) { FileTools::writelog(log_ERROR,"Usb read data timeout\n"); } return imData; } catch (const std::exception& e) { FileTools::writelog(log_ERROR, e.what()); } } /////////////////////////////////////////////////////////////////////////// void GScanO200::Pop_Image() { if (!(m_usb.get() && m_usb->is_open())) return; USBCB usbcb = { POP_IMAGE ,0,0 }; m_usb->write_bulk(&usbcb, sizeof(usbcb)); }