aboutsummaryrefslogtreecommitdiffstats
path: root/widget_timer.c
blob: 0190acd4ff3c65d017b9e7e50f30a561cc93227a (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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/* $Id: widget_timer.c,v 1.2 2006/02/25 13:36:33 geronet Exp $
 *
 * timer widget handling
 *
 * Copyright (C) 2006 Michael Reinelt <reinelt@eunet.at>
 * Copyright (C) 2006 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 *
 * This program 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.
 *
 * This program 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_timer.c,v $
 * Revision 1.2  2006/02/25 13:36:33  geronet
 * updated indent.sh, applied coding style
 *
 * Revision 1.1  2006/01/23 06:17:18  reinelt
 * timer widget added
 *
 */

/* 
 * exported functions:
 *
 * WIDGET_CLASS Widget_Timer
 *   the timer widget
 *
 */


#include "config.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include "debug.h"
#include "cfg.h"
#include "qprintf.h"
#include "evaluator.h"
#include "timer.h"
#include "widget.h"
#include "widget_timer.h"

#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif

void widget_timer_update(void *Self)
{
    WIDGET *W = (WIDGET *) Self;
    WIDGET_TIMER *Timer = W->data;
    RESULT result = { 0, 0, 0, NULL };

    /* evaluate expressions */
    Timer->update = 10;
    if (Timer->update_tree != NULL) {
	Eval(Timer->update_tree, &result);
	Timer->update = R2N(&result);
	if (Timer->update < 10)
	    Timer->update = 10;
	DelResult(&result);
    }

    Timer->active = 1;
    if (Timer->active_tree != NULL) {
	Eval(Timer->active_tree, &result);
	Timer->active = R2N(&result);
	if (Timer->active < 0)
	    Timer->active = 0;
	DelResult(&result);
    }

    /* finally, fire it! */
    if (Timer->active) {
	Eval(Timer->expr_tree, &result);
	DelResult(&result);
    }

    /* add a new one-shot timer */
    timer_add(widget_timer_update, Self, Timer->update, 1);
}



int widget_timer_init(WIDGET * Self)
{
    char *section;
    WIDGET_TIMER *Timer;

    /* prepare config section */
    /* strlen("Widget:")=7 */
    section = malloc(strlen(Self->name) + 8);
    strcpy(section, "Widget:");
    strcat(section, Self->name);

    Timer = malloc(sizeof(WIDGET_TIMER));
    memset(Timer, 0, sizeof(WIDGET_TIMER));

    /* get raw expressions (we evaluate them ourselves) */
    Timer->expression = cfg_get_raw(section, "axpression", NULL);
    Timer->update_expr = cfg_get_raw(section, "update", "100");
    Timer->active_expr = cfg_get_raw(section, "active", "1");

    /* sanity checks */
    if (Timer->expression == NULL || *Timer->expression == '\0') {
	error("Timer %s has no expression, using '1'", Self->name);
	Timer->expression = "1";
    }
    if (Timer->update_expr == NULL || *Timer->update_expr == '\0') {
	error("Timer %s has no update, using '100'", Self->name);
	Timer->update_expr = "100";
    }

    /* compile'em */
    Compile(Timer->expression, &Timer->expr_tree);
    Compile(Timer->update_expr, &Timer->update_tree);
    Compile(Timer->active_expr, &Timer->active_tree);


    free(section);
    Self->data = Timer;

    /* just do it! */
    widget_timer_update(Self);

    return 0;
}


int widget_timer_quit(WIDGET * Self)
{
    if (Self) {
	/* do not deallocate child widget! */
	if (Self->parent == NULL) {
	    if (Self->data) {
		WIDGET_TIMER *Timer = Self->data;
		DelTree(Timer->expr_tree);
		DelTree(Timer->update_tree);
		DelTree(Timer->active_tree);
		free(Self->data);
		Self->data = NULL;
	    }
	}
    }

    return 0;

}


int widget_timer_register(void)
{
    WIDGET_CLASS wc;
    wc = Widget_Timer;
    widget_register(&wc);
    return 0;
}


WIDGET_CLASS Widget_Timer = {
  name:"timer",
  type:WIDGET_TYPE_TIMER,
  init:widget_timer_init,
  draw:NULL,
  quit:widget_timer_quit,
};
"n">SIGNAL_RW; static unsigned char SIGNAL_RS; static unsigned char SIGNAL_ENABLE; static unsigned char SIGNAL_ENABLE2; static unsigned char SIGNAL_GPO; // Fixme static int GPOS; // static int GPO=0; // **************************************** // *** hardware dependant functions *** // **************************************** static void drv_HD_nibble(unsigned char controller, unsigned char nibble) { unsigned char enable; // enable signal: 'controller' is a bitmask // bit 0 .. send to controller #0 // bit 1 .. send to controller #1 // so we can send a byte to both controllers at the same time! enable=0; if (controller&0x01) enable|=SIGNAL_ENABLE; if (controller&0x02) enable|=SIGNAL_ENABLE2; // clear ENABLE // put data on DB1..DB4 // nibble already contains RS bit! drv_generic_parport_data(nibble); // Address set-up time ndelay(T_AS); // rise ENABLE drv_generic_parport_data(nibble | enable); // Enable pulse width ndelay(T_PW); // lower ENABLE drv_generic_parport_data(nibble); } static void drv_HD_byte (unsigned char controller, unsigned char data, unsigned char RS) { // send high nibble of the data drv_HD_nibble (controller, ((data>>4)&0x0f)|RS); // Make sure we honour T_CYCLE ndelay(T_CYCLE-T_AS-T_PW); // send low nibble of the data drv_HD_nibble(controller, (data&0x0f)|RS); } static void drv_HD_command (unsigned char controller, unsigned char cmd, int delay) { unsigned char enable; if (Bits==8) { // enable signal: 'controller' is a bitmask // bit 0 .. send to controller #0 // bit 1 .. send to controller #1 // so we can send a byte to both controllers at the same time! enable=0; if (controller&0x01) enable|=SIGNAL_ENABLE; if (controller&0x02) enable|=SIGNAL_ENABLE2; // put data on DB1..DB8 drv_generic_parport_data (cmd); // clear RW and RS drv_generic_parport_control (SIGNAL_RW | SIGNAL_RS, 0); // Address set-up time ndelay(T_AS); // send command drv_generic_parport_toggle (enable, 1, T_PW); } else { drv_HD_byte (controller, cmd, 0); } // wait for command completion udelay(delay); } static void drv_HD_data (unsigned char controller, char *string, int len, int delay) { unsigned char enable; // sanity check if (len<=0) return; if (Bits==8) { // enable signal: 'controller' is a bitmask // bit 0 .. send to controller #0 // bit 1 .. send to controller #1 // so we can send a byte to both controllers at the same time! enable=0; if (controller&0x01) enable|=SIGNAL_ENABLE; if (controller&0x02) enable|=SIGNAL_ENABLE2; // clear RW, set RS drv_generic_parport_control (SIGNAL_RW | SIGNAL_RS, SIGNAL_RS); // Address set-up time ndelay(T_AS); while (len--) { // put data on DB1..DB8 drv_generic_parport_data (*(string++)); // send command drv_generic_parport_toggle (enable, 1, T_PW); // wait for command completion udelay(delay); } } else { // 4 bit mode while (len--) { // send data with RS enabled drv_HD_byte (controller, *(string++), SIGNAL_RS); // wait for command completion udelay(delay); } } } static void drv_HD_goto (int row, int col) { int pos; // handle multiple displays/controllers if (Controllers>1 && row>=DROWS/2) { row -= DROWS/2; Controller = 2; } else { Controller = 1; } // 16x1 Displays are organized as 8x2 :-( if (DCOLS==16 && DROWS==1 && col>7) { row++; col-=8; } // 16x4 Displays use a slightly different layout if (DCOLS==16 && DROWS==4) { pos=(row%2)*64+(row/2)*16+col; } else { pos=(row%2)*64+(row/2)*20+col; } drv_HD_command (Controller, (0x80|pos), T_EXEC); } static int drv_HD_start (char *section) { int rows=-1, cols=-1, gpos=-1; 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 size '%s'", Name, s); return -1; } if (cfg_number(section, "GPOs", 0, 0, 8, &gpos)<0) return -1; info ("%s: controlling %d GPO's", Name, gpos); if (cfg_number(section, "Controllers", 1, 1, 2, &Controllers)<0) return -1; info ("%s: using display with %d controllers", Name, Controllers); // current controller Controller=1; DROWS = rows; DCOLS = cols; GPOS = gpos; if (cfg_number(section, "Bits", 8, 4, 8, &Bits)<0) return -1; if (Bits!=4 && Bits!=8) { error ("%s: bad %s.Bits '%s' from %s, should be '4' or '8'", Name, section, s, cfg_source()); return -1; } info ("%s: using %d bit mode", Name, Bits); if (drv_generic_parport_open(section, Name) != 0) { error ("%s: could not initialize parallel port!", Name); return -1; } if (Bits==8) { if ((SIGNAL_RS = drv_generic_parport_wire_ctrl ("RS", "AUTOFD"))==0xff) return -1; if ((SIGNAL_RW = drv_generic_parport_wire_ctrl ("RW", "GND" ))==0xff) return -1; if ((SIGNAL_ENABLE = drv_generic_parport_wire_ctrl ("ENABLE", "STROBE"))==0xff) return -1; if ((SIGNAL_ENABLE2 = drv_generic_parport_wire_ctrl ("ENABLE2", "GND" ))==0xff) return -1; if ((SIGNAL_GPO = drv_generic_parport_wire_ctrl ("GPO", "GND" ))==0xff) return -1; } else { if ((SIGNAL_RS = drv_generic_parport_wire_data ("RS", "DB4"))==0xff) return -1; if ((SIGNAL_RW = drv_generic_parport_wire_data ("RW", "DB5"))==0xff) return -1; if ((SIGNAL_ENABLE = drv_generic_parport_wire_data ("ENABLE", "DB6"))==0xff) return -1; if ((SIGNAL_ENABLE2 = drv_generic_parport_wire_data ("ENABLE2", "GND"))==0xff) return -1; if ((SIGNAL_GPO = drv_generic_parport_wire_data ("GPO", "GND"))==0xff) return -1; } // clear all signals if (Bits==8) { drv_generic_parport_control (SIGNAL_RS|SIGNAL_RW|SIGNAL_ENABLE|SIGNAL_ENABLE2|SIGNAL_GPO, 0); } else { drv_generic_parport_data (0); } // set direction: write drv_generic_parport_direction (0); // initialize *both* displays if (Bits==8) { drv_HD_command (0x03, 0x30, T_INIT1); // 8 Bit mode, wait 4.1 ms drv_HD_command (0x03, 0x30, T_INIT2); // 8 Bit mode, wait 100 us drv_HD_command (0x03, 0x38, T_EXEC); // 8 Bit mode, 1/16 duty cycle, 5x8 font } else { drv_HD_nibble(0x03, 0x03); udelay(T_INIT1); // 4 Bit mode, wait 4.1 ms drv_HD_nibble(0x03, 0x03); udelay(T_INIT2); // 4 Bit mode, wait 100 us drv_HD_nibble(0x03, 0x03); udelay(T_INIT1); // 4 Bit mode, wait 4.1 ms drv_HD_nibble(0x03, 0x02); udelay(T_INIT2); // 4 Bit mode, wait 100 us drv_HD_command (0x03, 0x28, T_EXEC); // 4 Bit mode, 1/16 duty cycle, 5x8 font } drv_HD_command (0x03, 0x08, T_EXEC); // Display off, cursor off, blink off drv_HD_command (0x03, 0x0c, T_CLEAR); // Display on, cursor off, blink off, wait 1.64 ms drv_HD_command (0x03, 0x06, T_EXEC); // curser moves to right, no shift drv_HD_command (0x03, 0x01, T_CLEAR); // clear *both* displays drv_HD_command (0x03, 0x03, T_CLEAR); // return home return 0; } static void drv_HD_write (char *string, int len) { drv_HD_data (Controller, string, len, T_EXEC); } static void drv_HD_defchar (int ascii, char *buffer) { // define chars on *both* controllers! drv_HD_command (0x03, 0x40|8*ascii, T_EXEC); drv_HD_data (0x03, buffer, 8, T_WRCG); } // Fixme #if 0 static void drv_HD_setGPO (int bits) { if (Lcd.gpos>0) { // put data on DB1..DB8 drv_generic_parport_data (bits); // 74HCT573 set-up time ndelay(20); // send data // 74HCT573 enable pulse width = 24ns drv_generic_parport_toggle (SIGNAL_GPO, 1, 230); } } #endif // **************************************** // *** plugins *** // **************************************** // **************************************** // *** 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_HD_list (void) { printf ("any"); return 0; } // initialize driver & display int drv_HD_init (char *section) { WIDGET_CLASS wc; int asc255bug; int ret; // display preferences XRES = 5; // pixel width of one char YRES = 8; // pixel height of one char CHARS = 8; // number of user-defineable characters CHAR0 = 0; // ASCII of first user-defineable char GOTO_COST = 2; // number of bytes a goto command requires // real worker functions drv_generic_text_real_write = drv_HD_write; drv_generic_text_real_goto = drv_HD_goto; drv_generic_text_real_defchar = drv_HD_defchar; // start display if ((ret=drv_HD_start (section))!=0) return ret; // initialize generic text driver if ((ret=drv_generic_text_init(section, Name))!=0) return ret; // initialize generic icon driver if ((ret=drv_generic_text_icon_init())!=0) return ret; // initialize generic bar driver if ((ret=drv_generic_text_bar_init())!=0) return ret; // add fixed chars to the bar driver // most displays have a full block on ascii 255, but some have kind of // an 'inverted P'. If you specify 'asc255bug 1 in the config, this // char will not be used, but rendered by the bar driver cfg_number(section, "asc255bug", 0, 0, 1, &asc255bug); drv_generic_text_bar_add_segment ( 0, 0,255, 32); // ASCII 32 = blank if (!asc255bug) drv_generic_text_bar_add_segment (255,255,255,255); // ASCII 255 = block // register text widget wc=Widget_Text; wc.draw=drv_generic_text_draw; widget_register(&wc); // register icon widget wc=Widget_Icon; wc.draw=drv_generic_text_icon_draw; widget_register(&wc); // register bar widget wc=Widget_Bar; wc.draw=drv_generic_text_bar_draw; widget_register(&wc); // register plugins // Fixme: plugins for HD44780? return 0; } // close driver & display int drv_HD_quit (void) { info("%s: shutting down.", Name); drv_generic_parport_close(); drv_generic_text_quit(); return (0); } DRIVER drv_HD44780 = { name: Name, list: drv_HD_list, init: drv_HD_init, quit: drv_HD_quit, };