|
1 /* |
|
2 * GraphLCD driver library |
|
3 * |
|
4 * serdisp.h - include support for displays supported by serdisplib (if library is installed) |
|
5 * http://serdisplib.sourceforge.net |
|
6 * |
|
7 * This file is released under the GNU General Public License. Refer |
|
8 * to the COPYING file distributed with this package. |
|
9 * |
|
10 * (c) 2003-2005 Wolfgang Astleitner <mrwastl AT users.sourceforge.net> |
|
11 */ |
|
12 |
|
13 #include <stdio.h> |
|
14 #include <stdlib.h> |
|
15 #include <syslog.h> |
|
16 #include <dlfcn.h> |
|
17 |
|
18 #include "common.h" |
|
19 #include "config.h" |
|
20 #include "serdisp.h" |
|
21 |
|
22 #define SERDISP_VERSION(a,b) ((long)(((a) << 8) + (b))) |
|
23 #define SERDISP_VERSION_GET_MAJOR(_c) ((int)( (_c) >> 8 )) |
|
24 #define SERDISP_VERSION_GET_MINOR(_c) ((int)( (_c) & 0xFF )) |
|
25 |
|
26 // taken from serdisp_control.h |
|
27 #define FEATURE_CONTRAST 0x01 |
|
28 #define FEATURE_REVERSE 0x02 |
|
29 #define FEATURE_BACKLIGHT 0x03 |
|
30 #define FEATURE_ROTATE 0x04 |
|
31 |
|
32 #define SD_COL_BLACK 0xFF000000 |
|
33 |
|
34 namespace GLCD |
|
35 { |
|
36 |
|
37 cDriverSerDisp::cDriverSerDisp(cDriverConfig * config) |
|
38 : config(config) |
|
39 { |
|
40 oldConfig = new cDriverConfig(*config); |
|
41 |
|
42 dd = (void *) NULL; |
|
43 } |
|
44 |
|
45 cDriverSerDisp::~cDriverSerDisp(void) |
|
46 { |
|
47 delete oldConfig; |
|
48 } |
|
49 |
|
50 int cDriverSerDisp::Init(void) |
|
51 { |
|
52 char* errmsg; // error message returned by dlerror() |
|
53 |
|
54 std::string controller; |
|
55 std::string optionstring = ""; |
|
56 std::string wiringstring; |
|
57 |
|
58 |
|
59 // dynamically load serdisplib using dlopen() & co. |
|
60 |
|
61 sdhnd = dlopen("libserdisp.so", RTLD_LAZY); |
|
62 if (!sdhnd) { // try /usr/local/lib |
|
63 sdhnd = dlopen("/usr/local/lib/libserdisp.so", RTLD_LAZY); |
|
64 } |
|
65 |
|
66 if (!sdhnd) { // serdisplib seems not to be installed |
|
67 syslog(LOG_ERR, "%s: error: unable to dynamically load library '%s'. Err: %s (cDriver::Init)\n", |
|
68 config->name.c_str(), "libserdisp.so", "not found"); |
|
69 return -1; |
|
70 } |
|
71 |
|
72 dlerror(); // clear error code |
|
73 |
|
74 /* pre-init some flags, function pointers, ... */ |
|
75 supports_options = 0; |
|
76 fg_colour = 1; |
|
77 bg_colour = -1; |
|
78 |
|
79 // get serdisp version |
|
80 fp_serdisp_getversioncode = (long int (*)()) dlsym(sdhnd, "serdisp_getversioncode"); |
|
81 |
|
82 if (dlerror()) { // no serdisp_getversioncode() -> version of serdisplib is < 1.95 |
|
83 syslog(LOG_DEBUG, "%s: INFO: symbol serdisp_getversioncode unknown: autodetecting pre 1.95 serdisplib version (cDriver::Init)\n", |
|
84 config->name.c_str()); |
|
85 |
|
86 fp_SDCONN_open = (void*(*)(const char*)) dlsym(sdhnd, "SDCONN_open"); |
|
87 if (dlerror()) { // no SDCONN_open() -> version of serdisplib is < 1.93 |
|
88 serdisp_version = SERDISP_VERSION(1,92); |
|
89 syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version <= 1.92 (cDriver::Init)\n", config->name.c_str()); |
|
90 |
|
91 fp_PP_open = (void*(*)(const char*))dlsym(sdhnd, "PP_open"); |
|
92 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
93 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
94 config->name.c_str(), "PP_open", errmsg); |
|
95 return -1; |
|
96 } |
|
97 fp_PP_close = (void*(*)(void*))dlsym(sdhnd, "PP_close"); |
|
98 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
99 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
100 config->name.c_str(), "PP_close", errmsg); |
|
101 return -1; |
|
102 } |
|
103 } else { |
|
104 serdisp_version = SERDISP_VERSION(1,94); // no serdisp_getversioncode, but SDCONN_open: 1.93 or 1.94 |
|
105 syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version 1.93 or 1.94 (cDriver::Init)\n", config->name.c_str()); |
|
106 |
|
107 fp_serdisp_quit = (void (*)(void*)) dlsym(sdhnd, "serdisp_quit"); |
|
108 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
109 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
110 config->name.c_str(), "serdisp_quit", errmsg); |
|
111 return -1; |
|
112 } |
|
113 } |
|
114 |
|
115 fp_serdisp_setpixcol = (void (*)(void*, int, int, long int)) dlsym(sdhnd, "serdisp_setpixel"); |
|
116 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
117 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
118 config->name.c_str(), "serdisp_setpixel", errmsg); |
|
119 return -1; |
|
120 } |
|
121 fg_colour = 1; /* set foreground to 'pixel on' */ |
|
122 |
|
123 } else { // serdisp version >= 1.95 |
|
124 serdisp_version = fp_serdisp_getversioncode(); |
|
125 syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version %d.%d (cDriver::Init)\n", |
|
126 config->name.c_str(), SERDISP_VERSION_GET_MAJOR(serdisp_version), SERDISP_VERSION_GET_MINOR(serdisp_version)); |
|
127 |
|
128 |
|
129 fp_SDCONN_open = (void*(*)(const char*)) dlsym(sdhnd, "SDCONN_open"); |
|
130 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
131 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
132 config->name.c_str(), "SDCONN_open", errmsg); |
|
133 return -1; |
|
134 } |
|
135 fp_serdisp_quit = (void (*)(void*)) dlsym(sdhnd, "serdisp_quit"); |
|
136 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
137 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
138 config->name.c_str(), "serdisp_quit", errmsg); |
|
139 return -1; |
|
140 } |
|
141 fp_serdisp_setpixcol = (void (*)(void*, int, int, long int)) dlsym(sdhnd, "serdisp_setcolour"); |
|
142 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
143 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
144 config->name.c_str(), "serdisp_setcolour", errmsg); |
|
145 return -1; |
|
146 } |
|
147 fg_colour = SD_COL_BLACK; /* set foreground colour to black */ |
|
148 |
|
149 if (serdisp_version >= SERDISP_VERSION(1,96) ) { |
|
150 supports_options = 1; |
|
151 |
|
152 fp_serdisp_isoption = (int (*)(void*, const char*)) dlsym(sdhnd, "serdisp_isoption"); |
|
153 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
154 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
155 config->name.c_str(), "serdisp_isoption", errmsg); |
|
156 return -1; |
|
157 } |
|
158 fp_serdisp_setoption = (void (*)(void*, const char*, long int)) dlsym(sdhnd, "serdisp_setoption"); |
|
159 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
160 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
161 config->name.c_str(), "serdisp_setoption", errmsg); |
|
162 return -1; |
|
163 } |
|
164 } /* >= 1.96 */ |
|
165 } |
|
166 |
|
167 // load other symbols that will be required |
|
168 fp_serdisp_init = (void*(*)(void*, const char*, const char*)) dlsym(sdhnd, "serdisp_init"); |
|
169 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
170 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
171 config->name.c_str(), "serdisp_init", errmsg); |
|
172 return -1; |
|
173 } |
|
174 |
|
175 fp_serdisp_rewrite = (void (*)(void*)) dlsym(sdhnd, "serdisp_rewrite"); |
|
176 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
177 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
178 config->name.c_str(), "serdisp_rewrite", errmsg); |
|
179 return -1; |
|
180 } |
|
181 |
|
182 fp_serdisp_update = (void (*)(void*)) dlsym(sdhnd, "serdisp_update"); |
|
183 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
184 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
185 config->name.c_str(), "serdisp_update", errmsg); |
|
186 return -1; |
|
187 } |
|
188 |
|
189 fp_serdisp_clearbuffer = (void (*)(void*)) dlsym(sdhnd, "serdisp_clearbuffer"); |
|
190 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
191 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
192 config->name.c_str(), "serdisp_clearbuffer", errmsg); |
|
193 return -1; |
|
194 } |
|
195 |
|
196 fp_serdisp_feature = (int (*)(void*, int, int)) dlsym(sdhnd, "serdisp_feature"); |
|
197 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
198 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
199 config->name.c_str(), "serdisp_feature", errmsg); |
|
200 return -1; |
|
201 } |
|
202 |
|
203 fp_serdisp_close = (void (*)(void*))dlsym(sdhnd, "serdisp_close"); |
|
204 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
205 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
206 config->name.c_str(), "serdisp_close", errmsg); |
|
207 return -1; |
|
208 } |
|
209 |
|
210 fp_serdisp_getwidth = (int (*)(void*)) dlsym(sdhnd, "serdisp_getwidth"); |
|
211 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
212 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
213 config->name.c_str(), "serdisp_getwidth", errmsg); |
|
214 return -1; |
|
215 } |
|
216 |
|
217 fp_serdisp_getheight = (int (*)(void*)) dlsym(sdhnd, "serdisp_getheight"); |
|
218 if ( (errmsg = dlerror()) != NULL ) { // should not happen |
|
219 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", |
|
220 config->name.c_str(), "serdisp_getheight", errmsg); |
|
221 return -1; |
|
222 } |
|
223 |
|
224 // done loading all required symbols |
|
225 |
|
226 |
|
227 // setting up the display |
|
228 width = 0; |
|
229 height = 0; |
|
230 |
|
231 for (unsigned int i = 0; i < config->options.size(); i++) |
|
232 { |
|
233 if (config->options[i].name == "Controller") { |
|
234 controller = config->options[i].value; |
|
235 } else if (config->options[i].name == "Options") { |
|
236 optionstring = config->options[i].value; |
|
237 } else if (config->options[i].name == "Wiring") { |
|
238 wiringstring = config->options[i].value; |
|
239 } else if (config->options[i].name == "FGColour") { |
|
240 fg_colour = strtoul(config->options[i].value.c_str(), (char **)NULL, 0); |
|
241 fg_colour |= 0xFF000000L; /* force alpha to 0xFF */ |
|
242 } else if (config->options[i].name == "BGColour") { |
|
243 bg_colour = strtoul(config->options[i].value.c_str(), (char **)NULL, 0); |
|
244 bg_colour |= 0xFF000000L; /* force alpha to 0xFF */ |
|
245 } |
|
246 } |
|
247 |
|
248 if (wiringstring.length()) { |
|
249 optionstring = "WIRING=" + wiringstring + ((optionstring != "") ? ";" + optionstring : ""); |
|
250 } |
|
251 |
|
252 if (controller == "") |
|
253 { |
|
254 syslog(LOG_ERR, "%s error: no controller given!\n", config->name.c_str()); |
|
255 return -1; |
|
256 } |
|
257 |
|
258 |
|
259 if (config->device == "") |
|
260 { |
|
261 // use DirectIO |
|
262 |
|
263 // neither device nor port is set |
|
264 if (config->port == 0) |
|
265 return -1; |
|
266 |
|
267 char temp[10]; |
|
268 snprintf(temp, 8, "0x%x", config->port); |
|
269 |
|
270 if (serdisp_version < SERDISP_VERSION(1,93) ) { |
|
271 sdcd = fp_PP_open(temp); |
|
272 } else { |
|
273 sdcd = fp_SDCONN_open(temp); |
|
274 } |
|
275 |
|
276 if (sdcd == 0) { |
|
277 syslog(LOG_ERR, "%s: error: unable to open port 0x%x for display %s. (cDriver::Init)\n", |
|
278 config->name.c_str(), config->port, controller.c_str()); |
|
279 return -1; |
|
280 } |
|
281 |
|
282 uSleep(10); |
|
283 } |
|
284 else |
|
285 { |
|
286 // use ppdev |
|
287 if (serdisp_version < SERDISP_VERSION(1,93) ) { |
|
288 sdcd = fp_PP_open(config->device.c_str()); |
|
289 } else { |
|
290 sdcd = fp_SDCONN_open(config->device.c_str()); |
|
291 } |
|
292 |
|
293 if (sdcd == 0) { |
|
294 syslog(LOG_ERR, "%s: error: unable to open device %s for display %s. (cDriver::Init)\n", |
|
295 config->name.c_str(), config->device.c_str(), controller.c_str()); |
|
296 return -1; |
|
297 } |
|
298 } |
|
299 |
|
300 if (serdisp_version < SERDISP_VERSION(1,95) ) |
|
301 dd = fp_serdisp_init(sdcd, controller.c_str(), ""); |
|
302 else |
|
303 dd = fp_serdisp_init(sdcd, controller.c_str(), optionstring.c_str()); |
|
304 |
|
305 if (!dd) |
|
306 { |
|
307 syslog(LOG_ERR, "%s: error: cannot open display %s. Err:%s (cDriver::Init)\n", |
|
308 config->name.c_str(), controller.c_str(), "no handle"); |
|
309 return -1; |
|
310 } |
|
311 |
|
312 width = config->width; |
|
313 if (width <= 0) |
|
314 width = fp_serdisp_getwidth(dd); |
|
315 height = config->height; |
|
316 if (height <= 0) |
|
317 height = fp_serdisp_getheight(dd); |
|
318 |
|
319 if (serdisp_version < SERDISP_VERSION(1,96) ) { |
|
320 fp_serdisp_feature(dd, FEATURE_ROTATE, config->upsideDown); |
|
321 fp_serdisp_feature(dd, FEATURE_CONTRAST, config->contrast); |
|
322 fp_serdisp_feature(dd, FEATURE_BACKLIGHT, config->backlight); |
|
323 fp_serdisp_feature(dd, FEATURE_REVERSE, config->invert); |
|
324 } else { |
|
325 /* standard options */ |
|
326 fp_serdisp_setoption(dd, "ROTATE", config->upsideDown); |
|
327 fp_serdisp_setoption(dd, "CONTRAST", config->contrast); |
|
328 fp_serdisp_setoption(dd, "BACKLIGHT", config->backlight); |
|
329 fp_serdisp_setoption(dd, "INVERT", config->invert); |
|
330 |
|
331 /* driver dependend options */ |
|
332 for (unsigned int i = 0; i < config->options.size(); i++) { |
|
333 std::string optionname = config->options[i].name; |
|
334 if (optionname != "UpsideDown" && optionname != "Contrast" && |
|
335 optionname != "Backlight" && optionname != "Invert") { |
|
336 |
|
337 if ( fp_serdisp_isoption(dd, optionname.c_str()) == 1 ) /* if == 1: option is existing AND r/w */ |
|
338 fp_serdisp_setoption(dd, optionname.c_str(), strtol(config->options[i].value.c_str(), NULL, 0)); |
|
339 } |
|
340 } |
|
341 |
|
342 } |
|
343 |
|
344 *oldConfig = *config; |
|
345 |
|
346 // clear display |
|
347 Clear(); |
|
348 |
|
349 syslog(LOG_INFO, "%s: SerDisp with %s initialized.\n", config->name.c_str(), controller.c_str()); |
|
350 return 0; |
|
351 } |
|
352 |
|
353 int cDriverSerDisp::DeInit(void) |
|
354 { |
|
355 if (serdisp_version < SERDISP_VERSION(1,93) ) { |
|
356 fp_serdisp_close(dd); |
|
357 fp_PP_close(sdcd); |
|
358 sdcd = NULL; |
|
359 } else { |
|
360 //fp_serdisp_quit(dd); |
|
361 /* use serdisp_close instead of serdisp_quit so that showpic and showtext are usable together with serdisplib */ |
|
362 fp_serdisp_close(dd); |
|
363 } |
|
364 (int) dlclose(sdhnd); |
|
365 sdhnd = NULL; |
|
366 |
|
367 return 0; |
|
368 } |
|
369 |
|
370 int cDriverSerDisp::CheckSetup() |
|
371 { |
|
372 bool update = false; |
|
373 |
|
374 if (config->device != oldConfig->device || |
|
375 config->port != oldConfig->port || |
|
376 config->width != oldConfig->width || |
|
377 config->height != oldConfig->height) |
|
378 { |
|
379 DeInit(); |
|
380 Init(); |
|
381 return 0; |
|
382 } |
|
383 |
|
384 if (config->contrast != oldConfig->contrast) |
|
385 { |
|
386 fp_serdisp_feature(dd, FEATURE_CONTRAST, config->contrast); |
|
387 oldConfig->contrast = config->contrast; |
|
388 update = true; |
|
389 } |
|
390 if (config->backlight != oldConfig->backlight) |
|
391 { |
|
392 fp_serdisp_feature(dd, FEATURE_BACKLIGHT, config->backlight); |
|
393 oldConfig->backlight = config->backlight; |
|
394 update = true; |
|
395 } |
|
396 if (config->upsideDown != oldConfig->upsideDown) |
|
397 { |
|
398 fp_serdisp_feature(dd, FEATURE_ROTATE, config->upsideDown); |
|
399 oldConfig->upsideDown = config->upsideDown; |
|
400 update = true; |
|
401 } |
|
402 if (config->invert != oldConfig->invert) |
|
403 { |
|
404 fp_serdisp_feature(dd, FEATURE_REVERSE, config->invert); |
|
405 oldConfig->invert = config->invert; |
|
406 update = true; |
|
407 } |
|
408 |
|
409 /* driver dependend options */ |
|
410 for (unsigned int i = 0; i < config->options.size(); i++) { |
|
411 std::string optionname = config->options[i].name; |
|
412 if (optionname != "UpsideDown" && optionname != "Contrast" && |
|
413 optionname != "Backlight" && optionname != "Invert") { |
|
414 |
|
415 if ( fp_serdisp_isoption(dd, optionname.c_str()) == 1 ) /* if == 1: option is existing AND r/w */ |
|
416 fp_serdisp_setoption(dd, optionname.c_str(), strtol(config->options[i].value.c_str(), NULL, 0)); |
|
417 oldConfig->options[i] = config->options[i]; |
|
418 update = true; |
|
419 } |
|
420 } |
|
421 |
|
422 |
|
423 if (update) |
|
424 return 1; |
|
425 return 0; |
|
426 } |
|
427 |
|
428 void cDriverSerDisp::Clear(void) |
|
429 { |
|
430 if (bg_colour == -1) |
|
431 fp_serdisp_clearbuffer(dd); |
|
432 else { /* if bg_colour is set, draw background 'by hand' */ |
|
433 int x,y; |
|
434 for (y = 0; y < fp_serdisp_getheight(dd); y++) |
|
435 for (x = 0; x < fp_serdisp_getwidth(dd); x++) |
|
436 fp_serdisp_setpixcol(dd, x, y, bg_colour); /* >= 1.95: serdisp_setcolour(), < 1.95: serdisp_setpixel() */ |
|
437 } |
|
438 } |
|
439 |
|
440 void cDriverSerDisp::Set8Pixels(int x, int y, unsigned char data) { |
|
441 int i, start, pixel; |
|
442 |
|
443 data = ReverseBits(data); |
|
444 |
|
445 start = (x >> 3) << 3; |
|
446 |
|
447 for (i = 0; i < 8; i++) { |
|
448 pixel = data & (1 << i); |
|
449 if (pixel) |
|
450 fp_serdisp_setpixcol(dd, start + i, y, fg_colour); /* >= 1.95: serdisp_setcolour(), < 1.95: serdisp_setpixel() */ |
|
451 else if (!pixel && bg_colour != -1) /* if bg_colour is set: use it if pixel is not set */ |
|
452 fp_serdisp_setpixcol(dd, start + i, y, bg_colour); /* >= 1.95: serdisp_setcolour(), < 1.95: serdisp_setpixel() */ |
|
453 } |
|
454 } |
|
455 |
|
456 void cDriverSerDisp::Refresh(bool refreshAll) |
|
457 { |
|
458 if (CheckSetup() == 1) |
|
459 refreshAll = true; |
|
460 |
|
461 if (refreshAll) |
|
462 fp_serdisp_rewrite(dd); |
|
463 else |
|
464 fp_serdisp_update(dd); |
|
465 } |
|
466 |
|
467 } // end of namespace |