📄 lcd-recorder.c
字号:
/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: lcd-recorder.c,v 1.26 2004/01/13 14:59:51 bagder Exp $ * * Copyright (C) 2002 by Alan Korr * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/#include "config.h"#ifdef HAVE_LCD_BITMAP#include "lcd.h"#include "kernel.h"#include "thread.h"#include <string.h>#include <stdlib.h>#include "file.h"#include "debug.h"#include "system.h"#include "font.h"#include "hwcompat.h"/*** definitions ***/#define LCD_SET_LOWER_COLUMN_ADDRESS ((char)0x00)#define LCD_SET_HIGHER_COLUMN_ADDRESS ((char)0x10)#define LCD_SET_INTERNAL_REGULATOR_RESISTOR_RATIO ((char)0x20)#define LCD_SET_POWER_CONTROL_REGISTER ((char)0x28)#define LCD_SET_DISPLAY_START_LINE ((char)0x40)#define LCD_SET_CONTRAST_CONTROL_REGISTER ((char)0x81)#define LCD_SET_SEGMENT_REMAP ((char)0xA0)#define LCD_SET_LCD_BIAS ((char)0xA2)#define LCD_SET_ENTIRE_DISPLAY_OFF ((char)0xA4)#define LCD_SET_ENTIRE_DISPLAY_ON ((char)0xA5)#define LCD_SET_NORMAL_DISPLAY ((char)0xA6)#define LCD_SET_REVERSE_DISPLAY ((char)0xA7)#define LCD_SET_MULTIPLEX_RATIO ((char)0xA8)#define LCD_SET_BIAS_TC_OSC ((char)0xA9)#define LCD_SET_1OVER4_BIAS_RATIO ((char)0xAA)#define LCD_SET_INDICATOR_OFF ((char)0xAC)#define LCD_SET_INDICATOR_ON ((char)0xAD)#define LCD_SET_DISPLAY_OFF ((char)0xAE)#define LCD_SET_DISPLAY_ON ((char)0xAF)#define LCD_SET_PAGE_ADDRESS ((char)0xB0)#define LCD_SET_COM_OUTPUT_SCAN_DIRECTION ((char)0xC0)#define LCD_SET_TOTAL_FRAME_PHASES ((char)0xD2)#define LCD_SET_DISPLAY_OFFSET ((char)0xD3)#define LCD_SET_READ_MODIFY_WRITE_MODE ((char)0xE0)#define LCD_SOFTWARE_RESET ((char)0xE2)#define LCD_NOP ((char)0xE3)#define LCD_SET_END_OF_READ_MODIFY_WRITE_MODE ((char)0xEE)/* LCD command codes */#define LCD_CNTL_RESET 0xe2 /* Software reset */#define LCD_CNTL_POWER 0x2f /* Power control */#define LCD_CNTL_CONTRAST 0x81 /* Contrast */#define LCD_CNTL_OUTSCAN 0xc8 /* Output scan direction */#define LCD_CNTL_SEGREMAP 0xa1 /* Segment remap */#define LCD_CNTL_DISPON 0xaf /* Display on */#define LCD_CNTL_PAGE 0xb0 /* Page address */#define LCD_CNTL_HIGHCOL 0x10 /* Upper column address */#define LCD_CNTL_LOWCOL 0x00 /* Lower column address */#define SCROLL_SPACING 3#define SCROLLABLE_LINES 10struct scrollinfo { char line[MAX_PATH + LCD_WIDTH/2 + SCROLL_SPACING + 2]; int len; /* length of line in chars */ int width; /* length of line in pixels */ int offset; int startx; int starty; bool backward; /* scroll presently forward or backward? */ bool bidir; bool invert; /* invert the scrolled text */ long start_tick;};static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */static void scroll_thread(void);static char scroll_stack[DEFAULT_STACK_SIZE];static char scroll_name[] = "scroll";static char scroll_speed = 8; /* updates per second */static int scroll_delay = HZ/2; /* ticks delay before start */static char scroll_step = 6; /* pixels per scroll step */static int bidir_limit = 50; /* percent */static struct scrollinfo scroll[SCROLLABLE_LINES];static int xmargin = 0;static int ymargin = 0;static int curfont = FONT_SYSFIXED;#ifndef SIMULATORstatic int xoffset = 0; /* needed for flip */#endifunsigned char lcd_framebuffer[LCD_HEIGHT/8][LCD_WIDTH];/* All zeros and ones bitmaps for area filling */static unsigned char zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };static unsigned char ones[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};int lcd_default_contrast(void){#ifdef SIMULATOR return 30;#else return (read_hw_mask() & LCD_CONTRAST_BIAS) ? 31 : 49;#endif}#ifdef SIMULATORvoid lcd_init(void){ create_thread(scroll_thread, scroll_stack, sizeof(scroll_stack), scroll_name);}#else/* * Initialize LCD */void lcd_init (void){ /* Initialize PB0-3 as output pins */ PBCR2 &= 0xff00; /* MD = 00 */ PBIOR |= 0x000f; /* IOR = 1 */ /* inits like the original firmware */ lcd_write(true, LCD_SOFTWARE_RESET); lcd_write(true, LCD_SET_INTERNAL_REGULATOR_RESISTOR_RATIO + 4); lcd_write(true, LCD_SET_1OVER4_BIAS_RATIO + 0); /* force 1/4 bias: 0 */ lcd_write(true, LCD_SET_POWER_CONTROL_REGISTER + 7); /* power control register: op-amp=1, regulator=1, booster=1 */ lcd_write(true, LCD_SET_DISPLAY_ON); lcd_write(true, LCD_SET_NORMAL_DISPLAY); lcd_write(true, LCD_SET_SEGMENT_REMAP + 1); /* mirror horizontal: 1 */ lcd_write(true, LCD_SET_COM_OUTPUT_SCAN_DIRECTION + 8); /* mirror vertical: 1 */ lcd_write(true, LCD_SET_DISPLAY_START_LINE + 0); lcd_set_contrast(lcd_default_contrast()); lcd_write(true, LCD_SET_PAGE_ADDRESS); lcd_write(true, LCD_SET_LOWER_COLUMN_ADDRESS + 0); lcd_write(true, LCD_SET_HIGHER_COLUMN_ADDRESS + 0); lcd_clear_display(); lcd_update(); create_thread(scroll_thread, scroll_stack, sizeof(scroll_stack), scroll_name);}/* Performance function that works with an external buffer note that y and height are in 8-pixel units! */void lcd_blit (unsigned char* p_data, int x, int y, int width, int height, int stride){ /* Copy display bitmap to hardware */ while (height--) { lcd_write (true, LCD_CNTL_PAGE | (y++ & 0xf)); lcd_write (true, LCD_CNTL_HIGHCOL | (((x+xoffset)>>4) & 0xf)); lcd_write (true, LCD_CNTL_LOWCOL | ((x+xoffset) & 0xf)); lcd_write_data(p_data, width); p_data += stride; } }/* * Update the display. * This must be called after all other LCD functions that change the display. */void lcd_update (void) __attribute__ ((section (".icode")));void lcd_update (void){ int y; /* Copy display bitmap to hardware */ for (y = 0; y < LCD_HEIGHT/8; y++) { lcd_write (true, LCD_CNTL_PAGE | (y & 0xf)); lcd_write (true, LCD_CNTL_HIGHCOL | ((xoffset>>4) & 0xf)); lcd_write (true, LCD_CNTL_LOWCOL | (xoffset & 0xf)); lcd_write_data (lcd_framebuffer[y], LCD_WIDTH); }}/* * Update a fraction of the display. */void lcd_update_rect (int, int, int, int) __attribute__ ((section (".icode")));void lcd_update_rect (int x_start, int y, int width, int height){ int ymax; /* The Y coordinates have to work on even 8 pixel rows */ ymax = (y + height-1)/8; y /= 8; if(x_start + width > LCD_WIDTH) width = LCD_WIDTH - x_start; if (width <= 0) return; /* nothing left to do, 0 is harmful to lcd_write_data() */ if(ymax >= LCD_HEIGHT/8) ymax = LCD_HEIGHT/8-1; /* Copy specified rectange bitmap to hardware */ for (; y <= ymax; y++) { lcd_write (true, LCD_CNTL_PAGE | (y & 0xf)); lcd_write (true, LCD_CNTL_HIGHCOL | (((x_start+xoffset)>>4) & 0xf)); lcd_write (true, LCD_CNTL_LOWCOL | ((x_start+xoffset) & 0xf)); lcd_write_data (&lcd_framebuffer[y][x_start], width); }}void lcd_set_contrast(int val){ lcd_write(true, LCD_CNTL_CONTRAST); lcd_write(true, val);}void lcd_set_invert_display(bool yesno){ if (yesno) lcd_write(true, LCD_SET_REVERSE_DISPLAY); else lcd_write(true, LCD_SET_NORMAL_DISPLAY);}/* turn the display upside down (call lcd_update() afterwards) */void lcd_set_flip(bool yesno){ if (yesno) { lcd_write(true, LCD_SET_SEGMENT_REMAP); lcd_write(true, LCD_SET_COM_OUTPUT_SCAN_DIRECTION); xoffset = 132 - LCD_WIDTH; /* 132 colums minus the 112 we have */ } else { lcd_write(true, LCD_SET_SEGMENT_REMAP | 0x01); lcd_write(true, LCD_SET_COM_OUTPUT_SCAN_DIRECTION | 0x08); xoffset = 0; }}/** * Rolls up the lcd display by the specified amount of lines. * Lines that are rolled out over the top of the screen are * rolled in from the bottom again. This is a hardware * remapping only and all operations on the lcd are affected. * -> * @param int lines - The number of lines that are rolled. * The value must be 0 <= pixels < LCD_HEIGHT. */void lcd_roll(int lines){ lcd_write(true, LCD_SET_DISPLAY_START_LINE | (lines & (LCD_HEIGHT-1)));}#endif /* SIMULATOR */void lcd_clear_display (void){ memset (lcd_framebuffer, 0, sizeof lcd_framebuffer); scrolling_lines = 0;}void lcd_setmargins(int x, int y){ xmargin = x; ymargin = y;}int lcd_getxmargin(void){ return xmargin;}int lcd_getymargin(void){ return ymargin;}void lcd_setfont(int newfont){ curfont = newfont;}int lcd_getstringsize(unsigned char *str, int *w, int *h){ struct font* pf = font_get(curfont); int ch; int width = 0; while((ch = *str++)) { /* check input range*/ if (ch < pf->firstchar || ch >= pf->firstchar+pf->size) ch = pf->defaultchar; ch -= pf->firstchar; /* get proportional width and glyph bits*/ width += pf->width? pf->width[ch]: pf->maxwidth; } if ( w ) *w = width; if ( h ) *h = pf->height; return width;}/* put a string at a given char position */void lcd_puts(int x, int y, unsigned char *str){ lcd_puts_style(x, y, str, STYLE_DEFAULT);}void lcd_puts_style(int x, int y, unsigned char *str, int style){ int xpos,ypos,w,h; struct scrollinfo* s; int index;#if defined(SIMULATOR) && defined(HAVE_LCD_CHARCELLS) /* We make the simulator truncate the string if it reaches the right edge, as otherwise it'll wrap. The real target doesn't wrap. */ char buffer[12]; if(strlen(str)+x > 11 ) { strncpy(buffer, str, sizeof buffer); buffer[11-x]=0; str = buffer; } xmargin = 0; ymargin = 8;#endif /* make sure scrolling is turned off on the line we are updating */ if (scrolling_lines) { for (index = 0; index < SCROLLABLE_LINES; index++) { if (scrolling_lines&(1<<index)) { s = &scroll[index]; if (s->starty == y) { scrolling_lines &= ~(1<<index); break; } } } } if(!str || !str[0]) return; lcd_getstringsize(str, &w, &h); xpos = xmargin + x*w / strlen(str); ypos = ymargin + y*h; lcd_putsxy(xpos, ypos, str); lcd_clearrect(xpos + w, ypos, LCD_WIDTH - (xpos + w), h); if (style & STYLE_INVERT) lcd_invertrect(xpos, ypos, LCD_WIDTH - xpos, h);#if defined(SIMULATOR) && defined(HAVE_LCD_CHARCELLS) lcd_update();#endif}/* put a string at a given pixel position, skipping first ofs pixel columns */static void lcd_putsxyofs(int x, int y, int ofs, unsigned char *str){ int ch; struct font* pf = font_get(curfont); while ((ch = *str++) != '\0' && x < LCD_WIDTH) { int width; /* check input range */ if (ch < pf->firstchar || ch >= pf->firstchar+pf->size) ch = pf->defaultchar; ch -= pf->firstchar; /* no partial-height drawing for now... */ if (y + pf->height > LCD_HEIGHT) break; /* get proportional width and glyph bits */ width = pf->width ? pf->width[ch] : pf->maxwidth; width = MIN (width, LCD_WIDTH - x); if (ofs != 0) { if (ofs > width) { ofs -= width; continue; } width -= ofs; } if (width > 0) { int rows = (pf->height + 7) / 8; bitmap_t* bits = pf->bits + (pf->offset ? pf->offset[ch] : (pf->height * ch)); lcd_bitmap (((unsigned char*) bits) + ofs*rows, x, y, width, pf->height, true); x += width; } ofs = 0; }}/* put a string at a given pixel position */void lcd_putsxy(int x, int y, unsigned char *str){ lcd_putsxyofs(x, y, 0, str);}/* * All bitmaps have this format: * Bits within a byte are arranged veritcally, LSB at top. * Bytes are stored in column-major format, with byte 0 at top left, * byte 1 is 2nd from top, etc. Bytes following left-most column * starts 2nd left column, etc. * * Note: The HW takes bitmap bytes in row-major order. * * Memory copy of display bitmap *//* * Draw a bitmap at (x, y), size (nx, ny) * if 'clear' is true, clear destination area first */void lcd_bitmap (unsigned char *src, int x, int y, int nx, int ny, bool clear) __attribute__ ((section (".icode")));void lcd_bitmap (unsigned char *src, int x, int y, int nx, int ny, bool clear){ unsigned char *dst; unsigned char *dst2; unsigned int data, mask, mask2, mask3, mask4; int shift; if (((unsigned)x >= LCD_WIDTH) || ((unsigned)y >= LCD_HEIGHT)) return; if (((unsigned)(x + nx)) >= LCD_WIDTH) nx = LCD_WIDTH - x; if (((unsigned)(y + ny)) >= LCD_HEIGHT) ny = LCD_HEIGHT - y; shift = y & 7; dst2 = &lcd_framebuffer[y/8][x]; /* short cut for byte aligned match (e.g. standard text) */ if (!shift && clear && ny==8) { memcpy(dst2, src, nx); return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -