altos/draw: Mock up TeleLCO boot sequence
authorKeith Packard <keithp@keithp.com>
Mon, 27 Feb 2023 00:01:20 +0000 (16:01 -0800)
committerKeith Packard <keithp@keithp.com>
Mon, 27 Feb 2023 00:08:08 +0000 (16:08 -0800)
Show logo, progress bar and discovered box numbers during
boot sequence

Signed-off-by: Keith Packard <keithp@keithp.com>
src/draw/Makefile
src/draw/draw-test.c
src/draw/frame.c

index cbbd3457db14d7beafe7e714c33a5914221f8ead..ccedc6a149caaef72d0b910b657932a93c637186 100644 (file)
@@ -105,7 +105,7 @@ OBJS=$(SRCS:.c=.o)
 
 LIBS=-lXrender -lX11 -lm -Wl,--gc-sections
 
-CFLAGS=-O2 -g $(WARN_FLAGS)
+CFLAGS=-O0 -g $(WARN_FLAGS)
 
 HEADERS=\
        ao_draw.h \
index 64080dfae59ae620745e78d6d7dedaf7d95838ff..0221fbb9a71a07fe4ca00c06ed98793b5524b2a7 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
+#define IMAGE_SCALE    8
 #define WIDTH  128
 #define HEIGHT 64
 
-#define DEFAULT_WIDTH  WIDTH
-#define DEFAULT_HEIGHT HEIGHT
+#define IMAGE_WIDTH    (WIDTH * IMAGE_SCALE)
+#define IMAGE_HEIGHT   (HEIGHT * IMAGE_SCALE)
+
+#define DEFAULT_WIDTH  IMAGE_WIDTH
+#define DEFAULT_HEIGHT IMAGE_HEIGHT
+
+#define TIMEOUT        50
 
 #define PASS_KEYS
 #include "frame.c"
