Merge remote-tracking branch 'origin/master' into develop
This commit is contained in:
commit
64a9cf18e1
3 changed files with 33 additions and 21 deletions
|
@ -80,19 +80,7 @@ static bool qmkusb_start_receive(QMKUSBDriver *qmkusbp) {
|
||||||
* Interface implementation.
|
* Interface implementation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static size_t _write(void *ip, const uint8_t *bp, size_t n) {
|
static size_t _write(void *ip, const uint8_t *bp, size_t n) { return obqWriteTimeout(&((QMKUSBDriver *)ip)->obqueue, bp, n, TIME_INFINITE); }
|
||||||
output_buffers_queue_t *obqueue = &((QMKUSBDriver *)ip)->obqueue;
|
|
||||||
chSysLock();
|
|
||||||
const bool full = obqIsFullI(obqueue);
|
|
||||||
chSysUnlock();
|
|
||||||
if (full || bqIsSuspendedX(obqueue)) {
|
|
||||||
/* Discard any writes while the queue is suspended or full, i.e. the hidraw
|
|
||||||
interface is not open. If we tried to send with an infinite timeout, we
|
|
||||||
would deadlock the keyboard otherwise. */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return obqWriteTimeout(obqueue, bp, n, TIME_INFINITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t _read(void *ip, uint8_t *bp, size_t n) { return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, n, TIME_INFINITE); }
|
static size_t _read(void *ip, uint8_t *bp, size_t n) { return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, n, TIME_INFINITE); }
|
||||||
|
|
||||||
|
|
|
@ -930,9 +930,32 @@ void send_consumer(uint16_t data) {
|
||||||
#ifdef CONSOLE_ENABLE
|
#ifdef CONSOLE_ENABLE
|
||||||
|
|
||||||
int8_t sendchar(uint8_t c) {
|
int8_t sendchar(uint8_t c) {
|
||||||
// The previous implmentation had timeouts, but I think it's better to just slow down
|
static bool timed_out = false;
|
||||||
// and make sure that everything is transferred, rather than dropping stuff
|
/* The `timed_out` state is an approximation of the ideal `is_listener_disconnected?` state.
|
||||||
return chnWrite(&drivers.console_driver.driver, &c, 1);
|
*
|
||||||
|
* When a 5ms timeout write has timed out, hid_listen is most likely not running, or not
|
||||||
|
* listening to this keyboard, so we go into the timed_out state. In this state we assume
|
||||||
|
* that hid_listen is most likely not gonna be connected to us any time soon, so it would
|
||||||
|
* be wasteful to write follow-up characters with a 5ms timeout, it would all add up and
|
||||||
|
* unncecessarily slow down the firmware. However instead of just dropping the characters,
|
||||||
|
* we write them with a TIME_IMMEDIATE timeout, which is a zero timeout,
|
||||||
|
* and this will succeed only if hid_listen gets connected again. When a write with
|
||||||
|
* TIME_IMMEDIATE timeout succeeds, we know that hid_listen is listening to us again, and
|
||||||
|
* we can go back to the timed_out = false state, and following writes will be executed
|
||||||
|
* with a 5ms timeout. The reason we don't just send all characters with the TIME_IMMEDIATE
|
||||||
|
* timeout is that this could cause bytes to be lost even if hid_listen is running, if there
|
||||||
|
* is a lot of data being sent over the console.
|
||||||
|
*
|
||||||
|
* This logic will work correctly as long as hid_listen is able to receive at least 200
|
||||||
|
* bytes per second. On a heavily overloaded machine that's so overloaded that it's
|
||||||
|
* unusable, and constantly swapping, hid_listen might have trouble receiving 200 bytes per
|
||||||
|
* second, so some bytes might be lost on the console.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const sysinterval_t timeout = timed_out ? TIME_IMMEDIATE : TIME_MS2I(5);
|
||||||
|
const size_t result = chnWriteTimeout(&drivers.console_driver.driver, &c, 1, timeout);
|
||||||
|
timed_out = (result == 0);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just a dummy function for now, this could be exposed as a weak function
|
// Just a dummy function for now, this could be exposed as a weak function
|
||||||
|
|
|
@ -829,9 +829,10 @@ static void send_consumer(uint16_t data) {
|
||||||
* FIXME: Needs doc
|
* FIXME: Needs doc
|
||||||
*/
|
*/
|
||||||
int8_t sendchar(uint8_t c) {
|
int8_t sendchar(uint8_t c) {
|
||||||
// Not wait once timeouted.
|
// Do not wait if the previous write has timed_out.
|
||||||
// Because sendchar() is called so many times, waiting each call causes big lag.
|
// Because sendchar() is called so many times, waiting each call causes big lag.
|
||||||
static bool timeouted = false;
|
// The `timed_out` state is an approximation of the ideal `is_listener_disconnected?` state.
|
||||||
|
static bool timed_out = false;
|
||||||
|
|
||||||
// prevents Console_Task() from running during sendchar() runs.
|
// prevents Console_Task() from running during sendchar() runs.
|
||||||
// or char will be lost. These two function is mutually exclusive.
|
// or char will be lost. These two function is mutually exclusive.
|
||||||
|
@ -845,11 +846,11 @@ int8_t sendchar(uint8_t c) {
|
||||||
goto ERROR_EXIT;
|
goto ERROR_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeouted && !Endpoint_IsReadWriteAllowed()) {
|
if (timed_out && !Endpoint_IsReadWriteAllowed()) {
|
||||||
goto ERROR_EXIT;
|
goto ERROR_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
timeouted = false;
|
timed_out = false;
|
||||||
|
|
||||||
uint8_t timeout = SEND_TIMEOUT;
|
uint8_t timeout = SEND_TIMEOUT;
|
||||||
while (!Endpoint_IsReadWriteAllowed()) {
|
while (!Endpoint_IsReadWriteAllowed()) {
|
||||||
|
@ -860,7 +861,7 @@ int8_t sendchar(uint8_t c) {
|
||||||
goto ERROR_EXIT;
|
goto ERROR_EXIT;
|
||||||
}
|
}
|
||||||
if (!(timeout--)) {
|
if (!(timeout--)) {
|
||||||
timeouted = true;
|
timed_out = true;
|
||||||
goto ERROR_EXIT;
|
goto ERROR_EXIT;
|
||||||
}
|
}
|
||||||
_delay_ms(1);
|
_delay_ms(1);
|
||||||
|
|
Loading…
Reference in a new issue