69 lines
3.4 KiB
Python
69 lines
3.4 KiB
Python
from pathlib import Path
|
|
import subprocess, tempfile, re
|
|
src=(Path(__file__).resolve().parents[1]/'components/platform/src/lcd_direct.c').read_text()
|
|
def function(name):
|
|
# Locate definition rather than the forward declaration.
|
|
matches=list(re.finditer(r'static [^;{}]+\b'+name+r'\([^;{}]*\)\s*\{',src))
|
|
assert len(matches)==1,name
|
|
start=matches[0].start(); p=src.index('{',start); depth=1; end=p+1
|
|
while depth:
|
|
if src[end]=='{':depth+=1
|
|
if src[end]=='}':depth-=1
|
|
end+=1
|
|
return src[start:end]
|
|
table=re.search(r'static const uint8_t s_clock_glyph_rows.*?\n};',src,re.S).group(0)
|
|
prefix='''#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#define LCD_DIRECT_WIDTH 320
|
|
#define LCD_DIRECT_CLOCK_GLYPH_HEIGHT 7
|
|
#define CONFIG_TQ_SCREEN_SWAP_COLOR_BYTES 1
|
|
#define portENTER_CRITICAL(x) ((void)0)
|
|
#define portEXIT_CRITICAL(x) ((void)0)
|
|
typedef struct {bool low_battery_visible, charging_visible, battery_valid; uint8_t battery_percent;} platform_lcd_status_overlay_t;
|
|
static platform_lcd_status_overlay_t s_status_overlay;
|
|
#define PLATFORM_LCD_PRESENTATION_IDLE 0
|
|
typedef struct { int kind; } lcd_direct_request_t;
|
|
static lcd_direct_request_t s_pending;
|
|
static bool s_pending_valid, s_stop_requested;
|
|
'''
|
|
test='''int main(void) {
|
|
uint16_t full[320*240+2], blocks[320*240+2];
|
|
for (unsigned valid=0;valid<2;++valid)
|
|
for (unsigned charge=0;charge<2;++charge)
|
|
for (unsigned low=0;low<2;++low)
|
|
for (unsigned percent=0;percent<=100;++percent) {
|
|
s_status_overlay=(platform_lcd_status_overlay_t){low,charge,valid,percent};
|
|
for (unsigned i=0;i<320*240+2;++i) full[i]=blocks[i]=0x1234;
|
|
lcd_direct_overlay_battery(full+1,0,240);
|
|
for(unsigned row=0;row<240;row+=8)
|
|
lcd_direct_overlay_battery(blocks+1+row*320,row,8);
|
|
assert(memcmp(full,blocks,sizeof(full))==0);
|
|
assert(full[0]==0x1234 && full[320*240+1]==0x1234);
|
|
for(unsigned y=0;y<240;++y) for(unsigned x=0;x<320;++x) {
|
|
if(x<212 || y<13 || y>=34) assert(full[1+y*320+x]==0x1234);
|
|
}
|
|
uint16_t expected=lcd_direct_swap_color(charge?0x07e0:low?0xf800:0xffff);
|
|
assert(full[1+14*320+288]==expected);
|
|
unsigned fill=percent*16/100;
|
|
if(valid && !charge && fill) assert(full[1+17*320+291]==expected);
|
|
if(!valid) assert(full[1+17*320+291]==0);
|
|
}
|
|
for (unsigned pending=0;pending<2;++pending)
|
|
for (unsigned stopping=0;stopping<2;++stopping) {
|
|
s_pending=(lcd_direct_request_t){99};
|
|
s_pending_valid=pending; s_stop_requested=stopping;
|
|
lcd_direct_queue_idle_if_available();
|
|
assert(s_pending.kind==((pending || stopping)?99:PLATFORM_LCD_PRESENTATION_IDLE));
|
|
assert(s_pending_valid==(pending || !stopping));
|
|
}
|
|
puts("PASS: idle queue preserves pending requests and stop; 808 battery combinations; full-frame/8-row equivalence, bounds, colors and fill");
|
|
}'''
|
|
with tempfile.TemporaryDirectory(prefix='lucky-hud-') as tmp:
|
|
c=Path(tmp)/'hud.c'; exe=Path(tmp)/'hud'
|
|
c.write_text(prefix+table+'\n'+'\n'.join(function(n) for n in ['lcd_direct_swap_color','lcd_direct_clock_glyph_index','lcd_direct_hud_pixel','lcd_direct_overlay_battery','lcd_direct_queue_idle_if_available'])+'\n'+test)
|
|
subprocess.run(['clang','-std=c11','-fsanitize=address,undefined','-g',str(c),'-o',str(exe)],check=True)
|
|
subprocess.run([str(exe)],check=True)
|