diff options
author | mrwastl <mrwastl@users.sourceforge.net> | 2013-01-07 00:40:59 +0100 |
---|---|---|
committer | mrwastl <mrwastl@users.sourceforge.net> | 2013-01-07 00:40:59 +0100 |
commit | c37e9b482fd9c8a610ea232bb1c6d7b45e248e6c (patch) | |
tree | 40994b2dbac06cf06177bd1314bde76410f0ebaf | |
parent | aa57a08ce857b7a932819cf9f40296f213a80539 (diff) | |
download | graphlcd-base-c37e9b482fd9c8a610ea232bb1c6d7b45e248e6c.tar.gz graphlcd-base-c37e9b482fd9c8a610ea232bb1c6d7b45e248e6c.tar.bz2 |
experimental support added for picoLCD 256x64 (contributed by Jochen Koch)
-rw-r--r-- | Make.config | 3 | ||||
-rw-r--r-- | glcddrivers/Makefile | 9 | ||||
-rw-r--r-- | glcddrivers/drivers.c | 10 | ||||
-rw-r--r-- | glcddrivers/drivers.h | 3 | ||||
-rw-r--r-- | glcddrivers/picoLCD_256x64.c | 553 | ||||
-rw-r--r-- | glcddrivers/picoLCD_256x64.h | 106 |
6 files changed, 682 insertions, 2 deletions
diff --git a/Make.config b/Make.config index 5ff6534..f6a668f 100644 --- a/Make.config +++ b/Make.config @@ -64,3 +64,6 @@ HAVE_FONTCONFIG=1 # uncomment this variable if you want to enable the experimental AX 206 based digital photo frame driver # Read DRIVER.ax206dpf before use! #HAVE_AX206DPF_EXPERIMENTAL=1 + +# uncomment this variable if you want to enable the experimental support for picoLCD 256x64 +#HAVE_picoLCD_256x64_EXPERIMENTAL=1 diff --git a/glcddrivers/Makefile b/glcddrivers/Makefile index f2c287b..a5c7481 100644 --- a/glcddrivers/Makefile +++ b/glcddrivers/Makefile @@ -34,8 +34,13 @@ ifeq ($(shell pkg-config --exists libusb && echo 1), 1) LIBS += $(shell pkg-config --libs libusb) DEFINES += -DHAVE_AX206DPF_EXPERIMENTAL endif -endif - + ifdef HAVE_picoLCD_256x64_EXPERIMENTAL + OBJS += picoLCD_256x64.o + INCLUDES += $(shell pkg-config --cflags libusb) + LIBS += $(shell pkg-config --libs libusb) + DEFINES += -DHAVE_picoLCD_256x64_EXPERIMENTAL + endif +endif ### Implicit rules: diff --git a/glcddrivers/drivers.c b/glcddrivers/drivers.c index a0e5ce0..62ad57f 100644 --- a/glcddrivers/drivers.c +++ b/glcddrivers/drivers.c @@ -33,6 +33,9 @@ #ifdef HAVE_AX206DPF_EXPERIMENTAL #include "ax206dpf.h" #endif +#ifdef HAVE_picoLCD_256x64_EXPERIMENTAL +#include "picoLCD_256x64.h" +#endif namespace GLCD { @@ -60,6 +63,9 @@ tDriver drivers[] = #ifdef HAVE_AX206DPF_EXPERIMENTAL {"ax206dpf", kDriverAX206DPF}, #endif +#ifdef HAVE_picoLCD_256x64_EXPERIMENTAL + {"picolcd256x64", kDriverPicoLCD_256x64}, +#endif {"", kDriverUnknown} }; @@ -122,6 +128,10 @@ cDriver * CreateDriver(int driverID, cDriverConfig * config) case kDriverAX206DPF: return new cDriverAX206DPF(config); #endif +#ifdef HAVE_picoLCD_256x64_EXPERIMENTAL + case kDriverPicoLCD_256x64: + return new cDriverPicoLCD_256x64(config); +#endif case kDriverUnknown: default: return NULL; diff --git a/glcddrivers/drivers.h b/glcddrivers/drivers.h index e93b968..1c1ee8e 100644 --- a/glcddrivers/drivers.h +++ b/glcddrivers/drivers.h @@ -43,6 +43,9 @@ enum eDriver #ifdef HAVE_AX206DPF_EXPERIMENTAL kDriverAX206DPF = 17, #endif +#ifdef HAVE_picoLCD_256x64_EXPERIMENTAL + kDriverPicoLCD_256x64 = 18, +#endif kDriverSerDisp = 100, kDriverG15daemon = 200 }; diff --git a/glcddrivers/picoLCD_256x64.c b/glcddrivers/picoLCD_256x64.c new file mode 100644 index 0000000..8cef04d --- /dev/null +++ b/glcddrivers/picoLCD_256x64.c @@ -0,0 +1,553 @@ +/* + * GraphLCD driver library + * + * PicoLCD_256x64.c - picoLCD Graphic 256x64 + * Output goes to a picoLCD Graphic 256x64 LCD + * + * Driver is based on lcd4linux driver by Nicu Pavel, Mini-Box.com <npavel@mini-box.com> + * + * This file is released under the GNU General Public License. + * + * See the files README and COPYING for details. + * + * 2012 by Jochen Koch <linuxfan1992 AT web de> + */ + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <time.h> +#include <stdint.h> + + +#include <stdio.h> +#include <syslog.h> +#include <cstring> + +#include "common.h" +#include "config.h" +#include "picoLCD_256x64.h" + +namespace GLCD { + +cDriverPicoLCD_256x64::cDriverPicoLCD_256x64(cDriverConfig * config) +: cDriver(config) +, pLG_framebuffer(0) +{ + dirty = 1; + inverted = 0; + gpo = 0; + read_timeout = 0; +} + +int cDriverPicoLCD_256x64::Init() +{ + DEBUG("picoLCD Graphic initialization"); + + // default values + width = config->width; + if (width <= 0 || width > SCREEN_W) + width = SCREEN_W; + height = config->height; + if (height <= 0 || height > SCREEN_H) + height = SCREEN_H; + + *oldConfig = *config; + + if (drv_pLG_open() < 0) { + return -1; + } + + /* Init framebuffer buffer */ + pLG_framebuffer = (unsigned char *)malloc(SCREEN_W * SCREEN_H / 8 * sizeof(unsigned char)); + if (!pLG_framebuffer) + { + INFO("picoLCD_256x64: frame buffer could not be allocated: malloc() failed"); + return -1; + } + + /* clear display */ + Clear(); + drv_pLG_clear(); + DEBUG("zeroed"); + + // inverted display + inverted = (config->invert ? 0xff : 0); + // Set Display SetBrightness + SetBacklight(config->backlight); + // Set Display SetContrast + SetContrast(config->contrast); + + return 0; +} + + +int cDriverPicoLCD_256x64::DeInit() +{ + + DEBUG("picoLCD_256x64: shutting down."); + + /* clear display */ + Clear(); + drv_pLG_clear(); + drv_pLG_close(); + + if (pLG_framebuffer) { + free(pLG_framebuffer); + pLG_framebuffer = NULL; + } + return 0; +} + + +int cDriverPicoLCD_256x64::CheckSetup() +{ + if (config->width != oldConfig->width || + config->height != oldConfig->height) + { + DeInit(); + return Init(); + } + + if (config->backlight != oldConfig->backlight) + { + oldConfig->backlight = config->backlight; + SetBacklight(config->backlight); + } + + if (config->contrast != oldConfig->contrast) + { + oldConfig->contrast = config->contrast; + SetContrast(config->contrast); + } + + if (config->upsideDown != oldConfig->upsideDown || + config->invert != oldConfig->invert) + { + oldConfig->upsideDown = config->upsideDown; + oldConfig->invert = config->invert; + inverted = (config->invert ? 0xff : 0); + return 1; + } + return 0; +} + + +void cDriverPicoLCD_256x64::Clear() +{ + for (unsigned int n = 0; pLG_framebuffer && n < (SCREEN_W * SCREEN_H / 8); n++) + pLG_framebuffer[n] = 0x00; +} + + +void cDriverPicoLCD_256x64::SetPixel(int x, int y, uint32_t data) +{ + unsigned char c; + int n; + + if (!pLG_framebuffer) + return; + + if (x >= width || x < 0) + return; + if (y >= height || y < 0) + return; + + if (config->upsideDown) + { + x = width - 1 - x; + y = height - 1 - y; + } + + n = x + ((y / 8) * SCREEN_W); + c = 0x01 << (y % 8); + + if (data == GRAPHLCD_White) + pLG_framebuffer[n] |= c; + else + pLG_framebuffer[n] &= (0xFF ^ c); + + /* display needs to be redrawn from frame buffer */ + dirty = 1; +} + + +void cDriverPicoLCD_256x64::Refresh(bool refreshAll) +{ + unsigned char cmd3[64] = { OUT_REPORT_CMD_DATA }; /* send command + data */ + unsigned char cmd4[64] = { OUT_REPORT_DATA }; /* send data only */ + + int index, x, s; + unsigned char cs, line; + + if (!pLG_framebuffer) + return; + + s = CheckSetup(); + if ((s > 0) || dirty) + refreshAll = true; + + /* do not redraw display if frame buffer has not changed */ + if (!refreshAll) { + DEBUG("Skipping"); + return; + } + DEBUG("entered"); + + for (cs = 0; cs < 4; cs++) + { + unsigned char chipsel = (cs << 2); //chipselect + for (line = 0; line < 8; line++) + { + //ha64_1.setHIDPkt(OUT_REPORT_CMD_DATA, 8+3+32, 8, chipsel, 0x02, 0x00, 0x00, 0xb8|j, 0x00, 0x00, 0x40); + cmd3[0] = OUT_REPORT_CMD_DATA; + cmd3[1] = chipsel; + cmd3[2] = 0x02; + cmd3[3] = 0x00; + cmd3[4] = 0x00; + cmd3[5] = 0xb8 | line; + cmd3[6] = 0x00; + cmd3[7] = 0x00; + cmd3[8] = 0x40; + cmd3[9] = 0x00; + cmd3[10] = 0x00; + cmd3[11] = 32; + + //ha64_2.setHIDPkt(OUT_REPORT_DATA, 4+32, 4, chipsel | 0x01, 0x00, 0x00, 32); + cmd4[0] = OUT_REPORT_DATA; + cmd4[1] = chipsel | 0x01; + cmd4[2] = 0x00; + cmd4[3] = 0x00; + cmd4[4] = 32; + + for (index = 0; index < 32; index++) + { + x=64*cs+index; + cmd3[12 + index] = pLG_framebuffer[line * SCREEN_W + x] ^ inverted; + } + for (index = 32; index < 64; index++) + { + x=64*cs+index; + cmd4[5 + (index - 32)] = pLG_framebuffer[line * SCREEN_W + x] ^ inverted; + } + drv_pLG_send(cmd3, 44); + drv_pLG_send(cmd4, 38); + } + } + /* mark display as up-to-date */ + dirty = 0; +} + + +/* + * Sets the backlight brightness of the display. + * + */ +void cDriverPicoLCD_256x64::SetBacklight(unsigned int onoff) +{ + unsigned char cmd[2] = { 0x91 }; /* set backlight */ + + cmd[1] = (onoff>0 ? 0xff : 0); + drv_pLG_send(cmd, 2); +} + + +void cDriverPicoLCD_256x64::SetContrast(unsigned int val) +{ + unsigned char cmd[2] = { 0x92 }; /* set contrast */ + + if (val > 10) + val = 10; + + cmd[1] = 0x99+val*(0xff-0x99)/10; + drv_pLG_send(cmd, 2); +} + +/****************************************/ +/*** hardware dependant functions ***/ +/****************************************/ + +int cDriverPicoLCD_256x64::drv_pLG_open(void) +{ + struct usb_bus *busses, *bus; + struct usb_device *dev; + char driver[1024]; + char product[1024]; + char manufacturer[1024]; + char serialnumber[1024]; + int ret; + + lcd = NULL; + + INFO("scanning for picoLCD 256x64..."); + + usb_init(); + usb_find_busses(); + usb_find_devices(); + busses = usb_get_busses(); + + for (bus = busses; bus; bus = bus->next) { + for (dev = bus->devices; dev; dev = dev->next) { + if ((dev->descriptor.idVendor == picoLCD_VENDOR) && (dev->descriptor.idProduct == picoLCD_DEVICE)) { + + DEBUG1("found picoLCD on bus %s device %s", bus->dirname, dev->filename); + + lcd = usb_open(dev); + + ret = usb_get_driver_np(lcd, 0, driver, sizeof(driver)); + + if (ret == 0) { + DEBUG1("interface 0 already claimed by '%s'", driver); + DEBUG(" attempting to detach driver..."); + if (usb_detach_kernel_driver_np(lcd, 0) < 0) { + DEBUG("usb_detach_kernel_driver_np() failed!"); + return -1; + } + } + + usb_set_configuration(lcd, 1); + usleep(100); + + if (usb_claim_interface(lcd, 0) < 0) { + DEBUG("picoLCD_256x64: usb_claim_interface() failed!"); + return -1; + } + + usb_set_altinterface(lcd, 0); + + usb_get_string_simple(lcd, dev->descriptor.iProduct, product, sizeof(product)); + usb_get_string_simple(lcd, dev->descriptor.iManufacturer, manufacturer, sizeof(manufacturer)); + usb_get_string_simple(lcd, dev->descriptor.iSerialNumber, serialnumber, sizeof(serialnumber)); + + INFO1("Manufacturer='%s' Product='%s' SerialNumber='%s\n'", manufacturer, product, serialnumber); + + return 0; + } + } + } + INFO("could not find a picoLCD"); + return -1; +} + + +int cDriverPicoLCD_256x64::drv_pLG_read(unsigned char *data, int size) +{ + return usb_interrupt_read(lcd, USB_ENDPOINT_IN + 1, (char *) data, size, read_timeout); +} + + +void cDriverPicoLCD_256x64::drv_pLG_send(unsigned char *data, int size) +{ + int __attribute__ ((unused)) ret; + ret = usb_interrupt_write(lcd, USB_ENDPOINT_OUT + 1, (char *) data, size, 1000); +} + + +int cDriverPicoLCD_256x64::drv_pLG_close(void) +{ + usb_release_interface(lcd, 0); + usb_close(lcd); + + return 0; +} + + +void cDriverPicoLCD_256x64::drv_pLG_clear(void) +{ + unsigned char cmd[3] = { 0x93, 0x01, 0x00 }; /* init display */ + unsigned char cmd2[9] = { OUT_REPORT_CMD }; /* init display */ + unsigned char cmd3[64] = { OUT_REPORT_CMD_DATA }; /* clear screen */ + unsigned char cmd4[64] = { OUT_REPORT_CMD_DATA }; /* clear screen */ + + int init, index; + unsigned char cs, line; + + + DEBUG("entering\n"); + drv_pLG_send(cmd, 3); + + for (init = 0; init < 4; init++) { + unsigned char cs = ((init << 2) & 0xFF); + + cmd2[0] = OUT_REPORT_CMD; + cmd2[1] = cs; + cmd2[2] = 0x02; + cmd2[3] = 0x00; + cmd2[4] = 0x64; + cmd2[5] = 0x3F; + cmd2[6] = 0x00; + cmd2[7] = 0x64; + cmd2[8] = 0xC0; + + drv_pLG_send(cmd2, 9); + } + + for (cs = 0; cs < 4; cs++) { + unsigned char chipsel = (cs << 2); //chipselect + for (line = 0; line < 8; line++) { + //ha64_1.setHIDPkt(OUT_REPORT_CMD_DATA, 8+3+32, 8, cs, 0x02, 0x00, 0x00, 0xb8|j, 0x00, 0x00, 0x40); + cmd3[0] = OUT_REPORT_CMD_DATA; + cmd3[1] = chipsel; + cmd3[2] = 0x02; + cmd3[3] = 0x00; + cmd3[4] = 0x00; + cmd3[5] = 0xb8 | line; + cmd3[6] = 0x00; + cmd3[7] = 0x00; + cmd3[8] = 0x40; + cmd3[9] = 0x00; + cmd3[10] = 0x00; + cmd3[11] = 32; + + unsigned char temp = 0; + + for (index = 0; index < 32; index++) { + cmd3[12 + index] = temp; + } + + drv_pLG_send(cmd3, 64); + + //ha64_2.setHIDPkt(OUT_REPORT_DATA, 4+32, 4, cs | 0x01, 0x00, 0x00, 32); + + cmd4[0] = OUT_REPORT_DATA; + cmd4[1] = chipsel | 0x01; + cmd4[2] = 0x00; + cmd4[3] = 0x00; + cmd4[4] = 32; + + for (index = 32; index < 64; index++) { + temp = 0x00; + cmd4[5 + (index - 32)] = temp; + } + drv_pLG_send(cmd4, 64); + } + } +} + +#ifdef ENABLE_GPIO_KEYPAD +/**************************************\ +* * +* Routines for GPI, GPO & Keypad * +* * +\**************************************/ + +#define _USBLCD_MAX_DATA_LEN 24 +#define IN_REPORT_KEY_STATE 0x11 + +typedef enum { + WIDGET_KEY_UP = 1, + WIDGET_KEY_DOWN = 2, + WIDGET_KEY_LEFT = 4, + WIDGET_KEY_RIGHT = 8, + WIDGET_KEY_CONFIRM = 16, + WIDGET_KEY_CANCEL = 32, + WIDGET_KEY_PRESSED = 64, + WIDGET_KEY_RELEASED = 128 +} KEYPADKEY; + +int cDriverPicoLCD_256x64::drv_pLG_gpi( __attribute__ ((unused)) + int num) +{ + int ret; + unsigned char read_packet[_USBLCD_MAX_DATA_LEN]; + ret = drv_pLG_read(read_packet, _USBLCD_MAX_DATA_LEN); + if ((ret > 0) && (read_packet[0] == IN_REPORT_KEY_STATE)) { +// DEBUG("picoLCD: pressed key= 0x%02x\n", read_packet[1]); + return read_packet[1]; + } + return 0; +} + + +int cDriverPicoLCD_256x64::drv_pLG_gpo(int num, int val) +{ + unsigned char cmd[2] = { 0x81 }; /* set GPO */ + + if (num < 0) + num = 0; + if (num > 7) + num = 7; + + if (val < 0) + val = 0; + if (val > 1) + val = 1; + + /* set led bit to 1 or 0 */ + if (val) + gpo |= 1 << num; + else + gpo &= ~(1 << num); + + cmd[1] = gpo; + drv_pLG_send(cmd, 2); + + return val; +} + + +void cDriverPicoLCD_256x64::drv_pLG_update_keypad(void) +{ + static int pressed_key = 0; + + int ret; + unsigned char read_packet[_USBLCD_MAX_DATA_LEN]; + ret = drv_pLG_read(read_packet, _USBLCD_MAX_DATA_LEN); + if ((ret > 0) && (read_packet[0] == IN_REPORT_KEY_STATE)) { +// DEBUG("picoLCD: pressed key= 0x%02x\n", read_packet[1]); + int new_pressed_key = read_packet[1]; + if (pressed_key != new_pressed_key) { + /* negative values mark a key release */ +// drv_generic_keypad_press(-pressed_key); +// drv_generic_keypad_press(new_pressed_key); + pressed_key = new_pressed_key; + } + } +} + + +int cDriverPicoLCD_256x64::drv_pLG_keypad(const int num) +{ + int val; + int new_num = num; + + if (new_num == 0) + return 0; + else if (new_num > 0) + val = WIDGET_KEY_PRESSED; + else { + /* negative values mark a key release */ + new_num = -num; + val = WIDGET_KEY_RELEASED; + } + + switch (new_num) { + case 1: + val += WIDGET_KEY_CANCEL; + break; + case 2: + val += WIDGET_KEY_LEFT; + break; + case 3: + val += WIDGET_KEY_RIGHT; + break; + case 5: + val += WIDGET_KEY_UP; + break; + case 6: + val += WIDGET_KEY_CONFIRM; + break; + case 7: + val += WIDGET_KEY_DOWN; + break; + default: + fprintf(stderr,"picoLCD_256x64: unknown keypad value %d", num); + } + + return val; +} +#endif + +// /namespace +} + diff --git a/glcddrivers/picoLCD_256x64.h b/glcddrivers/picoLCD_256x64.h new file mode 100644 index 0000000..223d748 --- /dev/null +++ b/glcddrivers/picoLCD_256x64.h @@ -0,0 +1,106 @@ +/* + * GraphLCD driver library + * + * PicoLCD_256x64.h - picoLCD Graphic 256x64 + * Output goes to a picoLCD Graphic 256x64 LCD + * + * Driver is based on lcd4linux driver by Nicu Pavel, Mini-Box.com <npavel@mini-box.com> + * + * This file is released under the GNU General Public License. + * + * See the files README and COPYING for details. + * + * 2012 by Jochen Koch <linuxfan1992 AT web de> + */ + +#ifndef _GLCDDRIVERS_PicoLCD_256x64_H_ +#define _GLCDDRIVERS_PicoLCD_256x64_H_ + +#include "driver.h" +#include "stdio.h" +#include <usb.h> +#include <syslog.h> + +#define HAVE_STDBOOL_H + +#define picoLCD_VENDOR 0x04d8 +#define picoLCD_DEVICE 0xc002 + +#define OUT_REPORT_LED_STATE 0x81 +#define OUT_REPORT_LCD_BACKLIGHT 0x91 +#define OUT_REPORT_LCD_CONTRAST 0x92 + +#define OUT_REPORT_CMD 0x94 +#define OUT_REPORT_DATA 0x95 +#define OUT_REPORT_CMD_DATA 0x96 + +#define SCREEN_H 64 +#define SCREEN_W 256 + +#if 0 +#define DEBUG(x) fprintf(stderr,"picoLCD_256x64: %s(): " #x "\n", __FUNCTION__); +#define DEBUG1(x,...) fprintf(stderr,"picoLCD_256x64: %s(): " #x "\n", __FUNCTION__, __VA_ARGS__); +#else +#define DEBUG(x) +#define DEBUG1(x,...) +#endif + +#define INFO(x) syslog(LOG_INFO, "picoLCD_256x64: %s\n", x); +#define INFO1(x,...) syslog(LOG_INFO, "picoLCD_256x64: " #x "\n", __VA_ARGS__); + +namespace GLCD +{ + class cDriverConfig; + + class cDriverPicoLCD_256x64 : public cDriver + { + /* "dirty" marks the display to be redrawn from frame buffer */ + int dirty; + + /* USB read timeout in ms (the picoLCD 256x64 times out on every read + unless a key has been pressed!) */ + int read_timeout; + + unsigned char *pLG_framebuffer; + + /* used to display white text on black background or inverse */ + unsigned char inverted; + + unsigned int gpo; + + usb_dev_handle *lcd; + + int CheckSetup(); + protected: + int drv_pLG_open(void); + int drv_pLG_read(unsigned char *data, int size); + void drv_pLG_send(unsigned char *data, int size); + int drv_pLG_close(void); + void drv_pLG_clear(void); +#ifdef ENABLE_GPIO_KEYPAD + // GPI, GPO, Keypad + int drv_pLG_gpi(int num); + int drv_pLG_gpo(int num, int val); + void drv_pLG_update_keypad(void); + int drv_pLG_keypad(const int num); +#endif + + public: + cDriverPicoLCD_256x64(cDriverConfig * config); + + virtual int Init(); + virtual int DeInit(); + + virtual void Clear(); + virtual void SetPixel(int x, int y, uint32_t data); + //virtual void Set8Pixels(int x, int y, byte data); + virtual void Refresh(bool refreshAll = false); + + virtual void SetBacklight(unsigned int percent); + virtual void SetContrast(unsigned int percent); + }; +}; +#endif + + + |