newtx/scanner/async_scanner.cpp

428 lines
11 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>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
async_scanner::async_scanner() : usb_(nullptr), cfg_mgr_(nullptr), scan_id_(0)
{
utils::init_log(LOG_TYPE_FILE);
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 = [&](bool connected) -> void
{
utils::to_log(LOG_LEVEL_ALL, "USB %s\n", connected ? "connected" : "dis-connected");
// if(!connected)
// stop_scan();
};
auto user = [&](int priv) -> bool
{
return true;
};
auto on_log = [&](const char* msg) -> void
{
utils::log_info(msg, LOG_LEVEL_DEBUG);
};
cfg_mgr_ = new device_option(user, on_log);
init();
usb_ = new async_usb_gadget(bulk_handle, on_connect);
last_err_ = usb_->last_error();
}
async_scanner::~async_scanner()
{
if(usb_)
{
usb_->stop();
usb_->release();
}
if(cfg_mgr_)
{
cfg_mgr_->clear();
delete cfg_mgr_;
}
for(auto& v: send_files_)
v->release();
send_files_.clear();
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)
{
}
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);
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, "receive file (%u 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);
*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
{
((LPPACK_BASE)reply->ptr())->payload_len = sizeof(TXFILE);
((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;
}
}
}
*used = base_head_size;
*required = dynamic_cast<packet_data_base_ptr>(reader);
// if reader was nullptr, notify failed by INT or control ?
utils::to_log(LOG_LEVEL_DEBUG, "File Send beginning (%p) ...\n", 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;
*used = base_head_size;
reply->set_len(base_head_size);
// scan_err_ = capture_->start();
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 = capture_->stop();
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();
}
}
int async_scanner::last_error(void)
{
return last_err_;
}