mirror of
https://github.com/wfjm/w11.git
synced 2026-01-26 12:22:03 +00:00
- Added simple simulation model of Cypress FX2 and test benches for functional verifcation of FX2 controller - Bugfixes in FX2 firmware and controller, works now also on Nexys3 & Atlys - Added test systems for rlink over USB verification for Nexys3 & Atlys
376 lines
10 KiB
C++
376 lines
10 KiB
C++
// $Id: RlinkPacketBuf.cpp 469 2013-01-05 12:29:44Z mueller $
|
|
//
|
|
// Copyright 2011-2013 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
|
|
//
|
|
// This program is free software; you may redistribute and/or modify it under
|
|
// the terms of the GNU General Public License as published by the Free
|
|
// Software Foundation, either version 2, or at your option any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful, but
|
|
// WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
|
|
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
// for complete details.
|
|
//
|
|
// Revision History:
|
|
// Date Rev Version Comment
|
|
// 2013-01-04 469 1.0.1 SndOob(): Add filler 0 to ensure escape state
|
|
// 2011-04-02 375 1.0 Initial version
|
|
// 2011-03-05 366 0.1 First draft
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/*!
|
|
\file
|
|
\version $Id: RlinkPacketBuf.cpp 469 2013-01-05 12:29:44Z mueller $
|
|
\brief Implemenation of class RlinkPacketBuf.
|
|
*/
|
|
|
|
#include <sys/time.h>
|
|
|
|
// debug
|
|
#include <iostream>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include "RlinkPacketBuf.hpp"
|
|
|
|
#include "librtools/RosFill.hpp"
|
|
#include "librtools/RosPrintf.hpp"
|
|
#include "librtools/RosPrintBvi.hpp"
|
|
|
|
using namespace std;
|
|
using namespace Retro;
|
|
|
|
/*!
|
|
\class Retro::RlinkPacketBuf
|
|
\brief FIXME_docs
|
|
*/
|
|
|
|
//------------------------------------------+-----------------------------------
|
|
// constants definitions
|
|
|
|
const uint32_t RlinkPacketBuf::kFlagSopSeen;
|
|
const uint32_t RlinkPacketBuf::kFlagEopSeen;
|
|
const uint32_t RlinkPacketBuf::kFlagNakSeen;
|
|
const uint32_t RlinkPacketBuf::kFlagAttnSeen;
|
|
const uint32_t RlinkPacketBuf::kFlagTout;
|
|
const uint32_t RlinkPacketBuf::kFlagDatDrop;
|
|
const uint32_t RlinkPacketBuf::kFlagDatMiss;
|
|
|
|
const uint8_t RlinkPacketBuf::kCPREF;
|
|
const uint8_t RlinkPacketBuf::kNCOMM;
|
|
const uint8_t RlinkPacketBuf::kCommaIdle;
|
|
const uint8_t RlinkPacketBuf::kCommaSop;
|
|
const uint8_t RlinkPacketBuf::kCommaEop;
|
|
const uint8_t RlinkPacketBuf::kCommaNak;
|
|
const uint8_t RlinkPacketBuf::kCommaAttn;
|
|
const uint8_t RlinkPacketBuf::kSymEsc;
|
|
|
|
//------------------------------------------+-----------------------------------
|
|
//! Default constructor
|
|
|
|
RlinkPacketBuf::RlinkPacketBuf()
|
|
: fPktBuf(),
|
|
fRawBuf(),
|
|
fRawBufSize(0),
|
|
fCrc(),
|
|
fFlags(0),
|
|
fNdone(0),
|
|
fNesc(0),
|
|
fNattn(0),
|
|
fNidle(0),
|
|
fNdrop(0)
|
|
{}
|
|
|
|
//------------------------------------------+-----------------------------------
|
|
//! Destructor
|
|
|
|
RlinkPacketBuf::~RlinkPacketBuf()
|
|
{}
|
|
|
|
//------------------------------------------+-----------------------------------
|
|
//! FIXME_docs
|
|
|
|
void RlinkPacketBuf::Init()
|
|
{
|
|
fPktBuf.clear();
|
|
fRawBufSize = 0;
|
|
fCrc.Clear();
|
|
fFlags = 0;
|
|
fNdone = 0;
|
|
fNesc = 0;
|
|
fNattn = 0;
|
|
fNidle = 0;
|
|
fNdrop = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------+-----------------------------------
|
|
//! FIXME_docs
|
|
|
|
bool RlinkPacketBuf::SndPacket(RlinkPort* port, RerrMsg& emsg)
|
|
{
|
|
fRawBuf.reserve(2*fPktBuf.size()+2); // max. size of raw data
|
|
fRawBuf.clear();
|
|
|
|
fRawBuf.push_back(kCommaSop);
|
|
|
|
size_t ni = fPktBuf.size();
|
|
uint8_t* pi = fPktBuf.data();
|
|
for (size_t i=0; i<ni; i++) {
|
|
uint8_t c = *pi++;
|
|
if (c == kSymEsc || (c >= kCPREF && c <= kCPREF+kNCOMM)) {
|
|
fRawBuf.push_back(kSymEsc);
|
|
fRawBuf.push_back(((~kCPREF) & 0xf0) | (c & 0x0f));
|
|
fNesc += 1;
|
|
} else {
|
|
fRawBuf.push_back(c);
|
|
}
|
|
}
|
|
|
|
fRawBuf.push_back(kCommaEop);
|
|
|
|
return SndRaw(port, emsg);
|
|
|
|
}
|
|
|
|
//------------------------------------------+-----------------------------------
|
|
//! FIXME_docs
|
|
|
|
bool RlinkPacketBuf::RcvPacket(RlinkPort* port, size_t nrcv, float timeout,
|
|
RerrMsg& emsg)
|
|
{
|
|
fPktBuf.clear();
|
|
|
|
bool escseen = false; // in esc
|
|
bool sopseen = false; // sop seen
|
|
bool eopseen = false; // eop seen
|
|
bool nakseen = false; // nak seen
|
|
|
|
while (!(eopseen|nakseen)) { // try till eop or nak received
|
|
size_t nread = nrcv - fPktBuf.size();
|
|
// FIXME_code: if the 'enough data' handling below correct ?
|
|
if (nread < 0) return true;
|
|
if (!sopseen) nread += 1;
|
|
if (!eopseen) nread += 1;
|
|
|
|
size_t sizeold = fRawBufSize;
|
|
int irc = RcvRaw(port, nread, timeout, emsg);
|
|
|
|
if (irc <= 0) {
|
|
if (irc == RlinkPort::kTout) {
|
|
SetFlagBit(kFlagTout);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
uint8_t* pi = fRawBuf.data()+sizeold;
|
|
for (int i=0; i<irc; i++) {
|
|
uint8_t c = *pi++;
|
|
if (escseen) {
|
|
escseen = false;
|
|
if (sopseen && !(nakseen || eopseen)) {
|
|
fPktBuf.push_back((kCPREF & 0xf0) | (c & 0x0f));
|
|
}
|
|
} else if (c == kCommaSop) {
|
|
if (!eopseen) {
|
|
SetFlagBit(kFlagSopSeen);
|
|
sopseen = true;
|
|
} else {
|
|
// FIXME_code: handle multiple sop
|
|
}
|
|
} else if (c == kCommaEop) {
|
|
SetFlagBit(kFlagEopSeen);
|
|
eopseen = true;
|
|
} else if (c == kCommaNak) {
|
|
SetFlagBit(kFlagNakSeen);
|
|
nakseen = true;
|
|
} else if (c == kCommaAttn) {
|
|
SetFlagBit(kFlagAttnSeen);
|
|
fNattn += 1;
|
|
} else if (c == kCommaIdle) {
|
|
fNidle += 1;
|
|
} else if (c == kSymEsc) {
|
|
fNesc += 1;
|
|
escseen = true;
|
|
} else {
|
|
if (sopseen && !(nakseen || eopseen)) {
|
|
fPktBuf.push_back(c);
|
|
} else {
|
|
fNdrop += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------+-----------------------------------
|
|
//! FIXME_docs
|
|
|
|
double RlinkPacketBuf::WaitAttn(RlinkPort* port, double timeout, RerrMsg& emsg)
|
|
{
|
|
if (timeout <= 0.)
|
|
throw invalid_argument("RlinkPacketBuf::WaitAttn(): timeout <= 0.");
|
|
|
|
struct timeval tval;
|
|
gettimeofday(&tval, 0);
|
|
double tbeg = double(tval.tv_sec) + 1.e-6*double(tval.tv_usec);
|
|
double trest = timeout;
|
|
|
|
Init();
|
|
|
|
while (trest > 0.) {
|
|
size_t sizeold = fRawBufSize;
|
|
int irc = RcvRaw(port, 1, trest, emsg);
|
|
|
|
if (irc <= 0) {
|
|
if (irc == RlinkPort::kTout) {
|
|
SetFlagBit(kFlagTout);
|
|
return -1.;
|
|
} else {
|
|
return -2.;
|
|
}
|
|
}
|
|
|
|
gettimeofday(&tval, 0);
|
|
double tend = double(tval.tv_sec) + 1.e-6*double(tval.tv_usec);
|
|
trest -= (tend-tbeg);
|
|
|
|
uint8_t c = fRawBuf[sizeold];
|
|
|
|
if (c == kCommaAttn) {
|
|
fNattn += 1;
|
|
SetFlagBit(kFlagAttnSeen);
|
|
break;
|
|
} else if (c == kCommaIdle) {
|
|
fNidle += 1;
|
|
} else {
|
|
fNdrop += 1;
|
|
}
|
|
|
|
tbeg = tend;
|
|
}
|
|
|
|
return timeout - trest;
|
|
}
|
|
|
|
//------------------------------------------+-----------------------------------
|
|
//! FIXME_docs
|
|
|
|
bool RlinkPacketBuf::SndOob(RlinkPort* port, uint16_t addr, uint16_t data,
|
|
RerrMsg& emsg)
|
|
{
|
|
Init();
|
|
|
|
fRawBuf.clear();
|
|
fRawBuf.push_back(kSymEsc); // ESC
|
|
fRawBuf.push_back(kSymEsc); // ESC
|
|
fRawBuf.push_back((uint8_t)addr); // ADDR
|
|
fRawBuf.push_back((uint8_t)(data & 0x00ff)); // DL
|
|
fRawBuf.push_back((uint8_t)((data>>8) & 0x00ff)); // DH
|
|
// write a filler char (just 0) to ensure that the 8b->9b stage in the
|
|
// receiver (byte2cdata) is always out if the escape state...
|
|
fRawBuf.push_back(0); // filler
|
|
|
|
return SndRaw(port, emsg);
|
|
}
|
|
|
|
//------------------------------------------+-----------------------------------
|
|
//! FIXME_docs
|
|
|
|
bool RlinkPacketBuf::SndKeep(RlinkPort* port, RerrMsg& emsg)
|
|
{
|
|
Init();
|
|
|
|
fRawBuf.clear();
|
|
fRawBuf.push_back(kSymEsc); // ESC
|
|
fRawBuf.push_back(kSymEsc); // ESC
|
|
|
|
return SndRaw(port, emsg);
|
|
}
|
|
|
|
//------------------------------------------+-----------------------------------
|
|
//! FIXME_docs
|
|
|
|
void RlinkPacketBuf::Dump(std::ostream& os, int ind, const char* text) const
|
|
{
|
|
RosFill bl(ind);
|
|
os << bl << (text?text:"--") << "RlinkPacketBuf @ " << this << endl;
|
|
os << bl << " fCrc: " << RosPrintBvi(fCrc.Crc(), 0) << endl;
|
|
os << bl << " fFlags: " << RosPrintBvi(fFlags, 0) << endl;
|
|
os << bl << " fNdone: " << RosPrintf(fNdone,"d",4) << endl;
|
|
os << bl << " fNesc: " << RosPrintf(fNesc,"d",4) << endl;
|
|
os << bl << " fNattn: " << RosPrintf(fNattn,"d",4) << endl;
|
|
os << bl << " fNidle: " << RosPrintf(fNidle,"d",4) << endl;
|
|
os << bl << " fNdrop: " << RosPrintf(fNdrop,"d",4) << endl;
|
|
|
|
os << bl << " fPktBuf(size): " << RosPrintf(fPktBuf.size(),"d",4);
|
|
size_t ncol = max(1, (80-ind-4-6)/(2+1));
|
|
for (size_t i=0; i< fPktBuf.size(); i++) {
|
|
if (i%ncol == 0) os << "\n" << bl << " " << RosPrintf(i,"d",4) << ": ";
|
|
os << RosPrintBvi(fPktBuf[i],16) << " ";
|
|
}
|
|
os << endl;
|
|
|
|
os << bl << " fRawBuf(size): " << RosPrintf(fRawBufSize,"d",4);
|
|
for (size_t i=0; i< fRawBufSize; i++) {
|
|
if (i%ncol == 0) os << "\n" << bl << " " << RosPrintf(i,"d",4) << ": ";
|
|
os << RosPrintBvi(fRawBuf[i],16) << " ";
|
|
}
|
|
os << endl;
|
|
|
|
return;
|
|
}
|
|
|
|
//------------------------------------------+-----------------------------------
|
|
//! FIXME_docs
|
|
|
|
bool RlinkPacketBuf::SndRaw(RlinkPort* port, RerrMsg& emsg)
|
|
{
|
|
if (port==0 || !port->IsOpen())
|
|
throw logic_error("RlinkPacketBuf::SndRaw(): port not open");
|
|
|
|
fRawBufSize = fRawBuf.size();
|
|
int irc = port->Write(fRawBuf.data(), fRawBuf.size(), emsg);
|
|
if (irc < 0) return false;
|
|
if ((size_t)irc != fRawBuf.size()) {
|
|
emsg.Init("RlinkPacketBuf::SndRaw()", "failed to write all data");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------+-----------------------------------
|
|
//! FIXME_docs
|
|
|
|
int RlinkPacketBuf::RcvRaw(RlinkPort* port, size_t size, float timeout,
|
|
RerrMsg& emsg)
|
|
{
|
|
if (port==0 || !port->IsOpen())
|
|
throw logic_error("RlinkPacketBuf::RcvRaw(): port not open");
|
|
|
|
if (fRawBuf.size() < fRawBufSize+size) fRawBuf.resize(fRawBufSize+size);
|
|
int irc = port->Read(fRawBuf.data()+fRawBufSize, size, timeout, emsg);
|
|
if (irc == RlinkPort::kEof) {
|
|
emsg.Init("RlinkPacketBuf::RcvRaw()", "eof on read");
|
|
}
|
|
|
|
if (irc > 0) {
|
|
fRawBufSize += irc;
|
|
}
|
|
|
|
return irc;
|
|
}
|
|
|
|
//------------------------------------------+-----------------------------------
|
|
#if (defined(Retro_NoInline) || defined(Retro_RlinkPacketBuf_NoInline))
|
|
#define inline
|
|
#include "RlinkPacketBuf.ipp"
|
|
#undef inline
|
|
#endif
|