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

Subversion Repositories w11

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

Details | Compare with Previous | View Log

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