summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-h100.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-h100.c')
-rw-r--r--firmware/drivers/lcd-h100.c387
1 files changed, 240 insertions, 147 deletions
diff --git a/firmware/drivers/lcd-h100.c b/firmware/drivers/lcd-h100.c
index af3782c0b3..2b0326eb3b 100644
--- a/firmware/drivers/lcd-h100.c
+++ b/firmware/drivers/lcd-h100.c
@@ -66,21 +66,10 @@ unsigned char lcd_framebuffer[LCD_HEIGHT/8][LCD_WIDTH]
66#endif 66#endif
67 ; 67 ;
68 68
69static int drawmode = DRMODE_SOLID;
69static int xmargin = 0; 70static int xmargin = 0;
70static int ymargin = 0; 71static int ymargin = 0;
71static int curfont = FONT_SYSFIXED; 72static int curfont = FONT_SYSFIXED;
72#ifndef SIMULATOR
73static int xoffset = 0; /* needed for flip */
74#endif
75
76/* All zeros and ones bitmaps for area filling */
77static const unsigned char zeros[16] = {
78 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
79};
80static const unsigned char ones[16] = {
81 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
82 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
83};
84 73
85/* scrolling */ 74/* scrolling */
86static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */ 75static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */
@@ -128,14 +117,12 @@ void lcd_set_flip(bool yesno)
128 lcd_write_command(LCD_CNTL_COLUMN_ADDRESS_DIR | 1); 117 lcd_write_command(LCD_CNTL_COLUMN_ADDRESS_DIR | 1);
129 lcd_write_command(LCD_CNTL_COMMON_OUTPUT_STATUS | 0); 118 lcd_write_command(LCD_CNTL_COMMON_OUTPUT_STATUS | 0);
130 lcd_write_command_ex(LCD_CNTL_DUTY_SET, 0x20, 0); 119 lcd_write_command_ex(LCD_CNTL_DUTY_SET, 0x20, 0);
131 xoffset = 160 - LCD_WIDTH; /* 160 colums minus the 160 we have */
132 } 120 }
133 else 121 else
134 { 122 {
135 lcd_write_command(LCD_CNTL_COLUMN_ADDRESS_DIR | 0); 123 lcd_write_command(LCD_CNTL_COLUMN_ADDRESS_DIR | 0);
136 lcd_write_command(LCD_CNTL_COMMON_OUTPUT_STATUS | 1); 124 lcd_write_command(LCD_CNTL_COMMON_OUTPUT_STATUS | 1);
137 lcd_write_command_ex(LCD_CNTL_DUTY_SET, 0x20, 1); 125 lcd_write_command_ex(LCD_CNTL_DUTY_SET, 0x20, 1);
138 xoffset = 0;
139 } 126 }
140} 127}
141 128
@@ -227,7 +214,7 @@ void lcd_blit(const unsigned char* p_data, int x, int y, int width,
227 while (height--) 214 while (height--)
228 { 215 {
229 lcd_write_command_ex(LCD_CNTL_PAGE, y++ & 0xf, -1); 216 lcd_write_command_ex(LCD_CNTL_PAGE, y++ & 0xf, -1);
230 lcd_write_command_ex(LCD_CNTL_COLUMN, x+xoffset, -1); 217 lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1);
231 218
232 lcd_write_command(LCD_CNTL_DATA_WRITE); 219 lcd_write_command(LCD_CNTL_DATA_WRITE);
233 lcd_write_data(p_data, width); 220 lcd_write_data(p_data, width);
@@ -275,7 +262,7 @@ void lcd_update_rect(int x_start, int y, int width, int height)
275 for (; y <= ymax; y++) 262 for (; y <= ymax; y++)
276 { 263 {
277 lcd_write_command_ex(LCD_CNTL_PAGE, y, -1); 264 lcd_write_command_ex(LCD_CNTL_PAGE, y, -1);
278 lcd_write_command_ex(LCD_CNTL_COLUMN, x_start+xoffset, -1); 265 lcd_write_command_ex(LCD_CNTL_COLUMN, x_start, -1);
279 266
280 lcd_write_command(LCD_CNTL_DATA_WRITE); 267 lcd_write_command(LCD_CNTL_DATA_WRITE);
281 lcd_write_data (&lcd_framebuffer[y][x_start], width); 268 lcd_write_data (&lcd_framebuffer[y][x_start], width);
@@ -285,6 +272,16 @@ void lcd_update_rect(int x_start, int y, int width, int height)
285 272
286/*** parameter handling ***/ 273/*** parameter handling ***/
287 274
275void lcd_set_drawmode(int mode)
276{
277 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
278}
279
280int lcd_get_drawmode(void)
281{
282 return drawmode;
283}
284
288void lcd_setmargins(int x, int y) 285void lcd_setmargins(int x, int y)
289{ 286{
290 xmargin = x; 287 xmargin = x;
@@ -311,103 +308,75 @@ int lcd_getstringsize(const unsigned char *str, int *w, int *h)
311 return font_getstringsize(str, w, h, curfont); 308 return font_getstringsize(str, w, h, curfont);
312} 309}
313 310
314/*** drawing functions ***/ 311/*** low-level drawing functions ***/
315 312
316void lcd_clear_display(void) 313static void setpixel(int x, int y)
317{ 314{
318 memset (lcd_framebuffer, 0, sizeof lcd_framebuffer); 315 lcd_framebuffer[y/8][x] |= 1 << (y & 7);
319 scrolling_lines = 0;
320} 316}
321 317
322/* Set a single pixel */ 318static void clearpixel(int x, int y)
323void lcd_drawpixel(int x, int y)
324{ 319{
325 DRAW_PIXEL(x,y); 320 lcd_framebuffer[y/8][x] &= ~(1 << (y & 7));
326} 321}
327 322
328/* Clear a single pixel */ 323static void flippixel(int x, int y)
329void lcd_clearpixel(int x, int y)
330{ 324{
331 CLEAR_PIXEL(x,y); 325 lcd_framebuffer[y/8][x] ^= 1 << (y & 7);
332} 326}
333 327
334/* Invert a single pixel */ 328static void nopixel(int x, int y)
335void lcd_invertpixel(int x, int y)
336{ 329{
337 INVERT_PIXEL(x,y); 330 (void)x;
331 (void)y;
338} 332}
339 333
340void lcd_drawline(int x1, int y1, int x2, int y2) 334tLCDPixelFunc* pixelfunc[8] = {flippixel, nopixel, setpixel, setpixel,
335 nopixel, clearpixel, nopixel, clearpixel};
336
337static void flipblock(unsigned char *address, unsigned mask, unsigned bits)
341{ 338{
342 int numpixels; 339 *address ^= (bits & mask);
343 int i; 340}
344 int deltax, deltay;
345 int d, dinc1, dinc2;
346 int x, xinc1, xinc2;
347 int y, yinc1, yinc2;
348 341
349 deltax = abs(x2 - x1); 342static void bgblock(unsigned char *address, unsigned mask, unsigned bits)
350 deltay = abs(y2 - y1); 343{
344 *address &= (bits | ~mask);
345}
351 346
352 if(deltax >= deltay) 347static void fgblock(unsigned char *address, unsigned mask, unsigned bits)
353 { 348{
354 numpixels = deltax; 349 *address |= (bits & mask);
355 d = 2 * deltay - deltax; 350}
356 dinc1 = deltay * 2;
357 dinc2 = (deltay - deltax) * 2;
358 xinc1 = 1;
359 xinc2 = 1;
360 yinc1 = 0;
361 yinc2 = 1;
362 }
363 else
364 {
365 numpixels = deltay;
366 d = 2 * deltax - deltay;
367 dinc1 = deltax * 2;
368 dinc2 = (deltax - deltay) * 2;
369 xinc1 = 0;
370 xinc2 = 1;
371 yinc1 = 1;
372 yinc2 = 1;
373 }
374 numpixels++; /* include endpoints */
375 351
376 if(x1 > x2) 352static void solidblock(unsigned char *address, unsigned mask, unsigned bits)
377 { 353{
378 xinc1 = -xinc1; 354 *address = (*address & ~mask) | (bits & mask);
379 xinc2 = -xinc2; 355}
380 }
381 356
382 if(y1 > y2) 357tLCDBlockFunc* blockfunc[4] = {flipblock, bgblock, fgblock, solidblock};
383 {
384 yinc1 = -yinc1;
385 yinc2 = -yinc2;
386 }
387 358
388 x = x1; 359/*** drawing functions ***/
389 y = y1;
390 360
391 for(i=0; i<numpixels; i++) 361/* Clear the whole display */
392 { 362void lcd_clear_display(void)
393 DRAW_PIXEL(x,y); 363{
364 if (drawmode & DRMODE_INVERSEVID)
365 memset (lcd_framebuffer, 0xFF, sizeof lcd_framebuffer);
366 else
367 memset (lcd_framebuffer, 0, sizeof lcd_framebuffer);
368 scrolling_lines = 0;
369}
394 370
395 if(d < 0) 371/* Set a single pixel */
396 { 372void lcd_drawpixel(int x, int y)
397 d += dinc1; 373{
398 x += xinc1; 374 if (((unsigned)x < LCD_WIDTH) || ((unsigned)y < LCD_HEIGHT))
399 y += yinc1; 375 pixelfunc[drawmode](x, y);
400 }
401 else
402 {
403 d += dinc2;
404 x += xinc2;
405 y += yinc2;
406 }
407 }
408} 376}
409 377
410void lcd_clearline(int x1, int y1, int x2, int y2) 378/* Draw a line */
379void lcd_drawline(int x1, int y1, int x2, int y2)
411{ 380{
412 int numpixels; 381 int numpixels;
413 int i; 382 int i;
@@ -415,20 +384,21 @@ void lcd_clearline(int x1, int y1, int x2, int y2)
415 int d, dinc1, dinc2; 384 int d, dinc1, dinc2;
416 int x, xinc1, xinc2; 385 int x, xinc1, xinc2;
417 int y, yinc1, yinc2; 386 int y, yinc1, yinc2;
387 tLCDPixelFunc *pfunc = pixelfunc[drawmode];
418 388
419 deltax = abs(x2 - x1); 389 deltax = abs(x2 - x1);
420 deltay = abs(y2 - y1); 390 deltay = abs(y2 - y1);
391 xinc2 = 1;
392 yinc2 = 1;
421 393
422 if(deltax >= deltay) 394 if (deltax >= deltay)
423 { 395 {
424 numpixels = deltax; 396 numpixels = deltax;
425 d = 2 * deltay - deltax; 397 d = 2 * deltay - deltax;
426 dinc1 = deltay * 2; 398 dinc1 = deltay * 2;
427 dinc2 = (deltay - deltax) * 2; 399 dinc2 = (deltay - deltax) * 2;
428 xinc1 = 1; 400 xinc1 = 1;
429 xinc2 = 1;
430 yinc1 = 0; 401 yinc1 = 0;
431 yinc2 = 1;
432 } 402 }
433 else 403 else
434 { 404 {
@@ -437,19 +407,17 @@ void lcd_clearline(int x1, int y1, int x2, int y2)
437 dinc1 = deltax * 2; 407 dinc1 = deltax * 2;
438 dinc2 = (deltax - deltay) * 2; 408 dinc2 = (deltax - deltay) * 2;
439 xinc1 = 0; 409 xinc1 = 0;
440 xinc2 = 1;
441 yinc1 = 1; 410 yinc1 = 1;
442 yinc2 = 1;
443 } 411 }
444 numpixels++; /* include endpoints */ 412 numpixels++; /* include endpoints */
445 413
446 if(x1 > x2) 414 if (x1 > x2)
447 { 415 {
448 xinc1 = -xinc1; 416 xinc1 = -xinc1;
449 xinc2 = -xinc2; 417 xinc2 = -xinc2;
450 } 418 }
451 419
452 if(y1 > y2) 420 if (y1 > y2)
453 { 421 {
454 yinc1 = -yinc1; 422 yinc1 = -yinc1;
455 yinc2 = -yinc2; 423 yinc2 = -yinc2;
@@ -458,11 +426,12 @@ void lcd_clearline(int x1, int y1, int x2, int y2)
458 x = x1; 426 x = x1;
459 y = y1; 427 y = y1;
460 428
461 for(i=0; i<numpixels; i++) 429 for (i = 0; i < numpixels; i++)
462 { 430 {
463 CLEAR_PIXEL(x,y); 431 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
432 pfunc(x, y);
464 433
465 if(d < 0) 434 if (d < 0)
466 { 435 {
467 d += dinc1; 436 d += dinc1;
468 x += xinc1; 437 x += xinc1;
@@ -477,68 +446,178 @@ void lcd_clearline(int x1, int y1, int x2, int y2)
477 } 446 }
478} 447}
479 448
480/* Draw a rectangle with upper left corner at (x, y) and size (nx, ny) */ 449/* Draw a horizontal line (optimised) */
481void lcd_drawrect(int x, int y, int nx, int ny) 450void lcd_hline(int x1, int x2, int y)
482{ 451{
483 int i; 452 int x;
453 unsigned char *dst;
454 unsigned char mask, bits;
455 tLCDBlockFunc *bfunc;
484 456
485 if (x > LCD_WIDTH) 457 /* direction flip */
486 return; 458 if (x2 < x1)
487 if (y > LCD_HEIGHT) 459 {
488 return; 460 x = x1;
461 x1 = x2;
462 x2 = x;
463 }
464
465 /* nothing to draw? */
466 if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0))
467 return;
468
469 /* clipping */
470 if (x1 < 0)
471 x1 = 0;
472 if (x2 >= LCD_WIDTH)
473 x2 = LCD_WIDTH-1;
474
475 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID];
476 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu;
477 dst = &lcd_framebuffer[y/8][x1];
478 mask = 1 << (y & 7);
489 479
490 if (x + nx > LCD_WIDTH) 480 for (x = x1; x <= x2; x++)
491 nx = LCD_WIDTH - x; 481 bfunc(dst++, mask, bits);
492 if (y + ny > LCD_HEIGHT) 482}
493 ny = LCD_HEIGHT - y;
494 483
495 /* vertical lines */ 484/* Draw a vertical line (optimised) */
496 for (i = 0; i < ny; i++) { 485void lcd_vline(int x, int y1, int y2)
497 DRAW_PIXEL(x, (y + i)); 486{
498 DRAW_PIXEL((x + nx - 1), (y + i)); 487 int ny;
488 unsigned char *dst;
489 unsigned char mask_top, mask_bottom, bits;
490 tLCDBlockFunc *bfunc;
491
492 /* direction flip */
493 if (y2 < y1)
494 {
495 ny = y1;
496 y1 = y2;
497 y2 = ny;
499 } 498 }
500 499
501 /* horizontal lines */ 500 /* nothing to draw? */
502 for (i = 0; i < nx; i++) { 501 if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0))
503 DRAW_PIXEL((x + i),y); 502 return;
504 DRAW_PIXEL((x + i),(y + ny - 1)); 503
504 /* clipping */
505 if (y1 < 0)
506 y1 = 0;
507 if (y2 >= LCD_HEIGHT)
508 y2 = LCD_HEIGHT-1;
509
510 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID];
511 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu;
512 dst = &lcd_framebuffer[y1/8][x];
513 ny = y2 - (y1 & ~7);
514 mask_top = 0xFFu << (y1 & 7);
515 mask_bottom = 0xFFu >> (7 - (ny & 7));
516
517 if (ny >= 8)
518 {
519 bfunc(dst, mask_top, bits);
520 dst += LCD_WIDTH;
521
522 for (; ny > 15; ny -= 8)
523 {
524 bfunc(dst, 0xFFu, bits);
525 dst += LCD_WIDTH;
526 }
505 } 527 }
528 else
529 mask_bottom &= mask_top;
530
531 bfunc(dst, mask_bottom, bits);
506} 532}
507 533
508/* Clear a rectangular area at (x, y), size (nx, ny) */ 534/* Draw a rectangular box */
509void lcd_clearrect(int x, int y, int nx, int ny) 535void lcd_drawrect(int x, int y, int width, int height)
510{ 536{
511 int i; 537 if ((width <= 0) || (height <= 0))
512 for (i = 0; i < nx; i++) 538 return;
513 lcd_bitmap (zeros, x+i, y, 1, ny, true); 539
540 int x2 = x + width - 1;
541 int y2 = y + height - 1;
542
543 lcd_vline(x, y, y2);
544 lcd_vline(x2, y, y2);
545 lcd_hline(x, x2, y);
546 lcd_hline(x, x2, y2);
514} 547}
515 548
516/* Fill a rectangular area at (x, y), size (nx, ny) */ 549/* helper function for lcd_fillrect() */
517void lcd_fillrect(int x, int y, int nx, int ny) 550static void fillrow(tLCDBlockFunc *bfunc, unsigned char *address,
551 int width, unsigned mask, unsigned bits)
518{ 552{
519 int i; 553 int i;
520 for (i = 0; i < nx; i++) 554
521 lcd_bitmap (ones, x+i, y, 1, ny, true); 555 for (i = 0; i < width; i++)
556 bfunc(address++, mask, bits);
522} 557}
523 558
524/* Invert a rectangular area at (x, y), size (nx, ny) */ 559/* Fill a rectangular area */
525void lcd_invertrect(int x, int y, int nx, int ny) 560void lcd_fillrect(int x, int y, int width, int height)
526{ 561{
527 int i, j; 562 int ny;
563 unsigned char *dst;
564 unsigned char mask_top, mask_bottom, bits;
565 tLCDBlockFunc *bfunc;
566 bool fillopt = (drawmode & DRMODE_INVERSEVID) ?
567 (drawmode & DRMODE_BG) : (drawmode & DRMODE_FG);
528 568
529 if (x > LCD_WIDTH) 569 /* nothing to draw? */
570 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
571 || (x + width < 0) || (y + height < 0))
530 return; 572 return;
531 if (y > LCD_HEIGHT)
532 return;
533
534 if (x + nx > LCD_WIDTH)
535 nx = LCD_WIDTH - x;
536 if (y + ny > LCD_HEIGHT)
537 ny = LCD_HEIGHT - y;
538 573
539 for (i = 0; i < nx; i++) 574 /* clipping */
540 for (j = 0; j < ny; j++) 575 if (x < 0)
541 INVERT_PIXEL((x + i), (y + j)); 576 {
577 width += x;
578 x = 0;
579 }
580 if (y < 0)
581 {
582 height += y;
583 y = 0;
584 }
585 if (x + width > LCD_WIDTH)
586 width = LCD_WIDTH - x;
587 if (y + height > LCD_HEIGHT)
588 height = LCD_HEIGHT - y;
589
590 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID];
591 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu;
592 dst = &lcd_framebuffer[y/8][x];
593 ny = height - 1 + (y & 7);
594 mask_top = 0xFFu << (y & 7);
595 mask_bottom = 0xFFu >> (7 - (ny & 7));
596
597 if (ny >= 8)
598 {
599 if (fillopt && mask_top == 0xFF)
600 memset(dst, bits, width);
601 else
602 fillrow(bfunc, dst, width, mask_top, bits);
603 dst += LCD_WIDTH;
604
605 for (; ny > 15; ny -= 8)
606 {
607 if (fillopt)
608 memset(dst, bits, width);
609 else
610 fillrow(bfunc, dst, width, 0xFFu, bits);
611 dst += LCD_WIDTH;
612 }
613 }
614 else
615 mask_bottom &= mask_top;
616
617 if (fillopt && mask_bottom == 0xFF)
618 memset(dst, bits, width);
619 else
620 fillrow(bfunc, dst, width, mask_bottom, bits);
542} 621}
543 622
544/* About Rockbox' internal bitmap format: 623/* About Rockbox' internal bitmap format:
@@ -706,6 +785,7 @@ void lcd_putsxy(int x, int y, const unsigned char *str)
706void lcd_puts_style(int x, int y, const unsigned char *str, int style) 785void lcd_puts_style(int x, int y, const unsigned char *str, int style)
707{ 786{
708 int xpos,ypos,w,h; 787 int xpos,ypos,w,h;
788 int lastmode = lcd_get_drawmode();
709 789
710 /* make sure scrolling is turned off on the line we are updating */ 790 /* make sure scrolling is turned off on the line we are updating */
711 scrolling_lines &= ~(1 << y); 791 scrolling_lines &= ~(1 << y);
@@ -717,9 +797,14 @@ void lcd_puts_style(int x, int y, const unsigned char *str, int style)
717 xpos = xmargin + x*w / strlen(str); 797 xpos = xmargin + x*w / strlen(str);
718 ypos = ymargin + y*h; 798 ypos = ymargin + y*h;
719 lcd_putsxy(xpos, ypos, str); 799 lcd_putsxy(xpos, ypos, str);
720 lcd_clearrect(xpos + w, ypos, LCD_WIDTH - (xpos + w), h); 800 lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
801 lcd_fillrect(xpos + w, ypos, LCD_WIDTH - (xpos + w), h);
721 if (style & STYLE_INVERT) 802 if (style & STYLE_INVERT)
722 lcd_invertrect(xpos, ypos, LCD_WIDTH - xpos, h); 803 {
804 lcd_set_drawmode(DRMODE_COMPLEMENT);
805 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, h);
806 }
807 lcd_set_drawmode(lastmode);
723} 808}
724 809
725/* put a string at a given char position */ 810/* put a string at a given char position */
@@ -835,6 +920,7 @@ static void scroll_thread(void)
835 struct scrollinfo* s; 920 struct scrollinfo* s;
836 int index; 921 int index;
837 int xpos, ypos; 922 int xpos, ypos;
923 int lastmode;
838 924
839 /* initialize scroll struct array */ 925 /* initialize scroll struct array */
840 scrolling_lines = 0; 926 scrolling_lines = 0;
@@ -880,10 +966,17 @@ static void scroll_thread(void)
880 s->offset %= s->width; 966 s->offset %= s->width;
881 } 967 }
882 968
883 lcd_clearrect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 969 lastmode = lcd_get_drawmode();
970 lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
971 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
972 lcd_set_drawmode(DRMODE_SOLID);
884 lcd_putsxyofs(xpos, ypos, s->offset, s->line); 973 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
885 if (s->invert) 974 if (s->invert)
886 lcd_invertrect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 975 {
976 lcd_set_drawmode(DRMODE_COMPLEMENT);
977 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
978 }
979 lcd_set_drawmode(lastmode);
887 lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 980 lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
888 } 981 }
889 982