152 lines
3.7 KiB
C
152 lines
3.7 KiB
C
#include <gint/display.h>
|
|
#include <gint/keyboard.h>
|
|
#include <gint/usb.h>
|
|
#include <gint/usb-ff-bulk.h>
|
|
#include <gint/gint.h>
|
|
|
|
/* Debug mode (uses gint perf counters not committed to repository) */
|
|
// #define DEBUG
|
|
|
|
#ifdef DEBUG
|
|
#include <libprof.h>
|
|
#include <fxlibc/printf.h>
|
|
#endif
|
|
|
|
//---
|
|
// Receiving and displaying video frames
|
|
//---
|
|
|
|
static void process_usb_message(struct usb_fxlink_header const *header)
|
|
{
|
|
static int count = 0;
|
|
count++;
|
|
|
|
if(header->size > DWIDTH * DHEIGHT * 2) {
|
|
dclear(C_BLACK);
|
|
dprint(1, 1, C_WHITE, "[%d] %.16s %.16s (%d B)", count,
|
|
header->application, header->type, header->size);
|
|
dupdate();
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
extern prof_t prof_round, prof_core;
|
|
prof_round = prof_make();
|
|
prof_core = prof_make();
|
|
|
|
prof_t prof_read = prof_make();
|
|
prof_enter(prof_read);
|
|
#endif
|
|
|
|
/* 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",
|
|
prof_time(prof_read) / 1000,
|
|
prof_time(prof_round) / 100,
|
|
prof_time(prof_core) / 100);
|
|
#endif
|
|
|
|
dupdate();
|
|
}
|
|
|
|
//---
|
|
// Sending keyboard events
|
|
//---
|
|
|
|
#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)
|
|
{
|
|
int i = 0;
|
|
|
|
key_event_t ev;
|
|
while((ev = pollevent()).type != KEYEV_NONE) {
|
|
/* 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 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);
|
|
|
|
/* 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, 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...");
|
|
dupdate();
|
|
|
|
usb_interface_t const *intf[] = { &usb_ff_bulk, NULL };
|
|
usb_open(intf, GINT_CALL_NULL);
|
|
usb_open_wait();
|
|
|
|
dclear(C_WHITE);
|
|
dprint(1, 1, C_BLACK, "USB connected!");
|
|
dupdate();
|
|
|
|
struct usb_fxlink_header header;
|
|
while(1) {
|
|
send_keyboard_events();
|
|
if(keydown(KEY_MENU))
|
|
gint_osmenu();
|
|
if(keydown(KEY_EXIT))
|
|
break;
|
|
|
|
while(usb_fxlink_handle_messages(&header)) {
|
|
process_usb_message(&header);
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
prof_quit();
|
|
#endif
|
|
return 0;
|
|
}
|