📄 ser_test_protocol.inl
字号:
//----------------------------------------------------------------------------
// Macros for read/write to serial with error cheking.
static volatile cyg_uint32 r_stamp;
static volatile int aborted;
// This routine will be called if the read "times out"
static void
do_abort(void *handle)
{
cyg_io_handle_t io_handle = (cyg_io_handle_t)handle;
cyg_uint32 len = 1; // Need something here
cyg_io_get_config(io_handle, CYG_IO_GET_CONFIG_SERIAL_ABORT, 0, &len);
aborted = 1;
}
#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)); \
if (ENOERR != __res && -EINTR != __res) { \
TEST_CRASH(__h, TEST_CRASH_IO_READ, \
"cyg_io_read/timeout failed", __res); \
} \
*(__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)); \
if (ENOERR != __res) { \
TEST_CRASH(__h, TEST_CRASH_IO_READ, \
"cyg_io_read failed", __res); \
} \
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)); \
if (ENOERR != __res) { \
TEST_CRASH(__h, TEST_CRASH_IO_WRITE, \
"cyg_io_write failed", __res); \
} \
__res = cyg_io_get_config((__h), \
CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN, \
0, &__len); \
if (ENOERR != __res) { \
TEST_CRASH(__h, TEST_CRASH_IO_DRAIN, \
"DRAIN failed", __res); \
} \
CYG_MACRO_END
//----------------------------------------------------------------------------
// Some libc like functions that are handy to have around.
static int
strlen(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)
void
hang(void)
{
while (1);
}
//-----------------------------------------------------------------------------
// Configuration changing function.
//
// First change to the new config and back again to determine if the driver
// can handle the config.
// If not, return error.
//
// Then query the host for its capability to use the config:
// Format out:
// "@CONFIG:<baud rate code>:<#data bits>:<#stop bits>:<parity on/off>:<flow control code>!"
// Format in:
// OK/ER
//
// On ER, return error.
//
// On OK, change to the new configuration. Resynchronize with the host:
// Target waits for host to send S(ync)
// [host will delay at least .1 secs after changing baud rate so the
// line has time to settle.]
//
// When receiving S(ync), target replies OK to the host which then
// acknowledges with D(one).
//
// Host can also send R(esync) which means it didn't receieve the OK. If
// so the target resends its S(ync) message.
//
// If the synchronization has not succeeded within 1 second
// (configurable in the protocol), both host and target will revert to
// the previous configuration and attempt to synchronize again. If
// this fails, this call will hang and the host will consider the test
// a failure.
//
// To Do:
// Host&protocol currently only supports:
// - no/even parity
int
change_config(cyg_io_handle_t handle, cyg_ser_cfg_t* cfg)
{
cyg_serial_info_t old_cfg, new_cfg;
const char cmd[] = "@CONFIG:";
char reply[2];
cyg_uint32 msglen;
int res;
cyg_uint32 len;
char *p1;
// Prepare 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 = itoa(p1, cfg->flags);
*p1++ = '!';
*p1 = 0; // note: we may append to this later
// Tell user what we're up to.
CYG_TEST_INFO((char *)&cmd_buffer[1]);
// Change to new config and then back to determine if the driver likes it.
len = sizeof(old_cfg);
res = cyg_io_get_config(handle, CYG_IO_GET_CONFIG_SERIAL_INFO,
&old_cfg, &len);
res = cyg_io_get_config(handle, CYG_IO_GET_CONFIG_SERIAL_INFO,
&new_cfg, &len);
if (res != ENOERR) {
TEST_CRASH(handle, TEST_CRASH_IO_GET_CFG,
"Can't get serial config", res);
}
new_cfg.baud = cfg->baud_rate;
new_cfg.word_length = cfg->data_bits;
new_cfg.stop = cfg->stop_bits;
new_cfg.parity = cfg->parity;
new_cfg.flags = cfg->flags;
res = cyg_io_set_config(handle, CYG_IO_SET_CONFIG_SERIAL_INFO,
&new_cfg, &len);
cyg_thread_delay(10); // Some chips don't like changes to happen to fast...
// Driver didn't like it. It will not have changed anything, so it's
// safe to return now.
if (ENOERR != res) {
// Let user know that the config was skipped due to the target.
const char txt_tskipped[] = "- skipped by target!";
p1 = strcpy(p1, txt_tskipped);
*p1 = 0;
CYG_TEST_INFO(&cmd_buffer[1]);
return res;
}
// Succeeded. Change back to the original config so we can communicate
// with the host.
res = cyg_io_set_config(handle, CYG_IO_SET_CONFIG_SERIAL_INFO,
&old_cfg, &len);
cyg_thread_delay(10); // Some chips don't like changes to happen to fast...
if (res != ENOERR) {
TEST_CRASH(handle, TEST_CRASH_IO_SET_CFG,
"Can't set serial config", res);
}
// Send command to host and read host's reply.
msglen = strlen(&cmd_buffer[0]);
Tcyg_io_write(handle, &cmd_buffer[0], &msglen);
msglen = 2;
Tcyg_io_read(handle, &reply[0], &msglen);
// Did host accept configuration?
if ('O' != reply[0] || 'K' != reply[1]) {
// Let user know that the config was skipped due to the host.
const char txt_hskipped[] = "- skipped by host!";
p1 = strcpy(p1, txt_hskipped);
*p1 = 0;
CYG_TEST_INFO(&cmd_buffer[1]);
diag_printf("Host didn't accept config (%02x, %02x).\n",
reply[0], reply[1]);
res = ENOSUPP;
return res;
}
// Now change config and wait for host to send us a S(ync)
// character.
// Loop until protocol exchange completed. This may hang (as seen
// from the host), but only when we get totally lost, in which
// case there's not much else to do really. In this case the host
// will consider the test a FAIL.
len = sizeof(new_cfg);
res = cyg_io_set_config(handle, CYG_IO_SET_CONFIG_SERIAL_INFO,
&new_cfg, &len);
cyg_thread_delay(10); // Some chips don't like changes to happen to fast...
if (res != ENOERR) {
TEST_CRASH(handle, TEST_CRASH_IO_SET_CFG,
"Can't set serial config/2", res);
}
{
int change_succeeded = 0;
int using_old_config = 0;
char in_buf[1];
cyg_uint32 len;
int saw_host_sync;
for (;;) {
aborted = 0; // global abort flag
// FIXME: Timeout time needs to be configurable, and needs to
// be sent to the host before getting here. That would allow
// changing the timeout by just rebuilding the test - without
// changing the host software.
saw_host_sync = 0;
r_stamp = timeout(100, do_abort, handle);
while(!aborted) {
len = 1;
in_buf[0] = 0;
res = cyg_io_read(handle, in_buf, &len);
if (ENOERR != res && -EINTR != res) {
// We may have to reset the driver here if the fail
// was due to a framing or parity error.
break;
}
if ('R' == in_buf[0]) {
// Resync - host didn't see our message. Try again.
saw_host_sync = 0;
} else if ('S' == in_buf[0] && !saw_host_sync) {
// In sync - reply to host if we haven't already
char ok_msg[2] = "OK";
cyg_uint32 ok_len = 2;
Tcyg_io_write(handle, ok_msg, &ok_len);
saw_host_sync = 1;
} else if ('D' == in_buf[0] && saw_host_sync) {
// Done - exchange completed.
change_succeeded = 1;
break;
}
}
untimeout(r_stamp);
if (change_succeeded) {
// If we had to revert to the old configuration, return error.
if (using_old_config)
return -EIO;
else
return ENOERR;
}
// We didn't synchronize with the host. Due to an IO error?
if (ENOERR != res && -EINTR != res) {
// We may have to reset the driver if the fail was due to
// a framing or parity error.
}
// Revert to the old configuration and try again.
len = sizeof(old_cfg);
res = cyg_io_set_config(handle, CYG_IO_SET_CONFIG_SERIAL_INFO,
&old_cfg, &len);
cyg_thread_delay(10); // Some chips don't like changes to happen to fast...
if (res != ENOERR) {
TEST_CRASH(handle, TEST_CRASH_IO_SET_CFG,
"Can't set serial config/3", res);
}
using_old_config = 1;
}
}
}
//-----------------------------------------------------------------------------
// Host sends CRC in decimal ASCII, terminated with !
int
read_host_crc(cyg_io_handle_t handle)
{
int crc;
cyg_uint32 len;
cyg_uint8 ch;
crc = 0;
while (1) {
len = 1;
Tcyg_io_read(handle, &ch, &len);
if ('!' == ch)
break;
if (!((ch >= '0' && ch <= '9'))){
TEST_CRASH(handle, TEST_CRASH_CRC_CHAR,
"Illegal CRC format from host", ch);
}
crc = crc*10 + (ch - '0');
}
return crc;
}
//---------------------------------------------------------------------------
// Test binary data transmission.
// Format out:
// "@BINARY:<byte size>:<mode>!"
// Format in:
// <checksum>!<#size bytes data>
// For echo modes, also:
// Format out:
// <#size bytes data>
// Format in:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -