Merge branch 'console_ringbuf_fix'

This commit is contained in:
tmk 2018-09-23 13:53:20 +09:00
commit e3d7b50f63
4 changed files with 207 additions and 136 deletions

View file

@ -92,7 +92,7 @@ uint8_t matrix_scan(void)
uint8_t code = xt_host_recv();
if (!code) return 0;
xprintf("%02X ", code);
dprintf("%02X ", code);
switch (state) {
case INIT:
switch (code) {

73
tmk_core/common/ringbuf.h Normal file
View file

@ -0,0 +1,73 @@
#ifndef RINGBUF_H
#define RINGBUF_H
#include <stdint.h>
#include <stdbool.h>
// NOTE: buffer size must be 2^n and up to 255. size_mask should be 2^n - 1 due to using &(AND) instead of %(modulo)
typedef struct {
uint8_t *buffer;
uint8_t head;
uint8_t tail;
uint8_t size_mask;
} ringbuf_t;
static inline void ringbuf_init(ringbuf_t *buf, uint8_t *array, uint8_t size);
static inline int16_t ringbuf_get(ringbuf_t *buf);
static inline bool ringbuf_put(ringbuf_t *buf, uint8_t data);
static inline void ringbuf_write(ringbuf_t *buf, uint8_t data);
static inline bool ringbuf_is_empty(ringbuf_t *buf);
static inline bool ringbuf_is_full(ringbuf_t *buf);
static inline void ringbuf_reset(ringbuf_t *buf);
static inline void ringbuf_init(ringbuf_t *buf, uint8_t *array, uint8_t size)
{
buf->buffer = array;
buf->head = 0;
buf->tail = 0;
buf->size_mask = size - 1;
}
static inline int16_t ringbuf_get(ringbuf_t *buf)
{
if (ringbuf_is_empty(buf)) return -1;
uint8_t data = buf->buffer[buf->tail];
buf->tail++;
buf->tail &= buf->size_mask;
return data;
}
static inline bool ringbuf_put(ringbuf_t *buf, uint8_t data)
{
if (ringbuf_is_full(buf)) {
return false;
}
buf->buffer[buf->head] = data;
buf->head++;
buf->head &= buf->size_mask;
return true;
}
// this overrides data in buffer when it is full
static inline void ringbuf_write(ringbuf_t *buf, uint8_t data)
{
buf->buffer[buf->head] = data;
buf->head++;
buf->head &= buf->size_mask;
// eat tail: override data yet to be consumed
if (buf->head == buf->tail) {
buf->tail++;
buf->tail &= buf->size_mask;
}
}
static inline bool ringbuf_is_empty(ringbuf_t *buf)
{
return (buf->head == buf->tail);
}
static inline bool ringbuf_is_full(ringbuf_t *buf)
{
return (((buf->head + 1) & buf->size_mask) == buf->tail);
}
static inline void ringbuf_reset(ringbuf_t *buf)
{
buf->head = 0;
buf->tail = 0;
}
#endif

View file

@ -43,6 +43,7 @@
#include "action.h"
#include "led.h"
#include "sendchar.h"
#include "ringbuf.h"
#include "debug.h"
#ifdef SLEEP_LED_ENABLE
#include "sleep_led.h"
@ -89,60 +90,97 @@ host_driver_t lufa_driver = {
* Console
******************************************************************************/
#ifdef CONSOLE_ENABLE
static void Console_Task(void)
#define SENDBUF_SIZE 256
static uint8_t sbuf[SENDBUF_SIZE];
static ringbuf_t sendbuf = {
.buffer = sbuf,
.head = 0,
.tail = 0,
.size_mask = SENDBUF_SIZE - 1
};
static bool console_putc(uint8_t c)
{
// return immediately if called while interrupt
if (!(SREG & (1<<SREG_I)))
goto EXIT;;
if (USB_DeviceState != DEVICE_STATE_Configured)
goto EXIT;;
uint8_t ep = Endpoint_GetCurrentEndpoint();
Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
goto EXIT_RESTORE_EP;
}
// write from buffer to endpoint bank
while (!ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
Endpoint_Write_8(ringbuf_get(&sendbuf));
// clear bank when it is full
if (!Endpoint_IsReadWriteAllowed() && Endpoint_IsINReady()) {
Endpoint_ClearIN();
}
}
// write c to bank directly if there is no others in buffer
if (ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
Endpoint_Write_8(c);
Endpoint_SelectEndpoint(ep);
return true;
}
EXIT_RESTORE_EP:
Endpoint_SelectEndpoint(ep);
EXIT:
return ringbuf_put(&sendbuf, c);
}
static void console_flush(void)
{
/* Device must be connected and configured for the task to run */
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
uint8_t ep = Endpoint_GetCurrentEndpoint();
#if 0
// TODO: impl receivechar()/recvchar()
Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
/* Check to see if a packet has been sent from the host */
if (Endpoint_IsOUTReceived())
{
/* Check to see if the packet contains data */
if (Endpoint_IsReadWriteAllowed())
{
/* Create a temporary buffer to hold the read in report from the host */
uint8_t ConsoleData[CONSOLE_EPSIZE];
/* Read Console Report Data */
Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
/* Process Console Report Data */
//ProcessConsoleHIDReport(ConsoleData);
}
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearOUT();
}
#endif
/* IN packet */
Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
Endpoint_SelectEndpoint(ep);
return;
}
// fill empty bank
while (Endpoint_IsReadWriteAllowed())
Endpoint_Write_8(0);
// write from buffer to endpoint bank
while (!ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
Endpoint_Write_8(ringbuf_get(&sendbuf));
// flash senchar packet
if (Endpoint_IsINReady()) {
// clear bank when it is full
if (!Endpoint_IsReadWriteAllowed() && Endpoint_IsINReady()) {
Endpoint_ClearIN();
}
}
// clear bank when there are chars in bank
if (Endpoint_BytesInEndpoint() && Endpoint_IsINReady()) {
// Windows needs to fill packet with 0
while (Endpoint_IsReadWriteAllowed()) {
Endpoint_Write_8(0);
}
Endpoint_ClearIN();
}
Endpoint_SelectEndpoint(ep);
}
#else
static void Console_Task(void)
static void console_task(void)
{
static uint16_t fn = 0;
if (fn == USB_Device_GetFrameNumber()) {
return;
}
fn = USB_Device_GetFrameNumber();
console_flush();
}
#endif
@ -205,24 +243,10 @@ void EVENT_USB_Device_WakeUp()
hook_usb_wakeup();
}
#ifdef CONSOLE_ENABLE
static bool console_flush = false;
#define CONSOLE_FLUSH_SET(b) do { \
uint8_t sreg = SREG; cli(); console_flush = b; SREG = sreg; \
} while (0)
// called every 1ms
void EVENT_USB_Device_StartOfFrame(void)
{
static uint8_t count;
if (++count % 50) return;
count = 0;
if (!console_flush) return;
Console_Task();
console_flush = false;
}
#endif
/** Event handler for the USB_ConfigurationChanged event.
* This is fired when the host sets the current configuration of the USB device after enumeration.
@ -419,7 +443,7 @@ static uint8_t keyboard_leds(void)
static void send_keyboard(report_keyboard_t *report)
{
uint8_t timeout = 255;
uint8_t timeout = 128;
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
@ -444,7 +468,7 @@ static void send_keyboard(report_keyboard_t *report)
Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
/* Check if write ready for a polling interval around 10ms */
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(80);
if (!Endpoint_IsReadWriteAllowed()) return;
/* Write Keyboard Report Data */
@ -531,72 +555,21 @@ static void send_consumer(uint16_t data)
* sendchar
******************************************************************************/
#ifdef CONSOLE_ENABLE
#define SEND_TIMEOUT 5
int8_t sendchar(uint8_t c)
{
#ifdef LUFA_DEBUG_SUART
#ifdef LUFA_DEBUG_SUART
xmit(c);
#endif
// Not wait once timeouted.
// Because sendchar() is called so many times, waiting each call causes big lag.
static bool timeouted = false;
#endif
// prevents Console_Task() from running during sendchar() runs.
// or char will be lost. These two function is mutually exclusive.
CONSOLE_FLUSH_SET(false);
if (USB_DeviceState != DEVICE_STATE_Configured)
return -1;
uint8_t ep = Endpoint_GetCurrentEndpoint();
Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
goto ERROR_EXIT;
}
if (timeouted && !Endpoint_IsReadWriteAllowed()) {
goto ERROR_EXIT;
}
timeouted = false;
uint8_t timeout = SEND_TIMEOUT;
while (!Endpoint_IsReadWriteAllowed()) {
if (USB_DeviceState != DEVICE_STATE_Configured) {
goto ERROR_EXIT;
}
if (Endpoint_IsStalled()) {
goto ERROR_EXIT;
}
if (!(timeout--)) {
timeouted = true;
goto ERROR_EXIT;
}
_delay_ms(1);
}
Endpoint_Write_8(c);
// send when bank is full
if (!Endpoint_IsReadWriteAllowed()) {
while (!(Endpoint_IsINReady()));
Endpoint_ClearIN();
} else {
CONSOLE_FLUSH_SET(true);
}
Endpoint_SelectEndpoint(ep);
return 0;
ERROR_EXIT:
Endpoint_SelectEndpoint(ep);
return -1;
bool r = console_putc(c);
return (r ? 0 : -1);
}
#else
int8_t sendchar(uint8_t c)
{
#ifdef LUFA_DEBUG_SUART
#ifdef LUFA_DEBUG_SUART
xmit(c);
#endif
#endif
return 0;
}
#endif
@ -622,7 +595,6 @@ static void setup_usb(void)
USB_Init();
// for Console_Task
USB_Device_EnableSOFEvents();
}
@ -635,15 +607,22 @@ int main(void)
SUART_OUT_DDR |= (1<<SUART_OUT_BIT);
SUART_OUT_PORT |= (1<<SUART_OUT_BIT);
#endif
print_set_sendchar(sendchar);
print("\r\ninit\n");
// setup sendchar: DO NOT USE print functions before this line
print_set_sendchar(sendchar);
host_set_driver(&lufa_driver);
print("Keyboard init.\n");
hook_early_init();
keyboard_setup();
setup_usb();
#ifdef SLEEP_LED_ENABLE
sleep_led_init();
#endif
sei();
/* wait for USB startup & debug output */
/* wait for USB startup */
while (USB_DeviceState != DEVICE_STATE_Configured) {
#if defined(INTERRUPT_CONTROL_ENDPOINT)
;
@ -652,27 +631,26 @@ int main(void)
#endif
}
/* wait for Console startup */
// TODO: long delay often works anyhoo but proper startup would be better
uint16_t delay = 2000;
while (delay--) {
#ifndef INTERRUPT_CONTROL_ENDPOINT
USB_USBTask();
#endif
_delay_ms(1);
}
print("USB configured.\n");
/* init modules */
keyboard_init();
host_set_driver(&lufa_driver);
#ifdef SLEEP_LED_ENABLE
sleep_led_init();
#endif
/* wait for Console startup */
// TODO: 2000ms delay often works anyhoo but proper startup would be better
// 1000ms delay of hid_listen affects this probably
#ifdef CONSOLE_ENABLE
if (debug_enable) {
uint16_t delay = 2000;
while (delay--) {
#ifndef INTERRUPT_CONTROL_ENDPOINT
USB_USBTask();
#endif
_delay_ms(1);
}
}
#endif
hook_late_init();
print("Keyboard start.\n");
hook_late_init();
while (1) {
while (USB_DeviceState == DEVICE_STATE_Suspended) {
#ifdef LUFA_DEBUG
@ -683,6 +661,10 @@ int main(void)
keyboard_task();
#ifdef CONSOLE_ENABLE
console_task();
#endif
#if !defined(INTERRUPT_CONTROL_ENDPOINT)
USB_USBTask();
#endif

View file

@ -39,10 +39,20 @@ POSSIBILITY OF SUCH DAMAGE.
#include <stdbool.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "pbuff.h"
#include "xt.h"
#include "wait.h"
#include "print.h"
#include "ringbuf.h"
#define BUF_SIZE 16
static uint8_t buf[BUF_SIZE];
static ringbuf_t rb = {
.buffer = buf,
.head = 0,
.tail = 0,
.size_mask = BUF_SIZE - 1
};
void xt_host_init(void)
{
@ -69,10 +79,12 @@ void xt_host_init(void)
/* get data received by interrupt */
uint8_t xt_host_recv(void)
{
if (pbuf_has_data()) {
return pbuf_dequeue();
} else {
if (ringbuf_is_empty(&rb)) {
return 0;
} else {
int16_t d = ringbuf_get(&rb);
XT_DATA_IN(); // ready to receive from keyboard
return d;
}
}
@ -111,7 +123,11 @@ ISR(XT_INT_VECT)
break;
}
if (state++ == BIT7) {
pbuf_enqueue(data);
ringbuf_put(&rb, data);
if (ringbuf_is_full(&rb)) {
XT_DATA_LO(); // inhibit keyboard sending
print("Full");
}
state = START;
data = 0;
}