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