#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(this), dynamic_cast(this)); img_src_ = image_collector::create_image_collector(dynamic_cast(this)); res_ = new res_mon(dynamic_cast(this)); ipc_ = ipc_wrapper::create_ipc(dynamic_cast(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 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; }