G15DAEMON_CLIENT_DEVEL(3)

πŸ“¦
version 1.9.5.3 Β· 2 versions
, in debian bookworm, debian trixie, ubuntu jammy, ubuntu noble, ubuntu questing, ubuntu resolute, ubuntu stonking

πŸ’– NAME πŸ’–

g15daemon_client β€” G15Daemon Server / Client communication for g15daemon 🫢

okay so you opened the G15daemon Client Development page and you're like "what is this" β€” bestie, it's the whole manual for talking to g15daemon from your own code. grab a snack, we're going in πŸ’…


✨ SYNOPSIS ✨

#include <libg15.h>
#include <g15daemon_client.h>

link with

-lg15daemon_client

int new_g15_screen(int screentype);
int g15_close_screen(int sock);
int g15_send(int sock, char *buf, unsigned int len);
int g15_recv(int sock, char *buf, unsigned int len);
int g15_send_cmd (int sock, unsigned char command, unsigned char value);

πŸ¦‹ G15Daemon Server / Client communication πŸ¦‹

so the tea is: G15Daemon talks to its clients over INET sockets, and it's sitting there listening on localhost port 15550 waiting for connection requests πŸ‘€

the second you connect, the server sends you the text string "G15 daemon HELLO" β€” that's it confirming to you that it really is a valid g15daemon process, no catfish here πŸ’€ β€” then it creates a new screen and just waits for LCD buffers or commands to show up from you.

and the way you get multiple screens? iconic. you literally just open more socket connections to the server process. that's it. that's the trick πŸ‘‘

if the socket gets closed, or your client just dips and exits, all the LCD buffers and the screen tied to that socket get automatically destroyed. no cleanup chores, the daemon handles it ✨

clients that wanna display stuff on the LCD must send entire screens, in whatever format they like. and lowkey important: partial screen updates (icons, etc.) are not supported right now πŸ™ˆ

commands go to the daemon via the OOB (out-of-band) messagetype, and the replies come back inband to the client. remember that, it matters later.


🌸 int new_g15_screen(int screentype) 🌸

opens a new connection and hands you back a network socket to use πŸŽ€

it also creates a screen, and the pixel format you get depends on which of these (defined in g15daemon_client.h) you pass:

  • G15_PIXELBUF β€” this buffer has to be exactly 6880 bytes, and it uses 1 byte per pixel. no more, no less, don't try it.
  • G15_TEXTBUF β€” currently ignored by the daemon. yeah. it's giving ghosted πŸ’€
  • G15_WBMPBUF β€” a packed pixel buffer in WBMP format with 8 pixels per byte. super handy for perl programmers using the GD:: and G15Daemon.pm perl modules (check the lang_bindings directory, iykyk).
  • G15_G15RBUF β€” another packed pixel buffer type, also 8 pixels/byte, and it's the native libg15render format. the real one ⭐

example of use:

int screen_fd = new_g15_screen( G15_WBMPBUF );

πŸŽ€ int g15_close_screen (int screen_fd) πŸŽ€

does exactly what it says bestie β€” it just closes a socket you previously opened with new_g15_screen(). then the daemon automatically cleans up any buffers and removes the LCD screen from the display list. it's giving "you don't have to do anything, I got you" 🫢

returns 0 if it worked, or errno if there was an error.

example:

int retval = 0; int screen_fd = new_g15_screen( G15_WBMPBUF );

 ... do processing and display here ...

retval = g15_close_screen( screen_fd );

πŸ”₯ int g15_send (int sock, char *buf, unsigned int len) πŸ”₯

a lil wrapper around send() whose whole personality is "make sure all len bytes of data actually get to the daemon". it just uses poll() to block until the entire message is sent. no half-sends, no drama ✨

returns 0 on success, -1 if the send failed because of a timeout or a socket error 😭


🌈 int g15_recv (int sock, char *buf, unsigned int len) 🌈

same energy, opposite direction: a wrapper around recv() that makes sure all len bytes of data are received from the daemon. again, poll() blocks until the whole message is in πŸ’–

returns 0 on success, -1 if the recv failed due to a timeout or socket error.


⭐ int g15_send_cmd ( int sock, unsigned char command, unsigned char value) ⭐

