大理水控初始版本
diff --git a/lcd/text.c b/lcd/text.c
new file mode 100644
index 0000000..23bfa5d
--- /dev/null
+++ b/lcd/text.c
@@ -0,0 +1,321 @@
+
+/**
+ \file text.c
+ \brief Functions relating to using text fonts of all sizes.
+ \author Andy Gock
+ */
+
+/*
+ Copyright (c) 2012, Andy Gock
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of Andy Gock nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL ANDY GOCK BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "glcd.h"
+
+extern uint8_t *glcd_buffer_selected;
+extern glcd_BoundingBox_t *glcd_bbox_selected;
+
+glcd_FontConfig_t font_current;
+
+#if defined(GLCD_DEVICE_AVR8)
+void glcd_set_font(PGM_P font_table, uint8_t width, uint8_t height, char start_char, char end_char)
+#else
+void glcd_set_font(const char * font_table, uint8_t width, uint8_t height, char start_char, char end_char)
+#endif
+{
+ /* Supports variable width fonts */
+ font_current.font_table = font_table;
+ font_current.width = width;
+ font_current.height = height;
+ font_current.start_char = start_char;
+ font_current.end_char = end_char;
+ font_current.table_type = MIKRO; /* Only supports MikroElektronika generated format at the moment */
+}
+
+#if defined(GLCD_DEVICE_AVR8)
+void glcd_font(PGM_P font_table, uint8_t width, uint8_t height, char start_char, char end_char, font_table_type_t type)
+#else
+void glcd_font(const char * font_table, uint8_t width, uint8_t height, char start_char, char end_char, font_table_type_t type)
+#endif
+{
+ /* Supports variable width fonts */
+ font_current.font_table = font_table;
+ font_current.width = width;
+ font_current.height = height;
+ font_current.start_char = start_char;
+ font_current.end_char = end_char;
+ font_current.table_type = type; /* Only supports MikroElektronika generated format at the moment */
+}
+
+uint8_t glcd_draw_char_xy(uint8_t x, uint8_t y, char c)
+{
+ if (c < font_current.start_char || c > font_current.end_char) {
+ c = '.';
+ }
+
+ if (font_current.table_type == STANG) {
+ /* Font table in Pascal Stang format (single byte height with with no width specifier) */
+ /* Maximum height of 8 bits only */
+
+ uint8_t i;
+ for ( i = 0; i < font_current.width; i++ ) {
+#if defined(GLCD_DEVICE_AVR8)
+ uint8_t dat = pgm_read_byte( font_current.font_table + ((c - font_current.start_char) * (font_current.width)) + i );
+#else
+ uint8_t dat = *( font_current.font_table + ((c - font_current.start_char) * (font_current.width)) + i );
+#endif
+ uint8_t j;
+
+ if(glcd_get_reverse_sta())
+ dat = ~dat;
+ for (j = 0; j < 8; j++) {
+ /* Set pixel color for each bit of the column (8-bits) */
+ if (x+i >= GLCD_LCD_WIDTH || y+j >= GLCD_LCD_HEIGHT) {
+ /* Don't try and write past the dimensions of the LCD */
+ return 0;
+ }
+ if (dat & (1<<j)) {
+ glcd_set_pixel(x+i,y+j,BLACK);
+ } else {
+ glcd_set_pixel(x+i,y+j,WHITE);
+ }
+ }
+ }
+
+ /* always return how many pixels of width were written */
+ /* here for "stang" format fonts, it is always fixed */
+ return font_current.width;
+
+ } else if (font_current.table_type == MIKRO) {
+ /* Font table in MikroElecktronica format
+ - multi row fonts allowed (more than 8 pixels high)
+ - variable width fonts allowed
+ a complete column is written before moving to the next */
+
+ uint8_t i;
+ uint8_t var_width;
+ uint8_t bytes_high;
+ uint8_t bytes_per_char;
+ const char *p;
+
+ if ((font_current.height % 8) > 0){
+ bytes_high = (font_current.height / 8) + 1;
+ }
+ else{
+ bytes_high = (font_current.height / 8);
+ }
+ bytes_per_char = font_current.width * bytes_high + 1; /* The +1 is the width byte at the start */
+
+ p = font_current.font_table + (c - font_current.start_char) * bytes_per_char;
+
+ /* The first byte per character is always the width of the character */
+#if defined(GLCD_DEVICE_AVR8)
+ var_width = pgm_read_byte(p);
+#else
+ var_width = *p;
+#endif
+ p++; /* Step over the variable width field */
+
+ /*
+ if (x+var_width >= GLCD_LCD_WIDTH || y+font_current.height >= GLCD_LCD_HEIGHT) {
+ return;
+ }
+ */
+
+ for ( i = 0; i < var_width; i++ ) {
+ uint8_t j;
+ for ( j = 0; j < bytes_high; j++ ) {
+#if defined(GLCD_DEVICE_AVR8)
+ uint8_t dat = pgm_read_byte( p + i*bytes_high + j );
+#else
+ uint8_t dat = *( p + i*bytes_high + j );
+#endif
+ uint8_t bit;
+
+ if(glcd_get_reverse_sta())
+ dat = ~dat;
+ for (bit = 0; bit < 8; bit++) {
+
+ if (x+i >= GLCD_LCD_WIDTH || y+j*8+bit >= GLCD_LCD_HEIGHT) {
+ /* Don't write past the dimensions of the LCD, skip the entire char */
+ return 0;
+ }
+
+ /* We should not write if the y bit exceeds font height */
+ if ((j*8 + bit) >= font_current.height) {
+ /* Skip the bit */
+ continue;
+ }
+
+ if (dat & (1<<bit)) {
+ glcd_set_pixel(x+i,y+j*8+bit,BLACK);
+ } else {
+ glcd_set_pixel(x+i,y+j*8+bit,WHITE);
+ }
+ }
+ }
+ }
+ return var_width;
+
+ } else if (font_current.table_type == GLCD_UTILS) {
+ /* Font table format of glcd-utils
+ - A complete row is written first (not completed columns)
+ - Width not stored, but we can search and determine it
+ - Not yet supported */
+
+ uint8_t var_width, n;
+ uint8_t bytes_high, bytes_per_char;
+ const char *p;
+ uint8_t j;
+
+ bytes_high = font_current.height / 8 + 1;
+ bytes_per_char = font_current.width * bytes_high;
+
+ /* Point to chars first byte */
+ p = font_current.font_table + (c - font_current.start_char) * bytes_per_char;
+
+ /* Determine the width of the character */
+ var_width = font_current.width;
+
+ n = 0; /* How many columns back from the end */
+
+ while (1) {
+ uint8_t max_byte = 0;
+ uint8_t row = 0;
+
+ for (row = 0; row < bytes_high; row++) {
+ uint8_t offset;
+ offset = (font_current.width - 1 - n) * row;
+ max_byte = *(p + offset);
+ }
+ if (max_byte == 0) {
+ /* column is empty for all rows, go left and test again */
+ /* reduce variable width by 1 */
+ var_width--;
+ if (var_width == 0) {
+ break;
+ }
+ } else {
+ break; /* Part of a character was found */
+ }
+ n++;
+ }
+
+ /* Uncomment line below, to force fixed width, for debugging only */
+ //var_width = font_current.width; // bypass auto width detection, treat as fixed width
+
+ /* For glcd-utils format, we write one complete row at a time */
+ /* loop as rows, 1st row, j=0 */
+ for ( j = 0; j < bytes_high; j++ ) {
+ /* Loop one row at a time */
+
+ uint8_t i;
+ for ( i = 0; i < var_width; i++ ) {
+ /* Loop one column at a time */
+
+ uint8_t dat, bit;
+
+#if defined(GLCD_DEVICE_AVR8)
+ dat = pgm_read_byte( p + j*font_current.width + i );
+#else
+ dat = *( p + j*font_current.width + i );
+#endif
+
+ if(glcd_get_reverse_sta())
+ dat = ~dat;
+
+ for (bit = 0; bit < 8; bit++) {
+
+ if ((x+i) >= GLCD_LCD_WIDTH || (y+j*8+bit) >= GLCD_LCD_HEIGHT) {
+ /* Don't write past the dimensions of the LCD, skip the entire char */
+ return 0;
+ }
+
+ /* We should not write if the y bit exceeds font height */
+ if ((j*8 + bit) >= font_current.height) {
+ /* Skip the bit */
+ continue;
+ }
+
+ if (dat & (1<<bit)) {
+ glcd_set_pixel(x+i,y+j*8+bit,BLACK);
+ } else {
+ glcd_set_pixel(x+i,y+j*8+bit,WHITE);
+ }
+ }
+ } /* i */
+ } /* j */
+
+ return var_width; /* Number of columns written to display */
+
+ } else {
+ /* Don't recognise the font table */
+ return 0;
+
+ }
+
+}
+
+void glcd_draw_string_xy(uint8_t x, uint8_t y, char *c)
+{
+ uint8_t width;
+
+ if (y > (GLCD_LCD_HEIGHT - font_current.height - 1)) {
+ /* Character won't fit */
+ return;
+ }
+
+ while (*c) {
+ width = glcd_draw_char_xy(x,y,*c);
+ x += (width + 1);
+ c++;
+ }
+}
+
+void glcd_draw_string_xy_P(uint8_t x, uint8_t y, const char *str)
+{
+ uint8_t width;
+
+ if (y > (GLCD_LCD_HEIGHT - font_current.height - 1)) {
+ /* Character won't fit */
+ return;
+ }
+
+ while (1) {
+#if defined(GLCD_DEVICE_AVR8)
+ char c = pgm_read_byte(str++);
+#else
+ char c = *(str++);
+#endif
+ if (!c)
+ return;
+
+ width = glcd_draw_char_xy(x,y,c);
+ x += (width + 1);
+ c++;
+ }
+}
+