blob: f8396ba3a6a46e9461db4856f7373d3893500a7d [file] [log] [blame]
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/*
* Task to echo any characters from the three non-console USARTs back to all
* non-console USARTs.
*/
#include "atomic.h"
#include "common.h"
#include "compile_time_macros.h"
#include "console.h"
#include "panic.h"
#include "task.h"
#include "timer.h"
#include "usart-stm32f0.h"
#include "usb-stream.h"
#include "util.h"
static void in_ready(struct in_stream const *stream)
{
task_wake(TASK_ID_ECHO);
}
static void out_ready(struct out_stream const *stream)
{
task_wake(TASK_ID_ECHO);
}
USART_CONFIG(usart1, usart1_hw, 115200, 64, 64, in_ready, NULL)
USART_CONFIG(usart3, usart3_hw, 115200, 64, 64, in_ready, NULL)
USART_CONFIG(usart4, usart4_hw, 115200, 64, 64, in_ready, NULL)
USB_STREAM_CONFIG(usb_stream1,
USB_IFACE_STREAM,
USB_STR_STREAM_NAME,
USB_EP_STREAM,
256,
256,
in_ready,
out_ready)
struct stream_console_state {
size_t wrote;
};
struct stream_console_config {
struct stream_console_state *state;
struct in_stream const *in;
struct out_stream const *out;
};
#define STREAM_CONSOLE_CONFIG(NAME, IN, OUT) \
static struct stream_console_state NAME##_state; \
struct stream_console_config const NAME = { \
.state = &NAME##_state, \
.in = IN, \
.out = OUT, \
};
STREAM_CONSOLE_CONFIG(usart1_stream_console, &usart1.in, &usart1.out)
STREAM_CONSOLE_CONFIG(usart3_stream_console, &usart3.in, &usart3.out)
STREAM_CONSOLE_CONFIG(usart4_stream_console, &usart4.in, &usart4.out)
STREAM_CONSOLE_CONFIG(usb_stream1_console, &usb_stream1.in, &usb_stream1.out)
static struct stream_console_config const *const consoles[] = {
&usart1_stream_console,
&usart3_stream_console,
&usart4_stream_console,
&usb_stream1_console,
};
static size_t echo(struct stream_console_config const *const consoles[],
size_t consoles_count)
{
size_t total = 0;
size_t i;
for (i = 0; i < consoles_count; ++i) {
size_t j;
uint8_t buffer[64];
size_t remaining = 0;
size_t count = in_stream_read(consoles[i]->in,
buffer,
sizeof(buffer));
if (count == 0)
continue;
for (j = 0; j < consoles_count; ++j)
consoles[j]->state->wrote = 0;
do {
remaining = 0;
for (j = 0; j < consoles_count; ++j) {
size_t wrote = consoles[j]->state->wrote;
if (count == wrote)
continue;
wrote += out_stream_write(consoles[j]->out,
buffer + wrote,
count - wrote);
consoles[j]->state->wrote = wrote;
remaining += count - wrote;
}
} while (remaining);
total += count;
}
return total;
}
void echo_task(void)
{
usart_init(&usart1);
usart_init(&usart3);
usart_init(&usart4);
while (1) {
while (echo(consoles, ARRAY_SIZE(consoles))) {
/*
* Make sure other tasks, like the HOOKS get to run.
*/
msleep(1);
}
/*
* There was nothing left to echo, go to sleep and be
* woken up by the next input.
*/
task_wait_event(-1);
}
}
static int command_echo_info(int argc, char **argv)
{
char const message[] = "Hello World!\r\n";
size_t i;
ccprintf("USART1 RX dropped %d bytes\n",
atomic_read_clear((uint32_t *) &(usart1.state->rx_dropped)));
ccprintf("USART3 RX dropped %d bytes\n",
atomic_read_clear((uint32_t *) &(usart3.state->rx_dropped)));
ccprintf("USART4 RX dropped %d bytes\n",
atomic_read_clear((uint32_t *) &(usart4.state->rx_dropped)));
for (i = 0; i < ARRAY_SIZE(consoles); ++i)
out_stream_write(consoles[i]->out, message, strlen(message));
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(echo_info,
command_echo_info,
NULL,
"Dump echo task debug info",
NULL);