diff --git a/server/drivers/lcdm001.c b/server/drivers/lcdm001.c index 2812d53..1081136 100644 --- a/server/drivers/lcdm001.c +++ b/server/drivers/lcdm001.c @@ -64,12 +64,24 @@ //#include "configfile.h" -int fd = -1; -static char icon_char = '@'; -static char pause_key = DOWN_KEY, back_key = LEFT_KEY, forward_key = RIGHT_KEY, main_menu_key = UP_KEY; -static char *framebuf = NULL; -static int width = LCD_DEFAULT_WIDTH; -static int height = LCD_DEFAULT_HEIGHT; +typedef struct driver_private_data { + char device[200]; + int fd; + int speed; + + char icon_char; + + char pause_key; + char back_key; + char forward_key; + char main_menu_key; + + char *framebuf; + + int width; + int height; +} PrivateData; + // Vars for the server core MODULE_EXPORT char *api_version = API_VERSION; @@ -80,8 +92,6 @@ MODULE_EXPORT char *symbol_prefix = "lcdm001_"; static void lcdm001_cursorblink(Driver *drvthis, int on); static char lcdm001_parse_keypad_setting(Driver *drvthis, char * keyname, char * default_value); -#define ValidX(x) if ((x) > width) { (x) = width; } else (x) = (x) < 1 ? 1 : (x); -#define ValidY(y) if ((y) > height) { (y) = height; } else (y) = (y) < 1 ? 1 : (y); // Parse one key from the configfile static char lcdm001_parse_keypad_setting(Driver *drvthis, char * keyname, char * default_value) @@ -116,11 +126,13 @@ static char lcdm001_parse_keypad_setting(Driver *drvthis, char * keyname, char * static void lcdm001_cursorblink(Driver *drvthis, int on) { + PrivateData *p = drvthis->private_data; + if (on) { - write(fd, "~K1", 3); + write(p->fd, "~K1", 3); debug(RPT_INFO, "%s: cursorblink turned on", drvthis->name); } else { - write(fd, "~K0", 3); + write(p->fd, "~K0", 3); debug(RPT_INFO, "%s: cursorblink turned off", drvthis->name); } } @@ -135,48 +147,63 @@ lcdm001_cursorblink(Driver *drvthis, int on) MODULE_EXPORT int lcdm001_init (Driver *drvthis) { - char device[200]; - int speed = B38400; - struct termios portset; + PrivateData *p; + struct termios portset; - char out[5] = ""; + /* Allocate and store private data */ + p = (PrivateData *) calloc(1, sizeof(PrivateData)); + if (p == NULL) + return -1; + if (drvthis->store_private_ptr(drvthis, p)) + return -1; + + /* initialize private data */ + p->speed = B38400; + p->icon_char = '@'; + p->pause_key = DOWN_KEY; + p->back_key = LEFT_KEY; + p->forward_key = RIGHT_KEY; + p->main_menu_key = UP_KEY; + p->framebuf = NULL; + p->width = LCD_DEFAULT_WIDTH; + p->height = LCD_DEFAULT_HEIGHT; debug(RPT_INFO, "LCDM001: init(%p)", drvthis); - framebuf = malloc(width * height); - if (framebuf == NULL) { + p->framebuf = calloc(1, p->width * p->height); + if (p->framebuf == NULL) { report(RPT_ERR, "%s: unable to create framebuffer", drvthis->name); return -1; } - memset(framebuf, ' ', width * height); + memset(p->framebuf, ' ', p->width * p->height); // READ CONFIG FILE: // which serial device should be used - strncpy(device, drvthis->config_get_string(drvthis->name, "Device", 0, "/dev/lcd"), sizeof(device)); - device[sizeof(device)-1] = '\0'; - report(RPT_INFO, "%s: using Device %s", drvthis->name, device); + strncpy(p->device, drvthis->config_get_string(drvthis->name, "Device", 0, "/dev/lcd"), sizeof(p->device)); + p->device[sizeof(p->device)-1] = '\0'; + report(RPT_INFO, "%s: using Device %s", drvthis->name, p->device); // keypad settings - pause_key = lcdm001_parse_keypad_setting(drvthis, "PauseKey", "DownKey"); - back_key = lcdm001_parse_keypad_setting(drvthis, "BackKey", "LeftKey"); - forward_key = lcdm001_parse_keypad_setting(drvthis, "ForwardKey", "RightKey"); - main_menu_key = lcdm001_parse_keypad_setting(drvthis, "MainMenuKey", "UpKey"); + p->pause_key = lcdm001_parse_keypad_setting(drvthis, "PauseKey", "DownKey"); + p->back_key = lcdm001_parse_keypad_setting(drvthis, "BackKey", "LeftKey"); + p->forward_key = lcdm001_parse_keypad_setting(drvthis, "ForwardKey", "RightKey"); + p->main_menu_key = lcdm001_parse_keypad_setting(drvthis, "MainMenuKey", "UpKey"); // Set up io port correctly, and open it... - debug(RPT_DEBUG, "%s: Opening serial device: %s", __FUNCTION__, device); - fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); - if (fd == -1) { + debug(RPT_DEBUG, "%s: opening serial device: %s", __FUNCTION__, p->device); + p->fd = open(p->device, O_RDWR | O_NOCTTY | O_NDELAY); + if (p->fd == -1) { report(RPT_ERR, "%s: open(%d) failed (%s)", - drvthis->name, device, strerror(errno)); + drvthis->name, p->device, strerror(errno)); if (errno == EACCES) report(RPT_ERR, "%s: make sure you have rw access to %s!", - drvthis->name, device); + drvthis->name, p->device); return -1; } - report(RPT_INFO, "%s: opened display on %s", drvthis->name, device); + report(RPT_INFO, "%s: opened display on %s", drvthis->name, p->device); - tcgetattr(fd, &portset); + tcgetattr(p->fd, &portset); #ifdef HAVE_CFMAKERAW /* The easy way: */ cfmakeraw(&portset); @@ -189,18 +216,17 @@ lcdm001_init (Driver *drvthis) portset.c_cflag &= ~( CSIZE | PARENB | CRTSCTS ); portset.c_cflag |= CS8 | CREAD | CLOCAL; #endif - cfsetospeed(&portset, speed); - cfsetispeed(&portset, speed); - tcsetattr(fd, TCSANOW, &portset); - tcflush(fd, TCIOFLUSH); + cfsetospeed(&portset, p->speed); + cfsetispeed(&portset, p->speed); + tcsetattr(p->fd, TCSANOW, &portset); + tcflush(p->fd, TCIOFLUSH); // Reset and clear the LCDM001 - write(fd, "~C", 2); + write(p->fd, "~C", 2); //Set cursorblink default lcdm001_cursorblink(drvthis, DEFAULT_CURSORBLINK); // Turn all LEDs off - snprintf(out, sizeof(out), "\%cL%c%c", 126, 0, 0); - write(fd, out, 4); + lcdm001_output(drvthis, 0); report(RPT_DEBUG, "%s: init() done", drvthis->name); @@ -215,19 +241,23 @@ lcdm001_init (Driver *drvthis) MODULE_EXPORT void lcdm001_close (Driver *drvthis) { - if (framebuf != NULL) - free(framebuf); - framebuf = NULL; + PrivateData *p = drvthis->private_data; - if (fd >= 0) { - char out[5]; + if (p != NULL) { + if (p->framebuf != NULL) + free(p->framebuf); + p->framebuf = NULL; - //switch off all LEDs - snprintf(out, sizeof(out), "\%cL%c%c", 126, 0, 0); - write(fd, out, 4); - close(fd); - } - fd = -1; + if (p->fd >= 0) { + //switch off all LEDs + lcdm001_output(drvthis, 0); + close(p->fd); + } + p->fd = -1; + + free(p); + } + drvthis->store_private_ptr(drvthis, NULL); report(RPT_INFO, "%s: closed", drvthis->name); } @@ -238,7 +268,9 @@ lcdm001_close (Driver *drvthis) MODULE_EXPORT int lcdm001_width (Driver *drvthis) { - return width; + PrivateData *p = drvthis->private_data; + + return p->width; } ///////////////////////////////////////////////////////////////// @@ -247,7 +279,9 @@ lcdm001_width (Driver *drvthis) MODULE_EXPORT int lcdm001_height (Driver *drvthis) { - return height; + PrivateData *p = drvthis->private_data; + + return p->height; } ///////////////////////////////////////////////////////////////// @@ -256,8 +290,9 @@ lcdm001_height (Driver *drvthis) MODULE_EXPORT void lcdm001_clear (Driver *drvthis) { - if (framebuf != NULL) - memset(framebuf, ' ', (width * height)); + PrivateData *p = drvthis->private_data; + + memset(p->framebuf, ' ', p->width * p->height); /* instant clear is NOT neccessary, it only makes the display flicker */ //write(fd, "~C", 2); @@ -270,11 +305,13 @@ lcdm001_clear (Driver *drvthis) MODULE_EXPORT void lcdm001_flush (Driver *drvthis) { + PrivateData *p = drvthis->private_data; + // Next 4 lines are moved from draw_frame (Joris) //TODO: Check whether this is still correct - write(fd, framebuf, 80); + write(p->fd, p->framebuf, p->width * p->height); debug(RPT_DEBUG, "LCDM001: frame buffer flushed"); } @@ -286,19 +323,15 @@ lcdm001_flush (Driver *drvthis) MODULE_EXPORT void lcdm001_chr (Driver *drvthis, int x, int y, char c) { - int offset; - - ValidX(x); - ValidY(y); + PrivateData *p = drvthis->private_data; if (c == '\0') - c = icon_char; //heartbeat workaround + c = p->icon_char; //heartbeat workaround - // write to frame buffer y--; x--; // translate to 0-coords - offset = (y * width) + x; - framebuf[offset] = c; + if ((x >= 0) && (y >= 0) && (x < p->width) && (y < p->height)) + p->framebuf[(y * p->width) + x] = c; debug(RPT_DEBUG, "LCDM001: writing character %02X to position (%d,%d)", c, x, y); } @@ -310,18 +343,19 @@ lcdm001_chr (Driver *drvthis, int x, int y, char c) MODULE_EXPORT void lcdm001_string (Driver *drvthis, int x, int y, char *string) { - int offset, siz; - - ValidX(x); - ValidY(y); + PrivateData *p = drvthis->private_data; + int i; x--; y--; // Convert 1-based coords to 0-based... - offset = (y * width) + x; - siz = (width * height) - offset - 1; - siz = (siz > strlen(string)) ? strlen(string) : siz; - memcpy(framebuf + offset, string, siz); + if ((y < 0) || (y >= p->height)) + return; + for (i = 0; (string[i] != '\0') && (x < p->width); i++, x++) { + if (x >= 0) // no write left of left border + p->framebuf[(y * p->width) + x] = string[i]; + } + debug(RPT_DEBUG, "LCDM001: printed string at (%d,%d)", x, y); } @@ -330,19 +364,13 @@ lcdm001_string (Driver *drvthis, int x, int y, char *string) MODULE_EXPORT void lcdm001_output (Driver *drvthis, int state) { + PrivateData *p = drvthis->private_data; char out[5]; - int one = 0, two = 0; + int one = (state & 0xFF); + int two = (state > 255) ? ((state >> 8) & 0xFF) : 0; - if (state <= 255) { - one = state; - two = 0; - } - else { - one = state & 0xff; - two = (state >> 8) & 0xff; - } snprintf(out, sizeof(out), "~L%c%c", one, two); - write(fd, out, 4); + write(p->fd, out, 4); debug(RPT_DEBUG, "LCDM001: current LED state %d", state); } @@ -353,7 +381,8 @@ lcdm001_output (Driver *drvthis, int state) MODULE_EXPORT void lcdm001_old_vbar(Driver *drvthis, int x, int len) { - int y = 4; + PrivateData *p = drvthis->private_data; + int y = p->height; debug(RPT_DEBUG , "LCDM001: vertical bar at %d set to %d", x, len); @@ -375,14 +404,16 @@ lcdm001_old_vbar(Driver *drvthis, int x, int len) MODULE_EXPORT void lcdm001_old_hbar(Driver *drvthis, int x, int y, int len) { - ValidX(x); - ValidY(y); + PrivateData *p = drvthis->private_data; + + if ((y <= 0) || (y > p->height)) + return; debug(RPT_DEBUG, "LCDM001: horizontal bar at %d set to %d", x, len); //TODO: Improve this function - while ((x <= width) && (len > 0)) { + while ((x <= p->width) && (len > 0)) { if (len < LCD_DEFAULT_CELLWIDTH) { //lcdm001_chr(x, y, 0x98 + len); break; @@ -402,6 +433,7 @@ lcdm001_old_hbar(Driver *drvthis, int x, int y, int len) MODULE_EXPORT void lcdm001_old_icon (Driver *drvthis, int which, char dest) { + PrivateData *p = drvthis->private_data; /*Heartbeat workaround: As custom chars are not supported OPEN_HEART @@ -411,13 +443,13 @@ lcdm001_old_icon (Driver *drvthis, int which, char dest) if (dest == 0) switch (which) { case 0: - icon_char = OPEN_HEART; + p->icon_char = OPEN_HEART; break; case 1: - icon_char = FILLED_HEART; + p->icon_char = FILLED_HEART; break; default: - icon_char = PAD; + p->icon_char = PAD; break; } } @@ -431,17 +463,18 @@ lcdm001_old_icon (Driver *drvthis, int which, char dest) MODULE_EXPORT const char * lcdm001_get_key (Driver *drvthis) { + PrivateData *p = drvthis->private_data; char in = '\0'; const char *key = NULL; - read(fd, &in, 1); - if (in == pause_key) { + read(p->fd, &in, 1); + if (in == p->pause_key) { key = "Enter"; - } else if (in == back_key) { + } else if (in == p->back_key) { key = "Left"; - } else if (in == forward_key) { + } else if (in == p->forward_key) { key = "Right"; - } else if (in == main_menu_key) { + } else if (in == p->main_menu_key) { key = "Escape"; } debug(RPT_DEBUG, "%s, get_key: %s",