sends a command to the daemon (all the possible commands are listed right below, don't scroll past them πŸ‘€).

returns 0 or the return value of the command on success, and -1 on failure.

see examples for usage.


πŸ‘‘ G15Daemon Command Types πŸ‘‘

commands and requests to the daemon are sent via OOB data packets. heads up: changes to the backlight and mkey state only affect the calling client β€” nobody else's screen is catching strays πŸ’…

the following commands are supported as defined in g15daemon_client.h:

G15DAEMON_KEY_HANDLER

requests that all M and G key presses get sent to this client. all the keys are packed into an unsigned int, and sent to the client inband when a key is pressed. main character privileges, honestly πŸ‘‘

G15DAEMON_MKEYLEDS

sets the M key LED state. to change LED state, each LED that's supposed to be turned on gets OR'd with the command byte. see libg15.h for values. for examples see the end of this document ✨

G15DAEMON_BACKLIGHT

sets the LCD Backlight brightness. the brightness level (0|1|2) is OR'd with the command byte. for examples see the end of this document 🌸

G15DAEMON_CONTRAST

sets the LCD contrast. the contrast level (0|1|2) is OR'd with the command byte. for examples see the end of this document πŸ’œ

G15DAEMON_GET_KEYSTATE

requests a packet containing the current keystate. the daemon will return an unsigned int containing any keys pressed. see libg15.h for details on key values, and lcdclient_test.c in the source distribution for an example πŸ‘€

G15DAEMON_SWITCH_PRIORITIES

toggles the client's LCD screen to/from the front. clients can check their foreground/background state with the following:

G15DAEMON_IS_FOREGROUND

on receipt of this command, G15Daemon will send a 1 byte packet back with the value 1 if the client is foreground, or 0 if not. simple as πŸŽ€

G15DAEMON_IS_USER_SELECTED

on receipt of this command, G15daemon will return a byte indicating if the user selected the client be foreground or background. (yes, the user is the one deciding your fate, not the daemon πŸ™ˆ)


πŸ“ EXAMPLES πŸ“

below is a completely nonsensical client which (poorly) demonstrates the usage of most of the commands. it's not good. it is educational. both things are true πŸ’€

--- Cut here ---

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <poll.h>
#include <g15daemon_client.h>
#include <libg15.h>

/* #define TEST_KEYHANDLER */

int main(int argc, char *argv[]) {
    int g15screen_fd, retval;
    char lcdbuffer[6880];
    unsigned int keystate;
    char msgbuf[256];
    int foo = 0;

    if((g15screen_fd = new_g15_screen(G15_PIXELBUF))<0){
        printf("Sorry, cant connect to the G15daemon0);
        return 5;
    }else
        printf("Connected to g15daemon.  sending image0);

        if(argc<2)
            retval = g15_send(g15screen_fd,(char*)logo_data,6880);
        else {
            memset(lcdbuffer,0,6880);
            memset(lcdbuffer,1,6880/2);
            retval = g15_send(g15screen_fd,(char*)lcdbuffer,6880);
        }

        printf("checking key status - press G1 to exit0,retval);

        while(1){
            keystate = 0;
            int foo;

            keystate = g15_send_cmd (g15screen_fd,
G15DAEMON_GET_KEYSTATE, foo);
            if(keystate)
                printf("keystate = %i0,keystate);

            if(keystate & G15_KEY_G1) //G1 key.  See libg15.h for
details on key values.
                break;

            /* G2,G3 & G4 change LCD backlight */
            if(keystate & G15_KEY_G2){
                retval = g15_send_cmd (g15screen_fd,
G15DAEMON_BACKLIGHT, G15_BRIGHTNESS_DARK);
            }
            if(keystate & G15_KEY_G3){
                retval = g15_send_cmd (g15screen_fd,
G15DAEMON_BACKLIGHT, G15_BRIGHTNESS_MEDIUM);
            }
            if(keystate & G15_KEY_G4){
                retval = g15_send_cmd (g15screen_fd,
G15DAEMON_BACKLIGHT, G15_BRIGHTNESS_BRIGHT);
            }

            /* is this client in the foreground?? */
            retval = g15_send_cmd (g15screen_fd,
G15DAEMON_IS_FOREGROUND, foo);

            if(retval)
              printf("Hey, we are in the foreground, Doc0);
            else
              printf("What dastardly wabbit put me in the background?0);

            retval = g15_send_cmd (g15screen_fd,
G15DAEMON_IS_USER_SELECTED, foo);
            if(retval)
              printf("You wanted me in the foreground, right Doc?0);
            else
              printf("You dastardly wabbit !0);

            if(retval){ /* we've been backgrounded! */
                sleep(2); /* remain in the background for a bit */
                retval = g15_send_cmd (g15screen_fd,
G15DAEMON_SWITCH_PRIORITIES, foo);
                sleep(2); /* switch to foreground */
                retval = g15_send_cmd (g15screen_fd,
G15DAEMON_SWITCH_PRIORITIES, foo);
            }

            usleep(500); #ifdef TEST_KEYHANDLER
            /* ok.. request that all G&M keys are passed to us.. */
            retval = g15_send_cmd (g15screen_fd, G15DAEMON_KEY_HANDLER,
foo);

            while(1){
                printf("waiting on keystate0);
                keystate=0;
                retval = recv(g15screen_fd, &keystate ,
sizeof(keystate),0);
                if(keystate)
                  printf("Recieved %i as keystate",keystate);
            } #endif
        }
        g15_close_screen(g15screen_fd);
        return 0; }

--- end cutting ---

and that's the whole page bestie πŸ’– this one comes from G15Daemon, version 1.0, and the date slot is literally just G15daemon Client Development() β€” which is a whole vibe. go forth and talk to your daemon, you're gonna slay βœ¨πŸŽ€πŸ¦‹