wip: gamma toys

matejcik 1 year ago
parent 1d2fcf1b93
commit e0384137b9

@ -0,0 +1,179 @@
# set up pyserial on /dev/ttyACM0
import serial
import time
from struct import Struct
DISPLAY_SIZE = (240, 240)
BUFSIZE = 16 * 1024
SERIAL = serial.Serial("/dev/ttyACM0", 921600, timeout=1)
# one byte read/write, one byte command, two bytes little-endian length
INITIAL_PACKET = Struct("<BBH")
# fmt: off
ONE = [
0, 0, 1, 0, 0, 0,
0, 1, 1, 0, 0, 0,
0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 0, 0,
1, 1, 1, 1, 1, 1
]
TWO = [
1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 1, 0,
0, 0, 0, 1, 0, 0,
0, 0, 1, 0, 0, 0,
0, 1, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1
]
THREE = [
0, 1, 1, 1, 0, 0,
1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0,
0, 1, 1, 1, 0, 0
]
FOUR = [
0, 0, 0, 1, 0, 0,
0, 0, 1, 1, 0, 0,
0, 1, 0, 1, 0, 0,
1, 0, 0, 1, 0, 0,
1, 1, 1, 1, 1, 1,
0, 0, 0, 1, 0, 0
]
# fmt: on
def cmd_write(cmd: int, data: bytes) -> None:
# write a command to the display
# cmd: command byte
# data: data bytes
assert len(data) <= BUFSIZE
initial_packet = INITIAL_PACKET.pack(0x00, cmd, len(data))
SERIAL.write(initial_packet + data)
def cmd_read(cmd: int, length: int) -> bytes:
# read a command from the display
# cmd: command byte
# length: number of bytes to read
assert length <= BUFSIZE
initial_packet = INITIAL_PACKET.pack(0x01, cmd, length)
SERIAL.write(initial_packet)
return SERIAL.read(length)
def set_window(x0, y0, x1, y1):
# CASET 0x2A
cmd_write(0x2A, x0.to_bytes(2, "big") + x1.to_bytes(2, "big"))
# RASET 0x2B
cmd_write(0x2B, y0.to_bytes(2, "big") + y1.to_bytes(2, "big"))
def pixels(data):
# RAMWR 0x2C
cmd_write(0x2C, b"")
# split data into chunks of BUFSIZE max
for i in range(0, len(data), BUFSIZE):
cmd_write(0, data[i : i + BUFSIZE])
def render_num(number: list[int]) -> None:
buf = bytearray()
for n in number:
buf.extend(b"\x00\x00" if not n else b"\xFF\xFF")
set_window(200, 200, 205, 205)
pixels(buf)
def _intensity(i: float) -> int:
"""Convert intensity to 6-bit value."""
return int(i * 63)
def rgb565(r: float, g: float, b: float) -> bytes:
"""Convert RGB to RGB565."""
return (
((_intensity(r) >> 1) << 11) | (_intensity(g) << 5) | (_intensity(b) >> 1)
).to_bytes(2, "little")
def rgb565i(r: int, g: int, b: int) -> bytes:
"""Convert RGB to RGB565."""
r &= 0b11111
g &= 0b111111
b &= 0b11111
return ((r << 11) | (g << 5) | b).to_bytes(2, "little")
def image_sampler() -> bytes:
"""Generate a 240x240 image sampler of gray, red, blue and green gradients.
The resulting buffer is RGB565, two bytes per pixel.
"""
result = bytearray()
gray_line = bytearray()
red_line = bytearray()
green_line = bytearray()
blue_line = bytearray()
for x in range(24):
intensity = x * 32 // 24
gray_line.extend(rgb565i(intensity, intensity * 2, intensity) * 10)
red_line.extend(rgb565i(intensity, 0, 0) * 10)
green_line.extend(rgb565i(0, intensity * 2, 0) * 10)
blue_line.extend(rgb565i(0, 0, intensity) * 10)
result.extend(gray_line * 60)
result.extend(red_line * 60)
result.extend(green_line * 60)
result.extend(blue_line * 60)
return bytes(result)
if __name__ == "__main__":
# # # set up display
# cmd_write(0x11, b"") # SLPOUT 0x11
# time.sleep(0.1)
# cmd_write(0x36, b"\x00") # MADCTL 0x36
# cmd_write(0x3A, b"\x05") # COLMOD 0x3A
# cmd_write(0x29, b"") # DISPON 0x29
set_window(0, 0, *DISPLAY_SIZE)
pixels(image_sampler())
while True:
# set gamma curve 1
cmd_write(0x26, b"\x01")
render_num(ONE)
input()
# set gamma curve 2
cmd_write(0x26, b"\x02")
render_num(TWO)
input()
# set gamma curve 3
cmd_write(0x26, b"\x04")
render_num(THREE)
input()
# set gamma curve 4
cmd_write(0x26, b"\x08")
render_num(FOUR)
input()
# write some pixels
# # read some pixels
# set_window(0, 0, 10, 10)
# print(cmd_read(0x2E, 11 * 11 * 2))
# # clean up
# cmd_write(0x10, b"") # SLPIN 0x10
# time.sleep(0.1)
# SERIAL.close()

@ -0,0 +1,64 @@
import tkinter as tk
class EditBoxComponent(tk.Frame):
def __init__(self, master, max, label):
super().__init__(master)
self.max = max
self.label = tk.Label(self, text=label)
self.label.pack(side="bottom")
self.edit_box = tk.Entry(self, width=5)
self.edit_box.pack(side="bottom")
self.bar = tk.Canvas(self, width=10, height=64)
self.bar.pack(side="top")
self.edit_box.bind("<KeyRelease>", self.update_bar)
def set_value(self, value):
value = max(0, min(self.max, value))
self.edit_box.delete(0, tk.END)
self.edit_box.insert(0, str(value))
self.bar.delete("all")
value_scaled = int(value * 64 / self.max)
self.bar.create_rectangle(0, 64 - value_scaled, 10, 64, fill="blue")
def update_bar(self, event):
# Update bar based on current value in edit box
try:
value = int(self.edit_box.get())
except ValueError:
value = 0
# If up arrow key is pressed, increase value by 1
if event.keysym == "Up":
value += 1
# If down arrow key is pressed, decrease value by 1
elif event.keysym == "Down":
value -= 1
self.set_value(value)
class EditBoxGUI:
def __init__(self):
self.root = tk.Tk()
self.root.title("Edit Box GUI")
self.edit_box_components = []
# Create empty labels to reserve space for the bars
for i in range(17):
label = tk.Label(self.root, text=" ")
label.grid(row=0, column=i)
for i in range(17):
# Create edit box component
edit_box_component = EditBoxComponent(self.root, 64, f"VP{i+1}")
edit_box_component.grid(row=1, column=i)
self.edit_box_components.append(edit_box_component)
self.root.mainloop()
if __name__ == "__main__":
gui = EditBoxGUI()

