diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2016-05-23 13:48:24 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2016-05-23 13:48:24 +0900 |
commit | b6603f677159b72a8165a5475dad525947889881 (patch) | |
tree | 0ebf65e409053730b9546a00d5debd3f1a7eb521 /example-fs-bb48 | |
parent | ee92bb15b361b3daee816a4e930be0032be2d9e7 (diff) |
Update example-fs-bb48
Diffstat (limited to 'example-fs-bb48')
-rw-r--r-- | example-fs-bb48/sample.c | 168 | ||||
-rw-r--r-- | example-fs-bb48/tty.h | 31 | ||||
-rw-r--r-- | example-fs-bb48/usb-cdc.c | 555 |
3 files changed, 453 insertions, 301 deletions
diff --git a/example-fs-bb48/sample.c b/example-fs-bb48/sample.c index 9250700..2935709 100644 --- a/example-fs-bb48/sample.c +++ b/example-fs-bb48/sample.c @@ -4,7 +4,7 @@ #include <chopstx.h> #include "usb_lld.h" -#include "stream.h" +#include "tty.h" #include "board.h" #include "crc32.h" @@ -93,43 +93,12 @@ blk (void *arg) return NULL; } -#define INTR_REQ_USB 24 -static void * -usb_intr (void *arg) -{ - extern void usb_lld_init (uint8_t feature); - extern void usb_interrupt_handler (void); - - chopstx_intr_t interrupt; - - (void)arg; - chopstx_claim_irq (&interrupt, INTR_REQ_USB); - usb_lld_init (0x80); /* Bus powered. */ - - while (1) - { - chopstx_intr_wait (&interrupt); - - /* Process interrupt. */ - usb_interrupt_handler (); - } - - return NULL; -} - -#if defined(BUSY_LOOP) -#define PRIO_PWM (CHOPSTX_SCHED_RR|1) -#define PRIO_BLK (CHOPSTX_SCHED_RR|1) -#else #define PRIO_PWM 3 #define PRIO_BLK 2 -#endif -#define PRIO_INTR 4 extern uint8_t __process1_stack_base__, __process1_stack_size__; extern uint8_t __process2_stack_base__, __process2_stack_size__; -extern uint8_t __process3_stack_base__, __process3_stack_size__; const uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__; const size_t __stacksize_pwm = (size_t)&__process1_stack_size__; @@ -137,9 +106,6 @@ const size_t __stacksize_pwm = (size_t)&__process1_stack_size__; const uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__; const size_t __stacksize_blk = (size_t)&__process2_stack_size__; -const uint32_t __stackaddr_intr = (uint32_t)&__process3_stack_base__; -const size_t __stacksize_intr = (size_t)&__process3_stack_size__; - static char hexchar (uint8_t x) { @@ -153,24 +119,11 @@ static char hexchar (uint8_t x) } -static int -check_recv (void *arg) -{ - struct stream *s = arg; - if ((s->flags & FLAG_CONNECTED) == 0) - return 1; - if ((s->flags & FLAG_RECV_AVAIL)) - return 1; - return 0; -} - - int main (int argc, const char *argv[]) { - struct stream *st; + struct tty *tty; uint8_t count; - extern uint32_t bDeviceState; (void)argc; (void)argv; @@ -182,14 +135,10 @@ main (int argc, const char *argv[]) chopstx_cond_init (&cnd0); chopstx_cond_init (&cnd1); - st = stream_open (); - m = 10; chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL); chopstx_create (PRIO_BLK, __stackaddr_blk, __stacksize_blk, blk, NULL); - chopstx_create (PRIO_INTR, __stackaddr_intr, __stacksize_intr, - usb_intr, NULL); chopstx_usec_wait (200*1000); @@ -199,81 +148,80 @@ main (int argc, const char *argv[]) chopstx_mutex_unlock (&mtx); u = 1; - while (bDeviceState != CONFIGURED) - chopstx_usec_wait (500*1000); + + tty = tty_open (); + tty_wait_configured (tty); count = 0; + m = 50; while (1) { - uint8_t s[64]; + uint8_t s[LINEBUFSIZE]; u = 1; - if (stream_wait_connection (st) < 0) - { - chopstx_usec_wait (1000*1000); - continue; - } + tty_wait_connection (tty); - chopstx_usec_wait (500*1000); + chopstx_usec_wait (50*1000); /* Send ZLP at the beginning. */ - stream_send (st, s, 0); + tty_send (tty, s, 0); memcpy (s, "xx: Hello, World with Chopstx!\r\n", 32); s[0] = hexchar (count >> 4); s[1] = hexchar (count & 0x0f); count++; - if (stream_send (st, s, 32) < 0) + if (tty_send (tty, s, 32) < 0) continue; while (1) { int size; uint32_t usec; - struct chx_poll_cond poll_desc; - - poll_desc.type = CHOPSTX_POLL_COND; - poll_desc.ready = 0; - poll_desc.cond = &st->cnd; - poll_desc.mutex = &st->mtx; - poll_desc.check = check_recv; - poll_desc.arg = st; - - /* With chopstx_poll, we can do timed cond_wait */ - usec = 3000000; - if (chopstx_poll (&usec, 1, &poll_desc)) + + usec = 3000000; /* 3.0 seconds */ + size = tty_recv (tty, s + 4, &usec); + if (size < 0) + break; + + if (usec) { - size = stream_recv (st, s + 4); + unsigned int value; - if (size < 0) - break; + if (s[4] == 't') + { + s[0] = 'T'; + s[1] = 'M'; + + adc_start_conversion (0, 1); + adc_wait_completion (NULL); + value = adc_buf[0]; - if (size >= 0) + s[4] = hexchar (value >> 28); + s[5] = hexchar (value >> 24); + s[6] = hexchar (value >> 20); + s[7] = hexchar (value >> 16); + s[8] = hexchar (value >> 12); + s[9] = hexchar (value >> 8); + s[10] = hexchar (value >> 4); + s[11] = hexchar (value); + s[12] = '\r'; + s[13] = '\n'; + + if (tty_send (tty, s, 14) < 0) + break; + } + else if (s[4] == 'c') { - unsigned int value; - - if (s[4] == 't') - { - s[0] = 'T'; - s[1] = 'M'; - - adc_start_conversion (0, 1); - adc_wait_completion (NULL); - value = adc_buf[0]; - } - else - { - int i; - - crc32_init (); - s[0] = hexchar (size >> 4); - s[1] = hexchar (size & 0x0f); - - for (i = 0; i < size; i++) - crc32_u8 (s[4 + i]); - value = crc32_value () ^ 0xffffffff; - } + int i; + + crc32_init (); + s[0] = hexchar (size >> 4); + s[1] = hexchar (size & 0x0f); + + for (i = 0; i < size; i++) + crc32_u8 (s[4 + i]); + value = crc32_value () ^ 0xffffffff; s[4] = hexchar (value >> 28); s[5] = hexchar (value >> 24); @@ -285,7 +233,19 @@ main (int argc, const char *argv[]) s[11] = hexchar (value); s[12] = '\r'; s[13] = '\n'; - if (stream_send (st, s, 14) < 0) + + if (tty_send (tty, s, 14) < 0) + break; + } + else + { + s[0] = hexchar (size >> 4); + s[1] = hexchar (size & 0x0f); + s[2] = ':'; + s[3] = ' '; + s[size + 4] = '\r'; + s[size + 5] = '\n'; + if (tty_send (tty, s, size + 6) < 0) break; } } diff --git a/example-fs-bb48/tty.h b/example-fs-bb48/tty.h index 77b7014..bd0f070 100644 --- a/example-fs-bb48/tty.h +++ b/example-fs-bb48/tty.h @@ -1,26 +1,9 @@ -#define BUFSIZE 128 -#define FLAG_CONNECTED (1 << 0) -#define FLAG_SEND_AVAIL (1 << 1) -#define FLAG_RECV_AVAIL (1 << 2) +#define LINEBUFSIZE 128 -/* - * Current implementation is synchronous and buffers are not yet used. - */ -struct stream { - chopstx_mutex_t mtx; - chopstx_cond_t cnd; - int sending; - unsigned int recv_len; - uint8_t recv_buf[BUFSIZE]; - uint8_t buf_send[BUFSIZE]; /* Not yet used. */ - uint8_t cnt_send_head; /* Not yet used. */ - uint8_t cnt_send_tail; /* Not yet used. */ - uint8_t cnt_recv_head; /* Not yet used. */ - uint8_t cnt_recv_tail; /* Not yet used. */ - uint32_t flags; -}; +struct tty; -struct stream *stream_open (void); -int stream_wait_connection (struct stream *st); -int stream_send (struct stream *st, uint8_t *buf, uint8_t count); -int stream_recv (struct stream *st, uint8_t *buf); +struct tty *tty_open (void); +void tty_wait_configured (struct tty *tty); +void tty_wait_connection (struct tty *tty); +int tty_send (struct tty *tty, uint8_t *buf, int count); +int tty_recv (struct tty *tty, uint8_t *buf, uint32_t *timeout); diff --git a/example-fs-bb48/usb-cdc.c b/example-fs-bb48/usb-cdc.c index 58588c8..b412cf1 100644 --- a/example-fs-bb48/usb-cdc.c +++ b/example-fs-bb48/usb-cdc.c @@ -3,19 +3,84 @@ #include <chopstx.h> #include <string.h> #include "usb_lld.h" -#include "stream.h" +#include "tty.h" -static uint8_t send_buf[64]; -static unsigned int send_len; -static uint8_t send_buf1[64]; +static chopstx_intr_t usb_intr; -static uint8_t recv_buf[64]; -static unsigned int recv_len; +struct line_coding +{ + uint32_t bitrate; + uint8_t format; + uint8_t paritytype; + uint8_t datatype; +} __attribute__((packed)); + +static const struct line_coding line_coding0 = { + 115200, /* baud rate: 115200 */ + 0x00, /* stop bits: 1 */ + 0x00, /* parity: none */ + 0x08 /* bits: 8 */ +}; -static uint8_t inputline[64]; -static unsigned int inputline_len; +/* + * Currently, we only support a single TTY. + * + * It is possible to extend to support multiple TTYs, for multiple + * interfaces. + * + * In that case, add argument to TTY_OPEN function and + * modify TTY_GET function to get the TTY structure. Functions which + * directy accesses TTY0 (usb_cb_device_reset and usb_cb_handle_event) + * should be modified, too. + * + * Modification of TTY_MAIN thread will be also needed to echo back + * input for each TTY, and the thread should run if one of TTY is + * opened. + */ + +struct tty { + chopstx_mutex_t mtx; + chopstx_cond_t cnd; + uint8_t inputline[LINEBUFSIZE]; /* Line editing is supported */ + uint8_t send_buf[LINEBUFSIZE]; /* Sending ring buffer for echo back */ + uint8_t send_buf0[64]; + uint8_t recv_buf0[64]; + uint32_t inputline_len : 8; + uint32_t send_head : 8; + uint32_t send_tail : 8; + uint32_t flag_connected : 1; + uint32_t flag_send_ready : 1; + uint32_t flag_input_avail : 1; + uint32_t : 2; + uint32_t device_state : 3; /* USB device status */ + struct line_coding line_coding; +}; + +static struct tty tty0; + +/* + * Locate TTY structure from interface number or endpoint number. + * Currently, it always returns tty0, because we only have the one. + */ +static struct tty * +tty_get (int interface, uint8_t ep_num) +{ + struct tty *t = &tty0; + + if (interface >= 0) + { + if (interface == 0) + t = &tty0; + } + else + { + if (ep_num == ENDP1 || ep_num == ENDP2 || ep_num == ENDP3) + t = &tty0; + } + + return t; +} -static struct stream stream; #define USB_CDC_REQ_SET_LINE_CODING 0x20 #define USB_CDC_REQ_GET_LINE_CODING 0x21 @@ -40,6 +105,8 @@ static const uint8_t vcom_device_desc[18] = { 1 /* bNumConfigurations. */ }; +#define VCOM_FEATURE_BUS_POWERED 0x80 + /* Configuration Descriptor tree for a CDC.*/ static const uint8_t vcom_config_desc[67] = { 9, @@ -49,7 +116,7 @@ static const uint8_t vcom_config_desc[67] = { 0x02, /* bNumInterfaces. */ 0x01, /* bConfigurationValue. */ 0, /* iConfiguration. */ - 0x80, /* bmAttributes (bus powered). */ + VCOM_FEATURE_BUS_POWERED, /* bmAttributes. */ 50, /* bMaxPower (100mA). */ /* Interface Descriptor.*/ 9, @@ -162,21 +229,24 @@ static const uint8_t vcom_string3[28] = { #define NUM_INTERFACES 2 -uint32_t bDeviceState = UNCONNECTED; /* USB device status */ - void usb_cb_device_reset (void) { - usb_lld_reset (vcom_config_desc[7]); + usb_lld_reset (VCOM_FEATURE_BUS_POWERED); /* Initialize Endpoint 0 */ usb_lld_setup_endpoint (ENDP0, 1, 1); - chopstx_mutex_lock (&stream.mtx); - stream.flags = 0; - bDeviceState = ATTACHED; - chopstx_mutex_unlock (&stream.mtx); + chopstx_mutex_lock (&tty0.mtx); + tty0.inputline_len = 0; + tty0.send_head = tty0.send_tail = 0; + tty0.flag_connected = 0; + tty0.flag_send_ready = 1; + tty0.flag_input_avail = 0; + tty0.device_state = ATTACHED; + memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding)); + chopstx_mutex_unlock (&tty0.mtx); } @@ -187,34 +257,19 @@ usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, struct req_args *arg) { uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT); - if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) + if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0 && USB_SETUP_SET (req) && req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE) { + struct tty *t = tty_get (arg->index, 0); + /* Open/close the connection. */ - chopstx_mutex_lock (&stream.mtx); - stream.flags &= ~FLAG_CONNECTED; - stream.flags |= ((arg->value & CDC_CTRL_DTR) != 0)? FLAG_CONNECTED : 0; - chopstx_cond_signal (&stream.cnd); - recv_len = 0; - usb_lld_rx_enable (ENDP3, recv_buf, 64); - chopstx_mutex_unlock (&stream.mtx); + chopstx_mutex_lock (&t->mtx); + t->flag_connected = ((arg->value & CDC_CTRL_DTR) != 0); + chopstx_cond_signal (&t->cnd); + chopstx_mutex_unlock (&t->mtx); } } -struct line_coding -{ - uint32_t bitrate; - uint8_t format; - uint8_t paritytype; - uint8_t datatype; -} __attribute__((packed)); - -static struct line_coding line_coding = { - 115200, /* baud rate: 115200 */ - 0x00, /* stop bits: 1 */ - 0x00, /* parity: none */ - 0x08 /* bits: 8 */ -}; static int @@ -222,15 +277,21 @@ vcom_port_data_setup (uint8_t req, uint8_t req_no, struct req_args *arg) { if (USB_SETUP_GET (req)) { + struct tty *t = tty_get (arg->index, 0); + if (req_no == USB_CDC_REQ_GET_LINE_CODING) - return usb_lld_reply_request (&line_coding, sizeof(line_coding), arg); + return usb_lld_reply_request (&t->line_coding, + sizeof (struct line_coding), arg); } else /* USB_SETUP_SET (req) */ { if (req_no == USB_CDC_REQ_SET_LINE_CODING - && arg->len == sizeof (line_coding)) + && arg->len == sizeof (struct line_coding)) { - usb_lld_set_data_to_recv (&line_coding, sizeof (line_coding)); + struct tty *t = tty_get (arg->index, 0); + + usb_lld_set_data_to_recv (&t->line_coding, + sizeof (struct line_coding)); return USB_SUCCESS; } else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE) @@ -313,10 +374,7 @@ vcom_setup_endpoints_for_interface (uint16_t interface, int stop) { usb_lld_setup_endpoint (ENDP1, 0, 1); usb_lld_setup_endpoint (ENDP3, 1, 0); -#if 0 - /* Start with no data receiving */ - usb_lld_stall (ENDP3); -#endif + /* Start with no data receiving (ENDP3 not enabled)*/ } else { @@ -335,7 +393,9 @@ usb_cb_handle_event (uint8_t event_type, uint16_t value) switch (event_type) { case USB_EVENT_ADDRESS: - bDeviceState = ADDRESSED; + chopstx_mutex_lock (&tty0.mtx); + tty0.device_state = ADDRESSED; + chopstx_mutex_unlock (&tty0.mtx); return USB_SUCCESS; case USB_EVENT_CONFIG: current_conf = usb_lld_current_configuration (); @@ -347,7 +407,9 @@ usb_cb_handle_event (uint8_t event_type, uint16_t value) usb_lld_set_configuration (1); for (i = 0; i < NUM_INTERFACES; i++) vcom_setup_endpoints_for_interface (i, 0); - bDeviceState = CONFIGURED; + chopstx_mutex_lock (&tty0.mtx); + tty0.device_state = CONFIGURED; + chopstx_mutex_unlock (&tty0.mtx); } else if (current_conf != value) { @@ -357,12 +419,12 @@ usb_cb_handle_event (uint8_t event_type, uint16_t value) usb_lld_set_configuration (0); for (i = 0; i < NUM_INTERFACES; i++) vcom_setup_endpoints_for_interface (i, 1); - bDeviceState = ADDRESSED; + chopstx_mutex_lock (&tty0.mtx); + tty0.device_state = ADDRESSED; + chopstx_mutex_unlock (&tty0.mtx); } /* Do nothing when current_conf == value */ return USB_SUCCESS; - - return USB_SUCCESS; default: break; } @@ -402,52 +464,67 @@ usb_cb_interface (uint8_t cmd, struct req_args *arg) } +/* + * Put a character into the ring buffer to be send back. + */ static void -stream_echo_char (int c) +put_char_to_ringbuffer (struct tty *t, int c) { - chopstx_mutex_lock (&stream.mtx); - if (send_len < sizeof (send_buf)) - send_buf[send_len++] = c; - else - { - /* All that we can is ignoring the output. */ - ; - } + uint32_t next = (t->send_tail + 1) % LINEBUFSIZE; + + if (t->send_head == next) + /* full */ + /* All that we can do is ignore this char. */ + return; + + t->send_buf[t->send_tail] = c; + t->send_tail = next; +} - if (stream.sending == 0) +/* + * Get characters from ring buffer into S. + */ +static int +get_chars_from_ringbuffer (struct tty *t, uint8_t *s, int len) +{ + int i = 0; + + if (t->send_head == t->send_tail) + /* Empty */ + return i; + + do { - memcpy (send_buf1, send_buf, send_len); - usb_lld_tx_enable (ENDP1, send_buf1, send_len); - send_len = 0; - stream.sending = 1; + s[i++] = t->send_buf[t->send_head]; + t->send_head = (t->send_head + 1) % LINEBUFSIZE; } - chopstx_mutex_unlock (&stream.mtx); + while (t->send_head != t->send_tail && i < len); + + return i; +} + + +static void +tty_echo_char (struct tty *t, int c) +{ + put_char_to_ringbuffer (t, c); } void usb_cb_tx_done (uint8_t ep_num) { + struct tty *t = tty_get (-1, ep_num); + if (ep_num == ENDP1) { - chopstx_mutex_lock (&stream.mtx); - stream.sending = 0; - if (send_len) + chopstx_mutex_lock (&t->mtx); + if (t->flag_send_ready == 0) { - stream.sending = 1; - memcpy (send_buf1, send_buf, send_len); - usb_lld_tx_enable (ENDP1, send_buf1, send_len); - send_len = 0; + t->flag_send_ready = 1; + chopstx_cond_signal (&t->cnd); } - else - { - if ((stream.flags & FLAG_SEND_AVAIL)) - { - stream.flags &= ~FLAG_SEND_AVAIL; - chopstx_cond_signal (&stream.cnd); - } - } - chopstx_mutex_unlock (&stream.mtx); + chopstx_mutex_unlock (&t->mtx); } else if (ep_num == ENDP2) { @@ -456,162 +533,294 @@ usb_cb_tx_done (uint8_t ep_num) } -static void -stream_input_char (int c) +static int +tty_input_char (struct tty *t, int c) { unsigned int i; + int r = 0; /* Process DEL, C-U, C-R, and RET as editing command. */ + chopstx_mutex_lock (&t->mtx); switch (c) { case 0x0d: /* Control-M */ - stream_echo_char (0x0d); - stream_echo_char (0x0a); - chopstx_mutex_lock (&stream.mtx); - if ((stream.flags & FLAG_RECV_AVAIL) == 0) - { - memcpy (stream.recv_buf, inputline, inputline_len); - stream.recv_len = inputline_len; - stream.flags |= FLAG_RECV_AVAIL; - chopstx_cond_signal (&stream.cnd); - } - chopstx_mutex_unlock (&stream.mtx); - inputline_len = 0; + tty_echo_char (t, 0x0d); + tty_echo_char (t, 0x0a); + t->flag_input_avail = 1; + r = 1; + chopstx_cond_signal (&t->cnd); break; case 0x12: /* Control-R */ - stream_echo_char ('^'); - stream_echo_char ('R'); - stream_echo_char (0x0d); - stream_echo_char (0x0a); - for (i = 0; i < inputline_len; i++) - stream_echo_char (inputline[i]); + tty_echo_char (t, '^'); + tty_echo_char (t, 'R'); + tty_echo_char (t, 0x0d); + tty_echo_char (t, 0x0a); + for (i = 0; i < t->inputline_len; i++) + tty_echo_char (t, t->inputline[i]); break; case 0x15: /* Control-U */ - for (i = 0; i < inputline_len; i++) + for (i = 0; i < t->inputline_len; i++) { - stream_echo_char (0x08); - stream_echo_char (0x20); - stream_echo_char (0x08); + tty_echo_char (t, 0x08); + tty_echo_char (t, 0x20); + tty_echo_char (t, 0x08); } - inputline_len = 0; + t->inputline_len = 0; break; case 0x7f: /* DEL */ - if (inputline_len > 0) + if (t->inputline_len > 0) { - stream_echo_char (0x08); - stream_echo_char (0x20); - stream_echo_char (0x08); - inputline_len--; + tty_echo_char (t, 0x08); + tty_echo_char (t, 0x20); + tty_echo_char (t, 0x08); + t->inputline_len--; } break; default: - if (inputline_len < sizeof (inputline)) + if (t->inputline_len < sizeof (t->inputline)) { - stream_echo_char (c); - inputline[inputline_len++] = c; + tty_echo_char (t, c); + t->inputline[t->inputline_len++] = c; } else /* Beep */ - stream_echo_char (0x0a); + tty_echo_char (t, 0x0a); break; } + chopstx_mutex_unlock (&t->mtx); + return r; } void usb_cb_rx_ready (uint8_t ep_num) { + struct tty *t = tty_get (-1, ep_num); + if (ep_num == ENDP3) { int i, r; r = usb_lld_rx_data_len (ENDP3); for (i = 0; i < r; i++) - stream_input_char (recv_buf[i]); + if (tty_input_char (t, t->recv_buf0[i])) + break; - usb_lld_rx_enable (ENDP3, recv_buf, 64); + chopstx_mutex_lock (&t->mtx); + if (t->flag_input_avail == 0) + usb_lld_rx_enable (ENDP3, t->recv_buf0, 64); + chopstx_mutex_unlock (&t->mtx); } } -struct stream * -stream_open (void) +static void *tty_main (void *arg); + +#define INTR_REQ_USB 24 +#define PRIO_TTY 4 + +extern uint8_t __process3_stack_base__, __process3_stack_size__; +const uint32_t __stackaddr_tty = (uint32_t)&__process3_stack_base__; +const size_t __stacksize_tty = (size_t)&__process3_stack_size__; + +struct tty * +tty_open (void) { - chopstx_mutex_init (&stream.mtx); - chopstx_cond_init (&stream.cnd); - return &stream; + chopstx_mutex_init (&tty0.mtx); + chopstx_cond_init (&tty0.cnd); + tty0.inputline_len = 0; + tty0.send_head = tty0.send_tail = 0; + tty0.flag_connected = 0; + tty0.flag_send_ready = 1; + tty0.flag_input_avail = 0; + tty0.device_state = UNCONNECTED; + memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding)); + + chopstx_create (PRIO_TTY, __stackaddr_tty, __stacksize_tty, tty_main, &tty0); + return &tty0; } -int -stream_wait_connection (struct stream *st) + +static void * +tty_main (void *arg) { - chopstx_mutex_lock (&st->mtx); - while ((stream.flags & FLAG_CONNECTED) == 0) - chopstx_cond_wait (&st->cnd, &st->mtx); - chopstx_mutex_unlock (&st->mtx); - stream.flags &= ~FLAG_SEND_AVAIL; - return 0; + struct tty *t = arg; + +#if defined(OLDER_SYS_H) + /* + * Historically (before sys < 3.0), NVIC priority setting for USB + * interrupt was done in usb_lld_sys_init. Thus this code. + * + * When USB interrupt occurs between usb_lld_init (which assumes + * ISR) and chopstx_claim_irq (which clears pending interrupt), + * invocation of usb_interrupt_handler won't occur. + * + * Calling usb_interrupt_handler is no harm even if there were no + * interrupts, thus, we call it unconditionally here, just in case + * if there is a request. + * + * We can't call usb_lld_init after chopstx_claim_irq, as + * usb_lld_init does its own setting for NVIC. Calling + * chopstx_claim_irq after usb_lld_init overrides that. + * + */ + usb_lld_init (VCOM_FEATURE_BUS_POWERED); + chopstx_claim_irq (&usb_intr, INTR_REQ_USB); + usb_interrupt_handler (); +#else + chopstx_claim_irq (&usb_intr, INTR_REQ_USB); + usb_lld_init (VCOM_FEATURE_BUS_POWERED); +#endif + + while (1) + { + chopstx_poll (NULL, 1, &usb_intr); + if (usb_intr.ready) + usb_interrupt_handler (); + + chopstx_mutex_lock (&t->mtx); + if (t->device_state == CONFIGURED && t->flag_connected + && t->flag_send_ready) + { + uint8_t line[32]; + int len = get_chars_from_ringbuffer (t, line, sizeof (len)); + + if (len) + { + memcpy (t->send_buf0, line, len); + usb_lld_tx_enable (ENDP1, t->send_buf0, len); + t->flag_send_ready = 0; + } + } + chopstx_mutex_unlock (&t->mtx); + } + + return NULL; +} + + +void +tty_wait_configured (struct tty *t) +{ + chopstx_mutex_lock (&t->mtx); + while (t->device_state != CONFIGURED) + chopstx_cond_wait (&t->cnd, &t->mtx); + chopstx_mutex_unlock (&t->mtx); } +void +tty_wait_connection (struct tty *t) +{ + chopstx_mutex_lock (&t->mtx); + while (t->flag_connected == 0) + chopstx_cond_wait (&t->cnd, &t->mtx); + t->flag_send_ready = 1; + t->flag_input_avail = 0; + t->send_head = t->send_tail = 0; + t->inputline_len = 0; + usb_lld_rx_enable (ENDP3, t->recv_buf0, 64); /* Accept input for line */ + chopstx_mutex_unlock (&t->mtx); +} + +static int +check_tx (struct tty *t) +{ + if (t->flag_send_ready) + /* TX done */ + return 1; + if (t->flag_connected == 0) + /* Disconnected */ + return -1; + return 0; +} + int -stream_send (struct stream *st, uint8_t *buf, uint8_t count) +tty_send (struct tty *t, uint8_t *buf, int len) { - int r = 0; + int r; + uint8_t *p; + int count; - chopstx_mutex_lock (&st->mtx); - if ((stream.flags & FLAG_CONNECTED) == 0) - r = -1; - else + p = buf; + count = len >= 64 ? 64 : len; + + while (1) { - stream.sending = 1; - usb_lld_tx_enable (ENDP1, buf, count); - stream.flags |= FLAG_SEND_AVAIL; - do + chopstx_mutex_lock (&t->mtx); + while ((r = check_tx (t)) == 0) + chopstx_cond_wait (&t->cnd, &t->mtx); + if (r > 0) { - chopstx_cond_wait (&st->cnd, &st->mtx); - if ((stream.flags & FLAG_SEND_AVAIL) == 0) - break; - else if ((stream.flags & FLAG_CONNECTED) == 0) - { - r = -1; - break; - } + usb_lld_tx_enable (ENDP1, p, count); + t->flag_send_ready = 0; } - while (1); + chopstx_mutex_unlock (&t->mtx); + + len -= count; + p += count; + if (len == 0 && count != 64) + /* + * The size of the last packet should be != 0 + * If 64, send ZLP (zelo length packet) + */ + break; + count = len >= 64 ? 64 : len; } - stream.sending = 0; - chopstx_mutex_unlock (&st->mtx); + return r; } +static int +check_rx (void *arg) +{ + struct tty *t = arg; + + if (t->flag_input_avail) + /* RX */ + return 1; + if (t->flag_connected == 0) + /* Disconnected */ + return 1; + return 0; +} + int -stream_recv (struct stream *st, uint8_t *buf) +tty_recv (struct tty *t, uint8_t *buf, uint32_t *timeout) { int r; + chopstx_poll_cond_t poll_desc; + + poll_desc.type = CHOPSTX_POLL_COND; + poll_desc.ready = 0; + poll_desc.cond = &t->cnd; + poll_desc.mutex = &t->mtx; + poll_desc.check = check_rx; + poll_desc.arg = t; + + while (1) + { + chopstx_poll (timeout, 1, &poll_desc); + chopstx_mutex_lock (&t->mtx); + r = check_rx (t); + chopstx_mutex_unlock (&t->mtx); + if (r || (timeout != NULL && *timeout == 0)) + break; + } - chopstx_mutex_lock (&st->mtx); - if ((stream.flags & FLAG_CONNECTED) == 0) + chopstx_mutex_lock (&t->mtx); + if (t->flag_connected == 0) r = -1; - else + else if (t->flag_input_avail) { - while (1) - { - if ((stream.flags & FLAG_RECV_AVAIL)) - { - r = stream.recv_len; - memcpy (buf, stream.recv_buf, r); - stream.flags &= ~FLAG_RECV_AVAIL; - break; - } - else if ((stream.flags & FLAG_CONNECTED) == 0) - { - r = -1; - break; - } - chopstx_cond_wait (&st->cnd, &st->mtx); - } + r = t->inputline_len; + memcpy (buf, t->inputline, r); + t->flag_input_avail = 0; + usb_lld_rx_enable (ENDP3, t->recv_buf0, 64); + t->inputline_len = 0; } - chopstx_mutex_unlock (&st->mtx); + else + r = 0; + chopstx_mutex_unlock (&t->mtx); return r; } |