📄 ser_test_protocol.inl
字号:
//==========================================================================//// ser_test_protocol.c//// Serial device driver testing protocol////==========================================================================//####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-17// Description: Protocol implementation used to test eCos serial devices.// Relies on ser_filter to be present on the host side to// respond to test requests.// // To Do:// o Clean up.// o Clean up config change magic.// o Figure out how to handle kernel dependency// : without kernel, no timeout. Without timeout, no filter auto detection.////####DESCRIPTIONEND#####include <pkgconf/system.h>#include <pkgconf/io.h>#include <pkgconf/io_serial.h>#include <cyg/io/io.h>#include <cyg/io/devtab.h>#include <cyg/io/ttyio.h>#include <cyg/infra/diag.h>#include <cyg/hal/hal_intr.h> // for reclaiming interrup vector//----------------------------------------------------------------------------// Definition of which device to run tests on on various platforms.#if defined(CYGPKG_HAL_POWERPC_COGENT) \ && defined(CYGPKG_IO_SERIAL_POWERPC_COGENT) \ && defined(CYGPKG_IO_SERIAL_POWERPC_COGENT_SERIAL_B)# define TEST_SER_DEV CYGDAT_IO_SERIAL_POWERPC_COGENT_SERIAL_B_NAME# if defined(CYGPKG_IO_SERIAL_TTY_TTY2)# define TEST_TTY_DEV CYGDAT_IO_SERIAL_TTY_TTY2_DEV# endif#endif#if defined(CYGPKG_HAL_ARM_PID) \ && defined(CYGPKG_IO_SERIAL_ARM_PID) \ && defined(CYGPKG_IO_SERIAL_ARM_PID_SERIAL0)# define TEST_SER_DEV CYGDAT_IO_SERIAL_ARM_PID_SERIAL0_NAME# if defined(CYGPKG_IO_SERIAL_TTY_TTY0)# define TEST_TTY_DEV CYGDAT_IO_SERIAL_TTY_TTY0_DEV# endif#endif#if defined(CYGPKG_HAL_ARM_AEB) \ && defined(CYGPKG_IO_SERIAL_ARM_AEB) \ && defined(CYGPKG_IO_SERIAL_ARM_AEB_SERIAL1)# define TEST_SER_DEV CYGDAT_IO_SERIAL_ARM_AEB_SERIAL1_NAME# if defined(CYGPKG_IO_SERIAL_TTY_TTY1)# define TEST_TTY_DEV CYGDAT_IO_SERIAL_TTY_TTY1_DEV# endif#endif#if defined(CYGPKG_HAL_TX39_JMR3904) \ && defined(CYGPKG_IO_SERIAL_TX39_JMR3904) \ && defined(CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0)# define TEST_SER_DEV CYGDAT_IO_SERIAL_TX39_JMR3904_SERIAL0_NAME# if defined(CYGPKG_IO_SERIAL_TTY_TTY1)# define TEST_TTY_DEV CYGDAT_IO_SERIAL_TTY_TTY1_DEV# endif#endif#if defined(CYGPKG_HAL_MN10300_STDEVAL1) \ && defined(CYGPKG_IO_SERIAL_MN10300) \ && defined(CYGPKG_IO_SERIAL_MN10300_SERIAL1)// Note: Serial1 is *not* the same port as GDB is using. It seems that// CygMon is interfering with the tests if run on the same port.// This configuration allows the serial driver to be tested using the// filter in stand alone mode (option -n).# define TEST_SER_DEV CYGDAT_IO_SERIAL_MN10300_SERIAL1_NAME# if defined(CYGPKG_IO_SERIAL_TTY_TTY1)# define TEST_TTY_DEV CYGDAT_IO_SERIAL_TTY_TTY1_DEV# endif#endif#if defined(CYGPKG_HAL_SPARCLITE_SLEB) \ && defined(CYGPKG_IO_SERIAL_SPARCLITE_SLEB) \ && defined(CYGPKG_IO_SERIAL_SPARCLITE_SLEB_CON1)# define TEST_SER_DEV CYGDAT_IO_SERIAL_SPARCLITE_SLEB_CON1_NAME# define SER_OVERRIDE_INT_1 CYGNUM_HAL_INTERRUPT_9# define SER_OVERRIDE_INT_2 CYGNUM_HAL_INTERRUPT_10# if defined(CYGPKG_IO_SERIAL_TTY_TTY0)# define TEST_TTY_DEV CYGDAT_IO_SERIAL_TTY_TTY0_DEV# endif#endif// We can't rely on haldiag for ser_filter detection - it may not define// a working character reading function.#ifndef TEST_SER_DEV# define SER_NOP_TEST# define TTY_NOP_TEST# define TEST_SER_DEV "/dev/null"# define TEST_TTY_DEV "/dev/null"#else# ifndef TEST_TTY_DEV# define TTY_NOP_TEST# define TEST_TTY_DEV "/dev/null"# endif#endif//----------------------------------------------------------------------------// FIXME: The PPC sometimes sees a spurious byte. There is workaround code// that can be enabled here.#define HANDLE_SPURIOUS 1//----------------------------------------------------------------------------// The data in buffer and the cmd buffer#define IN_BUFFER_SIZE 1024cyg_uint8 in_buffer[IN_BUFFER_SIZE];cyg_int8 cmd_buffer[128];//----------------------------------------------------------------------------// Some types specific to the testing protocol.typedef enum { MODE_NO_ECHO = 0, MODE_EOP_ECHO, MODE_DUPLEX_ECHO} cyg_mode_t;typedef enum { TEST_RETURN_OK = ENOERR, TEST_RETURN_NA} cyg_test_return_t;typedef struct ser_cfg { cyg_serial_baud_rate_t baud_rate; cyg_serial_word_length_t data_bits; cyg_serial_stop_bits_t stop_bits; cyg_serial_parity_t parity; // etc...} cyg_ser_cfg_t;//----------------------------------------------------------------------------// A few predefined configurations. These must all be valid for any// given target until change_config is behaving correctly.cyg_ser_cfg_t test_configs[] = {#if !defined(CYGPKG_HAL_TX39_JMR3904) && \ !defined(CYGPKG_HAL_ARM_PID) && \ !defined(CYGPKG_HAL_ARM_AEB) && \ !defined(CYGPKG_HAL_MN10300_STDEVAL1) && \ !defined(CYGPKG_HAL_SPARCLITE_SLEB) { CYGNUM_SERIAL_BAUD_115200, CYGNUM_SERIAL_WORD_LENGTH_8, CYGNUM_SERIAL_STOP_1, CYGNUM_SERIAL_PARITY_NONE },#endif#if !defined(CYGPKG_HAL_TX39_JMR3904) && \ !defined(CYGPKG_HAL_ARM_AEB) && \ !defined(CYGPKG_HAL_SPARCLITE_SLEB) { CYGNUM_SERIAL_BAUD_57600, CYGNUM_SERIAL_WORD_LENGTH_8, CYGNUM_SERIAL_STOP_1, CYGNUM_SERIAL_PARITY_NONE },#endif { CYGNUM_SERIAL_BAUD_38400, CYGNUM_SERIAL_WORD_LENGTH_8, CYGNUM_SERIAL_STOP_1, CYGNUM_SERIAL_PARITY_NONE }, { CYGNUM_SERIAL_BAUD_19200, CYGNUM_SERIAL_WORD_LENGTH_8, CYGNUM_SERIAL_STOP_1, CYGNUM_SERIAL_PARITY_NONE },#if !defined(CYGPKG_HAL_TX39_JMR3904) && !defined(CYGPKG_HAL_ARM_PID) { CYGNUM_SERIAL_BAUD_9600, CYGNUM_SERIAL_WORD_LENGTH_8, CYGNUM_SERIAL_STOP_1, CYGNUM_SERIAL_PARITY_NONE },#endif#if !defined(CYGPKG_HAL_TX39_JMR3904) && \ !defined(CYGPKG_HAL_ARM_AEB) && \ !defined(CYGPKG_HAL_ARM_PID) // One stop bit, even parity { CYGNUM_SERIAL_BAUD_19200, CYGNUM_SERIAL_WORD_LENGTH_8, CYGNUM_SERIAL_STOP_1, CYGNUM_SERIAL_PARITY_EVEN },#endif#if !defined(CYGPKG_HAL_TX39_JMR3904) && \ !defined(CYGPKG_HAL_ARM_AEB) && \ !defined(CYGPKG_HAL_ARM_PID) // Two stop bits, even parity { CYGNUM_SERIAL_BAUD_19200, CYGNUM_SERIAL_WORD_LENGTH_8, CYGNUM_SERIAL_STOP_2, CYGNUM_SERIAL_PARITY_EVEN },#endif#if !defined(CYGPKG_HAL_TX39_JMR3904) // Two stop bits, no parity { CYGNUM_SERIAL_BAUD_19200, CYGNUM_SERIAL_WORD_LENGTH_8, CYGNUM_SERIAL_STOP_2, CYGNUM_SERIAL_PARITY_NONE },#endif};//----------------------------------------------------------------------------// 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(__slot) \do { \ __ptr1 = index(__ptr2, (int) ':'); \ if (__ptr1) \ *__ptr1 = 0; \ v = atoi(__ptr2); \ __ptr2 = __ptr1+1; \ (__slot) = v; \} while (0)//----------------------------------------------------------------------------// CRC magic - it's a bit of a hack for now.// FIXME: standard definition?#define ADD_CRC_BYTE(__crc, __c) \ CYG_MACRO_START \ (__crc) = ((__crc) << 1) ^ (__c); \ CYG_MACRO_END// FIXME: Hack to allow easy ASCII transfer.#define FIX_CRC(__crc, __icrc) \ CYG_MACRO_START \ __icrc = (int) (__crc); \ if (__icrc < 0) \ __icrc = -__icrc; \ CYG_MACRO_END//----------------------------------------------------------------------------// Macros for read/write to serial with error cheking.cyg_uint32 r_stamp;// This routine will be called if the read "times out"static voiddo_abort(void *handle){ cyg_io_handle_t io_handle = (cyg_io_handle_t)handle; cyg_int32 len = 1; // Need something here cyg_io_get_config(io_handle, CYG_IO_GET_CONFIG_SERIAL_ABORT, 0, &len);}#include "timeout.inl"// Read with timeout (__t = timeout in ticks, int* __r = result)#define Tcyg_io_read_timeout(__h, __d, __l, __t, __r) \ CYG_MACRO_START \ int __res; \ r_stamp = timeout((__t), do_abort, (__h)); \ __res = cyg_io_read((__h), (__d), (__l)); \ CYG_TEST_CHECK((ENOERR == __res || -EINTR == __res),"cyg_io_read failed");\ *(__r) = __res; \ untimeout(r_stamp); \ CYG_MACRO_END#define Tcyg_io_read(__h, __d, __l) \ CYG_MACRO_START \ int __res = cyg_io_read((__h), (__d), (__l)); \ CYG_TEST_CHECK(ENOERR == __res, "cyg_io_read failed"); \ CYG_MACRO_END#define Tcyg_io_write(__h, __d, __l) \ CYG_MACRO_START \ int __res; \ cyg_uint32 __len = 1; \ __res = cyg_io_write((__h), (__d), (__l)); \ CYG_TEST_CHECK(ENOERR == __res, "cyg_io_write failed"); \ __res = cyg_io_get_config((__h), \ CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN, \ 0, &__len); \ CYG_TEST_CHECK(ENOERR == __res, "DRAIN failed"); \ CYG_MACRO_END//----------------------------------------------------------------------------// Some libc like functions that are handy to have around.static intstrlen(const char *c){ int l = 0; while (*c++) l++; return l;}static char*strcpy(char* dest, const char* src){ char c; while ((c = *src++)) { *dest++ = c; } *dest = c; return dest;}static char*itoa(char* dest, int v){ char b[16]; char* p = &b[16]; *--p = 0; if (v) { while (v){ *--p = (v % 10) + '0'; v = v / 10; } } else *--p = '0'; return strcpy(dest, p);}#define min(_a, _b) ((_a) < (_b)) ? (_a) : (_b)voidhang(void){ while (1);}//-----------------------------------------------------------------------------// Configuration changing function.// FIXME: This is still slightly bogus in that it doesn't check for target// capabilities. Correct way is;// o try setting new cfg// o restore// o if OK:// o send cfg to target// o if reply OK:// o change to new cfg//// Host&protocol currently only supports:// - no/even parityintchange_config(cyg_io_handle_t handle, cyg_ser_cfg_t* cfg){ const char cmd[] = "@CONFIG:"; char reply[2]; int msglen; int res; cyg_uint8 *p1; // Prepare and send the command. p1 = &cmd_buffer[0]; p1 = strcpy(p1, &cmd[0]); p1 = itoa(p1, cfg->baud_rate); *p1++ = ':'; p1 = itoa(p1, cfg->data_bits); *p1++ = ':'; p1 = itoa(p1, cfg->stop_bits); *p1++ = ':'; p1 = itoa(p1, cfg->parity); *p1++ = '!'; *p1++ = 0; CYG_TEST_INFO(&cmd_buffer[1]); msglen = strlen(&cmd_buffer[0]); Tcyg_io_write(handle, &cmd_buffer[0], &msglen); msglen = 2; Tcyg_io_read(handle, &reply[0], &msglen); if (reply[0] == 'O') { // Change config cyg_serial_info_t serial_info; int len = sizeof(serial_info); res = cyg_io_get_config(handle, CYG_IO_GET_CONFIG_SERIAL_INFO, &serial_info, &len); if (res != ENOERR) { diag_printf("Can't get serial config - DEVIO error: %d\n", res); hang(); } serial_info.baud = cfg->baud_rate; serial_info.word_length = cfg->data_bits; serial_info.stop = cfg->stop_bits; serial_info.parity = cfg->parity; res = cyg_io_set_config(handle, CYG_IO_SET_CONFIG_SERIAL_INFO, &serial_info, &len); if (res != ENOERR) { diag_printf("Can't set serial config - DEVIO error: %d\n", res); hang(); } res = ENOERR; } else { res = ENOSUPP;#ifdef __DEVELOPER__ diag_printf("Host didn't accept config (%02x, %02x).\n", reply[0], reply[1]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -