ref: 5f87804393f475e2eaa1ed9f5c6294c4ff2113aa
parent: fd2958b2cda8fed891c78542a032d9bee335192e
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sat Oct 8 16:37:25 EDT 2022
reform/pm: kbdoled: allow any size/depth of uncompressed image - convert ourselves
--- a/sys/man/1/reform
+++ b/sys/man/1/reform
@@ -110,9 +110,8 @@
Exposes the current temperature reading of the CPU.
.TP
.B kbdoled
-An image can be displayed on the keyboard OLED by writing a 126x32x1
-uncompressed Plan 9 image (with or without a header). Zero-length
-write clears the display.
+An uncompressed Plan 9image can be written to the file to display on
+the keyboard OLED. Zero-length write clears the display.
.TP
.B light
Provides a way to control the backlight of the built-in LCD by
--- a/sys/src/cmd/reform/pm.c
+++ b/sys/src/cmd/reform/pm.c
@@ -83,7 +83,7 @@
static u32int *pwm2, *tmu, *spi2;
static int kbdlight = 0;
static int kbdhidfd = -1;
-static Memimage *kbdoled;
+static Memimage *kbdoled, *image;
static u8int kbdoledraw[4+KbdoledW*KbdoledH/8] = {'W', 'B', 'I', 'T', 0};
static void
@@ -152,10 +152,13 @@
}
static int
-loadkbdoled(void *data, int size)
+loadkbdoled(char *data, int offset, int size)
{
- int x, y, i, k, v, bpl;
+ int x, y, i, k, v, bpl, used;
+ static Rectangle r;
+ char hdr[5*12+1];
u8int *p, q;
+ ulong chan;
if(openkbdhid() != 0)
return -1;
@@ -162,18 +165,58 @@
if(size == 0)
return write(kbdhidfd, "WCLR", 4);
- bpl = bytesperline(kbdoled->r, kbdoled->depth);
- if(size == 60+bpl*KbdoledH){
- data = (u8int*)data + 60;
+ used = 0;
+ if(offset == 0){
+ if(size < 60){
+ werrstr("invalid header");
+ return -1;
+ }
+ memmove(hdr, data, 60);
+ hdr[11] = 0;
+ hdr[60] = 0;
+ if((chan = strtochan(data)) == 0){
+ werrstr("bad channel string %s", (char*)data);
+ return -1;
+ }
+ r.min.x = atoi(data+1*12);
+ r.min.y = atoi(data+2*12);
+ r.max.x = atoi(data+3*12);
+ r.max.y = atoi(data+4*12);
+ if(badrect(r)){
+ werrstr("bad rect");
+ return -1;
+ }
+ data += 60;
size -= 60;
- }else if(size != bpl*KbdoledH){
- werrstr("invalid image: expected %dx%d GREY1 (%d bytes)", KbdoledW, KbdoledH, bpl*KbdoledH);
+ used += 60;
+ if(image == nil || chan != image->chan || !eqrect(r, image->r)){
+ freememimage(image);
+ if((image = allocmemimage(r, chan)) == nil)
+ return -1;
+ }
+ r.max.y = r.min.y;
+ }
+ if(image == nil){
+ werrstr("no header");
return -1;
}
-
- k = loadmemimage(kbdoled, kbdoled->r, data, size);
- if(k < 0 || openkbdhid() != 0)
+ bpl = bytesperline(image->r, image->depth);
+ i = size / bpl;
+ if(i < 1)
+ return used;
+ v = loadmemimage(image, Rect(r.min.x, r.max.y, r.max.x, r.max.y+i), (uchar*)data, size);
+ if(v <= 0){
+ werrstr("loadmemimage: failed");
return -1;
+ }
+ r.max.y += i;
+ used += v;
+ if(r.max.y < image->r.max.y)
+ return used;
+
+ memimagedraw(kbdoled, kbdoled->r, image, image->r.min, nil, ZP, S);
+ bpl = bytesperline(kbdoled->r, kbdoled->depth);
+
for(y = 0, i = 4; y < KbdoledH; y += 8){
for(x = v = 0; x < KbdoledW; x++, v = (v+1)&7){
SET(p);
@@ -181,11 +224,14 @@
p = byteaddr(kbdoled, Pt(x,y));
for(k = q = 0; k < 8; k++)
q |= ((p[bpl*k] >> (7-v)) & 1) << k;
- kbdoledraw[i++] = q;
+ kbdoledraw[i++] = ~q;
}
}
- return write(kbdhidfd, kbdoledraw, sizeof(kbdoledraw));
+ if(write(kbdhidfd, kbdoledraw, sizeof(kbdoledraw)) != sizeof(kbdoledraw))
+ return -1;
+
+ return used;
}
static int
@@ -467,12 +513,12 @@
aux = r->fid->file->aux;
if(aux == (void*)Kbdoled){
- if(loadkbdoled(r->ifcall.data, r->ifcall.count) < 0){
+ if((v = loadkbdoled(r->ifcall.data, r->ifcall.offset, r->ifcall.count)) < 0){
Err:
responderror(r);
return;
}
- r->ofcall.count = r->ifcall.count;
+ r->ofcall.count = v;
respond(r, nil);
return;
}