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 27

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

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