17. Norns

Norns hookup into the monolith struct. Only works with MONOLITH_NORNS macro defined.

17.1. Top Level Constructs

Functions, forward declarations, and struct contents are all conditinally included with the macro MONOLITH_NORNS. To make this easier, special named blocks have been made around these elements.

<<functions>>=
#ifdef MONOLITH_NORNS
<<norns_functions>>
#endif

The <> keyword is used because we only want these functions to be visible in this generated C file.

<<aux_includes>>=
#ifdef MONOLITH_NORNS
<<norns_function_declarations>>
#endif
<<struct_contents>>=
#ifdef MONOLITH_NORNS
<<norns_struct_contents>>
#endif
<<init>>=
#ifdef MONOLITH_NORNS
<<norns_init>>
#endif
<<cleanup>>=
#ifdef MONOLITH_NORNS
<<norns_cleanup>>
#endif
<<core_janet_entries>>=
#ifdef MONOLITH_NORNS
<<norns_janet_entries>>
#endif
<<janet_functions>>=
#ifdef MONOLITH_NORNS
<<norns_janet_functions>>
#endif

17.2. TODO Monolith Drawing Thread

Monolith has a single instance of drawing thread stored inside of the monolith data.

17.2.1. TODO Running flag

A flag is used to store whether or not the drawing thread has been allocated + started. When monolith first initializes, it is set to be false (0).

17.2.2. TODO Drawing Thread Data in Struct

Note that this is only included if MONOLITH_NORNS is enabled.

The drawing thread data is set to be NULL by default, to indicate that nothing has been allocated + initialized.

<<norns_struct_contents>>=
norns_drawthread *ndt;
<<norns_init>>=
m->ndt = NULL;

17.2.3. TODO Opening + Allocating the framebuffer

This opens + allocates the framebuffer data, without starting the drawing thread. This also includes allocating data needed for the drawing thread as well.

17.2.3.1. In C (via monolith_norns_gfx_init)

<<norns_function_declarations>>=
void monolith_norns_gfx_init(monolith_d *m);
<<norns_functions>>=
void monolith_norns_gfx_init(monolith_d *m)
{
    if (m->ndt != NULL) return;

    norns_drawthread_new(&m->ndt);
    norns_drawthread_init(m->ndt);
}
17.2.3.2. In Janet (via monolith/norns-gfx-init)

<<core_janet_entries>>=
#ifdef MONOLITH_NORNS
{
"monolith/norns-gfx-init",
j_norns_gfx_init,
"Initialize/open, but do not start, norns graphics thread."
},
#endif
<<janet_functions>>=
#ifdef MONOLITH_NORNS
static Janet j_norns_gfx_init(int32_t argc, Janet *argv)
{
    monolith_d *m;
    janet_fixarity(argc, 0);
    m = monolith_data_get();
    monolith_norns_gfx_init(m);
    return janet_wrap_nil();
}
#endif

17.2.4. TODO Starting the thread (user-level)

This will actually start the thread and allocate data for it, if it has not been done already.

17.2.4.1. TODO From Scheme

17.2.4.2. TODO From Janet

17.2.5. TODO Drawing Thread at Cleanup

The thread stop callback is called at cleanup, whether or not the thread has actually been started.

<<norns_function_declarations>>=
void monolith_norns_gfx_clean(monolith_d *m);
<<norns_functions>>=
void monolith_norns_gfx_clean(monolith_d *m)
{
    norns_drawthread *ndt;

    if (m->ndt == NULL) return;
    ndt = m->ndt;
    m->ndt = NULL;
    norns_drawthread_clean(ndt);
    norns_drawthread_del(&ndt);
}

17.2.6. DONE Getting the buffers

CLOSED: [2019-11-22 Fri 20:07] This is used to get the internal video + frame buffers.

This is useful for situations where interacting with the framebuffer directly is better than trying to use the drawing thread.

Getting the video buffer allows for certain norns drawing operations to be used directly, instead of having to write a bunch of wrapper functions around it.

<<norns_function_declarations>>=
norns_framebuffer * monolith_norns_framebuffer(monolith_d *m);
norns_videobuf * monolith_norns_videobuf(monolith_d *m);
<<norns_functions>>=
norns_framebuffer * monolith_norns_framebuffer(monolith_d *m)
{
    if (m->ndt == NULL) return NULL;
    return norns_drawthread_framebuffer(m->ndt);
}

