addin: improve stability by not blocking on reads

This commit is contained in:
Lephenixnoir 2023-03-26 21:03:15 +02:00
parent 9e76db9e7e
commit fb9174197f
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
1 changed files with 68 additions and 22 deletions

View File

@ -3,8 +3,15 @@
#include <gint/usb.h>
#include <gint/usb-ff-bulk.h>
#include <gint/gint.h>
#include <fxlibc/printf.h>
#include <libprof.h>
#include <fxlibc/printf.h>
/* Debug mode (uses gint perf counters not committed to repository) */
// #define DEBUG
//---
// Receiving and displaying video frames
//---
static void process_usb_message(struct usb_fxlink_header const *header)
{
@ -18,59 +25,96 @@ static void process_usb_message(struct usb_fxlink_header const *header)
dupdate();
return;
}
#if 0
#ifdef DEBUG
extern prof_t prof_round, prof_core;
prof_round = prof_make();
prof_core = prof_make();
uint32_t us = prof_exec({
prof_t prof_read = prof_make();
prof_enter(prof_read);
#endif
// TODO: async read for robustness
usb_read_sync(usb_ff_bulk_input(), gint_vram, header->size, false);
#if 0
});
/* Read the message payload directly into VRAM. We set a timeout so the
calculator doesn't freeze if the communication stops midway because the
VNC client on the PC was interrupted. */
timeout_t tm = timeout_make_ms(250);
usb_read_sync_timeout(usb_ff_bulk_input(), gint_vram, header->size, false,
&tm);
#ifdef DEBUG
prof_leave(prof_read);
dprint_opt(1, 1, C_WHITE, C_BLACK, DTEXT_LEFT, DTEXT_TOP,
"%d ms (read %.1D ms, wait %.1D ms)\n",
us / 1000,
prof_time(prof_read) / 1000,
prof_time(prof_round) / 100,
prof_time(prof_core) / 100);
#endif
dupdate();
}
#define MAX_PRESSES 16
//---
// Sending keyboard events
//---
static void handle_events(void)
#define MAX_EVENTS_PER_MESSAGE 16
struct key_event { uint8_t key; bool down; };
/* Keyboard data to be sent to the PC whenever a key is pressed */
static struct key_event keyinfo[MAX_EVENTS_PER_MESSAGE];
/* Whether there is such a transfer in progress */
static bool keyinfo_frame = false;
static void send_keyboard_events_callback(void)
{
keyinfo_frame = false;
}
static void send_keyboard_events(void)
{
static uint8_t keyinfo[MAX_PRESSES*2];
int i = 0;
key_event_t ev;
while((ev = pollevent()).type != KEYEV_NONE) {
if((ev.type == KEYEV_DOWN || ev.type == KEYEV_UP) && i < MAX_PRESSES) {
keyinfo[2*i] = ev.key;
keyinfo[2*i+1] = (ev.type == KEYEV_DOWN);
i++;
}
/* Filter out repeats and any events past the maximum number */
if(ev.type != KEYEV_DOWN && ev.type != KEYEV_UP)
continue;
if(i >= MAX_EVENTS_PER_MESSAGE)
continue;
keyinfo[i].key = ev.key;
keyinfo[i].down = (ev.type == KEYEV_DOWN);
i++;
}
/* Send keyboard update via fxlink */
if(i > 0 && usb_is_open()) {
/* Send keyboard updates via fxlink */
if(i > 0 && usb_is_open() && !keyinfo_frame) {
usb_fxlink_header_t header;
usb_fxlink_fill_header(&header, "cgvm", "pressed-keys", 2*i);
// TODO: async commit for robustness (write fits in buffer)
/* We don't need to use async writes because all of this clearly fits
in a single buffer (2 kB) and only the commit communicates */
int pipe = usb_ff_bulk_output();
usb_write_sync(pipe, &header, sizeof header, false);
usb_write_sync(pipe, keyinfo, 2*i, false);
usb_commit_sync(pipe);
usb_write_sync(pipe, keyinfo, i * sizeof *keyinfo, false);
usb_commit_async(pipe, GINT_CALL(send_keyboard_events_callback));
/* Remember that a transfer is in progress */
keyinfo_frame = true;
}
}
//--
// Main loop
//---
int main(void)
{
#ifdef DEBUG
prof_init();
__printf_enable_fixed();
#endif
dclear(C_WHITE);
dprint(1, 1, C_BLACK, "Opening USB connection...");
@ -86,7 +130,7 @@ int main(void)
struct usb_fxlink_header header;
while(1) {
handle_events();
send_keyboard_events();
if(keydown(KEY_MENU))
gint_osmenu();
if(keydown(KEY_EXIT))
@ -97,6 +141,8 @@ int main(void)
}
}
#ifdef DEBUG
prof_quit();
#endif
return 0;
}