]> git.friedersdorff.com Git - max/tmk_keyboard.git/commitdiff
Merge branch 'console_ringbuf_fix'
authortmk <hasu@tmk-kbd.com>
Sun, 23 Sep 2018 04:53:20 +0000 (13:53 +0900)
committertmk <hasu@tmk-kbd.com>
Sun, 23 Sep 2018 04:53:20 +0000 (13:53 +0900)
converter/xt_usb/matrix.c
tmk_core/common/ringbuf.h [new file with mode: 0644]
tmk_core/protocol/lufa/lufa.c
tmk_core/protocol/xt_interrupt.c

index fe4eebf3e1bde471a4abeabbd6ed0ad957f229a2..f6784573b385e519755a085b3fe3b3563b1c5767 100644 (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) {
diff --git a/tmk_core/common/ringbuf.h b/tmk_core/common/ringbuf.h
new file mode 100644 (file)
index 0000000..23bb41e
--- /dev/null
@@ -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
index 60849aea4c935da108839c6e583d596540624719..b1567fa9bdac242dfbe9a12395c7db8212177748 100644 (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)
 {
-    /* Device must be connected and configured for the task to run */
+    // return immediately if called while interrupt
+    if (!(SREG & (1<<SREG_I)))
+        goto EXIT;;
+
     if (USB_DeviceState != DEVICE_STATE_Configured)
-        return;
+        goto EXIT;;
 
     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];
+    Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
+    if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
+        goto EXIT_RESTORE_EP;
+    }
 
-            /* Read Console Report Data */
-            Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
+    // write from buffer to endpoint bank
+    while (!ringbuf_is_empty(&sendbuf) && Endpoint_IsReadWriteAllowed()) {
+        Endpoint_Write_8(ringbuf_get(&sendbuf));
 
-            /* Process Console Report Data */
-            //ProcessConsoleHIDReport(ConsoleData);
+        // clear bank when it is full
+        if (!Endpoint_IsReadWriteAllowed() && Endpoint_IsINReady()) {
+            Endpoint_ClearIN();
         }
+    }
 
-        /* Finalize the stream transfer to send the last packet */
-        Endpoint_ClearOUT();
+    // 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;
     }
-#endif
 
-    /* IN packet */
+EXIT_RESTORE_EP:
+    Endpoint_SelectEndpoint(ep);
+EXIT:
+    return ringbuf_put(&sendbuf, c);
+}
+
+static void console_flush(void)
+{
+    if (USB_DeviceState != DEVICE_STATE_Configured)
+        return;
+
+    uint8_t ep = Endpoint_GetCurrentEndpoint();
+
     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));
+
+        // clear bank when it is full
+        if (!Endpoint_IsReadWriteAllowed() && Endpoint_IsINReady()) {
+            Endpoint_ClearIN();
+        }
+    }
 
-    // flash senchar packet
-    if (Endpoint_IsINReady()) {
+    // 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;
-
-    // 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);
-    }
+    #endif
 
-    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
+
+    // setup sendchar: DO NOT USE print functions before this line
     print_set_sendchar(sendchar);
-    print("\r\ninit\n");
+    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
     }
 
+    keyboard_init();
+
     /* 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);
+    // 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
 
-    print("USB configured.\n");
-
-    /* init modules */
-    keyboard_init();
-    host_set_driver(&lufa_driver);
-#ifdef SLEEP_LED_ENABLE
-    sleep_led_init();
-#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
index a0c55e9c6e5f98fef585a5e12a0d31bf932219ea..ebaa436b382636e06cc3922006c8a3146e5ce104 100644 (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;
     }