Base: LCDproc 0.5.2
[lcdproc-de200c.git] / server / drivers / hd44780-serial.c
blobd2ad0a59a241c9a8f8434c488229d292ebbaf1a9
1 /*
2 * Driver for serial connected hd44780 LCDs
3 * Copyright (C) 2006-2007 Matteo Pillon <matteo.pillon@gmail.com>
5 * Some parts are based on the original pic-an-lcd driver code
6 * Copyright (C) 1997, Matthias Prinke <m.prinke@trashcan.mcnet.de>
7 * 1998, Richard Rognlie <rrognlie@gamerz.net>
8 * 1999, Ethan Dicks
9 * 1999-2000, Benjamin Tse <blt@Comports.com>
10 * 2001, Rene Wagner
11 * 2001-2002, Joris Robijn <joris@robijn.net>
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
29 #include "hd44780-serial.h"
30 #include "hd44780-low.h"
32 #include "report.h"
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <string.h>
38 #include <stdio.h>
39 #include <sys/types.h>
40 #include <fcntl.h>
41 #include <termios.h>
43 #include <errno.h>
45 #ifdef HAVE_CONFIG_H
46 # include "config.h"
47 #endif
49 #define SERIAL_IF serial_interfaces[p->serial_type]
51 /* bitrate conversion */
52 unsigned int bitrate_conversion[][2] = {
53 { 50, B50 },
54 { 75, B75 },
55 { 110, B110 },
56 { 134, B134 },
57 { 150, B150 },
58 { 200, B200 },
59 { 300, B300 },
60 { 600, B600 },
61 { 1200, B1200 },
62 { 1800, B1800 },
63 { 2400, B2400 },
64 { 4800, B4800 },
65 { 9600, B9600 },
66 { 19200, B19200 },
67 { 38400, B38400 },
68 { 57600, B57600 },
69 { 115200, B115200 },
70 { 230400, B230400 }
71 #if defined(B460800)
72 , { 460800, B460800 }
73 #endif
74 #if defined(B500000)
75 , { 500000, B500000 }
76 #endif
77 #if defined(B576000)
78 , { 576000, B576000 }
79 #endif
80 #if defined(B921600)
81 , { 921600, B921600 }
82 #endif
83 #if defined(B1000000)
84 , { 1000000, B1000000 }
85 #endif
86 #if defined(B1152000)
87 , { 1152000, B1152000 }
88 #endif
89 #if defined(B1500000)
90 , { 1500000, B1500000 }
91 #endif
92 #if defined(B2000000)
93 , { 2000000, B2000000 }
94 #endif
95 #if defined(B2500000)
96 , { 2500000, B2500000 }
97 #endif
98 #if defined(B3000000)
99 , { 3000000, B3000000 }
100 #endif
101 #if defined(B3500000)
102 , { 3500000, B3500000 }
103 #endif
104 #if defined(B4000000)
105 , { 4000000, B4000000 }
106 #endif
109 int convert_bitrate(unsigned int conf_bitrate, size_t *bitrate) {
110 int counter;
111 for (counter = 0; counter < sizeof(bitrate_conversion)/(2*sizeof(unsigned int)); counter++)
112 if (bitrate_conversion[counter][0] == conf_bitrate) {
113 *bitrate = (size_t) bitrate_conversion[counter][1];
114 return 0;
116 return 1;
119 static int lastdisplayID;
121 void serial_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch);
122 void serial_HD44780_backlight(PrivateData *p, unsigned char state);
123 unsigned char serial_HD44780_scankeypad(PrivateData *p);
124 void serial_HD44780_close(PrivateData *p);
126 // initialize the driver
128 hd_init_serial(Driver *drvthis)
130 PrivateData *p = (PrivateData*) drvthis->private_data;
132 struct termios portset;
133 char device[256] = DEFAULT_DEVICE;
135 /* READ CONFIG FILE */
137 /* Get interface type */
138 int counter;
139 char conf_serialif[SERIALIF_NAME_LENGTH];
141 strncpy(conf_serialif, drvthis->config_get_string(drvthis->name, "connectiontype", 0, ""), SERIALIF_NAME_LENGTH);
142 conf_serialif[SERIALIF_NAME_LENGTH-1] = '\0';
143 p->serial_type = 0;
144 for (counter = 0; counter < (sizeof(serial_interfaces)/sizeof(SerialInterface)); counter++) {
145 if (strcasecmp(conf_serialif, serial_interfaces[counter].name) == 0) {
146 p->serial_type = counter;
147 break;
150 if (p->serial_type != counter) {
151 report(RPT_ERR, "HD44780: serial: serial interface %s unknown", conf_serialif);
152 report(RPT_ERR, "HD44780: serial: available interfaces:");
153 for (counter = 0; counter < (sizeof(serial_interfaces)/sizeof(SerialInterface)); counter++)
154 report(RPT_ERR, " %s", serial_interfaces[counter].name);
155 return -1;
158 report(RPT_INFO,"HD44780: serial: device type: %s", SERIAL_IF.name);
160 /* Check if user knows the capabilities of his hardware ;-) */
161 if (p->have_keypad && !(SERIAL_IF.keypad)) {
162 report(RPT_ERR, "HD44780: serial: keypad is not supported by %s", SERIAL_IF.name);
163 report(RPT_ERR, "HD44780: serial: check your configuration file and disable it");
164 return -1;
166 if (p->have_backlight && !(SERIAL_IF.backlight)) {
167 report(RPT_ERR, "HD44780: serial: backlight control is not supported by %s", SERIAL_IF.name);
168 report(RPT_ERR, "HD44780: serial: check your configuration file and disable it");
169 return -1;
172 /* Get bitrate */
173 unsigned int conf_bitrate;
174 size_t bitrate;
176 conf_bitrate = drvthis->config_get_int(drvthis->name, "Speed", 0, SERIAL_IF.default_bitrate);
177 if (conf_bitrate==0)
178 conf_bitrate = SERIAL_IF.default_bitrate;
179 if (convert_bitrate(conf_bitrate, &bitrate)) {
180 report(RPT_ERR, "HD44780: serial: invalid configured bitrate speed");
181 return -1;
183 report(RPT_INFO,"HD44780: serial: using speed: %d", conf_bitrate);
185 /* Get serial device to use */
186 strncpy(device, drvthis->config_get_string(drvthis->name, "device", 0, DEFAULT_DEVICE), sizeof(device));
187 device[sizeof(device)-1] = '\0';
188 report(RPT_INFO,"HD44780: serial: using device: %s", device);
190 /* Set up io port correctly, and open it... */
191 p->fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
192 if (p->fd == -1) {
193 report(RPT_ERR, "HD44780: serial: could not open device %s (%s)", device, strerror(errno));
194 return -1;
197 /* Get serial device parameters */
198 tcgetattr(p->fd, &portset);
200 /* We use RAW mode */
201 #ifdef HAVE_CFMAKERAW
202 /* The easy way */
203 cfmakeraw(&portset);
204 portset.c_cflag |= CLOCAL;
205 #else
206 /* The hard way */
207 portset.c_iflag &= ~( IGNBRK | BRKINT | PARMRK | ISTRIP
208 | INLCR | IGNCR | ICRNL | IXON );
209 portset.c_oflag &= ~OPOST;
210 portset.c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN );
211 portset.c_cflag &= ~( CSIZE | PARENB | CRTSCTS );
212 portset.c_cflag |= CS8 | CREAD | CLOCAL ;
213 #endif
214 /* Set port speed */
215 cfsetospeed(&portset, bitrate);
216 cfsetispeed(&portset, B0);
218 /* Set TCSANOW mode of serial device */
219 tcsetattr(p->fd, TCSANOW, &portset);
221 lastdisplayID = -1;
223 /* Assign functions */
224 p->hd44780_functions->senddata = serial_HD44780_senddata;
225 p->hd44780_functions->backlight = serial_HD44780_backlight;
226 if (p->have_keypad)
227 p->hd44780_functions->scankeypad = serial_HD44780_scankeypad;
228 p->hd44780_functions->close = serial_HD44780_close;
230 /* Do initialization */
231 if (SERIAL_IF.if_bits == 8) {
232 report(RPT_INFO,"HD44780: serial: initializing with 8 bits interface");
233 common_init(p, IF_8BIT);
234 } else {
235 report(RPT_INFO,"HD44780: serial: initializing with 4 bits interface");
236 common_init(p, IF_4BIT);
239 return 0;
242 // serial_HD44780_senddata
243 void
244 serial_HD44780_senddata(PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch)
246 /* Filter illegally sent escape characters (for interfaces without data escape) */
247 if (flags == RS_DATA && SERIAL_IF.data_escape == 0 && ch == SERIAL_IF.instruction_escape)
248 ch='?';
250 if (flags == RS_DATA) {
251 /* Do we need a DATA indicator byte? */
252 if ((SERIAL_IF.data_escape != '\0') &&
253 (ch >= SERIAL_IF.data_escape_min) &&
254 (ch < SERIAL_IF.data_escape_max) ||
255 (SERIAL_IF.multiple_displays && displayID != lastdisplayID)) {
256 write(p->fd, &SERIAL_IF.data_escape + displayID, 1);
258 write(p->fd, &ch, 1);
260 else {
261 write(p->fd, &SERIAL_IF.instruction_escape, 1);
262 write(p->fd, &ch, 1);
264 lastdisplayID = displayID;
267 void
268 serial_HD44780_backlight(PrivateData *p, unsigned char state)
270 unsigned char send[1];
271 if (p->have_backlight) {
272 if (SERIAL_IF.backlight_escape) {
273 send[0] = SERIAL_IF.backlight_escape;
274 write(p->fd, &send, 1);
276 if (SERIAL_IF.backlight_on && SERIAL_IF.backlight_off) {
277 send[0] = state ? SERIAL_IF.backlight_on : SERIAL_IF.backlight_off;
279 else {
280 send[0] = state ? 0 : 0xFF;
282 write(p->fd, &send, 1);
286 unsigned char
287 serial_HD44780_scankeypad(PrivateData *p)
289 unsigned char buffer = 0;
290 char hangcheck = 100;
292 read(p->fd, &buffer, 1);
293 if (buffer == SERIAL_IF.keypad_escape) {
294 while (hangcheck > 0) {
295 /* Check if I can read another byte */
296 if (read(p->fd, &buffer, 1) == 1) {
297 return buffer;
299 hangcheck--;
302 return 0;
305 void
306 serial_HD44780_close(PrivateData *p)
308 if (SERIAL_IF.end_code)
309 write(p->fd, &SERIAL_IF.end_code, 1);
310 close(p->fd);