Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
13cd30069d | |||
1a780ac319 | |||
71d0b686d0 | |||
15806b6571 |
17
Makefile
17
Makefile
|
@ -1,9 +1,9 @@
|
|||
MCU = at90usb1287
|
||||
MCU = atmega8u2
|
||||
ARCH = AVR8
|
||||
BOARD = USER
|
||||
F_CPU = 8000000
|
||||
F_USB = 8000000
|
||||
OPTIMIZATION = 3
|
||||
F_CPU = 16000000
|
||||
F_USB = 16000000
|
||||
OPTIMIZATION = s
|
||||
TARGET = main
|
||||
LUFA_PATH = lufa/LUFA
|
||||
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -Iconfig/ -Wall
|
||||
|
@ -25,9 +25,13 @@ DEVICE = /dev/serial/by-id/usb-LUFA_FT232_*
|
|||
|
||||
# Open terminal on USB port
|
||||
term:
|
||||
terminal.py $(DEVICE)
|
||||
python terminal.py $(DEVICE)
|
||||
.PHONY: term
|
||||
|
||||
AVRDUDE_PROGRAMMER := buspirate
|
||||
AVRDUDE_PORT := /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AH00S82Y-if00-port0
|
||||
AVRDUDE_FLAGS := -V
|
||||
|
||||
# Include LUFA build script makefiles
|
||||
include $(LUFA_PATH)/Build/lufa_sources.mk
|
||||
include $(LUFA_PATH)/Build/lufa_build.mk
|
||||
|
@ -41,3 +45,6 @@ $(LUFA_PATH)/Build/lufa_core.mk:
|
|||
|
||||
# Remove some stuff from BASE_CC_FLAGS that the LUFA core put in there.
|
||||
BASE_CC_FLAGS := $(filter-out -fno-inline-small-functions,$(BASE_CC_FLAGS))
|
||||
|
||||
prog: main.hex
|
||||
avrdude -p atmega8u2 -P /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AH00S82Y-if00-port0 -c buspirate -V -U flash:w:main.hex
|
||||
|
|
267
ftdi.c
267
ftdi.c
|
@ -8,8 +8,8 @@
|
|||
#include "queue.h"
|
||||
|
||||
/* TX and RX queues */
|
||||
volatile static uint8_t ftdi_txqueue_buf[FTDI_TX_QUEUE_LEN];
|
||||
volatile static uint8_t ftdi_rxqueue_buf[FTDI_RX_QUEUE_LEN];
|
||||
static uint8_t ftdi_txqueue_buf[FTDI_TX_QUEUE_LEN];
|
||||
static uint8_t ftdi_rxqueue_buf[FTDI_RX_QUEUE_LEN];
|
||||
struct queue ftdi_txqueue =
|
||||
QUEUE_INITIALIZER(ftdi_txqueue_buf, sizeof(ftdi_txqueue_buf));
|
||||
struct queue ftdi_rxqueue =
|
||||
|
@ -35,7 +35,7 @@ static const uint8_t ftdi_eeprom[] = {
|
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0xa5
|
||||
};
|
||||
|
||||
volatile static struct ftdi_status {
|
||||
static struct ftdi_status {
|
||||
/* modem status */
|
||||
unsigned reserved_1:1;
|
||||
unsigned reserved_0:3;
|
||||
|
@ -55,28 +55,13 @@ volatile static struct ftdi_status {
|
|||
unsigned fifoerr:1;
|
||||
} ftdi_status = { 0 };
|
||||
|
||||
volatile static struct ctrl_status {
|
||||
static struct ctrl_status {
|
||||
unsigned dtr:1;
|
||||
unsigned rts:1;
|
||||
} ctrl_status = { 0 };
|
||||
|
||||
static bool ftdi_onlcr = false; /* Translate \n to \r\n, like stty "onlcr" */
|
||||
static bool ftdi_blocking_in = false;
|
||||
static bool ftdi_blocking_out = false;
|
||||
static bool ftdi_delay_init_tx = false;
|
||||
|
||||
volatile bool got_setbaudrate;
|
||||
volatile bool got_first_rx;
|
||||
#define WAIT_FRAMES 250
|
||||
volatile uint8_t frames_since_setbaudrate;
|
||||
|
||||
volatile uint8_t latency_timer = 16;
|
||||
volatile uint8_t latency_count = 0;
|
||||
|
||||
/* Fdev compatible wrappers */
|
||||
static int ftdi_fdev_write(char c, FILE *stream) {
|
||||
if (ftdi_onlcr && c == '\n')
|
||||
ftdi_putchar('\r');
|
||||
ftdi_putchar(c);
|
||||
return 0;
|
||||
}
|
||||
|
@ -87,38 +72,22 @@ static FILE _ftdi_stream =
|
|||
FDEV_SETUP_STREAM(ftdi_fdev_write, ftdi_fdev_read, _FDEV_SETUP_RW);
|
||||
FILE *ftdi_stream = &_ftdi_stream;
|
||||
|
||||
static void reset_internal_state(void)
|
||||
/* Init */
|
||||
static bool ftdi_blocking_in = false;
|
||||
static bool ftdi_blocking_out = false;
|
||||
void ftdi_init(int flags)
|
||||
{
|
||||
/* Disable endpoint interrupts */
|
||||
UEIENX &= ~(1 << RXOUTE);
|
||||
UEIENX &= ~(1 << TXINE);
|
||||
|
||||
/* Reset flags for ftdi_init_track_tx */
|
||||
got_setbaudrate = false;
|
||||
got_first_rx = false;
|
||||
frames_since_setbaudrate = 0;
|
||||
|
||||
/* Latency timer */
|
||||
latency_timer = 16;
|
||||
latency_count = 0;
|
||||
|
||||
/* Reset line state */
|
||||
ftdi_status = (struct ftdi_status) { 0 };
|
||||
memset(&ftdi_status, 0, sizeof(struct ftdi_status));
|
||||
ftdi_status.reserved_1 = 1;
|
||||
ftdi_status.cts = 1;
|
||||
ftdi_status.dsr = 1;
|
||||
ftdi_status.ri = 0;
|
||||
ftdi_status.cd = 1;
|
||||
|
||||
ctrl_status = (struct ctrl_status) { 0 };
|
||||
memset(&ctrl_status, 0, sizeof(struct ctrl_status));
|
||||
ctrl_status.dtr = 0;
|
||||
ctrl_status.rts = 0;
|
||||
}
|
||||
|
||||
/* Init */
|
||||
void ftdi_init(int flags)
|
||||
{
|
||||
reset_internal_state();
|
||||
|
||||
if (flags & FTDI_STDIO) {
|
||||
stdout = ftdi_stream;
|
||||
|
@ -129,17 +98,11 @@ void ftdi_init(int flags)
|
|||
ftdi_blocking_in = true;
|
||||
if (flags & FTDI_BLOCKING_OUT)
|
||||
ftdi_blocking_out = true;
|
||||
if (flags & FTDI_ONLCR)
|
||||
ftdi_onlcr = true;
|
||||
if (flags & FTDI_DELAY_INIT_TX)
|
||||
ftdi_delay_init_tx = true;
|
||||
|
||||
USB_Device_EnableSOFEvents();
|
||||
}
|
||||
|
||||
static inline void ftdi_control_request(void)
|
||||
{
|
||||
uint16_t val;
|
||||
uint16_t x;
|
||||
|
||||
if (!Endpoint_IsSETUPReceived())
|
||||
return;
|
||||
|
@ -151,68 +114,50 @@ static inline void ftdi_control_request(void)
|
|||
switch (USB_ControlRequest.bRequest) {
|
||||
|
||||
case SIO_RESET_REQUEST:
|
||||
/* Reset */
|
||||
switch (USB_ControlRequest.wValue) {
|
||||
case SIO_RESET_SIO:
|
||||
ctrl_status.dtr = 0;
|
||||
ctrl_status.rts = 0;
|
||||
ftdi_init(0);
|
||||
break;
|
||||
|
||||
case SIO_RESET_PURGE_RX:
|
||||
while (_queue_can_get(&ftdi_rxqueue))
|
||||
(void)_queue_get(&ftdi_rxqueue);
|
||||
break;
|
||||
|
||||
case SIO_RESET_PURGE_TX:
|
||||
while (_queue_can_get(&ftdi_txqueue))
|
||||
(void)_queue_get(&ftdi_txqueue);
|
||||
ftdi_status.temt = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
Endpoint_ClearSETUP();
|
||||
Endpoint_ClearStatusStage();
|
||||
return;
|
||||
|
||||
case SIO_READ_EEPROM_REQUEST:
|
||||
/* Return fake EEPROM data */
|
||||
val = (USB_ControlRequest.wIndex & 0xff) * 2;
|
||||
if (val + USB_ControlRequest.wLength > sizeof(ftdi_eeprom))
|
||||
x = (USB_ControlRequest.wIndex & 0xff) * 2;
|
||||
if (x + USB_ControlRequest.wLength > sizeof(ftdi_eeprom))
|
||||
return;
|
||||
|
||||
Endpoint_ClearSETUP();
|
||||
Endpoint_Write_Control_Stream_LE((uint8_t *)&ftdi_eeprom[val],
|
||||
Endpoint_Write_Control_Stream_LE((uint8_t *)&ftdi_eeprom[x],
|
||||
USB_ControlRequest.wLength);
|
||||
Endpoint_ClearStatusStage();
|
||||
return;
|
||||
|
||||
case SIO_SET_BAUDRATE_REQUEST:
|
||||
got_setbaudrate = true;
|
||||
Endpoint_ClearSETUP();
|
||||
Endpoint_ClearStatusStage();
|
||||
return;
|
||||
|
||||
case SIO_WRITE_EEPROM_REQUEST:
|
||||
case SIO_ERASE_EEPROM_REQUEST:
|
||||
case SIO_SET_BAUDRATE_REQUEST:
|
||||
case SIO_SET_DATA_REQUEST:
|
||||
case SIO_SET_FLOW_CTRL_REQUEST:
|
||||
case SIO_SET_EVENT_CHAR_REQUEST:
|
||||
case SIO_SET_ERROR_CHAR_REQUEST:
|
||||
case SIO_SET_LATENCY_TIMER_REQUEST:
|
||||
case SIO_SET_BITMODE_REQUEST:
|
||||
/* Ignore these */
|
||||
Endpoint_ClearSETUP();
|
||||
Endpoint_ClearStatusStage();
|
||||
return;
|
||||
|
||||
case SIO_SET_LATENCY_TIMER_REQUEST:
|
||||
val = USB_ControlRequest.wValue;
|
||||
if (val >= 1 && val <= 255) {
|
||||
latency_timer = val;
|
||||
latency_count = 0;
|
||||
}
|
||||
Endpoint_ClearSETUP();
|
||||
Endpoint_ClearStatusStage();
|
||||
return;
|
||||
|
||||
case SIO_SET_MODEM_CTRL_REQUEST:
|
||||
if (USB_ControlRequest.wValue & SIO_SET_DTR_HIGH)
|
||||
ctrl_status.dtr = 1;
|
||||
|
@ -227,11 +172,12 @@ static inline void ftdi_control_request(void)
|
|||
return;
|
||||
|
||||
case SIO_GET_LATENCY_TIMER_REQUEST:
|
||||
/* Return dummy value */
|
||||
if (USB_ControlRequest.wLength != 1)
|
||||
return;
|
||||
Endpoint_ClearSETUP();
|
||||
val = latency_timer;
|
||||
Endpoint_Write_Control_Stream_LE((uint8_t *)&val, 1);
|
||||
x = 100;
|
||||
Endpoint_Write_Control_Stream_LE((uint8_t *)&x, 1);
|
||||
Endpoint_ClearStatusStage();
|
||||
return;
|
||||
|
||||
|
@ -240,8 +186,8 @@ static inline void ftdi_control_request(void)
|
|||
if (USB_ControlRequest.wLength != 1)
|
||||
return;
|
||||
Endpoint_ClearSETUP();
|
||||
val = 0;
|
||||
Endpoint_Write_Control_Stream_LE((uint8_t *)&val, 1);
|
||||
x = 0;
|
||||
Endpoint_Write_Control_Stream_LE((uint8_t *)&x, 1);
|
||||
Endpoint_ClearStatusStage();
|
||||
return;
|
||||
|
||||
|
@ -264,7 +210,7 @@ static const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
|
|||
.Type = DTYPE_Device
|
||||
},
|
||||
|
||||
.USBSpecification = VERSION_BCD(2,0,0),
|
||||
.USBSpecification = VERSION_BCD(02.00),
|
||||
.Class = 0x00,
|
||||
.SubClass = 0x00,
|
||||
.Protocol = 0x00,
|
||||
|
@ -359,7 +305,7 @@ static const USB_Descriptor_String_t *strings[] = {
|
|||
};
|
||||
|
||||
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
|
||||
const uint16_t wIndex,
|
||||
const uint8_t wIndex,
|
||||
const void** const DescriptorAddress)
|
||||
{
|
||||
const uint8_t DescriptorType = (wValue >> 8);
|
||||
|
@ -403,13 +349,6 @@ void EVENT_USB_Device_Reset(void)
|
|||
{
|
||||
Endpoint_SelectEndpoint(ENDPOINT_CONTROLEP);
|
||||
USB_INT_Enable(USB_INT_RXSTPI);
|
||||
|
||||
reset_internal_state();
|
||||
}
|
||||
|
||||
void EVENT_USB_Device_Disconnect(void)
|
||||
{
|
||||
reset_internal_state();
|
||||
}
|
||||
|
||||
/* Configure endpoint with the best available number of banks. */
|
||||
|
@ -422,86 +361,26 @@ static inline bool ftdi_config_ep(uint8_t address, uint8_t type, uint16_t size)
|
|||
return Endpoint_ConfigureEndpoint(address, type, size, 1);
|
||||
}
|
||||
|
||||
static void maybe_enable_tx(void)
|
||||
{
|
||||
/* Not configured? */
|
||||
if (USB_DeviceState != DEVICE_STATE_Configured)
|
||||
return;
|
||||
|
||||
/* Transmitter empty, and latency timer hasn't timed out? */
|
||||
if (ftdi_status.temt && latency_count < latency_timer)
|
||||
return;
|
||||
|
||||
/* Delay the initial TX? */
|
||||
if (ftdi_delay_init_tx)
|
||||
{
|
||||
if (!got_first_rx)
|
||||
{
|
||||
if (!got_setbaudrate)
|
||||
return;
|
||||
if (frames_since_setbaudrate < WAIT_FRAMES)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable it */
|
||||
Endpoint_SelectEndpoint(FTDI_TX_EPADDR);
|
||||
UEIENX |= (1 << TXINE);
|
||||
}
|
||||
|
||||
void EVENT_USB_Device_StartOfFrame(void)
|
||||
{
|
||||
if (latency_count < latency_timer)
|
||||
{
|
||||
latency_count++;
|
||||
if (latency_count == latency_timer)
|
||||
maybe_enable_tx();
|
||||
}
|
||||
|
||||
if (!ftdi_delay_init_tx)
|
||||
return;
|
||||
|
||||
if (!got_setbaudrate)
|
||||
return;
|
||||
|
||||
if (frames_since_setbaudrate < WAIT_FRAMES)
|
||||
{
|
||||
frames_since_setbaudrate++;
|
||||
if (frames_since_setbaudrate == WAIT_FRAMES)
|
||||
maybe_enable_tx();
|
||||
}
|
||||
}
|
||||
|
||||
void EVENT_USB_Device_ConfigurationChanged(void)
|
||||
{
|
||||
uint8_t PrevSelectedEndpoint = Endpoint_GetCurrentEndpoint();
|
||||
|
||||
/* Configure endpoints */
|
||||
|
||||
/* IN */
|
||||
ftdi_config_ep(FTDI_TX_EPADDR, EP_TYPE_BULK, FTDI_TXRX_EPSIZE);
|
||||
Endpoint_SelectEndpoint(FTDI_TX_EPADDR);
|
||||
UEIENX = (1 << TXINE);
|
||||
|
||||
/* OUT */
|
||||
ftdi_config_ep(FTDI_RX_EPADDR, EP_TYPE_BULK, FTDI_TXRX_EPSIZE);
|
||||
|
||||
/* Start interrupt on RX endpoint */
|
||||
Endpoint_SelectEndpoint(FTDI_RX_EPADDR);
|
||||
UEIENX |= (1 << RXOUTE);
|
||||
|
||||
/* If we have data to send, start interrupt on TX endpoint */
|
||||
maybe_enable_tx();
|
||||
UEIENX = (1 << RXOUTE);
|
||||
|
||||
/* Done */
|
||||
Endpoint_SelectEndpoint(PrevSelectedEndpoint);
|
||||
}
|
||||
|
||||
static const char *fmt_ch(uint8_t ch) __attribute__((unused));
|
||||
static const char *fmt_ch(uint8_t ch)
|
||||
{
|
||||
static char s[10];
|
||||
if (ch > 32 && ch <= 127)
|
||||
sprintf(s, "%c", ch);
|
||||
else
|
||||
sprintf(s, "<%d>", ch);
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline void ftdi_bulk_in(void)
|
||||
{
|
||||
int len, i;
|
||||
|
@ -509,38 +388,27 @@ static inline void ftdi_bulk_in(void)
|
|||
/* Data format: ftdi_status structure (2 bytes) followed by the
|
||||
serial data. */
|
||||
len = _queue_get_len(&ftdi_txqueue);
|
||||
if (len > FTDI_TXRX_EPSIZE - 2) {
|
||||
/* There will be more data after this packet */
|
||||
|
||||
if (len >= FTDI_TXRX_EPSIZE - 2) {
|
||||
/* more to send */
|
||||
ftdi_status.thre = 0;
|
||||
ftdi_status.temt = 0;
|
||||
len = FTDI_TXRX_EPSIZE - 2;
|
||||
} else {
|
||||
/* No more data after this */
|
||||
ftdi_status.temt = 1;
|
||||
/* transmitter empty */
|
||||
ftdi_status.thre = 0;
|
||||
ftdi_status.temt = 0;
|
||||
}
|
||||
|
||||
/* If we have data or the latency timer expired, send status
|
||||
bytes and the data. Otherwise, this will just be a ZLP. */
|
||||
if (len > 0 || latency_count == latency_timer)
|
||||
{
|
||||
Endpoint_Write_8(((uint8_t *)&ftdi_status)[0]);
|
||||
Endpoint_Write_8(((uint8_t *)&ftdi_status)[1]);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
uint8_t ch = _queue_get(&ftdi_txqueue);
|
||||
Endpoint_Write_8(ch);
|
||||
}
|
||||
Endpoint_Write_8(_queue_get(&ftdi_txqueue));
|
||||
|
||||
/* Latency timer can be reset, since we're sending
|
||||
useful data to the host. */
|
||||
latency_count = 0;
|
||||
}
|
||||
|
||||
if (ftdi_status.temt)
|
||||
{
|
||||
/* If we have no more data, and we wrote a packet that was
|
||||
smaller than the full endpoint size, then this transfer is
|
||||
done and we can disable the IN interrupt. We'll reenable
|
||||
it when we have more data to send. */
|
||||
if (len != FTDI_TXRX_EPSIZE - 2)
|
||||
/* If that packet was empty, disable the IN interrupt. We'll
|
||||
reenable it when we have more data to send. */
|
||||
if (len == 0) {
|
||||
UEIENX &= ~(1 << TXINE);
|
||||
}
|
||||
|
||||
|
@ -552,28 +420,20 @@ static inline void ftdi_bulk_out(void)
|
|||
{
|
||||
int i;
|
||||
int len;
|
||||
bool overflow = false;
|
||||
|
||||
len = Endpoint_BytesInEndpoint();
|
||||
|
||||
if (_queue_get_free(&ftdi_rxqueue) < len) {
|
||||
/* We can't deal with this right now. Disable OUT
|
||||
interrupt; we'll reenable after reading some bytes */
|
||||
UEIENX &= ~(1 << RXOUTE);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
/* This will discard incoming bytes if queue is full */
|
||||
uint8_t ch = Endpoint_Read_8();
|
||||
got_first_rx = true;
|
||||
/* Put into RX queue */
|
||||
if (_queue_put(&ftdi_rxqueue, ch) < 0)
|
||||
overflow = true;
|
||||
_queue_put(&ftdi_rxqueue, Endpoint_Read_8());
|
||||
}
|
||||
|
||||
if (overflow)
|
||||
{
|
||||
/* We lost data because our RX queue was full.
|
||||
Disable OUT interrupt; we'll reenable after emptying
|
||||
some bytes from the RX queue. */
|
||||
UEIENX &= ~(1 << RXOUTE);
|
||||
}
|
||||
|
||||
|
||||
Endpoint_ClearOUT();
|
||||
}
|
||||
|
||||
|
@ -618,15 +478,10 @@ void ftdi_putchar(uint8_t c)
|
|||
if (ftdi_blocking_out == false)
|
||||
return;
|
||||
|
||||
/* Protect against race conditions by double checking
|
||||
that we still have data to send, while interrupts are
|
||||
disabled. */
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||
if (_queue_get_len(&ftdi_txqueue) > 0)
|
||||
{
|
||||
ftdi_status.temt = 0;
|
||||
maybe_enable_tx();
|
||||
}
|
||||
/* Enable the IN endpoint interrupt, since we have data to send. */
|
||||
if (USB_DeviceState == DEVICE_STATE_Configured) {
|
||||
Endpoint_SelectEndpoint(FTDI_TX_EPADDR);
|
||||
UEIENX |= (1 << TXINE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -639,17 +494,11 @@ int ftdi_getchar(void)
|
|||
if (ftdi_blocking_in == false)
|
||||
return -1;
|
||||
|
||||
/* Protect against race conditions by double checking
|
||||
that we still have space for new data, while interrupts
|
||||
are disabled. */
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||
/* Reenable the OUT endpoint interrupt, since we read
|
||||
some data */
|
||||
/* Reenable the OUT endpoint interrupt, since we read some data */
|
||||
if (USB_DeviceState == DEVICE_STATE_Configured) {
|
||||
Endpoint_SelectEndpoint(FTDI_RX_EPADDR);
|
||||
UEIENX |= (1 << RXOUTE);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
18
ftdi.h
18
ftdi.h
|
@ -9,11 +9,11 @@
|
|||
|
||||
/* FTDI device-to-host data IN endpoint */
|
||||
#define FTDI_TX_EPADDR (ENDPOINT_DIR_IN | 1)
|
||||
#define FTDI_TX_QUEUE_LEN 256
|
||||
#define FTDI_TX_QUEUE_LEN 32
|
||||
|
||||
/* Endpoint address of FTDI host-to-device data OUT endpoint */
|
||||
#define FTDI_RX_EPADDR (ENDPOINT_DIR_OUT | 2)
|
||||
#define FTDI_RX_QUEUE_LEN 256 /* Must be at least FTDI_TXRX_EPSIZE + 1 */
|
||||
#define FTDI_RX_QUEUE_LEN 32 /* Must be at least FTDI_TXRX_EPSIZE + 1 */
|
||||
|
||||
/* Endpoint size */
|
||||
#define FTDI_TXRX_EPSIZE 16 /* e.g. 16 or 64 */
|
||||
|
@ -63,18 +63,6 @@
|
|||
#define FTDI_BLOCKING_OUT (1 << 2)
|
||||
#define FTDI_BLOCKING (FTDI_BLOCKING_IN | FTDI_BLOCKING_OUT)
|
||||
|
||||
/* Whether to translate \n to \r\n on output, like stty's onlcr flag */
|
||||
#define FTDI_ONLCR (1 << 3)
|
||||
|
||||
/* Whether to delay the initial TX after USB configuration.
|
||||
If set, wait for either:
|
||||
- 250ms to pass after a SET_BAUDRATE command
|
||||
- input to be received
|
||||
before sending any data. This is to work around issues where
|
||||
some hsots will discard (or even echo) input while the port
|
||||
is still being opened. */
|
||||
#define FTDI_DELAY_INIT_TX (1 << 4)
|
||||
|
||||
/* Initialize FTDI routines, with flags above */
|
||||
void ftdi_init(int flags);
|
||||
|
||||
|
@ -92,7 +80,7 @@ void EVENT_USB_Device_ControlRequest(void);
|
|||
void EVENT_USB_Device_Reset(void);
|
||||
void EVENT_USB_Device_ConfigurationChanged(void);
|
||||
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
|
||||
const uint16_t wIndex,
|
||||
const uint8_t wIndex,
|
||||
const void** const DescriptorAddress)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
|
|
2
lufa
2
lufa
|
@ -1 +1 @@
|
|||
Subproject commit 737382aeda146ca793be452ac5790e12d1ca16ea
|
||||
Subproject commit f59a34370cec33272412d9aee6e68871d7e8b5e0
|
132
terminal.py
Executable file
132
terminal.py
Executable file
|
@ -0,0 +1,132 @@
|
|||
#!/usr/bin/python
|
||||
# Based on miniterm sample in pyserial
|
||||
|
||||
import sys, os, serial, threading, traceback, time
|
||||
|
||||
if os.name == 'nt':
|
||||
import msvcrt
|
||||
class Console:
|
||||
def __init__(self):
|
||||
pass
|
||||
def cleanup(self):
|
||||
pass
|
||||
def getkey(self):
|
||||
while 1:
|
||||
z = msvcrt.getch()
|
||||
if z == '\0' or z == '\xe0': # function keys
|
||||
msvcrt.getch()
|
||||
else:
|
||||
if z == '\r':
|
||||
return '\n'
|
||||
return z
|
||||
elif os.name == 'posix':
|
||||
import termios, sys, os
|
||||
class Console:
|
||||
def __init__(self):
|
||||
self.fd = sys.stdin.fileno()
|
||||
try:
|
||||
self.old = termios.tcgetattr(self.fd)
|
||||
new = termios.tcgetattr(self.fd)
|
||||
new[3] = new[3] & ~termios.ICANON & ~termios.ECHO & ~termios.ISIG
|
||||
new[6][termios.VMIN] = 1
|
||||
new[6][termios.VTIME] = 0
|
||||
termios.tcsetattr(self.fd, termios.TCSANOW, new)
|
||||
except termios.error:
|
||||
# ignore errors, so we can pipe stuff to this script
|
||||
pass
|
||||
def cleanup(self):
|
||||
try:
|
||||
termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old)
|
||||
except:
|
||||
# ignore errors, so we can pipe stuff to this script
|
||||
pass
|
||||
def getkey(self):
|
||||
c = os.read(self.fd, 1)
|
||||
return c
|
||||
else:
|
||||
raise ("Sorry, no terminal implementation for your platform (%s) "
|
||||
"available." % sys.platform)
|
||||
|
||||
class Miniterm:
|
||||
def __init__(self, serial):
|
||||
self.serial = serial
|
||||
|
||||
def start(self):
|
||||
self.alive = True
|
||||
#start serial->console thread
|
||||
self.receiver_thread = threading.Thread(target=self.reader)
|
||||
self.receiver_thread.daemon = True
|
||||
self.receiver_thread.start()
|
||||
#enter console->serial loop
|
||||
self.console = Console()
|
||||
self.transmitter_thread = threading.Thread(target=self.writer)
|
||||
self.transmitter_thread.daemon = True
|
||||
self.transmitter_thread.start()
|
||||
|
||||
def stop(self):
|
||||
self.alive = False
|
||||
|
||||
def join(self, transmit_only=False):
|
||||
self.receiver_thread.join()
|
||||
self.transmitter_thread.join()
|
||||
|
||||
def reader(self):
|
||||
"""loop and copy serial->console"""
|
||||
try:
|
||||
while self.alive:
|
||||
data = self.serial.read(1)
|
||||
sys.stdout.write(data)
|
||||
sys.stdout.flush()
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
self.console.cleanup()
|
||||
os._exit(1)
|
||||
|
||||
def writer(self):
|
||||
"""loop and copy console->serial until ^C"""
|
||||
try:
|
||||
while self.alive:
|
||||
try:
|
||||
c = self.console.getkey()
|
||||
except KeyboardInterrupt:
|
||||
c = '\x03'
|
||||
if c == '\x03':
|
||||
self.stop()
|
||||
return
|
||||
elif c == '':
|
||||
# EOF on input. Wait a tiny bit so we can
|
||||
# flush the remaining input, then stop.
|
||||
time.sleep(0.25)
|
||||
self.stop()
|
||||
return
|
||||
else:
|
||||
self.serial.write(c) # send character
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
self.console.cleanup()
|
||||
os._exit(1)
|
||||
|
||||
def run(self):
|
||||
self.serial.timeout = 0.1
|
||||
self.start()
|
||||
self.join()
|
||||
print ""
|
||||
self.console.cleanup()
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="Simple serial terminal")
|
||||
parser.add_argument('device', metavar='DEVICE',
|
||||
help='serial device')
|
||||
parser.add_argument('baudrate', metavar='BAUDRATE', type=int, nargs='?',
|
||||
help='baud rate', default=115200)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
dev = serial.Serial(args.device, args.baudrate)
|
||||
except serial.serialutil.SerialException:
|
||||
sys.stderr.write("error opening %s\n" % args.device)
|
||||
raise SystemExit(1)
|
||||
term = Miniterm(dev)
|
||||
term.run()
|
||||
|
Loading…
Reference in New Issue
Block a user