code_scanner/scanner/main/scanner.cpp

476 lines
10 KiB
C++

#include "scanner.h"
#include "../../common/log_util.h"
#include "../../common/ipc_wrapper.h"
#include "../../common/json/json.h"
#include "../img_collector/img_collector.h"
#include "../img_process/img_process.h"
#include "../res_monitor/res_monitor.h"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// scanner
scanner::scanner(const char* ipc_id) : img_proc_(nullptr), img_src_(nullptr), res_(nullptr), ipc_(nullptr)
, exit_(nullptr), run_(true), status_(SCANNER_STATUS_READY), ipc_id_(ipc_id)
, partial_msg_(""), write_thunk_(false)
{
hw_status_.val = 0;
exit_ = new linux_event("exit-scanner");
}
scanner::~scanner()
{
uninit();
exit_->release();
}
int32_t scanner::init(void)
{
run_ = true;
img_proc_ = new img_processor(dynamic_cast<paremeter_get*>(this), dynamic_cast<event_handler*>(this));
img_src_ = image_collector::create_image_collector(dynamic_cast<event_handler*>(this));
res_ = new res_mon(dynamic_cast<event_handler*>(this));
ipc_ = ipc_wrapper::create_ipc(dynamic_cast<event_handler*>(this), ipc_wrapper::IPC_SHARED_MEM, ipc_id_.c_str());
return ipc_->is_ok() ? 0 : ENOTCONN;
}
int32_t scanner::uninit(void)
{
run_ = false;
if (ipc_)
{
ipc_->stop();
ipc_->release();
}
if (res_)
{
res_->stop();
res_->release();
}
if (img_src_)
{
img_src_->stop();
img_src_->uninit();
img_src_->release();
}
if (img_proc_)
{
img_proc_->stop();
img_proc_->release();
}
img_proc_ = nullptr;
img_src_ = nullptr;
res_ = nullptr;
ipc_ = nullptr;
return 0;
}
int32_t scanner::add_ref(void)
{
return event_handler::add_ref();
}
int32_t scanner::release(void)
{
return event_handler::release();
}
int32_t scanner::from_thunk_data(std::string& pack)
{
LPPACK_BASE pk = (LPPACK_BASE)&pack[0];
if (pk->thunk && pk->cmd != PACK_CMD_INNER_WRITE)
{
std::string d("");
LPTHUNKD pthk = (LPTHUNKD)pk->payload;
while (pthk->bytes)
{
d += std::string(pthk->data, pthk->bytes);
pthk = (LPTHUNKD)((char*)pthk + sizeof(THUNKD) + pthk->bytes);
}
pack.erase(sizeof(PACK_BASE));
pack += d;
((LPPACK_BASE)&pack[0])->thunk = 0;
((LPPACK_BASE)&pack[0])->total_bytes = d.length();
}
return pack.length();
}
int32_t scanner::dispatch_ipc_message(LPPACK_BASE pack)
{
if (write_thunk_ && pack->cmd != PACK_CMD_INNER_WRITE)
{
return EAGAIN;
}
if (pack->cmd == PACK_CMD_ATTR_HISTORY_COUNT_GET)
{
}
else if (pack->cmd == PACK_CMD_ATTR_ROLLER_COUNT_GET)
{
}
else if (pack->cmd == PACK_CMD_ATTR_ROLLER_COUNT_SET)
{
}
else if (pack->cmd == PACK_CMD_SETTING_GET)
{
size_t len = 0;
char *buf = nullptr;
json *cis = nullptr, *proc = nullptr;
int ret = 0;
std::string cfg("");
if (img_src_->get_config(buf, &len) == ENOMEM)
{
buf = new char[len + 4];
if (img_src_->get_config(buf, &len) == 0)
{
cis = new json(buf);
}
}
ret = img_proc_->get_config(buf, &len);
if(ret == ENOMEM)
{
if (buf)
delete[] buf;
buf = new char[len + 4];
ret = img_proc_->get_config(buf, &len);
}
if (ret == 0)
{
proc = new json(buf);
if (cis)
{
json* child = cis->first_child();
while (child)
{
proc->set_value(child->key().c_str(), child);
child->release();
child = cis->next_child();
}
cis->release();
}
cfg = proc->to_string();
proc->release();
}
else if (cis)
{
cfg = cis->to_string();
cis->release();
}
if (buf)
delete[] buf;
PACK_BASE reply(*pack);
reply.result = cfg.empty() ? ENOENT : 0;
reply.thunk = 0;
reply.total_bytes = cfg.length();
cfg.insert(0, std::string((char*)&reply, sizeof(reply)));
len = cfg.length();
ipc_->write(cfg.c_str(), &len, false);
}
else if (pack->cmd == PACK_CMD_SETTING_GET_CUR)
{
}
else if (pack->cmd == PACK_CMD_SETTING_SET)
{
}
else if (pack->cmd == PACK_CMD_SETTING_RESTORE)
{
}
else if (pack->cmd == PACK_CMD_STATUS_GET)
{
PACK_BASE reply(*pack);
if (hw_status_.no_paper)
reply.result = SCANNER_STATUS_NO_PAPER;
else if (hw_status_.cover_opened)
reply.result = SCANNER_STATUS_COVER_OPENNED;
else if (hw_status_.sleeping)
reply.result = SCANNER_STATUS_SLEEPING;
else
reply.result = status_;
size_t len = sizeof(reply);
ipc_->write((char*)&reply, &len, false);
}
else if (pack->cmd == PACK_CMD_STATUS_RESTORE)
{
PACK_BASE reply(*pack);
size_t len = sizeof(reply);
reply.result = 0;
ipc_->write((char*)&reply, &len, false);
}
else if (pack->cmd == PACK_CMD_SCAN_START)
{
PACK_BASE reply(*pack);
if (hw_status_.no_paper)
reply.result = SCANNER_STATUS_NO_PAPER;
else if (hw_status_.cover_opened)
reply.result = SCANNER_STATUS_COVER_OPENNED;
else if (hw_status_.sleeping)
reply.result = SCANNER_STATUS_SLEEPING;
else if (status_ != SCANNER_STATUS_READY)
reply.result = status_;
else
reply.result = img_src_->start();
size_t len = sizeof(reply);
ipc_->write((char*)&reply, &len, false);
}
else if (pack->cmd == PACK_CMD_SCAN_STOP)
{
}
//else if (pack->cmd == PACK_CMD_SCAN_IMG_SIZE_GET)
//{
//
//}
//else if (pack->cmd == PACK_CMD_SCAN_IMG_READ)
//{
//
//}
//else if (pack->cmd == PACK_CMD_SCAN_IMG_POP)
//{
//
//}
else if (pack->cmd == PACK_CMD_INNER_WRITE)
{
size_t len = pack->total_bytes;
write_thunk_ = pack->thunk;
ipc_->write(pack->payload, &len, false);
}
return 0;
}
int32_t scanner::ipc_message_handler(void)
{
std::deque<std::string> task;
while (run_)
{
std::string msg("");
if (!msg_que_.take(msg, true))
continue;
from_thunk_data(msg);
if (dispatch_ipc_message((LPPACK_BASE)&msg[0]) == EAGAIN)
{
task.push_back(msg);
}
else if (!write_thunk_)
{
while (task.size())
{
msg = std::move(task.front());
task.pop_front();
dispatch_ipc_message((LPPACK_BASE)&msg[0]);
}
}
}
return 0;
}
int32_t scanner::on_ipc(void* data, size_t data_len, bool in)
{
int32_t ret = 0;
if (in)
{
partial_msg_ += std::string((char*)data, data_len);
if (partial_msg_.length() >= sizeof(PACK_BASE))
{
LPPACK_BASE pack = (LPPACK_BASE)&partial_msg_[0];
size_t len = sizeof(PACK_BASE) + pack->total_bytes;
if (pack->thunk)
{
LPTHUNKD pthk = (LPTHUNKD)pack->payload;
len = partial_msg_.length() - sizeof(PACK_BASE);
while (len >= sizeof(THUNKD))
{
if (pthk->bytes == 0)
{
pthk++;
len = (char*)pthk - (char*)pack;
std::string msg(&partial_msg_[0], len);
partial_msg_.erase(0, len);
msg_que_.save(msg, true);
break;
}
if (len < pthk->bytes + sizeof(THUNKD))
break;
len -= pthk->bytes + sizeof(THUNKD);
pthk = (LPTHUNKD)(pthk->data + pthk->bytes);
}
}
else
{
if (partial_msg_.length() >= len)
{
msg_que_.save(partial_msg_.substr(0, len), true);
partial_msg_.erase(0, len);
}
}
}
}
else
{
// several parts sent ...
}
return ret;
}
int32_t scanner::on_event(int32_t ev, void* data, size_t data_len)
{
// image-process, image-collector, resource-mgr, ipc_wrapper
int32_t ret = 0;
if (!run_)
return ESHUTDOWN;
switch (ev)
{
case SCANNER_EVENT_IPC_DATA_RECEIVED:
on_ipc(data, data_len, true);
break;
case SCANNER_EVENT_IPC_DATA_SENT:
on_ipc(data, data_len, false);
break;
case SCANNER_EVENT_COLLECTOR_WORKING:
status_ = SCANNER_STATUS_WORKING;
break;
case SCANNER_EVENT_COLLECTOR_IMG_DATA:
if (((LPIMGD)data)->info->pos.new_img && ((LPIMGD)data)->info->pos.img_over)
{
img_proc_->push_image(((LPIMGD)data)->info, ((LPIMGD)data)->data, data_len);
}
else
{
// thunked data, send by IPC immediately
PACK_BASE pk;
LPIMGD src = (LPIMGD)data;
std::string msg("");
THUNKD thunk;
pk.cmd = PACK_CMD_INNER_WRITE;
pk.thunk = !((LPIMGD)data)->info->pos.img_over;
if (((LPIMGD)data)->info->pos.new_img)
{
PACK_BASE head;
memset(&head, 0, sizeof(head));
head.cmd = PACK_CMD_SCAN_IMG_READ;
head.thunk = 1;
thunk.bytes = sizeof(head) + sizeof(src->info) + data_len;
head.total_bytes = thunk.bytes + sizeof(thunk);
msg = std::string((char*)&pk, sizeof(pk))
+ std::string((char*)&head, sizeof(head))
+ std::string((char*)&thunk, sizeof(thunk))
+ std::string((char*)&src->info, sizeof(src->info));
}
else
{
thunk.bytes = data_len;
msg = std::string((char*)&pk, sizeof(pk)) + std::string((char*)&thunk, sizeof(thunk));
}
msg += std::string((char*)src->data, data_len);
if (src->info->pos.img_over)
{
thunk.bytes = 0; // THUNK end flag
msg += std::string((char*)&thunk, sizeof(thunk));
}
((LPPACK_BASE)&msg[0])->total_bytes = msg.length() - sizeof(pk);
msg_que_.save(msg, true);
}
break;
case SCANNER_EVENT_COLLECTOR_PAPER_ON:
hw_status_.no_paper = !(*(bool*)data);
break;
case SCANNER_EVENT_COLLECTOR_COVER_OPENNED:
hw_status_.cover_opened = *(bool*)data;
break;
case SCANNER_EVENT_COLLECTOR_SLEEPPING:
hw_status_.sleeping = *(bool*)data;
break;
case SCANNER_EVENT_COLLECTOR_ERROR:
break;
case SCANNER_EVENT_COLLECTOR_STOPPED:
status_ = data_len ? (scanner_status)data_len : SCANNER_STATUS_READY;
break;
case SCANNER_EVENT_IMAGE_PROC_OK:
break;
case SCANNER_EVENT_RESOURCE_LOW_MEM:
case SCANNER_EVENT_RESOURCE_HIGH_CPU:
if (*(bool*)data) // low mem or high cpu
{
if (status_ == SCANNER_STATUS_WORKING)
{
if (img_src_->pause() == 0)
status_ = SCANNER_STATUS_PAUSING;
}
}
else if (status_ == SCANNER_STATUS_PAUSING)
{
if (img_src_->resume() == 0)
status_ = SCANNER_STATUS_WORKING;
}
img_proc_->set_speed_first(!(*(bool*)data));
break;
case SCANNER_EVENT_RESOURCE_LOW_DISK:
// we have no disk write operations, ignore now
break;
default:
ret = EINVAL;
break;
}
return ret;
}
int32_t scanner::get_fd(void)
{
return -1;
}
parameter* scanner::get_parameter(img_proc_param ipp)
{
return nullptr;
}
int32_t scanner::run(void)
{
int32_t ret = init();
if (ret == 0)
exit_->wait();
uninit();
return ret;
}
int32_t scanner::stop(void)
{
run_ = false;
exit_->trigger();
return 0;
}