code_device/hgdriver/hgdev/scanner/scanner_handler.cpp

851 lines
20 KiB
C++

#include "scanner_handler.h"
#include "async_usb_host.h"
#include <huagao/hgscanner_error.h>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cmd_result
MUTEX cmd_result::lock_;
uint32_t cmd_result::pack_id_ = 1;
cmd_result::cmd_result(std::function<int(cmd_result*)> call,
std::function<int(cmd_result*)> clean,
std::function<dyn_mem_ptr(dyn_mem_ptr, uint32_t*, packet_data_base_ptr*, cmd_result*)> 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<data_holder_ptr(LPPACKIMAGE, uint64_t)>())
, status_notify_(std::function<void(uint32_t)>())
{
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<data_holder_ptr>(new empty_holer(pimg->info_size + pimg->data_size));
}
*used = off;
*more = dynamic_cast<packet_data_base_ptr>(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<int(cmd_result*)> call,
std::function<int(cmd_result*)> clean,
std::function<dyn_mem_ptr(dyn_mem_ptr, uint32_t*, packet_data_base_ptr*, cmd_result*)> 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(&param, 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, &param);
}
int scanner_handler::status_get(void)
{
return status_;
}
void scanner_handler::set_image_receiver(std::function<data_holder_ptr(LPPACKIMAGE, uint64_t)> img)
{
img_receiver_ = img;
}
void scanner_handler::set_status_notifyer(std::function<void(uint32_t)> 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<packet_data_base_ptr>(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<packet_data_base_ptr>(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_;
}