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 /glcddrivers | |
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
Diffstat (limited to 'glcddrivers')
-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 |
5 files changed, 557 insertions, 0 deletions
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 + + + |