aboutsummaryrefslogtreecommitdiffstats
path: root/widget.h
blob: c1b2785fa22f648bade029aa9807c3b0ad8b146f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/* $Id: widget.h,v 1.7 2004/01/14 11:33:00 reinelt Exp $
 *
 * generic widget handling
 *
 * Copyright 2003,2004 Michael Reinelt <reinelt@eunet.at>
 * Copyright 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 *
 * This file is part of LCD4Linux.
 *
 * LCD4Linux is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * LCD4Linux is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 * $Log: widget.h,v $
 * Revision 1.7  2004/01/14 11:33:00  reinelt
 * new plugin 'uname' which does what it's called
 * text widget nearly finished
 * first results displayed on MatrixOrbital
 *
 * Revision 1.6  2004/01/13 08:18:20  reinelt
 * timer queues added
 * liblcd4linux deactivated turing transformation to new layout
 *
 * Revision 1.5  2004/01/11 18:26:02  reinelt
 * further widget and layout processing
 *
 * Revision 1.4  2004/01/10 20:22:33  reinelt
 * added new function 'cfg_list()' (not finished yet)
 * added layout.c (will replace processor.c someday)
 * added widget_text.c (will be the first and most important widget)
 * modified lcd4linux.c so that old-style configs should work, too
 *
 * Revision 1.3  2004/01/10 17:34:40  reinelt
 * further matrixOrbital changes
 * widgets initialized
 *
 * Revision 1.2  2003/10/05 17:58:50  reinelt
 * libtool junk; copyright messages cleaned up
 *
 * Revision 1.1  2003/09/19 03:51:29  reinelt
 * minor fixes, widget.c added
 *
 */


#ifndef _WIDGET_H_
#define _WIDGET_H_


struct WIDGET; // forward declaration


typedef struct WIDGET_CLASS {
  char *name;
  int (*init)   (struct WIDGET *Self);
  int (*draw)   (struct WIDGET *Self);
  int (*quit)   (struct WIDGET *Self);
} WIDGET_CLASS;


typedef struct WIDGET{
  char         *name;
  WIDGET_CLASS *class;
  int           row;
  int           col;
  void         *data;
} WIDGET;



int widget_register (WIDGET_CLASS *widget);
int widget_add      (char *name, int row, int col);

#endif
id='n423' href='#n423'>423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
/* $Id$
 * $URL$
 *
 * driver for picoLCD Graphic(256x64) displays from mini-box.com
 *
 * Copyright (C) 2005 Michael Reinelt <michael@reinelt.co.at>
 * Copyright (C) 2005, 2006, 2007 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 *
 * Copyright (C) 2008 Nicu Pavel, Mini-Box.com <npavel@mini-box.com>
 *
 * This file is part of LCD4Linux.
 *
 * LCD4Linux is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * LCD4Linux is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

/* 
 *
 * exported fuctions:
 *
 * struct DRIVER drv_picoLCDGraphic
 *
 */

#include "config.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>

#include <usb.h>

#include "debug.h"
#include "cfg.h"
#include "qprintf.h"
#include "udelay.h"
#include "plugin.h"
#include "widget.h"
#include "widget_text.h"
#include "widget_icon.h"
#include "widget_bar.h"
#include "drv.h"
#include "drv_generic_gpio.h"
#include "drv_generic_keypad.h"
#include "drv_generic_graphic.h"



#define picoLCD_VENDOR  0x04d8
#define picoLCD_DEVICE  0xc002

#define OUT_REPORT_LED_STATE		0x81
#define OUT_REPORT_LCD_BACKLIGHT	0x91
#define OUT_REPORT_LCD_CONTRAST		0x92

#define OUT_REPORT_CMD			0x94
#define OUT_REPORT_DATA			0x95
#define OUT_REPORT_CMD_DATA		0x96

#define SCREEN_H			64
#define SCREEN_W			256


#if 1
#define DEBUG(x) debug("%s(): %s", __FUNCTION__, x);
#else
#define DEBUG(x)
#endif


static char Name[] = "picoLCDGraphic";
static unsigned char *pLG_framebuffer;

/* used to display white text on black background or inverse */
unsigned char inverted = 0;

static unsigned int gpo = 0;

static char *Buffer;
static char *BufPtr;

static usb_dev_handle *lcd;



/****************************************/
/***  hardware dependant functions    ***/
/****************************************/

static int drv_pLG_open(void)
{
    struct usb_bus *busses, *bus;
    struct usb_device *dev;
    char driver[1024];
    char product[1024];
    char manufacturer[1024];
    char serialnumber[1024];
    int ret;

    lcd = NULL;

    info("%s: scanning for picoLCD 256x64...", Name);

    usb_set_debug(0);

    usb_init();
    usb_find_busses();
    usb_find_devices();
    busses = usb_get_busses();

    for (bus = busses; bus; bus = bus->next) {
	for (dev = bus->devices; dev; dev = dev->next) {
	    if ((dev->descriptor.idVendor == picoLCD_VENDOR) && (dev->descriptor.idProduct == picoLCD_DEVICE)) {

		info("%s: found picoLCD on bus %s device %s", Name, bus->dirname, dev->filename);

		lcd = usb_open(dev);

		ret = usb_get_driver_np(lcd, 0, driver, sizeof(driver));

		if (ret == 0) {
		    info("%s: interface 0 already claimed by '%s'", Name, driver);
		    info("%s: attempting to detach driver...", Name);
		    if (usb_detach_kernel_driver_np(lcd, 0) < 0) {
			error("%s: usb_detach_kernel_driver_np() failed!", Name);
			return -1;
		    }
		}

		usb_set_configuration(lcd, 1);
		usleep(100);

		if (usb_claim_interface(lcd, 0) < 0) {
		    error("%s: usb_claim_interface() failed!", Name);
		    return -1;
		}

		usb_set_altinterface(lcd, 0);

		usb_get_string_simple(lcd, dev->descriptor.iProduct, product, sizeof(product));
		usb_get_string_simple(lcd, dev->descriptor.iManufacturer, manufacturer, sizeof(manufacturer));
		usb_get_string_simple(lcd, dev->descriptor.iSerialNumber, serialnumber, sizeof(serialnumber));

		info("%s: Manufacturer='%s' Product='%s' SerialNumber='%s'", Name, manufacturer, product, serialnumber);

		return 0;
	    }
	}
    }
    error("%s: could not find a picoLCD", Name);
    return -1;
}


static void drv_pLG_send(unsigned char *data, int size)
{
    int ret;
    ret = usb_interrupt_write(lcd, USB_ENDPOINT_OUT + 1, (char *) data, size, 1000);
    //fprintf(stderr, "%s written %d bytes\n", __FUNCTION__, ret);
}

static int drv_pLG_close(void)
{
    usb_release_interface(lcd, 0);
    usb_close(lcd);

    return 0;
}

static void drv_pLG_update_img()
{
    unsigned char cmd3[64] = { OUT_REPORT_CMD_DATA };	/* send command + data */
    unsigned char cmd4[64] = { OUT_REPORT_DATA };	/* send data only */

    int index, bit, x, y;
    unsigned char cs, line;
    unsigned char pixel;

    info("In %s\n", __FUNCTION__);


    for (cs = 0; cs < 4; cs++) {
	unsigned char chipsel = (cs << 2);	//chipselect
	for (line = 0; line < 8; line++) {
	    //ha64_1.setHIDPkt(OUT_REPORT_CMD_DATA, 8+3+32, 8, chipsel, 0x02, 0x00, 0x00, 0xb8|j, 0x00, 0x00, 0x40);
	    cmd3[0] = OUT_REPORT_CMD_DATA;
	    cmd3[1] = chipsel;
	    cmd3[2] = 0x02;
	    cmd3[3] = 0x00;
	    cmd3[4] = 0x00;
	    cmd3[5] = 0xb8 | line;
	    cmd3[6] = 0x00;
	    cmd3[7] = 0x00;
	    cmd3[8] = 0x40;
	    cmd3[9] = 0x00;
	    cmd3[10] = 0x00;
	    cmd3[11] = 32;

	    //ha64_2.setHIDPkt(OUT_REPORT_DATA, 4+32, 4, chipsel | 0x01, 0x00, 0x00, 32);

	    cmd4[0] = OUT_REPORT_DATA;
	    cmd4[1] = chipsel | 0x01;
	    cmd4[2] = 0x00;
	    cmd4[3] = 0x00;
	    cmd4[4] = 32;

	    for (index = 0; index < 32; index++) {
		pixel = 0x00;

		for (bit = 0; bit < 8; bit++) {
		    x = cs * 64 + index;
		    y = (line * 8 + bit + 0) % SCREEN_H;

		    if (pLG_framebuffer[y * 256 + x] ^ inverted)
			pixel |= (1 << bit);
		}
		cmd3[12 + index] = pixel;
	    }

	    for (index = 32; index < 64; index++) {
		pixel = 0x00;

		for (bit = 0; bit < 8; bit++) {
		    x = cs * 64 + index;
		    y = (line * 8 + bit + 0) % SCREEN_H;
		    if (pLG_framebuffer[y * 256 + x] ^ inverted)
			pixel |= (1 << bit);
		}

		cmd4[5 + (index - 32)] = pixel;
	    }

	    drv_pLG_send(cmd3, 44);
	    drv_pLG_send(cmd4, 38);
	}
    }

    //drv_pLG_clear();
}


/* for graphic displays only */
static void drv_pLG_blit(const int row, const int col, const int height, const int width)
{
    int r, c;

    //DEBUG(fprintf(stderr, "In %s called with row %d col %d height %d width %d\n", __FUNCTION__, row, col, height, width));

    for (r = row; r < row + height; r++) {
	for (c = col; c < col + width; c++) {
	    pLG_framebuffer[r * 256 + c] = drv_generic_graphic_black(r, c);
	    //fprintf(stderr, "%d", pLG_framebuffer[r * 256 + c]);
	}
	//fprintf(stderr, "\n");
    }

    /*
       for (r = 0; r < 64; r++) {
       for(c = 0; c < 256; c++) {
       fprintf(stderr, "%d", pLG_framebuffer[r * 256 + c]); 
       }
       fprintf(stderr, "\n");
       }
     */
    drv_pLG_update_img();
}


void drv_pLG_clear(void)
{
    unsigned char cmd[3] = { 0x93, 0x01, 0x00 };	/* init display */
    unsigned char cmd2[9] = { OUT_REPORT_CMD };	/* init display */
    unsigned char cmd3[64] = { OUT_REPORT_CMD_DATA };	/* clear screen */
    unsigned char cmd4[64] = { OUT_REPORT_CMD_DATA };	/* clear screen */

    int init, index;
    unsigned char cs, line;


    info("In %s\n", __FUNCTION__);
    drv_pLG_send(cmd, 3);

    for (init = 0; init < 4; init++) {
	unsigned char cs = ((init << 2) & 0xFF);

	cmd2[0] = OUT_REPORT_CMD;
	cmd2[1] = cs;
	cmd2[2] = 0x02;
	cmd2[3] = 0x00;
	cmd2[4] = 0x64;
	cmd2[5] = 0x3F;
	cmd2[6] = 0x00;
	cmd2[7] = 0x64;
	cmd2[8] = 0xC0;

	drv_pLG_send(cmd2, 9);
    }


    for (cs = 0; cs < 4; cs++) {
	unsigned char chipsel = (cs << 2);	//chipselect
	for (line = 0; line < 8; line++) {
	    //ha64_1.setHIDPkt(OUT_REPORT_CMD_DATA, 8+3+32, 8, cs, 0x02, 0x00, 0x00, 0xb8|j, 0x00, 0x00, 0x40);
	    cmd3[0] = OUT_REPORT_CMD_DATA;
	    cmd3[1] = chipsel;
	    cmd3[2] = 0x02;
	    cmd3[3] = 0x00;
	    cmd3[4] = 0x00;
	    cmd3[5] = 0xb8 | line;
	    cmd3[6] = 0x00;
	    cmd3[7] = 0x00;
	    cmd3[8] = 0x40;
	    cmd3[9] = 0x00;
	    cmd3[10] = 0x00;
	    cmd3[11] = 32;

	    unsigned char temp = 0;

	    for (index = 0; index < 32; index++) {
		cmd3[12 + index] = temp;
	    }

	    drv_pLG_send(cmd3, 64);

	    //ha64_2.setHIDPkt(OUT_REPORT_DATA, 4+32, 4, cs | 0x01, 0x00, 0x00, 32);

	    cmd4[0] = OUT_REPORT_DATA;
	    cmd4[1] = chipsel | 0x01;
	    cmd4[2] = 0x00;
	    cmd4[3] = 0x00;
	    cmd4[4] = 32;

	    for (index = 32; index < 64; index++) {
		temp = 0x00;
		cmd4[5 + (index - 32)] = temp;
	    }
	    drv_pLG_send(cmd4, 64);
	}
    }
}

static int drv_pLG_contrast(int contrast)
{
    unsigned char cmd[2] = { 0x92 };	/* set contrast */

    if (contrast < 0)
	contrast = 0;
    if (contrast > 255)
	contrast = 255;

    cmd[1] = contrast;
    drv_pLG_send(cmd, 2);

    return contrast;
}


static int drv_pLG_backlight(int backlight)
{
    unsigned char cmd[2] = { 0x91 };	/* set backlight */

    if (backlight < 0)
	backlight = 0;
    if (backlight >= 1)
	backlight = 200;

    cmd[1] = backlight;
    drv_pLG_send(cmd, 2);

    return backlight;
}

static int drv_pLG_gpo(int num, int val)
{
    unsigned char cmd[2] = { 0x81 };	/* set GPO */

    if (num < 0)
	num = 0;
    if (num > 7)
	num = 7;

    if (val < 0)
	val = 0;
    if (val > 1)
	val = 1;

    /* set led bit to 1 or 0 */
    if (val)
	gpo |= 1 << num;
    else
	gpo &= ~(1 << num);

    cmd[1] = gpo;
    //drv_pLG_send(cmd, 2);

    return val;
}

static int drv_pLG_start(const char *section, const int quiet)
{
    int rows = -1, cols = -1;
    int value;
    char *s;

    s = cfg_get(section, "Size", NULL);
    if (s == NULL || *s == '\0') {
	error("%s: no '%s.Size' entry from %s", Name, section, cfg_source());
	return -1;
    }
    if (sscanf(s, "%dx%d", &cols, &rows) != 2 || rows < 1 || cols < 1) {
	error("%s: bad %s.Size '%s' from %s", Name, section, s, cfg_source());
	free(s);
	return -1;
    }

    if (cfg_number(section, "Inverted", 0, 0, 1, &value) > 0) {
	info("Setting display inverted to %d", value);
	inverted = value;
    }

    DROWS = SCREEN_H;
    DCOLS = SCREEN_W;

    if (drv_pLG_open() < 0) {
	return -1;
    }

    /* Init the command buffer */
    Buffer = (char *) malloc(1024);
    if (Buffer == NULL) {
	error("%s: coommand buffer could not be allocated: malloc() failed", Name);
	return -1;
    }
    BufPtr = Buffer;

    /* Init framebuffer buffer */
    pLG_framebuffer = malloc(SCREEN_W * SCREEN_H * sizeof(unsigned char));
    if (!pLG_framebuffer)
	return -1;

    DEBUG("allocated");
    memset(pLG_framebuffer, 0, SCREEN_W * SCREEN_H);
    DEBUG("zeroed");

    if (cfg_number(section, "Contrast", 0, 0, 255, &value) > 0) {
	info("Setting contrast to %d", value);
	drv_pLG_contrast(value);
    }

    if (cfg_number(section, "Backlight", 0, 0, 1, &value) > 0) {
	info("Setting backlight to %d", value);
	drv_pLG_backlight(value);
    }

    drv_pLG_clear();		/* clear display */

    if (!quiet) {
	char buffer[40];
	qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, SCREEN_W, SCREEN_H);
	if (drv_generic_graphic_greet(buffer, "http://www.picolcd.com")) {
	    sleep(3);
	    drv_pLG_clear();
	}
    }

    return 0;
}


/****************************************/
/***            plugins               ***/
/****************************************/

static void plugin_contrast(RESULT * result, RESULT * arg1)
{
    double contrast;

    contrast = drv_pLG_contrast(R2N(arg1));
    SetResult(&result, R_NUMBER, &contrast);
}

static void plugin_backlight(RESULT * result, RESULT * arg1)
{
    double backlight;

    backlight = drv_pLG_backlight(R2N(arg1));
    SetResult(&result, R_NUMBER, &backlight);
}

static void plugin_gpo(RESULT * result, RESULT * argv[])
{
    double gpo;
    gpo = drv_pLG_gpo(R2N(argv[0]), R2N(argv[1]));
    SetResult(&result, R_NUMBER, &gpo);
}


/****************************************/
/***        widget callbacks          ***/
/****************************************/


/* using drv_generic_text_draw(W) */
/* using drv_generic_text_icon_draw(W) */
/* using drv_generic_text_bar_draw(W) */


/****************************************/
/***        exported functions        ***/
/****************************************/


/* list models */
int drv_pLG_list(void)
{
    printf("picoLCD 256x64 Graphic LCD");
    return 0;
}


/* initialize driver & display */
int drv_pLG_init(const char *section, const int quiet)
{
    int ret;

    info("%s: %s", Name, "$Rev$");

    info("PICOLCD Graphic initialization\n");

    /* display preferences */
    XRES = 6;			/* pixel width of one char  */
    YRES = 8;			/* pixel height of one char  */
    GPOS = 8;

    /* real worker functions */
    drv_generic_graphic_real_blit = drv_pLG_blit;

    /* start display */
    if ((ret = drv_pLG_start(section, quiet)) != 0)
	return ret;


    /* initialize generic graphic driver */
    if ((ret = drv_generic_graphic_init(section, Name)) != 0)
	return ret;

    /* GPO's init */

    if ((ret = drv_generic_gpio_init(section, Name)) != 0)
	return ret;

    /* register plugins */

    AddFunction("LCD::contrast", -1, plugin_contrast);
    AddFunction("LCD::backlight", -1, plugin_backlight);
    AddFunction("LCD::gpo", -1, plugin_gpo);

    return 0;
}


/* close driver & display */
int drv_pLG_quit(const int quiet)
{

    info("%s: shutting down.", Name);

    drv_generic_graphic_quit();

    /* clear display */
    drv_pLG_clear();

    /* say goodbye... */
    if (!quiet) {
	drv_generic_graphic_greet("goodbye!", NULL);
    }

    drv_pLG_close();

    if (Buffer) {
	free(Buffer);
	BufPtr = NULL;
    }

    return (0);
}


DRIVER drv_picoLCDGraphic = {
    .name = Name,
    .list = drv_pLG_list,
    .init = drv_pLG_init,
    .quit = drv_pLG_quit,
};