@ -37,61 +37,52 @@
#include "memzero.h"
enum { VCP_IFACE = 0x00 };
#define BUFSIZE 32768
static void vcp_intr(void) {
display_clear();
ensure(secfalse, "vcp_intr");
}
enum { VCP_IFACE = 0x00 };
static void vcp_puts(const char *s, size_t len) {
int r = usb_vcp_write_blocking(VCP_IFACE, (const uint8_t *)s, len, -1);
(void)r;
}
// static void vcp_intr(void) {
// display_clear();
// ensure(secfalse, "vcp_intr");
// }
static char vcp_getchar(void) {
uint8_t c = 0;
int r = usb_vcp_read_blocking(VCP_IFACE, &c, 1, -1);
(void)r;
return (char)c;
}
static void vcp_readpacket() {
static uint8_t cmdbuf[4];
static uint8_t buf[BUFSIZE];
int r = usb_vcp_read_blocking(VCP_IFACE, cmdbuf, 4, -1);
if (r != 4) {
return;
}
uint16_t len = *(uint16_t*)(cmdbuf + 2);
ensure(sectrue * (len <= sizeof(buf)), "vcp_readpacket: len too big");
bool read = cmdbuf[0];
uint8_t cmd = cmdbuf[1];
static void vcp_readline(char *buf, size_t len) {
for (;;) {
char c = vcp_getchar();
if (c == '\r') {
vcp_puts("\r\n", 2);
break;
if (cmd > 0) {
CMD(cmd);
}
if (read) {
for (int i = 0; i < len; i++) {
buf[i] = *DISPLAY_DATA_ADDRESS;
}
if (c < 32 || c > 126) { // not printable
continue;
r = usb_vcp_write_blocking(VCP_IFACE, buf, len, -1);
ensure(sectrue * (r == len), "vcp_readpacket: read data");
} else {
size_t idx = 0;
while (idx < len) {
r = usb_vcp_read_blocking(VCP_IFACE, buf + idx, len - idx, -1);
idx += r;
}
if (len > 1) { // leave space for \0
*buf = c;
buf++;
len--;
vcp_puts(&c, 1);
for (int i = 0; i < len; i++) {
DATA(buf[i]);
}
}
if (len > 0) {
*buf = '\0';
}
}
static void vcp_printf(const char *fmt, ...) {
static char buf[128];
va_list va;
va_start(va, fmt);
int r = mini_vsnprintf(buf, sizeof(buf), fmt, va);
va_end(va);
vcp_puts(buf, r);
vcp_puts("\r\n", 2);
}
static void usb_init_all(void) {
enum {
VCP_PACKET_LEN = 64,
VCP_BUFFER_LEN = 1024,
VCP_BUFFER_LEN = BUFSIZE,
};
static const usb_dev_info_t dev_info = {
@ -121,8 +112,8 @@ static void usb_init_all(void) {
.rx_buffer = rx_buffer,
.tx_buffer_len = VCP_BUFFER_LEN,
.rx_buffer_len = VCP_BUFFER_LEN,
.rx_intr_fn = vcp_intr,
.rx_intr_byte = 3, // Ctrl-C
// .rx_intr_fn = vcp_intr,
// .rx_intr_byte = 3, // Ctrl-C
.iface_num = VCP_IFACE,
.data_iface_num = 0x01,
.ep_cmd = 0x82,
@ -145,229 +136,6 @@ static void draw_border(int width, int padding) {
display_refresh();
}
static void test_border(void) {
draw_border(2, 0);
vcp_printf("OK");
}
static void test_display(const char *colors) {
display_clear();
size_t l = strlen(colors);
size_t w = DISPLAY_RESX / l;
for (size_t i = 0; i < l; i++) {
uint16_t c = 0x0000; // black
switch (colors[i]) {
case 'R':
c = 0xF800;
break;
case 'G':
c = 0x07E0;
break;
case 'B':
c = 0x001F;
break;
case 'W':
c = 0xFFFF;
break;
}
display_bar(i * w, 0, i * w + w, 240, c);
}
display_refresh();
vcp_printf("OK");
}
static secbool touch_click_timeout(uint32_t *touch, uint32_t timeout_ms) {
uint32_t deadline = HAL_GetTick() + timeout_ms;
uint32_t r = 0;
while (touch_read())
;
while ((touch_read() & TOUCH_START) == 0) {
if (HAL_GetTick() > deadline) return secfalse;
}
while (((r = touch_read()) & TOUCH_END) == 0) {
if (HAL_GetTick() > deadline) return secfalse;
}
while (touch_read())
;
*touch = r;
return sectrue;
}
static void test_touch(const char *args) {
int column = args[0] - '0';
int timeout = args[1] - '0';
display_clear();
switch (column) {
case 1:
display_bar(0, 0, 120, 120, 0xFFFF);
break;
case 2:
display_bar(120, 0, 120, 120, 0xFFFF);
break;
case 3:
display_bar(120, 120, 120, 120, 0xFFFF);
break;
default:
display_bar(0, 120, 120, 120, 0xFFFF);
break;
}
display_refresh();
touch_power_on();
uint32_t evt = 0;
if (touch_click_timeout(&evt, timeout * 1000)) {
uint16_t x = touch_unpack_x(evt);
uint16_t y = touch_unpack_y(evt);
vcp_printf("OK %d %d", x, y);
} else {
vcp_printf("ERROR TIMEOUT");
}
display_clear();
display_refresh();
touch_power_off();
}
static void test_sensitivity(const char *args) {
int v = atoi(args);
touch_power_on();
touch_sensitivity(v & 0xFF);
display_clear();
display_refresh();
for (;;) {
uint32_t evt = touch_read();
if (evt & TOUCH_START || evt & TOUCH_MOVE) {
int x = touch_unpack_x(evt);
int y = touch_unpack_y(evt);
display_clear();
display_bar(x - 48, y - 48, 96, 96, 0xFFFF);
display_refresh();
} else if (evt & TOUCH_END) {
display_clear();
display_refresh();
}
}
touch_power_off();
}
static void test_pwm(const char *args) {
int v = atoi(args);
display_backlight(v);
display_refresh();
vcp_printf("OK");
}
static void test_sd(void) {
#define BLOCK_SIZE (32 * 1024)
static uint32_t buf1[BLOCK_SIZE / sizeof(uint32_t)];
static uint32_t buf2[BLOCK_SIZE / sizeof(uint32_t)];
if (sectrue != sdcard_is_present()) {
vcp_printf("ERROR NOCARD");
return;
}
ensure(sdcard_power_on(), NULL);
if (sectrue != sdcard_read_blocks(buf1, 0, BLOCK_SIZE / SDCARD_BLOCK_SIZE)) {
vcp_printf("ERROR sdcard_read_blocks (0)");
goto power_off;
}
for (int j = 1; j <= 2; j++) {
for (int i = 0; i < BLOCK_SIZE / sizeof(uint32_t); i++) {
buf1[i] ^= 0xFFFFFFFF;
}
if (sectrue !=
sdcard_write_blocks(buf1, 0, BLOCK_SIZE / SDCARD_BLOCK_SIZE)) {
vcp_printf("ERROR sdcard_write_blocks (%d)", j);
goto power_off;
}
HAL_Delay(1000);
if (sectrue !=
sdcard_read_blocks(buf2, 0, BLOCK_SIZE / SDCARD_BLOCK_SIZE)) {
vcp_printf("ERROR sdcard_read_blocks (%d)", j);
goto power_off;
}
if (0 != memcmp(buf1, buf2, sizeof(buf1))) {
vcp_printf("ERROR DATA MISMATCH");
goto power_off;
}
}
vcp_printf("OK");
power_off:
sdcard_power_off();
}
static void test_wipe(void) {
// erase start of the firmware (metadata) -> invalidate FW
ensure(flash_unlock_write(), NULL);
for (int i = 0; i < 1024 / sizeof(uint32_t); i++) {
ensure(flash_write_word(FLASH_SECTOR_FIRMWARE_START, i * sizeof(uint32_t),
0x00000000),
NULL);
}
ensure(flash_lock_write(), NULL);
display_clear();
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY / 2 + 10, "WIPED", -1,
FONT_BOLD, COLOR_WHITE, COLOR_BLACK);
display_refresh();
vcp_printf("OK");
}
static void test_sbu(const char *args) {
secbool sbu1 = sectrue * (args[0] == '1');
secbool sbu2 = sectrue * (args[1] == '1');
sbu_set(sbu1, sbu2);
vcp_printf("OK");
}
static void test_otp_read(void) {
uint8_t data[32];
memzero(data, sizeof(data));
ensure(flash_otp_read(FLASH_OTP_BLOCK_BATCH, 0, data, sizeof(data)), NULL);
// strip trailing 0xFF
for (size_t i = 0; i < sizeof(data); i++) {
if (data[i] == 0xFF) {
data[i] = 0x00;
break;
}
}
// use (null) for empty data
if (data[0] == 0x00) {
vcp_printf("OK (null)");
} else {
vcp_printf("OK %s", (const char *)data);
}
}
static void test_otp_write(const char *args) {
char data[32];
memzero(data, sizeof(data));
strncpy(data, args, sizeof(data) - 1);
ensure(flash_otp_write(FLASH_OTP_BLOCK_BATCH, 0, (const uint8_t *)data,
sizeof(data)),
NULL);
ensure(flash_otp_lock(FLASH_OTP_BLOCK_BATCH), NULL);
vcp_printf("OK");
}
static secbool startswith(const char *s, const char *prefix) {
return sectrue * (0 == strncmp(s, prefix, strlen(prefix)));
}
#define BACKLIGHT_NORMAL 150
int main(void) {
@ -393,48 +161,48 @@ int main(void) {
display_fade(0, BACKLIGHT_NORMAL, 1000);
char line[128];
for (;;) { vcp_readpacket(); }
for (;;) {
vcp_readline(line, sizeof(line));
// for (;;) {
// vcp_readline(line, sizeof(line));
if (startswith(line, "PING")) {
vcp_printf("OK");
// if (startswith(line, "PING")) {
// vcp_printf("OK");
} else if (startswith(line, "BORDER")) {
test_border();
// } else if (startswith(line, "BORDER")) {
// test_border();
} else if (startswith(line, "DISP ")) {
test_display(line + 5);
// } else if (startswith(line, "DISP ")) {
// test_display(line + 5);
} else if (startswith(line, "TOUCH ")) {
test_touch(line + 6);
// } else if (startswith(line, "TOUCH ")) {
// test_touch(line + 6);
} else if (startswith(line, "SENS ")) {
test_sensitivity(line + 5);
// } else if (startswith(line, "SENS ")) {
// test_sensitivity(line + 5);
} else if (startswith(line, "PWM ")) {
test_pwm(line + 4);
// } else if (startswith(line, "PWM ")) {
// test_pwm(line + 4);
} else if (startswith(line, "SD")) {
test_sd();
// } else if (startswith(line, "SD")) {
// test_sd();
} else if (startswith(line, "SBU ")) {
test_sbu(line + 4);
// } else if (startswith(line, "SBU ")) {
// test_sbu(line + 4);
} else if (startswith(line, "OTP READ")) {
test_otp_read();
// } else if (startswith(line, "OTP READ")) {
// test_otp_read();
} else if (startswith(line, "OTP WRITE ")) {
test_otp_write(line + 10);
// } else if (startswith(line, "OTP WRITE ")) {
// test_otp_write(line + 10);
} else if (startswith(line, "WIPE")) {
test_wipe();
// } else if (startswith(line, "WIPE")) {
// test_wipe();
} else {
vcp_printf("UNKNOWN");
}
}
// } else {
// vcp_printf("UNKNOWN");
// }
// }
return 0;
}

Loading…
Cancel
Save