From 1d71c6d777e1f8cc91921f612b27518459b66528 Mon Sep 17 00:00:00 2001 From: michael Date: Fri, 19 Jan 2007 16:34:43 +0000 Subject: driver for picoLCD displays from mini-box.com by Nicu Pavel git-svn-id: https://ssl.bulix.org/svn/lcd4linux/trunk@747 3ae390bd-cb1e-0410-b409-cd5a39f66f1f --- Makefile.am | 1 + drivers.m4 | 17 +- drv.c | 5 + drv_picoLCD.c | 512 ++++++++++++++++++++++++++++++++++++++++++++++++++ lcd4linux.conf.sample | 8 + 5 files changed, 541 insertions(+), 2 deletions(-) create mode 100644 drv_picoLCD.c diff --git a/Makefile.am b/Makefile.am index e1d2c1d..3d01351 100644 --- a/Makefile.am +++ b/Makefile.am @@ -83,6 +83,7 @@ drv_MatrixOrbital.c \ drv_MilfordInstruments.c \ drv_Noritake.c \ drv_NULL.c \ +drv_picoLCD.c \ drv_RouterBoard.c \ drv_Sample.c \ drv_serdisplib.c \ diff --git a/drivers.m4 b/drivers.m4 index 0976d50..e0d0cbe 100644 --- a/drivers.m4 +++ b/drivers.m4 @@ -35,7 +35,7 @@ AC_ARG_WITH( [ BeckmannEgle, BWCT, CrystalFontz, Curses, Cwlinux,] [ G15, HD44780, LCD2USB LCDLinux, LCDTerm, LPH7508,] [ LUIse, M50530, MatrixOrbital, MilfordInstruments,] - [ Noritake, NULL, PNG, PPM, RouterBoard, Sample,] + [ Noritake, NULL, PNG, PPM, picoLCD, RouterBoard, Sample,] [ serdisplib, SimpleLCD, T6963, Trefon, USBLCD,] [ USBHUB, WincorNixdorf, X11], drivers=$withval, @@ -76,9 +76,10 @@ for driver in $drivers; do MILINST="yes" NORITAKE="yes" NULL="yes" + picoLCD="yes" PNG="yes" PPM="yes" - ROUTERBOARD="yes" + ROUTERBOARD="yes" SAMPLE="yes" SERDISPLIB="yes" SIMPLELCD="yes" @@ -146,6 +147,9 @@ for driver in $drivers; do NULL) NULL=$val; ;; + picoLCD) + picoLCD=$val + ;; PNG) PNG=$val ;; @@ -375,6 +379,15 @@ if test "$NULL" = "yes"; then AC_DEFINE(WITH_NULL,1,[NULL driver]) fi +if test "$picoLCD" = "yes"; then + TEXT="yes" + GPIO="yes" + SERIAL="yes" + #I2C="yes" + DRIVERS="$DRIVERS drv_picoLCD.o" + AC_DEFINE(WITH_picoLCD,1,[picoLCD driver]) +fi + if test "$PNG" = "yes"; then if test "$has_gd" = "true"; then IMAGE="yes" diff --git a/drv.c b/drv.c index 13bbc3b..da161a8 100644 --- a/drv.c +++ b/drv.c @@ -66,6 +66,7 @@ extern DRIVER drv_MatrixOrbital; extern DRIVER drv_MilfordInstruments; extern DRIVER drv_Noritake; extern DRIVER drv_NULL; +extern DRIVER drv_picoLCD; extern DRIVER drv_RouterBoard; extern DRIVER drv_Sample; extern DRIVER drv_serdisplib; @@ -141,6 +142,10 @@ DRIVER *Driver[] = { #ifdef WITH_NULL &drv_NULL, #endif +#ifdef WITH_picoLCD + &drv_picoLCD, +#endif + #ifdef WITH_ROUTERBOARD &drv_RouterBoard, #endif diff --git a/drv_picoLCD.c b/drv_picoLCD.c new file mode 100644 index 0000000..dafd496 --- /dev/null +++ b/drv_picoLCD.c @@ -0,0 +1,512 @@ +/* $Id$ + * $URL$ + * + * driver for picoLCD displays from mini-box.com + * + * Copyright (C) 2005 Michael Reinelt + * Copyright (C) 2005, 2006, 2007 The LCD4Linux Team + * + * Copyright (C) 2007 Nicu Pavel, Mini-Box.com + * + * This file is part of LCD4Linux. + * + * LCD4Linux is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * LCD4Linux is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * + * exported fuctions: + * + * struct DRIVER drv_picoLCD + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_USB_H +#include +#endif + +#include "debug.h" +#include "cfg.h" +#include "qprintf.h" +#include "udelay.h" +#include "plugin.h" +#include "widget.h" +#include "widget_text.h" +#include "widget_icon.h" +#include "widget_bar.h" +#include "drv.h" +#include "drv_generic_text.h" +#include "drv_generic_gpio.h" +#include "drv_generic_keypad.h" + + + +#define picoLCD_VENDOR 0x04d8 +#define picoLCD_DEVICE 0x0002 + +static char Name[] = "picoLCD"; + +static int use_libusb = 1; +static unsigned int gpo = 0; + +static char *Buffer; +static char *BufPtr; + +#ifdef HAVE_USB_H + +static usb_dev_handle *lcd; +static int interface; + +extern int usb_debug; + +#endif + + + +/****************************************/ +/*** hardware dependant functions ***/ +/****************************************/ + +#ifdef HAVE_USB_H + +static int drv_pL_open(void) +{ + struct usb_bus *busses, *bus; + struct usb_device *dev; + char buf[1024]; + int ret; + + lcd = NULL; + + info("%s: scanning for picoLCD...", Name); + + usb_debug = 0; + + 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)) { + + info("%s: found picoLCD on bus %s device %s", Name, bus->dirname, dev->filename); + + interface = 0; + lcd = usb_open(dev); + + ret = usb_get_driver_np(lcd, 0, buf, sizeof(buf)); + + if (ret == 0) { + info("interface 0 already claimed attempting to detach it\n"); + ret = usb_detach_kernel_driver_np(lcd, 0); + printf("usb_detach_kernel_driver_np returned %d\n", ret); + } + + if (usb_claim_interface(lcd, interface) < 0) { + error("%s: usb_claim_interface() failed!", Name); + return -1; + } + return 0; + } + } + } + error("%s: could not find a picoLCD", Name); + return -1; +} + + +static int drv_pL_close(void) +{ + usb_release_interface(lcd, interface); + usb_close(lcd); + + return 0; +} + +#endif + + +static void drv_pL_send(void) +{ + +#if 0 + struct timeval now, end; + gettimeofday(&now, NULL); +#endif + + if (use_libusb) { +#ifdef HAVE_USB_H + usb_bulk_write(lcd, USB_ENDPOINT_OUT + 1, Buffer, BufPtr - Buffer, 1000); +#endif + } + +#if 0 + gettimeofday(&end, NULL); + debug("send %d bytes in %d usec (%d usec/byte)", BufPtr - Buffer, + (1000000 * (end.tv_sec - now.tv_sec) + end.tv_usec - now.tv_usec), + (1000000 * (end.tv_sec - now.tv_sec) + end.tv_usec - now.tv_usec) / (BufPtr - Buffer)); +#endif + + BufPtr = Buffer; +} + + +static void drv_pL_command(const unsigned char cmd) +{ + *BufPtr++ = cmd; +} + + +static void drv_pL_clear(void) +{ + drv_pL_command(0x94); /* clear display */ + drv_pL_send(); /* flush buffer */ +} + +static int drv_pL_contrast(int contrast) +{ + + if (contrast < 0) + contrast = 0; + if (contrast > 255) + contrast = 255; + + drv_pL_command(0x92); + drv_pL_command(contrast); + + drv_pL_send(); + + return contrast; +} + + +static int drv_pL_backlight(int backlight) +{ + if (backlight < 0) + backlight = 0; + if (backlight > 1) + backlight = 1; + + drv_pL_command(0x91); + drv_pL_command(backlight); + + drv_pL_send(); + + return backlight; +} + +static int drv_pL_gpo(int num, int val) +{ + 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); + + drv_pL_command(0x81); + drv_pL_command(gpo); + + return val; +} + + +static void drv_pL_write(const int row, const int col, const char *data, int len) +{ + + drv_pL_command(0x98); + drv_pL_command(row); + drv_pL_command(col); + drv_pL_command(len); + + while (len--) { + if (*data == 0) + *BufPtr++ = 0; + *BufPtr++ = *data++; + } + + drv_pL_send(); +} + +static void drv_pL_defchar(const int ascii, const unsigned char *matrix) +{ + int i; + + drv_pL_command(0x9c); + drv_pL_command(ascii); + + for (i = 0; i < 8; i++) { + if ((*matrix & 0x1f) == 0) + *BufPtr++ = 0; + *BufPtr++ = *matrix++ & 0x1f; + } + + drv_pL_send(); +} + + +static int drv_pL_start(const char *section, const int quiet) +{ + int rows = -1, cols = -1; + int value; + char *s; + +#ifdef HAVE_USB_H + use_libusb = 1; + debug("using libusb"); +#else + error("%s: lcd4linux was compiled without libusb support!", Name); + return -1; +#endif + + s = cfg_get(section, "Size", NULL); + if (s == NULL || *s == '\0') { + error("%s: no '%s.Size' entry from %s", Name, section, cfg_source()); + return -1; + } + if (sscanf(s, "%dx%d", &cols, &rows) != 2 || rows < 1 || cols < 1) { + error("%s: bad %s.Size '%s' from %s", Name, section, s, cfg_source()); + free(s); + return -1; + } + + DROWS = rows; + DCOLS = cols; + + +#ifdef HAVE_USB_H + if (drv_pL_open() < 0) { + return -1; + } +#endif + + + /* Init the command buffer */ + Buffer = (char *) malloc(1024); + if (Buffer == NULL) { + error("%s: coommand buffer could not be allocated: malloc() failed", Name); + return -1; + } + BufPtr = Buffer; + + if (cfg_number(section, "Contrast", 0, 0, 255, &value) > 0) { + info("Setting contrast to %d\n", value); + drv_pL_contrast(value); + } + + if (cfg_number(section, "Backlight", 0, 0, 1, &value) > 0) { + info("Setting backlight to %d\n", value); + drv_pL_backlight(value); + } + + drv_pL_clear(); /* clear display */ + + if (!quiet) { + char buffer[40]; + qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS); + if (drv_generic_text_greet(buffer, "http://www.picolcd.com")) { + sleep(3); + drv_pL_clear(); + } + } + + return 0; +} + + +/****************************************/ +/*** plugins ***/ +/****************************************/ + +static void plugin_contrast(RESULT * result, RESULT * arg1) +{ + double contrast; + + contrast = drv_pL_contrast(R2N(arg1)); + SetResult(&result, R_NUMBER, &contrast); +} + +static void plugin_backlight(RESULT * result, RESULT * arg1) +{ + double backlight; + + backlight = drv_pL_backlight(R2N(arg1)); + SetResult(&result, R_NUMBER, &backlight); +} + +static void plugin_gpo(RESULT * result, RESULT * argv[]) +{ + double gpo; + gpo = drv_pL_gpo(R2N(argv[0]), R2N(argv[1])); + SetResult(&result, R_NUMBER, &gpo); +} + + +/****************************************/ +/*** widget callbacks ***/ +/****************************************/ + + +/* using drv_generic_text_draw(W) */ +/* using drv_generic_text_icon_draw(W) */ +/* using drv_generic_text_bar_draw(W) */ + + +/****************************************/ +/*** exported functions ***/ +/****************************************/ + + +/* list models */ +int drv_pL_list(void) +{ + printf("generic"); + return 0; +} + + +/* initialize driver & display */ +int drv_pL_init(const char *section, const int quiet) +{ + WIDGET_CLASS wc; + int ret; + + info("%s: %s", Name, "$Rev$"); + + /* display preferences */ + XRES = 5; /* pixel width of one char */ + YRES = 8; /* pixel height of one char */ + CHARS = 8; /* number of user-defineable characters */ + CHAR0 = 0; /* ASCII of first user-defineable char */ + GPOS = 8; + INVALIDATE = 1; + GOTO_COST = 2; /* number of bytes a goto command requires */ + + /* real worker functions */ + drv_generic_text_real_write = drv_pL_write; + drv_generic_text_real_defchar = drv_pL_defchar; + drv_generic_gpio_real_set = drv_pL_gpo; + + /* start display */ + if ((ret = drv_pL_start(section, quiet)) != 0) + return ret; + + /* initialize generic text driver */ + if ((ret = drv_generic_text_init(section, Name)) != 0) + return ret; + + /* initialize generic icon driver */ + if ((ret = drv_generic_text_icon_init()) != 0) + return ret; + + /* initialize generic bar driver */ + if ((ret = drv_generic_text_bar_init(0)) != 0) + return ret; + + drv_generic_text_bar_add_segment(0, 0, 255, 32); + + /* GPO's init */ + if ((ret = drv_generic_gpio_init(section, Name)) != 0) + return ret; + + /* register text widget */ + wc = Widget_Text; + wc.draw = drv_generic_text_draw; + widget_register(&wc); + + /* register icon widget */ + wc = Widget_Icon; + wc.draw = drv_generic_text_icon_draw; + widget_register(&wc); + + /* register bar widget */ + wc = Widget_Bar; + wc.draw = drv_generic_text_bar_draw; + widget_register(&wc); + + /* register plugins */ + AddFunction("LCD::contrast", -1, plugin_contrast); + AddFunction("LCD::backlight", -1, plugin_backlight); + AddFunction("LCD::gpo", -1, plugin_gpo); + + return 0; +} + + +/* close driver & display */ +int drv_pL_quit(const int quiet) +{ + + info("%s: shutting down.", Name); + + /* flush buffer */ + drv_pL_send(); + + drv_generic_text_quit(); + + /* clear display */ + drv_pL_clear(); + + /* say goodbye... */ + if (!quiet) { + drv_generic_text_greet("goodbye!", NULL); + } + + if (use_libusb) { +#ifdef HAVE_USB_H + drv_pL_close(); +#endif + } + + if (Buffer) { + free(Buffer); + Buffer = NULL; + BufPtr = Buffer; + } + + return (0); +} + + +DRIVER drv_picoLCD = { + name:Name, + list:drv_pL_list, + init:drv_pL_init, + quit:drv_pL_quit, +}; diff --git a/lcd4linux.conf.sample b/lcd4linux.conf.sample index 56eb740..e27981d 100644 --- a/lcd4linux.conf.sample +++ b/lcd4linux.conf.sample @@ -246,6 +246,14 @@ Display HD44780-kernelconcepts { } } +Display picoLCD { + Driver 'picoLCD' + Size '20x2' + Contrast 0 + Backlight 1 + Icons 4 +} + Display SC1602D { Driver 'HD44780' Port '/dev/parports/0' -- cgit v1.2.3