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

Subversion Repositories w11

[/] [w11/] [tags/] [w11a_V0.74/] [tools/] [src/] [librlink/] [RlinkConnect.cpp] - Blame information for rev 29

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 29 wfjm
// $Id: RlinkConnect.cpp 632 2015-01-11 12:30:03Z mueller $
2 10 wfjm
//
3 28 wfjm
// Copyright 2011-2015 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4 10 wfjm
//
5
// This program is free software; you may redistribute and/or modify it under
6
// the terms of the GNU General Public License as published by the Free
7
// Software Foundation, either version 2, or at your option any later version.
8
//
9
// This program is distributed in the hope that it will be useful, but
10
// WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
11
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
// for complete details.
13
// 
14
// Revision History: 
15
// Date         Rev Version  Comment
16 29 wfjm
// 2015-01-06   631   2.1    full rlink v4 implementation
17 27 wfjm
// 2014-12-10   611   2.0    re-organize for rlink v4
18
// 2014-08-26   587   1.5    start accept rlink v4 protocol (partially...)
19
// 2014-08-15   583   1.4    rb_mreq addr now 16 bit
20 25 wfjm
// 2014-07-27   575   1.3.3  ExecPart(): increase packet tout from 5 to 15 sec
21 20 wfjm
// 2013-04-21   509   1.3.2  add SndAttn() method
22 19 wfjm
// 2013-03-01   493   1.3.1  add Server(Active..|SignalAttn)() methods
23
// 2013-02-23   492   1.3    use scoped_ptr for Port; Close allways allowed
24
//                           use RlinkContext, add Context(), Exec(..., cntx)
25
// 2013-02-22   491   1.2    use new RlogFile/RlogMsg interfaces
26
// 2013-02-03   481   1.1.2  use Rexception
27
// 2013-01-13   474   1.1.1  add PollAttn() method
28 12 wfjm
// 2011-04-25   380   1.1    use boost::(mutex&lock), implement Lockable IF
29
// 2011-04-22   379   1.0.1  add Lock(), Unlock(), lock connect in Exec()
30 10 wfjm
// 2011-04-02   375   1.0    Initial version
31
// 2011-01-15   356   0.1    First draft
32
// ---------------------------------------------------------------------------
33
 
34
/*!
35
  \file
36 29 wfjm
  \version $Id: RlinkConnect.cpp 632 2015-01-11 12:30:03Z mueller $
37 10 wfjm
  \brief   Implemenation of RlinkConnect.
38
*/
39
 
40
#include <iostream>
41
 
42 12 wfjm
#include "boost/thread/locks.hpp"
43
 
44 10 wfjm
#include "RlinkPortFactory.hpp"
45
#include "librtools/RosFill.hpp"
46
#include "librtools/RosPrintf.hpp"
47
#include "librtools/RosPrintBvi.hpp"
48 12 wfjm
#include "librtools/Rtools.hpp"
49 19 wfjm
#include "librtools/Rexception.hpp"
50
#include "librtools/RlogMsg.hpp"
51
#include "RlinkServer.hpp"
52 10 wfjm
 
53 19 wfjm
#include "RlinkConnect.hpp"
54
 
55 10 wfjm
using namespace std;
56
 
57
/*!
58
  \class Retro::RlinkConnect
59
  \brief FIXME_docs
60
*/
61
 
