📄 ecostestserialfilter.cpp
字号:
//####COPYRIGHTBEGIN####
//
// ----------------------------------------------------------------------------
// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
//
// This program is part of the eCos host tools.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, 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
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// ----------------------------------------------------------------------------
//
//####COPYRIGHTEND####
//=================================================================
//
// eCosTestSerialFilter.cpp
//
// Serial test filter class
//
//=================================================================
//=================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): jskov
// Contributors: jskov
// Date: 1999-03-01
// Description: This filter sits between GDB and the test running on
// the target, allowing testing of the serial driver
// without confusing GDB.
// To Do:
// o Add timeout setup and handling for recovery, can rely on testing
// agent to control global timeout.
// o Saving chunks that caused transfer failure?
// - In SEND with echo, do CRC on 32-byte sub-packets
// o Additional To Do items under each sub-protocol function.
// o Option to get all serial IO written (in hex, > and < prepends
// input/output lines) to a file.
// o Clean up the mess in this file....
//####DESCRIPTIONEND####
#include "eCosStd.h"
#include "eCosTestSerialFilter.h"
#include "eCosThreadUtils.h"
char msg_ok[] = "OK";
char msg_er[] = "ER";
CeCosTestSerialFilter::CeCosTestSerialFilter():
m_bOptConsoleOutput(false),
m_bOptSerDebug(false),
m_bOptFilterTrace(false),
m_xUnreadBuffer(NULL),
m_nUnreadBufferIndex(0),
m_nUnreadBufferSize(0),
m_xStoredTraceBuffer(NULL),
m_nStoredTraceBufferSize(0),
m_bNullFilter(false),
m_nCmdIndex(0),
m_bCmdFlag(false),
m_bFirstCommandSeen(false),
m_cGDBSocket(NULL)
{
}
CeCosTestSerialFilter::~CeCosTestSerialFilter()
{
}
//------------------------
// Output helpers.
// Encode string in an O-packet and send it to GDB.
void
CeCosTestSerialFilter::GDBWrite(const char* pszStr)
{
if (m_cGDBSocket) {
static const char hexchars[] = "0123456789abcdef";
char* packet = new char[strlen(pszStr)*2+6];
char* p = packet;
*p++ = '$';
*p++ = 'O';
unsigned char crc = 'O';
char c;
for (;;) {
c = *pszStr++;
if (0 == c)
break;
char h = hexchars[(c >> 4) & 0x0f];
char l = hexchars[c & 0x0f];
*p++ = h;
*p++ = l;
crc = (unsigned char) (crc + h + l);
};
*p++ = '#';
*p++ = hexchars[(crc >> 4) & 0x0f];
*p++ = hexchars[crc & 0x0f];
// Only try to send once. If it fails, it's probably because
// GDB has disconnected.
m_cGDBSocket->send(packet, p - packet);
m_cGDBSocket->recv(&c, 1);
delete [] packet;
}
}
void
CeCosTestSerialFilter::ConsoleWrite(const char* pszStr)
{
fputs(pszStr, stderr);
fflush(stderr);
}
void
CeCosTestSerialFilter::Trace(const char* pszFormat, ...)
{
va_list marker;
va_start (marker, pszFormat);
for(int nLength=100;nLength;) {
char *buf=new char[1+nLength];
int n=vsnprintf(buf+4, nLength-4, pszFormat, marker );
if(-1==n){
nLength*=2; // NT behavior
} else if (n<nLength){
memcpy(buf,"[f] ",4);
if (m_bOptConsoleOutput) {
ConsoleWrite(buf);
} else {
GDBWrite(buf);
}
nLength=0; // trigger exit from loop
} else {
nLength=n+1; // UNIX behavior generally, or NT behavior when buffer size exactly matches required length
}
delete [] buf;
}
va_end (marker);
}
void
CeCosTestSerialFilter::Log(const char* pszFormat, ...)
{
va_list marker;
va_start (marker, pszFormat);
for(int nLength=100;nLength;) {
char *buf=new char[1+nLength];
int n=vsnprintf(buf, nLength, pszFormat, marker );
if(-1==n){
nLength*=2; // NT behavior
} else if (n<nLength){
if (m_bOptConsoleOutput) {
ConsoleWrite(buf);
} else {
GDBWrite(buf);
}
nLength=0; // trigger exit from loop
} else {
nLength=n+1; // UNIX behavior generally, or NT behavior when buffer size exactly matches required length
}
delete [] buf;
}
va_end (marker);
}
void
CeCosTestSerialFilter::PrintHex(const unsigned char* d1, int len, data_origin_t origin/*=SF_TARGET*/)
{
int offset = 0;
int i;
char buf[128];
int width = 8;
while (len) {
int count = MIN(width, len);
char* p = buf;
switch (origin) {
case SF_TARGET:
p += sprintf(p, "T");
break;
case SF_FILTER:
p += sprintf(p, "F");
break;
}
p += sprintf(p, ":%04x ", offset);
// Print hex values.
for (i = 0; i < count; i++)
p += sprintf(p, "%02x ", d1[i]);
for ( ; i < width ; i++)
p += sprintf(p, ".. ");
// Print ASCII string
p += sprintf(p, "'");
for (i = 0; i < count; i++) {
int c = d1[i];
if (' ' > c || 'z' < c)
c = '.';
p += sprintf(p, "%c", c);
}
sprintf(p, "'\n");
Trace("%s", buf);
len -= count;
offset += count;
d1 += count;
}
}
void
CeCosTestSerialFilter::TargetWrite(CeCosSerial &pSer,
const unsigned char* buffer, int len)
{
unsigned int __written;
if (m_bOptFilterTrace)
PrintHex(buffer, len, SF_FILTER);
do {
if (!(pSer.Write((void*) buffer, len, __written))) {
fprintf(stderr, "Writing %d bytes to serial failed\n", len);
fprintf(stderr, "%s", (LPCTSTR)pSer.ErrString());
throw "serial write failed";
}
buffer += __written;
len -= __written;
} while (len);
}
bool
CeCosTestSerialFilter::TargetRead(CeCosSerial &pSer,
unsigned char* buffer, int len)
{
unsigned int __read;
int __total_read = 0;
unsigned char* __buffer_base = buffer;
int __timeouts = 0;
int __timeout_failure = 0;
int __orig_len = len;
do {
// First check for unread data.
if (m_nUnreadBufferSize) {
int i = 0;
__read = 0;
while (i < len && m_nUnreadBufferIndex < m_nUnreadBufferSize) {
buffer[i++] = m_xUnreadBuffer[m_nUnreadBufferIndex++];
__read++;
}
if (m_nUnreadBufferIndex == m_nUnreadBufferSize) {
free(m_xUnreadBuffer);
m_nUnreadBufferSize = 0;
m_nUnreadBufferIndex = 0;
}
} else {
// Then read directly from serial.
if (!(pSer.Read((void*) buffer, len, __read))) {
fprintf(stderr,"Reading %d bytes from serial failed (read %d).\n",
len, __read);
char *pszErr=pSer.ErrString().GetCString();
fprintf(stderr, "%s", pszErr);
delete [] pszErr;
throw "serial read failed";
}
}
__total_read += __read;
unsigned int i;
for (i = 0; i < __read; i++) {
if ('$' == buffer[i]) {
Log("FAIL:<target crashed>\n");
Trace("**** Detected $ -- resuming as null filter ****\n");
Trace("Data received %d bytes (of %d) from target:\n",
__total_read, __orig_len);
PrintHex(__buffer_base, __total_read);
Trace("<end>\n");
filter_abort_t* msg = new filter_abort_t();
msg->data_ptr = &buffer[i];
msg->data_len = __read - i;
throw msg;
}
}
if (0 == __read) {
CeCosThreadUtils::Sleep(20);
__timeouts++;
if (25 == __timeouts) {
__timeouts = 0;
if (5 == __timeout_failure++) {
Log("FAIL:<target timed out>\n");
Trace("**** Timed out while reading -- resuming as null filter\n");
Trace("Data received %d bytes (of %d) from target:\n",
__total_read, __orig_len);
PrintHex(__buffer_base, __total_read);
Trace("<end>\n");
static const char kill_msg[] = "$X00#b8";
filter_abort_t* msg = new filter_abort_t();
msg->data_len = strlen(kill_msg);
msg->data_ptr = (const unsigned char *)kill_msg;
throw msg;
}
}
} else {
__timeouts = 0;
__timeout_failure = 0;
}
buffer += __read;
len -= __read;
} while (len);
return true;
}
// Send C ASCII string to target.
void
CeCosTestSerialFilter::TargetASCIIWrite(CeCosSerial &pSer, const char* s)
{
TargetWrite(pSer, (const unsigned char*) s, strlen(s));
}
//------------------------
// Configuration Command.
// Set serial configuration.
bool
CeCosTestSerialFilter::SetConfig(CeCosSerial &pSer,
const ser_cfg_t* new_cfg,
ser_cfg_t* old_cfg)
{
// Note that for flow control, we assume that *both* receive and transmit
// flow control are set or not set
if (old_cfg) {
old_cfg->baud_rate = pSer.GetBaud();
old_cfg->parity = (0 != pSer.GetParity()) ? true : false;
old_cfg->data_bits = pSer.GetDataBits();
old_cfg->stop_bits = pSer.GetStopBits();
old_cfg->flags = pSer.GetXONXOFFFlowControl() ? FLOW_XONXOFF_RX : 0;
old_cfg->flags |= pSer.GetRTSCTSFlowControl() ? FLOW_RTSCTS_RX : 0;
old_cfg->flags |= pSer.GetDSRDTRFlowControl() ? FLOW_DSRDTR_RX : 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -