📄 ecostestserialfilter.cpp
字号:
// Send checksum to target.
SendChecksum(pSer, crc);
// Give the target 1/10th of a sec to digest it
CeCosThreadUtils::Sleep(100);
switch (mode) {
case MODE_NO_ECHO:
{
// Simple transmit. Don't expect target to echo data back.
TargetWrite(pSer, data_out, size);
ReceiveDone(pSer, NULL, 0);
}
break;
case MODE_EOP_ECHO:
{
int in_crc;
TargetWrite(pSer, data_out, size);
Trace("Finished write, waiting for target echo.\n");
// Expect target to echo the data
TargetRead(pSer, data_in, size);
// Check echoed data, and reply OK/ER accordingly.
in_crc = DoCRC(data_in, size);
SendStatus(pSer, (in_crc == crc));
// Dump seen/expected on console.
if (in_crc != crc) {
Trace("Data seen:\n");
PrintHex(data_in, size);
Trace("<end>\n");
Trace("Data expected:\n");
PrintHex(data_out, size);
Trace("<end>\n");
}
ReceiveDone(pSer, data_in, size);
}
break;
case MODE_DUPLEX_ECHO:
{
int block_size = 64;
int fail, j;
// This is a simple implementation (maybe too simple).
// Host sends 4 packets with the same size (64 bytes atm).
// Target echoes in this way:
// packet1 -> packet1
// packet2 -> packet2, packet2
// packet3 -> packet3
// packet4 -> /dev/null
//
// The reads/writes are interleaved in a way that should ensure
// the target out buffer to be full before the target starts to read
// packet3. That is, the target should be both receiving (packet3)
// and sending (packet2) at the same time.
// This code needs restructuring. It's not very obvious what's
// happening: The same block of data is output several times,
// the target echoes the data back (one of the blocks is
// echoed twice). Then the echoed data is compared agains the
// outgoing data block.
fail = 0;
while (loop_count--) {
int i;
for (i = 0; i < block_size*4; i++)
data_in[i] = 0;
// out1: block_size -> block_size
TargetWrite(pSer, data_out, block_size);
// out2: block_size -> 2 x block_size
TargetWrite(pSer, data_out, block_size);
// in1:
TargetRead(pSer, data_in, block_size);
// out3: block_size -> block_size
TargetWrite(pSer, data_out, block_size);
// in2:
TargetRead(pSer, &data_in[block_size], 2*block_size);
// out4: block_size -> 0
TargetWrite(pSer, data_out, block_size);
// in3:
TargetRead(pSer, &data_in[block_size*3], block_size);
if (0 == loop_count % 10)
Trace("%d loops to go\n", loop_count);
// Verify data.
if (!fail) {
for (j = 0; j < 4 && !fail; j++) {
for (i = 0; i < block_size && !fail; i++) {
if (data_out[i] != data_in[j*block_size + i]) {
fail = 1;
Trace("Failed at byte %d\n", j*block_size + i);
Trace("Data seen:\n");
PrintHex(&data_in[j*block_size],
block_size);
Trace("<end>\n");
Trace("Data expected:\n");
PrintHex(data_out, block_size);
Trace("<end>\n");
}
}
}
}
}
// Check echoed data, and reply OK/ER accordingly.
SendStatus(pSer, (!fail));
ReceiveDone(pSer, data_in, block_size*4);
}
break;
default:
Trace("Unknown mode. Ignoring.\n");
}
// Free buffer.
free(data_in);
free(data_out);
}
//-----------------------------------------------------------------------------
// Test transformations on text transmissions
//
// This test transmits null-terminated C strings back and forth. Since
// the translation is under test and may fail, the length of the data is
// (potentially) unknown. Sending with a null-terminator allows proper
// recovery even if the translations do not work as intended.
//
// Format in:
// <flags>!<4 bytes binary checksum><C string>
// Format out:
// <C string>
// OK/ER
//
// Mode:
// MODE_EOP_ECHO:
// Receive data, verify CRC, resend data.
// Send OK/ER reply when done.
// MODE_DUPLEX_ECHO:
// Receive data, echo data, verify CRC.
// Send OK/ER reply when done.
//
// To Do:
// Implement.
void
CeCosTestSerialFilter::CMD_TestText(CeCosSerial &pSer, char* /*args*/)
{
SendStatus(pSer, 1);
}
//-----------------------------------------------------------------------------
// Reply to PING packet from target.
// Format in:
// "!"
// Format out:
// OK
void
CeCosTestSerialFilter::CMD_TestPing(CeCosSerial &pSer, char* /*args*/)
{
SendStatus(pSer, 1);
}
//-----------------------------------------------------------------------------
// Dispatch test command.
void
CeCosTestSerialFilter::DispatchCommand(CeCosSerial &pSer, char* cmd)
{
char* args;
args = strchr(cmd, (int) ':');
if (!args) {
Trace("Bogus command (%s) Ignoring.\n", cmd);
return;
}
*args++ = 0;
Trace("Dispatching command %s.\n", cmd);
if (0 == strcmp("CONFIG", cmd)) {
CMD_ChangeConfig(pSer, args);
}
else if (0 == strcmp("DEFCONFIG", cmd)) {
// Note: Currently the arguments are ignored. 9600 8N1 is default.
CMD_DefaultConfig(pSer);
}
else if (0 == strcmp("BINARY", cmd)) {
CMD_TestBinary(pSer, args);
}
else if (0 == strcmp("TEXT", cmd)) {
CMD_TestText(pSer, args);
}
else if (0 == strcmp("PING", cmd)) {
CMD_TestPing(pSer, args);
}
else
Trace("Unknown command '%s'.\n", cmd);
Trace("Command %s completed.\n", cmd);
}
bool CALLBACK
SerialFilterFunction(void*& pBuf,
unsigned int& nRead,
CeCosSerial& serial,
CeCosSocket& socket,
void* pParem)
{
CeCosTestSerialFilter* p = (CeCosTestSerialFilter*) pParem;
return p->FilterFunctionProper(pBuf, nRead, serial, socket);
}
bool
CeCosTestSerialFilter::FilterFunctionProper(void*& pBuf,
unsigned int& nRead,
CeCosSerial& serial,
CeCosSocket& socket)
{
char* buffer = (char*) pBuf;
// Don't do anything in the null filter mode.
if (m_bNullFilter)
return true;
// Allows trace to be called without a reference to the socket...
m_cGDBSocket = &socket;
// Put in trace buffer in case we have to leave it because the packet
// is incomplete
m_xStoredTraceBuffer = (unsigned char *)
realloc( m_xStoredTraceBuffer, m_nStoredTraceBufferSize + nRead );
if ( NULL == m_xStoredTraceBuffer )
throw "Could not allocate stored trace buffer";
memcpy( m_xStoredTraceBuffer + m_nStoredTraceBufferSize, buffer, nRead );
m_nStoredTraceBufferSize += nRead;
// Now search for distinct packets, delimited by '@' (filter commands)
// and '$' (GDB packets)
unsigned int i, newStart=0;
for (i=0; i<m_nStoredTraceBufferSize; i++) {
if ( m_xStoredTraceBuffer[i] == '@' ||
m_xStoredTraceBuffer[i] == '$' ) {
if (m_bOptSerDebug &&
(m_bOptConsoleOutput || m_bFirstCommandSeen)) {
// Output the serial data if option enabled - but only if
// dumping state to the console or after the first command
// has been seen from the filter. GDB gets confused by
// O-packets if they appear when it's trying to connect.
PrintHex(&m_xStoredTraceBuffer[newStart], i - newStart);
}
newStart = i;
}
}
// If we managed to print output, rejig the buffer size, and shunt
// the new start of the data to the front of the trace buffer
m_nStoredTraceBufferSize -= newStart;
memmove( m_xStoredTraceBuffer, &m_xStoredTraceBuffer[newStart],
m_nStoredTraceBufferSize );
// Command handling.
// If we are not presently reading a command, look for the
// start marker.
i = 0;
if (!m_bCmdFlag)
for (; i < nRead; i++) {
if ('@' == buffer[i]) {
m_bCmdFlag = true;
// Send the data before the marker.
if (i)
socket.send(buffer, i);
break;
}
}
// If reading a command, look for the end marker.
if (m_bCmdFlag) {
char c = 0;
while (i < nRead && m_nCmdIndex < MAX_CMD_LEN) {
c = buffer[i++];
m_aCmd[m_nCmdIndex++] = c;
if ('!' == c) {
if (i != nRead) {
m_nUnreadBufferIndex = 0;
m_nUnreadBufferSize = nRead - i;
m_xUnreadBuffer =
(unsigned char*) malloc(m_nUnreadBufferSize);
if (!m_xUnreadBuffer) {
m_nUnreadBufferSize = 0;
throw "Could not allocate unread buffer!";
}
int ix = 0;
while (i < nRead)
m_xUnreadBuffer[ix++] = buffer[i++];
}
break;
}
}
if (MAX_CMD_LEN == m_nCmdIndex) {
Trace("Received too long command. Ignoring it!\n");
m_nCmdIndex = 0;
m_bCmdFlag = false;
} else if ('!' == c) {
// Was the command completed?
m_aCmd[m_nCmdIndex - 1] = 0;// terminate cmd
m_nCmdIndex = 0;
m_bCmdFlag = false;
// First command dispatched. Initialize serial to nonblocking.
if (!m_bFirstCommandSeen) {
m_bFirstCommandSeen = true;
serial.SetBlockingReads(false);
}
try {
// skip @ when passing ptr
DispatchCommand(serial, &m_aCmd[1]);
}
catch (filter_abort_t* msg) {
// This allows the filter to unwind, wherever in the
// protocol it may be, when a $ is detected from the
// target side. When this happens, we may have a
// trap/exception on the target and we want the user
// to access the target via GDB without intervention.
// Do nothing from next call.
m_bNullFilter = true;
// Copy the start of the $-packet to the inbuffer.
unsigned char *d = (unsigned char*) pBuf;
const unsigned char *s = msg->data_ptr;
unsigned int len = msg->data_len;
// It should be possible to re-allocate buffer. Didn't seem
// to work properly though. Probably won't be a problem
// since we would normally only see 1-2 bytes of the
// $-packet anyway.
if (len > nRead)
throw "Not enough room for $-message";
while (len--)
*d++ = *s++;
nRead = msg->data_len;
delete msg;
return true;
}
}
nRead = 0; // Never leave anything for caller
// This is a violation of the intended
// filter function behavior.
}
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -