大理水控初始版本
diff --git a/lcd/graphics.c b/lcd/graphics.c
new file mode 100644
index 0000000..dec75c0
--- /dev/null
+++ b/lcd/graphics.c
@@ -0,0 +1,309 @@
+/**
+   \file graphics.c
+   \brief Functions relating to graphics. e.g drawing lines, rectangles, circles etc.
+   \author Andy Gock
+
+   Some functions based on Limor Fried's PCD8544 Arduino library.
+
+ */ 
+
+/*
+	Copyright (c) 2012, Andy Gock
+
+	Copyright (c) 2012, Adafruit Industries
+
+	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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "glcd.h"
+
+/* Based on PCD8544 library by Limor Fried */
+void glcd_set_pixel(uint8_t x, uint8_t y, uint8_t color) {
+	if (x > (GLCD_LCD_WIDTH-1) || y > (GLCD_LCD_HEIGHT-1)) {
+		/* don't do anything if x/y is outside bounds of display size */
+		return;
+	}
+
+	if (color) {
+		/* Set black */
+		glcd_buffer[x+ (y/8)*GLCD_LCD_WIDTH] |= ( 1 << (y%8));
+	} else {
+		/* Set white */
+		glcd_buffer[x+ (y/8)*GLCD_LCD_WIDTH] &= ~ (1 << (y%8));
+	}
+
+	glcd_update_bbox(x,y,x,y);
+}
+
+/* Based on PCD8544 library by Limor Fried */
+uint8_t glcd_get_pixel(uint8_t x, uint8_t y) {
+	if ((x >= GLCD_LCD_WIDTH) || (y >= GLCD_LCD_HEIGHT)) {
+		return 0;
+	}
+	
+	if ( glcd_buffer[x+ (y/8)*GLCD_LCD_WIDTH] & ( 1 << (y%8)) ) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+void glcd_invert_pixel(uint8_t x, uint8_t y) {
+	if ((x >= GLCD_LCD_WIDTH) || (y >= GLCD_LCD_HEIGHT)) {
+		return;
+	}
+	glcd_update_bbox(x,y,x,y);
+	glcd_buffer[x+ (y/8)*GLCD_LCD_WIDTH] ^= ( 1 << (y%8));
+}
+
+/* Bresenham's algorithm - based on PCD8544 library Limor Fried */
+void glcd_draw_line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t color) {
+	uint8_t steep = abs(y1 - y0) > abs(x1 - x0);
+	uint8_t dx, dy;
+	int8_t err;
+	int8_t ystep;
+	
+	if (steep) {
+		swap(x0, y0);
+		swap(x1, y1);
+	}
+	
+	if (x0 > x1) {
+		swap(x0, x1);
+		swap(y0, y1);
+	}
+	
+	glcd_update_bbox( x0, y0, x1, y1 );
+
+	dx = x1 - x0;
+	dy = abs(y1 - y0);
+	
+	err = dx / 2;
+	
+	if (y0 < y1) {
+		ystep = 1;
+	} else {
+		ystep = -1;
+	}
+	
+	for (; x0<=x1; x0++) {
+		if (steep) {
+			glcd_set_pixel(y0, x0, color);
+		} else {
+			glcd_set_pixel(x0, y0, color);
+		}
+		err -= dy;
+		if (err < 0) {
+			y0 += ystep;
+			err += dx;
+		}
+	}
+}
+
+void glcd_fill_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color)
+{
+	int16_t i;
+	for (i=x; i<x+w; i++) {
+		int16_t j;
+		for (j=y; j<y+h; j++) {
+			glcd_set_pixel(i, j, color);
+		}
+	}
+	glcd_update_bbox(x, y, x+w-1, y+h-1);
+}
+
+void glcd_draw_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color)
+{
+	int16_t i;
+	for (i=x; i<x+w; i++) {
+		glcd_set_pixel(i, y, color);
+		glcd_set_pixel(i, y+h-1, color);
+	}
+	for (i=y; i<y+h; i++) {
+		glcd_set_pixel(x, i, color);
+		glcd_set_pixel(x+w-1, i, color);
+	} 
+	glcd_update_bbox(x, y, x+w-1, y+h-1);
+}
+
+void glcd_draw_rect_thick(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t tx, uint8_t ty, uint8_t color)
+{
+	int16_t i, t;
+	
+	if (tx == 0) {
+		tx = 1;
+	}
+
+	if (ty == 0) {
+		ty = 1;
+	}
+	
+	for (i=x; i<x+w; i++) {
+		/* Top and bottom sides */
+		for (t=0; t<(ty); t++) {
+			glcd_set_pixel(i, y+t, color);
+			glcd_set_pixel(i, y+h-1-t, color);
+		}
+	}
+	for (i=y; i<y+h; i++) {
+		/* Left and right sides */
+		for (t=0; t<(tx); t++) {
+			glcd_set_pixel(x+t, i, color);
+			glcd_set_pixel(x+w-1-t, i, color);
+		}
+	} 
+	glcd_update_bbox(x, y, x+w-1, y+h-1);
+}
+
+void glcd_draw_rect_shadow(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color)
+{
+	glcd_draw_rect(x, y, w, h, color);
+	glcd_draw_line(x+1, y+h, x+w, y+h, color);
+	glcd_draw_line(x+w, y+1, x+w, y+h, color);
+}
+
+void glcd_draw_circle(uint8_t x0, uint8_t y0, uint8_t r, uint8_t color)
+{
+		
+	int8_t f = 1 - r;
+	int8_t ddF_x = 1;
+	int8_t ddF_y = -2 * r;
+	int8_t x = 0;
+	int8_t y = r;
+	
+	glcd_update_bbox(x0-r, y0-r, x0+r, y0+r);
+	
+	glcd_set_pixel(x0, y0+r, color);
+	glcd_set_pixel(x0, y0-r, color);
+	glcd_set_pixel(x0+r, y0, color);
+	glcd_set_pixel(x0-r, y0, color);
+	
+	while (x<y) {
+		if (f >= 0) {
+			y--;
+			ddF_y += 2;
+			f += ddF_y;
+		}
+		x++;
+		ddF_x += 2;
+		f += ddF_x;
+		
+		glcd_set_pixel(x0 + x, y0 + y, color);
+		glcd_set_pixel(x0 - x, y0 + y, color);
+		glcd_set_pixel(x0 + x, y0 - y, color);
+		glcd_set_pixel(x0 - x, y0 - y, color);
+		
+		glcd_set_pixel(x0 + y, y0 + x, color);
+		glcd_set_pixel(x0 - y, y0 + x, color);
+		glcd_set_pixel(x0 + y, y0 - x, color);
+		glcd_set_pixel(x0 - y, y0 - x, color);
+		
+	}
+}
+
+void glcd_fill_circle(uint8_t x0, uint8_t y0, uint8_t r, uint8_t color)
+{
+	
+	int8_t f = 1 - r;
+	int8_t ddF_x = 1;
+	int8_t ddF_y = -2 * r;
+	int8_t x = 0;
+	int8_t y = r;
+	
+	int16_t i;
+
+	glcd_update_bbox(x0-r, y0-r, x0+r, y0+r);
+	
+	for (i=y0-r; i<=y0+r; i++) {
+		glcd_set_pixel(x0, i, color);
+	}
+	
+	while (x < y) {
+		if (f >= 0) {
+			y--;
+			ddF_y += 2;
+			f += ddF_y;
+		}
+		x++;
+		ddF_x += 2;
+		f += ddF_x;
+		
+		for (i=y0-y; i<=y0+y; i++) {
+			glcd_set_pixel(x0+x, i, color);
+			glcd_set_pixel(x0-x, i, color);
+		} 
+		for (i=y0-x; i<=y0+x; i++) {
+			glcd_set_pixel(x0+y, i, color);
+			glcd_set_pixel(x0-y, i, color);
+		}    
+	}
+}
+
+void glcd_invert_area(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
+{
+	uint8_t xx, yy;
+	for (xx = x; xx < (x+w); xx++) {
+		/* Loop through each partial column */
+		for (yy = y; yy < (y+h); yy++) {
+			/* Go down and invert every pixel */
+			glcd_invert_pixel(xx,yy);
+		}
+	}
+}
+
+void glcd_draw_bitmap(const unsigned char *data)
+{
+
+#if 0
+	/* Testing purposes only: Writing to the LCD right away (not for AVR) */
+	/* Normally, we do not do this, we just write to the screen buffer */
+	uint8_t *original_buffer;
+
+	/* Save the location of original screen buffer */
+	original_buffer = glcd_buffer_selected;
+	
+	/* Use bitmap location as screen buffer (this won't work when using AVR8 PGM_P) */
+	glcd_select_screen((uint8_t *)data, glcd_bbox_selected);
+	
+	/* Make sure we write the entre display */
+	glcd_bbox_refresh(); 
+	glcd_write();
+	
+	/* Restore the screen buffer back to original */
+	glcd_select_screen(original_buffer, glcd_bbox_selected);	
+#endif
+	
+	/* Copy bitmap data to the screen buffer */
+#if defined(GLCD_DEVICE_AVR8)
+	memcpy_P(glcd_buffer_selected, data, (GLCD_LCD_WIDTH * GLCD_LCD_HEIGHT / 8));
+#else
+	memcpy(glcd_buffer_selected, data, (GLCD_LCD_WIDTH * GLCD_LCD_HEIGHT / 8));
+#endif
+
+	glcd_bbox_refresh(); 
+}