#include #include "qappctrl.h" #include "../../src/defines.h" ///////////////////////////////////////////////////////////////////////////// #define _INVALID_SLOT_INDEX -1 #define _APP_CTRL_MAX_SLOTS ((int)(sizeof(appid_t) * 8)) #define _APP_INDEX_FROM_APP_ID(aid) (ffsll(aid) - 1) #define _IS_POWER_OF_2(x) (!!(x) && !((x) & ((x) - 1))) #define _IS_VALID_APP_ID(i) _IS_POWER_OF_2(i) #define _TIMESPEC_2_US(ts) (ts.tv_sec * 1000000 + ts.tv_nsec / 1000) #define _TIMESPEC_DIFF(ts1, ts2) (_TIMESPEC_2_US(ts1) - _TIMESPEC_2_US(ts2)) #define _MIN_TIMER_INT 20 ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// QGfaAppInfo::QGfaAppInfo(int nIndex, QObject *pParent) : QObject(pParent), m_state(GIAS_StateNotRunning), m_nIndex(nIndex), m_cycMin(0), m_cycMax(0) { m_nAppID = 1ull << m_nIndex; setStateText(m_state); } QGfaAppInfo::~QGfaAppInfo(void) { this->disconnect(); } ///////////////////////////////////////////////////////////////////////////// int QGfaAppInfo::state(void) const { return m_state; } void QGfaAppInfo::setState(int val) { if(m_state != val) { m_state = val; emit stateChanged(val); setStateText(val); if((m_state != GIAS_Running) && (m_state != GIAS_Paused)) { if(m_cycMin != 0) { m_cycMin = 0; emit cycMinChanged(m_cycMin); } if(m_cycMax != 0) { m_cycMax = 0; emit cycMaxChanged(m_cycMax); } } } } ///////////////////////////////////////////////////////////////////////////// QString QGfaAppInfo::stateText(void) const { return m_stateText; } void QGfaAppInfo::setStateText(int val) { QString sval = ::GfaIpcAppCtrlGetStateText((GfaIpcAppStates)val); if(m_stateText != sval) { m_stateText = sval; emit stateTextChanged(sval); } } ///////////////////////////////////////////////////////////////////////////// QString QGfaAppInfo::name(void) const { return m_name; } void QGfaAppInfo::setName(const QString &val) { if(m_name != val) { m_name = val; emit nameChanged(val); } } ///////////////////////////////////////////////////////////////////////////// quint64 QGfaAppInfo::cycMin(void) const { return m_cycMin; } quint64 QGfaAppInfo::cycMax(void) const { return m_cycMax; } void QGfaAppInfo::setAppTimes(LPCGFA_APPCTRL_APPTIMES pat) { if(pat) { if(m_cycMin != (quint64)pat->nCycleMin) { m_cycMin = (quint64)pat->nCycleMin; emit cycMinChanged(m_cycMin); } if(m_cycMax != (quint64)pat->nCycleMax) { m_cycMax = (quint64)pat->nCycleMax; emit cycMaxChanged(m_cycMax); } } } ///////////////////////////////////////////////////////////////////////////// bool QGfaAppInfo::pause(void) { emit sendControlMessage(m_nAppID, GFA_APPCTRL_CTRLMSG_PAUSE); return true; } bool QGfaAppInfo::resume(void) { emit sendControlMessage(m_nAppID, GFA_APPCTRL_CTRLMSG_RESUME); return true; } bool QGfaAppInfo::stop(void) { emit sendControlMessage(m_nAppID, GFA_APPCTRL_CTRLMSG_STOP); return true; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// QGfaAppCtrl::QGfaAppCtrl(QObject *pParent) : QObject(pParent), m_hAC(NULL), m_nAppID(0), m_nTimerID(0), m_curPass(0), m_minPass(LLONG_MAX), m_maxPass(LLONG_MIN), m_nEvtSrcs(0) { for(int i = 0; i < _APP_CTRL_MAX_SLOTS; ++i) { QGfaAppInfo *pai = new QGfaAppInfo(i, this); connect(pai, SIGNAL(sendControlMessage(appid_t, ctrlmsg_t)), SLOT(onSendControlMessage(appid_t, ctrlmsg_t))); m_appInfo.append(pai); } } QGfaAppCtrl::~QGfaAppCtrl(void) { Release(); for(int i = 0; i < _APP_CTRL_MAX_SLOTS; ++i) { QGfaAppInfo *pai = m_appInfo.at(i); delete pai; } } ///////////////////////////////////////////////////////////////////////////// bool QGfaAppCtrl::Create(appid_t nAppID, const char *pszDisplayName, int nTimerIntMs) { if(!m_hAC) { if(nTimerIntMs < _MIN_TIMER_INT) nTimerIntMs = _MIN_TIMER_INT; if((m_hAC = ::GfaIpcAppCtrlAcquire(nAppID, pszDisplayName, (clock64_t)(nTimerIntMs * 1000 * 2)))) { m_nAppID = nAppID; m_nTimerID = startTimer(nTimerIntMs, Qt::CoarseTimer); } } return !!m_hAC; } ///////////////////////////////////////////////////////////////////////////// void QGfaAppCtrl::Release(void) { if(m_hAC) { killTimer(m_nTimerID); ::GfaIpcAppCtrlRelease(m_hAC); m_hAC = NULL; } } ///////////////////////////////////////////////////////////////////////////// void QGfaAppCtrl::RegisterQmlTypes(QQmlEngine &rEng, int nVerMajor, int nVerMinor) { qmlRegisterUncreatableType("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "qAppInfo", QStringLiteral("class not creatable in QML")); qmlRegisterUncreatableType("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "qAppCtrl", QStringLiteral("class not creatable in QML")); rEng.rootContext()->setContextProperty(QStringLiteral("qAppCtrl"), this); } ///////////////////////////////////////////////////////////////////////////// bool QGfaAppCtrl::PresetDisplayName(appid_t nAppID, const char *pszName) { if(m_hAC) return ::GfaIpcAppCtrlPresetDisplayName(m_hAC, nAppID, pszName); return false; } ///////////////////////////////////////////////////////////////////////////// bool QGfaAppCtrl::SubscribeStateEvents(appid_t nAppMask) { if(m_hAC) { nAppMask &= ~m_nAppID; m_nEvtSrcs |= nAppMask; return ::GfaIpcAppCtrlSubscribeStateEvents(m_hAC, nAppMask); } return false; } ///////////////////////////////////////////////////////////////////////////// void QGfaAppCtrl::timerEvent(QTimerEvent *event) { struct timespec tsStart, tsEnd; ::clock_gettime(CLOCK_MONOTONIC, &tsStart); if((event->timerId() == m_nTimerID) && m_hAC) { HAPPINFO hAI; if((hAI = ::GfaIpcAppCtrlInfoUpdate(m_hAC))) { int b; ctrlmsg_t nCtrlMsg; appid_t app, nAppIdSrc; GFA_APPCTRL_APPTIMES at; char szDispName[128]; while((nCtrlMsg = ::GfaIpcAppCtrlGetNextCtrlMsg(hAI))) { switch(nCtrlMsg) { case GFA_APPCTRL_CTRLMSG_STOP: break; case GFA_APPCTRL_CTRLMSG_PAUSE: break; case GFA_APPCTRL_CTRLMSG_RESUME: break; default: break; } } while((nAppIdSrc = ::GfaIpcAppCtrlGetNextStateEvtSrc(hAI))) { GfaIpcAppStates state = ::GfaIpcAppCtrlGetState(m_hAC, nAppIdSrc); int nIndex = appIndexFromAppID(nAppIdSrc); QGfaAppInfo &ai = *m_appInfo[nIndex]; ai.setState(state); if((state >= GIAS_StateNotRunning) && (state <= GIAS_Paused)) { if(::GfaIpcAppCtrlGetDisplayName(m_hAC, nAppIdSrc, szDispName, sizeof(szDispName))) { ai.setName(szDispName); } } switch(nAppIdSrc) { case GFA_APPCTRL_APPID_REMANENT: break; case GFA_APPCTRL_APPID_REST: break; case GFA_APPCTRL_APPID_MQTTCL: break; } } nAppIdSrc = m_nEvtSrcs; while(nAppIdSrc) { b = ffsll(nAppIdSrc) - 1; app = ((appid_t)0x1 << b); nAppIdSrc &= ~app; GfaIpcAppStates state = ::GfaIpcAppCtrlGetState(m_hAC, app); if(state == GIAS_Running) { if(::GfaIpcAppCtrlGetAppTimes(m_hAC, app, &at) >= 0) { QGfaAppInfo &ai = *m_appInfo[b]; ai.setAppTimes(&at); } } } } } ::clock_gettime(CLOCK_MONOTONIC, &tsEnd); m_curPass = _TIMESPEC_DIFF(tsEnd, tsStart); if(m_minPass > m_curPass) { m_minPass = m_curPass; TRACE("Min pass: %llu us\n", m_minPass); } if(m_maxPass < m_curPass) { m_maxPass = m_curPass; TRACE("Max pass: %llu us\n", m_maxPass); } } ///////////////////////////////////////////////////////////////////////////// void QGfaAppCtrl::onSendControlMessage(appid_t nAppID, ctrlmsg_t msg) { if(m_hAC) ::GfaIpcAppCtrlSendCtrlMsg(m_hAC, nAppID, msg); } ///////////////////////////////////////////////////////////////////////////// int QGfaAppCtrl::SetState(int nState) { if(m_hAC) ::GfaIpcAppCtrlSetState(m_hAC, (GfaIpcAppStates)nState); return GIAS_Invalid; } ///////////////////////////////////////////////////////////////////////////// int QGfaAppCtrl::appIndexFromAppID(quint64 nAppID) { if(_IS_VALID_APP_ID(nAppID)) return _APP_INDEX_FROM_APP_ID(nAppID); return _INVALID_SLOT_INDEX; } ///////////////////////////////////////////////////////////////////////////// QQmlListProperty QGfaAppCtrl::appInfo(void) { return QQmlListProperty(this, m_appInfo); } ///////////////////////////////////////////////////////////////////////////// int QGfaAppCtrl::idxRemanent(void) const { static const int i = _APP_INDEX_FROM_APP_ID(GFA_APPCTRL_APPID_REMANENT); return i; } int QGfaAppCtrl::idxDatalogger(void) const { static const int i = _APP_INDEX_FROM_APP_ID(GFA_APPCTRL_APPID_DATALOGGER); return i; } int QGfaAppCtrl::idxSummarist(void) const { static const int i = _APP_INDEX_FROM_APP_ID(GFA_APPCTRL_APPID_SUMMARIST); return i; } int QGfaAppCtrl::idxRest(void) const { static const int i = _APP_INDEX_FROM_APP_ID(GFA_APPCTRL_APPID_REST); return i; } int QGfaAppCtrl::idxMqttCl(void) const { static const int i = _APP_INDEX_FROM_APP_ID(GFA_APPCTRL_APPID_MQTTCL); return i; }