norns_videobuf * monolith_norns_videobuf(monolith_d *m)
{
    if (m->ndt == NULL) return NULL;
    return norns_drawthread_videobuf(m->ndt);
}

17.2.7. TODO Updating the display (via the drawing thread)

Any time a change is made in the video buffer, it must be updated to the frame buffer. This function will send a message to update it in the drawing thread.

<<norns_function_declarations>>=
void monolith_norns_draw(monolith_d *m);
<<norns_functions>>=
void monolith_norns_draw(monolith_d *m)
{
    norns_framebuffer *fb;
    norns_videobuf *vb;
    if (m->ndt == NULL) return;

    fb = norns_drawthread_framebuffer(m->ndt);
    vb = norns_drawthread_videobuf(m->ndt);

    norns_videobuf_copy(vb, fb);
}

17.3. Monolith Norns Event Polling

Event polling from monolith.

17.3.1. Event polling struct declaration

<<norns_struct_contents>>=
norns_poll_d *norns_poll;
<<norns_init>>=
m->norns_poll = NULL;

17.3.2. Setup + Start the norns listener

17.3.2.1. norns listener setup in C

The function monolith_norns_setup is used to setup and start polling.

<<norns_function_declarations>>=
void monolith_norns_setup(monolith_d *m);
<<norns_functions>>=
void monolith_norns_setup(monolith_d *m)
{
    norns_poll_d *poll;
    if (m->norns_poll != NULL) return;
    norns_poll_new(&poll);
    norns_poll_init(poll);
    m->norns_poll = poll;
}
17.3.2.2. norns listener setup in Janet

<<core_janet_entries>>=
#ifdef MONOLITH_NORNS
{
"monolith/norns-setup",
j_norns_setup,
"Starts norns listener."
},
#endif
<<janet_functions>>=
#ifdef MONOLITH_NORNS
static Janet j_norns_setup(int32_t argc, Janet *argv)
{
    monolith_d *m;
    janet_fixarity(argc, 0);
    m = monolith_data_get();
    monolith_norns_setup(m);
    return janet_wrap_nil();
}
#endif

17.3.3. Stop + Clean the norns listener

The function monolith_norns_clean will stop and clean up the listener.

<<norns_function_declarations>>=
void monolith_norns_clean(monolith_d *m);

Note that norns_poll is set to be NULL before it is freed, in case the event loop is still running.

<<norns_functions>>=
void monolith_norns_clean(monolith_d *m)
{
    norns_poll_d *poll;
    if (m->norns_poll != NULL) {
        poll = m->norns_poll;
        m->norns_poll = NULL;
        norns_poll_del(&poll);
    }
}

It is called in the top-level monolith cleanup function, even if the norns listener has not been started.

<<norns_cleanup>>=
monolith_norns_clean(m);

17.3.4. Setting peripheral callbacks

Any time a knob or key event happens, a user-supplied callback can happen. These functions are inteded to be used by any monolith pages wishing to extend their functionality onto the norns. These callbacks should be assigned when a page is opened.

Since norns callbacks are not part of the main page interface, this means that they can persist between page selections if the new page does not utilize them. This is a delibrate design decision.

In practice, it is highly recommend to leave key 1 (top left) alone. This should be reserved for a "return to main menu" button.

17.3.4.1. Setting Buttons

<<norns_function_declarations>>=
void monolith_norns_key(monolith_d *m,
                        int key,
                        void (*fun)(void *, int),
                        void *ud);
<<norns_functions>>=
void monolith_norns_key(monolith_d *m,
                        int key,
                        void (*fun)(void *, int),
                        void *ud)
{
    if (m->norns_poll == NULL) return;
    norns_poll_cb_key(m->norns_poll, key, fun, ud);
}
17.3.4.2. Setting Knobs

<<norns_function_declarations>>=
void monolith_norns_knob(monolith_d *m,
                         int knob,
                         void (*fun)(void *, int),
                         void *ud);
