2 * Copyright © 2023 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23 #define IMAGE_WIDTH (WIDTH * IMAGE_SCALE)
24 #define IMAGE_HEIGHT (HEIGHT * IMAGE_SCALE)
26 #define DEFAULT_WIDTH IMAGE_WIDTH
27 #define DEFAULT_HEIGHT IMAGE_HEIGHT
35 #define STRIDE ((WIDTH + 31) / 32)
37 static uint32_t bits[STRIDE * HEIGHT];
39 static struct ao_bitmap fb = {
46 #define BIG_FONT FrutigerLT_Roman_64_font
47 #define VOLT_FONT FrutigerLT_Roman_64_font
48 #define SMALL_FONT NotoMono_12_font
49 #define TINY_FONT NotoMono_10_font
50 #define LOGO_FONT BenguiatGothicStd_Bold_26_font
52 #define LABEL_Y (int16_t) (SMALL_FONT.ascent)
53 #define VALUE_Y (int16_t) (LABEL_Y + BIG_FONT.ascent)
56 #define BOX_LABEL_X 30
57 #define VOLT_LABEL_X 25
58 #define RSSI_LABEL_X 15
59 #define PAD_LABEL_X 95
60 #define SEP_X (PAD_X - 10)
62 static int box_number = 1;
63 static int pad_number = 1;
64 static int do_polys = 1;
65 static int scan_number = 0;
67 static const struct ao_coord trek[] = {
71 { .x = 120, .y = 40 },
74 #define NCOORD_TREK (sizeof(trek)/sizeof(trek[0]))
76 static const struct ao_coord donut[] = {
89 #define NCOORD_DONUT (sizeof(donut)/sizeof(donut[0]))
91 static const struct ao_coord bowtie[] = {
98 #define NCOORD_BOWTIE (sizeof(bowtie)/sizeof(bowtie[0]))
100 static const struct ao_transform logo_transform = {
101 .x_scale = 48, .x_off = 0,
102 .y_scale = 48, .y_off = 0,
105 #define SCAN_X (WIDTH - 100) / 2
107 #define SCAN_HEIGHT 4
109 #define FOUND_WIDTH 14
110 #define MAX_VALID (WIDTH / FOUND_WIDTH)
112 static const struct ao_transform bowtie_transform = {
113 .x_scale = 1, .x_off = 50,
114 .y_scale = 1, .y_off = 20,
117 static const float pad_volts = 12.3f;
118 static const float lco_volts = 4.1f;
119 static const int rssi = -30;
121 #define IMAGE_STRIDE ((IMAGE_WIDTH + 31) / 32)
123 static uint32_t image_bits[IMAGE_STRIDE * IMAGE_HEIGHT];
125 static int boxes[] = { 1, 2, 3, 5, 8, 11, 13, 17, 19, 23, 29, 31, 37, 62, 97 };
127 static int max_box = 97;
129 #define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
137 for (i = 0; i < ARRAYSIZE(boxes); i++)
146 for (int n = box_number + 1; n <= max_box; n++)
157 for (int n = box_number - 1; n >= 0; n--)
162 box_number = max_box;
165 void HandleExpose(Display *dpy, Window win, GC gc)
172 ao_rect(&fb, 0, 0, WIDTH, HEIGHT, 0xffffffff, AO_COPY);
175 current_timeout = TIMEOUT;
180 ao_logo(&fb, &logo_transform, &LOGO_FONT, 0x00000000, AO_COPY);
182 ao_rect(&fb, SCAN_X, SCAN_Y, (int16_t) scan_number, SCAN_HEIGHT, 0x00000000, AO_COPY);
185 for (i = scan_number; i > 1; i--) {
192 for (; i <= scan_number; i++) {
194 sprintf(str, "%02d", i);
195 ao_text(&fb, &TINY_FONT, 0 + FOUND_WIDTH * b, FOUND_Y, str, 0x00000000, AO_COPY);
202 ao_poly(&fb, trek, NCOORD_TREK, NULL, 0x00000000, AO_COPY);
203 ao_poly(&fb, donut, NCOORD_DONUT, NULL, 0x00000000, AO_COPY);
206 ao_poly(&fb, bowtie, NCOORD_BOWTIE, &bowtie_transform, 0x00000000, AO_COPY);
210 switch (box_number) {
212 sprintf(str, "%4.1f", lco_volts);
213 ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
214 ao_text(&fb, &SMALL_FONT, VOLT_LABEL_X, LABEL_Y, "LCO Battery", 0x00000000, AO_COPY);
217 switch (pad_number) {
219 sprintf(str, "%4.1f", pad_volts);
220 ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
221 ao_text(&fb, &SMALL_FONT, VOLT_LABEL_X, LABEL_Y, "Pad Battery", 0x00000000, AO_COPY);
224 sprintf(str, "%4d", rssi);
225 ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
226 ao_text(&fb, &SMALL_FONT, RSSI_LABEL_X, LABEL_Y, "Signal Strength", 0x00000000, AO_COPY);
229 sprintf(str, "%02d", box_number);
230 ao_text(&fb, &BIG_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY);
231 ao_text(&fb, &SMALL_FONT, BOX_LABEL_X, LABEL_Y, "Box", 0x00000000, AO_COPY);
233 sprintf(str, "%d", pad_number);
234 ao_text(&fb, &BIG_FONT, PAD_X, VALUE_Y, str, 0x00000000, AO_COPY);
235 ao_text(&fb, &SMALL_FONT, PAD_LABEL_X, LABEL_Y, "Pad", 0x00000000, AO_COPY);
237 ao_rect(&fb, SEP_X, 0, 2, HEIGHT, 0x00000000, AO_COPY);
244 XImage *source_image = XCreateImage(dpy, visual, 1, XYBitmap, 0, (char *) bits, WIDTH, HEIGHT, 32, STRIDE*4);
245 XImage *image = XCreateImage(dpy, visual, 1, XYBitmap, 0, (char *) image_bits, IMAGE_WIDTH, IMAGE_HEIGHT, 32, IMAGE_STRIDE * 4);
249 for (iy = 0; iy < HEIGHT; iy++) {
250 for (ix = 0; ix < WIDTH; ix++) {
251 unsigned long bit = XGetPixel(source_image, ix, iy);
252 for (dy = 0; dy < IMAGE_SCALE; dy++) {
254 for (dx = 0; dx < IMAGE_SCALE; dx++) {
255 XPutPixel(image, ix * IMAGE_SCALE + dx, iy * IMAGE_SCALE + dy, bit);
260 XSetForeground(dpy, gc, WhitePixel(dpy, screen));
261 XSetBackground(dpy, gc, BlackPixel(dpy, screen));
262 XPutImage(dpy, win, gc, image, 0, 0, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
267 HandleKeyPress(Display *dpy, Window win, GC gc, XEvent *ev)
270 if (XLookupString ((XKeyEvent *) ev, string, sizeof (string), 0, 0) >= 1) {
275 if (box_number != 0) {
282 if (box_number != 0) {
309 if (scan_number < 99)
319 HandleExpose(dpy, win, gc);
324 HandleKeyRelease(Display *dpy, Window win, GC gc, XEvent *ev)
333 HandleTimeout(Display *dpy, Window win, GC gc)
336 if (scan_number < 99)
339 box_number = boxes[0];
343 HandleExpose(dpy, win, gc);