#include "GScan439Android.h" #include "IUsb.h" #include "UsbScanEx.h" #include using namespace std; static std::mutex mx_ctrl; #define m_max(a, b) (((a) > (b)) ? (a) : (b)) #define m_min(a, b) (((a) < (b)) ? (a) : (b)) static int read_reg(std::shared_ptr& usb, int addr) { std::lock_guard lck(mx_ctrl); std::this_thread::sleep_for(std::chrono::milliseconds(50)); if (usb.get() && usb->is_connected()) { int val = 0; usb->control_msg(0xc0, USB_REQ_GET_DEV_REGS, addr, 0, 4, &val); return val; } else FileTools::writelog(log_ERROR, " read_reg error usb disconnect"); return 0; } static void write_reg(std::shared_ptr& usb, int addr, int val) { std::lock_guard lck(mx_ctrl); std::this_thread::sleep_for(std::chrono::milliseconds(50)); if (usb.get() && usb->is_connected()) { usb->control_msg(0x40, USB_REQ_SET_DEV_REGS, addr, 0, 4, &val); } else FileTools::writelog(log_ERROR, " write_reg error usb disconnect"); } static void scanner_control(std::shared_ptr& usb, int cmd) { write_reg(usb, 0, cmd); } GScan439Android::GScan439Android():m_readimgpool(1) { im_data.reset(new std::vector()); m_status = -1; m_pImages.reset(new ImageMatQueue()); } GScan439Android::~GScan439Android() { if (m_usbthread.get() && m_usbthread->joinable()) { b_usbthread = false; m_usbthread->join(); m_usbthread.reset(); } imgs.ShutDown(); m_imagedata.ShutDown(); } void GScan439Android::open(int vid, int pid) { if (m_usb.get() && m_usb->is_connected()) return; auto lsusb = UsbScan_List::find_vid_pid(vid, pid); if (!lsusb.empty()) { m_usb = *lsusb.begin(); m_usb->open(); if (m_usb->is_open()) m_usb->set_usbhotplug_callback(usbhotplug_callback, this); } } void GScan439Android::regist_deviceevent_callback(deviceevent_callback callback, void* usrdata) { huagods = usrdata; dev_callback = callback; } void GScan439Android::DogEar_callback(std::function fun) { } int GScan439Android::aquire_bmpdata(std::vector& bmpdata) { FileTools::writelog(log_lv::log_DEBUG, " aquire_bmpdata start"); 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_usbthread.get() && m_usbthread->joinable()) { m_status = DEV_STOP; m_usbthread->join(); m_usbthread.reset(); } Stop_scan();//ֹͣɨ�� ResetScanner(); auto rollernew = Get_Roller_num(); set_scannum(abs(rollernew - roller_num)); FileTools::writelog(log_lv::log_DEBUG, " aquire_bmpdata timeout"); return HARDWARE_ERROR; } if (!is_scan()) { auto rollernew = Get_Roller_num(); set_scannum(abs(rollernew - roller_num)); FileTools::writelog(log_lv::log_DEBUG, " aquire_bmpdata stop"); if (m_status == DEV_WRONG) { return get_ErrorCode(); } return -1; } } else { if (m_pImages->valid()) { bmpdata = *(m_pImages->popBmpdata()); UpdateScanInfo(get_imgnReaded(), countNTransfered()); FileTools::writelog(log_lv::log_DEBUG, " aquire_bmpdata quit"); return 0; } DoEvents(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); } } } BOOL GScan439Android::IsConnected() { return m_usb.get() && m_usb->is_connected(); } std::string GScan439Android::GetFWVersion() { static std::string fw;// = "12312312"; if (m_usb.get() && m_usb->is_connected() && fw.empty()) { write_reg(m_usb, SR_GET_FWVERSION, 0); fw.resize(512); m_usb->read_bulk(&fw[0], 512); //read_data(&fw[0], fw.length(), 100); } return fw; } std::string GScan439Android::GetSerialNum() { static std::string sn;// = "12333123123123"; if (m_usb.get() && m_usb->is_connected() && sn.empty()) { write_reg(m_usb, SR_GET_SERIALNUM, 0); sn.resize(512); m_usb->read_bulk(&sn[0], 512); //read_data(&sn[0], sn.length(), 100); } return sn; } std::string GScan439Android::GetMacAdder() { return std::string(); } std::uint32_t GScan439Android::GetMotorFPGA() { return std::uint32_t(); } std::uint32_t GScan439Android::GetScanFPGA() { return std::uint32_t(); } bool GScan439Android::is_scan() { return m_status == DEV_ISRUNNING || (m_imagedata.Size() > 0); } BOOL GScan439Android::Get_Scanner_PaperOn() { return read_reg(m_usb, SR_GET_PAPERON); } int GScan439Android::Get_Roller_num() { return read_reg(m_usb, SR_GET_ROLLER_NUM); } void GScan439Android::config_params(GScanCap& param) { m_param = param; HGScanConfig cfg; cfg.value = 0; PaperStatus ps = { param.papertype,param.paperAlign }; cfg.g200params.paper = SupPaperTyps.count(ps) > 0 ? SupPaperTyps[ps] : 0; if (param.filter != 3 || param.enhance_color != 0 || param.hsvcorrect||param.hsvFilter!=0||param.fadeback!=0) cfg.g200params.color = 1;//color else { cfg.g200params.color = SupPixelTypes.count(param.pixtype) > 0 ? SupPixelTypes[param.pixtype] : 2; } cfg.g200params.dpi = param.resolution_dst >=300 ? 2 : 1;// SupResolutions.count(param.resolution_native) > 0 ? SupResolutions[param.resolution_native] : 1; param.resolution_native = param.resolution_dst >= 300 ? 300 : 200; cfg.g200params.double_feed_enbale = (unsigned int)param.hardwarecaps.en_doublefeed; //cfg.g200params.stable_enbale = 0; cfg.g200params.stable_enbale = (unsigned int)param.hardwarecaps.en_stapledetect; cfg.g200params.screw_detect_enable = (unsigned int)param.hardwarecaps.en_skrewdetect; cfg.g200params.screw_detect_level = (unsigned int)cfg.g200params.screw_detect_enable ? secrewMaps[param.hardwarecaps.skrewdetectlevel] : 0; cfg.g200params.enable_sizecheck = param.en_sizecheck == 1 ? 1 : 0; write_reg(m_usb, SR_CONFIG_SCAN_PARAM, cfg.value); m_pImages->setparam(param); } void GScan439Android::Scanner_StartScan(UINT16 count) { error_index = 0; roller_num = read_reg(m_usb, SR_GET_ROLLER_NUM); Set_ErrorCode(0); getimgnum = 0; aquirenum = 0; imagecount = 0; reset(); m_status = DEV_ISRUNNING; //if (read_reg(m_usb, SR_GET_SLEEP_STAUTUS) != 1) //{ // m_status = DEV_WRONG; // Set_ErrorCode(SLEEPING); // scanflag = false; // return; //} if (!Get_Scanner_PaperOn()) { m_status = DEV_WRONG; Set_ErrorCode(NO_FEED); scanflag = false; return; } int state = read_reg(m_usb, SR_GET_ANDROID_STATE); if (state != 0) { if (state == 1) Set_ErrorCode(OPEN_COVER); else if (state == 2) Set_ErrorCode(PAPER_JAM); else if (state == 3) Set_ErrorCode(NO_FEED); else Set_ErrorCode(HARDWARE_ERROR); scanflag = false; m_status = DEV_WRONG; return; } write_reg(m_usb, 0x1000, m_param.is_duplex ? m_param.scannum /2 : m_param.scannum); scanner_control(m_usb, SC_START); if (!m_usbthread.get()) { b_usbthread = true; m_usbthread.reset(new thread(&GScan439Android::usbmainloop, this)); } m_pImages->setscanflags(true); m_pImages->run(); } void GScan439Android::Stop_scan() { scanner_control(m_usb, SC_STOP); if ((m_status == DEV_WRONG) || (m_status == DEV_STOP)) return; m_status = DEV_STOP; } int GScan439Android::notifyscan() { return 1; } void GScan439Android::ResetScanner() { } bool GScan439Android::Get_IsImageQueueEmpty() { return m_pImages->empty() && m_status == DEV_STOP; } void GScan439Android::reset() { m_status = DEV_STOP; m_pImages->clear(); //scanner_control(m_usb, SC_INIT); } void GScan439Android::clear_hwerror() { //scanner_control(m_usb, SC_INIT); } UINT32 GScan439Android::get_ErrorCode() { return Error_Code; } void GScan439Android::Set_ErrorCode(UINT32 value) { Error_Code = value; } int GScan439Android::get_scanned_num() { return 0; } void GScan439Android::set_sleep_time(int mode) { } bool GScan439Android::set_scannercode(std::string str) { return false; } std::string GScan439Android::get_scannercode() { return std::string(); } void GScan439Android::usbhotplug_callback(bool isconnect, void* userdata) { GScan439Android* This = (GScan439Android*)userdata; This->usbhotplug(isconnect); } void GScan439Android::usbhotplug(bool isleft) { FileTools::writelog(log_ERROR, "enable usb callback "); if (isleft) { m_status = DEV_WRONG; Error_Code = USB_DISCONNECTED; m_pImages->setscanflags(false); scanflag = false; if (m_usb.get()) m_usb.reset(); if (huagods) dev_callback(USB_DISCONNECTED, huagods); } } int GScan439Android::read_data(void* data, int length, int timeout) { if (!m_usb.get() && !m_usb->is_connected()) { FileTools::writelog(log_INFO, "if (!m_usb.get() && !m_usb->is_connected())"); return 0; } timeout = std::max(1000, timeout); int readed = 0; int reading = 0; const int buffer_size = 512 * 1024; StopWatch sw; FileTools::writelog(log_INFO, "read_data timeout =" + to_string(timeout)); while (readed < length) { if (sw.elapsed_ms() < timeout && m_usb.get()) { reading = std::max(0, std::min(length - readed, buffer_size)); reading = m_usb->read_bulk((unsigned char*)data + readed, reading); if (reading > 0) { readed += reading; sw.reset(); } } else { FileTools::writelog(log_INFO, "read usb image data time out ,time = " + std::to_string(sw.elapsed_ms())); break; } } return readed; } void GScan439Android::usbmainloop() { unsigned char buff[32]; while (b_usbthread) { if (!m_usb.get() || !m_usb->is_connected()) { this_thread::sleep_for(chrono::milliseconds(20)); continue; } memset(buff, 0, sizeof(buff)); auto length = m_usb->read_int(buff, sizeof(buff)); if (((length) == sizeof(buff)))//|| im_dev_count() { HGEIntInfo info = *(HGEIntInfo*)&buff; if (codeconvter(info) > 0 && get_ErrorCode() == 0) { Set_ErrorCode(codeconvter(info)); } if (codeconvter(info) == -1) { m_readimgpool.enqueue([this] { StopWatch stoptime; while (stoptime.elapsed_s() < 3) { if (read_reg(m_usb, SR_IM_COUNT) > 0) { readimg(); stoptime.reset(); } this_thread::sleep_for(chrono::milliseconds(200)); } m_status = get_ErrorCode() == 0 ? DEV_STOP : DEV_WRONG; m_pImages->setscanflags(false); }); } switch (info.From) { case IMG: m_readimgpool.enqueue([this] { if (read_reg(m_usb, SR_IM_COUNT) > 0) readimg(); }); break; case MtBoard: FileTools::writelog(log_ERROR, "Got MotorBoard error code = " + to_string(info.Code)); break; case FPGA: FileTools::writelog(log_ERROR, "Got FPGA Error code = " + to_string(info.Code)); break; case V4L2: FileTools::writelog(log_ERROR, "Got V4L2 Error code = " + to_string(info.Code)); scanner_control(m_usb, SC_STOP); break; case STOPSCAN: FileTools::writelog(log_INFO, "StopScan"); break; default: FileTools::writelog(log_ERROR, "Got Unkown error code ! From =" + to_string(info.From) + " Code = " + to_string(info.Code)); break; } //this_thread::sleep_for(chrono::microseconds(10)); } } } void GScan439Android::readimg() { if (read_reg(m_usb, SR_IM_TXING)) { FileTools::writelog(log_ERROR, "Read image TXING"); return; } if (read_reg(m_usb, SR_IM_COUNT) > 0 && getStatus()) { unsigned int len = read_reg(m_usb, SR_IM_FRONT_SIZE); if (len > 0) { write_reg(m_usb, SR_IM_TX, 1); im_data->resize(len); static int indeximg = 0; auto nreaded = tranxferimg(len, im_data); if (nreaded == len) { m_pImages->pushMat(std::shared_ptr(new G400Decode(im_data))); this_thread::sleep_for(chrono::milliseconds(10)); write_reg(m_usb, SR_IM_POP, 1); FileTools::writelog(log_ERROR, "Enqueue image " + to_string(++indeximg) + "size " + to_string(nreaded)); UpdateScanInfo(countNReaded(), get_imgTransfered()); } else { FileTools::writelog(log_ERROR, "error :read image data len error"); } } else FileTools::writelog(log_ERROR, "error :Get front image data len ZERO" ); } else FileTools::writelog(log_ERROR, "image queue empty or not scanning" ); } int GScan439Android::tranxferimg(unsigned int datalen, std::shared_ptr> data) { unsigned int timeout = 3000; unsigned int readed = 0; unsigned int reading = 0; const int buffer_size = 512 * 1024; StopWatch sw; while (readed < datalen) { if (sw.elapsed_ms() < timeout && m_usb.get()) { reading = m_max(0, m_min(datalen - readed, buffer_size)); reading = m_usb->read_bulk((unsigned char*)data->data() + readed, reading); if (reading > 0) { readed += reading; sw.reset(); } else FileTools::writelog(log_ERROR, "Read Image size zero"); } else { FileTools::writelog(log_ERROR, "Read Image timeout" ); break; } } return readed; } int GScan439Android::codeconvter(HGEIntInfo code) { if (code.From == HGType::FPGA) { switch (code.Code) { default: break; } } if (code.From == HGType::MtBoard) { switch (code.Code) { case 0x00002: return NO_FEED; case 0x00004: return OPEN_COVER; case 0x00008: return FEED_IN_ERROR; case 0x00010: return PAPER_JAM; case 0x00020: return DETECT_DOUBLE_FEED; case 0x00040: return DETECT_STAPLE; case 0x00080: return PAPER_SKEW; case 0x10000: return AQUIRE_IMAGE_TIMEOUT; case 0x20000: return SIZE_ERROR; case 0x40000: return PAPER_HOLE; case 0x80000: return MLTOP_TIMEOUT; default: break; } } if (code.From == HGType::V4L2) { switch (code.Code) { case 0: return V4L2_AQULRE_ERROR; case 1: return V4L2_IMAGE_EMPTY; default: break; } } if (code.From == HGType::STOPSCAN) { switch (code.Code) { case 0: return -1; case 1: if (m_status == DEV_ISRUNNING) m_status = DEV_STOP; return 0; default: break; } } return 0; } bool GScan439Android::getStatus() { return 1; int val = read_reg(m_usb, SR_STATUS) & 0x3; bool ret = (val > 0) && (val < 4); return ret; }