LCOV - code coverage report
Current view: top level - utils/cursesINDI - cursesINDI.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 0.0 % 516 0
Test Date: 2026-01-03 21:03:39 Functions: 0.0 % 25 0

            Line data    Source code
       1              : 
       2              : #include <fstream>
       3              : 
       4              : #include <thread>
       5              : #include <mutex>
       6              : #include <set>
       7              : 
       8              : 
       9              : #include "../../INDI/libcommon/IndiClient.hpp"
      10              : #include "cursesTableGrid.hpp"
      11              : 
      12              : 
      13              : ///Simple utility to get the display string of a property
      14              : /**
      15              :   * \returns the properly formatted element value
      16              :   * \returns empty string on error
      17              :   */
      18            0 : std::string displayProperty( pcf::IndiProperty & ip /**< [in] the INDI property */ )
      19              : {
      20            0 :    std::string str = ip.getName();
      21            0 :    str += " [";
      22              : 
      23            0 :    std::string tstr = "n";
      24            0 :    if(ip.getType() == pcf::IndiProperty::Text) tstr = "t";
      25            0 :    if(ip.getType() == pcf::IndiProperty::Switch) tstr = "s";
      26            0 :    if(ip.getType() == pcf::IndiProperty::Light) tstr = "l";
      27              : 
      28            0 :    str += tstr;
      29              : 
      30            0 :    str += "]";
      31              : 
      32              : 
      33            0 :    if(ip.getState() == pcf::IndiProperty::Idle) str += "~";
      34            0 :    if(ip.getState() == pcf::IndiProperty::Ok) str += "-";
      35            0 :    if(ip.getState() == pcf::IndiProperty::Busy) str += "*";
      36            0 :    if(ip.getState() == pcf::IndiProperty::Alert) str += "!";
      37              : 
      38            0 :    return str;
      39            0 : }
      40              : 
      41              : ///Simple utility to get the display value of an element
      42              : /**
      43              :   * \returns the properly formatted element value
      44              :   * \returns empty string if element is not in property
      45              :   */
      46            0 : std::string displayValue( pcf::IndiProperty & ip, ///< [in] the INDI property
      47              :                           std::string & el ///< [in] the name of the element
      48              :                         )
      49              : {
      50            0 :    if(!ip.find(el)) return "";
      51              : 
      52            0 :    if(ip.getType() == pcf::IndiProperty::Switch)
      53              :    {
      54            0 :       if( ip[el].getSwitchState() == pcf::IndiElement::Off ) return "|O|";
      55            0 :       if( ip[el].getSwitchState() == pcf::IndiElement::On ) return "|X|";
      56            0 :       return pcf::IndiElement::getSwitchStateString(ip[el].getSwitchState());
      57              :    }
      58              :    else
      59              :    {
      60            0 :       return ip[el].getValue();
      61              :    }
      62              : }
      63              : 
      64              : class cursesINDI : public pcf::IndiClient, public cursesTableGrid
      65              : {
      66              : 
      67              : public:
      68              : 
      69              :    int m_redraw {0};
      70              : 
      71              :    int m_update {0};
      72              : 
      73              :    int m_cursStat {1};
      74              : 
      75              :    WINDOW * w_interactWin {nullptr};
      76              :    WINDOW * w_curvalWin {nullptr};
      77              :    WINDOW * w_attentionWin {nullptr};
      78              : 
      79              :    WINDOW * w_countWin {nullptr};
      80              : 
      81              :    bool m_shutdown {false};
      82              :    bool m_connectionLost{false};
      83              : 
      84              :    std::thread m_drawThread;
      85              :    std::mutex m_drawMutex;
      86              : 
      87              :    std::string m_msgFile {"/tmp/cursesINDI_logs.txt"};
      88              :    std::ofstream m_msgout;
      89              :    int m_msgsPrinted {0};
      90              :    int m_msgsMax {10000};
      91              : 
      92              :    cursesINDI( const std::string &szName,
      93              :                const std::string &szVersion,
      94              :                const std::string &szProtocolVersion
      95              :              );
      96              : 
      97              :    ~cursesINDI();
      98              : 
      99              :    typedef std::map< std::string, pcf::IndiProperty> propMapT;
     100              :    typedef propMapT::value_type propMapValueT;
     101              :    typedef propMapT::iterator propMapIteratorT;
     102              : 
     103              :    propMapT knownProps;
     104              : 
     105              :    struct elementSpec
     106              :    {
     107              :       std::string propKey;
     108              :       std::string device;
     109              :       std::string propertyName;
     110              :       std::string name;
     111              :       int tableRow {-1};
     112              :    };
     113              : 
     114              :    typedef std::map< std::string, elementSpec> elementMapT;
     115              :    typedef elementMapT::value_type elementMapValueT;
     116              :    typedef elementMapT::iterator elementMapIteratorT;
     117              : 
     118              :    elementMapT knownElements;
     119              : 
     120              : 
     121              :    bool m_deviceSearching {false};
     122              :    std::string m_deviceTarget;
     123              : 
     124              :    virtual void handleDefProperty( const pcf::IndiProperty &ipRecv );
     125              : 
     126              :    virtual void handleDelProperty( const pcf::IndiProperty &ipRecv );
     127              : 
     128              :    virtual void handleMessage( const pcf::IndiProperty &ipRecv );
     129              : 
     130              :    virtual void handleSetProperty( const pcf::IndiProperty &ipRecv );
     131              : 
     132              :    virtual void execute();
     133              : 
     134              :    void cursStat(int cs);
     135              : 
     136              :    int cursStat();
     137              : 
     138              :    void startUp();
     139              : 
     140              :    void shutDown();
     141              : 
     142              :    static void _drawThreadStart( cursesINDI * c /**< [in]  */);
     143              : 
     144              :    /// Start the draw thread.
     145              :    int drawThreadStart();
     146              : 
     147              :    /// Execute the draw thread.
     148              :    void drawThreadExec();
     149              : 
     150              : 
     151              :    void redrawTable();
     152              : 
     153              :    void updateTable();
     154              : 
     155              :    /// Update the current-value window.
     156              :    void updateCurVal();
     157              : 
     158              :    void moveCurrent( int nextY,
     159              :                      int nextX
     160              :                    );
     161              : 
     162              :    void _moveCurrent( int nextY,
     163              :                       int nextX
     164              :                     );
     165              : 
     166              :    void keyPressed( int ch );
     167              : 
     168              :    /// If a key is pressed in column 1 (the device column), this function searchs for devices alphabetically.
     169              :    void deviceSearch( int ch );
     170              : 
     171            0 :    virtual int postDraw()
     172              :    {
     173              :       //if(fpout) *fpout << "post draw" << std::endl;
     174              : 
     175            0 :       if(w_countWin)
     176              :       {
     177            0 :          wclear(w_countWin);
     178            0 :          delwin(w_countWin);
     179              :       }
     180            0 :       w_countWin = newwin( 1, m_minWidth, m_yTop+tabHeight()+1, m_xLeft);
     181              : 
     182            0 :       return postPrint();
     183              :    }
     184              : 
     185            0 :    virtual int postPrint()
     186              :    {
     187            0 :       if(! w_countWin) return 0;
     188              : 
     189            0 :       int shown = tabHeight();
     190            0 :       if( m_cellContents.size() - m_startRow <  (size_t) shown ) shown = m_cellContents.size() - m_startRow;
     191              : 
     192            0 :       wclear(w_countWin);
     193            0 :       wprintw(w_countWin, "%i/%zu elements shown.", shown, knownElements.size());
     194            0 :       wrefresh(w_countWin);
     195              : 
     196            0 :       return 0;
     197              :    }
     198              : 
     199              : 
     200              : };
     201              : 
     202            0 : cursesINDI::cursesINDI( const std::string &szName,
     203              :                         const std::string &szVersion,
     204              :                         const std::string &szProtocolVersion
     205            0 :                       ) : pcf::IndiClient(szName, szVersion, szProtocolVersion, "127.0.0.1", 7624)
     206              : {
     207            0 :    m_yTop = 6;
     208            0 :    colWidth({4, 19, 18, 18, 18});
     209              : 
     210            0 :    m_yBot = 1;
     211              : 
     212              : 
     213            0 :    m_msgout.open(m_msgFile);
     214              : 
     215            0 : }
     216              : 
     217            0 : cursesINDI::~cursesINDI()
     218              : {
     219            0 :    if( w_interactWin ) delwin(w_interactWin);
     220            0 :    if( w_curvalWin ) delwin(w_curvalWin);
     221            0 :    if( w_attentionWin ) delwin(w_attentionWin);
     222            0 :    if( w_countWin) delwin(w_countWin);
     223            0 : }
     224              : 
     225            0 : void cursesINDI::handleDefProperty( const pcf::IndiProperty &ipRecv )
     226              : {
     227            0 :    if(!ipRecv.hasValidDevice() && !ipRecv.hasValidName())
     228              :    {
     229            0 :       return;
     230              :    }
     231              : 
     232            0 :    std::pair<propMapIteratorT, bool> result;
     233              : 
     234            0 :    std::lock_guard<std::mutex> lock(m_drawMutex);
     235              : 
     236            0 :    result = knownProps.insert(propMapValueT( ipRecv.createUniqueKey(), ipRecv ));
     237              : 
     238              : 
     239            0 :    if(result.second == false)
     240              :    {
     241            0 :       result.first->second = ipRecv; //We already have it, so we're already registered
     242              :    }
     243              :    else
     244              :    {
     245            0 :       sendGetProperties(ipRecv); //Otherwise register for it
     246              :    }
     247              : 
     248            0 :    auto elIt = ipRecv.getElements().begin();
     249              : 
     250            0 :    while(elIt != ipRecv.getElements().end())
     251              :    {
     252            0 :       elementSpec es;
     253            0 :       es.propKey = ipRecv.createUniqueKey();
     254            0 :       es.device = ipRecv.getDevice();
     255            0 :       es.propertyName = ipRecv.getName();
     256            0 :       es.name = elIt->second.getName();
     257              : 
     258            0 :       std::string key = es.propKey + "." + es.name;
     259            0 :       auto elResult = knownElements.insert( elementMapValueT(key, es));
     260              : 
     261            0 :       if(elResult.second == true)
     262              :       {
     263              :          //If result is new insert, add to TUI table if filter requires
     264            0 :          ++m_redraw;
     265              :       }
     266              :       else
     267              :       {
     268              :          //Or just update the table.
     269              :          //Should check if this element actually changed....
     270            0 :          ++m_update;
     271              :       }
     272            0 :       ++elIt;
     273            0 :    }
     274              : 
     275            0 : }
     276              : 
     277            0 : void cursesINDI::handleDelProperty( const pcf::IndiProperty &ipRecv )
     278              : {
     279              :    //if(fpout) *fpout << "got delete property" << std::endl;
     280              : 
     281            0 :    if(ipRecv.hasValidDevice())
     282              :    {
     283            0 :       if(!ipRecv.hasValidName())
     284              :       {
     285              :          //if(fpout) *fpout << "will delete: " << ipRecv.getDevice() << "\n";
     286              : 
     287            0 :          for(elementMapIteratorT elIt = knownElements.begin(); elIt != knownElements.end();)
     288              :          {
     289            0 :             if( elIt->second.device == ipRecv.getDevice()) elIt = knownElements.erase(elIt);
     290            0 :             else ++elIt;
     291              :          }
     292              : 
     293            0 :          for(propMapIteratorT pIt = knownProps.begin(); pIt != knownProps.end();)
     294              :          {
     295            0 :             if( pIt->first == ipRecv.createUniqueKey() ) pIt = knownProps.erase(pIt);
     296            0 :             else ++pIt;
     297              :          }
     298              :       }
     299              :       else
     300              :       {
     301              :          //if(fpout) *fpout << "will delete: " << ipRecv.createUniqueKey() << "\n";
     302              : 
     303            0 :          for(elementMapIteratorT elIt = knownElements.begin(); elIt != knownElements.end();)
     304              :          {
     305            0 :             if( elIt->second.propKey == ipRecv.createUniqueKey()) elIt = knownElements.erase(elIt);
     306            0 :             else ++elIt;
     307              :          }
     308              : 
     309            0 :          knownProps.erase(ipRecv.createUniqueKey());
     310              : 
     311              :       }
     312              :    }
     313              : 
     314            0 :    ++m_redraw;
     315              : 
     316            0 : }
     317              : 
     318            0 : void cursesINDI::handleMessage( const pcf::IndiProperty &ipRecv )
     319              : {
     320              :    tm bdt; //broken down time
     321            0 :    time_t tt = ipRecv.getTimeStamp().getTimeVal().tv_sec;
     322            0 :    gmtime_r( &tt, &bdt);
     323              : 
     324              :    char tstr1[25];
     325            0 :    strftime(tstr1, sizeof(tstr1), "%H:%M:%S", &bdt);
     326              :    char tstr2[11];
     327            0 :    snprintf(tstr2, sizeof(tstr2), ".%06i", static_cast<int>(ipRecv.getTimeStamp().getTimeVal().tv_usec)); //casting in case we switch to int64_t
     328              : 
     329              : 
     330            0 :    std::string msg = ipRecv.getMessage();
     331              : 
     332            0 :    if(msg.size() > 4)
     333              :    {
     334            0 :       std::string prio = msg.substr(0,4);
     335            0 :       if(prio == "NOTE")
     336              :       {
     337            0 :          m_msgout << "\033[1m";
     338              :       }
     339            0 :       else if(prio == "WARN")
     340              :       {
     341            0 :          m_msgout << "\033[93m\033[1m";
     342              :       }
     343            0 :       else if(prio == "ERR ")
     344              :       {
     345            0 :          m_msgout << "\033[91m\033[1m";
     346              :       }
     347            0 :       else if(prio == "CRIT")
     348              :       {
     349            0 :          m_msgout << "\033[41m\033[1m";
     350              :       }
     351            0 :       else if(prio == "ALRT")
     352              :       {
     353            0 :          m_msgout << "\033[41m\033[1m";
     354              :       }
     355            0 :       else if(prio == "EMER")
     356              :       {
     357            0 :          m_msgout << "\033[41m\033[1m";
     358              :       }
     359            0 :    }
     360            0 :    m_msgout << std::string(tstr1) << std::string(tstr2) << " [" << ipRecv.getDevice() << "] " << msg;
     361              : 
     362            0 :    m_msgout << "\033[0m";
     363            0 :    m_msgout << std::endl;
     364              : 
     365              : 
     366            0 :    ++m_msgsPrinted;
     367            0 :    if(m_msgsPrinted > m_msgsMax)
     368              :    {
     369            0 :       m_msgout.close();
     370            0 :       m_msgout.open(m_msgFile);
     371            0 :       m_msgsPrinted = 0;
     372              :    }
     373            0 : }
     374              : 
     375            0 : void cursesINDI::handleSetProperty( const pcf::IndiProperty &ipRecv )
     376              : {
     377            0 :    handleDefProperty(ipRecv);
     378            0 : }
     379              : 
     380              : 
     381            0 : void cursesINDI::execute()
     382              : {
     383            0 :    processIndiRequests(false);
     384            0 : }
     385              : 
     386            0 : void cursesINDI::cursStat(int cs)
     387              : {
     388            0 :    m_cursStat = cs;
     389            0 :    curs_set(m_cursStat);
     390              : 
     391            0 : }
     392              : 
     393            0 : int cursesINDI::cursStat()
     394              : {
     395            0 :    return m_cursStat;
     396              : }
     397              : 
     398            0 : void cursesINDI::startUp()
     399              : {
     400            0 :    if(w_interactWin == nullptr)
     401              :    {
     402            0 :       w_interactWin = newwin( 1, m_minWidth, m_yTop-3, m_xLeft);
     403              :    }
     404              : 
     405            0 :    if(w_curvalWin == nullptr)
     406              :    {
     407            0 :       w_curvalWin = newwin( 1, m_minWidth, m_yTop-2, m_xLeft);
     408              :    }
     409              : 
     410            0 :    if(w_attentionWin == nullptr)
     411              :    {
     412            0 :       w_attentionWin = newwin( 1, m_minWidth, m_yTop-4, m_xLeft);
     413              :    }
     414              : 
     415            0 :    keypad(w_interactWin, TRUE);
     416              : 
     417              : 
     418            0 :    m_shutdown = false;
     419            0 :    drawThreadStart();
     420            0 : }
     421              : 
     422            0 : void cursesINDI::shutDown()
     423              : {
     424            0 :    if(getQuitProcess() && !m_shutdown) m_connectionLost = true;
     425              : 
     426            0 :    m_shutdown = true;
     427              : 
     428            0 :    quitProcess();
     429            0 :    deactivate();
     430              : 
     431            0 :    m_drawThread.join();
     432              : 
     433            0 :    m_cellContents.clear();
     434              : 
     435            0 :    if(w_interactWin) delwin(w_interactWin);
     436            0 :    w_interactWin = nullptr;
     437              : 
     438            0 :    if(w_countWin) delwin(w_countWin);
     439            0 :    w_countWin = nullptr;
     440              : 
     441            0 : }
     442              : 
     443              : inline
     444            0 : void cursesINDI::_drawThreadStart( cursesINDI * c)
     445              : {
     446            0 :    c->drawThreadExec();
     447            0 : }
     448              : 
     449              : inline
     450            0 : int cursesINDI::drawThreadStart()
     451              : {
     452              :    try
     453              :    {
     454            0 :       m_drawThread = std::thread( _drawThreadStart, this);
     455              :    }
     456            0 :    catch( const std::exception & e )
     457              :    {
     458            0 :       return -1;
     459            0 :    }
     460            0 :    catch( ... )
     461              :    {
     462            0 :       return -1;
     463            0 :    }
     464              : 
     465            0 :    if(!m_drawThread.joinable())
     466              :    {
     467            0 :       return -1;
     468              :    }
     469              : 
     470            0 :    return 0;
     471              : }
     472              : 
     473              : inline
     474            0 : void cursesINDI::drawThreadExec()
     475              : {
     476            0 :    while(!m_shutdown && !getQuitProcess())
     477              :    {
     478              :       ////if(fpout) *fpout << "draw thread . . ." << std::endl;
     479            0 :       if(m_redraw > 0)
     480              :       {
     481            0 :          redrawTable();
     482              :       }
     483              : 
     484            0 :       if(m_update > 0)
     485              :       {
     486            0 :          updateTable();
     487              :       }
     488              : 
     489            0 :       std::this_thread::sleep_for( std::chrono::duration<unsigned long, std::nano>(250000000));
     490              :    }
     491              : 
     492            0 :    if(getQuitProcess() && !m_shutdown)
     493              :    {
     494            0 :       m_connectionLost = true;
     495              : 
     496            0 :       m_cellContents.clear();
     497            0 :       redrawTable();
     498            0 :       m_shutdown = true;
     499              :    }
     500              : 
     501            0 : }
     502              : 
     503            0 : void cursesINDI::redrawTable()
     504              : {
     505            0 :    std::lock_guard<std::mutex> lock(m_drawMutex);
     506              : 
     507            0 :    int start_redraw = m_redraw;
     508              : 
     509              :    //if(fpout) *fpout << "redrawTable: " << m_redraw << std::endl;
     510              : 
     511            0 :    m_cellContents.clear();
     512              : 
     513            0 :    bool fsmAlerts = false;
     514              : 
     515            0 :    std::set<std::string> alertDev;
     516              : 
     517            0 :    for( elementMapIteratorT es = knownElements.begin(); es != knownElements.end(); ++es)
     518              :    {
     519              :       //if(fpout) *fpout << knownProps[es->second.propKey].getName() << " " << knownProps[es->second.propKey].getState() << "\n";
     520              : 
     521            0 :       if(knownProps[es->second.propKey].getName() == "fsm" &&
     522            0 :             knownProps[es->second.propKey].getState() == pcf::IndiProperty::Alert)
     523              :       {
     524            0 :          fsmAlerts = true;
     525            0 :          alertDev.insert(knownProps[es->second.propKey].getDevice());
     526              :       }
     527            0 :       std::vector<std::string> s;
     528              : 
     529            0 :       s.resize( m_colFraction.size() );
     530              : 
     531            0 :       s[0] = std::to_string(m_cellContents.size()+1);
     532            0 :       s[1] = knownProps[es->second.propKey].getDevice();
     533            0 :       s[2] = displayProperty( knownProps[es->second.propKey] );
     534              : 
     535            0 :       s[3] = es->second.name;
     536              : 
     537            0 :       s[4] = displayValue( knownProps[es->second.propKey], es->second.name);
     538              : 
     539            0 :       m_cellContents.push_back(s);
     540            0 :       es->second.tableRow = m_cellContents.size()-1;
     541            0 :    }
     542              : 
     543            0 :    draw();
     544              : 
     545              :    //if(fpout) *fpout << "fsmAlerts: " << fsmAlerts << "\n";
     546              : 
     547              :    int cx, cy;
     548            0 :    getyx(w_interactWin, cy, cx);
     549            0 :    int cs = cursStat();
     550            0 :    cursStat(0);
     551              : 
     552            0 :    wclear(w_attentionWin);
     553            0 :    if(fsmAlerts)
     554              :    {
     555            0 :       std::string alrt = "!! FSM alert: " + *alertDev.begin();
     556            0 :       if(alertDev.size() > 1) alrt += " (+" + std::to_string(alertDev.size()-1) + ")";
     557              : 
     558            0 :       wprintw(w_attentionWin, "%s", alrt.c_str());
     559            0 :    }
     560            0 :    wrefresh(w_attentionWin);
     561              : 
     562            0 :    wmove(w_interactWin,cy,cx);
     563            0 :    cursStat(cs);
     564            0 :    wrefresh(w_interactWin);
     565              : 
     566            0 :    m_redraw -= start_redraw;
     567            0 :    if(m_redraw <0) m_redraw = 0;
     568              : 
     569            0 :    _moveCurrent(m_currY, m_currX);
     570            0 : }
     571              : 
     572              : 
     573              : 
     574            0 : void cursesINDI::updateTable()
     575              : {
     576            0 :    if(m_redraw) return; //Pending redraw, so we skip it and let that take care of it.
     577              : 
     578            0 :    std::lock_guard<std::mutex> lock(m_drawMutex);
     579              : 
     580            0 :    int start_update = m_update;
     581              : 
     582              :    //if(fpout) *fpout << "updateTable: " << m_update << std::endl;
     583              :    int cx, cy;
     584              : 
     585            0 :    getyx(w_interactWin, cy, cx);
     586            0 :    int cs = cursStat();
     587              : 
     588            0 :    updateCurVal();
     589              : 
     590            0 :    bool fsmAlerts {false};
     591            0 :    std::set<std::string> alertDev;
     592              : 
     593            0 :    for(auto it = knownElements.begin(); it != knownElements.end(); ++it)
     594              :    {
     595              :       //if(fpout) *fpout << knownProps[it->second.propKey].getName() << " " << knownProps[it->second.propKey].getState() << "\n";
     596              : 
     597            0 :       if(knownProps[it->second.propKey].getName() == "fsm" &&
     598            0 :             knownProps[it->second.propKey].getState() == pcf::IndiProperty::Alert)
     599              :       {
     600            0 :          fsmAlerts = true;
     601            0 :          alertDev.insert(knownProps[it->second.propKey].getDevice());
     602              :       }
     603              : 
     604            0 :       if(it->second.tableRow == -1) continue;
     605              : 
     606            0 :       if(m_cellContents[it->second.tableRow][2] != displayProperty(knownProps[it->second.propKey]) )
     607              :       {
     608            0 :          m_cellContents[it->second.tableRow][2] = displayProperty(knownProps[it->second.propKey]) ;
     609              : 
     610            0 :          if(it->second.tableRow - m_startRow < (size_t) tabHeight()) //It's currently displayed
     611              :          {
     612            0 :             cursStat(0);
     613            0 :             wclear(m_gridWin[it->second.tableRow - m_startRow][2]);
     614            0 :             if(hasContent(it->second.tableRow,2)) wprintw(m_gridWin[it->second.tableRow - m_startRow][2], "%s", m_cellContents[it->second.tableRow][2].c_str());
     615            0 :             wrefresh(m_gridWin[it->second.tableRow - m_startRow][2]);
     616            0 :             wmove(w_interactWin,cy,cx);
     617            0 :             cursStat(cs);
     618            0 :             wrefresh(w_interactWin);
     619              :          }
     620              :       }
     621              : 
     622            0 :       if(m_cellContents[it->second.tableRow][4] != displayValue(knownProps[it->second.propKey], it->second.name)) //.getValue())
     623              :       {
     624            0 :          m_cellContents[it->second.tableRow][4] = displayValue(knownProps[it->second.propKey], it->second.name); //knownProps[it->second.propKey][it->second.name].getValue();
     625              : 
     626            0 :          if(it->second.tableRow - m_startRow < (size_t) tabHeight()) //It's currently displayed
     627              :          {
     628            0 :             cursStat(0);
     629            0 :             wclear(m_gridWin[it->second.tableRow - m_startRow][4]);
     630            0 :             if(hasContent(it->second.tableRow,4)) wprintw(m_gridWin[it->second.tableRow - m_startRow][4], "%s", m_cellContents[it->second.tableRow][4].c_str());
     631            0 :             wrefresh(m_gridWin[it->second.tableRow - m_startRow][4]);
     632            0 :             wmove(w_interactWin,cy,cx);
     633            0 :             cursStat(cs);
     634            0 :             wrefresh(w_interactWin);
     635              :          }
     636              : 
     637              :       };
     638              :       //updateContents( it->second.tableRow, 4,  knownProps[it->second.propKey][it->second.name].getValue());
     639              :    }
     640              : 
     641            0 :    wattron(m_gridWin[m_currY][m_currX], A_REVERSE);
     642              : 
     643              :    //if(fpout) *fpout << "fsmAlerts: " << fsmAlerts << "\n";
     644              : 
     645            0 :    getyx(w_interactWin, cy, cx);
     646            0 :    cs = cursStat();
     647            0 :    cursStat(0);
     648            0 :    wclear(w_attentionWin);
     649            0 :    if(fsmAlerts)
     650              :    {
     651            0 :       std::string alrt = "!! FSM alert: " + *alertDev.begin();
     652            0 :       if(alertDev.size() > 1) alrt += " (+" + std::to_string(alertDev.size()-1) + ")";
     653              : 
     654            0 :       wprintw(w_attentionWin, "%s", alrt.c_str());
     655            0 :    }
     656            0 :    wrefresh(w_attentionWin);
     657            0 :    wmove(w_interactWin,cy,cx);
     658            0 :    cursStat(cs);
     659            0 :    wrefresh(w_interactWin);
     660              : 
     661              :    //print();
     662              : 
     663              : //    wmove(w_interactWin,cy,cx);
     664              : //    cursStat(cs);
     665              : //    wrefresh(w_interactWin);
     666              : 
     667            0 :    m_update -= start_update;
     668            0 :    if(m_update <0) m_update = 0;
     669            0 : }
     670              : 
     671            0 : void cursesINDI::updateCurVal( )
     672              : {
     673              :    int cx, cy;
     674            0 :    getyx(w_interactWin, cy, cx);
     675            0 :    int cs = cursStat();
     676              : 
     677            0 :    cursStat(0);
     678            0 :    wclear(w_curvalWin);
     679              : 
     680            0 :    auto it = knownElements.begin();
     681            0 :    while(it != knownElements.end())
     682              :    {
     683            0 :       if( (size_t) it->second.tableRow == m_currY+m_startRow) break;
     684            0 :       ++it;
     685              :    }
     686              : 
     687            0 :    if(it == knownElements.end())
     688              :    {
     689            0 :       wrefresh(w_interactWin);
     690            0 :       cursStat(cs);
     691            0 :       return;
     692              :    }
     693              : 
     694            0 :    std::string cval = "> " + it->second.propKey + "." + it->second.name + " = ";
     695              : 
     696            0 :    cval += displayValue( knownProps[it->second.propKey], it->second.name);
     697              : 
     698            0 :    wprintw(w_curvalWin, "%s", cval.c_str());
     699            0 :    wrefresh(w_curvalWin);
     700              : 
     701            0 :    wmove(w_interactWin,cy,cx);
     702            0 :    cursStat(cs);
     703            0 :    wrefresh(w_interactWin);
     704              : 
     705            0 :    return;
     706            0 : }
     707              : 
     708            0 : void cursesINDI::moveCurrent( int nextY,
     709              :                               int nextX
     710              :                             )
     711              : {
     712            0 :    std::lock_guard<std::mutex> lock(m_drawMutex);
     713              : 
     714            0 :    _moveCurrent(nextY, nextX);
     715            0 : }
     716              : 
     717            0 : void cursesINDI::_moveCurrent( int nextY,
     718              :                                int nextX
     719              :                              )
     720              : {
     721            0 :    int currX = m_currX;
     722            0 :    int currY = m_currY;
     723              : 
     724            0 :    moveSelected(nextY, nextX);
     725              : 
     726              :    //if(fpout) *fpout << "moved: " << nextX << " " << nextY << " " << currX << "->" << m_currX << " " << currY << "->" << m_currY << std::endl;
     727              : 
     728            0 :    if(m_deviceSearching && nextX != 1)
     729              :    {
     730            0 :       wclear(w_interactWin);
     731            0 :       wrefresh(w_interactWin);
     732            0 :       m_deviceSearching = false;
     733              :    }
     734              : 
     735            0 :    updateCurVal();
     736              : 
     737            0 :    if(nextX == 1)
     738              :    {
     739            0 :       if( currX != nextX)
     740              :       {
     741            0 :          wclear(w_interactWin);
     742            0 :          wprintw(w_interactWin, "search: ");
     743            0 :          wrefresh(w_interactWin);
     744              :       }
     745              :    }
     746            0 :    else if(currY != nextY || currX == 1)
     747              :    {
     748            0 :       wclear(w_interactWin);
     749            0 :       if(m_currY + m_startRow >= knownElements.size())
     750              :       {
     751            0 :          wrefresh(w_interactWin);
     752            0 :          return;
     753              :       }
     754              : 
     755            0 :       auto it = knownElements.begin();
     756            0 :       while(it != knownElements.end())
     757              :       {
     758            0 :          if( (size_t) it->second.tableRow == m_currY+m_startRow) break;
     759            0 :          ++it;
     760              :       }
     761              : 
     762            0 :       if(it == knownElements.end())
     763              :       {
     764            0 :          wrefresh(w_interactWin);
     765            0 :          return;
     766              :       }
     767              : 
     768            0 :       if( knownProps[it->second.propKey].getPerm() != pcf::IndiProperty::ReadWrite)
     769              :       {
     770            0 :          wrefresh(w_interactWin);
     771            0 :          return;
     772              :       }
     773              : 
     774            0 :       if( knownProps[it->second.propKey].getType() == pcf::IndiProperty::Text)
     775              :       {
     776            0 :          wprintw(w_interactWin, "(e)dit this text");
     777              :       }
     778            0 :       else if( knownProps[it->second.propKey].getType() == pcf::IndiProperty::Number)
     779              :       {
     780            0 :          wprintw(w_interactWin, "(e)dit this number");
     781              :       }
     782            0 :       else if( knownProps[it->second.propKey].getType() == pcf::IndiProperty::Switch)
     783              :       {
     784            0 :          wprintw(w_interactWin, "(p)ress or (t)oggle this switch");
     785              :       }
     786              : 
     787              : 
     788            0 :       wrefresh(w_interactWin);
     789              :    }
     790              : 
     791              : }
     792              : 
     793              : 
     794            0 : void cursesINDI::deviceSearch( int ch )
     795              : {
     796            0 :    bool updated = false;
     797            0 :    if( m_deviceSearching == true )
     798              :    {
     799            0 :       if( ch == KEY_BACKSPACE )
     800              :       {
     801            0 :          if(m_deviceTarget.size() > 0)
     802              :          {
     803            0 :             std::lock_guard<std::mutex> lock(m_drawMutex);
     804            0 :             m_deviceTarget.erase(m_deviceTarget.size()-1,1);
     805            0 :             wprintw(w_interactWin, "\b \b");
     806            0 :             wrefresh(w_interactWin);
     807            0 :             return;
     808            0 :          }
     809              :       }
     810            0 :       else if (std::isprint(ch))
     811              :       {
     812            0 :          m_deviceTarget += ch;
     813            0 :          updated = true;
     814              :       }
     815            0 :       else return;
     816              :    }
     817            0 :    else if (std::isprint(ch))
     818              :    {
     819            0 :       m_deviceTarget = ch;
     820            0 :       updated = true;
     821              :    }
     822            0 :    else return;
     823              : 
     824              : 
     825            0 :    m_deviceSearching = true;
     826              : 
     827            0 :    if(updated)
     828              :    {
     829            0 :       std::lock_guard<std::mutex> lock(m_drawMutex);
     830            0 :       wprintw(w_interactWin, "%c", ch);
     831            0 :       wrefresh(w_interactWin);
     832            0 :    }
     833              : 
     834              :    //if(fpout) *fpout << "device searching: " << m_deviceTarget << std::endl;
     835            0 :    if(m_deviceTarget.size() == 0) return;
     836              : 
     837            0 :    auto it = knownElements.lower_bound(m_deviceTarget);
     838              : 
     839              :    //if(fpout) *fpout << "new row: " << it->second.tableRow << " " << m_startRow << " " << it->second.tableRow-m_startRow << "\n";
     840              : 
     841            0 :    if(it->second.tableRow == -1) return;
     842              : 
     843            0 :    m_startRow = it->second.tableRow;
     844              : 
     845            0 :    moveCurrent( 0, 1);
     846              : 
     847            0 :    redrawTable();
     848              : 
     849            0 :    return;
     850              : 
     851              : }
     852              : 
     853            0 : void cursesINDI::keyPressed( int ch )
     854              : {
     855              : 
     856              :    //If in first column, do device selection
     857            0 :    if(m_currX == 1 )
     858              :    {
     859            0 :       deviceSearch(ch);
     860            0 :       return;
     861              :    }
     862              : 
     863            0 :    if(m_deviceSearching)
     864              :    {
     865            0 :       wclear(w_interactWin);
     866            0 :       wrefresh(w_interactWin);
     867            0 :       m_deviceSearching = false;
     868              :    }
     869              : 
     870            0 :    switch(ch)
     871              :    {
     872            0 :       case 'e':
     873              :       {
     874            0 :          if(m_currY + m_startRow >= knownElements.size()) break;
     875            0 :          auto it = knownElements.begin();
     876            0 :          while(it != knownElements.end())
     877              :          {
     878            0 :             if( (size_t) it->second.tableRow == m_currY+m_startRow) break;
     879            0 :             ++it;
     880              :          }
     881              : 
     882            0 :          if(it == knownElements.end()) break;
     883              : 
     884              :          //Can't edit a switch
     885            0 :          if( knownProps[it->second.propKey].getType() != pcf::IndiProperty::Text && knownProps[it->second.propKey].getType() != pcf::IndiProperty::Number) break;
     886              : 
     887            0 :          cursStat(1);
     888              : 
     889              :          //mutex scope
     890              :          {
     891            0 :             std::lock_guard<std::mutex> lock(m_drawMutex);
     892            0 :             wclear(w_interactWin);
     893            0 :             wprintw(w_interactWin, "set %s.%s=", it->second.propKey.c_str(), it->second.name.c_str());
     894            0 :             wrefresh(w_interactWin);
     895            0 :          }
     896              : 
     897            0 :          bool escape = false;
     898            0 :          std::string newStr;
     899              :          int nch;
     900            0 :          while( (nch = wgetch(w_interactWin)) != '\n')
     901              :          {
     902            0 :             if(nch == ERR)
     903              :             {
     904            0 :                if( getQuitProcess())
     905              :                {
     906              :                   //If the IndiConnection has set 'quitProces' but no other shutdown
     907              :                   //has been issued then we record this as a lost connection.
     908            0 :                   if(!m_shutdown) m_connectionLost = true;
     909            0 :                   break;
     910              :                }
     911            0 :                else continue;
     912              :             }
     913              : 
     914            0 :             cursStat(1);
     915              : 
     916            0 :             if(nch == 27)
     917              :             {
     918            0 :                std::lock_guard<std::mutex> lock(m_drawMutex);
     919            0 :                wclear(w_interactWin);
     920            0 :                wrefresh(w_interactWin);
     921            0 :                escape = true;
     922            0 :                break;
     923            0 :             }
     924            0 :             if( nch == KEY_BACKSPACE )
     925              :             {
     926            0 :                if(newStr.size() > 0)
     927              :                {
     928            0 :                   std::lock_guard<std::mutex> lock(m_drawMutex);
     929            0 :                   newStr.erase(newStr.size()-1,1);
     930            0 :                   wprintw(w_interactWin, "\b \b");
     931            0 :                   wrefresh(w_interactWin);
     932            0 :                }
     933              :             }
     934            0 :             else if (std::isprint(nch))
     935              :             {
     936            0 :                std::lock_guard<std::mutex> lock(m_drawMutex);
     937            0 :                wprintw(w_interactWin, "%c", nch);
     938            0 :                wrefresh(w_interactWin);
     939              : 
     940            0 :                newStr += (char) nch;
     941            0 :             }
     942              :          }
     943            0 :          if(escape) break;
     944              : 
     945              :          //mutex scope
     946              :          {
     947            0 :             std::lock_guard<std::mutex> lock(m_drawMutex);
     948            0 :             wclear(w_interactWin);
     949            0 :             wprintw(w_interactWin, "send %s.%s=%s? y/n [n]", it->second.propKey.c_str(), it->second.name.c_str(), newStr.c_str());
     950            0 :             wrefresh(w_interactWin);
     951            0 :          }
     952              : 
     953            0 :          nch = 0;
     954            0 :          while( (nch = wgetch(w_interactWin)) == ERR)
     955              :          {
     956              :          }
     957              : 
     958            0 :          if(nch == 'y')
     959              :          {
     960            0 :             pcf::IndiProperty ipSend(knownProps[it->second.propKey].getType());
     961              : 
     962            0 :             ipSend.setDevice(knownProps[it->second.propKey].getDevice());
     963            0 :             ipSend.setName(knownProps[it->second.propKey].getName());
     964            0 :             ipSend.add(pcf::IndiElement(it->second.name));
     965              :             //if(fpout) *fpout << "newStr: " << newStr << std::endl;
     966              : 
     967            0 :             ipSend[it->second.name].setValue(newStr);
     968            0 :             sendNewProperty(ipSend);
     969            0 :          }
     970              : 
     971              :          //mutex scope
     972              :          {
     973            0 :             std::lock_guard<std::mutex> lock(m_drawMutex);
     974            0 :             wclear(w_interactWin);
     975            0 :             wrefresh(w_interactWin);
     976            0 :          }
     977              : 
     978            0 :          break;
     979            0 :       } //case 'e'
     980            0 :       case 't':
     981              :       {
     982            0 :          if(m_currY + m_startRow >= knownElements.size()) break;
     983            0 :          auto it = knownElements.begin();
     984            0 :          while(it != knownElements.end())
     985              :          {
     986            0 :             if( (size_t) it->second.tableRow == m_currY+m_startRow) break;
     987            0 :             ++it;
     988              :          }
     989              : 
     990            0 :          if(it == knownElements.end()) break;
     991              : 
     992            0 :          if( !knownProps[it->second.propKey].find(it->second.name)) break; //Just a check.
     993              : 
     994            0 :          if( knownProps[it->second.propKey].getType() != pcf::IndiProperty::Switch) break;
     995              : 
     996            0 :          std::string toggleString;
     997              :          pcf::IndiElement::SwitchStateType toggleState;
     998            0 :          if( knownProps[it->second.propKey][it->second.name].getSwitchState() == pcf::IndiElement::Off  )
     999              :          {
    1000            0 :             toggleString = "On";
    1001            0 :             toggleState = pcf::IndiElement::On;
    1002              :          }
    1003            0 :          else if(knownProps[it->second.propKey][it->second.name].getSwitchState() == pcf::IndiElement::On)
    1004              :          {
    1005            0 :             toggleString = "Off";
    1006            0 :             toggleState = pcf::IndiElement::Off;
    1007              :          }
    1008            0 :          else break; //would happen fo state unknown
    1009              : 
    1010            0 :          cursStat(1);
    1011              : 
    1012              :          //mutex scope
    1013              :          {
    1014            0 :             std::lock_guard<std::mutex> lock(m_drawMutex);
    1015            0 :             wclear(w_interactWin);
    1016            0 :             wprintw(w_interactWin, "toggle %s.%s to %s?", it->second.propKey.c_str(), it->second.name.c_str(), toggleString.c_str());
    1017            0 :             wrefresh(w_interactWin);
    1018            0 :          }
    1019              : 
    1020            0 :          int nch = 0;
    1021            0 :          while( (nch = wgetch(w_interactWin)) == ERR)
    1022              :          {
    1023              :          }
    1024              : 
    1025            0 :          if(nch == 'y')
    1026              :          {
    1027            0 :             pcf::IndiProperty ipSend(knownProps[it->second.propKey].getType());
    1028              : 
    1029            0 :             ipSend.setDevice(knownProps[it->second.propKey].getDevice());
    1030            0 :             ipSend.setName(knownProps[it->second.propKey].getName());
    1031            0 :             ipSend.add(pcf::IndiElement(it->second.name));
    1032            0 :             ipSend[it->second.name].setSwitchState(toggleState);
    1033            0 :             sendNewProperty(ipSend);
    1034            0 :          }
    1035              : 
    1036              :          //mutex scope
    1037              :          {
    1038            0 :             std::lock_guard<std::mutex> lock(m_drawMutex);
    1039            0 :             wclear(w_interactWin);
    1040            0 :             wrefresh(w_interactWin);
    1041            0 :          }
    1042              : 
    1043            0 :          break;
    1044            0 :       } //case 't'
    1045            0 :       case 'p':
    1046              :       {
    1047            0 :          if(m_currY + m_startRow >= knownElements.size()) break;
    1048            0 :          auto it = knownElements.begin();
    1049            0 :          while(it != knownElements.end())
    1050              :          {
    1051            0 :             if( (size_t) it->second.tableRow == m_currY+m_startRow) break;
    1052            0 :             ++it;
    1053              :          }
    1054              : 
    1055            0 :          if(it == knownElements.end()) break;
    1056              : 
    1057            0 :          if( !knownProps[it->second.propKey].find(it->second.name)) break; //Just a check.
    1058              : 
    1059            0 :          if( knownProps[it->second.propKey].getType() != pcf::IndiProperty::Switch) break;
    1060            0 :          cursStat(1);
    1061              : 
    1062              :          //mutex scope
    1063              :          {
    1064            0 :             std::lock_guard<std::mutex> lock(m_drawMutex);
    1065            0 :             wclear(w_interactWin);
    1066            0 :             wprintw(w_interactWin, "press switch %s.%s?", it->second.propKey.c_str(), it->second.name.c_str());
    1067            0 :             wrefresh(w_interactWin);
    1068            0 :          }
    1069              : 
    1070            0 :          int nch = 0;
    1071            0 :          while( (nch = wgetch(w_interactWin)) == ERR)
    1072              :          {
    1073              :          }
    1074              : 
    1075            0 :          if(nch == 'y')
    1076              :          {
    1077            0 :             pcf::IndiProperty ipSend(knownProps[it->second.propKey].getType());
    1078              : 
    1079            0 :             ipSend.setDevice(knownProps[it->second.propKey].getDevice());
    1080            0 :             ipSend.setName(knownProps[it->second.propKey].getName());
    1081              : 
    1082              :             //Must add all elements
    1083            0 :             for(auto elit = knownProps[it->second.propKey].getElements().begin(); elit != knownProps[it->second.propKey].getElements().end(); ++elit)
    1084              :             {
    1085            0 :                ipSend.add(elit->second);
    1086            0 :                if( knownProps[it->second.propKey].getRule() != pcf::IndiProperty::AnyOfMany)
    1087              :                {
    1088            0 :                   ipSend[elit->first].setSwitchState(pcf::IndiElement::Off);
    1089              :                }
    1090              :             }
    1091              : 
    1092            0 :             ipSend[it->second.name].setSwitchState(pcf::IndiElement::On);
    1093            0 :             sendNewProperty(ipSend);
    1094            0 :          }
    1095              : 
    1096              :          //mutex scope
    1097              :          {
    1098            0 :             std::lock_guard<std::mutex> lock(m_drawMutex);
    1099            0 :             wclear(w_interactWin);
    1100            0 :             wrefresh(w_interactWin);
    1101            0 :          }
    1102              : 
    1103            0 :          break;
    1104              :       } //case 'p'
    1105            0 :       default:
    1106            0 :          return;//break;
    1107              :    }
    1108              : 
    1109            0 :    std::lock_guard<std::mutex> lock(m_drawMutex);
    1110            0 :    cursStat(0);
    1111            0 :    wrefresh(w_interactWin);
    1112              : 
    1113              : }
        

Generated by: LCOV version 2.0-1