changed: smartxxlcd contrast code clean up
[xbmc:xbmc-antiquated.git] / xbmc / lib / smartXX / smartxxlcd.cpp
1
2 #include "../../stdafx.h"
3 #include "smartxxlcd.h"
4 #include "conio.h"
5 #include "../../Util.h"
6 #include "../../utils/SystemInfo.h"
7 #include "../../memutil.h"
8
9 #include <conio.h>
10
11 /*
12 HD44780 or equivalent
13 Character located  1   2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 
14 DDRAM address      00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13
15 DDRAM address      40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53
16 DDRAM address      14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27
17 DDRAM address      54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67
18 */
19
20 #define SCROLL_SPEED_IN_MSEC 250
21 #define DISP_O                          0xF700          // Display Port
22 #define DISP_O_LIGHT                      0xF701                // Display Port brightness control
23 #define DISP_O_CONTRAST                 0xF703          // Display Port contrast control
24 #define DISP_CTR_TIME               2                 // Controll Timing for Display routine
25
26 #define DISPCON_RS                    0x02                // some Display definitions
27 #define DISPCON_E                       0x04
28
29 #define INI                                 0x01
30 #define CMD                                 0x00
31 #define DAT                                 0x02
32
33 #define DISP_CLEAR                    0x01 // cmd: clear display command
34 #define DISP_HOME                       0x02 // cmd: return cursor to home
35 #define DISP_ENTRY_MODE_SET     0x04 // cmd: enable cursor moving direction and enable the shift of entire display
36 #define DISP_S_FLAG                   0x01
37 #define DISP_ID_FLAG                0x02
38
39 #define DISP_CONTROL                0x08        //cmd: display ON/OFF
40 #define DISP_D_FLAG                   0x04      // display on
41 #define DISP_C_FLAG                   0x02      // cursor on
42 #define DISP_B_FLAG                   0x01      // blinking on
43
44 #define DISP_EXT_CONTROL          0x08  //RE_FLAG = 1
45 #define DISP_FW_FLAG                0x04        //RE_FLAG = 1
46 #define DISP_BW_FLAG                0x02        //RE_FLAG = 1
47 #define DISP_NW_FLAG                0x01        //RE_FLAG = 1
48
49 #define DISP_SHIFT                    0x10  //cmd: set cursor moving and display shift control bit, and the direction without changing of ddram data
50 #define DISP_SC_FLAG                0x08
51 #define DISP_RL_FLAG                0x04
52
53 #define DISP_FUNCTION_SET         0x20 // cmd: set interface data length
54 #define DISP_DL_FLAG                0x10  // set interface data length: 8bit/4bit
55 #define DISP_N_FLAG                   0x08  // number of display lines:2-line / 1-line
56 #define DISP_F_FLAG                   0x04  // display font type 5x11 dots or 5x8 dots
57 #define DISP_RE_FLAG                0x04
58
59 #define DISP_CGRAM_SET            0x40 // cmd: set CGRAM address in address counter
60 #define DISP_SEGRAM_SET           0x40  //RE_FLAG = 1
61
62 #define DISP_DDRAM_SET            0x80 // cmd: set DDRAM address in address counter
63
64 char AnimIndex=0;
65
66 //*************************************************************************************************************
67 CSmartXXLCD::CSmartXXLCD()
68 {
69   m_iActualpos=0;
70   m_iRows    = 4;
71   m_iColumns = 20;                              // display rows each line
72   m_iRow1adr = 0x00;
73   m_iRow2adr = 0x20;
74   m_iRow3adr = 0x40;
75   m_iRow4adr = 0x60;
76
77   m_iRow1adr = 0x00;
78   m_iRow2adr = 0x40;
79   m_iRow3adr = 0x14;
80   m_iRow4adr = 0x54;
81   m_iBackLight=32;
82 }
83
84 //*************************************************************************************************************
85 CSmartXXLCD::~CSmartXXLCD()
86 {
87 }
88
89 //*************************************************************************************************************
90 void CSmartXXLCD::Initialize()
91 {
92   StopThread();
93   if (g_guiSettings.GetInt("lcd.type") == LCD_TYPE_NONE) 
94   {
95     CLog::Log(LOGINFO, "lcd not used");
96     return;
97   }
98   ILCD::Initialize();
99   Create();
100   
101 }
102 void CSmartXXLCD::SetBackLight(int iLight)
103 {
104   m_iBackLight=iLight;
105 }
106
107 void CSmartXXLCD::SetContrast(int iContrast)
108 {
109   m_iContrast=iContrast;
110 }
111
112 //*************************************************************************************************************
113 void CSmartXXLCD::Stop()
114 {
115   if (g_guiSettings.GetInt("lcd.type") == LCD_TYPE_NONE) return;
116   StopThread();
117 }
118
119 //*************************************************************************************************************
120 void CSmartXXLCD::SetLine(int iLine, const CStdString& strLine)
121 {
122   if (g_guiSettings.GetInt("lcd.type") == LCD_TYPE_NONE) return;
123   if (iLine < 0 || iLine >= (int)m_iRows) return;
124   
125   CStdString strLineLong=strLine;
126   strLineLong.Trim();
127         StringToLCDCharSet(strLineLong);
128
129   while (strLineLong.size() < m_iColumns) strLineLong+=" ";
130   if (strLineLong != m_strLine[iLine])
131   {
132 //    CLog::Log(LOGINFO, "set line:%i [%s]", iLine,strLineLong.c_str());
133     m_bUpdate[iLine]=true;
134     m_strLine[iLine]=strLineLong;
135     m_event.Set();
136   }
137 }
138
139
140 //************************************************************************************************************************
141 // wait_us: delay routine
142 // Input: (wait in ~us)
143 //************************************************************************************************************************
144 void CSmartXXLCD::wait_us(unsigned int value) 
145 {
146   // 1 us = 1000msec
147   int iValue=value/30;
148   if (iValue>10) iValue=10;
149   if (iValue) Sleep(iValue);
150 }
151
152
153 //************************************************************************************************************************
154 // DisplayOut: writes command or datas to display
155 // Input: (Value to write, token as CMD = Command / DAT = DATAs / INI for switching to 4 bit mode)
156 //************************************************************************************************************************
157 void CSmartXXLCD::DisplayOut(unsigned char data, unsigned char command) 
158 {
159         unsigned char odathigh;
160         unsigned char odatlow;
161   static DWORD dwTick=0;
162
163   if ((GetTickCount()-dwTick) < 3)
164   {
165     Sleep(1);
166   }
167   dwTick=GetTickCount();
168
169         // Data bit's mapping for higher nibble outbut
170         odathigh  = (data >> 2) & 0x28;         // outD7 => PortD5 => DisplayD7  //outD5 => PortD3 => DisplayD5
171         odathigh |= (data >> 0) & 0x50;         // outD6 => PortD6 => DisplayD6  //outD4 => PortD4 => DisplayD4         
172         
173   // Data bit's mapping for lower nibble outbut
174         odatlow  = (data << 2) & 0x28;   // outD3 => PortD5 => DisplayD7  //outD1 => PortD3 => DisplayD5
175         odatlow |= (data << 4) & 0x50;   // outD2 => PortD6 => DisplayD6  //outD0 => PortD4 => DisplayD4
176         
177         //outbut higher nibble
178         _outp(DISP_O, (command & DISPCON_RS) | odathigh);                                           // set the RS if needed
179         _outp(DISP_O,((command & DISPCON_RS) | DISPCON_E | odathigh));  // set E
180         _outp(DISP_O,((command & DISPCON_RS) | odathigh));                              // reset E
181
182
183         if ((command & INI) == 0) 
184   {                                                     
185     // if it's not the init command, do second nibble
186                 //wait_us(DISP_CTR_TIME * 21);
187                 //outbut lower nibble
188                 _outp(DISP_O,((command & DISPCON_RS) | odatlow));                         // set E
189                 _outp(DISP_O,((command & DISPCON_RS) | DISPCON_E | odatlow));   // set Data
190                 _outp(DISP_O,((command & DISPCON_RS) | odatlow));                         // reset E
191                 if ((data & 0xFC) == 0) 
192     {                                                                     
193       // if command was a Clear Display
194       // or Cursor Home, wait at least 1.5 ms more
195                         m_iActualpos = 0;
196                         Sleep(2);                                                                                          
197                 }
198                 if ((command & DISPCON_RS) == 0x02) m_iActualpos++;
199         }
200         else 
201   {                                                                             
202                 m_iActualpos = 0;
203     
204                 //wait_us(2500);                // wait 2.5 msec        
205         }
206         usleep(50);
207  }
208
209 //************************************************************************************************************************
210 //DisplayBuildCustomChars: load customized characters to character ram of display, resets cursor to pos 0
211 //************************************************************************************************************************
212 void CSmartXXLCD::DisplayBuildCustomChars() 
213 {
214         int I;
215         
216         static char Bar0[] ={0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10};
217         static char Bar1[] ={0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18};
218         static char Bar2[] ={0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c};
219         static char Bar3[] ={0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e};   //4pixel
220         static char REW[8][8]=
221         {
222                 {0x00, 0x05, 0x0a, 0x14, 0x0a, 0x05, 0x00, 0x00},
223                 {0x00, 0x0a, 0x14, 0x08, 0x14, 0x0a, 0x00, 0x00},
224                 {0x00, 0x14, 0x08, 0x10, 0x08, 0x14, 0x00, 0x00},
225                 {0x00, 0x08, 0x10, 0x00, 0x10, 0x08, 0x00, 0x00},
226                 {0x00, 0x10, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00},
227                 {0x00, 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00},
228                 {0x00, 0x01, 0x02, 0x05, 0x02, 0x01, 0x00, 0x00},
229                 {0x00, 0x02, 0x05, 0x0a, 0x05, 0x02, 0x00, 0x00}
230
231         };
232         static char FF[8][8]=
233         {
234                 {0x00, 0x14, 0x0a, 0x05, 0x0a, 0x14, 0x00, 0x00},
235                 {0x00, 0x0a, 0x05, 0x02, 0x05, 0x0a, 0x00, 0x00},
236                 {0x00, 0x05, 0x02, 0x01, 0x02, 0x05, 0x00, 0x00},
237                 {0x00, 0x02, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00},
238                 {0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00},
239                 {0x00, 0x00, 0x10, 0x08, 0x10, 0x00, 0x00, 0x00},
240                 {0x00, 0x10, 0x08, 0x14, 0x08, 0x10, 0x00, 0x00},
241                 {0x00, 0x08, 0x14, 0x0a, 0x14, 0x08, 0x00, 0x00}
242         };
243         static char Play[] ={0x00, 0x04, 0x06, 0x07, 0x07, 0x06, 0x04, 0x00};
244         static char Stop[] ={0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00};
245         static char Pause[]={0x00, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00};
246         
247         DisplayOut(DISP_CGRAM_SET, CMD);
248          for(I=0;I<8;I++) DisplayOut(Bar0[I], DAT);  // Bar0
249          for(I=0;I<8;I++) DisplayOut(Bar1[I], DAT);  // Bar1
250          for(I=0;I<8;I++) DisplayOut(Bar2[I], DAT);  // Bar2
251          for(I=0;I<8;I++) DisplayOut(REW[AnimIndex][I], DAT);   // REW
252          for(I=0;I<8;I++) DisplayOut(FF[AnimIndex][I], DAT);    // FF
253          for(I=0;I<8;I++) DisplayOut(Play[I], DAT);  // Play
254          //for(I=0;I<8;I++) DisplayOut(Stop[I], DAT);                   // Stop
255          for(I=0;I<8;I++) DisplayOut(Bar3[I], DAT);
256          for(I=0;I<8;I++) DisplayOut(Pause[I], DAT); // Pause
257         DisplayOut(DISP_DDRAM_SET, CMD);
258     AnimIndex=(AnimIndex+1) & 0x7;
259 }
260
261
262 //************************************************************************************************************************
263 // DisplaySetPos: sets cursor position
264 // Input: (row position, line number from 0 to 3)
265 //************************************************************************************************************************
266 void CSmartXXLCD::DisplaySetPos(unsigned char pos, unsigned char line) 
267 {
268         
269         unsigned int cursorpointer;
270         
271         cursorpointer = pos % m_iColumns;
272
273         if (line == 0) {
274                 cursorpointer += m_iRow1adr;
275         }
276         if (line == 1) {
277                 cursorpointer += m_iRow2adr;
278         }
279         if (line == 2) {
280                 cursorpointer += m_iRow3adr;
281         }
282         if (line == 3) {
283                 cursorpointer += m_iRow4adr;
284         }
285         DisplayOut(DISP_DDRAM_SET | cursorpointer, CMD);
286         m_iActualpos = cursorpointer;
287 }
288
289 //************************************************************************************************************************
290 // DisplayWriteFixText: write a fixed text to actual cursor position
291 // Input: ("fixed text like")
292 //************************************************************************************************************************
293 void CSmartXXLCD::DisplayWriteFixtext(const char *textstring)
294 {
295         unsigned char  c;
296         while (c = *textstring++) {
297                 DisplayOut(c,DAT);
298         }
299 }
300
301
302 //************************************************************************************************************************
303 // DisplayWriteString: write a string to acutal cursor position 
304 // Input: (pointer to a 0x00 terminated string)
305 //************************************************************************************************************************
306
307 void CSmartXXLCD::DisplayWriteString(char *pointer) 
308 {
309         /* display a normal 0x00 terminated string on the LCD display */
310         unsigned char c;
311         do {
312                 c = *pointer;
313                 if (c == 0x00) 
314                         break;
315     
316                 DisplayOut(c, DAT);
317                 *pointer++;
318         } while(1);
319  
320 }               
321
322
323 //************************************************************************************************************************
324 // DisplayClearChars:  clears a number of chars in a line and resets cursor position to it's startposition
325 // Input: (Startposition of clear in row, row number, number of chars to clear)
326 //************************************************************************************************************************
327 void CSmartXXLCD::DisplayClearChars(unsigned char startpos , unsigned char line, unsigned char lenght) 
328 {
329         int i;
330         
331         DisplaySetPos(startpos,line);
332         for (i=0;i<lenght; i++){
333                 DisplayOut(0x20,DAT);
334         }
335         DisplaySetPos(startpos,line);
336   
337 }
338
339
340 //************************************************************************************************************************
341 // DisplayProgressBar: shows a grafic bar staring at actual cursor position
342 // Input: (percent of bar to display, lenght of whole bar in chars when 100 %)
343 //************************************************************************************************************************
344 void CSmartXXLCD::DisplayProgressBar(unsigned char percent, unsigned char charcnt) 
345 {
346                 
347         unsigned int barcnt100;
348         
349         barcnt100 = charcnt * 5 * percent / 100;
350
351         int i;  
352         for (i=1; i<=charcnt; i++) {
353                 if (i<=(int)(barcnt100 / 5)){
354                         DisplayOut(4,DAT);
355                 }
356                 else 
357                 {
358                         if ( (i == (barcnt100 /5)+1) && (barcnt100 % 5 != 0) ){
359                                 DisplayOut((barcnt100 % 5)-1,DAT);
360                         }
361                         else{
362                                 DisplayOut(0x20,DAT);
363                         }
364                 }
365         }
366 }
367 //************************************************************************************************************************
368 //Set brightness level 
369 //************************************************************************************************************************
370 void CSmartXXLCD::DisplaySetBacklight(unsigned char level) 
371 {
372   if (g_guiSettings.GetInt("lcd.type")==LCD_TYPE_VFD)
373   {
374     //VFD:(value 0 to 3 = 100%, 75%, 50%, 25%)
375     if (level<0) level=0;
376     if (level>99) level=99;
377           level = (99-level);
378     level/=25;
379           DisplayOut(DISP_FUNCTION_SET | DISP_N_FLAG | level,CMD);
380   }
381   else //if (g_guiSettings.GetInt("lcd.type")==LCD_TYPE_LCD_HD44780)
382   {
383     if (g_sysinfo.SmartXXModCHIP().Equals("SmartXX V3"))
384     {
385       float fBackLight=((float)level)/100.0f;
386       fBackLight*=127.0f;
387       int iNewLevel=(int)fBackLight;
388       if (iNewLevel==63) iNewLevel=64;
389       _outp(DISP_O_LIGHT, iNewLevel&127);
390     }
391     else if (g_sysinfo.SmartXXModCHIP().Equals("SmartXX OPX"))
392     {
393       float fBackLight=((float)level)/100.0f;
394       fBackLight*=127.0f;
395       int iNewLevel=(int)fBackLight;
396       if (iNewLevel==63) iNewLevel=64;
397       _outp(DISP_O_LIGHT, iNewLevel&127);
398     }
399     else
400     {
401       float fBackLight=((float)level)/100.0f;
402       fBackLight*=63.0f;
403       int iNewLevel=(int)fBackLight;
404       if (iNewLevel==31) iNewLevel=32;
405       _outp(DISP_O_LIGHT, iNewLevel&63);
406     }
407   }
408 }
409 //************************************************************************************************************************
410 //Set brightness level 
411 //************************************************************************************************************************
412 void CSmartXXLCD::DisplaySetContrast(unsigned char level) 
413 {
414   // can't do this with a VFD
415   if (g_guiSettings.GetInt("lcd.type")==LCD_TYPE_VFD) 
416     return;
417
418   float fBackLight;
419   if (level<0) level=0;
420   if (level>99) level=99;
421   
422   if (g_sysinfo.SmartXXModCHIP().Equals("SmartXX V3"))
423   {   
424     level = (99-level);
425     fBackLight=((float)level/100)*42.0f;
426     int iNewLevel=(int)fBackLight;
427     if (iNewLevel>=41) iNewLevel=42;
428     _outp(DISP_O_LIGHT, iNewLevel&127|128); //V3 use DISP_O_LIGHT Port for Contrast
429         }
430   else if ( g_sysinfo.SmartXXModCHIP().Equals("SmartXX OPX"))
431   {
432     level = (99-level);
433     fBackLight=((float)level/100)*42.0f;
434     int iNewLevel=(int)fBackLight;
435     if (iNewLevel>=41) iNewLevel=42;
436     _outp(DISP_O_CONTRAST, iNewLevel&127|128);
437   }
438   else 
439   {
440     fBackLight=(((float)level)/100.0f)*63.0f;
441     int iNewLevel=(int)fBackLight;
442     if (iNewLevel>=31) iNewLevel=32;
443     _outp(DISP_O_CONTRAST, iNewLevel&63);
444   }
445 }
446
447 //************************************************************************************************************************
448 void CSmartXXLCD::DisplayInit()
449 {
450         _outp(DISP_O,0);
451         DisplayOut(DISP_FUNCTION_SET | DISP_DL_FLAG, INI);                    // 8-Bit Datalenght if display is already initialized to 4 bit
452         Sleep(5);
453   DisplayOut(DISP_FUNCTION_SET | DISP_DL_FLAG, INI);                  // 8-Bit Datalenght if display is already initialized to 4 bit
454         Sleep(5);
455   DisplayOut(DISP_FUNCTION_SET | DISP_DL_FLAG, INI);                  // 8-Bit Datalenght if display is already initialized to 4 bit
456         Sleep(5);
457         DisplayOut(DISP_FUNCTION_SET,INI);                                                // 4-Bit Datalenght
458         Sleep(5);
459         DisplayOut(DISP_FUNCTION_SET | DISP_N_FLAG | DISP_RE_FLAG ,CMD);        // 4-Bit Datalenght, 2 Lines, Font 5x7, and set RE Flag
460         Sleep(5);
461         DisplayOut(DISP_SEGRAM_SET, CMD);                                                   // set SEGRAM to 0x00 (RE = 1)
462         Sleep(5);
463         DisplayOut(DISP_EXT_CONTROL | DISP_NW_FLAG ,CMD);                       // set Display to 2 lines (RE = 1)
464         Sleep(5);
465         DisplayOut(DISP_FUNCTION_SET | DISP_N_FLAG ,CMD);                       // 4-Bit Datalenght, 2 Lines, Font 5x7, clear RE Flag
466         Sleep(5);
467         DisplayOut(DISP_CONTROL | DISP_D_FLAG ,CMD);                              // Display on
468         Sleep(5);
469         DisplayOut(DISP_CLEAR,CMD);                                                             // Display clear
470         Sleep(5);
471         DisplayOut(DISP_ENTRY_MODE_SET | DISP_ID_FLAG,CMD);                   // Cursor autoincrement
472         Sleep(5);
473
474   DisplayBuildCustomChars();                            
475   DisplaySetPos(0,0);
476 }
477
478 //************************************************************************************************************************
479 void CSmartXXLCD::Process()
480 {
481   int iOldLight=-1;
482   int iOldContrast=-1;
483
484   
485   m_iColumns = g_advancedSettings.m_lcdColumns;
486   m_iRows    = g_advancedSettings.m_lcdRows;
487   m_iRow1adr = g_advancedSettings.m_lcdAddress1;
488   m_iRow2adr = g_advancedSettings.m_lcdAddress2;
489   m_iRow3adr = g_advancedSettings.m_lcdAddress3;
490   m_iRow4adr = g_advancedSettings.m_lcdAddress4;
491   m_iBackLight= g_guiSettings.GetInt("lcd.backlight");
492   m_iContrast = g_guiSettings.GetInt("lcd.contrast");
493   if (m_iRows >= MAX_ROWS) m_iRows=MAX_ROWS-1;
494
495   DisplayInit();
496   while (!m_bStop)
497   {
498     Sleep(SCROLL_SPEED_IN_MSEC);  
499     if (m_iBackLight != iOldLight)
500     {
501       // backlight setting changed
502       iOldLight=m_iBackLight;
503       DisplaySetBacklight(m_iBackLight);
504     }
505     if (m_iContrast != iOldContrast)
506     {
507       // contrast setting changed
508       iOldContrast=m_iContrast;
509       DisplaySetContrast(m_iContrast);
510     }
511           DisplayBuildCustomChars();
512           for (int iLine=0; iLine < (int)m_iRows; ++iLine)
513     {
514             if (m_bUpdate[iLine])
515                         {
516         CStdString strTmp=m_strLine[iLine];
517         if (strTmp.size() > m_iColumns)
518         {
519           strTmp=m_strLine[iLine].Left(m_iColumns);
520         }
521         m_iPos[iLine]=0;
522         DisplaySetPos(0,iLine);
523         DisplayWriteFixtext(strTmp.c_str());
524         m_bUpdate[iLine]=false;
525         m_dwSleep[iLine]=GetTickCount();
526       }
527       else if ( (GetTickCount()-m_dwSleep[iLine]) > 1000)
528       {
529         int iSize=m_strLine[iLine].size();
530         if (iSize > (int)m_iColumns)
531         {
532           //scroll line
533           CStdString strRow=m_strLine[iLine]+"   -   ";
534           int iSize=strRow.size();
535           m_iPos[iLine]++;
536           if (m_iPos[iLine]>=iSize) m_iPos[iLine]=0;
537           int iPos=m_iPos[iLine];
538           CStdString strLine="";
539           for (int iCol=0; iCol < (int)m_iColumns;++iCol)
540           {
541             strLine +=strRow.GetAt(iPos);
542             iPos++;
543             if (iPos >= iSize) iPos=0;
544           }
545           DisplaySetPos(0,iLine);
546           DisplayWriteFixtext(strLine.c_str());
547         }
548       }
549     }
550   }
551   for (int i=0; i < (int)m_iRows; i++)
552   {
553           DisplayClearChars(0,i,m_iColumns);
554   } 
555   DisplayOut(DISP_CONTROL ,CMD);                                  // Display off
556 }