<<norns_functions>>=
void monolith_norns_knob(monolith_d *m,
                         int key,
                         void (*fun)(void *, int),
                         void *ud)
{
    if (m->norns_poll == NULL) return;
    norns_poll_cb_knob(m->norns_poll, key, fun, ud);
}

17.3.5. Norns polling in the main event loop

Norns gets polled inside the main event loop thread with Only if MONOLITH_NORNS is enabled.

<<poll_the_norns>>=
#ifdef MONOLITH_NORNS
if (m->norns_poll != NULL) {
    norns_poll(m->norns_poll);
}
#endif

17.3.6. Getting the poll data

<<norns_function_declarations>>=
norns_poll_d * monolith_norns_poll(monolith_d *m);
<<norns_functions>>=
norns_poll_d * monolith_norns_poll(monolith_d *m)
{
    return m->norns_poll;
}

17.4. Simple Loop

A quick and simple event loop, to get some simple standalone monolith programs working.

This will start a blocking loop that polls for the top left norns button. When pressed, the device will power off.

17.4.1. C Function (monolith_norns_simpleloop)

<<norns_function_declarations>>=
void monolith_norns_simpleloop(monolith_d *m);
<<norns_functions>>=
void monolith_norns_simpleloop(monolith_d *m)
{
    int fid;
    int rc;
    struct input_event evt[8];
    int nevts;
    int e;
    int running;
    int poweroff;
    norns_framebuffer *fb;
    norns_videobuf *vb;

    running = 1;
    poweroff = 0;
    fid = norns_open_keys();

    norns_framebuffer_new(&fb);
    norns_framebuffer_open(fb);
    norns_videobuf_new(&vb);
    norns_videobuf_init(vb);

    norns_draw_string(vb, 63 - (4*8), 28, 0xff, 0x00, "monolith");
    norns_videobuf_copy(vb, fb);

    while(running) {
        rc = read(fid, evt, sizeof(struct input_event) * 8);
        if(rc != -1) {
            nevts = rc / sizeof(struct input_event);
            for(e = 0; e < nevts; e++) {
                if(evt[e].type) {
                    if (evt[e].code == 1 && evt[e].value == 1) {
                        running = 0;
                        poweroff = 1;
                    } else if (evt[e].code == 2 && evt[e].value == 1) {
                        running = 0;
                    }
                    fflush(stdout);
                }
            }
        }
        usleep(10);
    }

    norns_videobuf_clear(vb);

    if (poweroff) {
        norns_draw_string(vb, 63 - (8*2), 28, 0x20, 0x00, "bye.");
    } else {
        norns_draw_string(vb, 63 - (4*5), 28, 0x20, 0x00, "quit.");
    }

    norns_videobuf_copy(vb, fb);

    close(fid);
    norns_framebuffer_close(fb);
    norns_framebuffer_del(&fb);
    norns_videobuf_del(&vb);

    if (poweroff) {
        system("poweroff");
    }
}

17.4.2. Janet Function (monolith/norns-simpleloop)

<<norns_janet_entries>>=
{
"monolith/norns-simpleloop",
norns_simpleloop,
"A simple event loop for the norns"
},
<<norns_janet_functions>>=
static Janet norns_simpleloop(int32_t argc, Janet *argv)
{
    janet_fixarity(argc, 0);
    monolith_norns_simpleloop(monolith_data_get());
    return janet_wrap_nil();
}

17.5. Norns Wait + Quit

For standalone apps.

<<norns_struct_contents>>=
int norns_running;
<<norns_init>>=
m->norns_running = 1;
<<norns_function_declarations>>=
void monolith_norns_wait(monolith_d *m);
<<norns_functions>>=
void monolith_norns_wait(monolith_d *m)
{
    while (m->norns_running) {
        sleep(1);
    }
}
<<norns_function_declarations>>=
void monolith_norns_quit(monolith_d *m);
<<norns_functions>>=
void monolith_norns_quit(monolith_d *m)
{
    m->norns_running = 0;
}
<<norns_janet_entries>>=
{
"monolith/norns-wait",
norns_wait,
"Wait to quit or poweroff."
},
<<norns_janet_functions>>=
static Janet norns_wait(int32_t argc, Janet *argv)
{
    janet_fixarity(argc, 0);
    monolith_norns_wait(monolith_data_get());
    return janet_wrap_nil();
}



prev | home | next