503 lines
13 KiB
C++
503 lines
13 KiB
C++
#include "async_scanner.h"
|
|
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <errno.h>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
#include <usb_io.h>
|
|
#include <sane_opt_json/device_opt.h>
|
|
#include <sane/sane_ex.h>
|
|
#include <huagao/hgscanner_error.h>
|
|
#include "scanner_const_opts.h"
|
|
#include <hardware.h>
|
|
#include <base/user.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
async_scanner::async_scanner() : usb_(nullptr), cfg_mgr_(nullptr), scan_id_(0)
|
|
{
|
|
utils::init_log(LOG_TYPE_FILE);
|
|
utils::to_log(LOG_LEVEL_DEBUG, "System info: page-size = %u, mapping-page-size = %u, disk-cluster-size = %u.\n"
|
|
, global_info::page_size, global_info::page_map_size, global_info::cluster_size);
|
|
init();
|
|
|
|
auto bulk_handle = [&](dyn_mem_ptr data, uint32_t* used, packet_data_base_ptr* required) -> dyn_mem_ptr
|
|
{
|
|
LPPACK_BASE pack = (LPPACK_BASE)data->ptr();
|
|
|
|
if(used)
|
|
*used = data->get_rest();
|
|
|
|
return handle_bulk_cmd(pack, used, required);
|
|
};
|
|
auto on_connect = [this](bool connected) -> void
|
|
{
|
|
utils::to_log(LOG_LEVEL_ALL, "USB %s\n", connected ? "connected" : "dis-connected");
|
|
connected_ = connected;
|
|
if(!connected)
|
|
cis_->stop_scan();
|
|
};
|
|
|
|
auto user = [&](int priv) -> bool
|
|
{
|
|
return user_->has_privilege(priv);
|
|
};
|
|
auto on_log = [&](const char* msg) -> void
|
|
{
|
|
utils::log_info(msg, LOG_LEVEL_DEBUG);
|
|
};
|
|
|
|
cfg_mgr_ = new device_option(true, user, on_log);
|
|
utils::to_log(LOG_LEVEL_DEBUG, "OPT - initializing ...\n");
|
|
const_opts_ = new scanner_const_opts();
|
|
user_ = new user_priv();
|
|
|
|
cfg_mgr_->add(const_opts_);
|
|
cis_->set_value(SANE_FULL_NAME(DEVICE_MODEL), &cfg_mgr_->get_option_value(SANE_FULL_NAME(DEVICE_MODEL), SANE_ACTION_GET_VALUE)[0]);
|
|
cfg_mgr_->add(cis_);
|
|
cfg_mgr_->add(user_);
|
|
utils::to_log(LOG_LEVEL_DEBUG, "OPT - initialized %u options.\n", cfg_mgr_->count());
|
|
|
|
usb_ = new async_usb_gadget(bulk_handle, on_connect);
|
|
last_err_ = usb_->last_error();
|
|
}
|
|
|
|
async_scanner::~async_scanner()
|
|
{
|
|
if(cis_)
|
|
{
|
|
cis_->stop_scan();
|
|
cis_->close();
|
|
cis_->release();
|
|
cis_ = nullptr;
|
|
}
|
|
if(usb_)
|
|
{
|
|
usb_->stop();
|
|
usb_->release();
|
|
}
|
|
if(cfg_mgr_)
|
|
{
|
|
cfg_mgr_->clear();
|
|
cfg_mgr_->release();
|
|
cfg_mgr_ = nullptr;
|
|
}
|
|
for(auto& v: send_files_)
|
|
v->release();
|
|
send_files_.clear();
|
|
const_opts_->release();
|
|
user_->release();
|
|
|
|
utils::uninit();
|
|
}
|
|
|
|
dyn_mem_ptr async_scanner::handle_bulk_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
|
{
|
|
dyn_mem_ptr reply = nullptr;
|
|
LPPACK_BASE pk = nullptr;
|
|
size_t base_head_size = sizeof(PACK_BASE);
|
|
|
|
if(pack->size != base_head_size)
|
|
{
|
|
if(used)
|
|
{
|
|
utils::log_mem_info("Invalid packet", (uint8_t*)pack, *used);
|
|
}
|
|
reply = dyn_mem::memory(base_head_size);
|
|
LPPACK_BASE p = (LPPACK_BASE)reply->ptr();
|
|
BASE_PACKET_REPLY(*p, PACK_CMD_INVALID, pack->pack_id, pack->cmd);
|
|
reply->set_len(base_head_size);
|
|
|
|
return reply;
|
|
}
|
|
|
|
switch(pack->cmd)
|
|
{
|
|
case PACK_CMD_SYNC:
|
|
reply = handle_simple_roger(pack, used, required);
|
|
break;
|
|
case PACK_CMD_SETTING_GET_CUR:
|
|
reply = handle_get_opt_value(pack, used, required);
|
|
break;
|
|
case PACK_CMD_SETTING_GET:
|
|
reply = handle_get_opt_all(pack, used, required);
|
|
break;
|
|
case PACK_CMD_SETTING_SET:
|
|
reply = handle_set_opt(pack, used, required);
|
|
break;
|
|
case PACK_CMD_FILE_WRITE_REQ:
|
|
reply = handle_file_receive(pack, used, required);
|
|
break;
|
|
case PACK_CMD_FILE_READ_REQ:
|
|
reply = handle_file_send(pack, used, required);
|
|
break;
|
|
case PACK_CMD_FILE_READ_REQ_ROGER:
|
|
reply = handle_file_send_roger(pack, used, required);
|
|
break;
|
|
case PACK_CMD_SCAN_START:
|
|
reply = handle_scan_start(pack, used, required);
|
|
break;
|
|
case PACK_CMD_SCAN_STOP:
|
|
reply = handle_scan_stop(pack, used, required);
|
|
break;
|
|
default:
|
|
if(used)
|
|
{
|
|
utils::log_mem_info("Unsupported command packet", (uint8_t*)pack, *used);
|
|
}
|
|
reply = dyn_mem::memory(base_head_size);
|
|
LPPACK_BASE p = (LPPACK_BASE)reply->ptr();
|
|
BASE_PACKET_REPLY(*p, pack->cmd + 1, pack->pack_id, EINVAL);
|
|
reply->set_len(base_head_size);
|
|
break;
|
|
}
|
|
|
|
return reply;
|
|
}
|
|
void async_scanner::init(void)
|
|
{
|
|
cis_ = new scanner_hw();
|
|
}
|
|
bool async_scanner::on_energy_conservation(bool normal)
|
|
{
|
|
bool enable = true;
|
|
|
|
if(normal)
|
|
{
|
|
|
|
}
|
|
else
|
|
{
|
|
if(cis_->is_scanning())
|
|
enable = false;
|
|
}
|
|
|
|
return enable;
|
|
}
|
|
|
|
dyn_mem_ptr async_scanner::handle_simple_roger(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
|
{
|
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
|
dyn_mem_ptr reply = dyn_mem::memory(base_head_size);
|
|
LPPACK_BASE pk = (LPPACK_BASE)reply->ptr();
|
|
|
|
*used = base_head_size;
|
|
BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, 0);
|
|
reply->set_len(base_head_size);
|
|
|
|
return reply;
|
|
}
|
|
dyn_mem_ptr async_scanner::handle_get_opt_value(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
|
{
|
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
|
dyn_mem_ptr reply = nullptr;
|
|
LPPACK_BASE pk = nullptr;
|
|
|
|
if(*used < base_head_size + pack->payload_len)
|
|
{
|
|
*used = 0;
|
|
}
|
|
else
|
|
{
|
|
std::string val(cfg_mgr_->get_option_value(pack->payload, SANE_ACTION_GET_VALUE));
|
|
uint32_t err = val.empty() ? SCANNER_ERR_NO_DATA : SCANNER_ERR_OK;
|
|
LPCFGVAL cfg = nullptr;
|
|
|
|
reply = dyn_mem::memory(base_head_size + sizeof(CFGVAL) + strlen(pack->payload) + 1 + val.length() + 1);
|
|
pk = (LPPACK_BASE)reply->ptr();
|
|
BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, err);
|
|
cfg = (LPCFGVAL)pk->payload;
|
|
cfg->val_size = val.length();
|
|
cfg->val_off = 0;
|
|
cfg->name_off = val.length() + 1;
|
|
pk->payload_len = sizeof(CFGVAL) + strlen(pack->payload) + 1 + val.length() + 1;
|
|
memcpy(cfg->data, val.c_str(), val.length());
|
|
strcpy(cfg->data + cfg->name_off, pack->payload);
|
|
reply->set_len(base_head_size + pk->payload_len);
|
|
*used = base_head_size + pack->payload_len;
|
|
}
|
|
|
|
return reply;
|
|
}
|
|
dyn_mem_ptr async_scanner::handle_get_opt_all(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
|
{
|
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
|
dyn_mem_ptr reply = nullptr;
|
|
LPPACK_BASE pk = nullptr;
|
|
|
|
*used = base_head_size;
|
|
{
|
|
std::string val(cfg_mgr_->get_option_value(nullptr, SANE_ACTION_GET_ENTIRE_JSON));
|
|
uint32_t err = 0;
|
|
|
|
reply = dyn_mem::memory(base_head_size + val.length() + 1);
|
|
pk = (LPPACK_BASE)reply->ptr();
|
|
BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, err);
|
|
strcpy(pk->payload, val.c_str());
|
|
pk->payload_len = val.length() + 1;
|
|
reply->set_len(base_head_size + val.length() + 1);
|
|
}
|
|
|
|
return reply;
|
|
}
|
|
dyn_mem_ptr async_scanner::handle_set_opt(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
|
{
|
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
|
dyn_mem_ptr reply = nullptr;
|
|
LPPACK_BASE pk = nullptr;
|
|
|
|
if (*used < base_head_size + pack->payload_len)
|
|
*used = 0;
|
|
else
|
|
{
|
|
LPCFGVAL cfg = (LPCFGVAL)pack->payload,
|
|
cfg_ret = nullptr;
|
|
std::string name(cfg->data + cfg->name_off);
|
|
size_t l = base_head_size + sizeof(CFGVAL) + name.length() + 1 + cfg->max_size + 1, val_size = cfg->val_size;
|
|
int32_t err = 0;
|
|
uint32_t after = 0;
|
|
|
|
reply = dyn_mem::memory(l);
|
|
pk = (LPPACK_BASE)reply->ptr();
|
|
cfg_ret = (LPCFGVAL)pk->payload;
|
|
cfg_ret->name_off = 0;
|
|
strcpy(cfg_ret->data + cfg_ret->name_off, name.c_str());
|
|
cfg_ret->val_off = name.length() + 1;
|
|
memcpy(cfg_ret->data + cfg_ret->val_off, cfg->data + cfg->val_off, cfg->val_size);
|
|
cfg_ret->val_size = cfg->val_size;
|
|
cfg_ret->max_size = cfg->max_size;
|
|
cfg_ret->type = cfg->type;
|
|
err = cfg_mgr_->update_data(cfg->data + cfg->name_off, cfg_ret->data + cfg_ret->val_off);
|
|
if(err == SCANNER_ERR_RELOAD_OPT_PARAM || err == SCANNER_ERR_RELOAD_IMAGE_PARAM || err == SCANNER_ERR_CONFIGURATION_CHANGED)
|
|
{
|
|
after = err;
|
|
err = SCANNER_ERR_OK;
|
|
}
|
|
cfg_ret->after_do = after;
|
|
cfg_ret->val_size = val_size;
|
|
BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, err);
|
|
pk->payload_len = sizeof(CFGVAL) + name.length() + 1 + cfg->max_size + 1;
|
|
reply->set_len(l);
|
|
}
|
|
|
|
return reply;
|
|
}
|
|
dyn_mem_ptr async_scanner::handle_file_receive(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
|
{
|
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
|
dyn_mem_ptr reply = nullptr;
|
|
LPPACK_BASE pk = nullptr;
|
|
|
|
if(*used < pack->payload_len + pack->size)
|
|
{
|
|
*used = 0;
|
|
}
|
|
else
|
|
{
|
|
LPTXFILE pfi = (LPTXFILE)pack->payload;
|
|
std::string path(pfi->path);
|
|
int err = 0;
|
|
file_saver *saver = new file_saver();
|
|
|
|
err = saver->open(path.c_str(), pfi->size, true, pfi->offset);
|
|
reply = dyn_mem::memory(base_head_size);
|
|
reply->set_len(base_head_size);
|
|
BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err);
|
|
*used = base_head_size + pack->payload_len;
|
|
if(err)
|
|
{
|
|
saver->release();
|
|
saver = nullptr;
|
|
}
|
|
else
|
|
{
|
|
saver->set_packet_param(pack->cmd, pack->pack_id);
|
|
}
|
|
utils::to_log(LOG_LEVEL_DEBUG, "Receiving file(%p bytes): %s = %d\n", pfi->size, path.c_str(), err);
|
|
*required = dynamic_cast<packet_data_base_ptr>(saver);
|
|
}
|
|
|
|
return reply;
|
|
}
|
|
dyn_mem_ptr async_scanner::handle_file_send(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
|
{
|
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
|
dyn_mem_ptr reply = dyn_mem::memory(base_head_size);
|
|
LPPACK_BASE pk = (LPPACK_BASE)reply->ptr();
|
|
|
|
if(*used < pack->payload_len + pack->size)
|
|
{
|
|
*used = 0;
|
|
}
|
|
else
|
|
{
|
|
LPTXFILE pfi = (LPTXFILE)pack->payload;
|
|
std::string path(pfi->path);
|
|
int err = 0;
|
|
file_reader *reader = new file_reader();
|
|
|
|
err = reader->open(path.c_str(), true, pfi->offset);
|
|
reply = dyn_mem::memory(base_head_size + sizeof(TXFILE));
|
|
reply->set_len(base_head_size + sizeof(TXFILE));
|
|
BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err);
|
|
((LPPACK_BASE)reply->ptr())->payload_len = sizeof(TXFILE);
|
|
*used = base_head_size + pack->payload_len;
|
|
utils::to_log(LOG_LEVEL_DEBUG, "To send file '%s' with %u bytes = %d\n", path.c_str(), reader->get_rest(), err);
|
|
if(err)
|
|
{
|
|
reader->release();
|
|
reader = nullptr;
|
|
}
|
|
else
|
|
{
|
|
((LPTXFILE)((LPPACK_BASE)reply->ptr())->payload)->size = reader->get_rest();
|
|
reader->set_packet_param(pack->cmd, pack->pack_id);
|
|
{
|
|
// move to PACK_CMD_FILE_READ_REQ_ROGER
|
|
SIMPLE_LOCK(fsender_);
|
|
send_files_.push_back(reader);
|
|
reader = nullptr;
|
|
}
|
|
}
|
|
*required = dynamic_cast<packet_data_base_ptr>(reader);
|
|
}
|
|
|
|
return reply;
|
|
}
|
|
dyn_mem_ptr async_scanner::handle_file_send_roger(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
|
{
|
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
|
dyn_mem_ptr reply = nullptr;
|
|
|
|
if(*used < base_head_size)
|
|
{
|
|
*used = 0;
|
|
}
|
|
else
|
|
{
|
|
file_reader* reader = nullptr;
|
|
|
|
{
|
|
SIMPLE_LOCK(fsender_);
|
|
for(size_t i = 0; i < send_files_.size(); ++i)
|
|
{
|
|
if(send_files_[i]->get_packet_id() == pack->pack_id)
|
|
{
|
|
reader = send_files_[i];
|
|
send_files_.erase(send_files_.begin() + i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!reader)
|
|
{
|
|
utils::log_mem_info("FATAL: Sending file lost source object !!!", pack, *used, LOG_LEVEL_FATAL);
|
|
}
|
|
else if(pack->data)
|
|
{
|
|
utils::to_log(LOG_LEVEL_DEBUG, "Sending file '%s' (%p) cancelled with error %d.\n", reader->path_file(), reader, pack->data);
|
|
reader->release();
|
|
reader = nullptr;
|
|
}
|
|
else
|
|
{
|
|
// if reader was nullptr, notify failed by INT or control ?
|
|
utils::to_log(LOG_LEVEL_DEBUG, "Sending file '%s' (%p) ...\n", reader->path_file(), reader);
|
|
}
|
|
*used = base_head_size;
|
|
*required = dynamic_cast<packet_data_base_ptr>(reader);
|
|
}
|
|
|
|
return reply;
|
|
}
|
|
dyn_mem_ptr async_scanner::handle_scan_start(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
|
{
|
|
if(!used)
|
|
{
|
|
reply_start_ = true;
|
|
return nullptr;
|
|
}
|
|
|
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
|
dyn_mem_ptr reply = dyn_mem::memory(base_head_size);
|
|
|
|
img_cnt_ = 0;
|
|
scan_id_ = pack->pack_id;
|
|
scan_err_ = 0;
|
|
reply_start_ = false;
|
|
|
|
auto receiver = [this](dyn_mem_ptr, bool, LPPACKIMAGE) -> void
|
|
{
|
|
|
|
};
|
|
|
|
*used = base_head_size;
|
|
reply->set_len(base_head_size);
|
|
scan_err_ = cis_->open(receiver);
|
|
if(scan_err_ == 0)
|
|
scan_err_ = cis_->start_scan();
|
|
if(scan_err_)
|
|
{
|
|
cis_->stop_scan();
|
|
}
|
|
BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, scan_err_);
|
|
*used |= INT32_MAX + 1;
|
|
|
|
return reply;
|
|
}
|
|
dyn_mem_ptr async_scanner::handle_scan_stop(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
|
{
|
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
|
dyn_mem_ptr reply = dyn_mem::memory(base_head_size);
|
|
int err = 0;
|
|
|
|
utils::to_log(LOG_LEVEL_DEBUG, "Received command Stop-Scan.\n");
|
|
err = cis_->stop_scan();
|
|
BASE_PACKET_REPLY(*((LPPACK_BASE)reply->ptr()), pack->cmd + 1, pack->pack_id, err);
|
|
reply->set_len(base_head_size);
|
|
*used = base_head_size;
|
|
|
|
return reply;
|
|
}
|
|
dyn_mem_ptr async_scanner::handle_process_cmd(LPPACK_BASE pack, uint32_t* used, packet_data_base_ptr* required)
|
|
{
|
|
uint32_t base_head_size = sizeof(PACK_BASE);
|
|
dyn_mem_ptr reply = dyn_mem::memory(base_head_size);
|
|
LPPACK_BASE pk = (LPPACK_BASE)reply->ptr();
|
|
|
|
*used = base_head_size + pack->payload_len;
|
|
BASE_PACKET_REPLY(*pk, pack->cmd + 1, pack->pack_id, EINVAL);
|
|
reply->set_len(base_head_size);
|
|
|
|
return reply;
|
|
}
|
|
|
|
|
|
uint32_t async_scanner::stop(void)
|
|
{
|
|
if(usb_)
|
|
{
|
|
usb_->stop();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
int async_scanner::last_error(void)
|
|
{
|
|
return last_err_;
|
|
}
|