root/branches/0.10.1/drv_MatrixOrbital.c

Revision 773, 12.9 kB (checked in by michael, 23 months ago)

backport 768:771 from trunk, version changed to 0.10.1-RC2

  • Property svn:keywords set to Id URL Rev
Line 
1/* $Id$
2 * $URL$
3 *
4 * new style driver for Matrix Orbital serial display modules
5 *
6 * Copyright (C) 1999, 2000 Michael Reinelt <reinelt@eunet.at>
7 * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
8 *
9 * This file is part of LCD4Linux.
10 *
11 * LCD4Linux is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
15 *
16 * LCD4Linux is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28 *
29 * exported fuctions:
30 *
31 * struct DRIVER drv_MatrixOrbital
32 *
33 */
34
35#include "config.h"
36
37#include <stdlib.h>
38#include <stdio.h>
39#include <string.h>
40#include <unistd.h>
41#include <time.h>
42
43#include "debug.h"
44#include "cfg.h"
45#include "plugin.h"
46#include "widget.h"
47#include "widget_text.h"
48#include "widget_icon.h"
49#include "widget_bar.h"
50#include "drv.h"
51#include "drv_generic_text.h"
52#include "drv_generic_gpio.h"
53#include "drv_generic_serial.h"
54
55
56static char Name[] = "MatrixOrbital";
57
58static int Model;
59static int Protocol;
60
61typedef struct {
62    int type;
63    char *name;
64    int rows;
65    int cols;
66    int gpis;
67    int gpos;
68    int protocol;
69} MODEL;
70
71/* Fixme #1: number of gpo's should be verified */
72/* Fixme #2: protocol should be verified */
73
74static MODEL Models[] = {
75    {0x01, "LCD0821", 2, 8, 0, 1, 1},
76    {0x03, "LCD2021", 2, 20, 0, 1, 1},
77    {0x04, "LCD1641", 4, 16, 0, 1, 1},
78    {0x05, "LCD2041", 4, 20, 0, 1, 1},
79    {0x06, "LCD4021", 2, 40, 0, 1, 1},
80    {0x07, "LCD4041", 4, 40, 0, 1, 1},
81    {0x08, "LK202-25", 2, 20, 8, 8, 2},
82    {0x09, "LK204-25", 4, 20, 8, 8, 2},
83    {0x0a, "LK404-55", 4, 40, 8, 8, 2},
84    {0x0b, "VFD2021", 2, 20, 0, 1, 1},
85    {0x0c, "VFD2041", 4, 20, 0, 1, 1},
86    {0x0d, "VFD4021", 2, 40, 0, 1, 1},
87    {0x0e, "VK202-25", 2, 20, 0, 1, 1},
88    {0x0f, "VK204-25", 4, 20, 0, 1, 1},
89    {0x10, "GLC12232", -1, -1, 0, 1, 1},
90    {0x13, "GLC24064", -1, -1, 0, 1, 1},
91    {0x15, "GLK24064-25", -1, -1, 0, 1, 1},
92    {0x22, "GLK12232-25", -1, -1, 0, 1, 1},
93    {0x31, "LK404-AT", 4, 40, 8, 8, 2},
94    {0x32, "VFD1621", 2, 16, 0, 1, 1},
95    {0x33, "LK402-12", 2, 40, 8, 8, 2},
96    {0x34, "LK162-12", 2, 16, 8, 8, 2},
97    {0x35, "LK204-25PC", 4, 20, 8, 8, 2},
98    {0x36, "LK202-24-USB", 2, 20, 8, 8, 2},
99    {0x38, "LK204-24-USB", 4, 20, 8, 8, 2},
100    {0x39, "VK204-24-USB", 4, 20, 8, 8, 2},
101    {0xff, "Unknown", -1, -1, 0, 0, 0}
102};
103
104
105/****************************************/
106/***  hardware dependant functions    ***/
107/****************************************/
108
109static void drv_MO_clear(void)
110{
111    switch (Protocol) {
112    case 1:
113  drv_generic_serial_write("\014", 1);  /* Clear Screen */
114  break;
115    case 2:
116  drv_generic_serial_write("\376\130", 2);  /* Clear Screen */
117  break;
118    }
119}
120
121
122static void drv_MO_write(const int row, const int col, const char *data, const int len)
123{
124    char cmd[5] = "\376Gyx";
125
126    cmd[2] = (char) col + 1;
127    cmd[3] = (char) row + 1;
128    drv_generic_serial_write(cmd, 4);
129
130    drv_generic_serial_write(data, len);
131}
132
133
134static void drv_MO_defchar(const int ascii, const unsigned char *matrix)
135{
136    int i;
137    char cmd[11] = "\376N";
138
139    cmd[2] = (char) ascii;
140    for (i = 0; i < 8; i++) {
141  cmd[i + 3] = matrix[i] & 0x1f;
142    }
143    drv_generic_serial_write(cmd, 11);
144}
145
146
147static int drv_MO_contrast(int contrast)
148{
149    static unsigned char Contrast = 0;
150    char cmd[3] = "\376Pn";
151
152    /* -1 is used to query the current contrast */
153    if (contrast == -1)
154  return Contrast;
155
156    if (contrast < 0)
157  contrast = 0;
158    if (contrast > 255)
159  contrast = 255;
160    Contrast = contrast;
161
162    cmd[2] = Contrast;
163
164    drv_generic_serial_write(cmd, 3);
165
166    return Contrast;
167}
168
169
170static int drv_MO_backlight(int backlight)
171{
172    static unsigned char Backlight = 0;
173    char cmd[3] = "\376Bn";
174
175    /* -1 is used to query the current backlight */
176    if (backlight == -1)
177  return Backlight;
178
179    if (backlight < 0)
180  backlight = 0;
181    if (backlight > 255)
182  backlight = 255;
183    Backlight = backlight;
184
185    if (backlight <= 0) {
186  /* backlight off */
187  drv_generic_serial_write("\376F", 2);
188    } else {
189  /* backlight on for n minutes */
190  cmd[2] = Backlight;
191  drv_generic_serial_write(cmd, 3);
192    }
193
194    return Backlight;
195}
196
197
198static int drv_MO_GPI(const int num)
199{
200    static int GPI[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
201    static time_t T[8], now;
202
203
204    if (num < 0 || num > 7) {
205  return 0;
206    }
207
208    /* read RPM every two seconds */
209    if (time(&now) - T[num] >= 2) {
210
211  char cmd[3];
212  unsigned char ans[7];
213
214  T[num] = now;
215
216  cmd[0] = '\376';
217  cmd[1] = '\301';
218  cmd[2] = (char) num + 1;
219  drv_generic_serial_write(cmd, 3);
220  usleep(100000);
221
222  if (drv_generic_serial_read((char *) ans, 7) == 7) {
223      if (ans[0] == 0x23 && ans[1] == 0x2a && ans[2] == 0x03 && ans[3] == 0x52 && ans[4] == num + 1) {
224    GPI[num] = 18750000 / (256 * ans[5] + ans[6]);
225      } else {
226    error("%s: strange answer %02x %02x %02x %02x %02x %02x %02x", Name, ans[0], ans[1], ans[2], ans[3],
227          ans[4], ans[5], ans[6]);
228      }
229  }
230    }
231
232    return GPI[num];
233}
234
235
236static int drv_MO_GPO(const int num, const int val)
237{
238    int v = 0;
239    char cmd[4];
240
241    switch (Protocol) {
242    case 1:
243  if (num == 0) {
244      if (val > 0) {
245    v = 1;
246    drv_generic_serial_write("\376W", 2); /* GPO on */
247      } else {
248    v = 0;
249    drv_generic_serial_write("\376V", 2); /* GPO off */
250      }
251  }
252  break;
253
254    case 2:
255  if (val <= 0) {
256      v = 0;
257      cmd[0] = '\376';
258      cmd[1] = 'V'; /* GPO off */
259      cmd[2] = (char) num + 1;
260      drv_generic_serial_write(cmd, 3);
261  } else if (val >= 255) {
262      v = 255;
263      cmd[0] = '\376';
264      cmd[1] = 'W'; /* GPO on */
265      cmd[2] = (char) num + 1;
266      drv_generic_serial_write(cmd, 3);
267  } else {
268      v = val;
269      cmd[0] = '\376';
270      cmd[1] = '\300';  /* PWM control */
271      cmd[2] = (char) num + 1;
272      cmd[3] = (char) v;
273      drv_generic_serial_write(cmd, 4);
274  }
275  break;
276    }
277
278    return v;
279}
280
281
282static int drv_MO_start(const char *section, const int quiet)
283{
284    int i;
285    char *model;
286    char buffer[256];
287
288    model = cfg_get(section, "Model", NULL);
289    if (model != NULL && *model != '\0') {
290  for (i = 0; Models[i].type != 0xff; i++) {
291      if (strcasecmp(Models[i].name, model) == 0)
292    break;
293  }
294  if (Models[i].type == 0xff) {
295      error("%s: %s.Model '%s' is unknown from %s", Name, section, model, cfg_source());
296      return -1;
297  }
298  Model = i;
299  info("%s: using model '%s'", Name, Models[Model].name);
300    } else {
301  info("%s: no '%s.Model' entry from %s, auto-dedecting", Name, section, cfg_source());
302  Model = -1;
303    }
304
305
306    if (drv_generic_serial_open(section, Name, 0) < 0)
307  return -1;
308
309    if (Model == -1 || Models[Model].protocol > 1) {
310  /* read module type */
311  drv_generic_serial_write("\3767", 2);
312  usleep(1000);
313  if (drv_generic_serial_read(buffer, 1) == 1) {
314      for (i = 0; Models[i].type != 0xff; i++) {
315    if (Models[i].type == (int) *buffer)
316        break;
317      }
318      info("%s: display reports model '%s' (type 0x%02x)", Name, Models[i].name, Models[i].type);
319
320      /* auto-dedection */
321      if (Model == -1)
322    Model = i;
323
324      /* auto-dedection matches specified model? */
325      if (Models[i].type != 0xff && Model != i) {
326    error("%s: %s.Model '%s' from %s does not match dedected Model '%s'", Name, section, model,
327          cfg_source(), Models[i].name);
328    return -1;
329      }
330
331  } else {
332      info("%s: display detection failed.", Name);
333  }
334    }
335
336    /* initialize global variables */
337    DROWS = Models[Model].rows;
338    DCOLS = Models[Model].cols;
339    GPIS = Models[Model].gpis;
340    GPOS = Models[Model].gpos;
341    Protocol = Models[Model].protocol;
342
343    if (Protocol > 1) {
344  /* read serial number */
345  drv_generic_serial_write("\3765", 2);
346  usleep(100000);
347  if (drv_generic_serial_read(buffer, 2) == 2) {
348      info("%s: display reports serial number 0x%x", Name, *(short *) buffer);
349  }
350
351  /* read version number */
352  drv_generic_serial_write("\3766", 2);
353  usleep(100000);
354  if (drv_generic_serial_read(buffer, 1) == 1) {
355      info("%s: display reports firmware version 0x%x", Name, *buffer);
356  }
357    }
358
359    drv_MO_clear();
360
361    drv_generic_serial_write("\376B", 3); /* backlight on */
362    drv_generic_serial_write("\376K", 2); /* cursor off */
363    drv_generic_serial_write("\376T", 2); /* blink off */
364    drv_generic_serial_write("\376D", 2); /* line wrapping off */
365    drv_generic_serial_write("\376R", 2); /* auto scroll off */
366
367    /* set contrast */
368    if (cfg_number(section, "Contrast", 0, 0, 255, &i) > 0) {
369  drv_MO_contrast(i);
370    }
371
372    /* set backlight */
373    if (cfg_number(section, "Backlight", 0, 0, 255, &i) > 0) {
374  drv_MO_backlight(i);
375    }
376
377    if (!quiet) {
378  if (drv_generic_text_greet(Models[Model].name, "MatrixOrbital")) {
379      sleep(3);
380      drv_MO_clear();
381  }
382    }
383
384    return 0;
385}
386
387
388/****************************************/
389/***            plugins               ***/
390/****************************************/
391
392
393static void plugin_contrast(RESULT * result, const int argc, RESULT * argv[])
394{
395    double contrast;
396
397    switch (argc) {
398    case 0:
399  contrast = drv_MO_contrast(-1);
400  SetResult(&result, R_NUMBER, &contrast);
401  break;
402    case 1:
403  contrast = drv_MO_contrast(R2N(argv[0]));
404  SetResult(&result, R_NUMBER, &contrast);
405  break;
406    default:
407  error("%s::contrast(): wrong number of parameters", Name);
408  SetResult(&result, R_STRING, "");
409    }
410}
411
412
413static void plugin_backlight(RESULT * result, const int argc, RESULT * argv[])
414{
415    double backlight;
416
417    switch (argc) {
418    case 0:
419  backlight = drv_MO_backlight(-1);
420  SetResult(&result, R_NUMBER, &backlight);
421  break;
422    case 1:
423  backlight = drv_MO_backlight(R2N(argv[0]));
424  SetResult(&result, R_NUMBER, &backlight);
425  break;
426    default:
427  error("%s::backlight(): wrong number of parameters", Name);
428  SetResult(&result, R_STRING, "");
429    }
430}
431
432
433/****************************************/
434/***        widget callbacks          ***/
435/****************************************/
436
437/* using drv_generic_text_draw(W) */
438/* using drv_generic_text_icon_draw(W) */
439/* using drv_generic_text_bar_draw(W) */
440/* using drv_generic_gpio_draw(W) */
441
442
443/****************************************/
444/***        exported functions        ***/
445/****************************************/
446
447
448/* list models */
449int drv_MO_list(void)
450{
451    int i;
452
453    for (i = 0; Models[i].type != 0xff; i++) {
454  printf("%s ", Models[i].name);
455    }
456    return 0;
457}
458
459
460/* initialize driver & display */
461int drv_MO_init(const char *section, const int quiet)
462{
463    WIDGET_CLASS wc;
464    int ret;
465
466    info("%s: %s", Name, "$Rev$");
467
468    /* display preferences */
469    XRES = 5;     /* pixel width of one char  */
470    YRES = 8;     /* pixel height of one char  */
471    CHARS = 8;      /* number of user-defineable characters */
472    CHAR0 = 0;      /* ASCII of first user-defineable char */
473    GOTO_COST = 4;    /* number of bytes a goto command requires */
474
475    /* real worker functions */
476    drv_generic_text_real_write = drv_MO_write;
477    drv_generic_text_real_defchar = drv_MO_defchar;
478    drv_generic_gpio_real_get = drv_MO_GPI;
479    drv_generic_gpio_real_set = drv_MO_GPO;
480
481
482    /* start display */
483    if ((ret = drv_MO_start(section, quiet)) != 0)
484  return ret;
485
486    /* initialize generic text driver */
487    if ((ret = drv_generic_text_init(section, Name)) != 0)
488  return ret;
489
490    /* initialize generic icon driver */
491    if ((ret = drv_generic_text_icon_init()) != 0)
492  return ret;
493
494    /* initialize generic bar driver */
495    if ((ret = drv_generic_text_bar_init(0)) != 0)
496  return ret;
497
498    /* add fixed chars to the bar driver */
499    drv_generic_text_bar_add_segment(0, 0, 255, 32);  /* ASCII  32 = blank */
500    drv_generic_text_bar_add_segment(255, 255, 255, 255); /* ASCII 255 = block */
501
502    /* initialize generic GPIO driver */
503    if ((ret = drv_generic_gpio_init(section, Name)) != 0)
504  return ret;
505
506    /* register text widget */
507    wc = Widget_Text;
508    wc.draw = drv_generic_text_draw;
509    widget_register(&wc);
510
511    /* register icon widget */
512    wc = Widget_Icon;
513    wc.draw = drv_generic_text_icon_draw;
514    widget_register(&wc);
515
516    /* register bar widget */
517    wc = Widget_Bar;
518    wc.draw = drv_generic_text_bar_draw;
519    widget_register(&wc);
520
521    /* register plugins */
522    AddFunction("LCD::contrast", -1, plugin_contrast);
523    AddFunction("LCD::backlight", -1, plugin_backlight);
524
525    return 0;
526}
527
528
529/* close driver & display */
530int drv_MO_quit(const int quiet)
531{
532
533    info("%s: shutting down display.", Name);
534
535    drv_generic_text_quit();
536    drv_generic_gpio_quit();
537
538    /* clear display */
539    drv_MO_clear();
540
541    /* say goodbye... */
542    if (!quiet) {
543  drv_generic_text_greet("goodbye!", NULL);
544    }
545
546    drv_generic_serial_close();
547
548    return (0);
549}
550
551
552DRIVER drv_MatrixOrbital = {
553    .name = Name,
554    .list = drv_MO_list,
555    .init = drv_MO_init,
556    .quit = drv_MO_quit,
557};
Note: See TracBrowser for help on using the browser.