├── Makefile ├── README.md ├── audio.c ├── button.c ├── demo.c ├── fbtest.c ├── font.png ├── font.xbm ├── input_monitor.c ├── kill_stuff.sh ├── knob.c ├── menu.c └── text.c /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -pedantic -std=c89 -O2 2 | 3 | # Needed to remove usleep warning 4 | # (this warning because the compiler is enforcing ANSI C) 5 | CFLAGS += -D_GNU_SOURCE 6 | 7 | CC=arm-linux-gnueabihf-gcc 8 | 9 | default: fbtest knob button input_monitor demo audio text menu 10 | 11 | fbtest: fbtest.c 12 | $(CC) $(CFLAGS) $< -o $@ 13 | 14 | knob: knob.c 15 | $(CC) $(CFLAGS) $< -o $@ 16 | 17 | button: button.c 18 | $(CC) $(CFLAGS) $< -o $@ 19 | 20 | input_monitor: input_monitor.c 21 | $(CC) $(CFLAGS) $< -o $@ 22 | 23 | demo: demo.c 24 | $(CC) -Inorns/include $< -o $@ -ljack -lpthread -lm 25 | 26 | audio: audio.c 27 | $(CC) -Inorns/include $< -o $@ -Lnorns/lib -ljack 28 | 29 | text: text.c 30 | $(CC) $(CFLAGS) $< -o $@ 31 | 32 | clean: 33 | $(RM) fbtest 34 | $(RM) knob 35 | $(RM) button 36 | $(RM) input_monitor 37 | $(RM) demo 38 | $(RM) audio 39 | $(RM) text 40 | 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Low Level Norns 2 | 3 | Some small snippets of C code that do relatively low-level 4 | things on the norns. 5 | 6 | ## Setup 7 | 8 | You will need to be able to enter a norns shell, either 9 | through SSH or serial. An internet connection is helpful, 10 | but not necessarily needed. 11 | 12 | Clone this repository onto your norns. 13 | 14 | Compile things with `make`. 15 | 16 | Temporarily disable default norns stuff by running 17 | `sh kill_stuff.sh`. This stops supercollider, matron, 18 | and crone. Rebooting the machine will restart these 19 | for you. I do this by running `poweroff`, then manually 20 | powering on the device. 21 | 22 | The programs available are as follows: 23 | * audio.c: simple JACK client example, audio stops on key press 24 | * button.c: button handling example 25 | * fbtest.c: uses the framebuffer to print a smiley face to norns screen 26 | * input_monitor: watches for button/encoder input and prints to console when detected 27 | * knob.c: similar to button.c, but uses the encoders 28 | 29 | Run one with `./(program name)`, replacing (program name) with your target program. Press Ctrl-C to stop it. 30 | -------------------------------------------------------------------------------- /audio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static int jack_process(jack_nframes_t nframes, void *arg); 6 | 7 | jack_port_t *out[2]; 8 | jack_client_t *client; 9 | 10 | 11 | static int jack_process(jack_nframes_t nframes, void *arg) 12 | { 13 | jack_default_audio_sample_t *o[2]; 14 | int n; 15 | float smp; 16 | 17 | o[0] = (jack_default_audio_sample_t*)jack_port_get_buffer(out[0], nframes); 18 | o[1] = (jack_default_audio_sample_t*)jack_port_get_buffer(out[1], nframes); 19 | 20 | for (n = 0; n < nframes; n++) { 21 | smp = (float)rand() / RAND_MAX; 22 | smp = (2 * smp) - 1; 23 | o[0][n] = smp; 24 | o[1][n] = smp; 25 | } 26 | 27 | return 0; 28 | } 29 | 30 | void audio_start(void) 31 | { 32 | const char **ports; 33 | const char *client_name; 34 | const char *server_name; 35 | jack_options_t options; 36 | jack_status_t status; 37 | 38 | if (client != NULL) { 39 | fprintf(stderr, "JACK audio server seems to be started already\n"); 40 | return; 41 | } 42 | 43 | options = JackNullOption; 44 | 45 | server_name=NULL; 46 | client_name="Monolith"; /* set the client name */ 47 | 48 | client = jack_client_open(client_name, options, &status, server_name); 49 | 50 | if (client == NULL) { 51 | fprintf(stderr, "JACK has failed you.\n"); 52 | if (status & JackServerFailed) { 53 | fprintf (stderr, "It was unable to connect to the JACK server\n"); 54 | } 55 | return; 56 | } 57 | 58 | if (status & JackServerStarted) { 59 | fprintf(stderr, "JACK server started\n"); 60 | } 61 | 62 | if (status & JackNameNotUnique) { 63 | client_name = jack_get_client_name(client); 64 | fprintf(stderr, "unique name `%s' assigned\n", client_name); 65 | } 66 | 67 | jack_set_process_callback (client, jack_process, NULL); 68 | 69 | out[0] = jack_port_register(client, "output1", 70 | JACK_DEFAULT_AUDIO_TYPE, 71 | JackPortIsOutput, 0); 72 | out[1] = jack_port_register (client, "output2", 73 | JACK_DEFAULT_AUDIO_TYPE, 74 | JackPortIsOutput, 0); 75 | 76 | if ((out[0] == NULL) || (out[1] == NULL)) { 77 | fprintf(stderr, "no more JACK ports available\n"); 78 | return; 79 | } 80 | 81 | if (jack_activate(client)) { 82 | fprintf(stderr, "cannot activate client\n"); 83 | return; 84 | } 85 | 86 | ports = jack_get_ports (client, NULL, NULL, 87 | JackPortIsPhysical|JackPortIsInput); 88 | 89 | if (ports == NULL) { 90 | fprintf(stderr, "no physical playback ports\n"); 91 | return; 92 | } 93 | 94 | if (jack_connect(client, jack_port_name(out[0]), ports[0])) { 95 | fprintf (stderr, "cannot connect output ports\n"); 96 | } 97 | 98 | if (jack_connect(client, jack_port_name(out[1]), ports[1])) { 99 | fprintf (stderr, "cannot connect output ports\n"); 100 | } 101 | 102 | jack_free (ports); 103 | } 104 | 105 | void audio_stop(void) 106 | { 107 | if (client != NULL) { 108 | jack_client_close (client); 109 | client = NULL; 110 | } 111 | } 112 | 113 | int main(int argc, char *argv[]) 114 | { 115 | out[0] = NULL; 116 | out[1] = NULL; 117 | client = NULL; 118 | audio_start(); 119 | printf("Hit any key to stop.\n"); 120 | fgetc(stdin); 121 | audio_stop(); 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /button.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int running = 1; 12 | 13 | void quit(int sig) 14 | { 15 | printf("Closing.\n"); 16 | running = 0; 17 | } 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | int fid; 22 | int rc; 23 | struct input_event evt[8]; 24 | int nevts; 25 | int e; 26 | 27 | 28 | signal(SIGINT, quit); 29 | 30 | fid = open( 31 | "/dev/input/by-path/platform-keys-event", 32 | O_RDONLY | O_NONBLOCK); 33 | 34 | 35 | running = 1; 36 | 37 | while (running) { 38 | rc = read(fid, evt, sizeof(struct input_event) * 8); 39 | if (rc != -1) { 40 | nevts = rc / sizeof(struct input_event); 41 | for (e = 0; e < nevts; e++) { 42 | if (evt[e].type) { 43 | fprintf(stdout, 44 | "%d %d\n", 45 | evt[e].code, 46 | evt[e].value); 47 | fflush(stdout); 48 | } 49 | } 50 | } 51 | usleep(10); 52 | } 53 | 54 | close(fid); 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /demo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | int running = 1; 21 | 22 | typedef struct { 23 | int fbfd; 24 | struct fb_var_screeninfo vinfo; 25 | struct fb_fix_screeninfo finfo; 26 | long int screensize; 27 | char *fbp; 28 | unsigned char *buf; 29 | } framebuffer; 30 | 31 | #define BUFSIZE 62 32 | 33 | typedef struct { 34 | framebuffer fb; 35 | float vals[3]; 36 | int please_draw; 37 | jack_port_t *out[2]; 38 | jack_client_t *client; 39 | float lphs; 40 | int sr; 41 | int counter; 42 | int subcount; 43 | float buf[4096]; 44 | int mute; 45 | } main_data; 46 | 47 | void quit(int sig) 48 | { 49 | printf("Closing.\n"); 50 | running = 0; 51 | } 52 | 53 | int open_knob(int knob) 54 | { 55 | char path[256]; 56 | sprintf(path, 57 | "/dev/input/by-path/platform-soc:knob%d-event", 58 | knob); 59 | return open(path, O_RDONLY | O_NONBLOCK); 60 | } 61 | 62 | int open_buttons(void) 63 | { 64 | return open( 65 | "/dev/input/by-path/platform-keys-event", 66 | O_RDONLY | O_NONBLOCK); 67 | } 68 | 69 | void pixel(framebuffer *fb, 70 | int x, 71 | int y, 72 | unsigned char val) 73 | { 74 | long int loc; 75 | if(x >= fb->vinfo.xres || y >= fb->vinfo.yres) return; 76 | 77 | loc = x + y * fb->vinfo.xres; 78 | fb->buf[loc] = val; 79 | 80 | } 81 | 82 | void copy_to_fb(framebuffer *fb) 83 | { 84 | long int location; 85 | int x, y; 86 | unsigned char val; 87 | int w, h; 88 | 89 | h = fb->vinfo.yres; 90 | w = fb->vinfo.xres; 91 | for (y = 0; y < h; y++) { 92 | for (x = 0; x < w; x++) { 93 | location = (x + fb->vinfo.xoffset) * 94 | (fb->vinfo.bits_per_pixel/8) + 95 | (y + fb->vinfo.yoffset) * fb->finfo.line_length; 96 | val = fb->buf[x + y * w]; 97 | fb->fbp[location] = 0x0; 98 | fb->fbp[location + 1] = val; 99 | } 100 | } 101 | } 102 | 103 | void clearscreen(framebuffer *fb) 104 | { 105 | int x, y; 106 | 107 | for (y = 0; y < fb->vinfo.yres; y++) { 108 | for(x = 0; x < fb->vinfo.xres; x++) { 109 | pixel(fb, x, y, 0); 110 | } 111 | } 112 | } 113 | 114 | void vslider(framebuffer *fb, int x, int y, float val) 115 | { 116 | float w; 117 | float h; 118 | int p1, p2; 119 | int n, k; 120 | int nlines; 121 | 122 | w = 8; 123 | h = 32; 124 | 125 | 126 | for (n = 0; n < w; n++) { 127 | pixel(fb, x + n, y, 255); 128 | } 129 | 130 | p1 = y + h - 1; 131 | for (n = 0; n < w; n++) { 132 | pixel(fb, x + n, p1, 255); 133 | } 134 | 135 | for (n = 0; n < h; n++) { 136 | pixel(fb, x, y + n, 255); 137 | } 138 | 139 | p1 = x + w - 1; 140 | for (n = 0; n < h; n++) { 141 | pixel(fb, p1, y + n, 255); 142 | } 143 | 144 | /* draw value */ 145 | 146 | nlines = round(val * 28); 147 | for (k = 0; k < nlines; k++) { 148 | for (n = 0; n < (w - 4); n++) { 149 | pixel(fb, x + 2 + n, (y + (h - k) - 3), 255); 150 | } 151 | } 152 | 153 | } 154 | 155 | void wavedisplay(framebuffer *fb, float *buf, int size) 156 | { 157 | float x, y; 158 | float w, h; 159 | int n; 160 | float val; 161 | int pos; 162 | int jmp; 163 | 164 | x = 48; 165 | y = 24; 166 | 167 | w = 64; 168 | h = 32; 169 | 170 | for (n = 0; n < w; n++) { 171 | pixel(fb, x+n, y, 255); 172 | } 173 | 174 | for (n = 0; n < w; n++) { 175 | pixel(fb, x+n, y + h - 1, 255); 176 | } 177 | 178 | for (n = 0; n < h; n++) { 179 | pixel(fb, x, y + n, 255); 180 | } 181 | 182 | for (n = 0; n < h; n++) { 183 | pixel(fb, x + w - 1, y + n, 255); 184 | } 185 | 186 | for (n = 0; n < 62; n++) { 187 | val = buf[n]; 188 | val = 1 - ((val + 1) * 0.5); 189 | pos = floor(val * 30); 190 | pixel(fb, x + 1 + n, y + pos, 255); 191 | } 192 | } 193 | 194 | void* draw(void *data) 195 | { 196 | framebuffer *fb; 197 | main_data *m; 198 | int draw; 199 | 200 | m = data; 201 | fb = &m->fb; 202 | 203 | clearscreen(fb); 204 | while (running) { 205 | draw = m->please_draw; 206 | 207 | if(draw) { 208 | clearscreen(fb); 209 | vslider(fb, 16, 24, m->vals[0]); 210 | vslider(fb, 24, 24, m->vals[1]); 211 | vslider(fb, 32, 24, m->vals[2]); 212 | wavedisplay(fb, m->buf, 4096); 213 | m->please_draw = 0; 214 | copy_to_fb(fb); 215 | } 216 | usleep(800); 217 | } 218 | 219 | fprintf(stderr, "quitting\n"); 220 | pthread_exit(NULL); 221 | } 222 | 223 | int fb_setup(framebuffer *fb) 224 | { 225 | int rc; 226 | 227 | fb->fbfd = open("/dev/fb0", O_RDWR); 228 | if (fb->fbfd == -1) { 229 | perror("Error: cannot open framebuffer device"); 230 | return 1; 231 | } 232 | 233 | rc = ioctl(fb->fbfd, FBIOGET_FSCREENINFO, &fb->finfo); 234 | 235 | if (rc == -1) { 236 | perror("Error reading fixed information"); 237 | return 2; 238 | } 239 | 240 | rc = ioctl(fb->fbfd, FBIOGET_VSCREENINFO, &fb->vinfo); 241 | 242 | if (rc == -1) { 243 | perror("Error reading variable information"); 244 | return 3; 245 | } 246 | 247 | fb->screensize = fb->vinfo.xres * 248 | fb->vinfo.yres * 249 | fb->vinfo.bits_per_pixel / 8; 250 | 251 | fb->fbp = (char *)mmap(0, 252 | fb->screensize, 253 | PROT_READ | PROT_WRITE, 254 | MAP_SHARED, 255 | fb->fbfd, 256 | 0); 257 | 258 | fb->buf = calloc(1, fb->vinfo.xres * fb->vinfo.xres); 259 | if ((int)fb->fbp == -1) { 260 | return 4; 261 | } 262 | 263 | return 0; 264 | } 265 | 266 | void fb_cleanup(framebuffer *fb) 267 | { 268 | munmap(fb->fbp, fb->screensize); 269 | close(fb->fbfd); 270 | free(fb->buf); 271 | } 272 | 273 | static int jack_process(jack_nframes_t nframes, void *arg); 274 | 275 | 276 | 277 | static int jack_process(jack_nframes_t nframes, void *arg) 278 | { 279 | jack_default_audio_sample_t *o[2]; 280 | int n; 281 | float smp; 282 | float frq; 283 | main_data *m; 284 | float gate; 285 | 286 | jack_port_t **out; 287 | jack_client_t *client; 288 | 289 | m = arg; 290 | out = m->out; 291 | client = m->client; 292 | 293 | o[0] = (jack_default_audio_sample_t*)jack_port_get_buffer(out[0], nframes); 294 | o[1] = (jack_default_audio_sample_t*)jack_port_get_buffer(out[1], nframes); 295 | 296 | gate = m->mute == 0; 297 | for (n = 0; n < nframes; n++) { 298 | smp = sin(m->lphs); 299 | smp *= m->vals[0] * gate; 300 | o[0][n] = smp; 301 | o[1][n] = smp; 302 | frq = 200 + 2000 * m->vals[1]; 303 | m->lphs += (float)frq * ((2.0 * M_PI) / m->sr); 304 | m->lphs = fmod(m->lphs, 2.0 * M_PI); 305 | 306 | if (m->subcount == 0) { 307 | m->buf[m->counter] = smp; 308 | } 309 | 310 | m->counter++; 311 | 312 | if (m->counter >= BUFSIZE) { 313 | m->counter = 0; 314 | if (m->subcount == 0) m->please_draw = 1; 315 | m->subcount = (m->subcount + 1) % 8; 316 | } 317 | } 318 | 319 | return 0; 320 | } 321 | 322 | void audio_start(main_data *m) 323 | { 324 | const char **ports; 325 | const char *client_name; 326 | const char *server_name; 327 | jack_options_t options; 328 | jack_status_t status; 329 | 330 | jack_port_t **out; 331 | jack_client_t *client; 332 | 333 | out = m->out; 334 | client = m->client; 335 | 336 | if (client != NULL) { 337 | fprintf(stderr, "JACK audio server seems to be started already\n"); 338 | return; 339 | } 340 | 341 | options = JackNullOption; 342 | 343 | server_name=NULL; 344 | client_name="Monolith"; /* set the client name */ 345 | 346 | client = jack_client_open(client_name, options, &status, server_name); 347 | 348 | if (client == NULL) { 349 | fprintf(stderr, "JACK has failed you.\n"); 350 | if (status & JackServerFailed) { 351 | fprintf (stderr, "It was unable to connect to the JACK server\n"); 352 | } 353 | return; 354 | } 355 | 356 | if (status & JackServerStarted) { 357 | fprintf(stderr, "JACK server started\n"); 358 | } 359 | 360 | if (status & JackNameNotUnique) { 361 | client_name = jack_get_client_name(client); 362 | fprintf(stderr, "unique name `%s' assigned\n", client_name); 363 | } 364 | 365 | jack_set_process_callback (client, jack_process, m); 366 | 367 | out[0] = jack_port_register(client, "output1", 368 | JACK_DEFAULT_AUDIO_TYPE, 369 | JackPortIsOutput, 0); 370 | out[1] = jack_port_register (client, "output2", 371 | JACK_DEFAULT_AUDIO_TYPE, 372 | JackPortIsOutput, 0); 373 | 374 | if ((out[0] == NULL) || (out[1] == NULL)) { 375 | fprintf(stderr, "no more JACK ports available\n"); 376 | return; 377 | } 378 | 379 | if (jack_activate(client)) { 380 | fprintf(stderr, "cannot activate client\n"); 381 | return; 382 | } 383 | 384 | ports = jack_get_ports (client, NULL, NULL, 385 | JackPortIsPhysical|JackPortIsInput); 386 | 387 | if (ports == NULL) { 388 | fprintf(stderr, "no physical playback ports\n"); 389 | return; 390 | } 391 | 392 | if (jack_connect(client, jack_port_name(out[0]), ports[0])) { 393 | fprintf (stderr, "cannot connect output ports\n"); 394 | } 395 | 396 | if (jack_connect(client, jack_port_name(out[1]), ports[1])) { 397 | fprintf (stderr, "cannot connect output ports\n"); 398 | } 399 | 400 | jack_free (ports); 401 | } 402 | 403 | void audio_stop(main_data *m) 404 | { 405 | if(m->client != NULL) { 406 | jack_client_close (m->client); 407 | m->client = NULL; 408 | } 409 | } 410 | 411 | int main(int argc, char *argv[]) 412 | { 413 | int fid[3]; 414 | int bfid; 415 | int rc; 416 | struct input_event evt[8]; 417 | int nevts; 418 | int e; 419 | int k; 420 | pthread_t draw_thread; 421 | main_data m; 422 | int pd; 423 | float tmp; 424 | int val; 425 | int code; 426 | int please_poweroff; 427 | 428 | signal(SIGINT, quit); 429 | 430 | fb_setup(&m.fb); 431 | 432 | for (k = 0; k < 3; k++) { 433 | fid[k] = open_knob(k + 1); 434 | m.vals[k] = 0; 435 | } 436 | bfid = open_buttons(); 437 | 438 | running = 1; 439 | 440 | pthread_create(&draw_thread, NULL, draw, &m); 441 | m.client = NULL; 442 | m.lphs = 0; 443 | m.counter = 0; 444 | m.subcount = 0; 445 | m.sr = 44100; /* TODO: make this dynamic */ 446 | m.mute = 0; 447 | please_poweroff = 0; 448 | audio_start(&m); 449 | 450 | while (running) { 451 | pd = 0; 452 | for (k = 0; k < 3; k++) { 453 | rc = read(fid[k], 454 | evt, 455 | sizeof(struct input_event) * 8); 456 | 457 | if (rc != -1) { 458 | nevts = rc / sizeof(struct input_event); 459 | pd = 1; 460 | for (e = 0; e < nevts; e++) { 461 | if (evt[e].type) { 462 | /* fprintf(stderr, "%d: %d\n", k, evt[e].value); */ 463 | tmp = m.vals[k]; 464 | tmp += evt[e].value * 0.01; 465 | if (tmp < 0) tmp = 0; 466 | if (tmp > 1) tmp = 1; 467 | m.vals[k] = tmp; 468 | } 469 | } 470 | } 471 | } 472 | rc = read(bfid, evt, sizeof(struct input_event) * 8); 473 | if (rc != -1) { 474 | nevts = rc / sizeof(struct input_event); 475 | for (e = 0; e < nevts; e++) { 476 | if (evt[e].type) { 477 | fprintf(stdout, 478 | "%d %d\n", 479 | evt[e].code, 480 | evt[e].value); 481 | fflush(stdout); 482 | 483 | val = evt[e].value; 484 | code = evt[e].code; 485 | switch (code) { 486 | case 1: 487 | quit(0); 488 | please_poweroff = 1; 489 | break; 490 | case 2: 491 | m.mute = val == 1; 492 | break; 493 | case 3: 494 | break; 495 | } 496 | } 497 | } 498 | } 499 | m.please_draw = pd; 500 | usleep(800); 501 | } 502 | 503 | audio_stop(&m); 504 | pthread_join(draw_thread, NULL); 505 | for (k = 0; k < 3; k++) close(fid[k]); 506 | close(bfid); 507 | fb_cleanup(&m.fb); 508 | if (please_poweroff) { 509 | system("poweroff"); 510 | } 511 | return 0; 512 | } 513 | -------------------------------------------------------------------------------- /fbtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define SMILES_WIDTH 8 10 | #define SMILES_HEIGHT 8 11 | 12 | const char *smiles[]= { 13 | "--####--", 14 | "-#----#-", 15 | "#-#--#-#", 16 | "#------#", 17 | "#-#--#-#", 18 | "#--##--#", 19 | "-#----#-", 20 | "--####--", 21 | }; 22 | 23 | void pixel(struct fb_var_screeninfo *vinfo, 24 | struct fb_fix_screeninfo *finfo, 25 | char *fbp, 26 | int x, 27 | int y, 28 | unsigned char val) 29 | { 30 | long int location; 31 | 32 | if (x >= vinfo->xres || y >= vinfo->yres) return; 33 | 34 | location = (x + vinfo->xoffset) * (vinfo->bits_per_pixel/8) + 35 | (y + vinfo->yoffset) * finfo->line_length; 36 | 37 | fbp[location] = 0x0; 38 | fbp[location + 1] = val; 39 | } 40 | 41 | void clearscreen(struct fb_var_screeninfo *vinfo, 42 | struct fb_fix_screeninfo *finfo, 43 | char *fbp) 44 | { 45 | int x, y; 46 | 47 | for (y = 0; y < vinfo->yres; y++) { 48 | for (x = 0; x < vinfo->xres; x++) { 49 | pixel(vinfo, finfo, fbp, x, y, 0); 50 | } 51 | } 52 | } 53 | 54 | void draw_smiles(struct fb_var_screeninfo *vinfo, 55 | struct fb_fix_screeninfo *finfo, 56 | char *fbp) 57 | { 58 | int x, y; 59 | unsigned char v; 60 | int offx, offy; 61 | 62 | offx = (vinfo->xres/2) - SMILES_WIDTH; 63 | offy = (vinfo->yres/2) - SMILES_HEIGHT; 64 | 65 | for (y = 0; y < SMILES_HEIGHT; y++) { 66 | for (x = 0; x < SMILES_WIDTH; x++) { 67 | if (smiles[y][x] == '#') v = 0xff; 68 | else v = 0; 69 | pixel(vinfo, finfo, fbp, x + offx, y + offy, v); 70 | } 71 | } 72 | } 73 | 74 | int main() 75 | { 76 | int fbfd = 0; 77 | struct fb_var_screeninfo vinfo; 78 | struct fb_fix_screeninfo finfo; 79 | long int screensize = 0; 80 | char *fbp = 0; 81 | 82 | fbfd = open("/dev/fb0", O_RDWR); 83 | if (fbfd == -1) { 84 | perror("Error: cannot open framebuffer device"); 85 | exit(1); 86 | } 87 | printf("The framebuffer device was opened successfully.\n"); 88 | 89 | if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) { 90 | perror("Error reading fixed information"); 91 | exit(2); 92 | } 93 | 94 | if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) { 95 | perror("Error reading variable information"); 96 | exit(3); 97 | } 98 | 99 | printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); 100 | 101 | screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; 102 | 103 | fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); 104 | if ((int)fbp == -1) { 105 | perror("Error: failed to map framebuffer device to memory"); 106 | exit(4); 107 | } 108 | 109 | clearscreen(&vinfo, &finfo, fbp); 110 | 111 | draw_smiles(&vinfo, &finfo, fbp); 112 | 113 | munmap(fbp, screensize); 114 | close(fbfd); 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaulBatchelor/norns-lowlevel/52107e8874a2e93dd417a13b1645bf9ee9dd51d4/font.png -------------------------------------------------------------------------------- /font.xbm: -------------------------------------------------------------------------------- 1 | #define font_width 256 2 | #define font_height 32 3 | static char font_bits[] = { 4 | 0x00, 0x18, 0x66, 0x66, 0x18, 0x46, 0x3C, 0x60, 0x30, 0x0C, 0x00, 0x00, 5 | 0x00, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x3C, 0x3C, 0x60, 0x7E, 0x3C, 0x7E, 6 | 0x3C, 0x3C, 0x00, 0x00, 0x70, 0x00, 0x0E, 0x3C, 0x00, 0x18, 0x66, 0x66, 7 | 0x7C, 0x66, 0x66, 0x30, 0x18, 0x18, 0x66, 0x18, 0x00, 0x00, 0x00, 0xC0, 8 | 0x66, 0x18, 0x66, 0x66, 0x70, 0x06, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 9 | 0x18, 0x00, 0x18, 0x66, 0x00, 0x18, 0x66, 0xFF, 0x06, 0x30, 0x3C, 0x18, 10 | 0x0C, 0x30, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x60, 0x76, 0x1C, 0x60, 0x60, 11 | 0x78, 0x3E, 0x06, 0x30, 0x66, 0x66, 0x18, 0x18, 0x0C, 0x7E, 0x30, 0x60, 12 | 0x00, 0x18, 0x00, 0x66, 0x3C, 0x18, 0x1C, 0x00, 0x0C, 0x30, 0xFF, 0x7E, 13 | 0x00, 0x7E, 0x00, 0x30, 0x6E, 0x18, 0x30, 0x38, 0x66, 0x60, 0x3E, 0x18, 14 | 0x3C, 0x7C, 0x00, 0x00, 0x06, 0x00, 0x60, 0x30, 0x00, 0x00, 0x00, 0xFF, 15 | 0x60, 0x0C, 0xE6, 0x00, 0x0C, 0x30, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x18, 16 | 0x66, 0x18, 0x0C, 0x60, 0xFE, 0x60, 0x66, 0x18, 0x66, 0x60, 0x00, 0x00, 17 | 0x0C, 0x7E, 0x30, 0x18, 0x00, 0x00, 0x00, 0x66, 0x3E, 0x66, 0x66, 0x00, 18 | 0x18, 0x18, 0x66, 0x18, 0x18, 0x00, 0x18, 0x0C, 0x66, 0x18, 0x06, 0x66, 19 | 0x60, 0x66, 0x66, 0x18, 0x66, 0x66, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00, 20 | 0x00, 0x18, 0x00, 0x66, 0x18, 0x62, 0xFC, 0x00, 0x30, 0x0C, 0x00, 0x00, 21 | 0x18, 0x00, 0x18, 0x06, 0x3C, 0x7E, 0x7E, 0x3C, 0x60, 0x3C, 0x3C, 0x18, 22 | 0x3C, 0x3C, 0x00, 0x18, 0x70, 0x00, 0x0E, 0x18, 0x00, 0x00, 0x00, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 25 | 0x00, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x3E, 0x3C, 0x1E, 0x7E, 0x7E, 0x3C, 26 | 0x66, 0x3C, 0x78, 0x66, 0x06, 0xC6, 0x66, 0x3C, 0x3E, 0x3C, 0x3E, 0x3C, 27 | 0x7E, 0x66, 0x66, 0xC6, 0x66, 0x66, 0x7E, 0x3C, 0x30, 0x3C, 0x00, 0x00, 28 | 0x66, 0x3C, 0x66, 0x66, 0x36, 0x06, 0x06, 0x66, 0x66, 0x18, 0x30, 0x36, 29 | 0x06, 0xEE, 0x6E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x18, 0x66, 0x66, 0xC6, 30 | 0x66, 0x66, 0x60, 0x0C, 0x48, 0x30, 0x18, 0x08, 0x76, 0x66, 0x66, 0x06, 31 | 0x66, 0x06, 0x06, 0x06, 0x66, 0x18, 0x30, 0x1E, 0x06, 0xFE, 0x7E, 0x66, 32 | 0x66, 0x66, 0x66, 0x06, 0x18, 0x66, 0x66, 0xC6, 0x3C, 0x66, 0x30, 0x0C, 33 | 0x0C, 0x30, 0x3C, 0x0C, 0x76, 0x7E, 0x3E, 0x06, 0x66, 0x1E, 0x1E, 0x76, 34 | 0x7E, 0x18, 0x30, 0x0E, 0x06, 0xD6, 0x7E, 0x66, 0x3E, 0x66, 0x3E, 0x3C, 35 | 0x18, 0x66, 0x66, 0xD6, 0x18, 0x3C, 0x18, 0x0C, 0x3E, 0x30, 0x7E, 0xFE, 36 | 0x06, 0x66, 0x66, 0x06, 0x66, 0x06, 0x06, 0x66, 0x66, 0x18, 0x30, 0x1E, 37 | 0x06, 0xC6, 0x76, 0x66, 0x06, 0x66, 0x1E, 0x60, 0x18, 0x66, 0x66, 0xFE, 38 | 0x3C, 0x18, 0x0C, 0x0C, 0x0C, 0x30, 0x18, 0xFE, 0x46, 0x66, 0x66, 0x66, 39 | 0x36, 0x06, 0x06, 0x66, 0x66, 0x18, 0x36, 0x36, 0x06, 0xC6, 0x66, 0x66, 40 | 0x06, 0x3C, 0x36, 0x66, 0x18, 0x66, 0x3C, 0xEE, 0x66, 0x18, 0x06, 0x0C, 41 | 0x46, 0x30, 0x18, 0x0C, 0x3C, 0x66, 0x3E, 0x3C, 0x1E, 0x7E, 0x06, 0x3C, 42 | 0x66, 0x3C, 0x1C, 0x66, 0x7E, 0xC6, 0x66, 0x3C, 0x06, 0x70, 0x66, 0x3C, 43 | 0x18, 0x3C, 0x18, 0xC6, 0x66, 0x18, 0x7E, 0x3C, 0x3F, 0x3C, 0x18, 0x08, 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 49 | 0x03, 0x18, 0xCC, 0xCC, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x70, 0x00, 50 | 0x06, 0x18, 0x60, 0x06, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x18, 0xCC, 0x99, 52 | 0x00, 0x3C, 0x06, 0x3C, 0x60, 0x3C, 0x18, 0x7C, 0x06, 0x00, 0x00, 0x06, 53 | 0x18, 0x66, 0x3E, 0x3C, 0x3E, 0x7C, 0x3E, 0x7C, 0x7E, 0x66, 0x66, 0xC6, 54 | 0x66, 0x66, 0x7E, 0x18, 0x0C, 0x18, 0x33, 0x33, 0xFF, 0x60, 0x3E, 0x06, 55 | 0x7C, 0x66, 0x7C, 0x66, 0x3E, 0x1C, 0x60, 0x36, 0x18, 0xFE, 0x66, 0x66, 56 | 0x66, 0x66, 0x66, 0x06, 0x18, 0x66, 0x66, 0xD6, 0x3C, 0x66, 0x30, 0xFF, 57 | 0x0C, 0x18, 0x33, 0x66, 0xFF, 0x7C, 0x66, 0x06, 0x66, 0x7E, 0x18, 0x66, 58 | 0x66, 0x18, 0x60, 0x1E, 0x18, 0xFE, 0x66, 0x66, 0x66, 0x66, 0x06, 0x3C, 59 | 0x18, 0x66, 0x66, 0xFE, 0x18, 0x66, 0x18, 0xFF, 0x03, 0x18, 0xCC, 0xCC, 60 | 0x00, 0x66, 0x66, 0x06, 0x66, 0x06, 0x18, 0x7C, 0x66, 0x18, 0x60, 0x36, 61 | 0x18, 0xD6, 0x66, 0x66, 0x3E, 0x7C, 0x06, 0x60, 0x18, 0x66, 0x3C, 0x7C, 62 | 0x3C, 0x7C, 0x0C, 0x18, 0x03, 0x18, 0xCC, 0x99, 0x00, 0x7C, 0x3E, 0x3C, 63 | 0x7C, 0x3C, 0x18, 0x60, 0x66, 0x3C, 0x60, 0x66, 0x3C, 0xC6, 0x66, 0x3C, 64 | 0x06, 0x60, 0x06, 0x3E, 0x70, 0x7C, 0x18, 0x6C, 0x66, 0x30, 0x7E, 0x18, 65 | 0x0C, 0x18, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 66 | 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x18, 0x0C, 0x18, 0x33, 0x66, 68 | 0x00, 0x0F, 0x00, 0xFF, 0x00, 0x03, 0x33, 0xC0, 0x00, 0x33, 0xC0, 0x18, 69 | 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x03, 0x07, 0xE0, 0xFF, 70 | 0xFF, 0x00, 0x80, 0x00, 0xF0, 0x18, 0x0F, 0x0F, 0x00, 0x0F, 0x00, 0x00, 71 | 0x00, 0x03, 0x33, 0xC0, 0x00, 0x99, 0xC0, 0x18, 0x00, 0x18, 0x00, 0x00, 72 | 0x00, 0x18, 0x00, 0x18, 0x03, 0x07, 0xE0, 0xFF, 0xFF, 0x00, 0xC0, 0x00, 73 | 0xF0, 0x18, 0x0F, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x03, 0xCC, 0xC0, 74 | 0x00, 0xCC, 0xC0, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 75 | 0x03, 0x07, 0xE0, 0x00, 0xFF, 0x00, 0x60, 0x00, 0xF0, 0x18, 0x0F, 0x0F, 76 | 0x00, 0x0F, 0x00, 0x00, 0x00, 0x03, 0xCC, 0xC0, 0x00, 0x66, 0xC0, 0xF8, 77 | 0x00, 0xF8, 0x1F, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x03, 0x07, 0xE0, 0x00, 78 | 0x00, 0x00, 0x36, 0x00, 0xF0, 0x1F, 0x0F, 0x0F, 0x00, 0x0F, 0xFF, 0x00, 79 | 0x00, 0x03, 0x33, 0xC0, 0x33, 0x33, 0xC0, 0xF8, 0xF0, 0xF8, 0x1F, 0x00, 80 | 0xF8, 0xFF, 0xFF, 0x1F, 0x03, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x1E, 0x0F, 81 | 0x00, 0x1F, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x03, 0x33, 0xC0, 82 | 0x33, 0x99, 0xC0, 0x18, 0xF0, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x18, 83 | 0x03, 0x07, 0xE0, 0x00, 0x00, 0xFF, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0xF0, 84 | 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x03, 0xCC, 0xC0, 0xCC, 0xCC, 0xC0, 0x18, 85 | 0xF0, 0x00, 0x18, 0xFF, 0x18, 0x00, 0x18, 0x18, 0x03, 0x07, 0xE0, 0x00, 86 | 0x00, 0xFF, 0x06, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0x00, 87 | 0xFF, 0x03, 0xCC, 0xC0, 0xCC, 0x66, 0xC0, 0x18, 0xF0, 0x00, 0x18, 0xFF, 88 | 0x18, 0x00, 0x18, 0x18, 0x03, 0x07, 0xE0, 0x00, 0x00, 0xFF, 0x00, 0x0F, 89 | 0x00, 0x00, 0x00, 0xF0, }; 90 | -------------------------------------------------------------------------------- /input_monitor.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int running = 1; 13 | 14 | void quit(int sig) 15 | { 16 | printf("Closing.\n"); 17 | running = 0; 18 | } 19 | 20 | int main(int argc, char *argv[]) 21 | { 22 | int keys_fid; 23 | int rc; 24 | struct input_event evt[8]; 25 | int nevts; 26 | int e; 27 | int knob_fid[3]; 28 | char tmp[64]; 29 | int k; 30 | 31 | 32 | signal(SIGINT, quit); 33 | 34 | keys_fid = open( 35 | "/dev/input/by-path/platform-keys-event", 36 | O_RDONLY | O_NONBLOCK); 37 | 38 | for (k = 0; k < 3; k++) { 39 | snprintf(tmp, 64, 40 | "/dev/input/by-path/platform-soc:knob%d-event", 41 | k + 1); 42 | knob_fid[k] = open(tmp, O_RDONLY | O_NONBLOCK); 43 | } 44 | 45 | 46 | running = 1; 47 | 48 | while (running) { 49 | rc = read(keys_fid, 50 | evt, 51 | sizeof(struct input_event) * 8); 52 | if (rc != -1) { 53 | nevts = rc / sizeof(struct input_event); 54 | for (e = 0; e < nevts; e++) { 55 | if (evt[e].type) { 56 | fprintf(stdout, 57 | "button: %d %d\n", 58 | evt[e].code, 59 | evt[e].value); 60 | fflush(stdout); 61 | } 62 | } 63 | } 64 | 65 | for (k = 0; k < 3; k++) { 66 | rc = read(knob_fid[k], 67 | evt, 68 | sizeof(struct input_event) * 8); 69 | if (rc != -1) { 70 | nevts = rc / sizeof(struct input_event); 71 | for (e = 0; e < nevts; e++) { 72 | if (evt[e].type) { 73 | fprintf(stdout, 74 | "knob%d: %d\n", 75 | k, 76 | evt[e].value); 77 | fflush(stdout); 78 | } 79 | } 80 | } 81 | } 82 | 83 | usleep(10); 84 | } 85 | 86 | close(keys_fid); 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /kill_stuff.sh: -------------------------------------------------------------------------------- 1 | killall crone matron scsynth 2 | -------------------------------------------------------------------------------- /knob.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int running = 1; 11 | 12 | void quit(int sig) 13 | { 14 | printf("Closing.\n"); 15 | running = 0; 16 | } 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | int fid; 21 | int rc; 22 | struct input_event evt[8]; 23 | int nevts; 24 | int e; 25 | 26 | 27 | signal(SIGINT, quit); 28 | 29 | fid = open( 30 | "/dev/input/by-path/platform-soc:knob1-event", 31 | O_RDONLY | O_NONBLOCK); 32 | 33 | 34 | running = 1; 35 | 36 | while (running) { 37 | rc = read(fid, evt, sizeof(struct input_event) * 8); 38 | if (rc != -1) { 39 | nevts = rc / sizeof(struct input_event); 40 | for (e = 0; e < nevts; e++) { 41 | if (evt[e].type) { 42 | fprintf(stdout, "%d\n", evt[e].value); 43 | fflush(stdout); 44 | } 45 | } 46 | } 47 | usleep(10); 48 | } 49 | 50 | close(fid); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /menu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "font.xbm" 12 | 13 | typedef struct { 14 | struct fb_var_screeninfo vinfo; 15 | struct fb_fix_screeninfo finfo; 16 | char *fbp; 17 | int fbfd; 18 | long int screensize; 19 | } the_screen; 20 | 21 | void pixel(struct fb_var_screeninfo *vinfo, 22 | struct fb_fix_screeninfo *finfo, 23 | char *fbp, 24 | int x, 25 | int y, 26 | unsigned char val) 27 | { 28 | long int location; 29 | 30 | if (x >= vinfo->xres || y >= vinfo->yres) return; 31 | 32 | location = (x + vinfo->xoffset) * (vinfo->bits_per_pixel/8) + 33 | (y + vinfo->yoffset) * finfo->line_length; 34 | 35 | fbp[location] = 0x0; 36 | fbp[location + 1] = val; 37 | } 38 | 39 | void clearscreen(struct fb_var_screeninfo *vinfo, 40 | struct fb_fix_screeninfo *finfo, 41 | char *fbp) 42 | { 43 | int x, y; 44 | 45 | for (y = 0; y < vinfo->yres; y++) { 46 | for (x = 0; x < vinfo->xres; x++) { 47 | pixel(vinfo, finfo, fbp, x, y, 0); 48 | } 49 | } 50 | } 51 | 52 | void draw_glyph(struct fb_var_screeninfo *vinfo, 53 | struct fb_fix_screeninfo *finfo, 54 | char *fbp, 55 | int offx, int offy, 56 | int gx, int gy, int invert) 57 | { 58 | int x, y; 59 | unsigned char v; 60 | char b; 61 | int stride; 62 | 63 | stride = font_width / 8; /* divide by 8 */ 64 | 65 | for (y = 0; y < 8; y++) { 66 | for (x = 0; x < 8; x++) { 67 | b = font_bits[(8 * gy + y) * stride + gx]; 68 | v = ((b & (1 << x)) != 0) * 0xff; 69 | if (invert) { 70 | v = ((b & (1 << x)) == 0) * 0xff; 71 | } else { 72 | v = ((b & (1 << x)) != 0) * 0xff; 73 | } 74 | pixel(vinfo, finfo, fbp, x + offx, y + offy, v); 75 | } 76 | } 77 | } 78 | 79 | void draw_char(struct fb_var_screeninfo *vinfo, 80 | struct fb_fix_screeninfo *finfo, 81 | char *fbp, 82 | int offx, int offy, 83 | char c, int invert) 84 | { 85 | int gx, gy; 86 | char o; 87 | 88 | o = c - ' '; /* start at 0 */ 89 | 90 | gx = o % (font_width >> 3); 91 | gy = o / (font_width >> 3); 92 | 93 | draw_glyph(vinfo, finfo, fbp, offx, offy, gx, gy, invert); 94 | } 95 | 96 | void draw_string(struct fb_var_screeninfo *vinfo, 97 | struct fb_fix_screeninfo *finfo, 98 | char *fbp, 99 | int offx, int offy, 100 | const char *str, 101 | int invert) 102 | { 103 | int len; 104 | int n; 105 | len = strlen(str); 106 | 107 | for (n = 0; n < len; n++) { 108 | draw_char(vinfo, finfo, fbp, offx + 8*n, offy, str[n], invert); 109 | } 110 | } 111 | 112 | void draw_bar(struct fb_var_screeninfo *vinfo, 113 | struct fb_fix_screeninfo *finfo, 114 | char *fbp, 115 | int row) 116 | { 117 | int start; 118 | int x, y; 119 | 120 | start = row * 8; 121 | 122 | for (y = 0; y < 8; y++) { 123 | for (x = 0; x < vinfo->xres; x++) { 124 | pixel(vinfo, finfo, fbp, x, start + y, 0xff); 125 | } 126 | } 127 | } 128 | 129 | const char *menu_items[10] = 130 | { 131 | "Lions", 132 | "Tigers", 133 | "Bears", 134 | "Penguins", 135 | "Cats", 136 | "Dogs", 137 | "Hamsters", 138 | "Elephants", 139 | "Mice", 140 | "Aardvarks", 141 | }; 142 | 143 | void open_screen(the_screen *scrn) 144 | { 145 | scrn->fbp = NULL; 146 | scrn->fbfd = 0; 147 | scrn->fbfd = open("/dev/fb0", O_RDWR); 148 | 149 | if (scrn->fbfd == -1) { 150 | perror("Error: cannot open framebuffer device"); 151 | exit(1); 152 | } 153 | 154 | if (ioctl(scrn->fbfd, FBIOGET_FSCREENINFO, &scrn->finfo) == -1) { 155 | perror("Error reading fixed information"); 156 | exit(2); 157 | } 158 | 159 | if (ioctl(scrn->fbfd, FBIOGET_VSCREENINFO, &scrn->vinfo) == -1) { 160 | perror("Error reading variable information"); 161 | exit(3); 162 | } 163 | 164 | scrn->screensize = scrn->vinfo.xres * 165 | scrn->vinfo.yres * 166 | scrn->vinfo.bits_per_pixel / 8; 167 | 168 | scrn->fbp = (char *)mmap(0, 169 | scrn->screensize, 170 | PROT_READ | PROT_WRITE, 171 | MAP_SHARED, 172 | scrn->fbfd, 173 | 0); 174 | 175 | if ((int)scrn->fbp == -1) { 176 | perror("Error: failed to map framebuffer device to memory"); 177 | exit(4); 178 | } 179 | 180 | } 181 | 182 | void close_screen(the_screen *scrn) 183 | { 184 | munmap(scrn->fbp, scrn->screensize); 185 | close(scrn->fbfd); 186 | } 187 | 188 | typedef struct { 189 | int start; 190 | int selected; 191 | int row; 192 | } menu_stuff; 193 | 194 | static void draw_menu(the_screen *scrn, menu_stuff *ms) 195 | { 196 | int m; 197 | int is_selected; 198 | clearscreen(&scrn->vinfo, &scrn->finfo, scrn->fbp); 199 | for (m = 0; m < 8; m++) { 200 | is_selected = m == ms->row; 201 | if (is_selected) { 202 | draw_bar(&scrn->vinfo, 203 | &scrn->finfo, 204 | scrn->fbp, m); 205 | } 206 | draw_string(&scrn->vinfo, &scrn->finfo, scrn->fbp, 207 | 0, 8*m, 208 | menu_items[m + ms->start], 209 | is_selected); 210 | } 211 | 212 | } 213 | 214 | int open_buttons(void) 215 | { 216 | return open( 217 | "/dev/input/by-path/platform-keys-event", 218 | O_RDONLY | O_NONBLOCK); 219 | } 220 | 221 | int open_knob(int knob) 222 | { 223 | char path[256]; 224 | sprintf(path, 225 | "/dev/input/by-path/platform-soc:knob%d-event", 226 | knob); 227 | return open(path, O_RDONLY | O_NONBLOCK); 228 | } 229 | 230 | void open_all_knobs(int *fid) 231 | { 232 | int k; 233 | for (k = 0; k < 3; k++) { 234 | fid[k] = open_knob(k + 1); 235 | } 236 | } 237 | 238 | void close_all_knobs(int *fid) 239 | { 240 | int k; 241 | for (k = 0; k < 3; k++) { 242 | close(fid[k]); 243 | } 244 | } 245 | 246 | int main() 247 | { 248 | the_screen scrn; 249 | menu_stuff ms; 250 | 251 | /* peripherals */ 252 | int fid[3]; 253 | int bfid; 254 | 255 | int running; 256 | 257 | /* input polling */ 258 | struct input_event evt[8]; 259 | int nevts; 260 | int e; 261 | int k; 262 | int changed; 263 | int code; 264 | int rc; 265 | 266 | running = 1; 267 | bfid = open_buttons(); 268 | open_all_knobs(fid); 269 | changed = 0; 270 | 271 | open_screen(&scrn); 272 | 273 | ms.start = 0; 274 | ms.selected = 0; 275 | ms.row = 0; 276 | 277 | draw_menu(&scrn, &ms); 278 | 279 | while (running) { 280 | changed = 0; 281 | for (k = 0; k < 3; k++) { 282 | rc = read(fid[k], 283 | evt, 284 | sizeof(struct input_event) * 8); 285 | 286 | if (rc != -1) { 287 | nevts = rc / sizeof(struct input_event); 288 | for (e = 0; e < nevts; e++) { 289 | if (evt[e].type) { 290 | ms.row += evt[e].value; 291 | if (ms.row < 0) { 292 | ms.start--; 293 | if(ms.start < 0) ms.start = 0; 294 | ms.row = 0; 295 | } else if (ms.row >= 8) { 296 | ms.start++; 297 | if (ms.start + 8 > 10) { 298 | ms.start = 10 - 8; 299 | } 300 | ms.row = 7; 301 | } 302 | changed = 1; 303 | } 304 | } 305 | } 306 | } 307 | rc = read(bfid, evt, sizeof(struct input_event) * 8); 308 | if (rc != -1) { 309 | nevts = rc / sizeof(struct input_event); 310 | for(e = 0; e < nevts; e++) { 311 | if(evt[e].type) { 312 | fprintf(stdout, 313 | "%d %d\n", 314 | evt[e].code, 315 | evt[e].value); 316 | fflush(stdout); 317 | 318 | code = evt[e].code; 319 | switch (code) { 320 | case 1: 321 | running = 0; 322 | break; 323 | case 2: 324 | break; 325 | case 3: 326 | break; 327 | } 328 | } 329 | } 330 | } 331 | if (changed) { 332 | draw_menu(&scrn, &ms); 333 | } 334 | usleep(800); 335 | } 336 | 337 | close_screen(&scrn); 338 | close(bfid); 339 | close_all_knobs(fid); 340 | return 0; 341 | } 342 | -------------------------------------------------------------------------------- /text.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "font.xbm" 11 | 12 | void pixel(struct fb_var_screeninfo *vinfo, 13 | struct fb_fix_screeninfo *finfo, 14 | char *fbp, 15 | int x, 16 | int y, 17 | unsigned char val) 18 | { 19 | long int location; 20 | 21 | if (x >= vinfo->xres || y >= vinfo->yres) return; 22 | 23 | location = (x + vinfo->xoffset) * (vinfo->bits_per_pixel/8) + 24 | (y + vinfo->yoffset) * finfo->line_length; 25 | 26 | fbp[location] = 0x0; 27 | fbp[location + 1] = val; 28 | } 29 | 30 | void clearscreen(struct fb_var_screeninfo *vinfo, 31 | struct fb_fix_screeninfo *finfo, 32 | char *fbp) 33 | { 34 | int x, y; 35 | 36 | for (y = 0; y < vinfo->yres; y++) { 37 | for (x = 0; x < vinfo->xres; x++) { 38 | pixel(vinfo, finfo, fbp, x, y, 0); 39 | } 40 | } 41 | } 42 | 43 | void draw_glyph(struct fb_var_screeninfo *vinfo, 44 | struct fb_fix_screeninfo *finfo, 45 | char *fbp, 46 | int offx, int offy, 47 | int gx, int gy) 48 | { 49 | int x, y; 50 | unsigned char v; 51 | char b; 52 | int stride; 53 | 54 | stride = font_width / 8; /* divide by 8 */ 55 | 56 | for (y = 0; y < 8; y++) { 57 | for (x = 0; x < 8; x++) { 58 | b = font_bits[(8 * gy + y) * stride + gx]; 59 | v = ((b & (1 << x)) != 0) * 0xff; 60 | pixel(vinfo, finfo, fbp, x + offx, y + offy, v); 61 | } 62 | } 63 | } 64 | 65 | void draw_char(struct fb_var_screeninfo *vinfo, 66 | struct fb_fix_screeninfo *finfo, 67 | char *fbp, 68 | int offx, int offy, 69 | char c) 70 | { 71 | int gx, gy; 72 | char o; 73 | 74 | o = c - ' '; /* start at 0 */ 75 | 76 | gx = o % (font_width >> 3); 77 | gy = o / (font_width >> 3); 78 | 79 | draw_glyph(vinfo, finfo, fbp, offx, offy, gx, gy); 80 | } 81 | 82 | void draw_string(struct fb_var_screeninfo *vinfo, 83 | struct fb_fix_screeninfo *finfo, 84 | char *fbp, 85 | int offx, int offy, 86 | const char *str) 87 | { 88 | int len; 89 | int n; 90 | len = strlen(str); 91 | 92 | for (n = 0; n < len; n++) { 93 | draw_char(vinfo, finfo, fbp, offx + 8*n, offy, str[n]); 94 | } 95 | } 96 | 97 | int main() 98 | { 99 | int fbfd = 0; 100 | struct fb_var_screeninfo vinfo; 101 | struct fb_fix_screeninfo finfo; 102 | long int screensize = 0; 103 | char *fbp = 0; 104 | 105 | fbfd = open("/dev/fb0", O_RDWR); 106 | if (fbfd == -1) { 107 | perror("Error: cannot open framebuffer device"); 108 | exit(1); 109 | } 110 | printf("The framebuffer device was opened successfully.\n"); 111 | 112 | if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) { 113 | perror("Error reading fixed information"); 114 | exit(2); 115 | } 116 | 117 | if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) { 118 | perror("Error reading variable information"); 119 | exit(3); 120 | } 121 | 122 | printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); 123 | 124 | screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; 125 | 126 | fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); 127 | if ((int)fbp == -1) { 128 | perror("Error: failed to map framebuffer device to memory"); 129 | exit(4); 130 | } 131 | 132 | clearscreen(&vinfo, &finfo, fbp); 133 | 134 | draw_string(&vinfo, &finfo, fbp, 0, 0, "there is"); 135 | draw_string(&vinfo, &finfo, fbp, 0, 8, "one art"); 136 | draw_string(&vinfo, &finfo, fbp, 0, 16, "no more"); 137 | draw_string(&vinfo, &finfo, fbp, 0, 24, "no less"); 138 | draw_string(&vinfo, &finfo, fbp, 0, 32, "to do"); 139 | draw_string(&vinfo, &finfo, fbp, 0, 40, "all things"); 140 | draw_string(&vinfo, &finfo, fbp, 0, 48, "with art-"); 141 | draw_string(&vinfo, &finfo, fbp, 0, 56, "lessness."); 142 | 143 | munmap(fbp, screensize); 144 | close(fbfd); 145 | return 0; 146 | } 147 | --------------------------------------------------------------------------------