]> git.webhop.me Git - lcd4linux.git/commitdiff
add shuttle VFD driver
authormichux <michux@3ae390bd-cb1e-0410-b409-cd5a39f66f1f>
Mon, 6 Apr 2009 20:03:37 +0000 (20:03 +0000)
committermichux <michux@3ae390bd-cb1e-0410-b409-cd5a39f66f1f>
Mon, 6 Apr 2009 20:03:37 +0000 (20:03 +0000)
git-svn-id: https://ssl.bulix.org/svn/lcd4linux/trunk@1022 3ae390bd-cb1e-0410-b409-cd5a39f66f1f

Makefile.am
drivers.m4
drv.c
drv_ShuttleVFD.c [new file with mode: 0644]

index f4889bc9159979e6ef36ec58092e7bef84c1144a..8e1a997bc553c067a214535e12491f6be3843f3c 100644 (file)
@@ -99,6 +99,7 @@ drv_RouterBoard.c             \
 drv_Sample.c                  \
 drv_st2205.c                  \
 drv_serdisplib.c              \
+drv_ShuttleVFD.c              \
 drv_SimpleLCD.c               \
 drv_T6963.c                   \
 drv_Trefon.c                  \
index decfe0e5a4adbe261a22c7c23dc4b2ec989b1508..2f19f5d014e99672291bbb73741524420aa4ccca 100644 (file)
@@ -36,9 +36,9 @@ AC_ARG_WITH(
   [                        G15, GLCD2USB, HD44780, IRLCD, LCD2USB, LCDLinux, LCDTerm,]
   [                        LPH7508, LUIse, M50530, MatrixOrbital, MilfordInstruments,]
   [                        Noritake, NULL, PNG, PPM, Pertelian, PHAnderson, picoLCD,]
-  [                        picoLCDGraphic, RouterBoard, Sample, serdisplib, SimpleLCD,]
-  [                        st2205, T6963, Trefon, ULA200, USBLCD, USBHUB, VNC,]
-  [                        WincorNixdorf, X11],
+  [                        picoLCDGraphic, RouterBoard, Sample, serdisplib, ShuttleVFD,]
+  [                        SimpleLCD, st2205, T6963, Trefon, ULA200, USBLCD, USBHUB,]
+  [                        VNC, WincorNixdorf, X11],
   drivers=$withval,
   drivers=all
 )
@@ -92,6 +92,7 @@ for driver in $drivers; do
          SAMPLE="yes"
          ST2205="yes"
         SERDISPLIB="yes"
+        SHUTTLEVFD="yes"
          SIMPLELCD="yes"
          T6963="yes"
          Trefon="yes"
@@ -186,7 +187,6 @@ for driver in $drivers; do
       picoLCDGraphic)
          PICOLCDGRAPHIC=$val
          ;;
-
       PNG)
          PNG=$val
          ;;
@@ -202,6 +202,9 @@ for driver in $drivers; do
       serdisplib)
          SERDISPLIB=$val;
          ;;
+      ShuttleVFD) 
+        SHUTTLEVFD=$val 
+        ;;          
       SimpleLCD)
          SIMPLELCD=$val
          ;;
@@ -576,6 +579,18 @@ if test "$SERDISPLIB" = "yes"; then
    fi
 fi
 
+if test "$SHUTTLEVFD" = "yes"; then 
+    if test "$has_usb" = "true"; then 
+    TEXT="yes" 
+    GPIO="yes" 
+    DRIVERS="$DRIVERS drv_ShuttleVFD.o" 
+    LIBUSB="yes" 
+    AC_DEFINE(WITH_SHUTTLEVFD,1,[ShuttleVFD driver]) 
+    else 
+      AC_MSG_WARN(usb.h not found: ShuttleVFD driver disabled) 
+    fi 
+fi 
+
 if test "$SIMPLELCD" = "yes"; then
    TEXT="yes"
    SERIAL="yes"
diff --git a/drv.c b/drv.c
index ddabf90e2da54be02a765f299498fb155ba89069..cc854f11f4f1cb1050275dc09274c2389c6186ef 100644 (file)
--- a/drv.c
+++ b/drv.c
@@ -78,6 +78,7 @@ extern DRIVER drv_RouterBoard;
 extern DRIVER drv_Sample;
 extern DRIVER drv_st2205;
 extern DRIVER drv_serdisplib;
+extern DRIVER drv_ShuttleVFD;
 extern DRIVER drv_SimpleLCD;
 extern DRIVER drv_T6963;
 extern DRIVER drv_Trefon;
@@ -185,6 +186,9 @@ DRIVER *Driver[] = {
 #ifdef WITH_ST2205
     &drv_st2205,
 #endif
+#ifdef WITH_SHUTTLEVFD
+    &drv_ShuttleVFD, 
+#endif 
 #ifdef WITH_SERDISPLIB
     &drv_serdisplib,
 #endif
diff --git a/drv_ShuttleVFD.c b/drv_ShuttleVFD.c
new file mode 100644 (file)
index 0000000..5eb4268
--- /dev/null
@@ -0,0 +1,430 @@
+/* $Id: drv_Sample.c 975 2009-01-18 11:16:20Z michael $
+ * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_Sample.c $
+ *
+ * Shuttle SG33G5M VFD lcd4linux driver
+ *
+ * Copyright (C) 2009 Matthieu Crapet <mcrapet@gmail.com>
+ * based on the USBLCD driver.
+ *
+ * Shuttle SG33G5M VFD (20x1 character display. Each character cell is 5x8 pixels)
+ * - The display is driven by Princeton Technologies PT6314 VFD controller
+ * - Cypress CY7C63723C (receives USB commands and talk to VFD controller)
+ *
+ * LCD "prococol" : each message has a length of 8 bytes
+ * - 1 nibble: command (0x1, 0x3, 0x7, 0x9, 0xD)
+ *     - 0x1 : clear text and icons (len=1)
+ *     - 0x7 : icons (len=4)
+ *     - 0x9 : text (len=7)
+ *     - 0xD : set clock data (len=7)
+ *     - 0x3 : display clock (internal feature) (len=1)
+ * - 1 nibble: message length (0-7)
+ * - 7 bytes : message data
+ *
+ * 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_ShuttleVFD
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_USB_H
+#include <usb.h>
+#else
+#error "ShuttleVFD: libusb required"
+#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_bar.h"                // for DIRECTION
+#include "drv.h"
+#include "drv_generic_text.h"
+#include "drv_generic_gpio.h"
+
+
+/*
+ * Some hardware definitions
+ */
+// VFD USB properties
+#define SHUTTLE_VFD_VENDOR_ID   0x051C
+#define SHUTTLE_VFD_PRODUCT_ID1 0x0003
+#define SHUTTLE_VFD_PRODUCT_ID2 0x0005 // IR-receiver included
+#define SHUTTLE_VFD_INTERFACE_NUM    1
+
+// VFD physical dimensions
+#define SHUTTLE_VFD_WIDTH           20
+#define SHUTTLE_VFD_HEIGHT           1
+
+// VFD USB control message
+#define SHUTTLE_VFD_PACKET_SIZE         8
+#define SHUTTLE_VFD_DATA_SIZE           (SHUTTLE_VFD_PACKET_SIZE-1)
+#define SHUTTLE_VFD_SUCCESS_SLEEP_USEC  25600
+
+
+/* Global static data */
+static char Name[] = "ShuttleVFD";
+static usb_dev_handle *lcd;
+static unsigned char buffer[SHUTTLE_VFD_PACKET_SIZE];
+
+/* Issues with the display module:
+ *  - Can't set cursor position. Must save full buffer here.
+ *  - Can't get icons status (on or off). Must save status here.
+ *  - Clear command also clear text AND icons.
+ */
+static unsigned char fb[SHUTTLE_VFD_WIDTH * SHUTTLE_VFD_HEIGHT];
+static unsigned icons;
+
+
+/****************************************/
+/***  hardware dependant functions    ***/
+/****************************************/
+
+/* look for device on USB bus */
+static int drv_ShuttleVFD_open(void)
+{
+    struct usb_bus *bus;
+    struct usb_device *dev;
+
+    int vendor_id = SHUTTLE_VFD_VENDOR_ID;
+    int interface = SHUTTLE_VFD_INTERFACE_NUM;
+
+    lcd = NULL;
+
+    usb_init();
+    usb_find_busses();
+    usb_find_devices();
+
+    for (bus = usb_get_busses(); bus != NULL; bus = bus->next) {
+       for (dev = bus->devices; dev != NULL; dev = dev->next) {
+               if (dev->descriptor.idVendor == vendor_id && (
+                       (dev->descriptor.idProduct == SHUTTLE_VFD_PRODUCT_ID1) ||
+                       (dev->descriptor.idProduct == SHUTTLE_VFD_PRODUCT_ID2))) {
+
+               unsigned int v = dev->descriptor.bcdDevice;
+
+               info("%s: found ShuttleVFD V%1d%1d.%1d%1d on bus %s device %s", Name,
+                    (v & 0xF000) >> 12, (v & 0xF00) >> 8, (v & 0xF0) >> 4, (v & 0xF), bus->dirname, dev->filename);
+
+               lcd = usb_open(dev);
+           }
+       }
+    }
+
+    if (lcd != NULL) {
+       if (usb_claim_interface(lcd, interface) < 0) {
+           usb_close(lcd);
+           error("%s: usb_claim_interface() failed!", Name);
+           error("%s: root permissions maybe required?", Name);
+           return -1;
+       }
+    } else {
+       error("%s: could not find ShuttleVFD", Name);
+       return -1;
+    }
+
+    return 0;
+}
+
+
+static int drv_ShuttleVFD_close(void)
+{
+    int interface = SHUTTLE_VFD_INTERFACE_NUM;
+
+    usb_release_interface(lcd, interface);
+    usb_close(lcd);
+    return 0;
+}
+
+
+static void drv_ShuttleVFD_send(unsigned char packet[SHUTTLE_VFD_PACKET_SIZE])
+{
+    if (usb_control_msg(lcd, 0x21,     // requesttype
+                       0x09,   // request
+                       0x0200, // value
+                       0x0001, // index
+                       (char *) packet, SHUTTLE_VFD_PACKET_SIZE, 100) == SHUTTLE_VFD_PACKET_SIZE) {
+
+       udelay(SHUTTLE_VFD_SUCCESS_SLEEP_USEC);
+    } else {
+       debug("usb_control_msg failed");
+    }
+}
+
+
+/* Clear full display and icons. */
+static void drv_ShuttleVFD_clear(void)
+{
+    // Update local framebuffer mirror
+    memset(fb, ' ', SHUTTLE_VFD_HEIGHT * SHUTTLE_VFD_WIDTH);
+
+    buffer[0] = (1 << 4) + 1;
+    buffer[1] = 0x1;
+    drv_ShuttleVFD_send(buffer);
+}
+
+
+static void drv_ShuttleVFD_reset_cursor(void)
+{
+    buffer[0] = (1 << 4) + 1;
+    buffer[1] = 0x2;
+    drv_ShuttleVFD_send(buffer);
+}
+
+
+/* text mode displays only */
+static void drv_ShuttleVFD_write(const int row, const int col, const char *data, int len)
+{
+    unsigned char *p;
+    int i;
+
+    // Update local framebuffer mirror
+    memcpy(fb + (row * SHUTTLE_VFD_WIDTH) + col, data, len);
+
+    p = fb;
+    len = SHUTTLE_VFD_WIDTH;
+
+    drv_ShuttleVFD_reset_cursor();
+
+    while (len > 0) {
+       if (len > 7)
+           buffer[0] = (9 << 4) + 7;
+       else
+           buffer[0] = (9 << 4) + len;
+
+       for (i = 0; i < 7 && len--; i++) {
+           buffer[i + 1] = *p++;
+       }
+
+       drv_ShuttleVFD_send(buffer);
+    }
+}
+
+
+static void drv_ShuttleVFD_defchar(const int ascii, const unsigned char *matrix)
+{
+    (void)matrix;
+    debug("%s: not available (ascii=%d)", Name, ascii);
+}
+
+
+static int drv_ShuttleVFD_start(const char *section)
+{
+    char *port;
+
+    port = cfg_get(section, "Port", NULL);
+
+    if (port == NULL || *port == '\0') {
+       error("%s: no '%s.Port' entry from %s", Name, section, cfg_source());
+       return -1;
+    }
+
+    if (strcasecmp(port, "libusb") != 0) {
+       error("%s: libusb expected", Name);
+       error("%s: compile lcd4linux with libusb support!", Name);
+       return -1;
+    }
+
+    DROWS = SHUTTLE_VFD_HEIGHT;
+    DCOLS = SHUTTLE_VFD_WIDTH;
+
+    /* open communication with the display */
+    if (drv_ShuttleVFD_open() < 0) {
+       return -1;
+    }
+
+    drv_ShuttleVFD_clear();    /* clear display */
+    return 0;
+}
+
+
+/* VFD Icons. Add +1 in lcd4linux.conf (GPO1..GPIO27)
+ *  0: television
+ *  1: cd/dvd
+ *  2: music
+ *  3: radio
+ *  4: clock
+ *  5: pause
+ *  6: play
+ *  7: record
+ *  8: rewind
+ *  9: camera
+ * 10: mute
+ * 11: repeat
+ * 12: reverse
+ * 13: fastforward
+ * 14: stop
+ * 15: volume 1
+ * 16: volume 2
+ * ...
+ * 25: volume 11
+ * 26: volume 12
+ */
+static int drv_ShuttleVFD_icons_set(const int num, const int val)
+{
+    unsigned long value;
+
+    if (num < 0 || num >= 27) {
+       info("%s: num %d out of range (1..27)", Name, num);
+       return -1;
+    }
+    // Special case for volume (icon n°16)
+    if (num >= 15)
+       value = (num - 15 + 1) << 15;
+    else
+       value = 1 << num;
+
+    if (val > 0)
+       icons |= value;
+    else
+       icons &= ~value;
+
+    buffer[0] = (7 << 4) + 4;
+    buffer[1] = (value >> 15) & 0x1F;
+    buffer[2] = (value >> 10) & 0x1F;
+    buffer[3] = (value >> 5) & 0x1F;
+    buffer[4] = value & 0x1F;  // each data byte is stored on 5 bits
+    drv_ShuttleVFD_send(buffer);
+
+    return 0;
+}
+
+
+/****************************************/
+/***            plugins               ***/
+/****************************************/
+
+/* none yet ! */
+
+
+/****************************************/
+/***        widget callbacks          ***/
+/****************************************/
+
+/* using drv_generic_text_draw(W) */
+/* using drv_generic_gpio_draw(W) */
+
+
+/****************************************/
+/***        exported functions        ***/
+/****************************************/
+
+
+/* supported Shuttle models */
+int drv_ShuttleVFD_list(void)
+{
+    printf("Shuttle SG33G5M, Shuttle PF27 upgrade kit");
+    return 0;
+}
+
+
+/* initialize driver & text display */
+int drv_ShuttleVFD_init(const char *section, const int quiet)
+{
+    WIDGET_CLASS wc;
+    int ret;
+
+    info("%s: %s", Name, "$Rev: 975 $");
+
+    /* display preferences */
+    XRES = 5;                  /* pixel width of one char  */
+    YRES = 8;                  /* pixel height of one char  */
+    CHARS = 0;                 /* number of user-defineable characters */
+    CHAR0 = 0;                 /* ASCII of first user-defineable char */
+    GOTO_COST = 2;             /* number of bytes a goto command requires */
+    GPOS = 15 + 12;            /* Fancy icons on top of display */
+
+    /* real worker functions */
+    drv_generic_text_real_write = drv_ShuttleVFD_write;
+    drv_generic_text_real_defchar = drv_ShuttleVFD_defchar;
+    drv_generic_gpio_real_set = drv_ShuttleVFD_icons_set;
+
+    /* start display */
+    if ((ret = drv_ShuttleVFD_start(section)) != 0)
+       return ret;
+
+    if (!quiet) {
+       char buffer[40];
+       qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS);
+       if (drv_generic_text_greet(buffer, "Shuttle")) {
+           sleep(3);
+           drv_ShuttleVFD_clear();
+       }
+    }
+
+    /* initialize generic text driver */
+    if ((ret = drv_generic_text_init(section, Name)) != 0)
+       return ret;
+
+    /* initialize generic GPIO driver */
+    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);
+
+    return 0;
+}
+
+
+/* close driver & text display */
+int drv_ShuttleVFD_quit(const int quiet)
+{
+    info("%s: shutting down.", Name);
+
+    /* clear display */
+    drv_ShuttleVFD_clear();
+
+    /* say goodbye... */
+    if (!quiet) {
+       drv_generic_text_greet("goodbye!", NULL);
+    }
+
+    drv_generic_text_quit();
+    drv_generic_gpio_quit();
+
+    debug("closing connection");
+    drv_ShuttleVFD_close();
+
+    return (0);
+}
+
+
+DRIVER drv_ShuttleVFD = {
+    .name = Name,
+    .list = drv_ShuttleVFD_list,
+    .init = drv_ShuttleVFD_init,
+    .quit = drv_ShuttleVFD_quit,
+};