Update example-fs-bb48
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
2016-05-23 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* example-fs-bb48/usb-cdc.c: Update from example-cdc.
|
||||||
|
* example-fs-bb48/tty.h: Likewise.
|
||||||
|
* example-fs-bb48/sample.c: Follow the change.
|
||||||
|
|
||||||
2016-05-20 NIIBE Yutaka <gniibe@fsij.org>
|
2016-05-20 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
* chopstx.c (chopstx_usec_wait_var): internal function.
|
* chopstx.c (chopstx_usec_wait_var): internal function.
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ main (int argc, const char *argv[])
|
|||||||
u = 1;
|
u = 1;
|
||||||
tty_wait_connection (tty);
|
tty_wait_connection (tty);
|
||||||
|
|
||||||
chopstx_usec_wait (500*1000);
|
chopstx_usec_wait (50*1000);
|
||||||
|
|
||||||
/* Send ZLP at the beginning. */
|
/* Send ZLP at the beginning. */
|
||||||
tty_send (tty, s, 0);
|
tty_send (tty, s, 0);
|
||||||
|
|||||||
@@ -378,8 +378,7 @@ vcom_setup_endpoints_for_interface (uint16_t interface, int stop)
|
|||||||
{
|
{
|
||||||
usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
|
usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
|
||||||
usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64);
|
usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64);
|
||||||
/* Start with no data receiving */
|
/* Start with no data receiving (ENDP3 not enabled)*/
|
||||||
usb_lld_stall_rx (ENDP3);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <chopstx.h>
|
#include <chopstx.h>
|
||||||
|
|
||||||
#include "usb_lld.h"
|
#include "usb_lld.h"
|
||||||
#include "stream.h"
|
#include "tty.h"
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
|
|
||||||
#include "crc32.h"
|
#include "crc32.h"
|
||||||
@@ -93,43 +93,12 @@ blk (void *arg)
|
|||||||
return NULL;
|
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_PWM 3
|
||||||
#define PRIO_BLK 2
|
#define PRIO_BLK 2
|
||||||
#endif
|
|
||||||
#define PRIO_INTR 4
|
|
||||||
|
|
||||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
||||||
extern uint8_t __process2_stack_base__, __process2_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 uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__;
|
||||||
const size_t __stacksize_pwm = (size_t)&__process1_stack_size__;
|
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 uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__;
|
||||||
const size_t __stacksize_blk = (size_t)&__process2_stack_size__;
|
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)
|
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
|
int
|
||||||
main (int argc, const char *argv[])
|
main (int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
struct stream *st;
|
struct tty *tty;
|
||||||
uint8_t count;
|
uint8_t count;
|
||||||
extern uint32_t bDeviceState;
|
|
||||||
|
|
||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
@@ -182,14 +135,10 @@ main (int argc, const char *argv[])
|
|||||||
chopstx_cond_init (&cnd0);
|
chopstx_cond_init (&cnd0);
|
||||||
chopstx_cond_init (&cnd1);
|
chopstx_cond_init (&cnd1);
|
||||||
|
|
||||||
st = stream_open ();
|
|
||||||
|
|
||||||
m = 10;
|
m = 10;
|
||||||
|
|
||||||
chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL);
|
chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL);
|
||||||
chopstx_create (PRIO_BLK, __stackaddr_blk, __stacksize_blk, blk, 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);
|
chopstx_usec_wait (200*1000);
|
||||||
|
|
||||||
@@ -199,57 +148,43 @@ main (int argc, const char *argv[])
|
|||||||
chopstx_mutex_unlock (&mtx);
|
chopstx_mutex_unlock (&mtx);
|
||||||
|
|
||||||
u = 1;
|
u = 1;
|
||||||
while (bDeviceState != CONFIGURED)
|
|
||||||
chopstx_usec_wait (500*1000);
|
tty = tty_open ();
|
||||||
|
tty_wait_configured (tty);
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
|
m = 50;
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
uint8_t s[64];
|
uint8_t s[LINEBUFSIZE];
|
||||||
|
|
||||||
u = 1;
|
u = 1;
|
||||||
if (stream_wait_connection (st) < 0)
|
tty_wait_connection (tty);
|
||||||
{
|
|
||||||
chopstx_usec_wait (1000*1000);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
chopstx_usec_wait (500*1000);
|
chopstx_usec_wait (50*1000);
|
||||||
|
|
||||||
/* Send ZLP at the beginning. */
|
/* 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);
|
memcpy (s, "xx: Hello, World with Chopstx!\r\n", 32);
|
||||||
s[0] = hexchar (count >> 4);
|
s[0] = hexchar (count >> 4);
|
||||||
s[1] = hexchar (count & 0x0f);
|
s[1] = hexchar (count & 0x0f);
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
if (stream_send (st, s, 32) < 0)
|
if (tty_send (tty, s, 32) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
uint32_t usec;
|
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))
|
|
||||||
{
|
|
||||||
size = stream_recv (st, s + 4);
|
|
||||||
|
|
||||||
|
usec = 3000000; /* 3.0 seconds */
|
||||||
|
size = tty_recv (tty, s + 4, &usec);
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (size >= 0)
|
if (usec)
|
||||||
{
|
{
|
||||||
unsigned int value;
|
unsigned int value;
|
||||||
|
|
||||||
@@ -261,19 +196,6 @@ main (int argc, const char *argv[])
|
|||||||
adc_start_conversion (0, 1);
|
adc_start_conversion (0, 1);
|
||||||
adc_wait_completion (NULL);
|
adc_wait_completion (NULL);
|
||||||
value = adc_buf[0];
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
s[4] = hexchar (value >> 28);
|
s[4] = hexchar (value >> 28);
|
||||||
s[5] = hexchar (value >> 24);
|
s[5] = hexchar (value >> 24);
|
||||||
@@ -285,7 +207,45 @@ main (int argc, const char *argv[])
|
|||||||
s[11] = hexchar (value);
|
s[11] = hexchar (value);
|
||||||
s[12] = '\r';
|
s[12] = '\r';
|
||||||
s[13] = '\n';
|
s[13] = '\n';
|
||||||
if (stream_send (st, s, 14) < 0)
|
|
||||||
|
if (tty_send (tty, s, 14) < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (s[4] == 'c')
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,9 @@
|
|||||||
#define BUFSIZE 128
|
#define LINEBUFSIZE 128
|
||||||
#define FLAG_CONNECTED (1 << 0)
|
|
||||||
#define FLAG_SEND_AVAIL (1 << 1)
|
|
||||||
#define FLAG_RECV_AVAIL (1 << 2)
|
|
||||||
|
|
||||||
/*
|
struct tty;
|
||||||
* 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 stream *stream_open (void);
|
struct tty *tty_open (void);
|
||||||
int stream_wait_connection (struct stream *st);
|
void tty_wait_configured (struct tty *tty);
|
||||||
int stream_send (struct stream *st, uint8_t *buf, uint8_t count);
|
void tty_wait_connection (struct tty *tty);
|
||||||
int stream_recv (struct stream *st, uint8_t *buf);
|
int tty_send (struct tty *tty, uint8_t *buf, int count);
|
||||||
|
int tty_recv (struct tty *tty, uint8_t *buf, uint32_t *timeout);
|
||||||
|
|||||||
@@ -3,19 +3,84 @@
|
|||||||
#include <chopstx.h>
|
#include <chopstx.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "usb_lld.h"
|
#include "usb_lld.h"
|
||||||
#include "stream.h"
|
#include "tty.h"
|
||||||
|
|
||||||
static uint8_t send_buf[64];
|
static chopstx_intr_t usb_intr;
|
||||||
static unsigned int send_len;
|
|
||||||
static uint8_t send_buf1[64];
|
|
||||||
|
|
||||||
static uint8_t recv_buf[64];
|
struct line_coding
|
||||||
static unsigned int recv_len;
|
{
|
||||||
|
uint32_t bitrate;
|
||||||
|
uint8_t format;
|
||||||
|
uint8_t paritytype;
|
||||||
|
uint8_t datatype;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
static uint8_t inputline[64];
|
static const struct line_coding line_coding0 = {
|
||||||
static unsigned int inputline_len;
|
115200, /* baud rate: 115200 */
|
||||||
|
0x00, /* stop bits: 1 */
|
||||||
|
0x00, /* parity: none */
|
||||||
|
0x08 /* bits: 8 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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_SET_LINE_CODING 0x20
|
||||||
#define USB_CDC_REQ_GET_LINE_CODING 0x21
|
#define USB_CDC_REQ_GET_LINE_CODING 0x21
|
||||||
@@ -40,6 +105,8 @@ static const uint8_t vcom_device_desc[18] = {
|
|||||||
1 /* bNumConfigurations. */
|
1 /* bNumConfigurations. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define VCOM_FEATURE_BUS_POWERED 0x80
|
||||||
|
|
||||||
/* Configuration Descriptor tree for a CDC.*/
|
/* Configuration Descriptor tree for a CDC.*/
|
||||||
static const uint8_t vcom_config_desc[67] = {
|
static const uint8_t vcom_config_desc[67] = {
|
||||||
9,
|
9,
|
||||||
@@ -49,7 +116,7 @@ static const uint8_t vcom_config_desc[67] = {
|
|||||||
0x02, /* bNumInterfaces. */
|
0x02, /* bNumInterfaces. */
|
||||||
0x01, /* bConfigurationValue. */
|
0x01, /* bConfigurationValue. */
|
||||||
0, /* iConfiguration. */
|
0, /* iConfiguration. */
|
||||||
0x80, /* bmAttributes (bus powered). */
|
VCOM_FEATURE_BUS_POWERED, /* bmAttributes. */
|
||||||
50, /* bMaxPower (100mA). */
|
50, /* bMaxPower (100mA). */
|
||||||
/* Interface Descriptor.*/
|
/* Interface Descriptor.*/
|
||||||
9,
|
9,
|
||||||
@@ -162,21 +229,24 @@ static const uint8_t vcom_string3[28] = {
|
|||||||
|
|
||||||
#define NUM_INTERFACES 2
|
#define NUM_INTERFACES 2
|
||||||
|
|
||||||
uint32_t bDeviceState = UNCONNECTED; /* USB device status */
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
usb_cb_device_reset (void)
|
usb_cb_device_reset (void)
|
||||||
{
|
{
|
||||||
usb_lld_reset (vcom_config_desc[7]);
|
usb_lld_reset (VCOM_FEATURE_BUS_POWERED);
|
||||||
|
|
||||||
/* Initialize Endpoint 0 */
|
/* Initialize Endpoint 0 */
|
||||||
usb_lld_setup_endpoint (ENDP0, 1, 1);
|
usb_lld_setup_endpoint (ENDP0, 1, 1);
|
||||||
|
|
||||||
chopstx_mutex_lock (&stream.mtx);
|
chopstx_mutex_lock (&tty0.mtx);
|
||||||
stream.flags = 0;
|
tty0.inputline_len = 0;
|
||||||
bDeviceState = ATTACHED;
|
tty0.send_head = tty0.send_tail = 0;
|
||||||
chopstx_mutex_unlock (&stream.mtx);
|
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);
|
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)
|
&& 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. */
|
/* Open/close the connection. */
|
||||||
chopstx_mutex_lock (&stream.mtx);
|
chopstx_mutex_lock (&t->mtx);
|
||||||
stream.flags &= ~FLAG_CONNECTED;
|
t->flag_connected = ((arg->value & CDC_CTRL_DTR) != 0);
|
||||||
stream.flags |= ((arg->value & CDC_CTRL_DTR) != 0)? FLAG_CONNECTED : 0;
|
chopstx_cond_signal (&t->cnd);
|
||||||
chopstx_cond_signal (&stream.cnd);
|
chopstx_mutex_unlock (&t->mtx);
|
||||||
recv_len = 0;
|
|
||||||
usb_lld_rx_enable (ENDP3, recv_buf, 64);
|
|
||||||
chopstx_mutex_unlock (&stream.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
|
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))
|
if (USB_SETUP_GET (req))
|
||||||
{
|
{
|
||||||
|
struct tty *t = tty_get (arg->index, 0);
|
||||||
|
|
||||||
if (req_no == USB_CDC_REQ_GET_LINE_CODING)
|
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) */
|
else /* USB_SETUP_SET (req) */
|
||||||
{
|
{
|
||||||
if (req_no == USB_CDC_REQ_SET_LINE_CODING
|
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;
|
return USB_SUCCESS;
|
||||||
}
|
}
|
||||||
else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
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 (ENDP1, 0, 1);
|
||||||
usb_lld_setup_endpoint (ENDP3, 1, 0);
|
usb_lld_setup_endpoint (ENDP3, 1, 0);
|
||||||
#if 0
|
/* Start with no data receiving (ENDP3 not enabled)*/
|
||||||
/* Start with no data receiving */
|
|
||||||
usb_lld_stall (ENDP3);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -335,7 +393,9 @@ usb_cb_handle_event (uint8_t event_type, uint16_t value)
|
|||||||
switch (event_type)
|
switch (event_type)
|
||||||
{
|
{
|
||||||
case USB_EVENT_ADDRESS:
|
case USB_EVENT_ADDRESS:
|
||||||
bDeviceState = ADDRESSED;
|
chopstx_mutex_lock (&tty0.mtx);
|
||||||
|
tty0.device_state = ADDRESSED;
|
||||||
|
chopstx_mutex_unlock (&tty0.mtx);
|
||||||
return USB_SUCCESS;
|
return USB_SUCCESS;
|
||||||
case USB_EVENT_CONFIG:
|
case USB_EVENT_CONFIG:
|
||||||
current_conf = usb_lld_current_configuration ();
|
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);
|
usb_lld_set_configuration (1);
|
||||||
for (i = 0; i < NUM_INTERFACES; i++)
|
for (i = 0; i < NUM_INTERFACES; i++)
|
||||||
vcom_setup_endpoints_for_interface (i, 0);
|
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)
|
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);
|
usb_lld_set_configuration (0);
|
||||||
for (i = 0; i < NUM_INTERFACES; i++)
|
for (i = 0; i < NUM_INTERFACES; i++)
|
||||||
vcom_setup_endpoints_for_interface (i, 1);
|
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 */
|
/* Do nothing when current_conf == value */
|
||||||
return USB_SUCCESS;
|
return USB_SUCCESS;
|
||||||
|
|
||||||
return USB_SUCCESS;
|
|
||||||
default:
|
default:
|
||||||
break;
|
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
|
static void
|
||||||
stream_echo_char (int c)
|
put_char_to_ringbuffer (struct tty *t, int c)
|
||||||
{
|
{
|
||||||
chopstx_mutex_lock (&stream.mtx);
|
uint32_t next = (t->send_tail + 1) % LINEBUFSIZE;
|
||||||
if (send_len < sizeof (send_buf))
|
|
||||||
send_buf[send_len++] = c;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* All that we can is ignoring the output. */
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream.sending == 0)
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
s[i++] = t->send_buf[t->send_head];
|
||||||
usb_lld_tx_enable (ENDP1, send_buf1, send_len);
|
t->send_head = (t->send_head + 1) % LINEBUFSIZE;
|
||||||
send_len = 0;
|
|
||||||
stream.sending = 1;
|
|
||||||
}
|
}
|
||||||
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
|
void
|
||||||
usb_cb_tx_done (uint8_t ep_num)
|
usb_cb_tx_done (uint8_t ep_num)
|
||||||
{
|
{
|
||||||
|
struct tty *t = tty_get (-1, ep_num);
|
||||||
|
|
||||||
if (ep_num == ENDP1)
|
if (ep_num == ENDP1)
|
||||||
{
|
{
|
||||||
chopstx_mutex_lock (&stream.mtx);
|
chopstx_mutex_lock (&t->mtx);
|
||||||
stream.sending = 0;
|
if (t->flag_send_ready == 0)
|
||||||
if (send_len)
|
|
||||||
{
|
{
|
||||||
stream.sending = 1;
|
t->flag_send_ready = 1;
|
||||||
memcpy (send_buf1, send_buf, send_len);
|
chopstx_cond_signal (&t->cnd);
|
||||||
usb_lld_tx_enable (ENDP1, send_buf1, send_len);
|
|
||||||
send_len = 0;
|
|
||||||
}
|
}
|
||||||
else
|
chopstx_mutex_unlock (&t->mtx);
|
||||||
{
|
|
||||||
if ((stream.flags & FLAG_SEND_AVAIL))
|
|
||||||
{
|
|
||||||
stream.flags &= ~FLAG_SEND_AVAIL;
|
|
||||||
chopstx_cond_signal (&stream.cnd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
chopstx_mutex_unlock (&stream.mtx);
|
|
||||||
}
|
}
|
||||||
else if (ep_num == ENDP2)
|
else if (ep_num == ENDP2)
|
||||||
{
|
{
|
||||||
@@ -456,162 +533,294 @@ usb_cb_tx_done (uint8_t ep_num)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static int
|
||||||
stream_input_char (int c)
|
tty_input_char (struct tty *t, int c)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
/* Process DEL, C-U, C-R, and RET as editing command. */
|
/* Process DEL, C-U, C-R, and RET as editing command. */
|
||||||
|
chopstx_mutex_lock (&t->mtx);
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case 0x0d: /* Control-M */
|
case 0x0d: /* Control-M */
|
||||||
stream_echo_char (0x0d);
|
tty_echo_char (t, 0x0d);
|
||||||
stream_echo_char (0x0a);
|
tty_echo_char (t, 0x0a);
|
||||||
chopstx_mutex_lock (&stream.mtx);
|
t->flag_input_avail = 1;
|
||||||
if ((stream.flags & FLAG_RECV_AVAIL) == 0)
|
r = 1;
|
||||||
{
|
chopstx_cond_signal (&t->cnd);
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
case 0x12: /* Control-R */
|
case 0x12: /* Control-R */
|
||||||
stream_echo_char ('^');
|
tty_echo_char (t, '^');
|
||||||
stream_echo_char ('R');
|
tty_echo_char (t, 'R');
|
||||||
stream_echo_char (0x0d);
|
tty_echo_char (t, 0x0d);
|
||||||
stream_echo_char (0x0a);
|
tty_echo_char (t, 0x0a);
|
||||||
for (i = 0; i < inputline_len; i++)
|
for (i = 0; i < t->inputline_len; i++)
|
||||||
stream_echo_char (inputline[i]);
|
tty_echo_char (t, t->inputline[i]);
|
||||||
break;
|
break;
|
||||||
case 0x15: /* Control-U */
|
case 0x15: /* Control-U */
|
||||||
for (i = 0; i < inputline_len; i++)
|
for (i = 0; i < t->inputline_len; i++)
|
||||||
{
|
{
|
||||||
stream_echo_char (0x08);
|
tty_echo_char (t, 0x08);
|
||||||
stream_echo_char (0x20);
|
tty_echo_char (t, 0x20);
|
||||||
stream_echo_char (0x08);
|
tty_echo_char (t, 0x08);
|
||||||
}
|
}
|
||||||
inputline_len = 0;
|
t->inputline_len = 0;
|
||||||
break;
|
break;
|
||||||
case 0x7f: /* DEL */
|
case 0x7f: /* DEL */
|
||||||
if (inputline_len > 0)
|
if (t->inputline_len > 0)
|
||||||
{
|
{
|
||||||
stream_echo_char (0x08);
|
tty_echo_char (t, 0x08);
|
||||||
stream_echo_char (0x20);
|
tty_echo_char (t, 0x20);
|
||||||
stream_echo_char (0x08);
|
tty_echo_char (t, 0x08);
|
||||||
inputline_len--;
|
t->inputline_len--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (inputline_len < sizeof (inputline))
|
if (t->inputline_len < sizeof (t->inputline))
|
||||||
{
|
{
|
||||||
stream_echo_char (c);
|
tty_echo_char (t, c);
|
||||||
inputline[inputline_len++] = c;
|
t->inputline[t->inputline_len++] = c;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* Beep */
|
/* Beep */
|
||||||
stream_echo_char (0x0a);
|
tty_echo_char (t, 0x0a);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
chopstx_mutex_unlock (&t->mtx);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
usb_cb_rx_ready (uint8_t ep_num)
|
usb_cb_rx_ready (uint8_t ep_num)
|
||||||
{
|
{
|
||||||
|
struct tty *t = tty_get (-1, ep_num);
|
||||||
|
|
||||||
if (ep_num == ENDP3)
|
if (ep_num == ENDP3)
|
||||||
{
|
{
|
||||||
int i, r;
|
int i, r;
|
||||||
|
|
||||||
r = usb_lld_rx_data_len (ENDP3);
|
r = usb_lld_rx_data_len (ENDP3);
|
||||||
for (i = 0; i < r; i++)
|
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 *
|
static void *tty_main (void *arg);
|
||||||
stream_open (void)
|
|
||||||
|
#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_mutex_init (&tty0.mtx);
|
||||||
chopstx_cond_init (&stream.cnd);
|
chopstx_cond_init (&tty0.cnd);
|
||||||
return &stream;
|
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);
|
struct tty *t = arg;
|
||||||
while ((stream.flags & FLAG_CONNECTED) == 0)
|
|
||||||
chopstx_cond_wait (&st->cnd, &st->mtx);
|
#if defined(OLDER_SYS_H)
|
||||||
chopstx_mutex_unlock (&st->mtx);
|
/*
|
||||||
stream.flags &= ~FLAG_SEND_AVAIL;
|
* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
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;
|
|
||||||
|
|
||||||
chopstx_mutex_lock (&st->mtx);
|
|
||||||
if ((stream.flags & FLAG_CONNECTED) == 0)
|
|
||||||
r = -1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
stream.sending = 1;
|
|
||||||
usb_lld_tx_enable (ENDP1, buf, count);
|
|
||||||
stream.flags |= FLAG_SEND_AVAIL;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (1);
|
|
||||||
}
|
|
||||||
stream.sending = 0;
|
|
||||||
chopstx_mutex_unlock (&st->mtx);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
stream_recv (struct stream *st, uint8_t *buf)
|
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
uint8_t *p;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
count = len >= 64 ? 64 : len;
|
||||||
|
|
||||||
chopstx_mutex_lock (&st->mtx);
|
|
||||||
if ((stream.flags & FLAG_CONNECTED) == 0)
|
|
||||||
r = -1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if ((stream.flags & FLAG_RECV_AVAIL))
|
chopstx_mutex_lock (&t->mtx);
|
||||||
|
while ((r = check_tx (t)) == 0)
|
||||||
|
chopstx_cond_wait (&t->cnd, &t->mtx);
|
||||||
|
if (r > 0)
|
||||||
{
|
{
|
||||||
r = stream.recv_len;
|
usb_lld_tx_enable (ENDP1, p, count);
|
||||||
memcpy (buf, stream.recv_buf, r);
|
t->flag_send_ready = 0;
|
||||||
stream.flags &= ~FLAG_RECV_AVAIL;
|
}
|
||||||
|
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;
|
break;
|
||||||
|
count = len >= 64 ? 64 : len;
|
||||||
}
|
}
|
||||||
else if ((stream.flags & FLAG_CONNECTED) == 0)
|
|
||||||
{
|
return r;
|
||||||
r = -1;
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
chopstx_cond_wait (&st->cnd, &st->mtx);
|
static int
|
||||||
}
|
check_rx (void *arg)
|
||||||
}
|
{
|
||||||
chopstx_mutex_unlock (&st->mtx);
|
struct tty *t = arg;
|
||||||
|
|
||||||
|
if (t->flag_input_avail)
|
||||||
|
/* RX */
|
||||||
|
return 1;
|
||||||
|
if (t->flag_connected == 0)
|
||||||
|
/* Disconnected */
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
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 (&t->mtx);
|
||||||
|
if (t->flag_connected == 0)
|
||||||
|
r = -1;
|
||||||
|
else if (t->flag_input_avail)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
r = 0;
|
||||||
|
chopstx_mutex_unlock (&t->mtx);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user