diff --git a/CREDITS b/CREDITS index bd6637e..0f4405b 100644 --- a/CREDITS +++ b/CREDITS @@ -228,7 +228,7 @@ Dave Platt - overhauled CwLnx driver Nicu Pavel - - overhauled picolcd driver + - overhauled & extended picolcd driver Daryl Fonseca-Holt - lis driver diff --git a/LCDd.conf b/LCDd.conf index 67fb1f9..70fd62e 100644 --- a/LCDd.conf +++ b/LCDd.conf @@ -775,9 +775,6 @@ Reboot=no ## Mini-box.com picoLCD (usblcd) driver ## [picolcd] -# This is for the Mini-Box.com usblcd device that ships with the M300. It can -# also be purchased separately but this driver has only been tested on the M300 -# setup. # KeyTimeout is the time that LCDd spends waiting for a key press before cycling # through other duties. Higher values make LCDd use less CPU time and make @@ -786,7 +783,10 @@ Reboot=no # balanced value. KeyTimeout=500 -# Contrast: [default: 1000; legal: 0 - 1000] +# Set the initial brightness [default: 1000; legal: 0 - 1000] +Brightness=1000 + +# Set the initial contrast [default: 1000; legal: 0 - 1000] Contrast=1000 # Light the keys? i[default: on; legal: on, off] diff --git a/docs/LCDd.8.in b/docs/LCDd.8.in index e289f14..d284c6c 100644 --- a/docs/LCDd.8.in +++ b/docs/LCDd.8.in @@ -220,7 +220,7 @@ LCD display on the Logitech MX5000 keyboard Noritake VFD Device CU20045SCPB-T28A .TP .B picolcd -Mini-box.com USB LCD (picoLCD 20x2) +Mini-box.com USB LCD (PicoLCD 20x4 & picoLCD 20x2) .TP .B pyramid LCD displays from Pyramid (http://www.pyramid.de) diff --git a/docs/lcdproc-user/drivers/picolcd.docbook b/docs/lcdproc-user/drivers/picolcd.docbook index f48b5ce..1a47cd0 100644 --- a/docs/lcdproc-user/drivers/picolcd.docbook +++ b/docs/lcdproc-user/drivers/picolcd.docbook @@ -1,56 +1,108 @@ -The Mini-Box USB LCD (picoLCD 20x2) Driver (picolcd) +The Mini-Box.com USB LCD picoLCD Driver - This section covers the installation and use of the Mini-Box USB LCD (picoLCD - 20x2) display. - - - The picoLCD page indicates that the device can be connected via I2C - or USART. - This LCDproc driver, however, is limited to the USB connected model. + This section covers the installation and use of the Mini-Box USB LCD displays. - -Setting up the picoLCD + +Displays + + Mini-Box.com offers two types of + USB LCD displays: + + + + +PicoLCD 4x20-Sideshow + + + PicoLCD 4x20-Sideshow + is the desktop variant targeted at end users. + It an external USB 2.0 full speed device that comes in a stylish casing and + sports a 4 line by 20 character display with white letters + on a blue background, a built-in InfraRed receiver as well as an + keypad with 8 keys labeled Escape, F1, + F2, F3, Home, + Up, Down and Enter. + + + + + +picoLCD 20x2 (OEM) + + + picoLCD-20x2-OEM is + the OEM version. + It is a 2 line by 20 character display with black letters on a + yellow-green background, that can be connected to the system via + USB, I2C or USART (the latter two are + not supported by this driver). + It has connectors for an InfraRed receiver, keypad and LEDs. + - The picoLCD device as used by this driver is USB connected and may be purchased - with an internal USB header connector (5-pin to 5-pin) or an external cable - (Type-A to 5-pin). See: . - It may also come pre-installed on systems like the Mini-Box M300: - . + When pre-installed in enclosures like the + Mini-Box M300 LCD + it comes equipped with an InfraRed receiver as well as key pad with + 12 keys labeled Plus, Minus, + F1, F2, F3, + F4, F5, Up, + Down, Left, Right, + and Enter. + - Building and using the USB LCD with this driver requires the - libusb library. - Most distributions do provide this library. - The only kernel module required is the USB host controller driver - (uhci_hcd on the M300) to fire up the USB bus + Finally, the picoLCD 20x2 (OEM) supports 8 general purpose outputs + and 10 custom splash screens. + Although these features are not supported by this driver, the + splash screens can be changed using the usblcd + tool, that can be built from the Linux SDK available on the picoLCD web page. + + + + + + + + + +Requirements + + + The driver is based on the + libusb + USB library, which should make it work with Linux, the different BSB variants + as well as Darwin/MacOS X. + + + + When using a libusb based driver like + picolcd, LCDd + needs to be started as root. + + + + + + On Linux, the only kernel module required is the USB host controller + driver (uhci_hcd on the M300) to fire up the USB bus to which the LCD is attached. + For other operating systems, analogous requirements apply. + - Lastly, the usbfs file system must be mounted on + Lastly, for libusb to work correctly, + the usbfs file system must be mounted on /proc/bus/usb, e.g. using the command - mount -t usbfs usbfs /proc/bus/usb or by your disptributions + mount -t usbfs usbfs /proc/bus/usb or by your system's default configuration. - - You can also change the USB LCD's initial display (what it shows when you - initialize the device) by using the usblcd binary's - splash command. - - - To use the picoLCD with LCDproc, add picolcd - to the LCDproc ./configure --drivers option - (or use all), set the Driver= to - picolcd in the LCDd.conf config - file, and then start LCDd either directly or using startup scripts. - The driver has sane default options and the options that are user configurable - are limited to mostly simple items, like contrast and which keys to light up. - + + Configuration in LCDd.conf @@ -58,6 +110,37 @@ [picolcd] + + + + + Brightness = + BRIGHTNESS + + + + Set the initial brightness. + Legal values are: 0 - 1000. + If not given, it defaults to 1000. + + + + Contrast = @@ -66,9 +149,10 @@ Contrast: 0-1000. 0 is visible, and 1000 is not on my M300. - Default is 0. + Default is 1000. + KeyLights = @@ -83,6 +167,7 @@ Allow key LEDs to be turned on or off. Default is yes. + Key0Light = @@ -98,6 +183,7 @@ setting this value to no. Default is yes. + Key1Light = @@ -113,6 +199,7 @@ to no. Default is yes. + Key2Light = @@ -128,6 +215,7 @@ to no. Default is yes. + Key3Light = @@ -143,6 +231,7 @@ to no. Default is yes. + Key4Light = @@ -158,6 +247,7 @@ to no. Default is yes. + Key5Light = @@ -173,6 +263,7 @@ to no. Default is yes. + KeyTimeout = @@ -186,9 +277,10 @@ Larger values make key presses more reliable if somewhat slow to take effect. + - LircHost= + LircHost = HOSTNAME_OR_IP-ADDRESS @@ -206,9 +298,10 @@ + - LircPort= + LircPort = PORTNUM @@ -218,9 +311,10 @@ + - LircSync= + LircSync = DURATION @@ -232,9 +326,10 @@ + - LircLength= + LircLength = DURATION @@ -251,63 +346,53 @@ - - picolcd driver status - - The lcdproc picolcd driver relies upon Mini-Box's usblcd library to setup the USB/HID - interface. Unfortunately the usblcd library is very thin and tends to put function - results on stdout/stderr instead of in return values. They (Mini-Box) really had - scripting interfaces in mind. - - - The primary example of this is that I had to write a replacement (get_key_events) for - usblcd's read_events so that I could get the key presses back to the calling function - instead of on stdout. usblcd also has a large number of function shells for which no - code exists yet. I am not an expert on HID and USB coding, but if and as time permits - and hardware is available I will try and improve this drivers access to the hardware in - order to get back data (get_contrast for example) and to potentially drive multiple - pcioLCDs at once (or pick the one we want out of many). - - - To sum up, this driver right now stabs and hopes since response data is lacking. - - - The hardware also reports key-up events. Normally this would be of no issue (they are - usually a 0 or 'no key') except that when keys are used in combonation, the key-up - event may actually come back as multiple events depending on how the user released the - keys. If the key-up event for a multiple key press comes back as two events, the first - up event will actually look like a new key press. The algorithm in get_key tries to - deal with this in a sane way and toss out all key-up events for now. The hardware is - touchy and both combo key-down and key-up actions may be reported as mutiple events if - the user is more than a tenth of a second (maybe less?) off in motions. - - - Infrared sensor status - - LIRC expects sensor data that starts with a longish 'sync' space, denoting the start of - a command; followed by the code data, a sequence of mark/space pairs; sometimes followed by - a 'gap', which should be a space long enough to make the entire command up to a preset - duration in milliseconds. The 'sync' and the 'gap' are absent from the data - emitted by the picolcd hardware. I found that LIRC configuration files for remotes similar to the - ones I tested all used such a fixed-duration encoding, and as that was the only way I could get it - working, this driver by default adds the gap as well as the sync. However I have - still had trouble getting irrecord to work; you need at least - to feed it a template configuration containing sync and gap data. - - - This code could therefore use more testing, more research, and more work. - - + +picolcd driver status + + + The hardware also reports key-up events. Normally this would be of no issue (they are + usually a 0 or 'no key') except that when keys are used in combonation, the key-up + event may actually come back as multiple events depending on how the user released the + keys. If the key-up event for a multiple key press comes back as two events, the first + up event will actually look like a new key press. The algorithm in get_key tries to + deal with this in a sane way and toss out all key-up events for now. The hardware is + touchy and both combo key-down and key-up actions may be reported as mutiple events if + the user is more than a tenth of a second (maybe less?) off in motions. + + + +Infrared sensor status + + + LIRC expects sensor data that starts with a longish 'sync' space, denoting the start of + a command; followed by the code data, a sequence of mark/space pairs; sometimes followed by + a 'gap', which should be a space long enough to make the entire command up to a preset + duration in milliseconds. The 'sync' and the 'gap' are absent from the data + emitted by the picolcd hardware. I found that LIRC configuration files for remotes similar to the + ones I tested all used such a fixed-duration encoding, and as that was the only way I could get it + working, this driver by default adds the gap as well as the sync. However I have + still had trouble getting irrecord to work; you need at least + to feed it a template configuration containing sync and gap data. + + + + This code could therefore use more testing, more research, and more work. + + + + - Copyright - - The lcdproc picolcd driver originally was written by Gatewood Green (woody@nitrosecurity.com) - or (woody@linif.org) and paid for by NitroSecurity, Inc (nitrosecurity.com), - but has been extended with code from various contributors since then. - +Copyright + + + The lcdproc picolcd driver originally was written by Gatewood Green (woody@nitrosecurity.com) + or (woody@linif.org) and paid for by NitroSecurity, Inc (nitrosecurity.com), + but has been extended with code from various contributors since then. + + diff --git a/server/drivers/picolcd.c b/server/drivers/picolcd.c index 4e26635..ea91925 100644 --- a/server/drivers/picolcd.c +++ b/server/drivers/picolcd.c @@ -48,11 +48,11 @@ #include #include -#define DEFAULT_CONTRAST 1000 /* Full */ -#define DEFAULT_BRIGHTNESS 255 /* Full */ -#define DEFAULT_BACKLIGHT 1 /* On */ -#define DEFAULT_KEYLIGHTS 1 /* On */ -#define DEFAULT_TIMEOUT 500 /* Half second */ +#define DEFAULT_CONTRAST 1000 /* Full */ +#define DEFAULT_BRIGHTNESS 1000 /* Full */ +#define DEFAULT_BACKLIGHT 1 /* On */ +#define DEFAULT_KEYLIGHTS 1 /* On */ +#define DEFAULT_TIMEOUT 500 /* Half second */ #define NUM_CCs 8 /* max. number of custom characters */ @@ -83,8 +83,8 @@ typedef struct pd { char *info; unsigned char *framebuf; unsigned char *lstframe; - /* device info struct */ - picolcd_device *device; + /* device info struct */ + picolcd_device *device; int IRenabled; //For communicating with LIRC int lircsock; @@ -98,57 +98,55 @@ typedef struct pd { /* Private function definitions */ static void picolcd_send(usb_dev_handle *lcd, unsigned char *data, int size); -/* Write function for 20x2 OEM displays */ static void picolcd_20x2_write(usb_dev_handle *lcd, const int row, const int col, const unsigned char *data); -/* Write function for 20x4 desktop displays */ static void picolcd_20x4_write(usb_dev_handle *lcd, const int row, const int col, const unsigned char *data); -/* Custom character define function for 20x2 OEM displays */ static void picolcd_20x2_set_char (Driver *drvthis, int n, unsigned char *dat); -/* Custom character define function for 20x4 desktop displays */ static void picolcd_20x4_set_char (Driver *drvthis, int n, unsigned char *dat); static void get_key_event (usb_dev_handle *lcd, lcd_packet *packet, int timeout); static void set_key_lights (usb_dev_handle *lcd, int keys[], int state); static int ir_transcode(Driver *drvthis, unsigned char *data, unsigned int cbdata, - unsigned char *result, int cbresult); + unsigned char *result, int cbresult); picolcd_device picolcd_device_ids[] = { - { - .device_name = "picoLCD20x2", - .description = "Driver for picoLCD 20x2 OEM and picoLCD found on M200/M300 cases", - .vendor_id = 0x04d8, - .device_id = 0x0002, - .bklight_max = 1, + { + .device_name = "picoLCD20x2", + .description = "Driver for picoLCD 20x2 OEM and picoLCD found on M200/M300 cases", + .vendor_id = 0x04d8, + .device_id = 0x0002, + .bklight_max = 1, .bklight_min = 0, - .contrast_max = 40, + .contrast_max = 40, .contrast_min = 0, - .width = 20, - .height = 2, - .write = picolcd_20x2_write, + .width = 20, + .height = 2, + .write = picolcd_20x2_write, .cchar = picolcd_20x2_set_char, - .keymap = { NULL, "Plus", "Minus", "F1", "F2", "F3", "F4", "F5", - "Left","Right", "Up", "Down", "Enter" }, - .initseq = {}, - }, - { - .device_name = "picoLCD20x4", - .description = "Driver for picoLCD 20x4 desktop LCD", - .vendor_id = 0x04d8, - .device_id = 0xc001, - .bklight_max = 100, + /* all keymap labels must be shorter than KEYPAD_LABEL_MAX */ + .keymap = { NULL, "Plus", "Minus", "F1", "F2", "F3", "F4", "F5", + "Left", "Right", "Up", "Down", "Enter" }, + .initseq = {}, + }, + { + .device_name = "picoLCD20x4", + .description = "Driver for picoLCD 20x4 desktop LCD", + .vendor_id = 0x04d8, + .device_id = 0xc001, + .bklight_max = 100, .bklight_min = 0, - .contrast_max = 1, + .contrast_max = 1, .contrast_min = 0, - .width = 20, - .height = 4, - .write = picolcd_20x4_write, + .width = 20, + .height = 4, + .write = picolcd_20x4_write, .cchar = picolcd_20x4_set_char, - .keymap = { NULL, "Back", "F1", "F2", "F3", "Home", "Down", - "Enter", "Up", "", "", "", ""}, - .initseq = { 0x94, 0x00, 0x07, 0x00, 0x32, 0x30, 0x00,0x32, 0x30, 0x00, 0x32, - 0x30, 0x00, 0x32, 0x38, 0x00, 0x32, 0x06, 0x00, 0x32, 0x0C, 0x07, - 0xD0, 0x01}, - }, - {}, /* End list */ + /* all keymap labels must be shorter than KEYPAD_LABEL_MAX */ + .keymap = { NULL, "Escape", "F1", "F2", "F3", "Home", "Down", + "Enter", "Up", "", "", "", ""}, + .initseq = { 0x94, 0x00, 0x07, 0x00, 0x32, 0x30, 0x00, 0x32, + 0x30, 0x00, 0x32, 0x30, 0x00, 0x32, 0x38, 0x00, + 0x32, 0x06, 0x00, 0x32, 0x0C, 0x07, 0xD0, 0x01}, + }, + {}, /* End list */ }; /* lcd_logical_driver Variables */ @@ -165,7 +163,7 @@ MODULE_EXPORT int picoLCD_init(Driver *drvthis) { struct usb_device *dev; const char *lirchost; int lircport; - int id; + int id; p = (PrivateData *) malloc(sizeof(PrivateData)); if (p == NULL) @@ -180,54 +178,59 @@ MODULE_EXPORT int picoLCD_init(Driver *drvthis) { usb_find_devices(); p->lcd = NULL; - p->device = NULL; - - for (id = 0; picolcd_device_ids[id].device_name; ++id) { - report(RPT_INFO, "Looking for device %s ", picolcd_device_ids[id].device_name); - for (bus = usb_get_busses(); bus != NULL; bus = bus->next) { - for (dev = bus->devices; dev != NULL; dev = dev->next) { - if ((dev->descriptor.idVendor == picolcd_device_ids[id].vendor_id) && - (dev->descriptor.idProduct == picolcd_device_ids[id].device_id)) { - - report(RPT_INFO, "Found %s on bus %s device %s", picolcd_device_ids[id].device_name, - bus->dirname, dev->filename); - - p->lcd = usb_open(dev); - p->device = &picolcd_device_ids[id]; - goto done; - } - } - } - } + p->device = NULL; + + for (id = 0; picolcd_device_ids[id].device_name != NULL; ++id) { + report(RPT_INFO, "%s: looking for device %s ", + drvthis->name, picolcd_device_ids[id].device_name); + for (bus = usb_get_busses(); bus != NULL; bus = bus->next) { + for (dev = bus->devices; dev != NULL; dev = dev->next) { + if ((dev->descriptor.idVendor == picolcd_device_ids[id].vendor_id) && + (dev->descriptor.idProduct == picolcd_device_ids[id].device_id)) { + report(RPT_INFO, "%s: found %s on bus %s device %s", + drvthis->name, picolcd_device_ids[id].device_name, + bus->dirname, dev->filename); + + p->lcd = usb_open(dev); + p->device = &picolcd_device_ids[id]; + goto done; + } + } + } + } done: if (p->lcd != NULL) { debug(RPT_DEBUG, "%s: opening device succeeded", drvthis->name); + #ifdef LIBUSB_HAS_GET_DRIVER_NP - char driver[1024]; - if (usb_get_driver_np(p->lcd, 0, driver, sizeof(driver)) == 0) { - report(RPT_WARNING, "Interface 0 already claimed by '%s' detaching.", driver); + char driver[1024]; + + if (usb_get_driver_np(p->lcd, 0, driver, sizeof(driver)) == 0) { + report(RPT_WARNING, "%s: interface 0 already claimed by '%s' - detaching", + drvthis->name, driver); #ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP - if ((usb_detach_kernel_driver_np(p->lcd, 0) < 0)) - report(RPT_ERR, "%s: unable to detach %s driver", driver); + if ((usb_detach_kernel_driver_np(p->lcd, 0) < 0)) + report(RPT_ERR, "%s: unable to detach %s driver", drvthis->name, driver); #endif - } + } #endif if (usb_claim_interface(p->lcd, 0) < 0) { - report(RPT_ERR, "Cannot claim interface !", driver); + report(RPT_ERR, "%s: cannot claim interface!", drvthis->name); usb_close(p->lcd); return -1; } usleep(100); if (usb_set_altinterface(p->lcd, 0) < 0) report(RPT_WARNING, "%s: unable to set alternate configuration", drvthis->name); - } else { - report(RPT_ERR, "%s: no device found", drvthis->name); - return -1; - } + } + else { + report(RPT_ERR, "%s: no device found", drvthis->name); + return -1; + } - /* if the device has a init sequence sent it to device */ - picolcd_send(p->lcd, p->device->initseq, PICOLCD_MAX_DATA_LEN); + /* if the device has a init sequence sent it to device */ + picolcd_send(p->lcd, p->device->initseq, PICOLCD_MAX_DATA_LEN); p->width = p->device->width; p->height = p->device->height; @@ -236,24 +239,19 @@ MODULE_EXPORT int picoLCD_init(Driver *drvthis) { p->cellheight = LCD_DEFAULT_CELLHEIGHT; p->ccmode = standard; - for (x = 0; x < KEYPAD_LIGHTS; x++) - p->key_light[x] = 1; /* individual lights on */ - - p->contrast = drvthis->config_get_int( drvthis->name, "Contrast", 0, DEFAULT_CONTRAST ); - p->brightness = drvthis->config_get_int( drvthis->name, "Brightness", 0, DEFAULT_BRIGHTNESS ); + p->contrast = drvthis->config_get_int(drvthis->name, "Contrast", 0, DEFAULT_CONTRAST); + p->brightness = drvthis->config_get_int(drvthis->name, "Brightness", 0, DEFAULT_BRIGHTNESS); p->backlight = drvthis->config_get_bool(drvthis->name, "BackLight", 0, DEFAULT_BACKLIGHT); p->keylights = drvthis->config_get_bool(drvthis->name, "KeyLights", 0, DEFAULT_KEYLIGHTS); /* key lights with LCD Backlight? */ - p->key_timeout = drvthis->config_get_int( drvthis->name, "KeyTimeout", 0, DEFAULT_TIMEOUT ); + p->key_timeout = drvthis->config_get_int(drvthis->name, "KeyTimeout", 0, DEFAULT_TIMEOUT); - /* These allow individual lights to be disabled */ - p->key_light[0] = drvthis->config_get_bool(drvthis->name, "Key0Light", 0, 1); - p->key_light[1] = drvthis->config_get_bool(drvthis->name, "Key1Light", 0, 1); - p->key_light[2] = drvthis->config_get_bool(drvthis->name, "Key2Light", 0, 1); - p->key_light[3] = drvthis->config_get_bool(drvthis->name, "Key3Light", 0, 1); - p->key_light[4] = drvthis->config_get_bool(drvthis->name, "Key4Light", 0, 1); - p->key_light[5] = drvthis->config_get_bool(drvthis->name, "Key5Light", 0, 1); - p->key_light[6] = drvthis->config_get_bool(drvthis->name, "Key6Light", 0, 1); - p->key_light[7] = drvthis->config_get_bool(drvthis->name, "Key7Light", 0, 1); + /* allow individual lights to be set */ + for (x = 0; x < KEYPAD_LIGHTS; x++) { + char configkey[32]; + + sprintf(configkey, "Key%dLight", x); + p->key_light[x] = drvthis->config_get_bool(drvthis->name, configkey, 0, 1); + } p->framebuf = (unsigned char *) malloc(p->width * p->height + 1); if (p->framebuf == NULL) { @@ -296,10 +294,10 @@ MODULE_EXPORT int picoLCD_init(Driver *drvthis) { return -1; } if ((p->lircsock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - report(RPT_ERR, "%s: failed to create socket to send data to LIRC", drvthis->name); + report(RPT_ERR, "%s: failed to create socket to send data to LIRC", drvthis->name); return -1; } - + /* Construct the server sockaddr_in structure */ memset(&p->lircserver, 0, sizeof(p->lircserver)); /* Clear struct */ p->lircserver.sin_family = AF_INET; /* Internet/IP */ @@ -396,7 +394,7 @@ MODULE_EXPORT void picoLCD_string(Driver *drvthis, int x, int y, unsigned char * unsigned char *dest; int len; - debug(RPT_DEBUG, "%s: string start (%s)", drvthis->name, str); + debug(RPT_DEBUG, "%s: string start (%s)", drvthis->name, str); if (y < 1 || y > p->height) return; @@ -413,7 +411,7 @@ MODULE_EXPORT void picoLCD_string(Driver *drvthis, int x, int y, unsigned char * x--; y--; /* Convert 1-based to 0-based */ dest = p->framebuf + (y * p->width + x); - memcpy(dest, str, len * sizeof(char)); + memcpy(dest, str, len * sizeof(unsigned char)); debug(RPT_DEBUG, "%s: string complete (%s)", drvthis->name, str); } @@ -423,6 +421,7 @@ MODULE_EXPORT void picoLCD_chr(Driver *drvthis, int x, int y, unsigned char chr) { PrivateData *p = drvthis->private_data; unsigned char *dest; + debug(RPT_DEBUG, "%s: chr start (%c)", drvthis->name, chr); if (y < 1 || y > p->height) @@ -432,7 +431,8 @@ MODULE_EXPORT void picoLCD_chr(Driver *drvthis, int x, int y, unsigned char chr) x--; y--; /* Convert 1-based to 0-based */ dest = p->framebuf + (y * p->width + x); - memcpy(dest, &chr, sizeof(char)); + memcpy(dest, &chr, sizeof(unsigned char)); + debug(RPT_DEBUG, "%s: chr complete (%c)", drvthis->name, chr); } @@ -602,19 +602,26 @@ MODULE_EXPORT char *picoLCD_get_key(Driver *drvthis) { debug(RPT_DEBUG, "%s: get_key got all clear", drvthis->name); /* Got a <0, 0> key-up event after reading a valid key press event */ keys_read++; /* All clear */ - } else if (! keydata->data[2] && ! two_keys) { + } + else if (! keydata->data[2] && ! two_keys) { debug(RPT_DEBUG, "%s: get_key got one key", drvthis->name); /* We got one key (but not after a two key event and before and all clear) */ keystr = p->device->keymap[keydata->data[1]]; - } else { + } + else { /* We got two keys */ + static char keybuf[2 * KEYPAD_LABEL_MAX + 1]; + debug(RPT_DEBUG, "%s: get_key got two keys", drvthis->name); two_keys++; - sprintf(keystr, "%s+%s", p->device->keymap[keydata->data[1]], p->device->keymap[keydata->data[2]]); + sprintf(keybuf, "%s+%s", p->device->keymap[keydata->data[1]], + p->device->keymap[keydata->data[2]]); + keystr = keybuf; } key_pass++; /* This hack allows us to deal with receiving left over <0,0> first */ - } else if (p->IRenabled && keydata->type == IN_REPORT_IR_DATA) { + } + else if (p->IRenabled && keydata->type == IN_REPORT_IR_DATA) { int cbres; debug(RPT_NOTICE, "%s: get_key irdata, length=%d bytes", @@ -627,7 +634,8 @@ MODULE_EXPORT char *picoLCD_get_key(Driver *drvthis) { if (cbres < 0) { report(RPT_ERR, "%s: could not transcode buffer, length=%d", drvthis->name, keydata->data[1]); - } else { + } + else { debug(RPT_NOTICE, "%s: sending packet to lirc, length=%d", drvthis->name, cbres); int ret = sendto(p->lircsock, p->result, cbres, 0, @@ -635,14 +643,17 @@ MODULE_EXPORT char *picoLCD_get_key(Driver *drvthis) { if (ret == -1) { report(RPT_ERR, "%s: error sending UDP packet, errno=%d", drvthis->name, errno); - } else if (ret != cbres) { + } + else if (ret != cbres) { report(RPT_ERR, "%s: mismatch in number of bytes sent (%d!=%d)", drvthis->name, cbres, ret); - } else { + } + else { debug(RPT_NOTICE, "%s: packet sent to lirc.", drvthis->name); } } - } else { + } + else { debug(RPT_DEBUG, "%s: get_key got non-key data or timeout", drvthis->name); /* We got IR or otherwise bad data */ free(keydata); @@ -694,41 +705,43 @@ MODULE_EXPORT char *picoLCD_get_key(Driver *drvthis) { /* lcd_logical_driver User-defined character functions */ /* lcd_logical_driver Hardware functions */ -/*MODULE_EXPORT int picoLCD_get_contrast(Driver *drvthis) +MODULE_EXPORT int picoLCD_get_contrast(Driver *drvthis) { PrivateData *p = drvthis->private_data; -}*/ + return p->contrast; +} -MODULE_EXPORT int picoLCD_set_contrast(Driver *drvthis, int promille) +MODULE_EXPORT void picoLCD_set_contrast(Driver *drvthis, int promille) { PrivateData *p = drvthis->private_data; int inv; /* The hardware seems to go dark on higher values, so we turn it around */ unsigned char packet[2] = { 0x92 }; /* set contrast id */ - - if (promille <= 1000 && promille > 0) { + p->contrast = promille; + if (p->device->contrast_max == 1) packet[1] = 0x00; /* picoLCD20x4 permits contrast as 0/1 value */ else { inv = 1000 - promille; packet[1] = inv / 1000 * p->device->contrast_max; } - } else if (promille > 1000) { + } + else if (promille > 1000) { + p->contrast = 1000; packet[1] = p->device->contrast_min; - } else if (promille <= 0) { + } + else if (promille <= 0) { + p->contrast = 0; packet[1] = p->device->contrast_max; - } else { - return -1; } picolcd_send(p->lcd, packet, 2); - - return 0; } + /*MODULE_EXPORT int picoLCD_get_brightness(Driver *drvthis, int state) { PrivateData *p = drvthis->private_data; @@ -760,23 +773,18 @@ MODULE_EXPORT void picoLCD_backlight(Driver *drvthis, int state) if (s > p->device->bklight_max) s = p->device->bklight_max; - if (state == 0) { + if (state == BACKLIGHT_OFF) { //packet[1] = (unsigned char) p->device->bklight_min; packet[1] = 0xff; picolcd_send(p->lcd, packet, 2); set_key_lights(p->lcd, p->key_light, state); - return; } - - if (state == 1) { + else if (state == BACKLIGHT_ON) { packet[1] = (unsigned char) s; picolcd_send(p->lcd, packet, 2); if (p->keylights) set_key_lights(p->lcd, p->key_light, state); - return; } - - return; } /*MODULE_EXPORT int picoLCD_output(Driver *drvthis, int state) { @@ -812,7 +820,7 @@ MODULE_EXPORT char *picoLCD_get_info(Driver *drvthis) { * @return: number of bytes placed in result buffer. */ static int ir_transcode(Driver *drvthis, unsigned char *data, unsigned int cbdata, - unsigned char *result, int cbresult) + unsigned char *result, int cbresult) { PrivateData *p = drvthis->private_data; int i; @@ -860,7 +868,8 @@ static int ir_transcode(Driver *drvthis, unsigned char *data, unsigned int cbdat //scale: orig is usec, new is jiffy. E.g. 9055usec = 148 jiffy. w = (w * 16384 /1000000) & 0xFFFF; p->gap -= w; - } else { + } + else { //Scale. w = w * 16384 / 1000000; //Set the space bit. @@ -870,7 +879,8 @@ static int ir_transcode(Driver *drvthis, unsigned char *data, unsigned int cbdat if (resptr + 2 < cbresult) { result[resptr++] = w & 0xFF; result[resptr++] = (w >> 8) & 0xFF; - } else { + } + else { resptr = -1; break; } @@ -893,17 +903,21 @@ static int ir_transcode(Driver *drvthis, unsigned char *data, unsigned int cbdat p->gap |= 0x8000; result[resptr++] = p->gap & 0xFF; result[resptr++] = (p->gap >>8) & 0xFF; - } else { + } + else { debug(RPT_DEBUG, "%s: terminal space=[%04x]; not appending gap (length=%d jiffies)", (unsigned int)(w & 0xffff), drvthis->name, p->gap); } - } else { + } + else { debug(RPT_DEBUG, "%s: not appending gap because it would be negative (length=%d jiffies)", drvthis->name, p->gap); } - } else { + } + else { //Result buffer would overflow resptr = -1; } - } else { + } + else { debug(RPT_DEBUG, "%s: cIntervals=%d; not appending gap (length=%d jiffies)", drvthis->name, cIntervals, p->gap); } @@ -913,73 +927,65 @@ static int ir_transcode(Driver *drvthis, unsigned char *data, unsigned int cbdat static void picolcd_send(usb_dev_handle *lcd, unsigned char *data, int size) { - if ((lcd == NULL) && (data == NULL)) - return; - - usb_interrupt_write(lcd, USB_ENDPOINT_OUT + 1, (char *) data, size, 1000); + if ((lcd == NULL) && (data == NULL)) + return; + + usb_interrupt_write(lcd, USB_ENDPOINT_OUT + 1, (char *) data, size, 1000); } + +/* Write function for 20x4 desktop displays */ static void picolcd_20x4_write(usb_dev_handle *lcd, const int row, const int col, const unsigned char *data) { - unsigned char packet[64]; - - unsigned char lineset[4][6] = { - { 0x94, 0x00, 0x01, 0x00, 0x64, 0x80 }, - { 0x94, 0x00, 0x01, 0x00, 0x64, 0xC0 }, - { 0x94, 0x00, 0x01, 0x00, 0x64, 0x94 }, - { 0x94, 0x00, 0x01, 0x00, 0x64, 0xD4 } - }; - - int len, i; - - switch(row) { - case 0: picolcd_send(lcd, lineset[0], 6); break; - case 1: picolcd_send(lcd, lineset[1], 6); break; - case 2: picolcd_send(lcd, lineset[2], 6); break; - case 3: picolcd_send(lcd, lineset[3], 6); break; - default: picolcd_send(lcd, lineset[0], 6); break; - } - - len = strlen((char *)data); - if (len > 20) len = 20; + unsigned char packet[64] = { 0x95, 0x01, 0x00, 0x01 }; + unsigned char lineset[4][6] = { + { 0x94, 0x00, 0x01, 0x00, 0x64, 0x80 }, + { 0x94, 0x00, 0x01, 0x00, 0x64, 0xC0 }, + { 0x94, 0x00, 0x01, 0x00, 0x64, 0x94 }, + { 0x94, 0x00, 0x01, 0x00, 0x64, 0xD4 } + }; + int len = strlen((char *) data); - packet[0] = 0x95; - packet[1] = 0x01; - packet[2] = 0x00; - packet[3] = 0x01; - packet[4] = len; + if (len > 20) + len = 20; - i = 5; - while (len--) { - packet[i++] = *data++; - } + switch (row) { + case 0: picolcd_send(lcd, lineset[0], 6); break; + case 1: picolcd_send(lcd, lineset[1], 6); break; + case 2: picolcd_send(lcd, lineset[2], 6); break; + case 3: picolcd_send(lcd, lineset[3], 6); break; + default: picolcd_send(lcd, lineset[0], 6); break; + } - picolcd_send(lcd, packet, i); + packet[4] = len; + + memcpy(packet + 5, data, len); + + picolcd_send(lcd, packet, 5 + len); } +/* Write function for 20x2 OEM displays */ static void picolcd_20x2_write(usb_dev_handle *lcd, const int row, const int col, const unsigned char *data) { - unsigned char packet[64]; - int len, i; - - len = strlen((char *)data); - if (len > 20) len = 20; + unsigned char packet[64] = { 0x98 }; + int len = strlen((char *) data); - packet[0] = 0x98; - packet[1] = row; - packet[2] = col; - packet[3] = len; + if (len > 20) + len = 20; - i = 4; - while (len--) { - packet[i++] = *data++; - } + packet[1] = row; + packet[2] = col; + packet[3] = len; - picolcd_send(lcd, packet, i); + memcpy(packet + 4, data, len); + + picolcd_send(lcd, packet, 4 + len); } -static void picolcd_20x2_set_char (Driver *drvthis, int n, unsigned char *dat) + +/* Custom character define function for 20x2 OEM displays */ +static void picolcd_20x2_set_char(Driver *drvthis, int n, unsigned char *dat) { PrivateData *p = drvthis->private_data; unsigned char packet[10] = { 0x9c }; /* define character */ @@ -998,29 +1004,26 @@ static void picolcd_20x2_set_char (Driver *drvthis, int n, unsigned char *dat) } picolcd_send(p->lcd, packet, 10); - - return; } -static void picolcd_20x4_set_char (Driver *drvthis, int n, unsigned char *dat) +/* Custom character define function for 20x4 desktop displays */ +static void picolcd_20x4_set_char(Driver *drvthis, int n, unsigned char *dat) { + PrivateData *p = drvthis->private_data; if ((n < 0) || (n >= NUM_CCs)) return; if (!dat) return; - PrivateData *p = drvthis->private_data; unsigned char command[6] = { OUT_REPORT_CMD, 0x00, 0x01, 0x00, 0x64, 0x40+8*n }; /* 0x94 */ unsigned char data[13] = { OUT_REPORT_DATA, 0x01, 0x00, 0x01, 0x08, dat[0], dat[1], dat[2], dat[3], - dat[4], dat[5], dat[6], dat[7]}; /* 0x95 */ + dat[4], dat[5], dat[6], dat[7]}; /* 0x95 */ picolcd_send(p->lcd, command, 6); picolcd_send(p->lcd, data, 13); - - return; } @@ -1030,7 +1033,7 @@ static void get_key_event(usb_dev_handle *lcd, lcd_packet *packet, int timeout) memset(packet->data, 0, 255); packet->type = 0; - + ret = usb_interrupt_read(lcd, USB_ENDPOINT_IN + 1, (char *)packet->data, PICOLCD_MAX_DATA_LEN, timeout); if (ret > 0) { switch (packet->data[0]) { @@ -1039,13 +1042,13 @@ static void get_key_event(usb_dev_handle *lcd, lcd_packet *packet, int timeout) } break; case IN_REPORT_IR_DATA: { packet->type = IN_REPORT_IR_DATA; - /* - * clears the halt status on the usb endpoint - * picoLCD 20x4 keeps last ir state without clearing the - * status on endpoint, meaning that we will get same IR data - * over and over till we clear the status manually. - */ - usb_clear_halt(lcd, USB_ENDPOINT_IN + 1); + /* + * clears the halt status on the usb endpoint + * picoLCD 20x4 keeps last ir state without clearing the + * status on endpoint, meaning that we will get same IR data + * over and over till we clear the status manually. + */ + usb_clear_halt(lcd, USB_ENDPOINT_IN + 1); } break; default: { packet->type = 0; @@ -1057,23 +1060,24 @@ static void get_key_event(usb_dev_handle *lcd, lcd_packet *packet, int timeout) static void set_key_lights(usb_dev_handle *lcd, int keys[], int state) { - unsigned char packet[2] = { 0x81 }; /* set led */ + unsigned char packet[2] = { 0x81 }; /* set led */ unsigned int leds = 0; - int i; - + int i; + if (state) { /* Only LEDs we want on */ for (i = 0; i < KEYPAD_LIGHTS; i++) if(keys[i]) - leds |= 1 << i; + leds |= (1 << i); else leds &= ~ (1 << i); - } else { + } + else { /* All LEDs off */ leds = 0; } packet[1] = leds; - picolcd_send(lcd, packet, 2); + picolcd_send(lcd, packet, 2); } diff --git a/server/drivers/picolcd.h b/server/drivers/picolcd.h index b1ff37c..5958ce9 100644 --- a/server/drivers/picolcd.h +++ b/server/drivers/picolcd.h @@ -34,17 +34,15 @@ #include /* 12 keys plus a 0 placeholder */ -#define KEYPAD_MAX 13 -#define KEYPAD_LIGHTS 8 - -#define picoLCD_VENDOR 0x04d8 -#define picoLCD_DEVICE 0x0002 +#define KEYPAD_MAX 13 +#define KEYPAD_LIGHTS 8 +#define KEYPAD_LABEL_MAX 25 #define IN_REPORT_KEY_STATE 0x11 #define IN_REPORT_IR_DATA 0x21 -#define OUT_REPORT_CMD 0x94 -#define OUT_REPORT_DATA 0x95 +#define OUT_REPORT_CMD 0x94 +#define OUT_REPORT_DATA 0x95 #define PICOLCD_MAX_DATA_LEN 24 @@ -53,33 +51,30 @@ #define DEFAULT_LENGTH_JIFFY 2048 -typedef struct _lcd_packet lcd_packet; - -struct _lcd_packet { +typedef struct _lcd_packet { unsigned char data[255]; unsigned int type; -}; +} lcd_packet; -typedef struct _picolcd_device picolcd_device ; - -struct _picolcd_device { - char *device_name; /* Device name */ - char *description; /* Device description */ - unsigned char initseq[PICOLCD_MAX_DATA_LEN]; /* init sequence */ - char *keymap[KEYPAD_MAX]; /* key pad button names */ +typedef struct _picolcd_device { + char *device_name; /* Device name */ + char *description; /* Device description */ + unsigned char initseq[PICOLCD_MAX_DATA_LEN]; /* init sequence */ + char *keymap[KEYPAD_MAX]; /* key pad button names */ unsigned int vendor_id; /* vendor id for detection */ unsigned int device_id; /* device id for detection */ - int bklight_max; /* maximum backlight value */ + int bklight_max; /* maximum backlight value */ int bklight_min; /* minimum backlight value */ - int contrast_max; /* contrast maximum value */ + int contrast_max; /* contrast maximum value */ int contrast_min; /* minimum contrast value */ - int width; /* width of lcd screen */ - int height; /* height of lcd screen */ + int width; /* width of lcd screen */ + int height; /* height of lcd screen */ /* Pointer to function that writes data to the LCD format */ - void (*write)(usb_dev_handle *lcd, const int row, const int col, const unsigned char *data); + void (*write)(usb_dev_handle *lcd, const int row, const int col, const unsigned char *data); /* Pointer to function that defines a custom character */ void (*cchar) (Driver *drvthis, int n, unsigned char *dat); -}; +} picolcd_device; + MODULE_EXPORT int picoLCD_init(Driver *drvthis); MODULE_EXPORT void picoLCD_close(Driver *drvthis); @@ -95,18 +90,16 @@ MODULE_EXPORT char *picoLCD_get_key(Driver *drvthis); MODULE_EXPORT void picoLCD_vbar(Driver *drvthis, int x, int y, int len, int promille, int options); MODULE_EXPORT void picoLCD_hbar(Driver *drvthis, int x, int y, int len, int promille, int options); MODULE_EXPORT void picoLCD_num(Driver *drvthis, int x, int num); -MODULE_EXPORT int picoLCD_icon(Driver *drvthis, int x, int y, int icon); +MODULE_EXPORT int picoLCD_icon(Driver *drvthis, int x, int y, int icon); MODULE_EXPORT void picoLCD_cursor(Driver *drvthis, int x, int y, int type); -MODULE_EXPORT int picoLCD_set_contrast(Driver *drvthis, int promille); -MODULE_EXPORT void picoLCD_set_brightness (Driver *drvthis, int state, int promille); +MODULE_EXPORT int picoLCD_get_contrast(Driver *drvthis); +MODULE_EXPORT void picoLCD_set_contrast(Driver *drvthis, int promille); +//MODULE_EXPORT int picoLCD_get_brightness(Driver *drvthis, int state); +MODULE_EXPORT void picoLCD_set_brightness(Driver *drvthis, int state, int promille); MODULE_EXPORT void picoLCD_backlight(Driver *drvthis, int promille); +//MODULE_EXPORT void picoLCD_output(Driver *drvthis, int state); + MODULE_EXPORT char *picoLCD_get_info(Driver *drvthis); -//MODULE_EXPORT void picoLCD_output(Driver *drvthis, int state); -//MODULE_EXPORT int picoLCD_get_contrast(Driver *drvthis); -//MODULE_EXPORT int picoLCD_get_brightness (Driver *drvthis, int state); - - - #endif