diff options
author | andreas 'randy' weinberger <vdr@smue.org> | 2010-09-25 10:16:54 +0200 |
---|---|---|
committer | andreas 'randy' weinberger <vdr@smue.org> | 2010-09-25 10:16:54 +0200 |
commit | c3aacc4722ff5c441b5c36b8443d96f90dbf0ae6 (patch) | |
tree | d48b1bd49e7d2c8adaec57208281ad60b33983b8 | |
parent | 5c6cbd1eb40cf4508a42a6948b4a3166f65f7664 (diff) | |
download | graphlcd-base-c3aacc4722ff5c441b5c36b8443d96f90dbf0ae6.tar.gz graphlcd-base-c3aacc4722ff5c441b5c36b8443d96f90dbf0ae6.tar.bz2 |
added futuba MDM166A driver from andreas brachold
http://projects.vdr-developer.org/issues/351
-rw-r--r-- | README | 3 | ||||
-rw-r--r-- | docs/DRIVER.futabaMDM166A | 69 | ||||
-rw-r--r-- | glcddrivers/Makefile | 6 | ||||
-rw-r--r-- | glcddrivers/drivers.c | 10 | ||||
-rw-r--r-- | glcddrivers/drivers.h | 1 | ||||
-rw-r--r-- | glcddrivers/futabaMDM166A.c | 465 | ||||
-rw-r--r-- | glcddrivers/futabaMDM166A.h | 75 | ||||
-rw-r--r-- | graphlcd.conf | 15 |
8 files changed, 643 insertions, 1 deletions
@@ -11,7 +11,7 @@ based on the graphlcd plugin for the Video Disc Recorder from 0.0.8 on maintained by Andreas Regel (andreas.regel AT powarman.de) from 0.1.5 on maintained by Wolfgang Astleitner (mrwastl AT users.sourceforge.net) & Andreas 'randy' Weinberger (vdr AT smue.org) - gu140x32f driver by Andreas Brachold (vdr04 AT deltab.de) + gu140x32f driver by Andreas Brachold (vdr07 AT deltab.de) gu256x64-372 driver by Andreas Weinberger (vdr AT smue.org) gu256x64-3xx0 driver by Ralf Mueller (ralf AT bj-ig.de) gu126x64D-K610A4 driver by Alexander Rieger (Alexander.Rieger AT inka.de) @@ -25,6 +25,7 @@ based on the graphlcd plugin for the Video Disc Recorder t6963c driver by Andreas Regel (andreas.regel AT powarman.de) noritake800 driver by Lucian Muresan (lucianm AT users.sourceforge.net) futaba dm140 driver by Stephan Skrodzki (skrodzki AT stevekist.de) + futama md166 driver by Andreas Brachold <vdr07 AT deltab de> Project's homepage: http://graphlcd.berlios.de/ GIT repo: http://projects.vdr-developer.org/projects/show/graphlcd diff --git a/docs/DRIVER.futabaMDM166A b/docs/DRIVER.futabaMDM166A new file mode 100644 index 0000000..94e6179 --- /dev/null +++ b/docs/DRIVER.futabaMDM166A @@ -0,0 +1,69 @@ +--------------------------------------------------------------------- +GraphLCD driver library + +The futabaMDM166A driver +--------------------------------------------------------------------- + +Description +----------- +The Futaba MDM166A driver supports Futaba MDM166A VFD displays. +The VFD is connected to a PC's USB port. + +Installation Notes +------------------ + +You need installed library libhid to use the futabaMDM166A driver. +This library libhid is used to access and interact with a USB HID device. + + * http://libhid.alioth.debian.org/ + +If Debian used, you can install them with the command : + +#> apt-get install libhid-dev libhid0 + +Wirings +------- +The futabaMDM166A driver supports a connections on a USB port. + + +Configuration Parameters +------------------------ +The futabaMDM166A driver supports the following parameters in config file: + +Width + Sets the horizontal size of the display. If this parameter is not + given, a default value of 96 pixels is used. + +Height + Sets the vertical size of the display. If this parameter is not + given, a default value of 16 pixels is used. + +UpsideDown + Rotates the display output by 180 degrees. This might be useful, if + the LCD is mounted upside-down. + Possible values: 'yes', 'no' + Default value: 'no' + +Invert + Inverts the display. + Possible values: 'yes', 'no' + Default value: 'no' + +Brightness + Sets the brightness of your display's backlight. + Possible values: 0 <= x <= 100) + Default value: 50 + +RefreshDisplay + Normally, most of the drivers do not update the whole display, but + only the areas that have changed since last update. So it might be, + that some faulty pixels would stay a longer time. To avoid this, the + plugin makes a complete refresh from time to time. This parameter + defines how often a complete refresh will be done. + e.g.: A value of 5 means, that the plugin will make a complete + refresh on every 5th update. + A value of 0 completely disables complete refreshs. + Possible values: 0 <= x <= 50 + Default value: 50 + + diff --git a/glcddrivers/Makefile b/glcddrivers/Makefile index 671c581..331c829 100644 --- a/glcddrivers/Makefile +++ b/glcddrivers/Makefile @@ -18,6 +18,12 @@ OBJS = common.o config.o driver.o drivers.o port.o simlcd.o framebuffer.o gu140x HEADERS = config.h driver.h drivers.h +ifeq ($(shell pkg-config --exists libhid && echo 1), 1) +OBJS += futabaMDM166A.o +INCLUDES += $(shell pkg-config --cflags libhid) +LIBS += $(shell pkg-config --libs libhid) +DEFINES += -DHAVE_LIBHID +endif ### Implicit rules: diff --git a/glcddrivers/drivers.c b/glcddrivers/drivers.c index 08149df..946ab39 100644 --- a/glcddrivers/drivers.c +++ b/glcddrivers/drivers.c @@ -30,6 +30,9 @@ #include "dm140gink.h" #include "serdisp.h" #include "g15daemon.h" +#ifdef HAVE_LIBHID +#include "futabaMDM166A.h" +#endif namespace GLCD { @@ -52,6 +55,9 @@ tDriver drivers[] = {"network", kDriverNetwork}, {"gu126x64D-K610A4", kDriverGU126X64D_K610A4}, {"dm140gink", kDriverDM140GINK}, +#ifdef HAVE_LIBHID + {"futabaMDM166A", kDriverFutabaMDM166A}, +#endif {"serdisp", kDriverSerDisp}, {"g15daemon", kDriverG15daemon}, {"", kDriverUnknown} @@ -108,6 +114,10 @@ cDriver * CreateDriver(int driverID, cDriverConfig * config) return new cDriverGU126X64D_K610A4(config); case kDriverDM140GINK: return new cDriverDM140GINK(config); +#ifdef HAVE_LIBHID + case kDriverFutabaMDM166A: + return new cDriverFutabaMDM166A(config); +#endif case kDriverSerDisp: return new cDriverSerDisp(config); case kDriverG15daemon: diff --git a/glcddrivers/drivers.h b/glcddrivers/drivers.h index 08054ec..b088713 100644 --- a/glcddrivers/drivers.h +++ b/glcddrivers/drivers.h @@ -40,6 +40,7 @@ enum eDriver kDriverNetwork = 14, kDriverGU126X64D_K610A4 = 15, kDriverDM140GINK = 16, + kDriverFutabaMDM166A = 17, kDriverSerDisp = 100, kDriverG15daemon = 200 }; diff --git a/glcddrivers/futabaMDM166A.c b/glcddrivers/futabaMDM166A.c new file mode 100644 index 0000000..2fc8d67 --- /dev/null +++ b/glcddrivers/futabaMDM166A.c @@ -0,0 +1,465 @@ +/* + * GraphLCD driver library + * + * (C) 2010 Andreas Brachold <vdr07 AT deltab de> + + * This file is released under the GNU General Public License. + * + * See the files README and COPYING for details. + * + */ + +#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 "futabaMDM166A.h" + +static const byte STATE_OFF = 0x00; //Symbol off +static const byte STATE_ON = 0x01; //Symbol on +static const byte STATE_ONHIGH = 0x02; //Symbol on, high intensity, can only be used with the volume symbols + +static const byte CMD_PREFIX = 0x1b; +static const byte CMD_SETCLOCK = 0x00; //Actualize the time of the display +static const byte CMD_SMALLCLOCK = 0x01; //Display small clock on display +static const byte CMD_BIGCLOCK = 0x02; //Display big clock on display +static const byte CMD_SETSYMBOL = 0x30; //Enable or disable symbol +static const byte CMD_SETDIMM = 0x40; //Set the dimming level of the display +static const byte CMD_RESET = 0x50; //Reset all configuration data to default and clear +static const byte CMD_SETRAM = 0x60; //Set the actual graphics RAM offset for next data write +static const byte CMD_SETPIXEL = 0x70; //Write pixel data to RAM of the display +static const byte CMD_TEST1 = 0xf0; //Show vertical test pattern +static const byte CMD_TEST2 = 0xf1; //Show horizontal test pattern + +static const byte TIME_12 = 0x00; //12 hours format +static const byte TIME_24 = 0x01; //24 hours format + +static const byte BRIGHT_OFF = 0x00; //Display off +static const byte BRIGHT_DIMM = 0x01; //Display dimmed +static const byte BRIGHT_FULL = 0x02; //Display full brightness + +namespace GLCD { + +cHIDQueue::cHIDQueue() { + hid = NULL; + bInit = false; +} + +cHIDQueue::~cHIDQueue() { + cHIDQueue::close(); +} + +bool cHIDQueue::open() +{ + HIDInterfaceMatcher matcher = { 0x19c2, 0x6a11, NULL, NULL, 0 }; + hid_return ret; + + /* see include/debug.h for possible values */ + hid_set_debug(HID_DEBUG_NONE); + hid_set_debug_stream(0); + /* passed directly to libusb */ + hid_set_usb_debug(0); + + ret = hid_init(); + if (ret != HID_RET_SUCCESS) { + syslog(LOG_ERR, "libhid: init - %s (%d)", hiderror(ret), ret); + return false; + } + bInit = true; + + hid = hid_new_HIDInterface(); + if (hid == 0) { + syslog(LOG_ERR, "libhid: hid_new_HIDInterface() failed, out of memory?\n"); + return false; + } + + ret = hid_force_open(hid, 0, &matcher, 3); + if (ret != HID_RET_SUCCESS) { + syslog(LOG_ERR, "libhid: open - %s (%d)", hiderror(ret), ret); + hid_close(hid); + hid_delete_HIDInterface(&hid); + hid = 0; + return false; + } + + while (!empty()) { + pop(); + } + //ret = hid_write_identification(stdout, hid); + //if (ret != HID_RET_SUCCESS) { + // syslog(LOG_INFO, "libhid: write_identification %s (%d)", hiderror(ret), ret); + // return false; + //} + return true; +} + +void cHIDQueue::close() { + hid_return ret; + if (hid != 0) { + ret = hid_close(hid); + if (ret != HID_RET_SUCCESS) { + syslog(LOG_ERR, "libhid: close - %s (%d)", hiderror(ret), ret); + } + + hid_delete_HIDInterface(&hid); + hid = 0; + } + if(bInit) { + ret = hid_cleanup(); + if (ret != HID_RET_SUCCESS) { + syslog(LOG_ERR, "libhid: cleanup - %s (%d)", hiderror(ret), ret); + } + bInit = false; + } +} + +void cHIDQueue::Cmd(const byte & cmd) { + this->push(CMD_PREFIX); + this->push(cmd); +} + +void cHIDQueue::Data(const byte & data) { + this->push(data); +} + +bool cHIDQueue::Flush() { + + if(empty()) + return true; + if(!isopen()) { + return false; + } + + int const PATH_OUT[1] = { 0xff7f0004 }; + char buf[64]; + hid_return ret; + + while (!empty()) { + buf[0] = (char) std::min((size_t)63,size()); + for(unsigned int i = 0;i < 63 && !empty();++i) { + buf[i+1] = (char) front(); //the first element in the queue + pop(); //remove the first element of the queue + } + ret = hid_set_output_report(hid, PATH_OUT, sizeof(PATH_OUT), buf, (buf[0] + 1)); + if (ret != HID_RET_SUCCESS) { + syslog(LOG_ERR, "libhid: set_output_report - %s (%d)", hiderror(ret), ret); + while (!empty()) { + pop(); + } + cHIDQueue::close(); + return false; + } + } + return true; +} + +const char *cHIDQueue::hiderror(hid_return ret) const +{ + switch(ret) { + case HID_RET_SUCCESS: + return "success"; + case HID_RET_INVALID_PARAMETER: + return "invalid parameter"; + case HID_RET_NOT_INITIALISED: + return "not initialized"; + case HID_RET_ALREADY_INITIALISED: + return "hid_init() already called"; + case HID_RET_FAIL_FIND_BUSSES: + return "failed to find any USB busses"; + case HID_RET_FAIL_FIND_DEVICES: + return "failed to find any USB devices"; + case HID_RET_FAIL_OPEN_DEVICE: + return "failed to open device"; + case HID_RET_DEVICE_NOT_FOUND: + return "device not found"; + case HID_RET_DEVICE_NOT_OPENED: + return "device not yet opened"; + case HID_RET_DEVICE_ALREADY_OPENED: + return "device already opened"; + case HID_RET_FAIL_CLOSE_DEVICE: + return "could not close device"; + case HID_RET_FAIL_CLAIM_IFACE: + return "failed to claim interface; is another driver using it?"; + case HID_RET_FAIL_DETACH_DRIVER: + return "failed to detach kernel driver"; + case HID_RET_NOT_HID_DEVICE: + return "not recognized as a HID device"; + case HID_RET_HID_DESC_SHORT: + return "HID interface descriptor too short"; + case HID_RET_REPORT_DESC_SHORT: + return "HID report descriptor too short"; + case HID_RET_REPORT_DESC_LONG: + return "HID report descriptor too long"; + case HID_RET_FAIL_ALLOC: + return "failed to allocate memory"; + case HID_RET_OUT_OF_SPACE: + return "no space left in buffer"; + case HID_RET_FAIL_SET_REPORT: + return "failed to set report"; + case HID_RET_FAIL_GET_REPORT: + return "failed to get report"; + case HID_RET_FAIL_INT_READ: + return "interrupt read failed"; + case HID_RET_NOT_FOUND: + return "not found"; +#ifdef HID_RET_TIMEOUT + case HID_RET_TIMEOUT: + return "timeout"; +#endif + } + return "unknown error"; +} + + +cDriverFutabaMDM166A::cDriverFutabaMDM166A(cDriverConfig * config) +: config(config) +, m_pDrawMem(0) +, m_pVFDMem(0) +{ + oldConfig = new cDriverConfig(*config); + m_nRefreshCounter = 0; + lastIconState = 0; +} + +cDriverFutabaMDM166A::~cDriverFutabaMDM166A() +{ + delete oldConfig; +} + +int cDriverFutabaMDM166A::Init() +{ + // default values + width = config->width; + if (width <= 0 || width > 96) + width = 96; + height = config->height; + if (height <= 0 || height > 16) + height = 16; + m_iSizeYb = ((height + 7) / 8); + + + /*for (unsigned int i = 0; i < config->options.size(); i++) + { + if (config->options[i].name == "") + { + } + }*/ + + *oldConfig = *config; + + // setup the memory array for the drawing array + m_pDrawMem = new unsigned char[width * m_iSizeYb]; + // setup the memory array for the display array + m_pVFDMem = new unsigned char[width * m_iSizeYb]; + if(!m_pDrawMem || !m_pVFDMem) { + syslog(LOG_ERR, "FutabaMDM166A: malloc frame buffer failed, out of memory?\n"); + return -1; + } + + // clear display + ClearVFDMem(); + Clear(); + + + if(!cHIDQueue::open()) { + return -1; + } + lastIconState = 0; + + cHIDQueue::Cmd(CMD_RESET); + // Set Display SetBrightness + SetBrightness(config->brightness ? config->brightness : 50); + + if(cHIDQueue::Flush()) { + syslog(LOG_INFO, "%s: initialized.\n", config->name.c_str()); + return 0; + } + return -1; +} + +int cDriverFutabaMDM166A::DeInit() +{ + cHIDQueue::close(); + + if (m_pVFDMem) + delete[] m_pVFDMem; + if (m_pDrawMem) + delete[] m_pDrawMem; + + return 0; +} + +int cDriverFutabaMDM166A::CheckSetup() +{ + if (config->width != oldConfig->width || + config->height != oldConfig->height) + { + DeInit(); + return Init(); + } + + if (config->brightness != oldConfig->brightness) + { + oldConfig->brightness = config->brightness; + SetBrightness(config->brightness); + } + + if (config->upsideDown != oldConfig->upsideDown || + config->invert != oldConfig->invert) + { + oldConfig->upsideDown = config->upsideDown; + oldConfig->invert = config->invert; + return 1; + } + return 0; +} + +void cDriverFutabaMDM166A::ClearVFDMem() +{ + for (unsigned int n = 0; m_pVFDMem && n < (width * m_iSizeYb); n++) + m_pVFDMem[n] = 0x00; +} + +void cDriverFutabaMDM166A::Clear() +{ + for (unsigned int n = 0; m_pDrawMem && n < (width * m_iSizeYb); n++) + m_pDrawMem[n] = 0x00; +} + +void cDriverFutabaMDM166A::SetPixel(int x, int y) +{ + byte c; + int n; + + if (!m_pDrawMem) + 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) * width); + c = 0x80 >> (y % 8); + + m_pDrawMem[n] |= c; +} + +void cDriverFutabaMDM166A::Set8Pixels(int x, int y, byte data) +{ + int n; + + // x - pos is'nt mayby align to 8 + x &= 0xFFF8; + + for (n = 0; n < 8; ++n) + { + if (data & (0x80 >> n)) // if bit is set + SetPixel(x + n, y); + } +} + +void cDriverFutabaMDM166A::Refresh(bool refreshAll) +{ + unsigned int n, x, yb; + + if (!m_pVFDMem || !m_pDrawMem) + return; + + bool doRefresh = false; + unsigned int nWidth = width; + unsigned int minX = nWidth; + unsigned int maxX = 0; + + int s = CheckSetup(); + if(s < 0) + return; + if (s > 0) + refreshAll = true; + + for (yb = 0; yb < m_iSizeYb; ++yb) + for (x = 0; x < nWidth; ++x) + { + n = x + (yb * nWidth); + if (m_pVFDMem[n] != m_pDrawMem[n]) + { + m_pVFDMem[n] = m_pDrawMem[n]; + minX = std::min(minX, x); + maxX = std::max(maxX, x + 1); + doRefresh = true; + } + } + + m_nRefreshCounter = (m_nRefreshCounter + 1) % (config->refreshDisplay ? config->refreshDisplay : 50); + + if (!refreshAll && !m_nRefreshCounter) + refreshAll = true; + + if (refreshAll || doRefresh) + { + if (refreshAll) { + minX = 0; + maxX = nWidth; + // and reset RefreshCounter + m_nRefreshCounter = 0; + } + + maxX = std::min(maxX, nWidth); + + unsigned int nData = (maxX-minX) * m_iSizeYb; + if(nData) { + // send data to display, controller + cHIDQueue::Cmd(CMD_SETRAM); + cHIDQueue::Data(minX*m_iSizeYb); + cHIDQueue::Cmd(CMD_SETPIXEL); + cHIDQueue::Data(nData); + + for (x = minX; x < maxX; ++x) + for (yb = 0; yb < m_iSizeYb; ++yb) + { + n = x + (yb * nWidth); + cHIDQueue::Data((m_pVFDMem[n]) ^ (config->invert ? 0xff : 0x00)); + } + } + } + cHIDQueue::Flush(); +} + +/** + * Sets the brightness of the display. + * + * \param nBrightness The value the brightness (less 33% = off + * more then 66% = highest brightness,else half brightness ). + */ +void cDriverFutabaMDM166A::SetBrightness(unsigned int percent) +{ + byte nBrightness = 1; + if (percent < 33) { + nBrightness = 0; + } else if (nBrightness > 66) { + nBrightness = 2; + } + cHIDQueue::Cmd(CMD_SETDIMM); + cHIDQueue::Data(nBrightness); +} + +} + + + + diff --git a/glcddrivers/futabaMDM166A.h b/glcddrivers/futabaMDM166A.h new file mode 100644 index 0000000..ca1783d --- /dev/null +++ b/glcddrivers/futabaMDM166A.h @@ -0,0 +1,75 @@ +/* + * GraphLCD driver library + * + * (C) 2010 Andreas Brachold <vdr07 AT deltab de> + * + * This file is released under the GNU General Public License. + * + * See the files README and COPYING for details. + * + */ + +#ifndef _GLCDDRIVERS_FutabaMDM166A_H_ +#define _GLCDDRIVERS_FutabaMDM166A_H_ + +#include "driver.h" + +#define HAVE_STDBOOL_H +#include <hid.h> +#include <queue> + +namespace GLCD +{ + class cDriverConfig; + + class cHIDQueue : public std::queue<byte> { + HIDInterface* hid; + bool bInit; + public: + cHIDQueue(); + virtual ~cHIDQueue(); + virtual bool open(); + virtual void close(); + virtual bool isopen() const { return hid != 0; } + void Cmd(const byte & cmd); + void Data(const byte & data); + bool Flush(); + private: + const char *hiderror(hid_return ret) const; + }; + + class cDriverFutabaMDM166A : public cDriver, cHIDQueue + { + cDriverConfig * config; + cDriverConfig * oldConfig; + unsigned char *m_pDrawMem; // the draw "memory" + unsigned char *m_pVFDMem; // the double buffed display "memory" + unsigned int m_iSizeYb; + unsigned int m_nRefreshCounter; + unsigned int lastIconState; + int CheckSetup(); + protected: + void ClearVFDMem(); + void SetPixel(int x, int y); + void icons(unsigned int state); + bool SendCmdClock(); + bool SendCmdShutdown(); + + public: + cDriverFutabaMDM166A(cDriverConfig * config); + virtual ~cDriverFutabaMDM166A(); + + virtual int Init(); + virtual int DeInit(); + + virtual void Clear(); + virtual void Set8Pixels(int x, int y, byte data); + virtual void Refresh(bool refreshAll = false); + + virtual void SetBrightness(unsigned int percent); + }; +}; +#endif + + + diff --git a/graphlcd.conf b/graphlcd.conf index 2b0e784..2aa61a2 100644 --- a/graphlcd.conf +++ b/graphlcd.conf @@ -560,3 +560,18 @@ Driver=dm140gink # USB ID activy 5xx: #Vendor=0x1509 #Product=0x925d + +######################################################################## +[futabaMDM166A] +# futabaMDM166A driver +# This is an driver module for Futaba MDM166A VFD displays. +# The VFD is built-in in Targa HTPC cases and connected to USB port. +# Default size: 96 x 16 +Driver=futabaMDM166A + +#Width=96 +#Height=16 +#UpsideDown=no +#Invert=no +#Brightness=50 +#RefreshDisplay=1000 |