#include "cdutils_core.h" #include "cdutils_parser.h" #include "piconfig.h" #include "piiobytearray.h" #include "piiostring.h" #include "piliterals_time.h" using namespace CDUtils; const char CDCore::app_config[] = "include = cd_ip.conf\n\ port_rec = 2\n\ port_send = 1\n\ [connection]\n\ device.cd = peer://cd_app:cd_pult #s\n\ []\n\ connectionmodel = AAAM2Xja7VXLTttAFD12QpsikKjUSixYlLbKEpIUtVIlVEfqhk2FWuiGRRolUYtoHgrmpYiv6IItf8AveMMH9E/YsG6Ph3sde5hGoQoblLGuPHfunTPjc49nADxDA110+LTYC7FrPCAPeAO+vZu+aX7c/8PGd45WCJC0OGcfT6FDnmfSTPtwhZFt3HjgDs/Qtu5jPbZHtI/x50XfIzMQbdwEolbg9INP4ku++myPaUtCHYRaT2j1ldIh3VP60/Qff8vSfXLu9BP6JX9K/0TVH6jqVe22P1X/fao/oddWu/paDs1vBf9Jv/EZ91clbyHqv7BL6sscDOd4v4WTqs6jzaHGJ8QJerxlpJSpdZ7IWFJvDW7I2JxZqIM62k6A57RZmMQGmlyrxdV+WGBnmR01mXPI267hBKwp4FeBeo9VPtssxyb7rzHg1B7T9nCMU45U8BZlWuVWtIcD/CRGOqtsbW09851tXsHN0UTlLIAdASjSXnLyLn+H7L2+xbGYvC63Ezqg543egkLmn8qnRF6USbM4Qp9godkhzI777Ne5bCIt/5UtGz2o/yGby0nKpjqmbOa1ynkjmyzIrzvIZUeBPjvlUmbh32EFJbGyJZhR8YcvlS+3TpjhqeWSyvUkpbI9plSWtcKLcsK05beOJVEnhaEFfHEH+RwpeMcpn1JKGqWMNOL+G6wZyahlpdVOtufKfbDS+guLke9O\n\ "; const char CDCore::pult_config[] = "include = cd_ip.conf\n\ port_rec = 1\n\ port_send = 2\n\ [connection]\n\ device.cd = peer://cd_pult:cd_app #s\n\ []\n\ connectionmodel = AAAM2Xja7VXLTttAFD12QpsikKjUSixYlLbKEpIUtVIlVEfqhk2FWuiGRRolUYtoHgrmpYiv6IItf8AveMMH9E/YsG6Ph3sde5hGoQoblLGuPHfunTPjc49nADxDA110+LTYC7FrPCAPeAO+vZu+aX7c/8PGd45WCJC0OGcfT6FDnmfSTPtwhZFt3HjgDs/Qtu5jPbZHtI/x50XfIzMQbdwEolbg9INP4ku++myPaUtCHYRaT2j1ldIh3VP60/Qff8vSfXLu9BP6JX9K/0TVH6jqVe22P1X/fao/oddWu/paDs1vBf9Jv/EZ91clbyHqv7BL6sscDOd4v4WTqs6jzaHGJ8QJerxlpJSpdZ7IWFJvDW7I2JxZqIM62k6A57RZmMQGmlyrxdV+WGBnmR01mXPI267hBKwp4FeBeo9VPtssxyb7rzHg1B7T9nCMU45U8BZlWuVWtIcD/CRGOqtsbW09851tXsHN0UTlLIAdASjSXnLyLn+H7L2+xbGYvC63Ezqg543egkLmn8qnRF6USbM4Qp9godkhzI777Ne5bCIt/5UtGz2o/yGby0nKpjqmbOa1ynkjmyzIrzvIZUeBPjvlUmbh32EFJbGyJZhR8YcvlS+3TpjhqeWSyvUkpbI9plSWtcKLcsK05beOJVEnhaEFfHEH+RwpeMcpn1JKGqWMNOL+G6wZyahlpdVOtufKfbDS+guLke9O\n\ "; int __Core_Initializer__::count_(0); CDCore * __Core_Initializer__::__instance__(0); const uchar header_direct = 0x80; const uchar header_transfer = 0x81; __Core_Initializer__::__Core_Initializer__() { count_++; if (count_ > 1) return; __instance__ = new CDCore(); } __Core_Initializer__::~__Core_Initializer__() { count_--; if (count_ < 0) { count_ = 0; return; } if (count_ > 0) return; if (__instance__) { delete __instance__; __instance__ = 0; } } CDCore::CDCore() { setName("CDCore"); x_timer.setName("_S.CDCore.x_timer"); datatr.setPacketSize(960); cout_buffer_id = PICout::registerExternalBufferID(); CONNECTU(&connection, dataReceivedEvent, this, dataReceived); CONNECTU(PICout::Notifier::object(), finished, this, piCoutFinished); /*PIString s(app_config); connection.configureFromString(&s); connection.start();*/ need_rebuild_x = x_pult_side = false; k_.cd_type_ = CDType::cdK; x_.cd_type_ = CDType::cdX; c_.cd_type_ = CDType::cdC; m_.cd_type_ = CDType::cdM; initRoot(&k_); initRoot(&x_); initRoot(&c_); initRoot(&m_); CONNECTU(&sendt, started, this, sendThread) CONNECTU(&datatr, sendRequest, this, dtSendRequest) CONNECTU(&datatr, receiveFinished, this, dtReceiveFinished) CONNECTU(&x_timer, tickEvent, this, xTimerTick) /*k_[1] = KType(1, "123", "120+3", "comment"); k_[2] = KType(2, "1", "2", "comm"); k_[4] = KType(4, "-0.6", "-6/10", "mment"); k_.section(10)[5] = KType(5, "8", "2*2*2", "88"); k_.section(10).section(50)[100] = KType(100, "8", "2*2*2", "88"); k_.section(11)[3] = KType(3, "1", "1", "88"); k_.section(11)[4] = KType(4, "0", "0", "88"); k_.section(11)[6] = KType(6, "0", "0", "88");*/ // piCout << s; } CDCore::~CDCore() { x_timer.stopAndWait(); datatr.stop(); sendt.stop(); sendt.waitForFinish(100_ms); connection.stop(); } void CDCore::cd_write(CDSection * cd, PIIODevice * d) { cd->write(d, PIString()); } void CDCore::cd_read(CDSection * cd, PIIODevice * d) { PIConfig conf(d, PIIODevice::ReadOnly); cd->read(&(conf.rootEntry())); if (cd->cd_type_ == CDType::cdX) x_selected = cd->collectX(); initRoot(cd); raiseChangedGlobal(cd->cd_type_); /*PIVector ds = connection.allDevices(); for (PIIODevice * d: ds) { if (d) piCoutObj << d->constructFullPath() << d->isOpened(); }*/ } void CDCore::cd_parse(CDSection * cd, PIIODevice * d) { *cd = CDParser::parse(d, cd->cd_type_); initRoot(cd); raiseChangedGlobal(cd->cd_type_); } void CDCore::cd_update(CDSection * cd, PIIODevice * d, UpdateModeFlags mode) { CDSection ucd = *cd; cd_parse(cd, d); /*bool kn = true; if (!ucd.isEmpty()) if (!ucd.isSameStructure(k_)) { piCout << "ask for save names"; K_KeepNamesRequest(&kn); }*/ ucd.update(*cd, mode); // piCout << k_.count() << ucd.count(); *cd = ucd; initRoot(cd); raiseChangedGlobal(cd->cd_type_); } void CDCore::cd_calculate(CDSection * cd) { cd->calculate(); raiseChangedGlobal(cd->cd_type_); } void CDCore::cd_send(CDSection * cd, CDPacketType pt, bool direct) { if (!cd) return; PIByteArray ba, sba; PIIOByteArray iob(&ba, PIIODevice::ReadWrite); cd_write(cd, &iob); // piCoutObj << PIString(ba); sba = makeHeader(pt, 0); sba << ba; if (direct) sendDirect(sba); else sendThreaded(sba); } void CDCore::send(CDType::cdT cdt) { CDPacketType pt = CD_Ping; switch (cdt) { case CDType::cdK: pt = CD_KSend; break; case CDType::cdX: pt = CD_XSend; break; case CDType::cdC: pt = CD_CSend; break; case CDType::cdM: pt = CD_MSend; break; default: break; } piCoutObj << "send" << typeLetter(cdt); cd_send(root(cdt), pt); } void CDCore::request(CDType::cdT cdt) { CDPacketType pt = CD_Ping; switch (cdt) { case CDType::cdK: pt = CD_KQuery; break; case CDType::cdX: pt = CD_XQuery; break; case CDType::cdC: pt = CD_CQuery; break; case CDType::cdM: pt = CD_MQuery; break; default: break; } piCoutObj << "request" << typeLetter(cdt); PIByteArray sba = makeHeader(pt, 0); sendThreaded(sba); } void CDCore::initApp() { init(appConfig(), false); } void CDCore::initPult() { init(pultConfig(), true); } void CDCore::init(const PIString & configuration, bool pult) { PIString c = configuration; // piCoutObj << "init" << c; connection.stop(); connection.removeAllDevices(); connection.configureFromString(&c); connection.start(); x_pult_side = pult; } void CDCore::stop() { x_timer.stopAndWait(); connection.stop(); } void CDCore::release() { stop(); connection.removeAllDevices(); } void CDCore::startX(double freq) { // piCout << "start x" << x_timer.isRunning() << freq; if (!x_timer.isRunning()) x_timer.start(piMax(PISystemTime::Frequency::fromHertz(freq), 0.01_Hz)); } void CDCore::stopX() { x_timer.stopAndWait(); } void CDCore::sendCommand(const CDType & c) { // piCoutObj << "C_sendCommand" << c; PIByteArray sba = makeHeader(CD_Command, 0); sba << c.path(); sendDirect(sba); } void CDCore::registerCHandler(const CDType & c, PIObject * o, Handler h) { PIString sp = pathToString(c.path()); if (sp.isEmpty() || !h) return; // piCout << "register" << sp; c_handlers[sp] = OHPair(o, h); } void CDCore::sendMessage(const CDType & m, MessageType mt, const PIString & msg) { if (msg.isEmpty() || (m.cd_type() != CDType::cdM)) return; PIByteArray sba = makeHeader(CD_Message, 0); sba << m.path() << int(mt) << msg; sendDirect(sba); } CDSection * CDCore::root(CDType::cdT cdt) { switch (cdt) { case CDType::cdK: return &k_; break; case CDType::cdX: return &x_; break; case CDType::cdC: return &c_; break; case CDType::cdM: return &m_; break; default: break; } return 0; } PIString CDCore::typeLetter(CDType::cdT cdt) { switch (cdt) { case CDType::cdK: return PIStringAscii("k"); break; case CDType::cdX: return PIStringAscii("x"); break; case CDType::cdC: return PIStringAscii("c"); break; case CDType::cdM: return PIStringAscii("m"); break; default: break; } return PIString(); } CDCore * CDCore::instance() { /*static CDCore * ret = new CDCore(); return ret;*/ return __Core_Initializer__::__instance__; } bool CDCore::destroy() { if (!__Core_Initializer__::__instance__) return false; // piCout << "delete Core ..."; delete __Core_Initializer__::__instance__; // piCout << "delete Core ok"; __Core_Initializer__::__instance__ = 0; __Core_Initializer__::count_ = 0; return true; } void CDUtils::CDCore::K_DirectChange(PIDeque path, PIString value) { // piCoutObj << "K_DirectChange"; PacketKDirectChange p; p.path = path; p.value = value; PIByteArray sba = makeHeader(CD_KDirectChange, 0); sba << p; sendDirect(sba); } void CDCore::sendThread() { if (send_data.size_s() < 4) return; PacketHeader h; memcpy(&h, send_data.data(), sizeof(h)); bool ok = datatr.send(send_data); switch (h.type) { case CD_KSend: if (ok) K_Sended(); else K_SendFail(); break; case CD_KQuery: if (!ok) K_ReceiveFail(); break; case CD_XSend: if (ok) X_Sended(); else X_SendFail(); break; case CD_XQuery: if (!ok) X_ReceiveFail(); break; case CD_CSend: if (ok) C_Sended(); else C_SendFail(); break; case CD_CQuery: if (!ok) C_ReceiveFail(); break; case CD_MSend: if (ok) M_Sended(); else M_SendFail(); break; case CD_MQuery: if (!ok) M_ReceiveFail(); break; default: break; } } void CDCore::xTimerTick() { // piCout << "x tick" << x_pult_side; PIByteArray ba; x_mutex.lock(); if (x_pult_side) { ba = makeHeader(CD_XRequest, 0); if (need_rebuild_x) { x_selected = x_.collectX(); // piCout << "collectX" << x_selected.size(); need_rebuild_x = false; } ba << x_selected; // piCout << "x pult send" << x_selected.size(); } else { ba = makeHeader(CD_XValues, 0); ba << x_selected; for (const auto & p: x_selected) { x_[p].writeX(ba); } // piCout << "x app" << x_selected.size(); } x_mutex.unlock(); sendDirect(ba); } void CDCore::piCoutFinished(int id, PIString * buffer) { if ((id != cout_buffer_id) || !buffer) return; PIString sp = buffer->takeRange('[', ']'); PIDeque p = CDCore::stringToPath(sp); sendMessage(m_[p], Log, *buffer); delete buffer; } void CDCore::initRoot(CDSection * r) { r->name = "__root__"; r->alias = "root"; r->makePath(); r->calculate(); } PIByteArray CDCore::makeHeader(CDPacketType type, int session_id) const { PacketHeader h; h.type = type; h.session_id = session_id; PIByteArray ret; ret << h; return ret; } void CDCore::sendDirect(PIByteArray & ba) { ba.push_front(header_direct); connection.writeByName("cd", ba); } void CDCore::sendThreaded(PIByteArray & ba) { if (sendt.isRunning()) { piCoutObj << "Send in process, abort"; return; } send_data = ba; sendt.startOnce(); } void CDCore::procReceivedPacket(PIByteArray & ba) { PacketHeader h; ba >> h; switch (h.type) { case CD_Ping: // piCoutObj << "ping"; break; case CD_KQuery: send(CDType::cdK); break; case CD_KSend: { PIByteArray k; ba >> k; k << uchar(0); PIIOByteArray ios(k); cd_read(&k_, &ios); K_Received(); piCoutObj << "K received"; } break; case CD_KDirectChange: { PacketKDirectChange p; ba >> p; k_[p.path].setValue(p.value); } break; case CD_XQuery: send(CDType::cdX); break; case CD_XSend: { PIByteArray x; ba >> x; x << uchar(0); PIIOByteArray ios(x); cd_read(&x_, &ios); x_selected = x_.collectX(); X_Received(); piCoutObj << "X received"; } break; case CD_XRequest: { if (x_pult_side) break; // break; x_mutex.lock(); x_selected.clear(); ba >> x_selected; // piCout << "X req" << x_selected.size(); x_.setSelectedX(false); for (const auto & p: x_selected) { x_[p].x_enabled = true; } x_mutex.unlock(); } break; case CD_XValues: { if (!x_pult_side) break; PIVector> x_vals; ba >> x_vals; x_mutex.lock(); for (const auto & p: x_vals) { x_[p].readX(ba); } x_mutex.unlock(); X_ReceivedX(x_vals); } break; case CD_CQuery: send(CDType::cdC); break; case CD_CSend: { piCoutObj << "C received"; PIByteArray c; ba >> c; c << uchar(0); PIIOByteArray ios(c); cd_read(&c_, &ios); C_Received(); } break; case CD_Command: { piCoutObj << "C command"; PIDeque p; ba >> p; if (p.isEmpty()) return; PIString sp = pathToString(p); OHPair h = c_handlers.value(sp, OHPair(0, 0)); // piCoutObj << "found" << sp << h.first; if (h.first && h.second) h.second(h.first); } break; case CD_MQuery: send(CDType::cdM); break; case CD_MSend: { piCoutObj << "M received"; PIByteArray m; ba >> m; m << uchar(0); PIIOByteArray ios(m); cd_read(&m_, &ios); M_Received(); } break; case CD_Message: { PIDeque p; ba >> p; piCoutObj << "M message" << p; if (p.isEmpty()) return; int t = 0; PIString msg; ba >> t >> msg; // piCoutObj << "found" << sp << h.first; // piCoutObj << "M message invoke"; M_Message(p, t, msg); } break; default: break; } } void CDCore::raiseChangedGlobal(CDType::cdT cdt) { switch (cdt) { case CDType::cdK: K_ChangedGlobal(); break; case CDType::cdX: X_ChangedGlobal(); break; case CDType::cdC: C_ChangedGlobal(); break; case CDType::cdM: M_ChangedGlobal(); break; default: break; } } PIString CDCore::pathToString(const PIDeque & p) { PIString ret; for (int i = 0; i < p.size_s(); ++i) { if (!ret.isEmpty()) ret += "."; ret += PIString::fromNumber(p[i]); } return ret; } PIDeque CDCore::stringToPath(const PIString & p) { PIDeque ret; PIStringList sl = p.split("."); for (const auto & s: sl) ret << s.toInt(); return ret; } void CDUtils::CDCore::dataReceived(const PIString & from, const PIByteArray & data) { // piCoutObj << "dataReceived" << from << data.size(); PIIODevice * d = connection.deviceByName("cd"); if (d && d == connection.deviceByFullPath(from)) { if (data.size() >= sizeof(int)) { PIByteArray ba = data; uchar header = ba.take_front(); if (header == header_transfer) { datatr.received(ba); } if (header == header_direct) { procReceivedPacket(ba); } } } } void CDCore::dtSendRequest(PIByteArray & data) { data.push_front(header_transfer); connection.writeByName("cd", data); // piCoutObj << "send" << data.size() << ret; } void CDCore::dtReceiveFinished(bool ok) { if (!ok) return; PIByteArray ba = datatr.data(); procReceivedPacket(ba); }