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