62 19 wfjm
// all method definitions in namespace Retro
63
namespace Retro {
64
 
65 10 wfjm
//------------------------------------------+-----------------------------------
66 27 wfjm
// constants definitions
67
 
68
const uint16_t RlinkConnect::kRbaddr_RLCNTL;
69
const uint16_t RlinkConnect::kRbaddr_RLSTAT;
70
const uint16_t RlinkConnect::kRbaddr_RLID1;
71
const uint16_t RlinkConnect::kRbaddr_RLID0;
72
 
73
const uint16_t RlinkConnect::kRLCNTL_M_AnEna;
74
const uint16_t RlinkConnect::kRLCNTL_M_AtoEna;
75
const uint16_t RlinkConnect::kRLCNTL_M_AtoVal;
76
 
77
const uint16_t RlinkConnect::kRLSTAT_V_LCmd;
78
const uint16_t RlinkConnect::kRLSTAT_B_LCmd;
79
const uint16_t RlinkConnect::kRLSTAT_M_BAbo;
80
const uint16_t RlinkConnect::kRLSTAT_M_RBSize;
81
 
82
const uint16_t RlinkConnect::kSBCNTL_V_RLMON;
83
const uint16_t RlinkConnect::kSBCNTL_V_RLBMON;
84
const uint16_t RlinkConnect::kSBCNTL_V_RBMON;
85
 
86 28 wfjm
const uint16_t RlinkConnect::kRbufBlkDelta;
87
const uint16_t RlinkConnect::kRbufPrudentDelta;
88
 
89 27 wfjm
//------------------------------------------+-----------------------------------
90 10 wfjm
//! Default constructor
91
 
92
RlinkConnect::RlinkConnect()
93 19 wfjm
  : fpPort(),
94 29 wfjm
    fpServ(nullptr),
95 27 wfjm
    fSndPkt(),
96
    fRcvPkt(),
97 19 wfjm
    fContext(),
98 10 wfjm
    fAddrMap(),
99
    fStats(),
100 29 wfjm
    fLogBaseAddr(16),
101
    fLogBaseData(16),
102
    fLogBaseStat(16),
103
    fPrintLevel(0),
104
    fDumpLevel(0),
105
    fTraceLevel(0),
106
    fspLog(new RlogFile(&cout)),
107 27 wfjm
    fConnectMutex(),
108
    fAttnNotiPatt(0),
109 28 wfjm
    fTsLastAttnNoti(-1),
110
    fSysId(0xffffffff),
111 29 wfjm
    fRbufSize(2048)
112 10 wfjm
{
113
  for (size_t i=0; i<8; i++) fSeqNumber[i] = 0;
114 12 wfjm
 
115
  // Statistic setup
116 10 wfjm
  fStats.Define(kStatNExec,     "NExec",     "Exec() calls");
117
  fStats.Define(kStatNExecPart, "NExecPart", "ExecPart() calls");
118
  fStats.Define(kStatNCmd,      "NCmd",      "commands executed");
119
  fStats.Define(kStatNRreg,     "NRreg",     "rreg commands");
120
  fStats.Define(kStatNRblk,     "NRblk",     "rblk commands");
121
  fStats.Define(kStatNWreg,     "NWreg",     "wreg commands");
122
  fStats.Define(kStatNWblk,     "NWblk",     "wblk commands");
123 27 wfjm
  fStats.Define(kStatNLabo,     "NLabo",     "labo commands");
124 10 wfjm
  fStats.Define(kStatNAttn,     "NAttn",     "attn commands");
125
  fStats.Define(kStatNInit,     "NInit",     "init commands");
126
  fStats.Define(kStatNRblkWord, "NRblkWord", "words rcvd with rblk");
127
  fStats.Define(kStatNWblkWord, "NWblkWord", "words send with wblk");
128
  fStats.Define(kStatNExpData,  "NExpData",  "Expect() for data defined");
129 28 wfjm
  fStats.Define(kStatNExpDone,  "NExpDone",  "Expect() for done defined");
130 10 wfjm
  fStats.Define(kStatNExpStat,  "NExpStat",  "Expect() for stat defined");
131
  fStats.Define(kStatNChkData,  "NChkData",  "expect data failed");
132 28 wfjm
  fStats.Define(kStatNChkDone,  "NChkData",  "expect done failed");
133 10 wfjm
  fStats.Define(kStatNChkStat,  "NChkStat",  "expect stat failed");
134
  fStats.Define(kStatNSndOob,   "NSndOob",   "SndOob() calls");
135 27 wfjm
  fStats.Define(kStatNErrMiss,  "NErrMiss",  "decode: missing data");
136
  fStats.Define(kStatNErrCmd,   "NErrCmd",   "decode: command mismatch");
137
  fStats.Define(kStatNErrLen,   "NErrLen",   "decode: length mismatch");
138
  fStats.Define(kStatNErrCrc,   "NErrCrc",   "decode: crc mismatch");
139 10 wfjm
}
140
 
141
//------------------------------------------+-----------------------------------
142
//! Destructor
143
 
144
RlinkConnect::~RlinkConnect()
145
{
146 19 wfjm
  Close();
147 10 wfjm
}
148
 
149
//------------------------------------------+-----------------------------------
150
//! FIXME_docs
151
 
152
bool RlinkConnect::Open(const std::string& name, RerrMsg& emsg)
153
{
154 19 wfjm
  Close();
155 10 wfjm
 
156 19 wfjm
  fpPort.reset(RlinkPortFactory::Open(name, emsg));
157 10 wfjm
  if (!fpPort) return false;
158
 
159 19 wfjm
  fpPort->SetLogFile(fspLog);
160 29 wfjm
  fpPort->SetTraceLevel(fTraceLevel);
161 28 wfjm
 
162
  RlinkCommandList clist;
163
  clist.AddRreg(kRbaddr_RLSTAT);
164
  clist.AddRreg(kRbaddr_RLID1);
165
  clist.AddRreg(kRbaddr_RLID0);
166
 
167
  if (!Exec(clist, emsg)) {
168
    Close();
169
    return false;
170
  }
171
 
172
  uint16_t rlstat = clist[0].Data();
173
  uint16_t rlid1  = clist[1].Data();
174
  uint16_t rlid0  = clist[2].Data();
175
 
176
  fRbufSize = size_t(1) << (10 + (rlstat & kRLSTAT_M_RBSize));
177
  fSysId    = uint32_t(rlid1)<<16 | uint32_t(rlid0);
178
 
179 10 wfjm
  return true;
180
}
181
 
182
//------------------------------------------+-----------------------------------
183
//! FIXME_docs
184
 
185
void RlinkConnect::Close()
186
{
187 19 wfjm
  if (!fpPort) return;
188 10 wfjm
 
189 19 wfjm
  if (fpServ) fpServ->Stop();               // stop server in case still running
190
 
191
  if (fpPort->Url().FindOpt("keep")) {
192 10 wfjm
    RerrMsg emsg;
193 27 wfjm
    fSndPkt.SndKeep(fpPort.get(), emsg);
194 10 wfjm
  }
195
 
196 19 wfjm
  fpPort.reset();
197 10 wfjm
 
198
  return;
199
}
200
 
201
//------------------------------------------+-----------------------------------
202 27 wfjm
//! Indicates whether server is active.
203
/*!
204
  \returns \c true if server active.
205
 */
206 10 wfjm
 
207 27 wfjm
 
208 19 wfjm
bool RlinkConnect::ServerActive() const
209
{
210
  return fpServ && fpServ->IsActive();
211
}
212
 
213
//------------------------------------------+-----------------------------------
214 27 wfjm
//! Indicates whether server is active and caller is inside server thread.
215
/*!
216
  \returns \c true if server active and method is called from server thread.
217
 */
218 19 wfjm
 
219
bool RlinkConnect::ServerActiveInside() const
220
{
221
  return fpServ && fpServ->IsActiveInside();
222
}
223
 
224
//------------------------------------------+-----------------------------------
225 27 wfjm
//! Indicates whether server is active and caller is outside server thread.
226
/*!
227
  \returns \c true if server active and method is called from a thread
228
           other than the server thread.
229
 */
230 19 wfjm
 
231
bool RlinkConnect::ServerActiveOutside() const
232
{
233
  return fpServ && fpServ->IsActiveOutside();
234
}
235
 
236
//------------------------------------------+-----------------------------------
237
//! FIXME_docs
238
 
239 12 wfjm
void RlinkConnect::lock()
240
{
241 19 wfjm
  fConnectMutex.lock();
242 12 wfjm
  return;
243
}
244
 
245
//------------------------------------------+-----------------------------------
246
//! FIXME_docs
247
 
248
bool RlinkConnect::try_lock()
249
{
250 19 wfjm
  return fConnectMutex.try_lock();
251 12 wfjm
}
252
 
253
//------------------------------------------+-----------------------------------
254
//! FIXME_docs
255
 
256
void RlinkConnect::unlock()
257
{
258 19 wfjm
  fConnectMutex.unlock();
259 12 wfjm
  return;
260
}
261
 
262
//------------------------------------------+-----------------------------------
263
//! FIXME_docs
264
 
265 19 wfjm
bool RlinkConnect::Exec(RlinkCommandList& clist, RlinkContext& cntx,
266
                        RerrMsg& emsg)
267 12 wfjm
{
268 10 wfjm
  if (clist.Size() == 0)
269 19 wfjm
    throw Rexception("RlinkConnect::Exec()", "Bad state: clist empty");
270 10 wfjm
  if (! IsOpen())
271 19 wfjm
    throw Rexception("RlinkConnect::Exec()", "Bad state: port not open");
272 10 wfjm
 
273 12 wfjm
  boost::lock_guard<RlinkConnect> lock(*this);
274
 
275 10 wfjm
  fStats.Inc(kStatNExec);
276
 
277 27 wfjm
  clist.ClearLaboIndex();
278
 
279 10 wfjm
  size_t size = clist.Size();
280
 
281
  for (size_t i=0; i<size; i++) {
282
    RlinkCommand& cmd = clist[i];
283
   if (!cmd.TestFlagAny(RlinkCommand::kFlagInit))
284 19 wfjm
     throw Rexception("RlinkConnect::Exec()",
285
                      "BugCheck: command not initialized");
286 10 wfjm
    if (cmd.Command() > RlinkCommand::kCmdInit)
287 19 wfjm
      throw Rexception("RlinkConnect::Exec()",
288
                       "BugCheck: invalid command code");
289
    // trap attn command when server running and outside server thread
290
    if (cmd.Command() == RlinkCommand::kCmdAttn && ServerActiveOutside())
291
      throw Rexception("RlinkConnect::Exec()",
292 27 wfjm
                       "attn command not allowed outside active server");
293 22 wfjm
 
294 27 wfjm
    cmd.ClearFlagBit(RlinkCommand::kFlagSend   |
295
                     RlinkCommand::kFlagDone   |
296
                     RlinkCommand::kFlagLabo   |
297
                     RlinkCommand::kFlagPktBeg |
298
                     RlinkCommand::kFlagPktEnd |
299
                     RlinkCommand::kFlagErrNak |
300
                     RlinkCommand::kFlagErrDec);
301 10 wfjm
  }
302
 
303 27 wfjm
  // old split volative logic. Currently dormant
304
  // may be later used for rtbuf size prot
305
#ifdef NEVER
306 10 wfjm
  while (ibeg < size) {
307
    size_t iend = ibeg;
308
    for (size_t i=ibeg; i<size; i++) {
309
      iend = i;
310
      if (clist[i].TestFlagAll(RlinkCommand::kFlagVol)) {
311
        fStats.Inc(kStatNSplitVol);
312
        break;
313
      }
314
    }
315 19 wfjm
    bool rc = ExecPart(clist, ibeg, iend, emsg, cntx);
316 10 wfjm
    if (!rc) return rc;
317
    ibeg = iend+1;
318
  }
319 27 wfjm
#endif
320 10 wfjm
 
321 27 wfjm
  bool rc = ExecPart(clist, 0, size-1, emsg, cntx);
322
  if (!rc) return rc;
323
 
324 10 wfjm
  bool checkseen = false;
325
  bool errorseen = false;
326
 
327
  for (size_t i=0; i<size; i++) {
328
    RlinkCommand& cmd = clist[i];
329
 
330 19 wfjm
    bool checkfound = cmd.TestFlagAny(RlinkCommand::kFlagChkStat |
331 28 wfjm
                                      RlinkCommand::kFlagChkData |
332
                                      RlinkCommand::kFlagChkDone);
333 19 wfjm
    bool errorfound = cmd.TestFlagAny(RlinkCommand::kFlagErrNak |
334 27 wfjm
                                      RlinkCommand::kFlagErrDec);
335 19 wfjm
    checkseen |= checkfound;
336
    errorseen |= errorfound;
337
    if (checkfound | errorfound) cntx.IncErrorCount();
338 10 wfjm
  }
339
 
340
  size_t loglevel = 3;
341
  if (checkseen) loglevel = 2;
342
  if (errorseen) loglevel = 1;
343 29 wfjm
  if (loglevel <= fPrintLevel) {
344 19 wfjm
    RlogMsg lmsg(*fspLog);
345 29 wfjm
    clist.Print(lmsg(), cntx, &AddrMap(), fLogBaseAddr, fLogBaseData,
346
                fLogBaseStat);
347 19 wfjm
  }
348 29 wfjm
  if (loglevel <= fDumpLevel) {
349 19 wfjm
    RlogMsg lmsg(*fspLog);
350
    clist.Dump(lmsg(), 0);
351
  }
352
 
353 10 wfjm
  return true;
354
}
355
 
356
//------------------------------------------+-----------------------------------
357
//! FIXME_docs
358
 
359 29 wfjm
void RlinkConnect::Exec(RlinkCommandList& clist, RlinkContext& cntx)
360 19 wfjm
{
361
  RerrMsg emsg;
362
  bool rc = Exec(clist, cntx, emsg);
363
  if (!rc) {
364 29 wfjm
    RlogMsg lmsg(*fspLog, 'F');
365 19 wfjm
    lmsg << emsg << endl;
366
    lmsg << "Dump of failed clist:" << endl;
367
    clist.Dump(lmsg(), 0);
368
  }
369 29 wfjm
  if (!rc)
370
    throw Rexception("RlinkConnect::Exec", "Exec() failed: ", emsg);
371
  return;
372 19 wfjm
}
373
 
374
//------------------------------------------+-----------------------------------
375 27 wfjm
//! Wait for an attention notify.
376
/*!
377
  First checks whether there are received and not yet harvested notifies.
378
  In that case the cummulative pattern of these pending notifies is returned
379
  in \a apat, and a 0. return value.
380
 
381
  If a positive \a timeout is specified the method waits this long for a
382
  valid and non-zero attention notify.
383
 
384
  \param      timeout  maximal time to wait for input in sec. Must be >= 0.
385
                       A zero \a timeout can be used to only harvest pending
386
                       notifies without waiting for new ones.
387
  \param[out] apat     cummulative attention pattern
388
  \param[out] emsg     contains error description (mainly from port layer)
389
 
390
  \returns wait time, or a negative value indicating an error:
391
    - =0.  if there was already a received and not yet harvested notify
392
    - >0   the wait time till the nofity was received
393
    - -1.  indicates timeout (\a apat will be 0)
394
    - -2.  indicates port IO error (\a emsg will contain information)
395
 
396
  \throws Rexception if called outside of an active server
397
 
398
  \pre ServerActiveOutside() must be \c false.
399
 
400
 */
401
 
402
double RlinkConnect::WaitAttn(double timeout, uint16_t& apat, RerrMsg& emsg)
403
{
404
  if (ServerActiveOutside())
405
    throw Rexception("RlinkConnect::WaitAttn()",
406
                     "not allowed outside active server");
407
 
408
  apat = 0;
409
 
410
  boost::lock_guard<RlinkConnect> lock(*this);
411
 
412
  // harvest pending notifiers
413
  if (fAttnNotiPatt != 0) {
414
    apat = fAttnNotiPatt;
415
    fAttnNotiPatt = 0;
416
    return 0.;
417
  }
418
 
419
  // quit if poll only (zero timeout) 
420
  if (timeout == 0.) return -1.;
421
 
422
  // wait for new notifier
423
  double tnow = Rtools::TimeOfDayAsDouble();
424
  double tend = tnow + timeout;
425
  double tbeg = tnow;
426
 
427
  while (tnow < tend) {
428
    int irc = fRcvPkt.ReadData(fpPort.get(), tend-tnow, emsg);
429
    if (irc == RlinkPort::kTout) return -1.;
430
    if (irc == RlinkPort::kErr)  return -2.;
431
    tnow = Rtools::TimeOfDayAsDouble();
432
    while (fRcvPkt.ProcessData()) {
433
      int irc = fRcvPkt.PacketState();
434
      if (irc == RlinkPacketBufRcv::kPktPend) break;
435
      if (irc == RlinkPacketBufRcv::kPktAttn) {
436
        ProcessAttnNotify();
437
        if (fAttnNotiPatt != 0) {
438
          apat = fAttnNotiPatt;
439
          fAttnNotiPatt = 0;
440
          return tnow - tbeg;
441
        }
442
      } else {
443
        RlogMsg lmsg(*fspLog, 'E');
444
        lmsg << "WaitAttn: dropped spurious packet";
445
        fRcvPkt.AcceptPacket();
446
      }
447
 
448
    } // while (fRcvPkt.ProcessData())
449
  } // while (tnow < tend)
450
 
451
  return -1;
452
}
453
 
454
//------------------------------------------+-----------------------------------
455 19 wfjm
//! FIXME_docs
456
 
457 27 wfjm
bool RlinkConnect::SndOob(uint16_t addr, uint16_t data, RerrMsg& emsg)
458
{
459
  boost::lock_guard<RlinkConnect> lock(*this);
460
  fStats.Inc(kStatNSndOob);
461
  return fSndPkt.SndOob(fpPort.get(), addr, data, emsg);
462
}
463
 
464
//------------------------------------------+-----------------------------------
465
//! FIXME_docs
466
 
467
bool RlinkConnect::SndAttn(RerrMsg& emsg)
468
{
469
  boost::lock_guard<RlinkConnect> lock(*this);
470
  return fSndPkt.SndAttn(fpPort.get(), emsg);
471
}
472
 
473
//------------------------------------------+-----------------------------------
474
//! FIXME_docs
475
 
476 29 wfjm
void RlinkConnect::SetLogBaseAddr(uint32_t base)
477 27 wfjm
{
478 29 wfjm
  if (base!=2 && base!=8 && base!=16)
479
    throw Rexception("RlinkConnect::SetLogBaseAddr()",
480
                     "Bad args: base != 2,8,16");
481
  fLogBaseAddr = base;
482
  return;
483
}
484
 
485
//------------------------------------------+-----------------------------------
486
//! FIXME_docs
487 27 wfjm
 
488 29 wfjm
void RlinkConnect::SetLogBaseData(uint32_t base)
489
{
490
  if (base!=2 && base!=8 && base!=16)
491
    throw Rexception("RlinkConnect::SetLogBaseData()",
492
                     "Bad args: base != 2,8,16");
493
  fLogBaseData = base;
494 27 wfjm
  return;
495
}
496 29 wfjm
 
497
//------------------------------------------+-----------------------------------
498
//! FIXME_docs
499 27 wfjm
 
500 29 wfjm
void RlinkConnect::SetLogBaseStat(uint32_t base)
501
{
502
  if (base!=2 && base!=8 && base!=16)
503
    throw Rexception("RlinkConnect::SetLogBaseStat()",
504
                     "Bad args: base != 2,8,16");
505
  fLogBaseStat = base;
506
  return;
507
}
508
 
509 27 wfjm
//------------------------------------------+-----------------------------------
510
//! FIXME_docs
511
 
512 29 wfjm
void RlinkConnect::SetPrintLevel(uint32_t lvl)
513 27 wfjm
{
514 29 wfjm
  fPrintLevel = lvl;
515
  return;
516
}
517
 
518
//------------------------------------------+-----------------------------------
519
//! FIXME_docs
520
 
521
void RlinkConnect::SetDumpLevel(uint32_t lvl)
522
{
523
  fDumpLevel = lvl;
524
  return;
525
}
526
 
527
//------------------------------------------+-----------------------------------
528
//! FIXME_docs
529
 
530
void RlinkConnect::SetTraceLevel(uint32_t lvl)
531
{
532
  fTraceLevel = lvl;
533
  if (fpPort) fpPort->SetTraceLevel(lvl);
534
  return;
535
}
536
 
537
//------------------------------------------+-----------------------------------
538
//! FIXME_docs
539
 
540
bool RlinkConnect::LogOpen(const std::string& name, RerrMsg& emsg)
541
{
542
  if (!fspLog->Open(name, emsg)) {
543
    fspLog->UseStream(&cout);
544 27 wfjm
    return false;
545
  }
546
  return true;
547
}
548
 
549
//------------------------------------------+-----------------------------------
550
//! FIXME_docs
551
 
552
void RlinkConnect::LogUseStream(std::ostream* pstr, const std::string& name)
553
{
554
  fspLog->UseStream(pstr, name);
555
  return;
556
}
557
 
558
//------------------------------------------+-----------------------------------
559
//! FIXME_docs
560
 
561 29 wfjm
void RlinkConnect::SetLogFileName(const std::string& name)
562
{
563
  RerrMsg emsg;
564
  if (!LogOpen(name, emsg)) {
565
    throw Rexception("RlinkConnect::SetLogFile",
566
                     emsg.Text() + "', using stdout");
567
  }
568
  return;
569
}
570
 
571
//------------------------------------------+-----------------------------------
572
//! FIXME_docs
573
 
574 27 wfjm
void RlinkConnect::Print(std::ostream& os) const
575
{
576
  os << "RlinkConnect::Print(std::ostream& os)" << endl;
577
  return;
578
}
579
 
580
//------------------------------------------+-----------------------------------
581
//! FIXME_docs
582
 
583
void RlinkConnect::Dump(std::ostream& os, int ind, const char* text) const
584
{
585
  RosFill bl(ind);
586
  os << bl << (text?text:"--") << "RlinkConnect @ " << this << endl;
587
 
588
  if (fpPort) {
589
    fpPort->Dump(os, ind+2, "fpPort: ");
590
  } else {
591
    os << bl << "  fpPort:          " <<  fpPort.get() << endl;
592
  }
593
 
594
  os << bl << "  fpServ:          " << fpServ << endl;
595
  os << bl << "  fSeqNumber:      ";
596
  for (size_t i=0; i<8; i++) os << RosPrintBvi(fSeqNumber[i],16) << " ";
597
  os << endl;
598
 
599
  fSndPkt.Dump(os, ind+2, "fSndPkt: ");
600
  fRcvPkt.Dump(os, ind+2, "fRcvPkt: ");
601
  fContext.Dump(os, ind+2, "fContext: ");
602
  fAddrMap.Dump(os, ind+2, "fAddrMap: ");
603
  fStats.Dump(os, ind+2, "fStats: ");
604 29 wfjm
  os << bl << "  fLogBaseAddr:    " << fLogBaseAddr << endl;
605
  os << bl << "  fLogBaseData:    " << fLogBaseData << endl;
606
  os << bl << "  fLogBaseStat:    " << fLogBaseStat << endl;
607
  os << bl << "  fPrintLevel:     " << fPrintLevel << endl;
608
  os << bl << "  fDumpLevel       " << fDumpLevel << endl;
609
  os << bl << "  fTraceLevel      " << fTraceLevel << endl;
610 27 wfjm
  fspLog->Dump(os, ind+2, "fspLog: ");
611
  os << bl << "  fAttnNotiPatt: " << RosPrintBvi(fAttnNotiPatt,16) << endl;
612
  //FIXME_code: fTsLastAttnNoti not yet in Dump (get formatter...)
613
 
614
  return;
615
}
616
 
617
//------------------------------------------+-----------------------------------
618
//! Handle unsolicited data from port.
619
/*!
620
  Called by RlinkServer to process unsolicited input data. Will read all
621
  pending data from input port and process it with ProcessUnsolicitedData().
622
 
623
  \throws Rexception if not called from inside of an active server
624
 
625
  \pre ServerActiveInside() must be \c true.
626
 */
627
 
628
void RlinkConnect::HandleUnsolicitedData()
629
{
630
  if (!ServerActiveInside())
631
    throw Rexception("RlinkConnect::HandleUnsolicitedData()",
632
                     "only allowed inside active server");
633
 
634
  boost::lock_guard<RlinkConnect> lock(*this);
635
  RerrMsg emsg;
636
  int irc = fRcvPkt.ReadData(fpPort.get(), 0., emsg);
637
  if (irc == 0) return;
638
  if (irc < 0) {
639
    RlogMsg lmsg(*fspLog, 'E');
640
    lmsg << "HandleUnsolicitedData: IO error: " << emsg;
641
  }
642
  ProcessUnsolicitedData();
643
  return;
644
}
645
 
646
//------------------------------------------+-----------------------------------
647
//! FIXME_docs
648
 
649 10 wfjm
bool RlinkConnect::ExecPart(RlinkCommandList& clist, size_t ibeg, size_t iend,
650 19 wfjm
                            RerrMsg& emsg, RlinkContext& cntx)
651 27 wfjm
{
652
  if (ibeg>iend || iend>=clist.Size())
653 19 wfjm
    throw Rexception("RlinkConnect::ExecPart()",
654
                     "Bad args: ibeg or iend invalid");
655 10 wfjm
  if (!IsOpen())
656 19 wfjm
    throw Rexception("RlinkConnect::ExecPart()","Bad state: port not open");
657 10 wfjm
 
658
  fStats.Inc(kStatNExecPart);
659 27 wfjm
  EncodeRequest(clist, ibeg, iend);
660 10 wfjm
 
661 27 wfjm
  // FIXME_code: handle send fail properly;
662
  if (!fSndPkt.SndPacket(fpPort.get(), emsg)) return false;
663 10 wfjm
 
664 27 wfjm
  // FIXME_code: handle recoveries
665
  // FIXME_code: use proper value for timeout
666
  bool ok = ReadResponse(15., emsg);
667
  if (!ok) Rexception("RlinkConnect::ExecPart()","faulty response");
668
 
669
  int ncmd = DecodeResponse(clist, ibeg, iend, cntx);
670
  if (ncmd != int(iend-ibeg+1)) {
671
    clist.Dump(cout);
672
    throw Rexception("RlinkConnect::ExecPart()","incomplete response");
673
  }
674
 
675
  AcceptResponse();
676
 
677
  return true;
678
}
679
 
680
//------------------------------------------+-----------------------------------
681
//! FIXME_docs
682
 
683
void RlinkConnect::EncodeRequest(RlinkCommandList& clist, size_t ibeg,
684
                                 size_t iend)
685
{
686
  fSndPkt.Init();
687
 
688 10 wfjm
  for (size_t i=ibeg; i<=iend; i++) {
689
    RlinkCommand& cmd = clist[i];
690
    uint8_t   ccode = cmd.Command();
691
    size_t    ndata = cmd.BlockSize();
692
    uint16_t* pdata = cmd.BlockPointer();
693
 
694
    fStats.Inc(kStatNCmd);
695
 
696
    cmd.SetSeqNumber(fSeqNumber[ccode]++);
697
    cmd.ClearFlagBit(RlinkCommand::kFlagPktBeg | RlinkCommand::kFlagPktEnd);
698
 
699 27 wfjm
    fSndPkt.PutWithCrc(cmd.Request());
700 10 wfjm
 
701 27 wfjm
    switch (ccode) {
702
      case RlinkCommand::kCmdRreg:          // rreg command ---------------
703 10 wfjm
        fStats.Inc(kStatNRreg);
704 27 wfjm
        cmd.SetRcvSize(1+2+1+2);            // rcv: cmd+data+stat+crc
705
        fSndPkt.PutWithCrc(cmd.Address());
706 10 wfjm
        break;
707
 
708 27 wfjm
      case RlinkCommand::kCmdRblk:          // rblk command ---------------
709 10 wfjm
        fStats.Inc(kStatNRblk);
710
        fStats.Inc(kStatNRblkWord, (double) ndata);
711 27 wfjm
        cmd.SetRcvSize(1+2+2*ndata+2+1+2); // rcv: cmd+cnt+n*data+dcnt+stat+crc
712
        fSndPkt.PutWithCrc(cmd.Address());
713
        fSndPkt.PutWithCrc((uint16_t)ndata);
714 10 wfjm
        break;
715
 
716 27 wfjm
      case RlinkCommand::kCmdWreg:          // wreg command ---------------
717 10 wfjm
        fStats.Inc(kStatNWreg);
718 27 wfjm
        cmd.SetRcvSize(1+1+2);              // rcv: cmd+stat+crc
719
        fSndPkt.PutWithCrc(cmd.Address());
720
        fSndPkt.PutWithCrc(cmd.Data());
721 10 wfjm
        break;
722
 
723 27 wfjm
      case RlinkCommand::kCmdWblk:          // wblk command ---------------
724 10 wfjm
        fStats.Inc(kStatNWblk);
725
        fStats.Inc(kStatNWblkWord, (double) ndata);
726 27 wfjm
        cmd.SetRcvSize(1+2+1+2);              // rcv: cmd+dcnt+stat+crc
727
        fSndPkt.PutWithCrc(cmd.Address());
728
        fSndPkt.PutWithCrc((uint16_t)ndata);
729
        fSndPkt.PutCrc();
730
        fSndPkt.PutWithCrc(pdata, ndata);
731 10 wfjm
        break;
732
 
733 27 wfjm
      case RlinkCommand::kCmdLabo:          // labo command ---------------
734
        fStats.Inc(kStatNLabo);
735
        cmd.SetRcvSize(1+1+1+2);            // rcv: cmd+babo+stat+crc
736 10 wfjm
        break;
737 27 wfjm
      case RlinkCommand::kCmdAttn:          // attn command ---------------
738 10 wfjm
        fStats.Inc(kStatNAttn);
739 27 wfjm
        cmd.SetRcvSize(1+2+1+2);            // rcv: cmd+data+stat+crc
740 10 wfjm
        break;
741
 
742 27 wfjm
      case RlinkCommand::kCmdInit:          // init command ---------------
743 10 wfjm
        fStats.Inc(kStatNInit);
744 27 wfjm
        cmd.SetRcvSize(1+1+2);              // rcv: cmd+stat+crc
745
        fSndPkt.PutWithCrc(cmd.Address());
746
        fSndPkt.PutWithCrc(cmd.Data());
747 10 wfjm
        break;
748
 
749
      default:
750 19 wfjm
        throw Rexception("RlinkConnect::Exec()", "BugCheck: invalid command");
751 27 wfjm
    } // switch (ccode)
752 10 wfjm
 
753 27 wfjm
    fSndPkt.PutCrc();
754 10 wfjm
    cmd.SetFlagBit(RlinkCommand::kFlagSend);
755 27 wfjm
  } // for (size_t i=ibeg; i<=iend; i++)
756 10 wfjm
 
757 27 wfjm
  // FIXME_code: do we still need kFlagPktBeg,kFlagPktEnd ?
758 10 wfjm
  clist[ibeg].SetFlagBit(RlinkCommand::kFlagPktBeg);
759
  clist[iend].SetFlagBit(RlinkCommand::kFlagPktEnd);
760
 
761 27 wfjm
  return;
762
}
763
 
764
//------------------------------------------+-----------------------------------
765
//! FIXME_docs
766 10 wfjm
 
767 27 wfjm
int RlinkConnect::DecodeResponse(RlinkCommandList& clist, size_t ibeg,
768
                                 size_t iend, RlinkContext& cntx)
769
{
770 10 wfjm
  size_t ncmd = 0;
771 27 wfjm
 
772 10 wfjm
  for (size_t i=ibeg; i<=iend; i++) {
773
    RlinkCommand& cmd = clist[i];
774
    uint8_t   ccode = cmd.Command();
775 27 wfjm
    uint16_t  rdata;
776
    uint8_t   rdata8;
777 10 wfjm
 
778 27 wfjm
    // handle commands after an active labo
779
    if (clist.LaboActive()) {
780
      ncmd += 1;
781
      cmd.SetFlagBit(RlinkCommand::kFlagDone|RlinkCommand::kFlagLabo);
782
      continue;
783 10 wfjm
    }
784 27 wfjm
 
785
    // FIXME_code: handle NAK properly !!
786
 
787
    if (!fRcvPkt.CheckSize(cmd.RcvSize())) {   // not enough data for cmd
788
      cmd.SetFlagBit(RlinkCommand::kFlagErrDec);
789
      fStats.Inc(kStatNErrMiss);
790
      RlogMsg lmsg(*fspLog, 'E');
791
      lmsg << "DecodeResponse: not enough data for cmd";
792
      return -1;
793
    }
794 10 wfjm
 
795 27 wfjm
    fRcvPkt.GetWithCrc(rdata8);
796
    if (rdata8 != cmd.Request()) { // command mismatch
797
      cmd.SetFlagBit(RlinkCommand::kFlagErrDec);
798
      fStats.Inc(kStatNErrCmd);
799
      RlogMsg lmsg(*fspLog, 'E');
800
      lmsg << "DecodeResponse: command mismatch";
801
      return -1;
802 10 wfjm
    }
803
 
804 27 wfjm
    switch (ccode) {
805
      case RlinkCommand::kCmdRreg:          // rreg command ---------------
806
        fRcvPkt.GetWithCrc(rdata);
807
        cmd.SetData(rdata);
808 10 wfjm
        break;
809
 
810 27 wfjm
      case RlinkCommand::kCmdRblk:          // rblk command ---------------
811
        fRcvPkt.GetWithCrc(rdata);
812
        if (rdata != (uint16_t)cmd.BlockSize()) {    // length mismatch
813
          cmd.SetFlagBit(RlinkCommand::kFlagErrDec);
814
          fStats.Inc(kStatNErrLen);
815
          RlogMsg lmsg(*fspLog, 'E');
816
          lmsg << "DecodeResponse: rblk length mismatch";
817
          return -1;
818
        }
819
        fRcvPkt.GetWithCrc(cmd.BlockPointer(), cmd.BlockSize());
820
        fRcvPkt.GetWithCrc(rdata);
821
        cmd.SetBlockDone(rdata);
822
       break;
823 10 wfjm
 
824 27 wfjm
      case RlinkCommand::kCmdWreg:          // wreg command ---------------
825 10 wfjm
        break;
826
 
827 27 wfjm
      case RlinkCommand::kCmdWblk:          // wblk command ---------------
828
        fRcvPkt.GetWithCrc(rdata);
829
        cmd.SetBlockDone(rdata);
830
       break;
831 10 wfjm
 
832 27 wfjm
      case RlinkCommand::kCmdLabo:          // labo command ---------------
833
        fRcvPkt.GetWithCrc(rdata8);
834
        cmd.SetData((uint16_t)rdata8);
835 10 wfjm
        break;
836
 
837 27 wfjm
      case RlinkCommand::kCmdAttn:          // attn command ---------------
838
        fRcvPkt.GetWithCrc(rdata);
839
        cmd.SetData(rdata);
840 10 wfjm
        break;
841
 
842 27 wfjm
      case RlinkCommand::kCmdInit:          // init command ---------------
843 10 wfjm
        break;
844 27 wfjm
    } // switch (ccode)
845 10 wfjm
 
846 27 wfjm
    // crc handling
847
    fRcvPkt.GetWithCrc(rdata8);
848
    cmd.SetStatus(rdata8);
849
    if (!fRcvPkt.CheckCrc()) {              // crc mismatch
850
      cmd.SetFlagBit(RlinkCommand::kFlagErrDec);
851
      fStats.Inc(kStatNErrCrc);
852
      RlogMsg lmsg(*fspLog, 'E');
853
      lmsg << "DecodeResponse: crc mismatch";
854
      return -1;
855 10 wfjm
    }
856
 
857 27 wfjm
    ncmd += 1;
858
    cmd.SetFlagBit(RlinkCommand::kFlagDone);
859
 
860
    // handle active labo command, here we know that crc is ok
861
    if (ccode==RlinkCommand::kCmdLabo && cmd.Data()) {    // labo active ?
862
      clist.SetLaboIndex(i);                  // set index
863 10 wfjm
    }
864
 
865 27 wfjm
    // expect handling
866 19 wfjm
    if (cmd.Expect()) {                     // expect object attached ?
867 10 wfjm
      RlinkCommandExpect& expect = *cmd.Expect();
868 28 wfjm
      if (ccode==RlinkCommand::kCmdRblk ||
869
          ccode==RlinkCommand::kCmdWblk) {
870
        if (expect.BlockValue().size()>0) fStats.Inc(kStatNExpData);
871
        if (expect.DoneIsChecked()) fStats.Inc(kStatNExpDone);
872
      } else {
873
        if (expect.DataIsChecked()) fStats.Inc(kStatNExpData);
874
      }
875 10 wfjm
      if (expect.StatusIsChecked())     fStats.Inc(kStatNExpStat);
876
 
877 27 wfjm
      if (ccode==RlinkCommand::kCmdRreg ||
878
          ccode==RlinkCommand::kCmdLabo ||
879 10 wfjm
          ccode==RlinkCommand::kCmdAttn) {
880
        if (!expect.DataCheck(cmd.Data())) {
881
          fStats.Inc(kStatNChkData);
882
          cmd.SetFlagBit(RlinkCommand::kFlagChkData);
883
        }
884
      } else if (ccode==RlinkCommand::kCmdRblk) {
885
        size_t nerr = expect.BlockCheck(cmd.BlockPointer(), cmd.BlockSize());
886
        if (nerr != 0) {
887
          fStats.Inc(kStatNChkData);
888
          cmd.SetFlagBit(RlinkCommand::kFlagChkData);
889
        }
890
      }
891 28 wfjm
      if (ccode==RlinkCommand::kCmdRblk ||
892
          ccode==RlinkCommand::kCmdWblk) {
893
        if (!expect.DoneCheck(cmd.BlockDone())) {
894
          fStats.Inc(kStatNChkDone);
895
          cmd.SetFlagBit(RlinkCommand::kFlagChkDone);
896
        }
897
     }
898 10 wfjm
      if (!expect.StatusCheck(cmd.Status())) {
899
        fStats.Inc(kStatNChkStat);
900
        cmd.SetFlagBit(RlinkCommand::kFlagChkStat);
901
      }
902 19 wfjm
 
903
    } else {                                // no expect, use context
904
      if (!cntx.StatusCheck(cmd.Status())) {
905
        fStats.Inc(kStatNChkStat);
906
        cmd.SetFlagBit(RlinkCommand::kFlagChkStat);
907
      }
908 27 wfjm
    } // if (cmd.Expect())
909 10 wfjm
 
910 27 wfjm
  } // for (size_t i=ibeg; i<=iend; i++)
911 10 wfjm
 
912 27 wfjm
  // FIXME_code: check that all data is consumed !!
913 10 wfjm
 
914 27 wfjm
  return ncmd;
915 10 wfjm
}
916
 
917
//------------------------------------------+-----------------------------------
918 27 wfjm
//! Decodes an attention notify packet.
919
/*!
920
  \param[out]  apat  attention pattern, can be zero
921
  \returns  \c true if decode without errors, \c false otherwise
922
 */
923 10 wfjm
 
924 27 wfjm
bool RlinkConnect::DecodeAttnNotify(uint16_t& apat)
925 10 wfjm
{
926 27 wfjm
  apat = 0;
927
 
928
  if (!fRcvPkt.CheckSize(2+2)) {            // not enough data for data+crc
929
    fStats.Inc(kStatNErrMiss);
930
    RlogMsg lmsg(*fspLog, 'E');
931
    lmsg << "DecodeAttnNotify: not enough data for data+crc";
932
    return false;
933
  }
934 19 wfjm
 
935 27 wfjm
  fRcvPkt.GetWithCrc(apat);
936 10 wfjm
 
937 27 wfjm
  if (!fRcvPkt.CheckCrc()) {                // crc mismatch
938
    fStats.Inc(kStatNErrCrc);
939
    RlogMsg lmsg(*fspLog, 'E');
940
    lmsg << "DecodeAttnNotify: crc mismatch";
941
    return false;
942
  }
943 10 wfjm
 
944 27 wfjm
  // FIXME_code: check for extra data
945
 
946
  return true;
947 19 wfjm
}
948
 
949
//------------------------------------------+-----------------------------------
950 27 wfjm
//! Read data from port until complete response packet seen.
951
/*!
952
  Any spurious data or corrupt packages, e.g. with framing errors,
953
  are logged and discarded.
954 19 wfjm
 
955 27 wfjm
  If an attention notify packet is detected it will handled with
956
  ProcessAttnNotify().
957 10 wfjm
 
958 27 wfjm
  The method returns \c true if a complete response packet is received.
959
  The caller will usually use DecodeResponse() and must accept the packet
960
  with AcceptResponse() afterwards.
961 10 wfjm
 
962 27 wfjm
  The method returns \c false if
963
    - no valid response packet is seen within the time given by \a timeout
964
    - an IO error occurred
965
    .
966
  An appropriate log message is generated, any partial input packet discarded.
967 20 wfjm
 
968 27 wfjm
  \param      timeout  maximal time to wait for input in sec. Must be > 0.
969
  \param[out] emsg     contains error description (mainly from port layer)
970 20 wfjm
 
971 27 wfjm
  \returns \c true if complete response packet received
972
 
973
  \pre a previous response must have been accepted with AcceptResponse().
974
 */
975
 
976
bool RlinkConnect::ReadResponse(double timeout, RerrMsg& emsg)
977 10 wfjm
{
978 27 wfjm
  double tnow = Rtools::TimeOfDayAsDouble();
979
  double tend = tnow + timeout;
980 19 wfjm
 
981 27 wfjm
  while (tnow < tend) {
982
    int irc = fRcvPkt.ReadData(fpPort.get(), tend-tnow, emsg);
983
    if (irc <= 0) {
984
      RlogMsg lmsg(*fspLog, 'E');
985
      lmsg << "ReadResponse: IO error or timeout: " << emsg;
986
      return false;
987
    }
988 10 wfjm
 
989 27 wfjm
    while (fRcvPkt.ProcessData()) {
990
      int irc = fRcvPkt.PacketState();
991
      if (irc == RlinkPacketBufRcv::kPktPend) break;
992
      if (irc == RlinkPacketBufRcv::kPktAttn) {
993
        ProcessAttnNotify();
994
      } else if (irc == RlinkPacketBufRcv::kPktResp) {
995
        return true;
996
      } else {
997
        RlogMsg lmsg(*fspLog, 'E');
998
        lmsg << "ReadResponse: dropped spurious packet";
999
        fRcvPkt.AcceptPacket();
1000
      }
1001
    } //while (fRcvPkt.ProcessData())
1002 10 wfjm
 
1003 27 wfjm
    tnow = Rtools::TimeOfDayAsDouble();
1004
 
1005
  } // while (tnow < tend)
1006
 
1007
  {
1008
    RlogMsg lmsg(*fspLog, 'E');
1009
    lmsg << "ReadResponse: timeout";
1010 19 wfjm
  }
1011 27 wfjm
  fRcvPkt.AcceptPacket();
1012
 
1013
  return false;
1014 10 wfjm
}
1015
 
1016
//------------------------------------------+-----------------------------------
1017 27 wfjm
//! Accept response packet received with ReadResponse().
1018
/*!
1019
  The packet buffer is cleared, and any still buffered input data is processed
1020
  with ProcessUnsolicitedData().
1021
 */
1022 10 wfjm
 
1023 27 wfjm
void RlinkConnect::AcceptResponse()
1024 10 wfjm
{
1025 27 wfjm
  fRcvPkt.AcceptPacket();
1026
  ProcessUnsolicitedData();
1027 10 wfjm
  return;
1028
}
1029 27 wfjm
 
1030 10 wfjm
//------------------------------------------+-----------------------------------
1031 27 wfjm
//! Process data still pending in the input buffer.
1032
/*!
1033
  If an attention notify packet is detected it will handled with
1034
  ProcessAttnNotify(). If a response or corrupted packet is seen
1035
  it will be logged and discarded.
1036
 */
1037 10 wfjm
 
1038 27 wfjm
void RlinkConnect::ProcessUnsolicitedData()
1039 10 wfjm
{
1040 27 wfjm
  while (fRcvPkt.ProcessData()) {
1041
    int irc = fRcvPkt.PacketState();
1042
    if (irc == RlinkPacketBufRcv::kPktPend) break;
1043
    if (irc == RlinkPacketBufRcv::kPktAttn) {
1044
      ProcessAttnNotify();
1045
    } else {
1046
      fRcvPkt.AcceptPacket();
1047
      RlogMsg lmsg(*fspLog, 'E');
1048
      lmsg << "ProcessUnsolicitedData: dropped spurious packet";
1049
    }
1050
  }
1051 10 wfjm
  return;
1052
}
1053
 
1054
//------------------------------------------+-----------------------------------
1055 27 wfjm
//! Process attention notify packets.
1056
/*!
1057
  The packets is decoded with DecodeAttnNotify(). If the packet is valid and
1058
  contains a non-zero attention pattern the pattern is ored to the attention
1059
  notify pattern which can later be inquired with HarvestAttnNotifies().
1060
  Corrupt packets are logged and discarded. Notifies with a zero pattern
1061
  are silently ignored.
1062
 */
1063 10 wfjm
 
1064 27 wfjm
void RlinkConnect::ProcessAttnNotify()
1065 10 wfjm
{
1066 27 wfjm
  uint16_t apat;
1067
  bool ok = DecodeAttnNotify(apat);
1068
  fRcvPkt.AcceptPacket();
1069 10 wfjm
 
1070 27 wfjm
  if (ok) {
1071
    if (apat) {
1072
      if (ServerActive()) {                   // if server active
1073
        fpServ->SignalAttnNotify(apat);       //   handle in RlinkServer
1074
      } else {                                // otherwise
1075
        fAttnNotiPatt |= apat;                //   handle in RlinkConnect
1076
      }
1077
    } else {
1078
      RlogMsg lmsg(*fspLog, 'W');
1079
      lmsg << "ProcessAttnNotify: zero attn notify received";
1080
    }
1081 10 wfjm
  }
1082
 
1083 29 wfjm
  if (ok && fPrintLevel == 3) {
1084 27 wfjm
     RlogMsg lmsg(*fspLog, 'I');
1085
     lmsg << "ATTN notify apat = " << RosPrintf(apat,"x0",4)
1086
          << "  lams =";
1087
     if (apat) {
1088
       char sep = ' ';
1089
       for (int i=15; i>=0; i--) {
1090
         if (apat & (uint16_t(1)<<i) ) {
1091
           lmsg << sep << i;
1092
           sep = ',';
1093
         }
1094
       }
1095
     } else {
1096
       lmsg << " !NONE!";
1097
     }
1098
     double now = Rtools::TimeOfDayAsDouble();
1099
     if (fTsLastAttnNoti > 0.)
1100
       lmsg << "  dt=" << RosPrintf(now-fTsLastAttnNoti,"f",8,6);
1101
     fTsLastAttnNoti = now;
1102
  }
1103 10 wfjm
  return;
1104
}
1105
 
1106 27 wfjm
 
1107 19 wfjm
} // end namespace Retro

powered by: WebSVN 2.1.0

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