@@ -40,6 +46,7 @@ static struct ao_bitmap fb = {
 #define BIG_FONT FrutigerLT_Roman_64_font
 #define VOLT_FONT FrutigerLT_Roman_64_font
 #define SMALL_FONT NotoMono_12_font
+#define TINY_FONT NotoMono_10_font
 #define LOGO_FONT BenguiatGothicStd_Bold_26_font
 
 #define LABEL_Y                (int16_t) (SMALL_FONT.ascent)
@@ -47,14 +54,15 @@ static struct ao_bitmap fb = {
 #define BOX_X          2
 #define PAD_X          90
 #define BOX_LABEL_X    30
-#define VOLT_LABEL_X   35
+#define VOLT_LABEL_X   25
 #define RSSI_LABEL_X   15
 #define PAD_LABEL_X    95
-#define SEP_X          (PAD_X - 8)
+#define SEP_X          (PAD_X - 10)
 
 static int     box_number = 1;
 static int     pad_number = 1;
-static int     do_polys = 0;
+static int     do_polys = 1;
+static int     scan_number = 0;
 
 static const struct ao_coord trek[] = {
        { .x = 90, .y = 0 },
@@ -91,9 +99,16 @@ static const struct ao_coord bowtie[] = {
 
 static const struct ao_transform logo_transform = {
        .x_scale = 48, .x_off = 0,
-       .y_scale = 48, .y_off = 10,
+       .y_scale = 48, .y_off = 0,
 };
 
+#define SCAN_X         (WIDTH - 100) / 2
+#define SCAN_Y         51
+#define SCAN_HEIGHT    4
+#define FOUND_Y                64
+#define FOUND_WIDTH    14
+#define MAX_VALID      (WIDTH / FOUND_WIDTH)
+
 static const struct ao_transform bowtie_transform = {
        .x_scale = 1, .x_off = 50,
        .y_scale = 1, .y_off = 20,
@@ -103,15 +118,85 @@ static const float pad_volts = 12.3f;
 static const float lco_volts = 4.1f;
 static const int rssi = -30;
 
+#define IMAGE_STRIDE   ((IMAGE_WIDTH + 31) / 32)
+
+static uint32_t image_bits[IMAGE_STRIDE * IMAGE_HEIGHT];
+
+static int     boxes[] = { 1, 2, 3, 5, 8, 11, 13, 17, 19, 23, 29, 31, 37, 62, 97 };
+
+static int     max_box = 97;
+
+#define ARRAYSIZE(a)   (sizeof(a) / sizeof((a)[0]))
+
+static bool
+valid_box(int box)
+{
+       size_t i;
+       if (box == 0)
+               return true;
+       for (i = 0; i < ARRAYSIZE(boxes); i++)
+               if (boxes[i] == box)
+                       return true;
+       return false;
+}
+
+static void
+next_box(void)
+{
+       for (int n = box_number + 1; n <= max_box; n++)
+               if (valid_box(n)) {
+                       box_number = n;
+                       return;
+               }
+       box_number = 0;
+}
+
+static void
+prev_box(void)
+{
+       for (int n = box_number - 1; n >= 0; n--)
+               if (valid_box(n)) {
+                       box_number = n;
+                       return;
+               }
+       box_number = max_box;
+}
+
 void HandleExpose(Display *dpy, Window win, GC gc)
 {
        char    str[64];
+       int     i;
+       int     v;
+       int16_t b;
 
        ao_rect(&fb, 0, 0, WIDTH, HEIGHT, 0xffffffff, AO_COPY);
 
+       if (do_polys == 1)
+               current_timeout = TIMEOUT;
+       else
+               current_timeout = 0;
        switch (do_polys) {
        case 1:
                ao_logo(&fb, &logo_transform, &LOGO_FONT, 0x00000000, AO_COPY);
+               if (scan_number) {
+                       ao_rect(&fb, SCAN_X, SCAN_Y, (int16_t) scan_number, SCAN_HEIGHT, 0x00000000, AO_COPY);
+                       b = 0;
+                       v = 0;
+                       for (i = scan_number; i > 1; i--) {
+                               if (valid_box(i)) {
+                                       v++;
+                                       if (v == MAX_VALID)
+                                               break;
+                               }
+                       }
+                       for (; i <= scan_number; i++) {
+                               if (valid_box(i)) {
+                                       sprintf(str, "%02d", i);
+                                       ao_text(&fb, &TINY_FONT, 0 + FOUND_WIDTH * b, FOUND_Y, str, 0x00000000, AO_COPY);
+                                       b++;
+                               }
+                       }
+               }
                break;
        case 2:
                ao_poly(&fb, trek, NCOORD_TREK, NULL, 0x00000000, AO_COPY);
@@ -149,17 +234,32 @@ void HandleExpose(Display *dpy, Window win, GC gc)
                                ao_text(&fb, &BIG_FONT, PAD_X, VALUE_Y, str, 0x00000000, AO_COPY);
                                ao_text(&fb, &SMALL_FONT, PAD_LABEL_X, LABEL_Y, "Pad", 0x00000000, AO_COPY);
 
-                               ao_line(&fb, SEP_X, 0, SEP_X, HEIGHT, 0x00000000, AO_COPY);
+                               ao_rect(&fb, SEP_X, 0, 2, HEIGHT, 0x00000000, AO_COPY);
                        }
                        break;
                }
                break;
        }
 
-       XImage *image = XCreateImage(dpy, visual, 1, XYBitmap, 0, (char *) bits, WIDTH, HEIGHT, 32, STRIDE*4);
+       XImage *source_image = XCreateImage(dpy, visual, 1, XYBitmap, 0, (char *) bits, WIDTH, HEIGHT, 32, STRIDE*4);
+       XImage *image = XCreateImage(dpy, visual, 1, XYBitmap, 0, (char *) image_bits, IMAGE_WIDTH, IMAGE_HEIGHT, 32, IMAGE_STRIDE * 4);
+       int ix, iy;
+       int dx, dy;
+
+       for (iy = 0; iy < HEIGHT; iy++) {
+               for (ix = 0; ix < WIDTH; ix++) {
+                       unsigned long bit = XGetPixel(source_image, ix, iy);
+                       for (dy = 0; dy < IMAGE_SCALE; dy++) {
+
+                               for (dx = 0; dx < IMAGE_SCALE; dx++) {
+                                       XPutPixel(image, ix * IMAGE_SCALE + dx, iy * IMAGE_SCALE + dy, bit);
+                               }
+                       }
+               }
+       }
        XSetForeground(dpy, gc, WhitePixel(dpy, screen));
        XSetBackground(dpy, gc, BlackPixel(dpy, screen));
-       XPutImage(dpy, win, gc, image, 0, 0, 0, 0, WIDTH, HEIGHT);
+       XPutImage(dpy, win, gc, image, 0, 0, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
        free(image);
 }
 
@@ -186,19 +286,32 @@ HandleKeyPress(Display *dpy, Window win, GC gc, XEvent *ev)
                        }
                        break;
                case 'b':
-                       box_number++;
-                       if (box_number > 99)
-                               box_number = 0;
+                       next_box();
                        break;
                case 'B':
-                       box_number--;
-                       if (box_number < 0)
-                               box_number = 99;
+                       prev_box();
                        break;
-               case 's':
+               case 'i':
                        do_polys++;
                        if (do_polys == 4)
                                do_polys = 0;
+                       if (do_polys == 1)
+                               scan_number = 0;
+                       break;
+               case 'I':
+                       do_polys--;
+                       if (do_polys < 0)
+                               do_polys = 4;
+                       if (do_polys == 1)
+                               scan_number = 0;
+                       break;
+               case 's':
+                       if (scan_number < 99)
+                               scan_number++;
+                       break;
+               case 'S':
+                       if (scan_number > 0)
+                               scan_number--;
                        break;
                case 'c':
                        break;
@@ -215,3 +328,18 @@ HandleKeyRelease(Display *dpy, Window win, GC gc, XEvent *ev)
        (void) gc;
        (void) ev;
 }
+
+void
+HandleTimeout(Display *dpy, Window win, GC gc)
+{
+       if (do_polys == 1) {
+               if (scan_number < 99)
+                       scan_number++;
+               else {
+                       box_number = boxes[0];
+                       pad_number = 1;
+                       do_polys = 0;
+               }
+               HandleExpose(dpy, win, gc);
+       }
+}
index b04a767f028468a9374013dd9f17615a7be9a54c..84b30b36797e8f1a6fad16bd184327f19cb4bd65 100644 (file)
@@ -19,6 +19,7 @@
 #include    <stdlib.h>
 #include    <ctype.h>
 #include    <strings.h>
+#include    <poll.h>
 #include    <X11/Xos.h>
 #include    <X11/Xlib.h>
 #include    <X11/Xutil.h>
@@ -361,6 +362,9 @@ Visual          *visual;
 int        depth;
 Window  root = 0;
 int        screen;
+#ifdef TIMEOUT
+int    current_timeout = TIMEOUT;
+#endif
 
 void
 HandleExpose(Display *dpy, Window win, GC gc);
@@ -371,6 +375,9 @@ HandleKeyPress(Display *dpy, Window win, GC gc, XEvent *ev);
 void
 HandleKeyRelease(Display *dpy, Window win, GC gc, XEvent *ev);
 
+void
+HandleTimeout(Display *dpy, Window win, GC gc);
+
 #include <X11/extensions/Xrender.h>
 
 XRenderColor   renderBlack = { 0, 0, 0, 0xffff };
@@ -691,6 +698,17 @@ main (int argc, char **argv)
        XSetDashes (dpy, gc, 0, dashes, ndashes);
     XMapWindow (dpy, win);
     for (;;) {
+#ifdef TIMEOUT
+       while (current_timeout && !XEventsQueued(dpy, QueuedAfterFlush)) {
+           struct pollfd pollfd = {
+               .fd = ConnectionNumber(dpy),
+               .events = POLLIN
+           };
+           int r = poll(&pollfd, 1, current_timeout);
+           if (r == 0)
+               HandleTimeout(dpy, win, gc);
+       }
+#endif
        XNextEvent (dpy, &ev);
 #ifdef PASS_BUTTONS
        if (HasMotion && ev.type != MotionNotify) {