#include "action.h"
#include "led.h"
#include "sendchar.h"
+#include "ringbuf.h"
#include "debug.h"
#ifdef SLEEP_LED_ENABLE
#include "sleep_led.h"
* 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));
- // 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
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.
static void send_keyboard(report_keyboard_t *report)
{
- uint8_t timeout = 255;
+ uint8_t timeout = 128;
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
* 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;
- }
+ #endif
- 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
USB_Init();
- // for Console_Task
USB_Device_EnableSOFEvents();
}
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)
;
#endif
}
+ keyboard_init();
+
/* wait for Console startup */
// TODO: long delay often works anyhoo but proper startup would be better
+ // 1000ms delay of hid_listen may affect this
uint16_t delay = 2000;
while (delay--) {
#ifndef INTERRUPT_CONTROL_ENDPOINT
_delay_ms(1);
}
- 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
keyboard_task();
+#ifdef CONSOLE_ENABLE
+ console_task();
+#endif
+
#if !defined(INTERRUPT_CONTROL_ENDPOINT)
USB_USBTask();
#endif