~siretart/lcd4linux/debian

« back to all changes in this revision

Viewing changes to drv_MatrixOrbital.c

  • Committer: Reinhard Tartler
  • Date: 2011-04-27 17:24:15 UTC
  • mto: This revision was merged to the branch mainline in revision 750.
  • Revision ID: siretart@tauware.de-20110427172415-6n4aptmvmz0eztvm
Tags: upstream-0.11.0~svn1143
ImportĀ upstreamĀ versionĀ 0.11.0~svn1143

Show diffs side-by-side

added added

removed removed

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