~siretart/lcd4linux/debian

« back to all changes in this revision

Viewing changes to drv_ShuttleVFD.c

  • Committer: Reinhard Tartler
  • Date: 2011-04-27 17:28:49 UTC
  • mfrom: (0.1.1 upstream)
  • Revision ID: siretart@tauware.de-20110427172849-mj5cj5a0igpcc9fn
New upstream snapshot

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: drv_Sample.c 975 2009-01-18 11:16:20Z michael $
 
2
 * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_Sample.c $
 
3
 *
 
4
 * Shuttle SG33G5M VFD lcd4linux driver
 
5
 *
 
6
 * Copyright (C) 2009 Matthieu Crapet <mcrapet@gmail.com>
 
7
 * based on the USBLCD driver.
 
8
 *
 
9
 * Shuttle SG33G5M VFD (20x1 character display. Each character cell is 5x8 pixels)
 
10
 * - The display is driven by Princeton Technologies PT6314 VFD controller
 
11
 * - Cypress CY7C63723C (receives USB commands and talk to VFD controller)
 
12
 *
 
13
 * LCD "prococol" : each message has a length of 8 bytes
 
14
 * - 1 nibble: command (0x1, 0x3, 0x7, 0x9, 0xD)
 
15
 *     - 0x1 : clear text and icons (len=1)
 
16
 *     - 0x7 : icons (len=4)
 
17
 *     - 0x9 : text (len=7)
 
18
 *     - 0xD : set clock data (len=7)
 
19
 *     - 0x3 : display clock (internal feature) (len=1)
 
20
 * - 1 nibble: message length (0-7)
 
21
 * - 7 bytes : message data
 
22
 *
 
23
 * This file is part of LCD4Linux.
 
24
 *
 
25
 * LCD4Linux is free software; you can redistribute it and/or modify
 
26
 * it under the terms of the GNU General Public License as published by
 
27
 * the Free Software Foundation; either version 2, or (at your option)
 
28
 * any later version.
 
29
 *
 
30
 * LCD4Linux is distributed in the hope that it will be useful,
 
31
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
32
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
33
 * GNU General Public License for more details.
 
34
 *
 
35
 * You should have received a copy of the GNU General Public License
 
36
 * along with this program; if not, write to the Free Software
 
37
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
38
 *
 
39
 */
 
40
 
 
41
/*
 
42
 *
 
43
 * exported fuctions:
 
44
 *
 
45
 * struct DRIVER drv_ShuttleVFD
 
46
 *
 
47
 */
 
48
 
 
49
#include "config.h"
 
50
 
 
51
#include <stdlib.h>
 
52
#include <stdio.h>
 
53
#include <unistd.h>
 
54
#include <string.h>
 
55
#include <errno.h>
 
56
 
 
57
#ifdef HAVE_USB_H
 
58
#include <usb.h>
 
59
#else
 
60
#error "ShuttleVFD: libusb required"
 
61
#endif
 
62
 
 
63
#include "debug.h"
 
64
#include "cfg.h"
 
65
#include "qprintf.h"
 
66
#include "udelay.h"
 
67
#include "plugin.h"
 
68
#include "widget.h"
 
69
#include "widget_text.h"
 
70
#include "widget_bar.h"         // for DIRECTION
 
71
#include "drv.h"
 
72
#include "drv_generic_text.h"
 
73
#include "drv_generic_gpio.h"
 
74
 
 
75
 
 
76
/*
 
77
 * Some hardware definitions
 
78
 */
 
79
// VFD USB properties
 
80
#define SHUTTLE_VFD_VENDOR_ID   0x051C
 
81
#define SHUTTLE_VFD_PRODUCT_ID1 0x0003
 
82
#define SHUTTLE_VFD_PRODUCT_ID2 0x0005  // IR-receiver included
 
83
#define SHUTTLE_VFD_INTERFACE_NUM    1
 
84
 
 
85
// VFD physical dimensions
 
86
#define SHUTTLE_VFD_WIDTH           20
 
87
#define SHUTTLE_VFD_HEIGHT           1
 
88
 
 
89
// VFD USB control message
 
90
#define SHUTTLE_VFD_PACKET_SIZE         8
 
91
#define SHUTTLE_VFD_DATA_SIZE           (SHUTTLE_VFD_PACKET_SIZE-1)
 
92
#define SHUTTLE_VFD_SUCCESS_SLEEP_USEC  25600
 
93
 
 
94
 
 
95
/* Global static data */
 
96
static char Name[] = "ShuttleVFD";
 
97
static usb_dev_handle *lcd;
 
98
static unsigned char buffer[SHUTTLE_VFD_PACKET_SIZE];
 
99
 
 
100
/* Issues with the display module:
 
101
 *  - Can't set cursor position. Must save full buffer here.
 
102
 *  - Can't get icons status (on or off). Must save status here.
 
103
 *  - Clear command also clear text AND icons.
 
104
 */
 
105
static unsigned char fb[SHUTTLE_VFD_WIDTH * SHUTTLE_VFD_HEIGHT];
 
106
static unsigned icons;
 
107
 
 
108
 
 
109
/****************************************/
 
110
/***  hardware dependant functions    ***/
 
111
/****************************************/
 
112
 
 
113
/* look for device on USB bus */
 
114
static int drv_ShuttleVFD_open(void)
 
115
{
 
116
    struct usb_bus *bus;
 
117
    struct usb_device *dev;
 
118
 
 
119
    int vendor_id = SHUTTLE_VFD_VENDOR_ID;
 
120
    int interface = SHUTTLE_VFD_INTERFACE_NUM;
 
121
 
 
122
    lcd = NULL;
 
123
 
 
124
    usb_init();
 
125
    usb_find_busses();
 
126
    usb_find_devices();
 
127
 
 
128
    for (bus = usb_get_busses(); bus != NULL; bus = bus->next) {
 
129
        for (dev = bus->devices; dev != NULL; dev = dev->next) {
 
130
            if (dev->descriptor.idVendor == vendor_id && ((dev->descriptor.idProduct == SHUTTLE_VFD_PRODUCT_ID1) ||
 
131
                                                          (dev->descriptor.idProduct == SHUTTLE_VFD_PRODUCT_ID2))) {
 
132
 
 
133
                unsigned int v = dev->descriptor.bcdDevice;
 
134
 
 
135
                info("%s: found ShuttleVFD V%1d%1d.%1d%1d on bus %s device %s", Name,
 
136
                     (v & 0xF000) >> 12, (v & 0xF00) >> 8, (v & 0xF0) >> 4, (v & 0xF), bus->dirname, dev->filename);
 
137
 
 
138
                lcd = usb_open(dev);
 
139
            }
 
140
        }
 
141
    }
 
142
 
 
143
    if (lcd != NULL) {
 
144
        if (usb_claim_interface(lcd, interface) < 0) {
 
145
            usb_close(lcd);
 
146
            error("%s: usb_claim_interface() failed!", Name);
 
147
            error("%s: root permissions maybe required?", Name);
 
148
            return -1;
 
149
        }
 
150
    } else {
 
151
        error("%s: could not find ShuttleVFD", Name);
 
152
        return -1;
 
153
    }
 
154
 
 
155
    return 0;
 
156
}
 
157
 
 
158
 
 
159
static int drv_ShuttleVFD_close(void)
 
160
{
 
161
    int interface = SHUTTLE_VFD_INTERFACE_NUM;
 
162
 
 
163
    usb_release_interface(lcd, interface);
 
164
    usb_close(lcd);
 
165
    return 0;
 
166
}
 
167
 
 
168
 
 
169
static void drv_ShuttleVFD_send(unsigned char packet[SHUTTLE_VFD_PACKET_SIZE])
 
170
{
 
171
    if (usb_control_msg(lcd, 0x21,      // requesttype
 
172
                        0x09,   // request
 
173
                        0x0200, // value
 
174
                        0x0001, // index
 
175
                        (char *) packet, SHUTTLE_VFD_PACKET_SIZE, 100) == SHUTTLE_VFD_PACKET_SIZE) {
 
176
 
 
177
        udelay(SHUTTLE_VFD_SUCCESS_SLEEP_USEC);
 
178
    } else {
 
179
        debug("usb_control_msg failed");
 
180
    }
 
181
}
 
182
 
 
183
 
 
184
/* Clear full display and icons. */
 
185
static void drv_ShuttleVFD_clear(void)
 
186
{
 
187
    // Update local framebuffer mirror
 
188
    memset(fb, ' ', SHUTTLE_VFD_HEIGHT * SHUTTLE_VFD_WIDTH);
 
189
 
 
190
    buffer[0] = (1 << 4) + 1;
 
191
    buffer[1] = 0x1;
 
192
    drv_ShuttleVFD_send(buffer);
 
193
}
 
194
 
 
195
 
 
196
static void drv_ShuttleVFD_reset_cursor(void)
 
197
{
 
198
    buffer[0] = (1 << 4) + 1;
 
199
    buffer[1] = 0x2;
 
200
    drv_ShuttleVFD_send(buffer);
 
201
}
 
202
 
 
203
 
 
204
/* text mode displays only */
 
205
static void drv_ShuttleVFD_write(const int row, const int col, const char *data, int len)
 
206
{
 
207
    unsigned char *p;
 
208
    int i;
 
209
 
 
210
    // Update local framebuffer mirror
 
211
    memcpy(fb + (row * SHUTTLE_VFD_WIDTH) + col, data, len);
 
212
 
 
213
    p = fb;
 
214
    len = SHUTTLE_VFD_WIDTH;
 
215
 
 
216
    drv_ShuttleVFD_reset_cursor();
 
217
 
 
218
    while (len > 0) {
 
219
        if (len > 7)
 
220
            buffer[0] = (9 << 4) + 7;
 
221
        else
 
222
            buffer[0] = (9 << 4) + len;
 
223
 
 
224
        for (i = 0; i < 7 && len--; i++) {
 
225
            buffer[i + 1] = *p++;
 
226
        }
 
227
 
 
228
        drv_ShuttleVFD_send(buffer);
 
229
    }
 
230
}
 
231
 
 
232
 
 
233
static void drv_ShuttleVFD_defchar(const int ascii, const unsigned char *matrix)
 
234
{
 
235
    (void) matrix;
 
236
    debug("%s: not available (ascii=%d)", Name, ascii);
 
237
}
 
238
 
 
239
 
 
240
static int drv_ShuttleVFD_start(const char *section)
 
241
{
 
242
    char *port;
 
243
 
 
244
    port = cfg_get(section, "Port", NULL);
 
245
 
 
246
    if (port == NULL || *port == '\0') {
 
247
        error("%s: no '%s.Port' entry from %s", Name, section, cfg_source());
 
248
        return -1;
 
249
    }
 
250
 
 
251
    if (strcasecmp(port, "libusb") != 0) {
 
252
        error("%s: libusb expected", Name);
 
253
        error("%s: compile lcd4linux with libusb support!", Name);
 
254
        return -1;
 
255
    }
 
256
 
 
257
    DROWS = SHUTTLE_VFD_HEIGHT;
 
258
    DCOLS = SHUTTLE_VFD_WIDTH;
 
259
 
 
260
    /* open communication with the display */
 
261
    if (drv_ShuttleVFD_open() < 0) {
 
262
        return -1;
 
263
    }
 
264
 
 
265
    drv_ShuttleVFD_clear();     /* clear display */
 
266
    return 0;
 
267
}
 
268
 
 
269
 
 
270
/* VFD Icons. Add +1 in lcd4linux.conf (GPO1..GPIO27)
 
271
 *  0: television
 
272
 *  1: cd/dvd
 
273
 *  2: music
 
274
 *  3: radio
 
275
 *  4: clock
 
276
 *  5: pause
 
277
 *  6: play
 
278
 *  7: record
 
279
 *  8: rewind
 
280
 *  9: camera
 
281
 * 10: mute
 
282
 * 11: repeat
 
283
 * 12: reverse
 
284
 * 13: fastforward
 
285
 * 14: stop
 
286
 * 15: volume 1
 
287
 * 16: volume 2
 
288
 * ...
 
289
 * 25: volume 11
 
290
 * 26: volume 12
 
291
 */
 
292
static int drv_ShuttleVFD_icons_set(const int num, const int val)
 
293
{
 
294
    unsigned long value;
 
295
 
 
296
    if (num < 0 || num >= 27) {
 
297
        info("%s: num %d out of range (1..27)", Name, num);
 
298
        return -1;
 
299
    }
 
300
    // Special case for volume (icon n°16)
 
301
    if (num >= 15)
 
302
        value = (num - 15 + 1) << 15;
 
303
    else
 
304
        value = 1 << num;
 
305
 
 
306
    if (val > 0)
 
307
        icons |= value;
 
308
    else
 
309
        icons &= ~value;
 
310
 
 
311
    buffer[0] = (7 << 4) + 4;
 
312
    buffer[1] = (value >> 15) & 0x1F;
 
313
    buffer[2] = (value >> 10) & 0x1F;
 
314
    buffer[3] = (value >> 5) & 0x1F;
 
315
    buffer[4] = value & 0x1F;   // each data byte is stored on 5 bits
 
316
    drv_ShuttleVFD_send(buffer);
 
317
 
 
318
    return 0;
 
319
}
 
320
 
 
321
 
 
322
/****************************************/
 
323
/***            plugins               ***/
 
324
/****************************************/
 
325
 
 
326
/* none yet ! */
 
327
 
 
328
 
 
329
/****************************************/
 
330
/***        widget callbacks          ***/
 
331
/****************************************/
 
332
 
 
333
/* using drv_generic_text_draw(W) */
 
334
/* using drv_generic_gpio_draw(W) */
 
335
 
 
336
 
 
337
/****************************************/
 
338
/***        exported functions        ***/
 
339
/****************************************/
 
340
 
 
341
 
 
342
/* supported Shuttle models */
 
343
int drv_ShuttleVFD_list(void)
 
344
{
 
345
    printf("Shuttle SG33G5M, Shuttle PF27 upgrade kit");
 
346
    return 0;
 
347
}
 
348
 
 
349
 
 
350
/* initialize driver & text display */
 
351
int drv_ShuttleVFD_init(const char *section, const int quiet)
 
352
{
 
353
    WIDGET_CLASS wc;
 
354
    int ret;
 
355
 
 
356
    info("%s: %s", Name, "$Rev: 975 $");
 
357
 
 
358
    /* display preferences */
 
359
    XRES = 5;                   /* pixel width of one char  */
 
360
    YRES = 8;                   /* pixel height of one char  */
 
361
    CHARS = 0;                  /* number of user-defineable characters */
 
362
    CHAR0 = 0;                  /* ASCII of first user-defineable char */
 
363
    GOTO_COST = 2;              /* number of bytes a goto command requires */
 
364
    GPOS = 15 + 12;             /* Fancy icons on top of display */
 
365
 
 
366
    /* real worker functions */
 
367
    drv_generic_text_real_write = drv_ShuttleVFD_write;
 
368
    drv_generic_text_real_defchar = drv_ShuttleVFD_defchar;
 
369
    drv_generic_gpio_real_set = drv_ShuttleVFD_icons_set;
 
370
 
 
371
    /* start display */
 
372
    if ((ret = drv_ShuttleVFD_start(section)) != 0)
 
373
        return ret;
 
374
 
 
375
    if (!quiet) {
 
376
        char buffer[40];
 
377
        qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS);
 
378
        if (drv_generic_text_greet(buffer, "Shuttle")) {
 
379
            sleep(3);
 
380
            drv_ShuttleVFD_clear();
 
381
        }
 
382
    }
 
383
 
 
384
    /* initialize generic text driver */
 
385
    if ((ret = drv_generic_text_init(section, Name)) != 0)
 
386
        return ret;
 
387
 
 
388
    /* initialize generic GPIO driver */
 
389
    if ((ret = drv_generic_gpio_init(section, Name)) != 0)
 
390
        return ret;
 
391
 
 
392
    /* register text widget */
 
393
    wc = Widget_Text;
 
394
    wc.draw = drv_generic_text_draw;
 
395
    widget_register(&wc);
 
396
 
 
397
    return 0;
 
398
}
 
399
 
 
400
 
 
401
/* close driver & text display */
 
402
int drv_ShuttleVFD_quit(const int quiet)
 
403
{
 
404
    info("%s: shutting down.", Name);
 
405
 
 
406
    /* clear display */
 
407
    drv_ShuttleVFD_clear();
 
408
 
 
409
    /* say goodbye... */
 
410
    if (!quiet) {
 
411
        drv_generic_text_greet("goodbye!", NULL);
 
412
    }
 
413
 
 
414
    drv_generic_text_quit();
 
415
    drv_generic_gpio_quit();
 
416
 
 
417
    debug("closing connection");
 
418
    drv_ShuttleVFD_close();
 
419
 
 
420
    return (0);
 
421
}
 
422
 
 
423
 
 
424
DRIVER drv_ShuttleVFD = {
 
425
    .name = Name,
 
426
    .list = drv_ShuttleVFD_list,
 
427
    .init = drv_ShuttleVFD_init,
 
428
    .quit = drv_ShuttleVFD_quit,
 
429
};