diff options
-rw-r--r-- | tmk_core/protocol/chibios/usb_driver.c | 14 | ||||
-rw-r--r-- | tmk_core/protocol/chibios/usb_main.c | 29 | ||||
-rw-r--r-- | tmk_core/protocol/lufa/lufa.c | 11 |
3 files changed, 33 insertions, 21 deletions
diff --git a/tmk_core/protocol/chibios/usb_driver.c b/tmk_core/protocol/chibios/usb_driver.c index 40bfb8eb2..cc0ce7600 100644 --- a/tmk_core/protocol/chibios/usb_driver.c +++ b/tmk_core/protocol/chibios/usb_driver.c | |||
@@ -80,19 +80,7 @@ static bool qmkusb_start_receive(QMKUSBDriver *qmkusbp) { | |||
80 | * Interface implementation. | 80 | * Interface implementation. |
81 | */ | 81 | */ |
82 | 82 | ||
83 | static size_t _write(void *ip, const uint8_t *bp, size_t n) { | 83 | static size_t _write(void *ip, const uint8_t *bp, size_t n) { return obqWriteTimeout(&((QMKUSBDriver *)ip)->obqueue, bp, n, TIME_INFINITE); } |
84 | output_buffers_queue_t *obqueue = &((QMKUSBDriver *)ip)->obqueue; | ||
85 | chSysLock(); | ||
86 | const bool full = obqIsFullI(obqueue); | ||
87 | chSysUnlock(); | ||
88 | if (full || bqIsSuspendedX(obqueue)) { | ||
89 | /* Discard any writes while the queue is suspended or full, i.e. the hidraw | ||
90 | interface is not open. If we tried to send with an infinite timeout, we | ||
91 | would deadlock the keyboard otherwise. */ | ||
92 | return -1; | ||
93 | } | ||
94 | return obqWriteTimeout(obqueue, bp, n, TIME_INFINITE); | ||
95 | } | ||
96 | 84 | ||
97 | static size_t _read(void *ip, uint8_t *bp, size_t n) { return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, n, TIME_INFINITE); } | 85 | static size_t _read(void *ip, uint8_t *bp, size_t n) { return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, n, TIME_INFINITE); } |
98 | 86 | ||
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c index 8adecfa71..0703cdc71 100644 --- a/tmk_core/protocol/chibios/usb_main.c +++ b/tmk_core/protocol/chibios/usb_main.c | |||
@@ -930,9 +930,32 @@ void send_consumer(uint16_t data) { | |||
930 | #ifdef CONSOLE_ENABLE | 930 | #ifdef CONSOLE_ENABLE |
931 | 931 | ||
932 | int8_t sendchar(uint8_t c) { | 932 | int8_t sendchar(uint8_t c) { |
933 | // The previous implmentation had timeouts, but I think it's better to just slow down | 933 | static bool timed_out = false; |
934 | // and make sure that everything is transferred, rather than dropping stuff | 934 | /* The `timed_out` state is an approximation of the ideal `is_listener_disconnected?` state. |
935 | return chnWrite(&drivers.console_driver.driver, &c, 1); | 935 | * |
936 | * When a 5ms timeout write has timed out, hid_listen is most likely not running, or not | ||
937 | * listening to this keyboard, so we go into the timed_out state. In this state we assume | ||
938 | * that hid_listen is most likely not gonna be connected to us any time soon, so it would | ||
939 | * be wasteful to write follow-up characters with a 5ms timeout, it would all add up and | ||
940 | * unncecessarily slow down the firmware. However instead of just dropping the characters, | ||
941 | * we write them with a TIME_IMMEDIATE timeout, which is a zero timeout, | ||
942 | * and this will succeed only if hid_listen gets connected again. When a write with | ||
943 | * TIME_IMMEDIATE timeout succeeds, we know that hid_listen is listening to us again, and | ||
944 | * we can go back to the timed_out = false state, and following writes will be executed | ||
945 | * with a 5ms timeout. The reason we don't just send all characters with the TIME_IMMEDIATE | ||
946 | * timeout is that this could cause bytes to be lost even if hid_listen is running, if there | ||
947 | * is a lot of data being sent over the console. | ||
948 | * | ||
949 | * This logic will work correctly as long as hid_listen is able to receive at least 200 | ||
950 | * bytes per second. On a heavily overloaded machine that's so overloaded that it's | ||
951 | * unusable, and constantly swapping, hid_listen might have trouble receiving 200 bytes per | ||
952 | * second, so some bytes might be lost on the console. | ||
953 | */ | ||
954 | |||
955 | const sysinterval_t timeout = timed_out ? TIME_IMMEDIATE : TIME_MS2I(5); | ||
956 | const size_t result = chnWriteTimeout(&drivers.console_driver.driver, &c, 1, timeout); | ||
957 | timed_out = (result == 0); | ||
958 | return result; | ||
936 | } | 959 | } |
937 | 960 | ||
938 | // Just a dummy function for now, this could be exposed as a weak function | 961 | // Just a dummy function for now, this could be exposed as a weak function |
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index f1908b3d0..85d71d083 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c | |||
@@ -829,9 +829,10 @@ static void send_consumer(uint16_t data) { | |||
829 | * FIXME: Needs doc | 829 | * FIXME: Needs doc |
830 | */ | 830 | */ |
831 | int8_t sendchar(uint8_t c) { | 831 | int8_t sendchar(uint8_t c) { |
832 | // Not wait once timeouted. | 832 | // Do not wait if the previous write has timed_out. |
833 | // Because sendchar() is called so many times, waiting each call causes big lag. | 833 | // Because sendchar() is called so many times, waiting each call causes big lag. |
834 | static bool timeouted = false; | 834 | // The `timed_out` state is an approximation of the ideal `is_listener_disconnected?` state. |
835 | static bool timed_out = false; | ||
835 | 836 | ||
836 | // prevents Console_Task() from running during sendchar() runs. | 837 | // prevents Console_Task() from running during sendchar() runs. |
837 | // or char will be lost. These two function is mutually exclusive. | 838 | // or char will be lost. These two function is mutually exclusive. |
@@ -845,11 +846,11 @@ int8_t sendchar(uint8_t c) { | |||
845 | goto ERROR_EXIT; | 846 | goto ERROR_EXIT; |
846 | } | 847 | } |
847 | 848 | ||
848 | if (timeouted && !Endpoint_IsReadWriteAllowed()) { | 849 | if (timed_out && !Endpoint_IsReadWriteAllowed()) { |
849 | goto ERROR_EXIT; | 850 | goto ERROR_EXIT; |
850 | } | 851 | } |
851 | 852 | ||
852 | timeouted = false; | 853 | timed_out = false; |
853 | 854 | ||
854 | uint8_t timeout = SEND_TIMEOUT; | 855 | uint8_t timeout = SEND_TIMEOUT; |
855 | while (!Endpoint_IsReadWriteAllowed()) { | 856 | while (!Endpoint_IsReadWriteAllowed()) { |
@@ -860,7 +861,7 @@ int8_t sendchar(uint8_t c) { | |||
860 | goto ERROR_EXIT; | 861 | goto ERROR_EXIT; |
861 | } | 862 | } |
862 | if (!(timeout--)) { | 863 | if (!(timeout--)) { |
863 | timeouted = true; | 864 | timed_out = true; |
864 | goto ERROR_EXIT; | 865 | goto ERROR_EXIT; |
865 | } | 866 | } |
866 | _delay_ms(1); | 867 | _delay_ms(1); |