Compare commits
3 Commits
f5d30515bf
...
efafce9fb0
Author | SHA1 | Date |
---|---|---|
Lephenixnoir | efafce9fb0 | |
Lephenixnoir | bb1bcafe01 | |
Lephenixnoir | be73b114c1 |
16
README.md
16
README.md
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
//---
|
||||
|
|
Before Width: | Height: | Size: 3.9 MiB After Width: | Height: | Size: 3.9 MiB |
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue