1
/* $Id: drv_picoLCDGraphic.c 1143 2011-02-12 22:46:19Z mzuther $
2
* $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_picoLCDGraphic.c $
4
* driver for picoLCD Graphic(256x64) displays from mini-box.com
6
* Copyright (C) 2005 Michael Reinelt <michael@reinelt.co.at>
7
* Copyright (C) 2005, 2006, 2007 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
9
* Copyright (C) 2009 Nicu Pavel, Mini-Box.com <npavel@mini-box.com>
11
* This file is part of LCD4Linux.
13
* LCD4Linux is free software; you can redistribute it and/or modify
14
* it under the terms of the GNU General Public License as published by
15
* the Free Software Foundation; either version 2, or (at your option)
18
* LCD4Linux is distributed in the hope that it will be useful,
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
* GNU General Public License for more details.
23
* You should have received a copy of the GNU General Public License
24
* along with this program; if not, write to the Free Software
25
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33
* struct DRIVER drv_picoLCDGraphic
46
#include <sys/ioctl.h>
58
#include "widget_text.h"
59
#include "widget_icon.h"
60
#include "widget_bar.h"
61
#include "widget_keypad.h"
63
#include "drv_generic_gpio.h"
64
#include "drv_generic_keypad.h"
65
#include "drv_generic_graphic.h"
69
#define picoLCD_VENDOR 0x04d8
70
#define picoLCD_DEVICE 0xc002
72
#define OUT_REPORT_LED_STATE 0x81
73
#define OUT_REPORT_LCD_BACKLIGHT 0x91
74
#define OUT_REPORT_LCD_CONTRAST 0x92
76
#define OUT_REPORT_CMD 0x94
77
#define OUT_REPORT_DATA 0x95
78
#define OUT_REPORT_CMD_DATA 0x96
85
#define DEBUG(x) debug("%s(): %s", __FUNCTION__, x);
90
/* "dirty" marks the display to be redrawn from frame buffer */
93
/* timer for display redraw (set to zero for "direct updates") */
94
static int update = 0;
96
/* USB read timeout in ms (the picoLCD 256x64 times out on every read
97
unless a key has been pressed!) */
98
static int read_timeout = 0;
100
static char Name[] = "picoLCDGraphic";
101
static unsigned char *pLG_framebuffer;
103
/* used to display white text on black background or inverse */
104
unsigned char inverted = 0;
106
static unsigned int gpo = 0;
111
static usb_dev_handle *lcd;
112
//extern int usb_debug;
116
/****************************************/
117
/*** hardware dependant functions ***/
118
/****************************************/
120
static int drv_pLG_open(void)
122
struct usb_bus *busses, *bus;
123
struct usb_device *dev;
126
char manufacturer[1024];
127
char serialnumber[1024];
132
info("%s: scanning for picoLCD 256x64...", Name);
139
busses = usb_get_busses();
141
for (bus = busses; bus; bus = bus->next) {
142
for (dev = bus->devices; dev; dev = dev->next) {
143
if ((dev->descriptor.idVendor == picoLCD_VENDOR) && (dev->descriptor.idProduct == picoLCD_DEVICE)) {
145
info("%s: found picoLCD on bus %s device %s", Name, bus->dirname, dev->filename);
149
ret = usb_get_driver_np(lcd, 0, driver, sizeof(driver));
152
info("%s: interface 0 already claimed by '%s'", Name, driver);
153
info("%s: attempting to detach driver...", Name);
154
if (usb_detach_kernel_driver_np(lcd, 0) < 0) {
155
error("%s: usb_detach_kernel_driver_np() failed!", Name);
160
usb_set_configuration(lcd, 1);
163
if (usb_claim_interface(lcd, 0) < 0) {
164
error("%s: usb_claim_interface() failed!", Name);
168
usb_set_altinterface(lcd, 0);
170
usb_get_string_simple(lcd, dev->descriptor.iProduct, product, sizeof(product));
171
usb_get_string_simple(lcd, dev->descriptor.iManufacturer, manufacturer, sizeof(manufacturer));
172
usb_get_string_simple(lcd, dev->descriptor.iSerialNumber, serialnumber, sizeof(serialnumber));
174
info("%s: Manufacturer='%s' Product='%s' SerialNumber='%s'", Name, manufacturer, product, serialnumber);
180
error("%s: could not find a picoLCD", Name);
184
static int drv_pLG_read(unsigned char *data, int size)
186
return usb_interrupt_read(lcd, USB_ENDPOINT_IN + 1, (char *) data, size, read_timeout);
190
static void drv_pLG_send(unsigned char *data, int size)
193
ret = usb_interrupt_write(lcd, USB_ENDPOINT_OUT + 1, (char *) data, size, 1000);
194
//fprintf(stderr, "%s written %d bytes\n", __FUNCTION__, ret);
197
static int drv_pLG_close(void)
199
usb_release_interface(lcd, 0);
205
static void drv_pLG_update_img()
207
unsigned char cmd3[64] = { OUT_REPORT_CMD_DATA }; /* send command + data */
208
unsigned char cmd4[64] = { OUT_REPORT_DATA }; /* send data only */
210
int index, bit, x, y;
211
unsigned char cs, line;
214
/* do not redraw display if frame buffer has not changed, unless
215
"direct updates" have been requested (update is zero) */
216
if ((!dirty) && (update > 0)) {
217
debug("Skipping %s\n", __FUNCTION__);
221
debug("In %s\n", __FUNCTION__);
223
for (cs = 0; cs < 4; cs++) {
224
unsigned char chipsel = (cs << 2); //chipselect
225
for (line = 0; line < 8; line++) {
226
//ha64_1.setHIDPkt(OUT_REPORT_CMD_DATA, 8+3+32, 8, chipsel, 0x02, 0x00, 0x00, 0xb8|j, 0x00, 0x00, 0x40);
227
cmd3[0] = OUT_REPORT_CMD_DATA;
232
cmd3[5] = 0xb8 | line;
240
//ha64_2.setHIDPkt(OUT_REPORT_DATA, 4+32, 4, chipsel | 0x01, 0x00, 0x00, 32);
242
cmd4[0] = OUT_REPORT_DATA;
243
cmd4[1] = chipsel | 0x01;
248
for (index = 0; index < 32; index++) {
251
for (bit = 0; bit < 8; bit++) {
253
y = (line * 8 + bit + 0) % SCREEN_H;
255
if (pLG_framebuffer[y * 256 + x] ^ inverted)
258
cmd3[12 + index] = pixel;
261
for (index = 32; index < 64; index++) {
264
for (bit = 0; bit < 8; bit++) {
266
y = (line * 8 + bit + 0) % SCREEN_H;
267
if (pLG_framebuffer[y * 256 + x] ^ inverted)
271
cmd4[5 + (index - 32)] = pixel;
274
drv_pLG_send(cmd3, 44);
275
drv_pLG_send(cmd4, 38);
279
/* mark display as up-to-date */
285
#define _USBLCD_MAX_DATA_LEN 24
286
#define IN_REPORT_KEY_STATE 0x11
287
static void drv_pLG_update_keypad()
289
static int pressed_key = 0;
292
unsigned char read_packet[_USBLCD_MAX_DATA_LEN];
293
ret = drv_pLG_read(read_packet, _USBLCD_MAX_DATA_LEN);
294
if ((ret > 0) && (read_packet[0] == IN_REPORT_KEY_STATE)) {
295
debug("picoLCD: pressed key= 0x%02x\n", read_packet[1]);
296
int new_pressed_key = read_packet[1];
297
if (pressed_key != new_pressed_key) {
298
/* negative values mark a key release */
299
drv_generic_keypad_press(-pressed_key);
300
drv_generic_keypad_press(new_pressed_key);
301
pressed_key = new_pressed_key;
307
/* for graphic displays only */
308
static void drv_pLG_blit(const int row, const int col, const int height, const int width)
312
//DEBUG(fprintf(stderr, "In %s called with row %d col %d height %d width %d\n", __FUNCTION__, row, col, height, width));
314
for (r = row; r < row + height; r++) {
315
for (c = col; c < col + width; c++) {
316
pLG_framebuffer[r * 256 + c] = drv_generic_graphic_black(r, c);
317
//fprintf(stderr, "%d", pLG_framebuffer[r * 256 + c]);
319
//fprintf(stderr, "\n");
323
for (r = 0; r < 64; r++) {
324
for(c = 0; c < 256; c++) {
325
fprintf(stderr, "%d", pLG_framebuffer[r * 256 + c]);
327
fprintf(stderr, "\n");
331
/* display needs to be redrawn from frame buffer */
334
/* if "direct updates" have been requested, redraw now */
336
drv_pLG_update_img();
340
void drv_pLG_clear(void)
342
unsigned char cmd[3] = { 0x93, 0x01, 0x00 }; /* init display */
343
unsigned char cmd2[9] = { OUT_REPORT_CMD }; /* init display */
344
unsigned char cmd3[64] = { OUT_REPORT_CMD_DATA }; /* clear screen */
345
unsigned char cmd4[64] = { OUT_REPORT_CMD_DATA }; /* clear screen */
348
unsigned char cs, line;
351
debug("In %s\n", __FUNCTION__);
352
drv_pLG_send(cmd, 3);
354
for (init = 0; init < 4; init++) {
355
unsigned char cs = ((init << 2) & 0xFF);
357
cmd2[0] = OUT_REPORT_CMD;
367
drv_pLG_send(cmd2, 9);
371
for (cs = 0; cs < 4; cs++) {
372
unsigned char chipsel = (cs << 2); //chipselect
373
for (line = 0; line < 8; line++) {
374
//ha64_1.setHIDPkt(OUT_REPORT_CMD_DATA, 8+3+32, 8, cs, 0x02, 0x00, 0x00, 0xb8|j, 0x00, 0x00, 0x40);
375
cmd3[0] = OUT_REPORT_CMD_DATA;
380
cmd3[5] = 0xb8 | line;
388
unsigned char temp = 0;
390
for (index = 0; index < 32; index++) {
391
cmd3[12 + index] = temp;
394
drv_pLG_send(cmd3, 64);
396
//ha64_2.setHIDPkt(OUT_REPORT_DATA, 4+32, 4, cs | 0x01, 0x00, 0x00, 32);
398
cmd4[0] = OUT_REPORT_DATA;
399
cmd4[1] = chipsel | 0x01;
404
for (index = 32; index < 64; index++) {
406
cmd4[5 + (index - 32)] = temp;
408
drv_pLG_send(cmd4, 64);
413
static int drv_pLG_contrast(int contrast)
415
unsigned char cmd[2] = { 0x92 }; /* set contrast */
423
drv_pLG_send(cmd, 2);
429
static int drv_pLG_backlight(int backlight)
431
unsigned char cmd[2] = { 0x91 }; /* set backlight */
439
drv_pLG_send(cmd, 2);
444
static int drv_pLG_gpi( __attribute__ ((unused))
448
unsigned char read_packet[_USBLCD_MAX_DATA_LEN];
449
ret = drv_pLG_read(read_packet, _USBLCD_MAX_DATA_LEN);
450
if ((ret > 0) && (read_packet[0] == IN_REPORT_KEY_STATE)) {
451
debug("picoLCD: pressed key= 0x%02x\n", read_packet[1]);
452
return read_packet[1];
458
static int drv_pLG_gpo(int num, int val)
460
unsigned char cmd[2] = { 0x81 }; /* set GPO */
472
/* set led bit to 1 or 0 */
479
drv_pLG_send(cmd, 2);
484
static int drv_pLG_start(const char *section, const int quiet)
486
int rows = -1, cols = -1;
490
/* set display redraw interval (set to zero for "direct updates") */
491
cfg_number(section, "update", 200, 0, -1, &update);
493
/* USB read timeout in ms (the picoLCD 256x64 times out on every
494
read unless a key has been pressed!) */
495
cfg_number(section, "Timeout", 5, 1, 1000, &read_timeout);
497
s = cfg_get(section, "Size", NULL);
498
if (s == NULL || *s == '\0') {
499
error("%s: no '%s.Size' entry from %s", Name, section, cfg_source());
502
if (sscanf(s, "%dx%d", &cols, &rows) != 2 || rows < 1 || cols < 1) {
503
error("%s: bad %s.Size '%s' from %s", Name, section, s, cfg_source());
508
if (cfg_number(section, "Inverted", 0, 0, 1, &value) > 0) {
509
info("Setting display inverted to %d", value);
516
if (drv_pLG_open() < 0) {
520
/* Init the command buffer */
521
Buffer = (char *) malloc(1024);
522
if (Buffer == NULL) {
523
error("%s: command buffer could not be allocated: malloc() failed", Name);
528
/* Init framebuffer buffer */
529
pLG_framebuffer = malloc(SCREEN_W * SCREEN_H * sizeof(unsigned char));
530
if (!pLG_framebuffer)
534
memset(pLG_framebuffer, 0, SCREEN_W * SCREEN_H);
537
if (cfg_number(section, "Contrast", 0, 0, 255, &value) > 0) {
538
info("Setting contrast to %d", value);
539
drv_pLG_contrast(value);
542
if (cfg_number(section, "Backlight", 0, 0, 1, &value) > 0) {
543
info("Setting backlight to %d", value);
544
drv_pLG_backlight(value);
547
drv_pLG_clear(); /* clear display */
551
qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, SCREEN_W, SCREEN_H);
552
if (drv_generic_graphic_greet(buffer, "http://www.picolcd.com")) {
558
/* setup a timer that regularly redraws the display from the frame
559
buffer (unless "direct updates" have been requested */
561
timer_add(drv_pLG_update_img, NULL, update, 0);
563
/* setup a timer that regularly checks the keypad for pressed or
565
/* FIXME: make 100msec configurable */
566
timer_add(drv_pLG_update_keypad, NULL, 100, 0);
572
/****************************************/
574
/****************************************/
576
static void plugin_contrast(RESULT * result, RESULT * arg1)
580
contrast = drv_pLG_contrast(R2N(arg1));
581
SetResult(&result, R_NUMBER, &contrast);
584
static void plugin_backlight(RESULT * result, RESULT * arg1)
588
backlight = drv_pLG_backlight(R2N(arg1));
589
SetResult(&result, R_NUMBER, &backlight);
592
static void plugin_gpo(RESULT * result, RESULT * argv[])
595
gpo = drv_pLG_gpo(R2N(argv[0]), R2N(argv[1]));
596
SetResult(&result, R_NUMBER, &gpo);
600
/****************************************/
601
/*** widget callbacks ***/
602
/****************************************/
605
/* using drv_generic_text_draw(W) */
606
/* using drv_generic_text_icon_draw(W) */
607
/* using drv_generic_text_bar_draw(W) */
610
/****************************************/
611
/*** exported functions ***/
612
/****************************************/
616
int drv_pLG_list(void)
618
printf("picoLCD 256x64 Graphic LCD");
623
static int drv_pLG_keypad(const int num)
630
else if (new_num > 0)
631
val = WIDGET_KEY_PRESSED;
633
/* negative values mark a key release */
635
val = WIDGET_KEY_RELEASED;
640
val += WIDGET_KEY_CANCEL;
643
val += WIDGET_KEY_LEFT;
646
val += WIDGET_KEY_RIGHT;
649
val += WIDGET_KEY_UP;
652
val += WIDGET_KEY_CONFIRM;
655
val += WIDGET_KEY_DOWN;
658
error("%s: unknown keypad value %d", Name, num);
665
/* initialize driver & display */
666
int drv_pLG_init(const char *section, const int quiet)
670
info("%s: %s", Name, "$Rev: 1143 $");
672
info("PICOLCD Graphic initialization\n");
674
/* display preferences */
675
XRES = 6; /* pixel width of one char */
676
YRES = 8; /* pixel height of one char */
679
/* real worker functions */
680
drv_generic_graphic_real_blit = drv_pLG_blit;
681
drv_generic_keypad_real_press = drv_pLG_keypad;
682
drv_generic_gpio_real_set = drv_pLG_gpo;
683
drv_generic_gpio_real_get = drv_pLG_gpi;
687
if ((ret = drv_pLG_start(section, quiet)) != 0)
691
/* initialize generic graphic driver */
692
if ((ret = drv_generic_graphic_init(section, Name)) != 0)
696
/* initialize generic key pad driver */
697
if ((ret = drv_generic_keypad_init(section, Name)) != 0)
703
if ((ret = drv_generic_gpio_init(section, Name)) != 0)
706
/* register plugins */
708
AddFunction("LCD::contrast", 1, plugin_contrast);
709
AddFunction("LCD::backlight", 1, plugin_backlight);
710
AddFunction("LCD::gpo", -1, plugin_gpo);
716
/* close driver & display */
717
int drv_pLG_quit(const int quiet)
720
info("%s: shutting down.", Name);
727
drv_generic_graphic_greet("goodbye!", NULL);
737
drv_generic_graphic_quit();
738
drv_generic_keypad_quit();
744
DRIVER drv_picoLCDGraphic = {
746
.list = drv_pLG_list,
747
.init = drv_pLG_init,
748
.quit = drv_pLG_quit,