OpenCores
URL https://opencores.org/ocsvn/w11/w11/trunk

Subversion Repositories w11

[/] [w11/] [tags/] [w11a_V0.74/] [tools/] [src/] [librlink/] [RlinkConnect.cpp] - Diff between revs 25 and 27

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 25 Rev 27
Line 1... Line 1...
// $Id: RlinkConnect.cpp 575 2014-07-27 20:55:41Z mueller $
// $Id: RlinkConnect.cpp 611 2014-12-10 23:23:58Z mueller $
//
//
// Copyright 2011-2014 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
// Copyright 2011-2014 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
//
//
// This program is free software; you may redistribute and/or modify it under
// This program is free software; you may redistribute and/or modify it under
// the terms of the GNU General Public License as published by the Free
// the terms of the GNU General Public License as published by the Free
Line 11... Line 11...
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for complete details.
// for complete details.
// 
// 
// Revision History: 
// Revision History: 
// Date         Rev Version  Comment
// Date         Rev Version  Comment
 
// 2014-12-10   611   2.0    re-organize for rlink v4
 
// 2014-08-26   587   1.5    start accept rlink v4 protocol (partially...)
 
// 2014-08-15   583   1.4    rb_mreq addr now 16 bit
// 2014-07-27   575   1.3.3  ExecPart(): increase packet tout from 5 to 15 sec
// 2014-07-27   575   1.3.3  ExecPart(): increase packet tout from 5 to 15 sec
// 2013-04-21   509   1.3.2  add SndAttn() method
// 2013-04-21   509   1.3.2  add SndAttn() method
// 2013-03-01   493   1.3.1  add Server(Active..|SignalAttn)() methods
// 2013-03-01   493   1.3.1  add Server(Active..|SignalAttn)() methods
// 2013-02-23   492   1.3    use scoped_ptr for Port; Close allways allowed
// 2013-02-23   492   1.3    use scoped_ptr for Port; Close allways allowed
//                           use RlinkContext, add Context(), Exec(..., cntx)
//                           use RlinkContext, add Context(), Exec(..., cntx)
Line 27... Line 30...
// 2011-01-15   356   0.1    First draft
// 2011-01-15   356   0.1    First draft
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
 
 
/*!
/*!
  \file
  \file
  \version $Id: RlinkConnect.cpp 575 2014-07-27 20:55:41Z mueller $
  \version $Id: RlinkConnect.cpp 611 2014-12-10 23:23:58Z mueller $
  \brief   Implemenation of RlinkConnect.
  \brief   Implemenation of RlinkConnect.
*/
*/
 
 
#include <iostream>
#include <iostream>
 
 
Line 57... Line 60...
 
 
// all method definitions in namespace Retro
// all method definitions in namespace Retro
namespace Retro {
namespace Retro {
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
 
// constants definitions
 
 
 
const uint16_t RlinkConnect::kRbaddr_RLCNTL;
 
const uint16_t RlinkConnect::kRbaddr_RLSTAT;
 
const uint16_t RlinkConnect::kRbaddr_RLID1;
 
const uint16_t RlinkConnect::kRbaddr_RLID0;
 
 
 
const uint16_t RlinkConnect::kRLCNTL_M_AnEna;
 
const uint16_t RlinkConnect::kRLCNTL_M_AtoEna;
 
const uint16_t RlinkConnect::kRLCNTL_M_AtoVal;
 
 
 
const uint16_t RlinkConnect::kRLSTAT_V_LCmd;
 
const uint16_t RlinkConnect::kRLSTAT_B_LCmd;
 
const uint16_t RlinkConnect::kRLSTAT_M_BAbo;
 
const uint16_t RlinkConnect::kRLSTAT_M_RBSize;
 
 
 
const uint16_t RlinkConnect::kSBCNTL_V_RLMON;
 
const uint16_t RlinkConnect::kSBCNTL_V_RLBMON;
 
const uint16_t RlinkConnect::kSBCNTL_V_RBMON;
 
 
 
//------------------------------------------+-----------------------------------
//! Default constructor
//! Default constructor
 
 
RlinkConnect::RlinkConnect()
RlinkConnect::RlinkConnect()
  : fpPort(),
  : fpPort(),
    fpServ(0),
    fpServ(0),
    fTxPkt(),
    fSndPkt(),
    fRxPkt(),
    fRcvPkt(),
    fContext(),
    fContext(),
    fAddrMap(),
    fAddrMap(),
    fStats(),
    fStats(),
    fLogOpts(),
    fLogOpts(),
    fspLog(new RlogFile(&cout, "<cout>")),
    fspLog(new RlogFile(&cout, "<cout>")),
    fConnectMutex()
    fConnectMutex(),
 
    fAttnNotiPatt(0),
 
