Compare commits

...

3 Commits

Author SHA1 Message Date
Lephenixnoir efafce9fb0
vnc: improve frame update timing 2023-03-27 21:55:39 +02:00
Lephenixnoir bb1bcafe01
vnc: gracefully handle outputs of any size
Shows the top-left corner of the output on the top-left corner of the
calculator display.
2023-03-27 19:22:42 +02:00
Lephenixnoir be73b114c1
minor adjustements 2023-03-27 19:21:20 +02:00
4 changed files with 63 additions and 32 deletions

View File

@ -16,16 +16,17 @@ Instead, sway's outputs are exposed by a VNC server running locally
([wayvnc](https://github.com/any1/wayvnc)).
The VNC client in this repository's `vnc-client` folder is connected to the
VNC server, while at the same time using the communications library _libfxlink_
VNC server, while at the same time using the communications library libfxlink
from the [fxSDK](https://gitea.planet-casio.com/Lephenixnoir/fxsdk) to discover
calculators and exchange messages. It sends framebuffer updates and receives
keyboard updates (which are, unsurprisingly, forwarded to the VNC server).
The calculators themselves run [gint](https://gitea.planet-casio.com/Lephenixnoir/gint)
2.10 using newly-added support for host → calculator USB communication. They
"simply" show framebuffers they receive and send back keyboard updates so that
the calculator keyboards can control the PC. Obviously the USB driver is not
that simple... but this is invisible from the application code.
The calculators themselves run the addin in the `cgvm-addin` folder, which is
based on [gint](https://gitea.planet-casio.com/Lephenixnoir/gint) 2.10 with
newly-added support for host → calculator USB communication. They "simply" show
framebuffers they receive and send back keyboard updates so that the calculator
keyboards can control the PC. Obviously the USB driver is not that simple...
but this is invisible from the application code.
The entire setup runs at about 30 FPS, which each frame taking about:
@ -145,9 +146,6 @@ finally remove the outputs.
## Known issues
- The first frame is often incorrect.
- Frames from the VNC server are dropped if the calculator is busy processing a
previous frame.
- The VNC client seems to lost connection with the calculator sometimes (libusb
returning "No such device"). Not sure why yet, as it's hard to reproduce. In
that case restart the VNC client.

View File

@ -3,12 +3,15 @@
#include <gint/usb.h>
#include <gint/usb-ff-bulk.h>
#include <gint/gint.h>
#include <libprof.h>
#include <fxlibc/printf.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
//---

View File

Before

Width:  |  Height:  |  Size: 3.9 MiB

After

Width:  |  Height:  |  Size: 3.9 MiB

View File

@ -13,6 +13,8 @@
/* Number of monitors */
#define MONITOR_COUNT 2
#define min(a, b) ((a) < (b) ? (a) : (b))
/* Tracking data for a calculator-attached virtual monitor */
struct monitor {
/* RFB/VNC client to get framebuffers from VNC server */
@ -25,6 +27,10 @@ struct monitor {
libusb_device *calc_unique_id;
/* 16-bit framebuffer for the calculator (big endian) */
uint16_t *fb16_be;
/* Update flag for the calculator */
bool needs_update;
/* Whether the client has itself received any framebuffer yet */
bool client_has_fb;
};
/* Application globals */
@ -73,35 +79,27 @@ static void cleanup(void)
libusb_exit(app.libusb_ctx);
}
/* Handle a framebuffer update by displaying to the SDL window and/or sending a
new 16-bit framebuffer to the calculator. */
/* Handle a framebuffer update. We immediately display to the SDL window but
delay communication with the calculator since the calculator might be busy
with a previous frame right now. */
static void fb_update(rfbClient *client)
{
uint32_t *fb = (void *)client->frameBuffer;
struct monitor *mon = rfbClientGetClientData(client, NULL);
int min_w = min(client->width, CALC_WIDTH);
int min_h = min(client->height, CALC_HEIGHT);
if(app.display_sdl) {
/* Very crude assumption about the SDL surface format and pitch */
memcpy(mon->surface->pixels, fb, CALC_WIDTH * CALC_HEIGHT * 4);
memset(mon->surface->pixels, 0, CALC_WIDTH * CALC_HEIGHT * 4);
for(int y = 0; y < min_h; y++) {
memcpy(mon->surface->pixels + y * mon->surface->pitch,
fb + y * client->width, min_w * 4);
}
SDL_UpdateWindowSurface(mon->window);
}
if(app.display_calc && mon->calc && mon->fb16_be) {
for(int y = 0; y < CALC_HEIGHT; y++)
for(int x = 0; x < CALC_WIDTH; x++) {
uint32_t color = fb[CALC_WIDTH * y + x];
int R = (color >> 16) & 0xff;
int G = (color >> 8) & 0xff;
int B = (color & 0xff);
/* Conversion to RGB565 */
int c = ((R & 0xf8) << 8) | ((G & 0xfc) << 3) | ((B & 0xf8) >> 3);
mon->fb16_be[CALC_WIDTH * y + x] = (c >> 8) | (c << 8);
}
fxlink_device_start_bulk_OUT(mon->calc,
"cgvm", "fb", mon->fb16_be, CALC_WIDTH * CALC_HEIGHT * 2, false);
}
mon->client_has_fb = true;
mon->needs_update = true;
}
/* Convert a gint keycode to an rfbKeySym. This is just for show, the keymap is
@ -330,6 +328,7 @@ void monitor_update(struct monitor *mon, int mon_id)
mon->calc = fdev;
mon->calc_unique_id = fdev->dp;
fxlink_device_start_bulk_IN(fdev);
mon->needs_update = true;
break;
}
}
@ -343,6 +342,37 @@ void monitor_update(struct monitor *mon, int mon_id)
fxlink_device_start_bulk_IN(mon->calc);
}
}
/* Send new frames */
if(app.display_calc && mon->needs_update && mon->calc) {
if(mon->client_has_fb) {
uint32_t *fb = (void *)mon->client->frameBuffer;
int min_w = min(mon->client->width, CALC_WIDTH);
int min_h = min(mon->client->height, CALC_HEIGHT);
memset(mon->fb16_be, 0, CALC_WIDTH * CALC_HEIGHT * 2);
for(int y = 0; y < min_h; y++)
for(int x = 0; x < min_w; x++) {
uint32_t color = fb[y * mon->client->width + x];
int R = (color >> 16) & 0xff;
int G = (color >> 8) & 0xff;
int B = (color & 0xff);
/* Conversion to RGB565 */
int c = ((R & 0xf8)<<8) | ((G & 0xfc)<<3) | ((B & 0xf8)>>3);
mon->fb16_be[CALC_WIDTH * y + x] = (c >> 8) | (c << 8);
}
}
else {
memset(mon->fb16_be, 0x55, CALC_WIDTH * CALC_HEIGHT * 2);
}
if(fxlink_device_start_bulk_OUT(mon->calc, "cgvm", "fb",
mon->fb16_be, CALC_WIDTH * CALC_HEIGHT * 2, false))
mon->needs_update = false;
}
}
int main(int argc, char **argv)
@ -410,7 +440,7 @@ int main(int argc, char **argv)
if(!mon)
continue;
int rc = WaitForMessage(mon->client, 1000);
int rc = WaitForMessage(mon->client, 5000);
if(rc < 0) {
fprintf(stderr, "WaitForMessage() select: %d\n", rc);
continue;