diff --git a/src/config.c b/src/config.c index 8aecc61..dbfcb1a 100644 --- a/src/config.c +++ b/src/config.c @@ -7,6 +7,7 @@ #include "scode.h" #include "log.h" +/* command line options for UPIWIN */ static const struct option long_options[] = { {"framebuffer", required_argument, 0, 'F'}, {"help", no_argument, 0, 'h'}, @@ -16,6 +17,7 @@ static const struct option long_options[] = { static const char *short_options = "F:hT:"; +/* printed to stdout when upiwin is executed with -h/--help option */ static const char *helptext = "UPIWIN - Micro Pi Windows server program\n\n" "Usage: upiwin [options] scriptname [scriptargs]\n\n" @@ -25,19 +27,20 @@ static const char *helptext = " -T,--touchscreen - Specifies the touchscreen device name\n" ""; -#define EXITFUNCBLOCK_FUNCCOUNT 64 +#define EXITFUNCBLOCK_FUNCCOUNT 64 /* number of exit functions per function block */ +/* exit functions are stored in these data blocks */ typedef struct tagEXITFUNCBLOCK { - struct tagEXITFUNCBLOCK *next; - int num_funcs; - PEXITFUNC funcs[EXITFUNCBLOCK_FUNCCOUNT]; + struct tagEXITFUNCBLOCK *next; /* chained in single linked list */ + int num_funcs; /* number of functions this block contains */ + PEXITFUNC funcs[EXITFUNCBLOCK_FUNCCOUNT]; /* pointers to functions */ } EXITFUNCBLOCK, *PEXITFUNCBLOCK; /* The global configuration data */ GLOBAL_CONFIG Gconfig; -static PEXITFUNCBLOCK exitfuncs = NULL; +static PEXITFUNCBLOCK exitfuncs = NULL; /* pointer to head of exit function chain */ static void run_exit_funcs(void) { @@ -50,6 +53,7 @@ static void run_exit_funcs(void) exitfuncs = p->next; for (i = p->num_funcs - 1; i >= 0; i--) { + /* execute functions in LIFO order */ ASSERT(p->funcs[i]); (*(p->funcs[i]))(); } @@ -59,6 +63,7 @@ static void run_exit_funcs(void) static void init_defaults(void) { + memset(&Gconfig, 0, sizeof(GLOBAL_CONFIG)); Gconfig.framebuffer_device = "/dev/fb1"; Gconfig.touchscreen_device = "/dev/input/touchscreen"; Gconfig.button_debounce = 100; @@ -79,7 +84,7 @@ static HRESULT parse_cmdline(int argc, char *argv[], GLOBAL_CONFIG *parsed) break; switch (c) { - case 'F': + case 'F': /* frame buffer device name */ pstr = strdup(optarg); if (!pstr) { @@ -91,11 +96,11 @@ static HRESULT parse_cmdline(int argc, char *argv[], GLOBAL_CONFIG *parsed) parsed->framebuffer_device = pstr; break; - case 'h': + case 'h': /* show help */ help = TRUE; break; - case 'T': + case 'T': /* touchscreen device name */ pstr = strdup(optarg); if (!pstr) { @@ -138,10 +143,16 @@ HRESULT Config_setup(int argc, char *argv[]) Log(LFATAL, "Unable to set up exit function mechanism"); return E_FAIL; } + + /* set defaults */ init_defaults(); + + /* evaluate command line */ hr = parse_cmdline(argc, argv, &from_commandline); if (hr != S_OK) return hr; + + /* command line overrides everything */ overlay_config(&from_commandline); return S_OK; } diff --git a/src/config.h b/src/config.h index 3955d9c..e543bd4 100644 --- a/src/config.h +++ b/src/config.h @@ -5,14 +5,15 @@ typedef void (*PEXITFUNC)(void); +/* global configuration data for UPIWIN */ typedef struct tagGLOBAL_CONFIG { - PCSTR framebuffer_device; - PCSTR touchscreen_device; - UINT32 button_debounce; - UINT32 sys_mq_length; + PCSTR framebuffer_device; /* name of frame buffer device */ + PCSTR touchscreen_device; /* name of touchscreen device */ + UINT32 button_debounce; /* minimum time between button up and next button down (ms) */ + UINT32 sys_mq_length; /* length of system message queue */ } GLOBAL_CONFIG; -extern GLOBAL_CONFIG Gconfig; +extern GLOBAL_CONFIG Gconfig; /* one global configuration to rule them all */ extern HRESULT Config_setup(int argc, char *argv[]); extern HRESULT Config_exitfunc(PEXITFUNC pfn); diff --git a/src/fbinit.c b/src/fbinit.c index 24cbe7e..11bbcd3 100644 --- a/src/fbinit.c +++ b/src/fbinit.c @@ -16,12 +16,13 @@ extern uint8_t _binary_splash_bin_start[]; extern uint8_t _binary_splash_bin_end; extern uint8_t _binary_splash_bin_size; -static int fb_fd = -1; +static int fb_fd = -1; /* framebuffer file descriptor */ +/* frame buffer information */ static FBINFO local_info; PCFBINFO Fb_Info = &local_info; -UINT16 *Fb_Ptr = NULL; +UINT16 *Fb_Ptr = NULL; /* pointer to memory-mapped frame buffer */ inline static UINT16 makemask(unsigned offset, unsigned length) { @@ -30,12 +31,11 @@ inline static UINT16 makemask(unsigned offset, unsigned length) static void do_cleanup(void) { - /* additional cleanup here */ - + /* black out the display */ memset(Fb_Ptr, 0, local_info.screenbytes); - munmap((void *)Fb_Ptr, local_info.screenbytes); - Fb_Ptr = NULL; + munmap((void *)Fb_Ptr, local_info.screenbytes); + Fb_Ptr = NULL; close(fb_fd); fb_fd = -1; } @@ -50,10 +50,11 @@ HRESULT Fb_setup(void) if (fb_fd == -1) { hr = ERRNO_AS_SCODE; - Log(LFATAL, "Unable to open framebuffer (%08X)", hr); + Log(LFATAL, "Unable to open framebuffer device %s (%08X)", Gconfig.framebuffer_device, hr); return hr; } + /* fixed info is needed to get the memory parameters for the display */ if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fixed)) { hr = ERRNO_AS_SCODE; @@ -64,6 +65,7 @@ HRESULT Fb_setup(void) local_info.linebytes = fixed.line_length; local_info.screenbytes = fixed.smem_len; + /* variable info is used to get scren geometry and color info */ if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &var)) { hr = ERRNO_AS_SCODE; @@ -100,8 +102,6 @@ HRESULT Fb_setup(void) /* display the splash screen */ memcpy(Fb_Ptr, _binary_splash_bin_start, (size_t)(&_binary_splash_bin_size)); - /* additional setup here */ - hr = Config_exitfunc(do_cleanup); if (FAILED(hr)) do_cleanup(); diff --git a/src/fbinit.h b/src/fbinit.h index 8638317..66e4f35 100644 --- a/src/fbinit.h +++ b/src/fbinit.h @@ -3,28 +3,29 @@ #include "wintype.h" +/* info about the frame buffer */ typedef struct tagFBINFO { - UINT32 width; - UINT32 height; - UINT32 virtual_width; - UINT32 virtual_height; - UINT32 bpp; - UINT32 linebytes; - UINT32 screenbytes; - UINT16 red_offset; - UINT16 red_length; - UINT16 red_mask; - UINT16 green_offset; - UINT16 green_length; - UINT16 green_mask; - UINT16 blue_offset; - UINT16 blue_length; - UINT16 blue_mask; + UINT32 width; /* screen width */ + UINT32 height; /* screen height */ + UINT32 virtual_width; /* virtual screen width */ + UINT32 virtual_height; /* virtual screen height */ + UINT32 bpp; /* bits per pixel (16) */ + UINT32 linebytes; /* number of bytes per line */ + UINT32 screenbytes; /* number of bytes for the entire screen */ + UINT16 red_offset; /* offset of "red" bits within pixel word (11) */ + UINT16 red_length; /* number of "red" bits within pixel word (5) */ + UINT16 red_mask; /* mask for the "red" bits in a pixel word */ + UINT16 green_offset; /* offset of "green" bits within pixel word (5) */ + UINT16 green_length; /* number of "green" bits within pixel word (6) */ + UINT16 green_mask; /* mask for the "green" bits in a pixel word */ + UINT16 blue_offset; /* offset of "blue" bits within pixel word (0) */ + UINT16 blue_length; /* number of "blue" bits within pixel word (5) */ + UINT16 blue_mask; /* mask for the "blue" bits in a pixel word */ } FBINFO; typedef const FBINFO * const PCFBINFO; -extern PCFBINFO Fb_Info; -extern UINT16 *Fb_Ptr; +extern PCFBINFO Fb_Info; /* pointer to screen information */ +extern UINT16 *Fb_Ptr; /* pointer to memory-mapped screen buffer */ extern HRESULT Fb_setup(void); extern void Fb_clear(void); diff --git a/src/fbprimitive.c b/src/fbprimitive.c index 805dcd4..f434226 100644 --- a/src/fbprimitive.c +++ b/src/fbprimitive.c @@ -25,6 +25,7 @@ void Fb_line(INT32 x1, INT32 y1, INT32 x2, INT32 y2, UINT16 color, BOOL xor) INT32 dx = x2 - x1; INT32 dy = y2 - y1; + /* uses Bresenham's line algorithm with fixed-point arithmetic */ if (ABS(dx) < ABS(dy)) { if (y1 > y2) diff --git a/src/fbprimitive.h b/src/fbprimitive.h index fddd6c8..8f0ea8e 100644 --- a/src/fbprimitive.h +++ b/src/fbprimitive.h @@ -3,6 +3,7 @@ #include "wintype.h" +/* Some predefined "primitive" color values */ #define FBPRIMCLR_BLACK 0x0000 #define FBPRIMCLR_RED 0xF800 #define FBPRIMCLR_GREEN 0x07E0 diff --git a/src/gpio.c b/src/gpio.c index b4e8758..dfe0710 100644 --- a/src/gpio.c +++ b/src/gpio.c @@ -5,13 +5,14 @@ #include "scode.h" #include "gpio.h" +/* GPIO lines used by various peripheral devices */ #define GLINE_BUTTON1 17 #define GLINE_BUTTON2 22 #define GLINE_BUTTON3 23 #define GLINE_BUTTON4 27 #define GLINE_BACKLIGHT 18 -#define PWM_BACKLIGHT 0 +#define PWM_BACKLIGHT 0 /* PWM channel used for backlight */ static void do_cleanup(void) { diff --git a/src/gpio.h b/src/gpio.h index 24c7398..707393a 100644 --- a/src/gpio.h +++ b/src/gpio.h @@ -3,14 +3,15 @@ #include "wintype.h" -#define GPIO_BUTTON_COUNT 4 +#define GPIO_BUTTON_COUNT 4 /* number of GPIO buttons we have */ +/* state flags for the GPIO buttons */ #define GRB_STATE_BUTTON1 (1 << 0) #define GRB_STATE_BUTTON2 (1 << 1) #define GRB_STATE_BUTTON3 (1 << 2) #define GRB_STATE_BUTTON4 (1 << 3) -#define GSB_BACKLIGHT_MAX 1023 +#define GSB_BACKLIGHT_MAX 1023 /* maximum level for backlight */ extern HRESULT Gpio_setup(void); extern UINT32 Gpio_read_buttons(void); diff --git a/src/log.c b/src/log.c index 81afc30..e6ab3c6 100644 --- a/src/log.c +++ b/src/log.c @@ -4,8 +4,11 @@ #include #include "log.h" +/* string equivalents to the severity values */ static const char *severities[] = { "FATAL", "ERROR", "WARN ", "INFO ", "DEBUG" }; +static FILE *logfile = stdout; /* log file pointer */ + void Log(int level, const char *format, ...) { va_list argp; @@ -21,7 +24,7 @@ void Log(int level, const char *format, ...) gettimeofday(&tv, NULL); localtime_r(&(tv.tv_sec), &tm); strftime(timestamp, 32, "%F %T", &tm); - printf("%s.%06u %s %s\n", timestamp, tv.tv_usec, severities[level], buf); + fprintf(logfile, "%s.%06u %s %s\n", timestamp, tv.tv_usec, severities[level], buf); } void Log_assert_failed(const char *test, const char *file, int line) diff --git a/src/log.h b/src/log.h index 82145f5..a0871ca 100644 --- a/src/log.h +++ b/src/log.h @@ -1,18 +1,21 @@ #ifndef __LOG_H_INCLUDED #define __LOG_H_INCLUDED -#define LFATAL 0 -#define LERROR 1 -#define LWARN 2 -#define LINFO 3 -#define LDEBUG 4 +/* Logging level severities */ +#define LFATAL 0 /* fatal error */ +#define LERROR 1 /* error */ +#define LWARN 2 /* warning */ +#define LINFO 3 /* information */ +#define LDEBUG 4 /* debugging */ extern void Log(int level, const char *format, ...); extern void Log_assert_failed(const char *test, const char *file, int line); +/* Current file name definitions for assert macros */ #define THIS_FILE __FILE__ #define DECLARE_THIS_FILE() static const char THIS_FILE[] = __FILE__ +/* Assert macros */ #ifdef DEBUG_ASSERT #define ASSERT(x) ((x) ? (void)0 : Log_assert_failed(#x, THIS_FILE, __LINE__)) #define VERIFY(x) ASSERT(x) diff --git a/src/main.c b/src/main.c index 459ae84..7bdd267 100644 --- a/src/main.c +++ b/src/main.c @@ -35,6 +35,7 @@ int main(int argc, char *argv[]) MSG msg; char *tmp; + /* initialization sequence */ Time_init(); hr = Config_setup(argc, argv); if (FAILED(hr)) @@ -48,7 +49,7 @@ int main(int argc, char *argv[]) if (FAILED(Sys_enable_input())) return EXIT_FAILURE; Log(LINFO, "Pausing at startup."); - sleep(5); /* wait to show off splash screen */ + sleep(3); /* wait to show off splash screen */ Fb_clear(); /* temporary drawing here */ diff --git a/src/msg_queue.h b/src/msg_queue.h index 1ba3626..10c49ae 100644 --- a/src/msg_queue.h +++ b/src/msg_queue.h @@ -1,22 +1,25 @@ #ifndef __MSG_QUEUE_H_INCLUDED #define __MSG_QUEUE_H_INCLUDED +#include #include "wintype.h" #include "msg.h" +/* internal structure of a message queue */ typedef struct tagMSG_QUEUE { - struct tagMSG_QUEUE *next; - PMSG startbound; - PMSG endbound; - PMSG head; - PMSG tail; - UINT32 nentries; - pthread_mutex_t mutex; - MSG messagestore[0]; + struct tagMSG_QUEUE *next; /* allow us to be in a singly-linked list */ + PMSG startbound; /* start boundary for message buffer */ + PMSG endbound; /* end boundary for message buffer */ + PMSG head; /* head pointer of message queue */ + PMSG tail; /* tail pointer of message queue */ + UINT32 nentries; /* number of entries possible in message buffer */ + pthread_mutex_t mutex; /* controls access to queue from multiple threads */ + MSG messagestore[0]; /* message buffer */ } MSG_QUEUE, *PMSG_QUEUE; -#define PEEK_REMOVE 0x0001 -#define PEEK_NOREMOVE 0x0000 +/* flags to Mq_peek */ +#define PEEK_REMOVE 0x0001 /* remove message if found */ +#define PEEK_NOREMOVE 0x0000 /* do not remove message if found */ extern PMSG_QUEUE Mq_alloc(UINT32 nentries); extern void Mq_destroy(PMSG_QUEUE queue); diff --git a/src/sysinput.c b/src/sysinput.c index dcec699..530489c 100644 --- a/src/sysinput.c +++ b/src/sysinput.c @@ -13,20 +13,22 @@ #include "gpio.h" #include "time_func.h" -#define INPUT_EVENT_BATCH 16 +#define INPUT_EVENT_BATCH 16 /* number of events to retrieve from touchscreen at once */ -PMSG_QUEUE Sys_Queue = NULL; +PMSG_QUEUE Sys_Queue = NULL; /* system message queue */ +static int ts_fd = 0; /* file descriptor for touchscreen */ -static pthread_t ithread; -static volatile sig_atomic_t running = 1; -static int ts_fd = 0; +static pthread_t ithread; /* input thread handle */ +static volatile sig_atomic_t running = 1; /* "running" flag for input thread */ -static UINT32 last_bstate = 0; -static TIMESTAMP button_event_ok[GPIO_BUTTON_COUNT]; +/* Local data for poll_buttons() */ +static UINT32 last_bstate = 0; /* previous button state */ +static TIMESTAMP button_event_ok[GPIO_BUTTON_COUNT]; /* timestamps to debounce events */ -static UINT_PTR touch_x = 0; -static UINT_PTR touch_y = 0; -static UINT32 touch_nextmsg = WM_TOUCHMOVE; +/* Local data for poll_touchscreen() */ +static UINT_PTR touch_x = 0; /* X coordinate to send with next message */ +static UINT_PTR touch_y = 0; /* Y coordinate to send with next message */ +static UINT32 touch_nextmsg = WM_TOUCHMOVE; /* identifier of next message to send */ static void poll_buttons(void) { @@ -44,9 +46,10 @@ static void poll_buttons(void) for (attr = 1, mask = GRB_STATE_BUTTON1; attr <= GPIO_BUTTON_COUNT; attr++, mask <<= 1) { if (now < button_event_ok[attr - 1]) - continue; + continue; /* this is a "contact bounce" event, don't bother */ if (up & mask) { + /* reset contact bounce timer - only seems to happen after button releases */ button_event_ok[attr - 1] = now + Gconfig.button_debounce; Mq_post1(Sys_Queue, 0, WM_HWBUTTONUP, attr); } @@ -75,10 +78,12 @@ static void poll_touchscreen(void) Log(LERROR, "Unexpected end of file reading from touchscreen device"); return; } + nev = nb / sizeof(struct input_event); xerrno = nev * sizeof(struct input_event); if (nb > xerrno) Log(LERROR, "read %d bytes from touchscreen but we can only use %d", nb, xerrno); + for (i=0; i #include "time_func.h" -static TIMESTAMP start_timestamp = 0; +static TIMESTAMP start_timestamp = 0; /* time since epoch at start of run */ TIMESTAMP Time_since_epoch(void) { diff --git a/src/wintype.h b/src/wintype.h index 96c3645..34bdf50 100644 --- a/src/wintype.h +++ b/src/wintype.h @@ -32,7 +32,7 @@ #define INT64_BITS 64 #define UINT64_BITS 64 -#define LOG_PTRSIZE 2 /* log2(sizeof(void *)) */ +#define LOG_PTRSIZE 2 /* log2(sizeof(void *)) */ #define LOG_INTSIZE 2 /* log2(sizeof(int)) */ #define LOG_UINTSIZE 2 /* log2(sizeof(UINT32)) */