root/branches/0.10.1/drv_Cwlinux.c

Revision 789, 11.7 kB (checked in by michael, 21 months ago)

ported r784-r788 from trunk

  • Property svn:keywords set to Id URL Rev
Line 
1/* $Id$
2 * $URL$
3 *
4 * new style driver for Cwlinux 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_Cwlinux
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
42#include "debug.h"
43#include "cfg.h"
44#include "qprintf.h"
45#include "timer.h"
46#include "plugin.h"
47#include "widget.h"
48#include "widget_text.h"
49#include "widget_icon.h"
50#include "widget_bar.h"
51#include "widget_keypad.h"
52#include "drv.h"
53#include "drv_generic_text.h"
54#include "drv_generic_gpio.h"
55#include "drv_generic_serial.h"
56#include "drv_generic_keypad.h"
57
58
59static char Name[] = "Cwlinux";
60
61static int Model;
62static int Protocol;
63
64/* ring buffer for bytes received from the display */
65static unsigned char RingBuffer[256];
66static unsigned int RingRPos = 0;
67static unsigned int RingWPos = 0;
68
69typedef struct {
70    int type;
71    char *name;
72    int rows;
73    int cols;
74    int xres;     /* pixel width of one char */
75    int yres;     /* pixel height of one char */
76    int gpos;
77    int gpis;
78    int chars;      /* number of user definable chars */
79    int protocol;
80} MODEL;
81
82
83/* Fixme: number of gpo's should be verified */
84
85static MODEL Models[] = {
86    {0x01, "CW1602", 2, 16, 5, 7, 2, 2, 8, 1},
87    {0x02, "CW12232", 4, 20, 6, 8, 2, 2, 16, 2},
88    {0xff, "Unknown", -1, -1, -1, -1, -1, -1, -1, -1}
89};
90
91
92/****************************************/
93/***  hardware dependant functions    ***/
94/****************************************/
95
96static void drv_CW_process_input(void)
97{
98    while (RingRPos != RingWPos) {
99  drv_generic_keypad_press(RingBuffer[RingRPos++]);
100  if (RingRPos >= sizeof(RingBuffer))
101      RingRPos = 0;
102    }
103}
104
105
106static int drv_CW_poll(void)
107{
108    while (1) {
109  char buffer[32];
110  int num, n;
111
112  num = drv_generic_serial_poll(buffer, sizeof(buffer));
113  if (num <= 0)
114      break;    /* no more input */
115
116  /* put result into RingBuffer */
117  for (n = 0; n < num; n++) {
118      RingBuffer[RingWPos++] = (unsigned char) buffer[n];
119      if (RingWPos >= sizeof(RingBuffer))
120    RingWPos = 0;
121  }
122    }
123
124    if (RingRPos != RingWPos)
125  return 1;
126    else
127  return 0;
128}
129
130
131static void drv_CW_timer(void __attribute__ ((unused)) * notused)
132{
133    while (drv_CW_poll()) {
134  drv_CW_process_input();
135    }
136}
137
138
139static void drv_CW_send(const char *string, const int len)
140{
141    drv_generic_serial_write(string, len);
142    usleep(20);
143    if (drv_CW_poll())
144  drv_CW_process_input();
145}
146
147
148static void drv_CW_write(const int row, const int col, const char *data, const int len)
149{
150    char cmd[6] = "\376Gxy\375";
151
152    cmd[2] = (char) col;
153    cmd[3] = (char) row;
154    drv_CW_send(cmd, 5);
155    drv_CW_send(data, len);
156}
157
158
159static void drv_CW1602_defchar(const int ascii, const unsigned char *buffer)
160{
161    int i;
162    char cmd[12] = "\376Nn12345678\375";
163
164    cmd[2] = (char) ascii;
165
166    for (i = 0; i < 8; i++) {
167  cmd[3 + i] = buffer[i] & 0x1f;
168    }
169    drv_CW_send(cmd, 12);
170}
171
172
173static void drv_CW12232_defchar(const int ascii, const unsigned char *buffer)
174{
175    int i, j;
176    char cmd[10] = "\376Nn123456\375";
177
178    cmd[2] = (char) ascii;
179
180    /* The CW12232 uses a vertical bitmap layout, */
181    /* so we have to 'rotate' the bitmap. */
182
183    for (i = 0; i < 6; i++) {
184  cmd[3 + i] = 0;
185  for (j = 0; j < 8; j++) {
186      if (buffer[j] & (1 << (5 - i))) {
187    cmd[3 + i] |= (1 << j);
188      }
189  }
190    }
191    drv_CW_send(cmd, 10);
192}
193
194
195static int drv_CW_GPO(const int num, const int val)
196{
197    /* Fixme: GPO's not yet implemented! */
198    error("%s: GPO's not yet implemented!", Name);
199    /* Fixme: num*val to avoid compiler warning */
200    return num * val;
201}
202
203
204static int drv_CW_GPI(const int num)
205{
206    if (num < 0 || num > GPIS) {
207  return 0;
208    }
209    error("%s: GPI's not yet implemented!", Name);
210    return num;
211}
212
213
214static void drv_CW_clear(void)
215{
216#if 1
217    drv_CW_send("\376X\375", 3);  /* Clear Display */
218    usleep(500000);
219#else
220    /* for some mysterious reason, we have to sleep after  */
221    /* the command _and_ after the CMD_END... */
222    drv_CW_send("\376X", 2);  /* Clear Display */
223    drv_CW_send("\375", 1); /* Command End */
224#endif
225}
226
227
228static int drv_CW_brightness(int brightness)
229{
230    static unsigned char Brightness = 0;
231    char cmd[5] = "\376A_\375";
232
233    /* -1 is used to query the current brightness */
234    if (brightness == -1)
235  return Brightness;
236
237    if (brightness < 0)
238  brightness = 0;
239    if (brightness > 255)
240  brightness = 255;
241    Brightness = brightness;
242
243    switch (Brightness) {
244    case 0:
245  /* backlight off */
246  drv_CW_send("\376F\375", 3);
247  break;
248    case 8:
249  /* backlight on */
250  drv_CW_send("\376B\375", 3);
251  break;
252    default:
253  /* backlight level */
254  cmd[2] = (char) Brightness;
255  drv_CW_send(cmd, 4);
256  break;
257    }
258
259    return Brightness;
260}
261
262
263static int drv_CW_keypad(const int num)
264{
265    int val = WIDGET_KEY_PRESSED;
266
267    switch (num) {
268    case 65:
269  val += WIDGET_KEY_UP;
270  break;
271    case 66:
272  val += WIDGET_KEY_DOWN;
273  break;
274    case 67:
275  val += WIDGET_KEY_LEFT;
276  break;
277    case 68:
278  val += WIDGET_KEY_RIGHT;
279  break;
280    case 69:
281  val += WIDGET_KEY_CONFIRM;
282  break;
283    case 70:
284  val += WIDGET_KEY_CANCEL;
285  break;
286    default:
287  error("%s: unknown keypad value %d", Name, num);
288    }
289
290    debug("%s: key %c (0x%x) pressed", Name, num, num);
291    return val;
292}
293
294
295static int drv_CW_start(const char *section)
296{
297    int i;
298    char *model;
299    char buffer[16];
300
301    model = cfg_get(section, "Model", NULL);
302    if (model != NULL && *model != '\0') {
303  for (i = 0; Models[i].type != 0xff; i++) {
304      if (strcasecmp(Models[i].name, model) == 0)
305    break;
306  }
307  if (Models[i].type == 0xff) {
308      error("%s: %s.Model '%s' is unknown from %s", Name, section, model, cfg_source());
309      return -1;
310  }
311  Model = i;
312  info("%s: using model '%s'", Name, Models[Model].name);
313    } else {
314  error("%s: no '%s.Model' entry from %s", Name, section, cfg_source());
315  return -1;
316    }
317
318    /* open serial port */
319    if (drv_generic_serial_open(section, Name, 0) < 0)
320  return -1;
321
322    /* read firmware version */
323    drv_generic_serial_write("\3761\375", 3);
324    usleep(100000);
325    if (drv_generic_serial_read(buffer, 2) != 2) {
326  info("unable to read firmware version!");
327    } else {
328  info("Cwlinux Firmware V%d.%d", (int) buffer[0], (int) buffer[1]);
329    }
330
331    /* read model mumber */
332    drv_generic_serial_write("\3760\375", 3);
333    usleep(100000);
334    if (drv_generic_serial_read(buffer, 2) != 2) {
335  info("unable to read model number!");
336    } else {
337  info("Cwlinux model CW%d%d", (int) buffer[0], (int) buffer[1]);
338    }
339
340    /* initialize global variables */
341    DROWS = Models[Model].rows;
342    DCOLS = Models[Model].cols;
343    XRES = Models[Model].xres;
344    YRES = Models[Model].yres;
345    GPOS = Models[Model].gpos;
346    GPIS = Models[Model].gpis;
347    CHARS = Models[Model].chars;
348    Protocol = Models[Model].protocol;
349
350    /* regularly process display input */
351    timer_add(drv_CW_timer, NULL, 250, 0);
352
353    drv_CW_clear();
354
355    drv_CW_send("\376D\375", 3);  /* auto line wrap off */
356    drv_CW_send("\376R\375", 3);  /* auto scroll off */
357    drv_CW_send("\376K\375", 3);  /* underline cursor off */
358    drv_CW_send("\376B\375", 3);  /* backlight on */
359
360    /* set brightness */
361    if (cfg_number(section, "Brightness", 0, 0, 8, &i) > 0) {
362  drv_CW_brightness(i);
363    }
364
365    return 0;
366}
367
368
369/****************************************/
370/***            plugins               ***/
371/****************************************/
372
373
374static void plugin_brightness(RESULT * result, const int argc, RESULT * argv[])
375{
376    double brightness;
377
378    switch (argc) {
379    case 0:
380  brightness = drv_CW_brightness(-1);
381  SetResult(&result, R_NUMBER, &brightness);
382  break;
383    case 1:
384  brightness = drv_CW_brightness(R2N(argv[0]));
385  SetResult(&result, R_NUMBER, &brightness);
386  break;
387    default:
388  error("%s.brightness(): wrong number of parameters", Name);
389  SetResult(&result, R_STRING, "");
390    }
391}
392
393
394/****************************************/
395/***        widget callbacks          ***/
396/****************************************/
397
398/* using drv_generic_text_draw(W) */
399/* using drv_generic_text_icon_draw(W) */
400/* using drv_generic_text_bar_draw(W) */
401/* using drv_generic_gpio_draw(W) */
402/* using drv_generic_keypad_draw(W) */
403
404
405/****************************************/
406/***        exported functions        ***/
407/****************************************/
408
409
410/* list models */
411int drv_CW_list(void)
412{
413    int i;
414
415    for (i = 0; Models[i].type != 0xff; i++) {
416  printf("%s ", Models[i].name);
417    }
418    return 0;
419}
420
421
422/* initialize driver & display */
423int drv_CW_init(const char *section, const int quiet)
424{
425    WIDGET_CLASS wc;
426    int ret;
427
428    info("%s: %s", Name, "$Rev$");
429
430    /* display preferences */
431    CHAR0 = 1;      /* ASCII of first user-defineable char */
432    GOTO_COST = 3;    /* number of bytes a goto command requires */
433    INVALIDATE = 1;   /* re-defined chars must be re-sent to the display */
434
435    /* start display */
436    if ((ret = drv_CW_start(section)) != 0)
437  return ret;
438
439    /* real worker functions */
440    drv_generic_text_real_write = drv_CW_write;
441    drv_generic_gpio_real_set = drv_CW_GPO;
442    drv_generic_gpio_real_get = drv_CW_GPI;
443    drv_generic_keypad_real_press = drv_CW_keypad;
444
445    switch (Protocol) {
446    case 1:
447  drv_generic_text_real_defchar = drv_CW1602_defchar;
448  break;
449    case 2:
450  drv_generic_text_real_defchar = drv_CW12232_defchar;
451  break;
452    }
453
454    if (!quiet) {
455  char buffer[40];
456  qprintf(buffer, sizeof(buffer), "%s %s", Name, Models[Model].name);
457  if (drv_generic_text_greet(buffer, "www.cwlinux.com")) {
458      sleep(3);
459      drv_CW_clear();
460  }
461    }
462
463    /* initialize generic text driver */
464    if ((ret = drv_generic_text_init(section, Name)) != 0)
465  return ret;
466
467    /* initialize generic icon driver */
468    if ((ret = drv_generic_text_icon_init()) != 0)
469  return ret;
470
471    /* initialize generic bar driver */
472    if ((ret = drv_generic_text_bar_init(0)) != 0)
473  return ret;
474
475    /* add fixed chars to the bar driver */
476    drv_generic_text_bar_add_segment(0, 0, 255, 32);  /* ASCII 32 = blank */
477
478    /* initialize generic GPIO driver */
479    if ((ret = drv_generic_gpio_init(section, Name)) != 0)
480  return ret;
481
482    /* initialize generic key pad driver */
483    if ((ret = drv_generic_keypad_init(section, Name)) != 0)
484  return ret;
485
486    /* register text widget */
487    wc = Widget_Text;
488    wc.draw = drv_generic_text_draw;
489    widget_register(&wc);
490
491    /* register icon widget */
492    wc = Widget_Icon;
493    wc.draw = drv_generic_text_icon_draw;
494    widget_register(&wc);
495
496    /* register bar widget */
497    wc = Widget_Bar;
498    wc.draw = drv_generic_text_bar_draw;
499    widget_register(&wc);
500
501    /* register plugins */
502    AddFunction("LCD::brightness", -1, plugin_brightness);
503
504    return 0;
505}
506
507
508/* close driver & display */
509int drv_CW_quit(const int quiet)
510{
511
512    info("%s: shutting down.", Name);
513    drv_generic_text_quit();
514    drv_generic_gpio_quit();
515    drv_generic_keypad_quit();
516
517    /* clear display */
518    drv_CW_clear();
519
520    /* say goodbye... */
521    if (!quiet) {
522  drv_generic_text_greet("goodbye!", NULL);
523    }
524
525    drv_generic_serial_close();
526
527    return (0);
528}
529
530
531DRIVER drv_Cwlinux = {
532    .name = Name,
533    .list = drv_CW_list,
534    .init = drv_CW_init,
535    .quit = drv_CW_quit,
536};
Note: See TracBrowser for help on using the browser.