    fTsLastAttnNoti(-1)
{
{
  for (size_t i=0; i<8; i++) fSeqNumber[i] = 0;
  for (size_t i=0; i<8; i++) fSeqNumber[i] = 0;
 
 
  // Statistic setup
  // Statistic setup
  fStats.Define(kStatNExec,     "NExec",     "Exec() calls");
  fStats.Define(kStatNExec,     "NExec",     "Exec() calls");
  fStats.Define(kStatNSplitVol, "NSplitVol", "clist splits: Volatile");
 
  fStats.Define(kStatNExecPart, "NExecPart", "ExecPart() calls");
  fStats.Define(kStatNExecPart, "NExecPart", "ExecPart() calls");
  fStats.Define(kStatNCmd,      "NCmd",      "commands executed");
  fStats.Define(kStatNCmd,      "NCmd",      "commands executed");
  fStats.Define(kStatNRreg,     "NRreg",     "rreg commands");
  fStats.Define(kStatNRreg,     "NRreg",     "rreg commands");
  fStats.Define(kStatNRblk,     "NRblk",     "rblk commands");
  fStats.Define(kStatNRblk,     "NRblk",     "rblk commands");
  fStats.Define(kStatNWreg,     "NWreg",     "wreg commands");
  fStats.Define(kStatNWreg,     "NWreg",     "wreg commands");
  fStats.Define(kStatNWblk,     "NWblk",     "wblk commands");
  fStats.Define(kStatNWblk,     "NWblk",     "wblk commands");
  fStats.Define(kStatNStat,     "NStat",     "stat commands");
  fStats.Define(kStatNLabo,     "NLabo",     "labo commands");
  fStats.Define(kStatNAttn,     "NAttn",     "attn commands");
  fStats.Define(kStatNAttn,     "NAttn",     "attn commands");
  fStats.Define(kStatNInit,     "NInit",     "init commands");
  fStats.Define(kStatNInit,     "NInit",     "init commands");
  fStats.Define(kStatNRblkWord, "NRblkWord", "words rcvd with rblk");
  fStats.Define(kStatNRblkWord, "NRblkWord", "words rcvd with rblk");
  fStats.Define(kStatNWblkWord, "NWblkWord", "words send with wblk");
  fStats.Define(kStatNWblkWord, "NWblkWord", "words send with wblk");
  fStats.Define(kStatNTxPktByt, "NTxPktByt", "Tx packet bytes send");
  fStats.Define(kStatNTxPktByt, "NTxPktByt", "Tx packet bytes send");
  fStats.Define(kStatNTxEsc,    "NTxEsc",    "Tx escapes");
 
  fStats.Define(kStatNRxPktByt, "NRxPktByt", "Rx packet bytes rcvd");
  fStats.Define(kStatNRxPktByt, "NRxPktByt", "Rx packet bytes rcvd");
  fStats.Define(kStatNRxEsc,    "NRxEsc",    "Rx escapes");
 
  fStats.Define(kStatNRxAttn,   "NRxAttn",   "Rx ATTN commas seen");
 
  fStats.Define(kStatNRxIdle,   "NRxIdle",   "Rx IDLE commas seen");
 
  fStats.Define(kStatNRxDrop,   "NRxDrop",   "Rx bytes droped");
 
  fStats.Define(kStatNExpData,  "NExpData",  "Expect() for data defined");
  fStats.Define(kStatNExpData,  "NExpData",  "Expect() for data defined");
  fStats.Define(kStatNExpStat,  "NExpStat",  "Expect() for stat defined");
  fStats.Define(kStatNExpStat,  "NExpStat",  "Expect() for stat defined");
  fStats.Define(kStatNChkData,  "NChkData",  "expect data failed");
  fStats.Define(kStatNChkData,  "NChkData",  "expect data failed");
  fStats.Define(kStatNChkStat,  "NChkStat",  "expect stat failed");
  fStats.Define(kStatNChkStat,  "NChkStat",  "expect stat failed");
  fStats.Define(kStatNSndOob,   "NSndOob",   "SndOob() calls");
  fStats.Define(kStatNSndOob,   "NSndOob",   "SndOob() calls");
 
  fStats.Define(kStatNErrMiss,  "NErrMiss",  "decode: missing data");
 
  fStats.Define(kStatNErrCmd,   "NErrCmd",   "decode: command mismatch");
 
  fStats.Define(kStatNErrLen,   "NErrLen",   "decode: length mismatch");
 
  fStats.Define(kStatNErrCrc,   "NErrCrc",   "decode: crc mismatch");
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! Destructor
//! Destructor
 
 
Line 135... Line 159...
 
 
  if (fpServ) fpServ->Stop();               // stop server in case still running
  if (fpServ) fpServ->Stop();               // stop server in case still running
 
 
  if (fpPort->Url().FindOpt("keep")) {
  if (fpPort->Url().FindOpt("keep")) {
    RerrMsg emsg;
    RerrMsg emsg;
    fTxPkt.SndKeep(fpPort.get(), emsg);
    fSndPkt.SndKeep(fpPort.get(), emsg);
  }
  }
 
 
  fpPort.reset();
  fpPort.reset();
 
 
  return;
  return;
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! Indicates whether server is active.
 
/*!
 
  \returns \c true if server active.
 
 */
 
 
 
 
bool RlinkConnect::ServerActive() const
bool RlinkConnect::ServerActive() const
{
{
  return fpServ && fpServ->IsActive();
  return fpServ && fpServ->IsActive();
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! Indicates whether server is active and caller is inside server thread.
 
/*!
 
  \returns \c true if server active and method is called from server thread.
 
 */
 
 
bool RlinkConnect::ServerActiveInside() const
bool RlinkConnect::ServerActiveInside() const
{
{
  return fpServ && fpServ->IsActiveInside();
  return fpServ && fpServ->IsActiveInside();
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! Indicates whether server is active and caller is outside server thread.
 
/*!
 
  \returns \c true if server active and method is called from a thread
 
           other than the server thread.
 
 */
 
 
bool RlinkConnect::ServerActiveOutside() const
bool RlinkConnect::ServerActiveOutside() const
{
{
  return fpServ && fpServ->IsActiveOutside();
  return fpServ && fpServ->IsActiveOutside();
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! FIXME_docs
 
 
void RlinkConnect::ServerSignalAttn()
 
{
 
  if (fpServ) fpServ->SignalAttn();
 
  return;
 
}
 
 
 
//------------------------------------------+-----------------------------------
 
//! FIXME_docs
 
 
 
void RlinkConnect::lock()
void RlinkConnect::lock()
{
{
  fConnectMutex.lock();
  fConnectMutex.lock();
  return;
  return;
}
}
Line 217... Line 243...
 
 
  boost::lock_guard<RlinkConnect> lock(*this);
  boost::lock_guard<RlinkConnect> lock(*this);
 
 
  fStats.Inc(kStatNExec);
  fStats.Inc(kStatNExec);
 
 
  size_t ibeg = 0;
  clist.ClearLaboIndex();
 
 
  size_t size = clist.Size();
  size_t size = clist.Size();
 
 
  for (size_t i=0; i<size; i++) {
  for (size_t i=0; i<size; i++) {
    RlinkCommand& cmd = clist[i];
    RlinkCommand& cmd = clist[i];
   if (!cmd.TestFlagAny(RlinkCommand::kFlagInit))
   if (!cmd.TestFlagAny(RlinkCommand::kFlagInit))
Line 231... Line 258...
      throw Rexception("RlinkConnect::Exec()",
      throw Rexception("RlinkConnect::Exec()",
                       "BugCheck: invalid command code");
                       "BugCheck: invalid command code");
    // trap attn command when server running and outside server thread
    // trap attn command when server running and outside server thread
    if (cmd.Command() == RlinkCommand::kCmdAttn && ServerActiveOutside())
    if (cmd.Command() == RlinkCommand::kCmdAttn && ServerActiveOutside())
      throw Rexception("RlinkConnect::Exec()",
      throw Rexception("RlinkConnect::Exec()",
                       "attn command not allowed outside avtice server");
                       "attn command not allowed outside active server");
 
 
    cmd.ClearFlagBit(RlinkCommand::kFlagSend   | RlinkCommand::kFlagDone |
    cmd.ClearFlagBit(RlinkCommand::kFlagSend   |
                     RlinkCommand::kFlagPktBeg | RlinkCommand::kFlagPktEnd |
                     RlinkCommand::kFlagDone   |
                     RlinkCommand::kFlagRecov  | RlinkCommand::kFlagResend |
                     RlinkCommand::kFlagLabo   |
                     RlinkCommand::kFlagErrNak | RlinkCommand::kFlagErrMiss |
                     RlinkCommand::kFlagPktBeg |
                     RlinkCommand::kFlagErrCmd | RlinkCommand::kFlagErrCrc);
                     RlinkCommand::kFlagPktEnd |
 
                     RlinkCommand::kFlagErrNak |
 
                     RlinkCommand::kFlagErrDec);
  }
  }
 
 
 
  // old split volative logic. Currently dormant
 
  // may be later used for rtbuf size prot
 
#ifdef NEVER
  while (ibeg < size) {
  while (ibeg < size) {
    size_t iend = ibeg;
    size_t iend = ibeg;
    for (size_t i=ibeg; i<size; i++) {
    for (size_t i=ibeg; i<size; i++) {
      iend = i;
      iend = i;
      if (clist[i].TestFlagAll(RlinkCommand::kFlagVol)) {
      if (clist[i].TestFlagAll(RlinkCommand::kFlagVol)) {
Line 253... Line 285...
    }
    }
    bool rc = ExecPart(clist, ibeg, iend, emsg, cntx);
    bool rc = ExecPart(clist, ibeg, iend, emsg, cntx);
    if (!rc) return rc;
    if (!rc) return rc;
    ibeg = iend+1;
    ibeg = iend+1;
  }
  }
 
#endif
 
 
 
  bool rc = ExecPart(clist, 0, size-1, emsg, cntx);
 
  if (!rc) return rc;
 
 
  bool checkseen = false;
  bool checkseen = false;
  bool errorseen = false;
  bool errorseen = false;
 
 
  for (size_t i=0; i<size; i++) {
  for (size_t i=0; i<size; i++) {
    RlinkCommand& cmd = clist[i];
    RlinkCommand& cmd = clist[i];
 
 
    bool checkfound = cmd.TestFlagAny(RlinkCommand::kFlagChkStat |
    bool checkfound = cmd.TestFlagAny(RlinkCommand::kFlagChkStat |
                                      RlinkCommand::kFlagChkData);
                                      RlinkCommand::kFlagChkData);
    bool errorfound = cmd.TestFlagAny(RlinkCommand::kFlagErrNak |
    bool errorfound = cmd.TestFlagAny(RlinkCommand::kFlagErrNak |
                                      RlinkCommand::kFlagErrMiss |
                                      RlinkCommand::kFlagErrDec);
                                      RlinkCommand::kFlagErrCmd |
 
                                      RlinkCommand::kFlagErrCrc);
 
    checkseen |= checkfound;
    checkseen |= checkfound;
    errorseen |= errorfound;
    errorseen |= errorfound;
    if (checkfound | errorfound) cntx.IncErrorCount();
    if (checkfound | errorfound) cntx.IncErrorCount();
  }
  }
 
 
Line 304... Line 338...
  }
  }
  return rc;
  return rc;
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
 
//! Wait for an attention notify.
 
/*!
 
  First checks whether there are received and not yet harvested notifies.
 
  In that case the cummulative pattern of these pending notifies is returned
 
  in \a apat, and a 0. return value.
 
 
 
  If a positive \a timeout is specified the method waits this long for a
 
  valid and non-zero attention notify.
 
 
 
  \param      timeout  maximal time to wait for input in sec. Must be >= 0.
 
                       A zero \a timeout can be used to only harvest pending
 
                       notifies without waiting for new ones.
 
  \param[out] apat     cummulative attention pattern
 
  \param[out] emsg     contains error description (mainly from port layer)
 
 
 
  \returns wait time, or a negative value indicating an error:
 
    - =0.  if there was already a received and not yet harvested notify
 
    - >0   the wait time till the nofity was received
 
    - -1.  indicates timeout (\a apat will be 0)
 
    - -2.  indicates port IO error (\a emsg will contain information)
 
 
 
  \throws Rexception if called outside of an active server
 
 
 
  \pre ServerActiveOutside() must be \c false.
 
 
 
 */
 
 
 
double RlinkConnect::WaitAttn(double timeout, uint16_t& apat, RerrMsg& emsg)
 
{
 
  if (ServerActiveOutside())
 
    throw Rexception("RlinkConnect::WaitAttn()",
 
                     "not allowed outside active server");
 
 
 
  apat = 0;
 
 
 
  boost::lock_guard<RlinkConnect> lock(*this);
 
 
 
  // harvest pending notifiers
 
  if (fAttnNotiPatt != 0) {
 
    apat = fAttnNotiPatt;
 
    fAttnNotiPatt = 0;
 
    return 0.;
 
  }
 
 
 
  // quit if poll only (zero timeout) 
 
  if (timeout == 0.) return -1.;
 
 
 
  // wait for new notifier
 
  double tnow = Rtools::TimeOfDayAsDouble();
 
  double tend = tnow + timeout;
 
  double tbeg = tnow;
 
 
 
  while (tnow < tend) {
 
    int irc = fRcvPkt.ReadData(fpPort.get(), tend-tnow, emsg);
 
    if (irc == RlinkPort::kTout) return -1.;
 
    if (irc == RlinkPort::kErr)  return -2.;
 
    tnow = Rtools::TimeOfDayAsDouble();
 
    while (fRcvPkt.ProcessData()) {
 
      int irc = fRcvPkt.PacketState();
 
      if (irc == RlinkPacketBufRcv::kPktPend) break;
 
      if (irc == RlinkPacketBufRcv::kPktAttn) {
 
        ProcessAttnNotify();
 
        if (fAttnNotiPatt != 0) {
 
          apat = fAttnNotiPatt;
 
          fAttnNotiPatt = 0;
 
          return tnow - tbeg;
 
        }
 
      } else {
 
        RlogMsg lmsg(*fspLog, 'E');
 
        lmsg << "WaitAttn: dropped spurious packet";
 
        fRcvPkt.AcceptPacket();
 
      }
 
 
 
    } // while (fRcvPkt.ProcessData())
 
  } // while (tnow < tend)
 
 
 
  return -1;
 
}
 
 
 
//------------------------------------------+-----------------------------------
 
//! FIXME_docs
 
 
 
bool RlinkConnect::SndOob(uint16_t addr, uint16_t data, RerrMsg& emsg)
 
{
 
  boost::lock_guard<RlinkConnect> lock(*this);
 
  fStats.Inc(kStatNSndOob);
 
  return fSndPkt.SndOob(fpPort.get(), addr, data, emsg);
 
}
 
 
 
//------------------------------------------+-----------------------------------
 
//! FIXME_docs
 
 
 
bool RlinkConnect::SndAttn(RerrMsg& emsg)
 
{
 
  boost::lock_guard<RlinkConnect> lock(*this);
 
  return fSndPkt.SndAttn(fpPort.get(), emsg);
 
}
 
 
 
//------------------------------------------+-----------------------------------
 
//! FIXME_docs
 
 
 
void RlinkConnect::SetLogOpts(const LogOpts& opts)
 
{
 
  if (opts.baseaddr!=2 && opts.baseaddr!=8 && opts.baseaddr!=16)
 
    throw Rexception("RlinkConnect::SetLogOpts()",
 
                     "Bad args: baseaddr != 2,8,16");
 
  if (opts.basedata!=2 && opts.basedata!=8 && opts.basedata!=16)
 
    throw Rexception("RlinkConnect::SetLogOpts()",
 
                     "Bad args: basedata != 2,8,16");
 
  if (opts.basestat!=2 && opts.basestat!=8 && opts.basestat!=16)
 
    throw Rexception("RlinkConnect::SetLogOpts()",
 
                     "Bad args: basestat != 2,8,16");
 
 
 
  fLogOpts = opts;
 
  if (fpPort) fpPort->SetTraceLevel(opts.tracelevel);
 
  return;
 
}
 
 
 
//------------------------------------------+-----------------------------------
 
//! FIXME_docs
 
 
 
bool RlinkConnect::LogOpen(const std::string& name)
 
{
 
  if (!fspLog->Open(name)) {
 
    fspLog->UseStream(&cout, "<cout>");
 
    return false;
 
  }
 
  return true;
 
}
 
 
 
//------------------------------------------+-----------------------------------
 
//! FIXME_docs
 
 
 
void RlinkConnect::LogUseStream(std::ostream* pstr, const std::string& name)
 
{
 
  fspLog->UseStream(pstr, name);
 
  return;
 
}
 
 
 
//------------------------------------------+-----------------------------------
 
//! FIXME_docs
 
 
 
void RlinkConnect::Print(std::ostream& os) const
 
{
 
  os << "RlinkConnect::Print(std::ostream& os)" << endl;
 
  return;
 
}
 
 
 
//------------------------------------------+-----------------------------------
 
//! FIXME_docs
 
 
 
void RlinkConnect::Dump(std::ostream& os, int ind, const char* text) const
 
{
 
  RosFill bl(ind);
 
  os << bl << (text?text:"--") << "RlinkConnect @ " << this << endl;
 
 
 
  if (fpPort) {
 
    fpPort->Dump(os, ind+2, "fpPort: ");
 
  } else {
 
    os << bl << "  fpPort:          " <<  fpPort.get() << endl;
 
  }
 
 
 
  os << bl << "  fpServ:          " << fpServ << endl;
 
  os << bl << "  fSeqNumber:      ";
 
  for (size_t i=0; i<8; i++) os << RosPrintBvi(fSeqNumber[i],16) << " ";
 
  os << endl;
 
 
 
  fSndPkt.Dump(os, ind+2, "fSndPkt: ");
 
  fRcvPkt.Dump(os, ind+2, "fRcvPkt: ");
 
  fContext.Dump(os, ind+2, "fContext: ");
 
  fAddrMap.Dump(os, ind+2, "fAddrMap: ");
 
  fStats.Dump(os, ind+2, "fStats: ");
 
  os << bl << "  fLogOpts.baseaddr   " << fLogOpts.baseaddr << endl;
 
  os << bl << "          .basedata   " << fLogOpts.basedata << endl;
 
  os << bl << "          .basestat   " << fLogOpts.basestat << endl;
 
  os << bl << "          .printlevel " << fLogOpts.printlevel << endl;
 
  os << bl << "          .dumplevel  " << fLogOpts.dumplevel << endl;
 
  os << bl << "          .tracelevel " << fLogOpts.tracelevel << endl;
 
  fspLog->Dump(os, ind+2, "fspLog: ");
 
  os << bl << "  fAttnNotiPatt: " << RosPrintBvi(fAttnNotiPatt,16) << endl;
 
  //FIXME_code: fTsLastAttnNoti not yet in Dump (get formatter...)
 
 
 
  return;
 
}
 
 
 
//------------------------------------------+-----------------------------------
 
//! Handle unsolicited data from port.
 
/*!
 
  Called by RlinkServer to process unsolicited input data. Will read all
 
  pending data from input port and process it with ProcessUnsolicitedData().
 
 
 
  \throws Rexception if not called from inside of an active server
 
 
 
  \pre ServerActiveInside() must be \c true.
 
 */
 
 
 
void RlinkConnect::HandleUnsolicitedData()
 
{
 
  if (!ServerActiveInside())
 
    throw Rexception("RlinkConnect::HandleUnsolicitedData()",
 
                     "only allowed inside active server");
 
 
 
  boost::lock_guard<RlinkConnect> lock(*this);
 
  RerrMsg emsg;
 
  int irc = fRcvPkt.ReadData(fpPort.get(), 0., emsg);
 
  if (irc == 0) return;
 
  if (irc < 0) {
 
    RlogMsg lmsg(*fspLog, 'E');
 
    lmsg << "HandleUnsolicitedData: IO error: " << emsg;
 
  }
 
  ProcessUnsolicitedData();
 
  return;
 
}
 
 
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! FIXME_docs
 
 
bool RlinkConnect::ExecPart(RlinkCommandList& clist, size_t ibeg, size_t iend,
bool RlinkConnect::ExecPart(RlinkCommandList& clist, size_t ibeg, size_t iend,
                            RerrMsg& emsg, RlinkContext& cntx)
                            RerrMsg& emsg, RlinkContext& cntx)
{
{
  if (ibeg<0 || ibeg>iend || iend>=clist.Size())
  if (ibeg>iend || iend>=clist.Size())
    throw Rexception("RlinkConnect::ExecPart()",
    throw Rexception("RlinkConnect::ExecPart()",
                     "Bad args: ibeg or iend invalid");
                     "Bad args: ibeg or iend invalid");
  if (!IsOpen())
  if (!IsOpen())
    throw Rexception("RlinkConnect::ExecPart()","Bad state: port not open");
    throw Rexception("RlinkConnect::ExecPart()","Bad state: port not open");
 
 
  fStats.Inc(kStatNExecPart);
  fStats.Inc(kStatNExecPart);
 
  EncodeRequest(clist, ibeg, iend);
 
 
 
  // FIXME_code: handle send fail properly;
 
  if (!fSndPkt.SndPacket(fpPort.get(), emsg)) return false;
 
  fStats.Inc(kStatNTxPktByt, double(fSndPkt.PktSize()));
 
 
 
  // FIXME_code: handle recoveries
 
  // FIXME_code: use proper value for timeout
 
  bool ok = ReadResponse(15., emsg);
 
  if (!ok) Rexception("RlinkConnect::ExecPart()","faulty response");
 
 
 
  int ncmd = DecodeResponse(clist, ibeg, iend, cntx);
 
  if (ncmd != int(iend-ibeg+1)) {
 
    clist.Dump(cout);
 
    throw Rexception("RlinkConnect::ExecPart()","incomplete response");
 
  }
 
 
  size_t nrcvtot = 0;
  AcceptResponse();
  fTxPkt.Init();
 
 
  return true;
 
}
 
 
 
//------------------------------------------+-----------------------------------
 
//! FIXME_docs
 
 
 
void RlinkConnect::EncodeRequest(RlinkCommandList& clist, size_t ibeg,
 
                                 size_t iend)
 
{
 
  fSndPkt.Init();
 
 
  for (size_t i=ibeg; i<=iend; i++) {
  for (size_t i=ibeg; i<=iend; i++) {
    RlinkCommand& cmd = clist[i];
    RlinkCommand& cmd = clist[i];
    uint8_t   ccode = cmd.Command();
    uint8_t   ccode = cmd.Command();
    size_t    ndata = cmd.BlockSize();
    size_t    ndata = cmd.BlockSize();
Line 331... Line 606...
    fStats.Inc(kStatNCmd);
    fStats.Inc(kStatNCmd);
 
 
    cmd.SetSeqNumber(fSeqNumber[ccode]++);
    cmd.SetSeqNumber(fSeqNumber[ccode]++);
    cmd.ClearFlagBit(RlinkCommand::kFlagPktBeg | RlinkCommand::kFlagPktEnd);
    cmd.ClearFlagBit(RlinkCommand::kFlagPktBeg | RlinkCommand::kFlagPktEnd);
 
 
    fTxPkt.PutWithCrc(cmd.Request());
    fSndPkt.PutWithCrc(cmd.Request());
 
 
    switch(ccode) {
    switch(ccode) {
      case RlinkCommand::kCmdRreg:
      case RlinkCommand::kCmdRreg:          // rreg command ---------------
        fStats.Inc(kStatNRreg);
        fStats.Inc(kStatNRreg);
        cmd.SetRcvSize(1+2+1+1);            // rcv: cmd+data+stat+crc
        cmd.SetRcvSize(1+2+1+2);            // rcv: cmd+data+stat+crc
        fTxPkt.PutWithCrc((uint8_t)cmd.Address());
        fSndPkt.PutWithCrc(cmd.Address());
        break;
        break;
 
 
      case RlinkCommand::kCmdRblk:
      case RlinkCommand::kCmdRblk:          // rblk command ---------------
        fStats.Inc(kStatNRblk);
        fStats.Inc(kStatNRblk);
        fStats.Inc(kStatNRblkWord, (double) ndata);
        fStats.Inc(kStatNRblkWord, (double) ndata);
        cmd.SetRcvSize(1+1+2*ndata+1+1);    // rcv: cmd+nblk+n*data+stat+crc
        cmd.SetRcvSize(1+2+2*ndata+2+1+2); // rcv: cmd+cnt+n*data+dcnt+stat+crc
        fTxPkt.PutWithCrc((uint8_t)cmd.Address());
        fSndPkt.PutWithCrc(cmd.Address());
        fTxPkt.PutWithCrc((uint8_t)(ndata-1));
        fSndPkt.PutWithCrc((uint16_t)ndata);
        break;
        break;
 
 
      case RlinkCommand::kCmdWreg:
      case RlinkCommand::kCmdWreg:          // wreg command ---------------
        fStats.Inc(kStatNWreg);
        fStats.Inc(kStatNWreg);
        cmd.SetRcvSize(1+1+1);              // rcv: cmd+stat+crc
        cmd.SetRcvSize(1+1+2);              // rcv: cmd+stat+crc
        fTxPkt.PutWithCrc((uint8_t)cmd.Address());
        fSndPkt.PutWithCrc(cmd.Address());
        fTxPkt.PutWithCrc(cmd.Data());
        fSndPkt.PutWithCrc(cmd.Data());
        break;
        break;
 
 
      case RlinkCommand::kCmdWblk:
      case RlinkCommand::kCmdWblk:          // wblk command ---------------
        fStats.Inc(kStatNWblk);
        fStats.Inc(kStatNWblk);
        fStats.Inc(kStatNWblkWord, (double) ndata);
        fStats.Inc(kStatNWblkWord, (double) ndata);
        cmd.SetRcvSize(1+1+1);              // rcv: cmd+stat+crc
        cmd.SetRcvSize(1+2+1+2);              // rcv: cmd+dcnt+stat+crc
        fTxPkt.PutWithCrc((uint8_t)cmd.Address());
        fSndPkt.PutWithCrc(cmd.Address());
        fTxPkt.PutWithCrc((uint8_t)(ndata-1));
        fSndPkt.PutWithCrc((uint16_t)ndata);
        fTxPkt.PutCrc();
        fSndPkt.PutCrc();
        for (size_t j=0; j<ndata; j++) fTxPkt.PutWithCrc(*pdata++);
        fSndPkt.PutWithCrc(pdata, ndata);
        break;
        break;
 
 
      case RlinkCommand::kCmdStat:
      case RlinkCommand::kCmdLabo:          // labo command ---------------
        fStats.Inc(kStatNStat);
        fStats.Inc(kStatNLabo);
        cmd.SetRcvSize(1+1+2+1+1);          // rcv: cmd+ccmd+data+stat+crc
        cmd.SetRcvSize(1+1+1+2);            // rcv: cmd+babo+stat+crc
        break;
        break;
      case RlinkCommand::kCmdAttn:
      case RlinkCommand::kCmdAttn:          // attn command ---------------
        fStats.Inc(kStatNAttn);
        fStats.Inc(kStatNAttn);
        cmd.SetRcvSize(1+2+1+1);            // rcv: cmd+data+stat+crc
        cmd.SetRcvSize(1+2+1+2);            // rcv: cmd+data+stat+crc
        break;
        break;
 
 
      case RlinkCommand::kCmdInit:
      case RlinkCommand::kCmdInit:          // init command ---------------
        fStats.Inc(kStatNInit);
        fStats.Inc(kStatNInit);
        cmd.SetRcvSize(1+1+1);              // rcv: cmd+stat+crc
        cmd.SetRcvSize(1+1+2);              // rcv: cmd+stat+crc
        fTxPkt.PutWithCrc((uint8_t)cmd.Address());
        fSndPkt.PutWithCrc(cmd.Address());
        fTxPkt.PutWithCrc(cmd.Data());
        fSndPkt.PutWithCrc(cmd.Data());
        break;
        break;
 
 
      default:
      default:
        throw Rexception("RlinkConnect::Exec()", "BugCheck: invalid command");
        throw Rexception("RlinkConnect::Exec()", "BugCheck: invalid command");
    }
    } // switch (ccode)
 
 
    fTxPkt.PutCrc();
    fSndPkt.PutCrc();
    cmd.SetFlagBit(RlinkCommand::kFlagSend);
    cmd.SetFlagBit(RlinkCommand::kFlagSend);
    nrcvtot += cmd.RcvSize();
  } // for (size_t i=ibeg; i<=iend; i++)
  }
 
 
 
 
  // FIXME_code: do we still need kFlagPktBeg,kFlagPktEnd ?
  clist[ibeg].SetFlagBit(RlinkCommand::kFlagPktBeg);
  clist[ibeg].SetFlagBit(RlinkCommand::kFlagPktBeg);
  clist[iend].SetFlagBit(RlinkCommand::kFlagPktEnd);
  clist[iend].SetFlagBit(RlinkCommand::kFlagPktEnd);
 
 
  // FIXME_code: handle send fail properly;
  return;
  if (!fTxPkt.SndPacket(fpPort.get(), emsg)) return false;
 
  fStats.Inc(kStatNTxPktByt, double(fTxPkt.PktSize()));
 
  fStats.Inc(kStatNTxEsc   , double(fTxPkt.Nesc()));
 
 
 
  fRxPkt.Init();
 
  // FIXME_code: parametrize timeout
 
  if (!fRxPkt.RcvPacket(fpPort.get(), nrcvtot, 15.0, emsg)) return false;
 
 
 
  // FIXME_code: handle timeout properly
 
  if (fRxPkt.TestFlag(RlinkPacketBuf::kFlagTout)) {
 
    emsg.Init("RlinkConnect::ExecPart", "timeout from RlinkPacketBuf");
 
    return false;
 
  }
  }
 
 
  // if attn seen, signal to server
//------------------------------------------+-----------------------------------
  if (fRxPkt.Nattn()) ServerSignalAttn();
//! FIXME_docs
 
 
  fStats.Inc(kStatNRxPktByt, double(fRxPkt.PktSize()));
 
  fStats.Inc(kStatNRxEsc   , double(fRxPkt.Nesc()));
 
  fStats.Inc(kStatNRxAttn  , double(fRxPkt.Nattn()));
 
  fStats.Inc(kStatNRxIdle  , double(fRxPkt.Nidle()));
 
  fStats.Inc(kStatNRxDrop  , double(fRxPkt.Ndrop()));
 
 
 
 
int RlinkConnect::DecodeResponse(RlinkCommandList& clist, size_t ibeg,
 
                                 size_t iend, RlinkContext& cntx)
 
{
  size_t ncmd = 0;
  size_t ncmd = 0;
  const char* etxt = 0;
 
 
 
  for (size_t i=ibeg; i<=iend; i++) {
  for (size_t i=ibeg; i<=iend; i++) {
    RlinkCommand& cmd = clist[i];
    RlinkCommand& cmd = clist[i];
    uint8_t   ccode = cmd.Command();
    uint8_t   ccode = cmd.Command();
    size_t    ndata = cmd.BlockSize();
    uint16_t  rdata;
    uint16_t* pdata = cmd.BlockPointer();
    uint8_t   rdata8;
 
 
    if (!fRxPkt.CheckSize(cmd.RcvSize())) {   // not enough data for cmd
    // handle commands after an active labo
      cmd.SetFlagBit(RlinkCommand::kFlagErrMiss);
    if (clist.LaboActive()) {
      etxt = "FlagErrMiss: not enough data for cmd";
      ncmd += 1;
      break;
      cmd.SetFlagBit(RlinkCommand::kFlagDone|RlinkCommand::kFlagLabo);
 
      continue;
    }
    }
 
 
    if (fRxPkt.Get8WithCrc() != cmd.Request()) { // command mismatch
    // FIXME_code: handle NAK properly !!
      cmd.SetFlagBit(RlinkCommand::kFlagErrCmd);
 
      etxt = "FlagErrCmd: command mismatch";
 
      break;
 
    }
 
 
 
    // check length mismatch in rblk here (simpler than multi-level break)
    if (!fRcvPkt.CheckSize(cmd.RcvSize())) {   // not enough data for cmd
    if (ccode == RlinkCommand::kCmdRblk) {
      cmd.SetFlagBit(RlinkCommand::kFlagErrDec);
      if (fRxPkt.Get8WithCrc() != (uint8_t)(ndata-1)) {  // length mismatch
      fStats.Inc(kStatNErrMiss);
        cmd.SetFlagBit(RlinkCommand::kFlagErrCmd);
      RlogMsg lmsg(*fspLog, 'E');
        etxt = "FlagErrCmd: length mismatch";
      lmsg << "DecodeResponse: not enough data for cmd";
        break;
      return -1;
      }
      }
 
 
 
    fRcvPkt.GetWithCrc(rdata8);
 
    if (rdata8 != cmd.Request()) { // command mismatch
 
      cmd.SetFlagBit(RlinkCommand::kFlagErrDec);
 
      fStats.Inc(kStatNErrCmd);
 
      RlogMsg lmsg(*fspLog, 'E');
 
      lmsg << "DecodeResponse: command mismatch";
 
      return -1;
    }
    }
 
 
    switch(ccode) {
    switch(ccode) {
      case RlinkCommand::kCmdRreg:
      case RlinkCommand::kCmdRreg:          // rreg command ---------------
        cmd.SetData(fRxPkt.Get16WithCrc());
        fRcvPkt.GetWithCrc(rdata);
 
        cmd.SetData(rdata);
        break;
        break;
 
 
      case RlinkCommand::kCmdRblk:
      case RlinkCommand::kCmdRblk:          // rblk command ---------------
        // length was consumed and tested already before switch()..
        fRcvPkt.GetWithCrc(rdata);
        for (size_t j=0; j<ndata; j++) *pdata++ = fRxPkt.Get16WithCrc();
        if (rdata != (uint16_t)cmd.BlockSize()) {    // length mismatch
 
          cmd.SetFlagBit(RlinkCommand::kFlagErrDec);
 
          fStats.Inc(kStatNErrLen);
 
          RlogMsg lmsg(*fspLog, 'E');
 
          lmsg << "DecodeResponse: rblk length mismatch";
 
          return -1;
 
        }
 
        fRcvPkt.GetWithCrc(cmd.BlockPointer(), cmd.BlockSize());
 
        fRcvPkt.GetWithCrc(rdata);
 
        cmd.SetBlockDone(rdata);
        break;
        break;
 
 
      case RlinkCommand::kCmdWreg:
      case RlinkCommand::kCmdWreg:          // wreg command ---------------
      case RlinkCommand::kCmdWblk:
 
        break;
        break;
 
 
      case RlinkCommand::kCmdStat:
      case RlinkCommand::kCmdWblk:          // wblk command ---------------
        cmd.SetStatRequest(fRxPkt.Get8WithCrc());
        fRcvPkt.GetWithCrc(rdata);
        cmd.SetData(fRxPkt.Get16WithCrc());
        cmd.SetBlockDone(rdata);
        break;
        break;
 
 
      case RlinkCommand::kCmdAttn:
      case RlinkCommand::kCmdLabo:          // labo command ---------------
        cmd.SetData(fRxPkt.Get16WithCrc());
        fRcvPkt.GetWithCrc(rdata8);
 
        cmd.SetData((uint16_t)rdata8);
        break;
        break;
 
 
      case RlinkCommand::kCmdInit:
      case RlinkCommand::kCmdAttn:          // attn command ---------------
 
        fRcvPkt.GetWithCrc(rdata);
 
        cmd.SetData(rdata);
        break;
        break;
    } // switch(ccode)
 
 
 
    cmd.SetStatus(fRxPkt.Get8WithCrc());
      case RlinkCommand::kCmdInit:          // init command ---------------
    if (!fRxPkt.CheckCrc()) {                 // crc mismatch
 
      cmd.SetFlagBit(RlinkCommand::kFlagErrCrc);
 
      //fStats.Inc(kStatNRxCcrc);
 
      etxt = "FlagErrCrc: crc mismatch";
 
      break;
      break;
    }
    } // switch (ccode)
 
 
    // FIXME_code: proper wblk dcrc handling...
    // crc handling
    if (ccode == RlinkCommand::kCmdWblk) {
    fRcvPkt.GetWithCrc(rdata8);
      // FIXME_code: check for dcrc flag...
    cmd.SetStatus(rdata8);
      if (false) {
    if (!fRcvPkt.CheckCrc()) {              // crc mismatch
        //fStats.Inc(kStatNRxDcrc);
      cmd.SetFlagBit(RlinkCommand::kFlagErrDec);
        break;
      fStats.Inc(kStatNErrCrc);
      }
      RlogMsg lmsg(*fspLog, 'E');
 
      lmsg << "DecodeResponse: crc mismatch";
 
      return -1;
    }
    }
 
 
    cmd.SetFlagBit(RlinkCommand::kFlagDone);
 
    ncmd += 1;
    ncmd += 1;
 
    cmd.SetFlagBit(RlinkCommand::kFlagDone);
 
 
 
    // handle active labo command, here we know that crc is ok
 
    if (ccode==RlinkCommand::kCmdLabo && cmd.Data()) {    // labo active ?
 
      clist.SetLaboIndex(i);                  // set index
 
    }
 
 
 
    // expect handling
    if (cmd.Expect()) {                     // expect object attached ?
    if (cmd.Expect()) {                     // expect object attached ?
      RlinkCommandExpect& expect = *cmd.Expect();
      RlinkCommandExpect& expect = *cmd.Expect();
      if (expect.DataIsChecked() ||
      if (expect.DataIsChecked() ||
          expect.BlockValue().size()>0) fStats.Inc(kStatNExpData);
          expect.BlockValue().size()>0) fStats.Inc(kStatNExpData);
      if (expect.StatusIsChecked())     fStats.Inc(kStatNExpStat);
      if (expect.StatusIsChecked())     fStats.Inc(kStatNExpStat);
 
 
      if (ccode==RlinkCommand::kCmdRreg || ccode==RlinkCommand::kCmdStat ||
      if (ccode==RlinkCommand::kCmdRreg ||
 
          ccode==RlinkCommand::kCmdLabo ||
          ccode==RlinkCommand::kCmdAttn) {
          ccode==RlinkCommand::kCmdAttn) {
        if (!expect.DataCheck(cmd.Data())) {
        if (!expect.DataCheck(cmd.Data())) {
          fStats.Inc(kStatNChkData);
          fStats.Inc(kStatNChkData);
          cmd.SetFlagBit(RlinkCommand::kFlagChkData);
          cmd.SetFlagBit(RlinkCommand::kFlagChkData);
        }
        }
Line 523... Line 803...
    } else {                                // no expect, use context
    } else {                                // no expect, use context
      if (!cntx.StatusCheck(cmd.Status())) {
      if (!cntx.StatusCheck(cmd.Status())) {
        fStats.Inc(kStatNChkStat);
        fStats.Inc(kStatNChkStat);
        cmd.SetFlagBit(RlinkCommand::kFlagChkStat);
        cmd.SetFlagBit(RlinkCommand::kFlagChkStat);
      }
      }
    }
    } // if (cmd.Expect())
 
 
  }
  } // for (size_t i=ibeg; i<=iend; i++)
 
 
  // FIXME_code: add proper error handling...
  // FIXME_code: check that all data is consumed !!
  if (ncmd != iend-ibeg+1) {
 
    if (etxt == 0) etxt = "not all commands processed";
 
    emsg.Init("RlinkConnect::ExecPart", etxt);
 
    return false;
 
  }
 
 
 
  return true;
  return ncmd;
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! Decodes an attention notify packet.
 
/*!
 
  \param[out]  apat  attention pattern, can be zero
 
  \returns  \c true if decode without errors, \c false otherwise
 
 */
 
 
double RlinkConnect::WaitAttn(double timeout, RerrMsg& emsg)
bool RlinkConnect::DecodeAttnNotify(uint16_t& apat)
{
{
  if (ServerActiveOutside())
  apat = 0;
    throw Rexception("RlinkConnect::WaitAttn()",
 
                     "not allowed outside avtice server");
 
 
 
  double rval = fRxPkt.WaitAttn(fpPort.get(), timeout, emsg);
  if (!fRcvPkt.CheckSize(2+2)) {            // not enough data for data+crc
  fStats.Inc(kStatNRxAttn  , double(fRxPkt.Nattn()));
    fStats.Inc(kStatNErrMiss);
  fStats.Inc(kStatNRxIdle  , double(fRxPkt.Nidle()));
    RlogMsg lmsg(*fspLog, 'E');
  fStats.Inc(kStatNRxDrop  , double(fRxPkt.Ndrop()));
    lmsg << "DecodeAttnNotify: not enough data for data+crc";
  return rval;
    return false;
}
}
 
 
//------------------------------------------+-----------------------------------
  fRcvPkt.GetWithCrc(apat);
//! FIXME_docs
 
 
 
int RlinkConnect::PollAttn(RerrMsg& emsg)
 
{
 
  if (ServerActiveOutside())
 
    throw Rexception("RlinkConnect::PollAttn()",
 
                     "not allowed outside avtice server");
 
 
 
  int rval = fRxPkt.PollAttn(fpPort.get(), emsg);
  if (!fRcvPkt.CheckCrc()) {                // crc mismatch
  fStats.Inc(kStatNRxAttn  , double(fRxPkt.Nattn()));
    fStats.Inc(kStatNErrCrc);
  fStats.Inc(kStatNRxIdle  , double(fRxPkt.Nidle()));
    RlogMsg lmsg(*fspLog, 'E');
  fStats.Inc(kStatNRxDrop  , double(fRxPkt.Ndrop()));
    lmsg << "DecodeAttnNotify: crc mismatch";
  return rval;
    return false;
}
}
 
 
//------------------------------------------+-----------------------------------
  // FIXME_code: check for extra data
//! FIXME_docs
 
 
 
bool RlinkConnect::SndOob(uint16_t addr, uint16_t data, RerrMsg& emsg)
  return true;
{
 
  boost::lock_guard<RlinkConnect> lock(*this);
 
  fStats.Inc(kStatNSndOob);
 
  return fTxPkt.SndOob(fpPort.get(), addr, data, emsg);
 
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! Read data from port until complete response packet seen.
 
/*!
 
  Any spurious data or corrupt packages, e.g. with framing errors,
 
  are logged and discarded.
 
 
bool RlinkConnect::SndAttn(RerrMsg& emsg)
  If an attention notify packet is detected it will handled with
{
  ProcessAttnNotify().
  boost::lock_guard<RlinkConnect> lock(*this);
 
  return fTxPkt.SndAttn(fpPort.get(), emsg);
 
}
 
 
 
//------------------------------------------+-----------------------------------
  The method returns \c true if a complete response packet is received.
//! FIXME_docs
  The caller will usually use DecodeResponse() and must accept the packet
 
  with AcceptResponse() afterwards.
 
 
void RlinkConnect::SetLogOpts(const LogOpts& opts)
  The method returns \c false if
{
    - no valid response packet is seen within the time given by \a timeout
  if (opts.baseaddr!=2 && opts.baseaddr!=8 && opts.baseaddr!=16)
    - an IO error occurred
    throw Rexception("RlinkConnect::SetLogOpts()",
    .
                     "Bad args: baseaddr != 2,8,16");
  An appropriate log message is generated, any partial input packet discarded.
  if (opts.basedata!=2 && opts.basedata!=8 && opts.basedata!=16)
 
    throw Rexception("RlinkConnect::SetLogOpts()",
 
                     "Bad args: basedata != 2,8,16");
 
  if (opts.basestat!=2 && opts.basestat!=8 && opts.basestat!=16)
 
    throw Rexception("RlinkConnect::SetLogOpts()",
 
                     "Bad args: basestat != 2,8,16");
 
 
 
  fLogOpts = opts;
  \param      timeout  maximal time to wait for input in sec. Must be > 0.
  if (fpPort) fpPort->SetTraceLevel(opts.tracelevel);
  \param[out] emsg     contains error description (mainly from port layer)
  return;
 
}
 
 
 
//------------------------------------------+-----------------------------------
  \returns \c true if complete response packet received
//! FIXME_docs
 
 
 
bool RlinkConnect::LogOpen(const std::string& name)
  \pre a previous response must have been accepted with AcceptResponse().
 
 */
 
 
 
bool RlinkConnect::ReadResponse(double timeout, RerrMsg& emsg)
{
{
  if (!fspLog->Open(name)) {
  double tnow = Rtools::TimeOfDayAsDouble();
    fspLog->UseStream(&cout, "<cout>");
  double tend = tnow + timeout;
 
 
 
  while (tnow < tend) {
 
    int irc = fRcvPkt.ReadData(fpPort.get(), tend-tnow, emsg);
 
    if (irc <= 0) {
 
      RlogMsg lmsg(*fspLog, 'E');
 
      lmsg << "ReadResponse: IO error or timeout: " << emsg;
    return false;
    return false;
  }
  }
 
 
 
    while (fRcvPkt.ProcessData()) {
 
      int irc = fRcvPkt.PacketState();
 
      if (irc == RlinkPacketBufRcv::kPktPend) break;
 
      if (irc == RlinkPacketBufRcv::kPktAttn) {
 
        ProcessAttnNotify();
 
      } else if (irc == RlinkPacketBufRcv::kPktResp) {
  return true;
  return true;
 
      } else {
 
        RlogMsg lmsg(*fspLog, 'E');
 
        lmsg << "ReadResponse: dropped spurious packet";
 
        fRcvPkt.AcceptPacket();
 
      }
 
    } //while (fRcvPkt.ProcessData())
 
 
 
    tnow = Rtools::TimeOfDayAsDouble();
 
 
 
  } // while (tnow < tend)
 
 
 
  {
 
    RlogMsg lmsg(*fspLog, 'E');
 
    lmsg << "ReadResponse: timeout";
 
  }
 
  fRcvPkt.AcceptPacket();
 
 
 
  return false;
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! Accept response packet received with ReadResponse().
 
/*!
 
  The packet buffer is cleared, and any still buffered input data is processed
 
  with ProcessUnsolicitedData().
 
 */
 
 
void RlinkConnect::LogUseStream(std::ostream* pstr, const std::string& name)
void RlinkConnect::AcceptResponse()
{
{
  fspLog->UseStream(pstr, name);
  fRcvPkt.AcceptPacket();
 
  ProcessUnsolicitedData();
  return;
  return;
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! Process data still pending in the input buffer.
 
/*!
 
  If an attention notify packet is detected it will handled with
 
  ProcessAttnNotify(). If a response or corrupted packet is seen
 
  it will be logged and discarded.
 
 */
 
 
void RlinkConnect::Print(std::ostream& os) const
void RlinkConnect::ProcessUnsolicitedData()
{
{
  os << "RlinkConnect::Print(std::ostream& os)" << endl;
  while (fRcvPkt.ProcessData()) {
 
    int irc = fRcvPkt.PacketState();
 
    if (irc == RlinkPacketBufRcv::kPktPend) break;
 
    if (irc == RlinkPacketBufRcv::kPktAttn) {
 
      ProcessAttnNotify();
 
    } else {
 
      fRcvPkt.AcceptPacket();
 
      RlogMsg lmsg(*fspLog, 'E');
 
      lmsg << "ProcessUnsolicitedData: dropped spurious packet";
 
    }
 
  }
  return;
  return;
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! Process attention notify packets.
 
/*!
 
  The packets is decoded with DecodeAttnNotify(). If the packet is valid and
 
  contains a non-zero attention pattern the pattern is ored to the attention
 
  notify pattern which can later be inquired with HarvestAttnNotifies().
 
  Corrupt packets are logged and discarded. Notifies with a zero pattern
 
  are silently ignored.
 
 */
 
 
void RlinkConnect::Dump(std::ostream& os, int ind, const char* text) const
void RlinkConnect::ProcessAttnNotify()
{
{
  RosFill bl(ind);
  uint16_t apat;
  os << bl << (text?text:"--") << "RlinkConnect @ " << this << endl;
  bool ok = DecodeAttnNotify(apat);
 
  fRcvPkt.AcceptPacket();
  if (fpPort) {
 
    fpPort->Dump(os, ind+2, "fpPort: ");
  if (ok) {
 
    if (apat) {
 
      if (ServerActive()) {                   // if server active
 
        fpServ->SignalAttnNotify(apat);       //   handle in RlinkServer
 
      } else {                                // otherwise
 
        fAttnNotiPatt |= apat;                //   handle in RlinkConnect
 
      }
  } else {
  } else {
    os << bl << "  fpPort:          " <<  fpPort.get() << endl;
      RlogMsg lmsg(*fspLog, 'W');
 
      lmsg << "ProcessAttnNotify: zero attn notify received";
 
    }
  }
  }
 
 
  os << bl << "  fpServ:          " << fpServ << endl;
  if (ok && fLogOpts.printlevel == 3) {
  os << bl << "  fSeqNumber:      ";
     RlogMsg lmsg(*fspLog, 'I');
  for (size_t i=0; i<8; i++) os << RosPrintBvi(fSeqNumber[i],16) << " ";
     lmsg << "ATTN notify apat = " << RosPrintf(apat,"x0",4)
  os << endl;
          << "  lams =";
 
     if (apat) {
  fTxPkt.Dump(os, ind+2, "fTxPkt: ");
       char sep = ' ';
  fRxPkt.Dump(os, ind+2, "fRxPkt: ");
       for (int i=15; i>=0; i--) {
  fContext.Dump(os, ind+2, "fContext: ");
         if (apat & (uint16_t(1)<<i) ) {
  fAddrMap.Dump(os, ind+2, "fAddrMap: ");
           lmsg << sep << i;
  fStats.Dump(os, ind+2, "fStats: ");
           sep = ',';
  os << bl << "  fLogOpts.baseaddr   " << fLogOpts.baseaddr << endl;
         }
  os << bl << "          .basedata   " << fLogOpts.basedata << endl;
       }
  os << bl << "          .basestat   " << fLogOpts.basestat << endl;
     } else {
  os << bl << "          .printlevel " << fLogOpts.printlevel << endl;
       lmsg << " !NONE!";
  os << bl << "          .dumplevel  " << fLogOpts.dumplevel << endl;
     }
  os << bl << "          .tracelevel " << fLogOpts.tracelevel << endl;
     double now = Rtools::TimeOfDayAsDouble();
  fspLog->Dump(os, ind+2, "fspLog: ");
     if (fTsLastAttnNoti > 0.)
 
       lmsg << "  dt=" << RosPrintf(now-fTsLastAttnNoti,"f",8,6);
 
     fTsLastAttnNoti = now;
 
  }
  return;
  return;
}
}
 
 
 
 
} // end namespace Retro
} // end namespace Retro
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.