📄 ser_filter.cpp
字号:
//-----------------------------------------------------------------------------// Test binary data transmission.// Format in:// <byte size>:<mode>// Format out:// <4 bytes binary checksum><#size bytes data>// If echo mode, also:// Format in:// <#size bytes data>// Format out:// OK/ER - according to CRC match on incomin data// Format in:// DONE//// To Do:// o Add mode/flag specifying 5-8 bit transfer.// Test that 0xff gets masked off accordingly when transfered.// (This should be an INFO result if failing)// o Clean up the DUPLEX_ECHO implementation. Currently it's an ugly hack// that doesn't match the arguments / behavior of the two other modes.voidtest_binary(CeCosTestSerial &pSer, char* args){ int size; cyg_mode_t mode; unsigned char *data_out, *data_in; int i; int crc; int loop_count = 0; INIT_VALUE(args); SET_VALUE(int, size); SET_VALUE(cyg_mode_t, mode); // Change behavior for DUPLEX mode. if (MODE_DUPLEX_ECHO == mode) { loop_count = size; size = 1024; // must be at least 4*block_size } // Generate data. data_out = (unsigned char*) malloc(size); if (!data_out) { fprintf(stderr, "Could not allocate %d byte buffer for data!\n", size); throw "data_out malloc failed"; } data_in = (unsigned char*) malloc(size); if (!data_in) { fprintf(stderr, "Could not allocate %d byte buffer for data!\n", size); throw "data_in malloc failed"; } for (i = 0; i < size; i++) { static int count = 0; unsigned char c = (unsigned char) (count++ & 0xff); // don't allow $s and @s in the data, nor 0x03 (GDB C-c) if ('$' == c || '@' == c || 0x03 == c) c = (unsigned char) '*'; data_out[i] = c; } // Do checksum. crc = do_crc(data_out, size); // Send checksum to target. send_checksum(pSer, crc); switch (mode) { case MODE_NO_ECHO: { // Simple transmit. Don't expect target to echo data back. target_write(pSer, data_out, size); receive_done(pSer, NULL, 0); } break; case MODE_EOP_ECHO: { int in_crc; target_write(pSer, data_out, size); // Expect target to echo the data target_read(pSer, data_in, size); // Check echoed data, and reply OK/ER accordingly. in_crc = do_crc(data_in, size); send_status(pSer, (in_crc == crc)); // Dump seen/expected on console. if (in_crc != crc) { trace("Data seen:\n"); print_hex(data_in, size); trace("<end>\n"); trace("Data expected:\n"); print_hex(data_out, size); trace("<end>\n"); } receive_done(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 target_write(pSer, data_out, block_size); // out2: block_size -> 2 x block_size target_write(pSer, data_out, block_size); // in1: target_read(pSer, data_in, block_size); // out3: block_size -> block_size target_write(pSer, data_out, block_size); // in2: target_read(pSer, &data_in[block_size], 2*block_size); // out4: block_size -> 0 target_write(pSer, data_out, block_size); // in3: target_read(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"); print_hex(&data_in[j*block_size], block_size); trace("<end>\n"); trace("Data expected:\n"); print_hex(data_out, block_size); trace("<end>\n"); } } } } } // Check echoed data, and reply OK/ER accordingly. send_status(pSer, (!fail)); receive_done(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.voidtest_text(CeCosTestSerial &pSer, char* args){ CYG_UNUSED_PARAM(char*, args); send_status(pSer, 1);}//-----------------------------------------------------------------------------// Reply to PING packet from target.// Format in:// "!"// Format out:// OKvoidtest_ping(CeCosTestSerial &pSer, char* args){ CYG_UNUSED_PARAM(char*, args); send_status(pSer, 1);}//-----------------------------------------------------------------------------// Dispatch test command. voiddispatch_command(CeCosTestSerial &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)) { change_config(pSer, args); } else if (0 == strcmp("DEFCONFIG", cmd)) { // Note: Currently the arguments are ignored. 9600 8N1 is default. default_config(pSer); } else if (0 == strcmp("BINARY", cmd)) { test_binary(pSer, args); } else if (0 == strcmp("TEXT", cmd)) { test_text(pSer, args); } else if (0 == strcmp("PING", cmd)) { test_ping(pSer, args); } else trace("Unknown command '%s'.\n", cmd); trace("Command %s completed.\n", cmd);}bool CALLBACKserial_filter(void*& pBuf, unsigned int& nRead, CeCosTestSerial& serial, CeCosTestSocket& socket, void* pParem){ ser_filter_state_t* state = (ser_filter_state_t*) pParem; char* buffer = (char*) pBuf; // Don't do anything in the null_filter mode. if (state->null_filter) return true; // Allows trace to be called without a reference to the socket... gdb_socket = &socket; // 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. recover_data_len = 0; state->null_filter = setjmp(fallback_buf) ? true : false; if (state->null_filter) { if (recover_data_len) { unsigned char *s, *d; d = (unsigned char*) pBuf; s = (unsigned char*) recover_data; for (int i = 0; i < recover_data_len; i++) *d++ = *s++; } nRead = recover_data_len; return true; } if (opt_ser_debug && state->first_command_seen) print_hex((unsigned char*) buffer, nRead); // Command handling. // If we are not presently reading a command, look for the // start marker. unsigned int i = 0; if (!state->cmd_flag) for (; i < nRead; i++) { if ('@' == buffer[i]) { state->cmd_flag = 1; // Send the data before the marker. if (i) socket.send(buffer, i); break; } } // If reading a command, look for the end marker. if (state->cmd_flag) { char c = 0; while (i < nRead && state->cmd_i < MAX_CMD_LEN) { c = buffer[i++]; state->cmd[state->cmd_i++] = c; if ('!' == c) { if (i != nRead) { // Hopefully, we'll never have to cope // with this. fprintf(stderr, "Yikes! We need to unread %d bytes!\n", nRead - i); throw "Yikes! We need to unread some bytes!"; } break; } } if (MAX_CMD_LEN == state->cmd_i) { trace("Received too long command. Ignoring it!\n"); state->cmd_i = 0; state->cmd_flag = 0; } else if ('!' == c) { // Was the command completed? state->cmd[state->cmd_i - 1] = 0; // terminate cmd state->cmd_i = 0; state->cmd_flag = 0; state->first_command_seen = true; // skip @ when passing ptr dispatch_command(serial, &state->cmd[1]); } nRead = 0; // Never leave anything for caller // This is a violation of the intended // filter function behavior. } return true;}#ifdef DEFINE_MAINvoidno_gdb(const char* pszPort, int nBaud, FilterFunc *pSerialToSocketFilterFunc, void *pParam, bool *pbStop){ trace("no_gdb, listening on %s\n",pszPort); CeCosTestSocket dummy_socket; CeCosTestSerial serial; serial.SetBlockingReads(false); bool rc=false; // Open serial device. if (!serial.Open(pszPort,nBaud)){ ERROR("Couldn't open port %s\n",pszPort); } else { // Flush the serial buffer. serial.Flush(); serial.ClearError(); enum {BUFSIZE=8192}; void *pBuf=malloc(BUFSIZE); rc=true; while(rc && (0==pbStop || !(*pbStop))){ unsigned int nRead=0; while (1) { if(serial.Read(pBuf,BUFSIZE,nRead)){ if(nRead>0){ break; } CeCosTestUtils::Sleep(1); } else { trace("Serial read failed (%d)\n", errno); } } trace("Serial:%d\n",nRead); if(pSerialToSocketFilterFunc){ rc=pSerialToSocketFilterFunc(pBuf,nRead,serial,dummy_socket, pParam); } } free(pBuf); }}intmain(int argc, char** argv){ int nSock = 0; int baud_rate, nTcpPort; int opt_no_gdb = 0; char* ser_port; int i=1; while(i<argc){ if(argv[i][0]=='-'){ switch(argv[i][1]){ case 't': CeCosTestUtils::EnableTracing(true); break; case 'S': opt_ser_debug = 1; break; case 'n': opt_no_gdb = 1; break; case 'c': opt_console_output = 1; break; default: fprintf(stderr,"Unrecognized switch %s\n",argv[i]); goto Usage; break; } for(int j=i;j<argc;j++){ argv[j]=argv[j+1]; } argc--; argv[argc]=0; } else { i++; } } if(!((3==argc && opt_no_gdb) || (4==argc && !opt_no_gdb))) { goto Usage; } if (opt_no_gdb) { ser_port = argv[1]; baud_rate=atoi(argv[2]); } else { nTcpPort=atoi(argv[1]); if(0==nTcpPort){ fprintf(stderr,"Invalid port %s\n",argv[1]); return main(0,argv); // Provoke usage message } ser_port = argv[2]; baud_rate=atoi(argv[3]); nSock = CeCosTestSocket::Listen(nTcpPort); if (-1 == nSock) { fprintf(stderr, "Couldn't access socket.\n"); throw "listen failed"; } } while (1) { ser_filter_state_t state; gdb_socket = NULL; try { if (opt_no_gdb) no_gdb(ser_port, baud_rate, &serial_filter, &state, NULL); else ConnectSocketToSerial(nSock, ser_port, baud_rate, &serial_filter, NULL, &state, NULL); } catch (const char* p) { trace("Caught filter crash: %s\n", p); } } return 0;Usage: const char *pszMe=CeCosTestUtils::Tail(argv[0]); fprintf(stderr,"Usage: %s [-t -c -S] TcpIPport SerialPort BaudRate\n", // 1 2 3 pszMe); fprintf(stderr," or: %s -n [-t -c -S] SerialPort BaudRate\n", // 1 2 pszMe); fprintf(stderr, " -t: Enable tracing.\n"); fprintf(stderr, " -S: Output data read from serial line.\n"); fprintf(stderr, " -c: Output data on console instead of via GDB.\n"); fprintf(stderr, " -n: No GDB.\n"); return 1;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -