diff --git a/server/drivers/hd44780-ftdi.c b/server/drivers/hd44780-ftdi.c index 65534d3..48a0787 100644 --- a/server/drivers/hd44780-ftdi.c +++ b/server/drivers/hd44780-ftdi.c @@ -7,12 +7,27 @@ * connected to a FT2232C/D chip in 8 bit mode. * * Copyright (c) 2007, Intra2net AG + * + * Modified February 2008 by Ismail Ibrahim to + * add support for single channel FTDI chip with 4 bit wiring mode. * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. * */ +/* info for 4bit mote (ftdi_mode == 4): + wiring example: + FTDI chip: D0 D1 D2 D3 D4 D5 D6 D7 + | | | | | | | | + HD44780: D4 D5 D6 D7 EN RS RW n/c + + in LCDd.conf we then need to define + ftdi_line_RS=0x40 + ftdi_line_RW=0x20 + ftdi_line_EN=0x10 +*/ + #include "hd44780-ftdi.h" #include "report.h" @@ -62,42 +77,69 @@ hd_init_ftdi(Driver *drvthis) product_id = drvthis->config_get_int(drvthis->name, "ProductID", 0, 0x6001); // these config settings are not documented intentionally + p->ftdi_mode = drvthis->config_get_int(drvthis->name, "ftdi_mode", 0, 8); p->ftdi_line_RS = drvthis->config_get_int(drvthis->name, "ftdi_line_RS", 0, 0x01); p->ftdi_line_RW = drvthis->config_get_int(drvthis->name, "ftdi_line_RW", 0, 0x02); p->ftdi_line_EN = drvthis->config_get_int(drvthis->name, "ftdi_line_EN", 0, 0x04); p->ftdi_line_backlight = drvthis->config_get_int(drvthis->name, "ftdi_line_backlight", 0, 0x08); + //some foolproof check + if (p->ftdi_mode != 4 && p->ftdi_mode != 8) { + report(RPT_ERR, "invalid ftdi_mode: %d", p->ftdi_mode); + return -1; + } + // Init 1. channel: data ftdi_init(&p->ftdic); ftdi_set_interface(&p->ftdic, INTERFACE_A); f = ftdi_usb_open(&p->ftdic, vendor_id, product_id); if (f < 0 && f != -5) { - report(RPT_ERR, "unable to open ftdi device: %d (%s)", f, ftdi_get_error_string(&p->ftdic)); - return -1; + report(RPT_ERR, "unable to open ftdi device: %d (%s)", f, ftdi_get_error_string(&p->ftdic)); + return -1; } debug(RPT_DEBUG, "ftdi open succeeded(channel 1): %d", f); debug(RPT_DEBUG, "enabling bitbang mode(channel 1)\n"); + + if (p->ftdi_mode == 4) { + //set fast baudrate for 4 bit wiring to eliminate garbage on lcd + f = ftdi_set_baudrate(&p->ftdic, 921600); + if (f < 0) { + report(RPT_ERR, "unable to open ftdi device: %d (%s)", f, ftdi_get_error_string(&p->ftdic)); + return -1; + } + } + ftdi_enable_bitbang(&p->ftdic, 0xFF); - // Init 2. channel: control - ftdi_init(&p->ftdic2); - ftdi_set_interface(&p->ftdic2, INTERFACE_B); - f = ftdi_usb_open(&p->ftdic2, vendor_id, product_id); - if (f < 0 && f != -5) { - report(RPT_ERR, "unable to open second ftdi device: %d (%s)", f, ftdi_get_error_string(&p->ftdic2)); - return -2; + if (p->ftdi_mode == 8) { + // Init 2. channel: control + ftdi_init(&p->ftdic2); + ftdi_set_interface(&p->ftdic2, INTERFACE_B); + f = ftdi_usb_open(&p->ftdic2, vendor_id, product_id); + if (f < 0 && f != -5) { + report(RPT_ERR, "unable to open second ftdi device: %d (%s)", f, ftdi_get_error_string(&p->ftdic2)); + return -2; + } + debug(RPT_DEBUG, "ftdi open succeeded(channel 2): %d", f); + + debug(RPT_DEBUG, "enabling bitbang mode (channel 2)"); + ftdi_enable_bitbang(&p->ftdic2, 0xFF); + + // FTDI bug: Sometimes first write gets lost on kernel 2.6, needs investigation. + ftdi_HD44780_senddata (p, 0, RS_INSTR, FUNCSET | IF_8BIT); + usleep (4100); + + common_init(p, IF_8BIT); } - debug(RPT_DEBUG, "ftdi open succeeded(channel 2): %d", f); + else if (p->ftdi_mode == 4) { + ftdi_HD44780_senddata (p, 0, RS_INSTR, FUNCSET | IF_4BIT ); + ftdi_HD44780_senddata (p, 0, RS_INSTR, FUNCSET | IF_4BIT ); + ftdi_HD44780_senddata (p, 0, RS_INSTR, FUNCSET | IF_4BIT ); - debug(RPT_DEBUG, "enabling bitbang mode (channel 2)"); - ftdi_enable_bitbang(&p->ftdic2, 0xFF); + common_init(p, IF_4BIT); + } - // FTDI bug: Sometimes first write gets lost on kernel 2.6, needs investigation. - ftdi_HD44780_senddata (p, 0, RS_INSTR, FUNCSET | IF_8BIT); - usleep (4100); - - common_init(p, IF_8BIT); return 0; } @@ -107,36 +149,62 @@ hd_init_ftdi(Driver *drvthis) void ftdi_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch) { - // Output data on first channel - int f = ftdi_write_data(&p->ftdic, &ch, 1); - if (f < 0) { - p->hd44780_functions->drv_report(RPT_ERR, "failed to write: %d (%s). Exiting", - f, ftdi_get_error_string(&p->ftdic)); - exit (-1); - } + if (p->ftdi_mode == 8) { + // Output data on first channel + int f = ftdi_write_data(&p->ftdic, &ch, 1); + if (f < 0) { + p->hd44780_functions->drv_report(RPT_ERR, "failed to write: %d (%s). Exiting", + f, ftdi_get_error_string(&p->ftdic)); + exit (-1); + } - // Setup RS and R/W and EN - ch = p->ftdi_line_EN | p->backlight_bit; - if (flags == RS_DATA) { - ch |= p->ftdi_line_RS; - } - f = ftdi_write_data(&p->ftdic2, &ch, 1); - if (f < 0) { - p->hd44780_functions->drv_report(RPT_ERR, "failed to write: %d (%s). Exiting", - f, ftdi_get_error_string(&p->ftdic2)); - exit(-1); - } + // Setup RS and R/W and EN + ch = p->ftdi_line_EN | p->backlight_bit; + if (flags == RS_DATA) { + ch |= p->ftdi_line_RS; + } + f = ftdi_write_data(&p->ftdic2, &ch, 1); + if (f < 0) { + p->hd44780_functions->drv_report(RPT_ERR, "failed to write: %d (%s). Exiting", + f, ftdi_get_error_string(&p->ftdic2)); + exit(-1); + } - // Disable E - ch = 0x00 | p->backlight_bit; - if (flags == RS_DATA) { - ch |= p->ftdi_line_RS; + // Disable E + ch = 0x00 | p->backlight_bit; + if (flags == RS_DATA) { + ch |= p->ftdi_line_RS; + } + f = ftdi_write_data(&p->ftdic2, &ch, 1); + if (f < 0) { + p->hd44780_functions->drv_report(RPT_ERR, "failed to write: %d (%s). Exiting", + f, ftdi_get_error_string(&p->ftdic2)); + exit(-1); + } } - f = ftdi_write_data(&p->ftdic2, &ch, 1); - if (f < 0) { - p->hd44780_functions->drv_report(RPT_ERR, "failed to write: %d (%s). Exiting", - f, ftdi_get_error_string(&p->ftdic2)); - exit(-1); + else if (p->ftdi_mode == 4) { + unsigned char buf[4]; + unsigned char portControl = 0; + + if (flags == RS_DATA) { + portControl = p->ftdi_line_RS; + } + + buf[0] = (ch>>4) & 0x0F | portControl | p->ftdi_line_EN; + buf[1] = (ch>>4) & 0x0F | portControl; + buf[2] = (ch & 0x0F) | portControl | p->ftdi_line_EN; + buf[3] = (ch & 0x0F) | portControl; + int f = ftdi_write_data(&p->ftdic, &buf, 4); + + if (f < 0) { + p->hd44780_functions->drv_report(RPT_ERR, "failed to write: %d (%s). Exiting", + f, ftdi_get_error_string(&p->ftdic)); + exit(-1); + } + + if (flags == RS_INSTR) { + usleep (4100); + } } } @@ -144,15 +212,17 @@ ftdi_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char fla void ftdi_HD44780_backlight(PrivateData *p, unsigned char state) { - int f; + if (p->ftdi_mode == 8) { + int f; - p->backlight_bit = state ? p->ftdi_line_backlight : 0; + p->backlight_bit = state ? p->ftdi_line_backlight : 0; - f = ftdi_write_data(&p->ftdic2, &state, 1); - if (f < 0) { - p->hd44780_functions->drv_report(RPT_ERR, "failed to write: %d (%s). Exiting", - f, ftdi_get_error_string(&p->ftdic2)); - exit(-1); + f = ftdi_write_data(&p->ftdic2, &state, 1); + if (f < 0) { + p->hd44780_functions->drv_report(RPT_ERR, "failed to write: %d (%s). Exiting", + f, ftdi_get_error_string(&p->ftdic2)); + exit(-1); + } } } @@ -164,9 +234,11 @@ ftdi_HD44780_close(PrivateData *p) ftdi_usb_close(&p->ftdic); ftdi_deinit(&p->ftdic); - ftdi_disable_bitbang(&p->ftdic2); - ftdi_usb_close(&p->ftdic2); - ftdi_deinit(&p->ftdic2); + if (p->ftdi_mode == 8) { + ftdi_disable_bitbang(&p->ftdic2); + ftdi_usb_close(&p->ftdic2); + ftdi_deinit(&p->ftdic2); + } } /* EOF */ diff --git a/server/drivers/hd44780-low.h b/server/drivers/hd44780-low.h index 3c7d75f..2c55186 100644 --- a/server/drivers/hd44780-low.h +++ b/server/drivers/hd44780-low.h @@ -111,6 +111,7 @@ typedef struct driver_private_data { // FTDI connection type struct ftdi_context ftdic, ftdic2; + int ftdi_mode; int ftdi_line_RS; int ftdi_line_RW; int ftdi_line_EN;