#include "scanner_handler.h" #include "async_usb_host.h" #include ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cmd_result MUTEX cmd_result::lock_; uint32_t cmd_result::pack_id_ = 1; cmd_result::cmd_result(std::function call, std::function clean, std::function roger, void* param, uint32_t id) : wait_(new platform_event("wait_reply")), id_(id == 0 ? cmd_result::gen_pack_id() : id) , call_(call), clean_(clean), roger_(roger), param_(param), err_(0), to_(1000), over_(false) { wait_->enable_log(false); } cmd_result::~cmd_result() { wait_->release(); } uint32_t cmd_result::gen_pack_id(void) { SIMPLE_LOCK(cmd_result::lock_); return cmd_result::pack_id_++; } uint32_t cmd_result::get_id(void) { return id_; } uint32_t cmd_result::set_timeout(uint32_t timeout) { uint32_t prev = to_; to_ = timeout; return prev; } void* cmd_result::get_param(void) { return param_; } void* cmd_result::set_param(void* param) { void* r = param_; param_ = param; return r; } bool cmd_result::wait(void) { return wait_->wait(to_); } void cmd_result::trigger(void) { over_ = true; wait_->trigger(); } bool cmd_result::is_over(void) { return over_; } int cmd_result::get_error_code(void) { return err_; } void cmd_result::set_error_code(int err) { err_ = err; } int cmd_result::call(void) { int ret = call_(this); if (ret == 0) { if (wait()) { ret = err_; } else { ret = ETIMEDOUT; } } return ret; } dyn_mem_ptr cmd_result::roger(dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* more) { SIMPLE_LOCK(locker_); dyn_mem_ptr ret = nullptr; LPPACK_BASE pack = (LPPACK_BASE)data->ptr(); err_ = pack->data; ret = roger_(data, used, more, this); // trigger(); return ret; } int cmd_result::clean(void) { SIMPLE_LOCK(locker_); over_ = true; return clean_(this); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // though all command transferred by BULK are asychronous in transffer level, // make BLOCKED in this layer #define WAIT_COMMAND(call, clean, roger, param) \ cmd_result * r = gen_reply(call, clean, roger, param); \ int ret = r->call(); \ r->clean(); \ r->release(); \ return ret; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // scanner_handler scanner_handler::scanner_handler(void) : usb_(nullptr), status_(SCANNER_ERR_NOT_OPEN) , img_receiver_(std::function()) , status_notify_(std::function()) { auto on_reply = [&](dyn_mem_ptr reply, uint32_t* used, packet_data_base_ptr* more) ->dyn_mem_ptr { LPPACK_BASE pack = (LPPACK_BASE)reply->ptr(); cmd_result* cmd = take_reply(pack->pack_id); dyn_mem_ptr ret = nullptr; *used = reply->get_rest(); *more = nullptr; if (cmd) { ret = cmd->roger(reply, used, more); if (cmd->is_over()) cmd->release(); else // if (status_ != SCANNER_STATUS_RESET_BULK) { SIMPLE_LOCK(lock_reply_); reply_.push_back(cmd); } } //else if (status_ == SCANNER_STATUS_RESET_BULK) //{ // if (pack->size == sizeof(PACK_BASE) && // pack->cmd == PACK_CMD_SYNC_ROGER && // pack->payload_len == 0) // status_ = SCANNER_STATUS_READY; //} else if (pack->size == sizeof(PACK_BASE)) { if (pack->cmd == PACK_CMD_SCAN_IMG_ROGER) { uint32_t off = sizeof(PACK_BASE) + sizeof(PACKIMAGE); if (*used < off) { *used = 0; } else { LPPACKIMAGE pimg = (LPPACKIMAGE)pack->payload; data_holder_ptr receiver = nullptr; if(img_receiver_) receiver = img_receiver_(pimg, pimg->info_size + pimg->data_size); if (!receiver) { // usb_->cancel_command(pack->cmd, pack->pack_id); receiver = dynamic_cast(new empty_holer(pimg->info_size + pimg->data_size)); } *used = off; *more = dynamic_cast(receiver); } } else if (pack->cmd == PACK_CMD_SCAN_PAPER_ROGER) { if (img_receiver_) { data_holder_ptr receiver = img_receiver_(IMG_RECEIVER_PAPER_CNT, pack->data); if (receiver) receiver->release(); } *used = sizeof(PACK_BASE); } else if (pack->cmd == PACK_CMD_SCAN_FINISHED_ROGER) { if (img_receiver_) { data_holder_ptr receiver = img_receiver_(IMG_RECEIVER_FINISHED, pack->data); if (receiver) receiver->release(); } *used = sizeof(PACK_BASE); status_ = pack->data; } else if (pack->cmd == PACK_CMD_STATUS_ROGER) { *used = sizeof(PACK_BASE); status_ = pack->data; if (status_notify_) status_notify_(status_); } else if (pack->cmd == PACK_CMD_FILE_WRITE_REQ_ROGER) { *used = sizeof(PACK_BASE); utils::to_log(LOG_LEVEL_DEBUG, "Send file finished with error: %s\r\n", scanner_error_name(pack->data).c_str()); } else { // unknown packet ... uint8_t* ptr = reply->ptr(); utils::to_log(LOG_LEVEL_DEBUG, "Unhandled packet(%d): %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X ...\r\n", reply->get_rest() , ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7] , ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]); } } else { // unknown packet ... uint8_t* ptr = reply->ptr(); utils::to_log(LOG_LEVEL_DEBUG, "Unknown packet received(%d): %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X ...\r\n", reply->get_rest() , ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7] , ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]); } return ret; }; usb_ = new async_usb_host(on_reply); } scanner_handler::~scanner_handler() { usb_->stop(); for (auto& v : reply_) v->release(); usb_->release(); } cmd_result* scanner_handler::gen_reply(std::function call, std::function clean, std::function roger, void* param, uint32_t id) { cmd_result* reply = new cmd_result(call, clean, roger, param, id); { SIMPLE_LOCK(lock_reply_); reply_.push_back(reply); } reply->add_ref(); // for reply_ queue storing return reply; } cmd_result* scanner_handler::take_reply(uint32_t id) { cmd_result* reply = nullptr; SIMPLE_LOCK(lock_reply_); for (size_t i = 0; i < reply_.size(); ++i) { if (reply_[i]->get_id() == id) { reply = reply_[i]; reply_.erase(reply_.begin() + i); break; } } return reply; } int scanner_handler::wait_result(cmd_result* reply) { if (reply->wait()) { return reply->get_error_code(); } else { cmd_result* q = take_reply(reply->get_id()); if (q) { q->release(); } else { // take out by reply just now ? try again ... reply->set_timeout(500); if (reply->wait()) return reply->get_error_code(); } return ETIMEDOUT; } } int scanner_handler::get_peer_config(LPPEERCFG cfg) { if (cfg) { cfg->io_size = usb_->get_io_buffer_size(); cfg->ver = usb_->get_protocol_version(); } return 0; } int scanner_handler::get_scanner_status(LPEP0REPLYSTATUS status, bool en_dev_log) { if (!is_scanner_available()) return ENODEV; return usb_->get_peer_status(status, en_dev_log); } int scanner_handler::restart_peer_bulk(uint32_t timeout) { if (!is_scanner_available()) return ENODEV; return usb_->reset_peer(timeout); } int scanner_handler::option_get_all(std::string& json_opts) { auto call = [&](cmd_result* cmd) -> int { return usb_->get_settings(cmd->get_id()); }; auto clean = [&](cmd_result* cmd) -> int { return 0; }; auto roger = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* more, cmd_result* cmd) ->dyn_mem_ptr { std::string *ret = (std::string*)cmd->get_param(); LPPACK_BASE pack = (LPPACK_BASE)data->ptr(); if (data->get_rest() < sizeof(PACK_BASE) + pack->payload_len) *used = 0; else { if(!cmd->is_over()) *(std::string*)cmd->get_param() = std::string(pack->payload, pack->payload_len); *used = sizeof(*pack) + pack->payload_len; cmd->trigger(); } *more = nullptr; return nullptr; }; json_opts = ""; if (!is_scanner_available()) return ENODEV; WAIT_COMMAND(call, clean, roger, &json_opts); } int scanner_handler::option_value_get(const char* name, void* buf, uint32_t* size) { auto call = [&](cmd_result* cmd) -> int { return usb_->get_setting_val(cmd->get_id(), name); }; auto clean = [&](cmd_result* cmd) -> int { return 0; }; auto roger = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* more, cmd_result* cmd) ->dyn_mem_ptr { LPPACK_BASE pack = (LPPACK_BASE)data->ptr(); LPCFGVAL cfg = (LPCFGVAL)pack->payload; if (data->get_rest() < sizeof(PACK_BASE) + pack->payload_len) *used = 0; else { if (!cmd->is_over()) memcpy(cmd->get_param(), cfg->data + cfg->val_off, cfg->val_size); *size = cfg->val_size; *used = sizeof(*pack) + pack->payload_len; cmd->trigger(); } *more = nullptr; return nullptr; }; if (!is_scanner_available()) return ENODEV; WAIT_COMMAND(call, clean, roger, buf); } int scanner_handler::option_value_set(const char* name, uint32_t type, void* buf, uint32_t size, uint32_t val_size, uint16_t* after) { struct { void* buf; uint16_t* after; }param; auto call = [&](cmd_result* cmd) -> int { memcpy(¶m, cmd->get_param(), sizeof(param)); return usb_->set_setting(cmd->get_id(), name, type, param.buf, val_size, size); }; auto clean = [&](cmd_result* cmd) -> int { return 0; }; auto roger = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* more, cmd_result* cmd) ->dyn_mem_ptr { struct { void* buf; uint16_t* after; }*result = nullptr; LPPACK_BASE pack = (LPPACK_BASE)data->ptr(); LPCFGVAL cfg = (LPCFGVAL)pack->payload; if (data->get_rest() < sizeof(PACK_BASE) + pack->payload_len) *used = 0; else { if (!cmd->is_over()) { *(void**)&result = cmd->get_param(); memcpy(result->buf, cfg->data + cfg->val_off, cfg->val_size); *result->after = cfg->after_do; } *used = sizeof(*pack) + pack->payload_len; cmd->trigger(); } *more = nullptr; return nullptr; }; if (!is_scanner_available()) return ENODEV; param.buf = buf; param.after = after; WAIT_COMMAND(call, clean, roger, ¶m); } int scanner_handler::status_get(void) { return status_; } void scanner_handler::set_image_receiver(std::function img) { img_receiver_ = img; } void scanner_handler::set_status_notifyer(std::function stntf) { status_notify_ = stntf; } int scanner_handler::scan_start(std::string* devcfg) { auto call = [&](cmd_result* cmd) -> int { cmd->set_timeout(20 * 1000); return usb_->scan_start(cmd->get_id()); }; auto clean = [&](cmd_result* cmd) -> int { return 0; }; auto roger = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* more, cmd_result* cmd) ->dyn_mem_ptr { LPPACK_BASE pack = (LPPACK_BASE)data->ptr(); *used = sizeof(PACK_BASE) + pack->payload_len; *more = nullptr; status_ = pack->data == 0 ? SCANNER_ERR_DEVICE_BUSY : pack->data; if (devcfg && pack->payload_len) *devcfg = std::move(std::string(pack->payload, pack->payload_len)); cmd->trigger(); return nullptr; }; if (status_ == SCANNER_ERR_DEVICE_BUSY) return SCANNER_ERR_DEVICE_BUSY; if (!is_scanner_available()) return ENODEV; WAIT_COMMAND(call, clean, roger, nullptr); } int scanner_handler::scan_stop(void) { auto call = [&](cmd_result* cmd) -> int { return usb_->scan_stop(cmd->get_id()); }; auto clean = [&](cmd_result* cmd) -> int { return 0; }; auto roger = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* more, cmd_result* cmd) ->dyn_mem_ptr { *used = sizeof(PACK_BASE); *more = nullptr; cmd->trigger(); return nullptr; }; if (!is_scanner_available()) return ENODEV; WAIT_COMMAND(call, clean, roger, nullptr); } int scanner_handler::file_transfer(const char* local_path, const char* remote_path, bool to_device, PROGRESS_NOTIFYER progress, uint64_t local_off, uint64_t remote_off) { if (!is_scanner_available()) return ENODEV; if (to_device) { uint64_t size = 0; file_reader *reader = new file_reader(); int err = reader->open(local_path, true, local_off); utils::to_log(LOG_LEVEL_DEBUG, "Send '%s' to '%s' ...\r\n", local_path, remote_path); if (err) { utils::to_log(LOG_LEVEL_FATAL, "Send file failed in open local file '%s': %d\n", local_path, err); reader->release(); return err; } size = reader->get_rest(); reader->set_progress_notify(progress); auto call = [&](cmd_result* cmd) -> int { cmd->set_timeout(3000); return usb_->file_send(cmd->get_id(), remote_path, size, remote_off); }; auto clean = [&](cmd_result* cmd) -> int { file_reader* reader = (file_reader*)cmd->get_param(); if (reader) reader->release(); return 0; }; auto roger = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* more, cmd_result* cmd) ->dyn_mem_ptr { LPPACK_BASE pack = (LPPACK_BASE)data->ptr(); dyn_mem_ptr ret = nullptr; *used = sizeof(PACK_BASE); *more = nullptr; if (pack->data == 0) { if (cmd->is_over()) { reset_message_que(); } else { file_reader_ptr freader = (file_reader_ptr)cmd->set_param(nullptr); if (err) { // cancel tx-file ... cmd->set_error_code(err); freader->release(); reset_message_que(); utils::to_log(LOG_LEVEL_DEBUG, "Send file - Attach to source file failed: %d\r\n", err); } else { *more = dynamic_cast(freader); status_ = SCANNER_ERR_DEVICE_BUSY; } } } else utils::to_log(LOG_LEVEL_DEBUG, "Send file - Roger of send file result: %d\r\n", pack->data); cmd->trigger(); return ret; }; WAIT_COMMAND(call, clean, roger, reader); } else { auto call = [&](cmd_result* cmd) -> int { cmd->set_timeout(2000); return usb_->file_get(cmd->get_id(), remote_path, remote_off); }; auto clean = [&](cmd_result* cmd) -> int { return 0; }; auto roger = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* more, cmd_result* cmd) ->dyn_mem_ptr { LPPACK_BASE pack = (LPPACK_BASE)data->ptr(); LPTXFILE pfi = (LPTXFILE)pack->payload; dyn_mem_ptr reply = dyn_mem::memory(sizeof(PACK_BASE)); *used = sizeof(PACK_BASE) + pack->payload_len; *more = nullptr; BASE_PACKET_REPLY((*(LPPACK_BASE)reply->ptr()), PACK_CMD_FILE_READ_REQ_ROGER, pack->pack_id, -1); reply->set_len(sizeof(PACK_BASE)); if (pack->data == 0) { if (cmd->is_over()) { utils::to_log(LOG_LEVEL_DEBUG, "Receive file - timeout, user cancelled\r\n"); reset_message_que(); } else { file_saver* fsaver = new file_saver(); int err = fsaver->open(local_path, pfi->size, true, local_off); if (err) { // cancel tx-file ... cmd->set_error_code(err); (*(LPPACK_BASE)reply->ptr()).data = err; fsaver->release(); reset_message_que(); utils::to_log(LOG_LEVEL_DEBUG, "Receive file - open local file failed: %d\r\n", err); } else { fsaver->set_progress_notify(progress); *more = dynamic_cast(fsaver); (*(LPPACK_BASE)reply->ptr()).data = 0; status_ = SCANNER_ERR_DEVICE_BUSY; } } } else { utils::to_log(LOG_LEVEL_DEBUG, "Receive file - Roger result: %d\r\n", pack->data); reply->release(); reply = nullptr; } cmd->trigger(); return reply; }; utils::to_log(LOG_LEVEL_DEBUG, "Receive '%s' to '%s' ...\r\n", remote_path, local_path); WAIT_COMMAND(call, clean, roger, (void*)local_path); } } int scanner_handler::file_move(const char* rfrom, const char* rto) { auto call = [&](cmd_result* cmd) -> int { return usb_->file_move(cmd->get_id(), rfrom, rto); }; auto clean = [&](cmd_result* cmd) -> int { return 0; }; auto roger = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* more, cmd_result* cmd) ->dyn_mem_ptr { *used = sizeof(PACK_BASE); *more = nullptr; cmd->trigger(); return nullptr; }; if (!is_scanner_available()) return ENODEV; WAIT_COMMAND(call, clean, roger, nullptr); } int scanner_handler::file_delete(const char* remote) { auto call = [&](cmd_result* cmd) -> int { return usb_->file_remove(cmd->get_id(), remote); }; auto clean = [&](cmd_result* cmd) -> int { return 0; }; auto roger = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* more, cmd_result* cmd) ->dyn_mem_ptr { *used = sizeof(PACK_BASE); *more = nullptr; cmd->trigger(); return nullptr; }; if (!is_scanner_available()) return ENODEV; WAIT_COMMAND(call, clean, roger, nullptr); } int scanner_handler::program_start(const char* remote_pe, const char* param, uint64_t* pid) { auto call = [&](cmd_result* cmd) -> int { return usb_->program_start(cmd->get_id(), remote_pe, param); }; auto clean = [&](cmd_result* cmd) -> int { return 0; }; auto roger = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* more, cmd_result* cmd) ->dyn_mem_ptr { LPPACK_BASE pack = (LPPACK_BASE)data->ptr(); if (pack->data == 0 && !cmd->is_over()) *(uint64_t*)cmd->get_param() = *(uint64_t*)pack->payload; *used = sizeof(PACK_BASE) + pack->payload_len; *more = nullptr; cmd->trigger(); return nullptr; }; if (!is_scanner_available()) return ENODEV; WAIT_COMMAND(call, clean, roger, pid); } int scanner_handler::program_stop(uint64_t pid) { auto call = [&](cmd_result* cmd) -> int { return usb_->program_stop(cmd->get_id(), pid); }; auto clean = [&](cmd_result* cmd) -> int { return 0; }; auto roger = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* more, cmd_result* cmd) ->dyn_mem_ptr { *used = sizeof(PACK_BASE); *more = nullptr; cmd->trigger(); return nullptr; }; if (!is_scanner_available()) return ENODEV; WAIT_COMMAND(call, clean, roger, nullptr); } int scanner_handler::open_usb_scanner(libusb_device* dev) { int ret = close(); if (ret == 0) { ret = usb_->start(dev); if(ret == 0) status_ = SCANNER_ERR_OK; //usb_->set_gadget_encrypting_method(ENCRYPT_CMD_XOR_PID); } return ret; } int scanner_handler::close(void) { int ret = usb_->stop(); { SIMPLE_LOCK(lock_reply_); for (auto& v : reply_) v->release(); reply_.clear(); } if(ret == 0) status_ = SCANNER_ERR_NOT_OPEN; return ret; } int scanner_handler::reset_message_que(void) { return 0; //int err = usb_->cancel_write(); // //status_ = SCANNER_STATUS_RESET_BULK; //utils::to_log(LOG_LEVEL_DEBUG, "reset_message_que - send reset command ...\r\n"); //err = usb_->reset_peer(); //utils::to_log(LOG_LEVEL_DEBUG, "reset_message_que - send reset command = %d\r\n", err); //if (err == 0) //{ // EP0REPLYSTATUS s; // dyn_mem_ptr raw(dyn_mem::memory(sizeof(PACK_BASE))); // LPPACK_BASE pack = (LPPACK_BASE)raw->ptr(); // // BASE_PACKET_REPLY(*pack, PACK_CMD_SYNC, 0, 0); // raw->set_len(sizeof(PACK_BASE)); // utils::to_log(LOG_LEVEL_DEBUG, "reset_message_que - wait 100ms ...\r\n"); // std::this_thread::sleep_for(std::chrono::milliseconds(100)); // utils::to_log(LOG_LEVEL_DEBUG, "reset_message_que - send SYNC packet ...\r\n"); // usb_->send_bulk_raw_data(raw); // raw->release(); // // std::this_thread::sleep_for(std::chrono::milliseconds(50)); // if (status_ == SCANNER_STATUS_RESET_BULK) // err = EFAULT; // utils::to_log(LOG_LEVEL_DEBUG, "reset_message_que - final status = %d\r\n", status_); //} // //return err; } bool scanner_handler::is_scanner_available(void) { //return status_ == SCANNER_ERR_OK || // status_ == SCANNER_ERR_DEVICE_BUSY || // status_ == SCANNER_ERR_DEVICE_NO_PAPER; return SCANNER_ERR_NOT_OPEN != status_ && SCANNER_ERR_DEVICE_NOT_FOUND != status_; }