📄 ser_filter.cpp
字号:
//=================================================================//// ser_filter.cxx//// Serial test filter////=================================================================//####COPYRIGHTBEGIN####//// -------------------------------------------// The contents of this file are subject to the Cygnus eCos Public License// Version 1.0 (the "License"); you may not use this file except in// compliance with the License. You may obtain a copy of the License at// http://sourceware.cygnus.com/ecos// // Software distributed under the License is distributed on an "AS IS"// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the// License for the specific language governing rights and limitations under// the License.// // The Original Code is eCos - Embedded Cygnus Operating System, released// September 30, 1998.// // The Initial Developer of the Original Code is Cygnus. Portions created// by Cygnus are Copyright (C) 1998, 1999 Cygnus Solutions.// All Rights Reserved.// -------------------------------------------////####COPYRIGHTEND####//=================================================================//#####DESCRIPTIONBEGIN####//// Author(s): jskov// Contributors: jskov// Date: 1999-03-01// Description: This program acts as a filter between GDB and the test// running on the target, allowing testing of the serial// driver without confusing GDB.// Usage: Run the program with one argument, the serial port// on with the target is connected.// Run serial test in GDB, connecting to the target with// 'target remote localhost:5678'.//// 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 "stdafx.h"#include "eCosTest.h"#include "eCosTestSocket.h"#include "eCosTestSerial.h"#include <setjmp.h>#ifdef _WIN32#define CYG_UNUSED_PARAM( _type_, _name_ ) _name_#else#define CYG_UNUSED_PARAM( _type_, _name_ ) { \ _type_ __tmp1 = (_name_); \ _type_ __tmp2 = __tmp1; \ __tmp1 = __tmp2; \}#endif// This gets uglier and uglier...CeCosTestSocket* gdb_socket;int opt_ser_debug = 0;int opt_console_output = 0;jmp_buf fallback_buf;enum {MAX_CMD_LEN=128};struct ser_filter_state_t { bool null_filter; int cmd_i; int cmd_flag; char cmd[MAX_CMD_LEN]; // We need this to avoid outputting serial tracing while GDB is trying to // connect, or it will get confused. bool first_command_seen; ser_filter_state_t() : null_filter(0), cmd_i(0), cmd_flag(0), first_command_seen(0) {}};typedef struct ser_cfg { int baud_rate; int data_bits; CeCosTestSerial::StopBitsType stop_bits; bool parity; // etc...} ser_cfg_t;typedef enum { MODE_NO_ECHO = 0, MODE_EOP_ECHO, MODE_DUPLEX_ECHO} cyg_mode_t;char msg_ok[] = "OK";char msg_er[] = "ER";//----------------------------------------------------------------------------// Macros to help extract values from the argument string.// Note: This is probably not an ideal solution, but it was easy to make :)#define INIT_VALUE(__args) \ unsigned int v; \ char *__ptr1, *__ptr2 = (__args)#define SET_VALUE(__type, __slot) \{ \ __ptr1 = strchr(__ptr2, (int) ':'); \ if (__ptr1) \ *__ptr1 = 0; \ v = atoi(__ptr2); \ __ptr2 = __ptr1+1; \ (__slot) = (__type) v; \}//------------------------// Output helpers.// Encode string in an O-packet and send it to GDB.void gdb_write(const char* pszStr){ if (gdb_socket) { 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. gdb_socket->send(packet, p - packet); gdb_socket->recv(&c, 1); delete [] packet; }}voidconsole_write(const char* pszStr){ fputs(pszStr, stderr); fflush(stderr);}voidtrace(const char* pszFormat, ...){ va_list marker; va_start (marker, pszFormat); CeCosTestUtils::String str; str.vFormat(pszFormat,marker); va_end (marker); // Prefix with [f] CeCosTestUtils::String str2("[f] "); str2 += str; if (opt_console_output) console_write((const char*) str2); else gdb_write((const char*) str2);}voidprint_hex(unsigned char* d1, int len){ int offset = 0; int i; char buf[128]; int width = 8; while (len) { int count = min(width, len); char* p = buf; 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; }}voidtarget_write(CeCosTestSerial &pSer, const unsigned char* buffer, int len){ unsigned int __written; do { if (!(pSer.Write((void*) buffer, len, __written))) { fprintf(stderr, "Writing %d bytes to serial failed\n", len); fprintf(stderr, strerror(errno)); throw "serial write failed"; } buffer += __written; len -= __written; } while (len);}// Yuck! There is probably a better way to do this...void* recover_data;int recover_data_len;booltarget_read(CeCosTestSerial &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; do { if (!(pSer.Read((void*) buffer, len, __read))) { fprintf(stderr,"Reading %d bytes from serial failed (read %d).\n", len, __read); fprintf(stderr, strerror(errno)); throw "serial read failed"; } __total_read += __read; unsigned int i; for (i = 0; i < __read; i++) { if ('$' == buffer[i]) { trace("**** Detected $ -- resuming as null filter ****\n"); trace("Data received %d bytes (of %d) from target:\n", __total_read, len); print_hex(__buffer_base, __total_read); trace("<end>\n"); recover_data = (void*) &buffer[i]; recover_data_len = __read - i; longjmp(fallback_buf, 1); } } if (0 == __read) { CeCosTestUtils::Sleep(20); __timeouts++; if (25 == __timeouts) { __timeouts = 0; if (5 == __timeout_failure++) { trace("**** Timed out while reading -- resuming as null filter\n"); trace("Data received %d bytes (of %d) from target:\n", __total_read, len); print_hex(__buffer_base, __total_read); trace("<end>\n"); static const char kill_msg[] = "$X00#b8"; recover_data_len = strlen(kill_msg); recover_data = (void*) kill_msg; longjmp(fallback_buf, 2); } } } else { __timeouts = 0; __timeout_failure = 0; } buffer += __read; len -= __read; } while (len); return true;}// Send C ASCII string to target.void target_ASCII_write(CeCosTestSerial &pSer, const char* s) { target_write(pSer, (const unsigned char*) s, strlen(s)); };//------------------------// Configuration Command.void parse_config(char* cfg_str, ser_cfg_t* new_cfg);void change_config(char* cfg_str);// Return false if the serial configuration is not valid for the host.int verify_config(ser_cfg_t* cfg){ CYG_UNUSED_PARAM(ser_cfg_t*, cfg); // FIXME: Assume OK for now. return 1;}// Set serial configuration.voidset_config(CeCosTestSerial &pSer, const ser_cfg_t* cfg){ pSer.SetBaud(cfg->baud_rate, false); pSer.SetParity(cfg->parity, false); pSer.SetDataBits(cfg->data_bits, false); pSer.SetStopBits(cfg->stop_bits, true); // apply settings}// Set default serial configuration.void default_config(CeCosTestSerial &pSer);//-----------------------------------------------------------------------------// Change serial configuration.// To Do:// Proper (full) implementation.voidchange_config(CeCosTestSerial &pSer, char* cfg_str){ ser_cfg_t new_cfg; parse_config(cfg_str, &new_cfg); if (verify_config(&new_cfg)) { target_ASCII_write(pSer, "OK"); set_config(pSer, &new_cfg); } else { target_ASCII_write(pSer, "ER"); }}// Set default configuration.voiddefault_config(CeCosTestSerial &pSer){ static const ser_cfg_t default_ser_cfg = { 9600, 8, CeCosTestSerial::ONE, false }; target_ASCII_write(pSer, "OK"); set_config(pSer, &default_ser_cfg);}// Parse config string from target and set new_cfg accordingly.// String from target is:// <baud rate>:<data bits>:<stop bits>:<parity>:....voidparse_config(char* args, ser_cfg_t* new_cfg){ int ecos_parity, ecos_stop_bits, ecos_baud_rate; CeCosTestSerial::StopBitsType t2h_stop_bits[3] = { CeCosTestSerial::ONE, CeCosTestSerial::ONE_POINT_FIVE, CeCosTestSerial::TWO}; INIT_VALUE(args); SET_VALUE(int, ecos_baud_rate); SET_VALUE(int, new_cfg->data_bits); SET_VALUE(int, ecos_stop_bits); SET_VALUE(int, ecos_parity); new_cfg->parity = (ecos_parity) ? true : false; new_cfg->stop_bits = t2h_stop_bits[ecos_stop_bits - 1]; // eCos->human translation of serial baud rate. This table must // match the one in io/serial/current/include/serialio.h static const int tt_baud_rate[] = { -1, // 0 invalid 50, // 1 50 75, // 2 75 110, // 3 135, // 4 134_5 150, // 5 200, // 6 200 300, // 7 600, // 8 1200, // 9 1800, // 10 1800 2400, // 11 3600, // 12 3600 4800, // 13 7200, // 14 7200 9600, // 15 14400, // 16 14400 19200, // 17 38400, // 18 57600, // 19 115200, // 20 234000 // 21 234000 }; if (ecos_baud_rate > 0 && ecos_baud_rate < (int) sizeof(tt_baud_rate)) ecos_baud_rate = tt_baud_rate[ecos_baud_rate]; else ecos_baud_rate = -2; new_cfg->baud_rate = ecos_baud_rate;}// Always make sure CRC fits in 31 bits. Bit of a hack, but we want// to send CRC as ASCII without too much hassle.intdo_crc(unsigned char* data, int size){ int i; unsigned long crc; for (i = 0, crc = 0; i < size; i++) { crc = (crc << 1) ^ data[i]; // FIXME: standard definition? } i = (int) crc; if (i < 0) i = -i; return i;}voidsend_checksum(CeCosTestSerial &pSer, int crc){ char buffer[128]; int len; len = sprintf(buffer, "%d!", crc); target_write(pSer, (const unsigned char*)buffer, len);}voidsend_status(CeCosTestSerial &pSer, int state){ if (state) target_write(pSer, (unsigned char*) &msg_ok, 2); else target_write(pSer, (unsigned char*) &msg_er, 2);}// Receive test DONE message from target.voidreceive_done(CeCosTestSerial &pSer, unsigned char* data_in, int size){ static const char msg_done[] = "DONE"; unsigned char data_reply[4]; int first = 1; target_read(pSer, data_reply, 4); while (0 != strncmp((char*) data_reply, msg_done, 4)) { if (first) { if (data_in && size) { trace("Data received from target:\n"); print_hex(data_in, size); trace("<end>\n"); } trace("Receiving junk instead of DONE:\n"); first = 0; } print_hex(data_reply, 4); data_reply[0] = data_reply[1]; data_reply[1] = data_reply[2]; data_reply[2] = data_reply[3]; // The target_read call will handle recovery in case of timeout... target_read(pSer, &data_reply[3], 1); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -