Doc fixes.
[bertos.git] / drv / lcd_lm44_qt.cpp
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2006 Develer S.r.l. (http://www.develer.com/)
30  * Copyright 2000,2001 Bernardo Innocenti <bernie@codewiz.org>
31  *
32  * -->
33  *
34  * \version $Id$
35  *
36  * \author Bernardo Innocenti <bernie@develer.com>
37  *
38  * \brief Custom Qt widget for emulating a graphics LCD display (implementation)
39  */
40
41 /*#*
42  *#* $Log$
43  *#* Revision 1.1  2006/01/16 03:51:35  bernie
44  *#* Add LCD Qt emulator.
45  *#*
46  *#*/
47
48 #include <qpainter.h>
49 #include <qfont.h>
50 #include <qsizepolicy.h>
51 #include <qsize.h>
52 #include "EmulLCD.h"
53 #include "Emul.h"
54
55
56 // Display colors
57 #define LCD_FG_COLOR 0x0, 0x0, 0x0
58 #define LCD_BG_COLOR 0xBB, 0xCC, 0xBB
59
60
61 EmulLCD::EmulLCD(QWidget *parent, const char *name) :
62         QFrame(parent, name, WRepaintNoErase | WResizeNoErase),
63         lcd_font("courier", 18),
64         fg_color(LCD_FG_COLOR),
65         bg_color(LCD_BG_COLOR),
66         cr_row(0),
67         cr_col(0),
68         cgramaddr(-1),
69         show_cursor(true)
70 {
71         // initialize DDRAM
72         memcpy(ddram,
73                 "01234567890123456789"
74                 "abcdefghijhlmnopqrst"
75                 "ABCDEFGHIJKLMNOPQRST"
76                 "!@#$%^&*()_+|{}':?><",
77                 sizeof(ddram));
78
79         // setup font
80         lcd_font.setFixedPitch(true);
81         setFont(lcd_font);
82
83         // get exact font size
84         QFontMetrics fm(lcd_font);
85         font_width      = fm.width(QChar(' '));
86         font_height     = fm.height();
87
88         // set widget frame
89         setFrameStyle(QFrame::Panel | QFrame::Sunken);
90 //      setLineWidth(2);
91         frame_width = frameWidth();
92 }
93
94
95 EmulLCD::~EmulLCD()
96 {
97         // nop
98 }
99
100
101 QSizePolicy EmulLCD::sizePolicy() const
102 {
103         return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed, false);
104 }
105
106
107 QSize EmulLCD::sizeHint() const
108 {
109         return QSize(
110                 font_width * COLS + frame_width * 2,
111                 font_height * ROWS + frame_width * 2);
112 }
113
114
115 void EmulLCD::drawContents(QPainter *p)
116 {
117         RedrawText(*p);
118 }
119
120
121 void EmulLCD::SetPainter(QPainter & p)
122 {
123         p.setBackgroundMode(OpaqueMode);
124         p.setPen(fg_color);
125         p.setBackgroundColor(bg_color);
126 }
127
128
129 void EmulLCD::RedrawText(QPainter & p)
130 {
131         int r, c;
132
133         SetPainter(p);
134
135         for (r = 0; r < ROWS; r++)
136                 for (c = 0; c < COLS; c++)
137                         PrintChar(p, r, c);
138 }
139
140
141 void EmulLCD::PrintChar(QPainter & p, int row, int col)
142 {
143         // Fetch char from DD RAM
144         unsigned char c = ddram[row][col];
145
146         // Map some Hitachi characters to ISO Latin1
147         switch(c)
148         {
149                 case 0xDF:
150                         c = 0xBA;       // "degrees" glyph
151                         break;
152
153                 case 0xE4:
154                         c = 0xB5;       // "micro" glyph
155                         break;
156
157                 default:                // all others
158                         break;
159         }
160
161         // Draw char on display
162         int x = col * font_width + frame_width;
163         int y = row * font_height + frame_width;
164         bool restore_colors = false;
165
166         if (show_cursor && (row == cr_row) && (col == cr_col))
167         {
168                 // Exchange FG/BG colors
169                 p.setPen(bg_color);
170                 p.setBackgroundColor(fg_color);
171                 restore_colors = true;
172         }
173
174         p.drawText(x, y, x + font_width, y + font_height, 0 /*tf*/,
175                 QString(QChar(c)), 1);
176
177         if (restore_colors)
178         {
179                 // Restore FG/BG colors
180                 p.setPen(fg_color);
181                 p.setBackgroundColor(bg_color);
182         }
183 }
184
185
186 void EmulLCD::MoveCursor(int r, int c)
187 {
188         // Save old cursor position
189         int old_row = cr_row;
190         int old_col = cr_col;
191         
192         // Move the cursor
193         cgramaddr = -1;
194         cr_row = r;
195         cr_col = c;
196
197         if (show_cursor && (old_col != cr_col || old_row != cr_row))
198         {
199                 QPainter p(this);
200                 SetPainter(p);
201
202                 // Draw new cursor
203                 PrintChar(p, cr_row, cr_col);
204
205                 // Erase old cursor
206                 PrintChar(p, old_row, old_col);
207         }
208 }
209
210
211 void EmulLCD::ShowCursor(bool show)
212 {
213         show_cursor = show;
214
215         // Draw (or erase) cursor
216         QPainter p(this);
217         SetPainter(p);
218         PrintChar(p, cr_row, cr_col);
219 }
220
221
222 void EmulLCD::AdvanceCursor()
223 {
224         // Move the cursor
225         if (cr_col == COLS - 1)
226         {
227                 if (cr_row == ROWS - 1)
228                         MoveCursor(0, 0);
229                 else
230                         MoveCursor(cr_row + 1, 0);
231         }
232         else
233                 MoveCursor(cr_row, cr_col + 1);
234 }
235
236
237 void EmulLCD::PutChar(unsigned char c)
238 {
239         if (cgramaddr != -1)
240         {
241                 // Write data in CGRAM
242                 cgram[cgramaddr] = c;
243
244                 // Auto increment CGRAM address
245                 cgramaddr = (cgramaddr + 1) & 0x3F;
246         }
247         else
248         {
249                 // Writing in DDRAM
250                 ddram[cr_row][cr_col] = c;
251
252                 // Update display
253                 {
254                         QPainter p(this);
255                         SetPainter(p);
256                         PrintChar(p, cr_row, cr_col);
257                 }
258                 AdvanceCursor();
259         }
260 }
261
262
263 char EmulLCD::GetChar()
264 {
265         char c = ddram[cr_row][cr_col];
266         AdvanceCursor();
267         return c;
268 }
269
270
271 void EmulLCD::Clear()
272 {
273         memset(ddram, ' ', sizeof(ddram));
274         cr_row = cr_col = 0;
275
276         QPainter p(this);
277         RedrawText(p);
278 }
279
280
281 void EmulLCD::SetCGRamAddr(unsigned char addr)
282 {
283         cgramaddr = addr & (sizeof(cgram) - 1);
284 }
285
286
287 // Hitachi LM044L register-level emulation
288
289 #define INI_DISPLAY             0x30
290 #define INI_OP_DISP             0x38    /* 8 bits, 2 lines, 5x7 dots */
291 #define ON_DISPLAY              0x0F    /* Switch on display */
292 #define OFF_DISPLAY             0x08    /* Switch off display */
293 #define CLR_DISPLAY             0x01    /* Clear display */
294 #define CURSOR_BLOCK    0x0D    /* Show cursor (block) */
295 #define CURSOR_LINE             0x0F    /* Show cursor (line) */
296 #define CURSOR_OFF              0x0C    /* Hide cursor */
297 #define MODE_DISPL              0x06
298 #define SHIFT_DISPLAY   0x18
299 #define MOVESHIFT_LEFT  0x00
300 #define MOVESHIFT_RIGHT 0x04
301 #define LCD_CGRAMADDR   (1<<6)
302 #define LCD_DDRAMADDR   (1<<7)
303
304
305 extern "C" void Emul_LCDWriteReg(unsigned char d)
306 {
307         static const unsigned char lcd_rowaddress[EmulLCD::ROWS] = { 0x80, 0xC0, 0x94, 0xD4 };
308
309         switch(d)
310         {
311                 case CLR_DISPLAY:
312                         emul->emulLCD->Clear();
313                         break;
314
315                 case CURSOR_BLOCK:
316                 case CURSOR_LINE:
317                         emul->emulLCD->ShowCursor(true);
318                         break;
319
320                 case CURSOR_OFF:
321                         emul->emulLCD->ShowCursor(false);
322                         break;
323
324                 default:
325                         // Set DDRAM address?
326                         if (d & LCD_DDRAMADDR)
327                         {
328                                 for (int i = 0; i < EmulLCD::ROWS; i++)
329                                 {
330                                         if ((d >= lcd_rowaddress[i]) && (d < lcd_rowaddress[i] + EmulLCD::COLS))
331                                         {
332                                                 emul->emulLCD->MoveCursor(i, d - lcd_rowaddress[i]);
333                                                 break;
334                                         }
335                                 }
336                         }
337                         else if (d & LCD_CGRAMADDR)
338                                 emul->emulLCD->SetCGRamAddr(d);
339                         break;
340         }
341 }
342
343
344 extern "C" unsigned char Emul_LCDReadReg(void)
345 {
346         return 0;       /* This LCD model is never busy ;-) */
347 }
348
349
350 extern "C" void Emul_LCDWriteData(unsigned char d)
351 {
352         emul->emulLCD->PutChar(d);
353 }
354
355
356 extern "C" unsigned char Emul_LCDReadData(void)
357 {
358         return emul->emulLCD->GetChar();
359 }
360
361 #include "EmulLCD.moc"
362