add calendar support

This commit is contained in:
Shuanglei Tao
2025-02-09 18:26:43 +08:00
parent 147181e2f8
commit 9d6cbff256
26 changed files with 3351 additions and 1706 deletions

943
GUI/Adafruit_GFX.c Normal file
View File

@@ -0,0 +1,943 @@
/*
This is the core graphics library for all our displays, providing a common
set of graphics primitives (points, lines, circles, etc.). It needs to be
paired with a hardware-specific library for each display device we carry
(to handle the lower-level functions).
Adafruit invests time and resources providing this open source code, please
support Adafruit & open-source hardware by purchasing products from Adafruit!
Copyright (c) 2013 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.
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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Adafruit_GFX.h"
#ifndef abs
#define abs(x) ((x)>0?(x):-(x))
#endif
#ifndef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef _swap_int16_t
#define _swap_int16_t(a, b) \
{ \
int16_t t = a; \
a = b; \
b = t; \
}
#endif
static void GFX_u8g2_draw_hv_line(int16_t x, int16_t y, int16_t len,
uint8_t dir, uint16_t color, void *arg)
{
Adafruit_GFX *gfx = (Adafruit_GFX *)arg;
switch(dir) {
case 0:
GFX_drawFastHLine(gfx, x, y, len, color);
break;
case 1:
GFX_drawFastVLine(gfx, x, y, len, color);
break;
case 2:
GFX_drawFastHLine(gfx, x - len + 1, y, len, color);
break;
case 3:
GFX_drawFastVLine(gfx, x, y - len + 1, len, color);
break;
}
}
/**************************************************************************/
/*!
@brief Instatiate a GFX context for graphics
@param w Display width, in pixels
@param h Display height, in pixels
@param buffer_height Page buffer height
*/
/**************************************************************************/
void GFX_begin(Adafruit_GFX *gfx, int16_t w, int16_t h, int16_t buffer_height) {
memset(gfx, 0, sizeof(Adafruit_GFX));
memset(&gfx->u8g2, 0, sizeof(gfx->u8g2));
gfx->WIDTH = gfx->_width = w;
gfx->HEIGHT = gfx->_height = h;
gfx->u8g2.draw_hv_line = GFX_u8g2_draw_hv_line;
gfx->u8g2.draw_hv_line_arg = gfx;
gfx->buffer = malloc(((gfx->WIDTH + 7) / 8) * buffer_height);
gfx->page_height = buffer_height;
gfx->total_pages = (gfx->HEIGHT / gfx->page_height) + (gfx->HEIGHT % gfx->page_height > 0);
}
/**************************************************************************/
/*!
@brief Instatiate a 3-color GFX context for graphics
@param w Display width, in pixels
@param h Display height, in pixels
@param buffer_height Page buffer height, should be multiple of 2
*/
/**************************************************************************/
void GFX_begin_3c(Adafruit_GFX *gfx, int16_t w, int16_t h, int16_t buffer_height) {
GFX_begin(gfx, w, h, buffer_height);
gfx->page_height = buffer_height / 2;
gfx->color = gfx->buffer + ((gfx->WIDTH + 7) / 8) * gfx->page_height;
gfx->total_pages = (gfx->HEIGHT / gfx->page_height) + (gfx->HEIGHT % gfx->page_height > 0);
}
void GFX_end(Adafruit_GFX *gfx) {
if (gfx->buffer) free(gfx->buffer);
}
void GFX_firstPage(Adafruit_GFX *gfx) {
GFX_fillScreen(gfx, GFX_WHITE);
gfx->current_page = 0;
}
bool GFX_nextPage(Adafruit_GFX *gfx, buffer_callback callback) {
int16_t page_y = gfx->current_page * gfx->page_height;
int16_t height = min(gfx->page_height, gfx->HEIGHT - page_y);
if (callback)
callback(gfx->buffer, gfx->color, 0, page_y, gfx->WIDTH, height);
gfx->current_page++;
GFX_fillScreen(gfx, GFX_WHITE);
return gfx->current_page < gfx->total_pages;
}
/**************************************************************************/
/*!
@brief Set rotation setting for display
@param r 0 thru 3 corresponding to 4 cardinal rotations
*/
/**************************************************************************/
void GFX_setRotation(Adafruit_GFX *gfx, GFX_Rotate r) {
gfx->rotation = r;
switch (gfx->rotation) {
case GFX_ROTATE_0:
case GFX_ROTATE_180:
gfx->_width = gfx->WIDTH;
gfx->_height = gfx->HEIGHT;
break;
case GFX_ROTATE_90:
case GFX_ROTATE_270:
gfx->_width = gfx->HEIGHT;
gfx->_height = gfx->WIDTH;
break;
}
}
/**************************************************************************/
/*!
@brief Draw a pixel
@param x x coordinate
@param y y coordinate
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFX_drawPixel(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t color) {
if (x < 0 || x >= gfx->_width || y < 0 || y >= gfx->_height) return;
switch (gfx->rotation) {
case GFX_ROTATE_0:
break;
case GFX_ROTATE_90:
_swap_int16_t(x, y);
x = gfx->WIDTH - x - 1;
break;
case GFX_ROTATE_180:
x = gfx->WIDTH - x - 1;
y = gfx->HEIGHT - y - 1;
break;
case GFX_ROTATE_270:
_swap_int16_t(x, y);
y = gfx->HEIGHT - y - 1;
break;
}
y -= gfx->current_page * gfx->page_height;
if (y < 0 || y >= gfx->page_height) return;
uint16_t i = x / 8 + y * (gfx->WIDTH / 8);
if (gfx->color != NULL) {
gfx->buffer[i] |= 0x80 >> (x & 7); // white
gfx->color[i] |= 0x80 >> (x & 7);
if (color == GFX_BLACK)
gfx->buffer[i] &= ~(0x80 >> (x & 7));
else if (color == GFX_RED)
gfx->color[i] &= ~(0x80 >> (x & 7));
} else {
if (color == GFX_WHITE)
gfx->buffer[i] |= 0x80 >> (x & 7);
else
gfx->buffer[i] &= ~(0x80 >> (x & 7));
}
}
/**************************************************************************/
/*!
@brief Draw a line. Bresenham's algorithm - thx wikpedia
@param x0 Start point x coordinate
@param y0 Start point y coordinate
@param x1 End point x coordinate
@param y1 End point y coordinate
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void GFX_drawLine(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1, int16_t y1,
uint16_t color) {
int16_t steep = abs(y1 - y0) > abs(x1 - x0);
if (steep) {
_swap_int16_t(x0, y0);
_swap_int16_t(x1, y1);
}
if (x0 > x1) {
_swap_int16_t(x0, x1);
_swap_int16_t(y0, y1);
}
int16_t dx, dy;
dx = x1 - x0;
dy = abs(y1 - y0);
int16_t err = dx / 2;
int16_t ystep;
if (y0 < y1) {
ystep = 1;
} else {
ystep = -1;
}
for (; x0 <= x1; x0++) {
if (steep) {
GFX_drawPixel(gfx, y0, x0, color);
} else {
GFX_drawPixel(gfx, x0, y0, color);
}
err -= dy;
if (err < 0) {
y0 += ystep;
err += dx;
}
}
}
/**************************************************************************/
/*!
@brief Draw a perfectly vertical line
@param x Top-most x coordinate
@param y Top-most y coordinate
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFX_drawFastVLine(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t h,
uint16_t color) {
GFX_drawLine(gfx, x, y, x, y + h - 1, color);
}
/**************************************************************************/
/*!
@brief Draw a perfectly horizontal line
@param x Left-most x coordinate
@param y Left-most y coordinate
@param w Width in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFX_drawFastHLine(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w,
uint16_t color) {
GFX_drawLine(gfx, x, y, x + w - 1, y, color);
}
/**************************************************************************/
/*!
@brief Fill a rectangle completely with one color.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFX_fillRect(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color) {
for (int16_t i = x; i < x + w; i++) {
GFX_drawFastVLine(gfx, i, y, h, color);
}
}
/**************************************************************************/
/*!
@brief Fill the screen completely with one color.
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFX_fillScreen(Adafruit_GFX *gfx, uint16_t color) {
uint32_t size = ((gfx->WIDTH + 7) / 8) * gfx->page_height;
memset(gfx->buffer, color == GFX_WHITE ? 0xFF : 0x00, size);
if (gfx->color != NULL)
memset(gfx->color, color == GFX_RED ? 0x00 : 0xFF, size);
}
/**************************************************************************/
/*!
@brief Draw a circle outline
@param x0 Center-point x coordinate
@param y0 Center-point y coordinate
@param r Radius of circle
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void GFX_drawCircle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r,
uint16_t color) {
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * r;
int16_t x = 0;
int16_t y = r;
GFX_drawPixel(gfx, x0, y0 + r, color);
GFX_drawPixel(gfx, x0, y0 - r, color);
GFX_drawPixel(gfx, x0 + r, y0, color);
GFX_drawPixel(gfx, x0 - r, y0, color);
while (x < y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
GFX_drawPixel(gfx, x0 + x, y0 + y, color);
GFX_drawPixel(gfx, x0 - x, y0 + y, color);
GFX_drawPixel(gfx, x0 + x, y0 - y, color);
GFX_drawPixel(gfx, x0 - x, y0 - y, color);
GFX_drawPixel(gfx, x0 + y, y0 + x, color);
GFX_drawPixel(gfx, x0 - y, y0 + x, color);
GFX_drawPixel(gfx, x0 + y, y0 - x, color);
GFX_drawPixel(gfx, x0 - y, y0 - x, color);
}
}
/**************************************************************************/
/*!
@brief Quarter-circle drawer, used to do circles and roundrects
@param x0 Center-point x coordinate
@param y0 Center-point y coordinate
@param r Radius of circle
@param cornername Mask bit #1 or bit #2 to indicate which quarters of
the circle we're doing
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void GFX_drawCircleHelper(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r,
uint8_t cornername, uint16_t color) {
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * r;
int16_t x = 0;
int16_t y = r;
while (x < y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
if (cornername & 0x4) {
GFX_drawPixel(gfx, x0 + x, y0 + y, color);
GFX_drawPixel(gfx, x0 + y, y0 + x, color);
}
if (cornername & 0x2) {
GFX_drawPixel(gfx, x0 + x, y0 - y, color);
GFX_drawPixel(gfx, x0 + y, y0 - x, color);
}
if (cornername & 0x8) {
GFX_drawPixel(gfx, x0 - y, y0 + x, color);
GFX_drawPixel(gfx, x0 - x, y0 + y, color);
}
if (cornername & 0x1) {
GFX_drawPixel(gfx, x0 - y, y0 - x, color);
GFX_drawPixel(gfx, x0 - x, y0 - y, color);
}
}
}
/**************************************************************************/
/*!
@brief Draw a circle with filled color
@param x0 Center-point x coordinate
@param y0 Center-point y coordinate
@param r Radius of circle
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFX_fillCircle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r,
uint16_t color) {
GFX_drawFastVLine(gfx, x0, y0 - r, 2 * r + 1, color);
GFX_fillCircleHelper(gfx, x0, y0, r, 3, 0, color);
}
/**************************************************************************/
/*!
@brief Quarter-circle drawer with fill, used for circles and roundrects
@param x0 Center-point x coordinate
@param y0 Center-point y coordinate
@param r Radius of circle
@param corners Mask bits indicating which quarters we're doing
@param delta Offset from center-point, used for round-rects
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void GFX_fillCircleHelper(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r,
uint8_t corners, int16_t delta, uint16_t color) {
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * r;
int16_t x = 0;
int16_t y = r;
int16_t px = x;
int16_t py = y;
delta++; // Avoid some +1's in the loop
while (x < y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
// These checks avoid double-drawing certain lines, important
// for the SSD1306 library which has an INVERT drawing mode.
if (x < (y + 1)) {
if (corners & 1)
GFX_drawFastVLine(gfx, x0 + x, y0 - y, 2 * y + delta, color);
if (corners & 2)
GFX_drawFastVLine(gfx, x0 - x, y0 - y, 2 * y + delta, color);
}
if (y != py) {
if (corners & 1)
GFX_drawFastVLine(gfx, x0 + py, y0 - px, 2 * px + delta, color);
if (corners & 2)
GFX_drawFastVLine(gfx, x0 - py, y0 - px, 2 * px + delta, color);
py = y;
}
px = x;
}
}
/**************************************************************************/
/*!
@brief Draw a rectangle with no fill color
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void GFX_drawRect(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color) {
GFX_drawFastHLine(gfx, x, y, w, color);
GFX_drawFastHLine(gfx, x, y + h - 1, w, color);
GFX_drawFastVLine(gfx, x, y, h, color);
GFX_drawFastVLine(gfx, x + w - 1, y, h, color);
}
/**************************************************************************/
/*!
@brief Draw a rounded rectangle with no fill color
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param r Radius of corner rounding
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void GFX_drawRoundRect(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w,
int16_t h, int16_t r, uint16_t color) {
int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
if (r > max_radius)
r = max_radius;
// smarter version
GFX_drawFastHLine(gfx, x + r, y, w - 2 * r, color); // Top
GFX_drawFastHLine(gfx, x + r, y + h - 1, w - 2 * r, color); // Bottom
GFX_drawFastVLine(gfx, x, y + r, h - 2 * r, color); // Left
GFX_drawFastVLine(gfx, x + w - 1, y + r, h - 2 * r, color); // Right
// draw four corners
GFX_drawCircleHelper(gfx, x + r, y + r, r, 1, color);
GFX_drawCircleHelper(gfx, x + w - r - 1, y + r, r, 2, color);
GFX_drawCircleHelper(gfx, x + w - r - 1, y + h - r - 1, r, 4, color);
GFX_drawCircleHelper(gfx, x + r, y + h - r - 1, r, 8, color);
}
/**************************************************************************/
/*!
@brief Draw a rounded rectangle with fill color
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param r Radius of corner rounding
@param color 16-bit 5-6-5 Color to draw/fill with
*/
/**************************************************************************/
void GFX_fillRoundRect(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w,
int16_t h, int16_t r, uint16_t color) {
int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
if (r > max_radius)
r = max_radius;
// smarter version
GFX_fillRect(gfx, x + r, y, w - 2 * r, h, color);
// draw four corners
GFX_fillCircleHelper(gfx, x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color);
GFX_fillCircleHelper(gfx, x + r, y + r, r, 2, h - 2 * r - 1, color);
}
/**************************************************************************/
/*!
@brief Draw a triangle with no fill color
@param x0 Vertex #0 x coordinate
@param y0 Vertex #0 y coordinate
@param x1 Vertex #1 x coordinate
@param y1 Vertex #1 y coordinate
@param x2 Vertex #2 x coordinate
@param y2 Vertex #2 y coordinate
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void GFX_drawTriangle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1,
int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
GFX_drawLine(gfx, x0, y0, x1, y1, color);
GFX_drawLine(gfx, x1, y1, x2, y2, color);
GFX_drawLine(gfx, x2, y2, x0, y0, color);
}
/**************************************************************************/
/*!
@brief Draw a triangle with color-fill
@param x0 Vertex #0 x coordinate
@param y0 Vertex #0 y coordinate
@param x1 Vertex #1 x coordinate
@param y1 Vertex #1 y coordinate
@param x2 Vertex #2 x coordinate
@param y2 Vertex #2 y coordinate
@param color 16-bit 5-6-5 Color to fill/draw with
*/
/**************************************************************************/
void GFX_fillTriangle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1,
int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
int16_t a, b, y, last;
// Sort coordinates by Y order (y2 >= y1 >= y0)
if (y0 > y1) {
_swap_int16_t(y0, y1);
_swap_int16_t(x0, x1);
}
if (y1 > y2) {
_swap_int16_t(y2, y1);
_swap_int16_t(x2, x1);
}
if (y0 > y1) {
_swap_int16_t(y0, y1);
_swap_int16_t(x0, x1);
}
if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing
a = b = x0;
if (x1 < a)
a = x1;
else if (x1 > b)
b = x1;
if (x2 < a)
a = x2;
else if (x2 > b)
b = x2;
GFX_drawFastHLine(gfx, a, y0, b - a + 1, color);
return;
}
int16_t dx01 = x1 - x0, dy01 = y1 - y0, dx02 = x2 - x0, dy02 = y2 - y0,
dx12 = x2 - x1, dy12 = y2 - y1;
int32_t sa = 0, sb = 0;
// For upper part of triangle, find scanline crossings for segments
// 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
// is included here (and second loop will be skipped, avoiding a /0
// error there), otherwise scanline y1 is skipped here and handled
// in the second loop...which also avoids a /0 error here if y0=y1
// (flat-topped triangle).
if (y1 == y2)
last = y1; // Include y1 scanline
else
last = y1 - 1; // Skip it
for (y = y0; y <= last; y++) {
a = x0 + sa / dy01;
b = x0 + sb / dy02;
sa += dx01;
sb += dx02;
/* longhand:
a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
*/
if (a > b)
_swap_int16_t(a, b);
GFX_drawFastHLine(gfx, a, y, b - a + 1, color);
}
// For lower part of triangle, find scanline crossings for segments
// 0-2 and 1-2. This loop is skipped if y1=y2.
sa = (int32_t)dx12 * (y - y1);
sb = (int32_t)dx02 * (y - y0);
for (; y <= y2; y++) {
a = x1 + sa / dy12;
b = x0 + sb / dy02;
sa += dx12;
sb += dx02;
/* longhand:
a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
*/
if (a > b)
_swap_int16_t(a, b);
GFX_drawFastHLine(gfx, a, y, b - a + 1, color);
}
}
/**************************************************************************/
/*!
@brief Draw a RAM-resident 1-bit image at the specified (x,y) position,
using the specified foreground color (unset bits are transparent).
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param bitmap byte array with monochrome bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
@param color 16-bit 5-6-5 Color to draw with
@param invert When true, will invert the bitmap
*/
/**************************************************************************/
void GFX_drawBitmap(Adafruit_GFX *gfx, int16_t x, int16_t y, const uint8_t bitmap[],
int16_t w, int16_t h, uint16_t color, bool invert) {
int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
uint8_t byte = 0;
for (int16_t j = 0; j < h; j++) {
for (int16_t i = 0; i < w; i++) {
if (i & 7)
byte <<= 1;
else
byte = bitmap[j * byteWidth + i / 8];
if (((byte & 0x80) == 0x80) ^ invert)
GFX_drawPixel(gfx, x + i, y + j, color);
}
}
}
/*
U8g2_for_Adafruit_GFX.cpp
Add unicode support and U8g2 fonts to Adafruit GFX libraries.
U8g2 for Adafruit GFX Lib (https://github.com/olikraus/U8g2_for_Adafruit_GFX)
Copyright (c) 2018, olikraus@gmail.com
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.
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 THE COPYRIGHT HOLDER OR
CONTRIBUTORS 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.
*/
void GFX_setCursor(Adafruit_GFX *gfx, int16_t x, int16_t y) {
gfx->tx = x;
gfx->ty = y;
gfx->utf8_state = 0;
}
void GFX_setFont(Adafruit_GFX *gfx, const uint8_t *font) {
u8g2_SetFont(&gfx->u8g2, font);
}
void GFX_setFontMode(Adafruit_GFX *gfx, uint8_t is_transparent) {
u8g2_SetFontMode(&gfx->u8g2, is_transparent);
}
void GFX_setFontDirection(Adafruit_GFX *gfx, GFX_Rotate d) {
u8g2_SetFontDirection(&gfx->u8g2, (uint8_t)d);
}
void GFX_setTextColor(Adafruit_GFX *gfx, uint16_t fg, uint16_t bg) {
u8g2_SetForegroundColor(&gfx->u8g2, fg);
u8g2_SetBackgroundColor(&gfx->u8g2, bg);
}
int8_t GFX_getFontAscent(Adafruit_GFX *gfx) {
return gfx->u8g2.font_info.ascent_A;
}
int8_t GFX_getFontDescent(Adafruit_GFX *gfx) {
return gfx->u8g2.font_info.descent_g;
}
int16_t GFX_drawGlyph(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t e) {
return u8g2_DrawGlyph(&gfx->u8g2, x, y, e);
}
int16_t GFX_drawStr(Adafruit_GFX *gfx, int16_t x, int16_t y, const char *s) {
return u8g2_DrawStr(&gfx->u8g2, x, y, s);
}
static uint16_t utf8_next(Adafruit_GFX *gfx, uint8_t b)
{
if ( b == 0 ) /* '\n' terminates the string to support the string list procedures */
return 0x0ffff; /* end of string detected, pending UTF8 is discarded */
if ( gfx->utf8_state == 0 )
{
if ( b >= 0xfc ) /* 6 byte sequence */
{
gfx->utf8_state = 5;
b &= 1;
}
else if ( b >= 0xf8 )
{
gfx->utf8_state = 4;
b &= 3;
}
else if ( b >= 0xf0 )
{
gfx->utf8_state = 3;
b &= 7;
}
else if ( b >= 0xe0 )
{
gfx->utf8_state = 2;
b &= 15;
}
else if ( b >= 0xc0 )
{
gfx->utf8_state = 1;
b &= 0x01f;
}
else
{
/* do nothing, just use the value as encoding */
return b;
}
gfx->encoding = b;
return 0x0fffe;
}
else
{
gfx->utf8_state--;
/* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */
gfx->encoding<<=6;
b &= 0x03f;
gfx->encoding |= b;
if ( gfx->utf8_state != 0 )
return 0x0fffe; /* nothing to do yet */
}
return gfx->encoding;
}
int16_t GFX_drawUTF8(Adafruit_GFX *gfx, int16_t x, int16_t y, const char *str)
{
uint16_t e;
int16_t delta, sum;
gfx->utf8_state = 0;
sum = 0;
for(;;)
{
e = utf8_next(gfx, (uint8_t)*str);
if ( e == 0x0ffff )
break;
str++;
if ( e != 0x0fffe )
{
delta = u8g2_DrawGlyph(&gfx->u8g2, x, y, e);
switch(gfx->u8g2.font_decode.dir)
{
case 0:
x += delta;
break;
case 1:
y += delta;
break;
case 2:
x -= delta;
break;
case 3:
y -= delta;
break;
}
sum += delta;
}
}
return sum;
}
int16_t GFX_getUTF8Width(Adafruit_GFX *gfx, const char *str)
{
uint16_t e;
int16_t dx, w;
gfx->u8g2.font_decode.glyph_width = 0;
gfx->utf8_state = 0;
w = 0;
dx = 0;
for(;;)
{
e = utf8_next(gfx, (uint8_t)*str);
if ( e == 0x0ffff )
break;
str++;
if ( e != 0x0fffe )
{
dx = u8g2_GetGlyphWidth(&gfx->u8g2, e);
w += dx;
}
}
/* adjust the last glyph, check for issue #16: do not adjust if width is 0 */
if ( gfx->u8g2.font_decode.glyph_width != 0 )
{
w -= dx;
w += gfx->u8g2.font_decode.glyph_width; /* the real pixel width of the glyph, sideeffect of GetGlyphWidth */
/* issue #46: we have to add the x offset also */
w += gfx->u8g2.glyph_x_offset; /* this value is set as a side effect of u8g2_GetGlyphWidth() */
}
return w;
}
size_t GFX_print(Adafruit_GFX *gfx, const char c) {
int16_t delta;
uint16_t e = utf8_next(gfx, (uint8_t)c);
if ( e == '\n' )
{
gfx->tx = 0;
gfx->ty += gfx->u8g2.font_info.ascent_para - gfx->u8g2.font_info.descent_para;
}
else if ( e == '\r' )
{
gfx->tx = 0;
}
else if ( e < 0x0fffe )
{
delta = u8g2_DrawGlyph(&gfx->u8g2, gfx->tx, gfx->ty, e);
switch(gfx->u8g2.font_decode.dir)
{
case 0:
gfx->tx += delta;
break;
case 1:
gfx->ty += delta;
break;
case 2:
gfx->tx -= delta;
break;
case 3:
gfx->ty -= delta;
break;
}
}
return 1;
}
size_t GFX_write(Adafruit_GFX *gfx, const char *buffer, size_t size) {
size_t cnt = 0;
while( size > 0 ) {
cnt += GFX_print(gfx, *buffer++);
size--;
}
return cnt;
}
size_t GFX_printf(Adafruit_GFX *gfx, const char* format, ...) {
va_list va;
char tmp[64] = {0};
char *buf = tmp;
size_t len;
va_start(va, format);
len = vsnprintf(tmp, sizeof(tmp), format, va);
va_end(va);
if (len > sizeof(tmp) - 1)
{
buf = malloc(len + 1);
if (buf == NULL)
return 0;
va_start(va, format);
vsnprintf(buf, len + 1, format, va);
va_end(va);
}
return GFX_write(gfx, buf, len);
}

91
GUI/Adafruit_GFX.h Normal file
View File

@@ -0,0 +1,91 @@
#ifndef _ADAFRUIT_GFX_H
#define _ADAFRUIT_GFX_H
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "u8g2_font.h"
#define GFX_BLACK 0x0000
#define GFX_WHITE 0xFFFF
#define GFX_RED 0xF800
typedef void (*buffer_callback)(uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h);
typedef enum {
GFX_ROTATE_0 = 0,
GFX_ROTATE_90 = 1,
GFX_ROTATE_180 = 2,
GFX_ROTATE_270 = 3,
} GFX_Rotate;
// GRAPHICS CONTEXT
typedef struct {
int16_t WIDTH; ///< This is the 'raw' display width - never changes
int16_t HEIGHT; ///< This is the 'raw' display height - never changes
int16_t _width; ///< Display width as modified by current rotation
int16_t _height; ///< Display height as modified by current rotation
GFX_Rotate rotation; ///< Display rotation (0 thru 3)
u8g2_font_t u8g2;
int16_t tx, ty; // current position for the print command
uint16_t encoding; // the unicode, detected by the utf-8 decoder
uint8_t utf8_state; // current state of the utf-8 decoder, contains the remaining bytes for a detected unicode glyph
uint8_t *buffer; // black pixel buffer
uint8_t *color; // color pixel buffer
int16_t page_height;
int16_t current_page;
int16_t total_pages;
} Adafruit_GFX;
// CONTROL API
void GFX_begin(Adafruit_GFX *gfx, int16_t w, int16_t h, int16_t buffer_height);
void GFX_begin_3c(Adafruit_GFX *gfx, int16_t w, int16_t h, int16_t buffer_height);
void GFX_setRotation(Adafruit_GFX *gfx, GFX_Rotate r);
void GFX_firstPage(Adafruit_GFX *gfx);
bool GFX_nextPage(Adafruit_GFX *gfx, buffer_callback callback);
void GFX_end(Adafruit_GFX *gfx);
// DRAW API
void GFX_drawPixel(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t color);
void GFX_drawLine(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
void GFX_drawFastVLine(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t h, uint16_t color);
void GFX_drawFastHLine(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w, uint16_t color);
void GFX_fillRect(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void GFX_fillScreen(Adafruit_GFX *gfx, uint16_t color);
void GFX_drawRect(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void GFX_drawCircle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r, uint16_t color);
void GFX_drawCircleHelper(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
uint16_t color);
void GFX_fillCircle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r, uint16_t color);
void GFX_fillCircleHelper(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
int16_t delta, uint16_t color);
void GFX_drawTriangle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2,
int16_t y2, uint16_t color);
void GFX_fillTriangle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2,
int16_t y2, uint16_t color);
void GFX_drawRoundRect(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t w, int16_t h,
int16_t radius, uint16_t color);
void GFX_fillRoundRect(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t w, int16_t h,
int16_t radius, uint16_t color);
void GFX_drawBitmap(Adafruit_GFX *gfx, int16_t x, int16_t y, const uint8_t bitmap[], int16_t w,
int16_t h, uint16_t color, bool invert);
// U8G2 FONT API
void GFX_setCursor(Adafruit_GFX *gfx, int16_t x, int16_t y);
void GFX_setFont(Adafruit_GFX *gfx, const uint8_t *font);
void GFX_setFontMode(Adafruit_GFX *gfx, uint8_t is_transparent);
void GFX_setFontDirection(Adafruit_GFX *gfx, GFX_Rotate d);
void GFX_setTextColor(Adafruit_GFX *gfx, uint16_t fg, uint16_t bg);
int8_t GFX_getFontAscent(Adafruit_GFX *gfx);
int8_t GFX_getFontDescent(Adafruit_GFX *gfx);
int16_t GFX_drawGlyph(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t e);
int16_t GFX_drawStr(Adafruit_GFX *gfx, int16_t x, int16_t y, const char *s);
int16_t GFX_drawUTF8(Adafruit_GFX *gfx, int16_t x, int16_t y, const char *str);
int16_t GFX_getUTF8Width(Adafruit_GFX *gfx, const char *str);
size_t GFX_print(Adafruit_GFX *gfx, const char c);
size_t GFX_write(Adafruit_GFX *gfx, const char *buffer, size_t size);
size_t GFX_printf(Adafruit_GFX *gfx, const char* format, ...);
#endif // _ADAFRUIT_GFX_H

106
GUI/Calendar.c Normal file
View File

@@ -0,0 +1,106 @@
#include "Adafruit_GFX.h"
#include "fonts.h"
#include "EPD_driver.h"
#include "Lunar.h"
#include "Calendar.h"
#define PAGE_HEIGHT 32
static void DrawDateHeader(Adafruit_GFX *gfx, int16_t x, int16_t y, tm_t *tm, struct Lunar_Date *Lunar)
{
GFX_setCursor(gfx, x, y);
GFX_setFont(gfx, u8g2_font_wqy12b_t_lunar);
GFX_setTextColor(gfx, GFX_BLACK, GFX_WHITE);
GFX_printf(gfx, "%d年%02d月%02d日 星期%s", tm->tm_year + YEAR0, tm->tm_mon + 1, tm->tm_mday, Lunar_DayString[tm->tm_wday]);
LUNAR_SolarToLunar(Lunar, tm->tm_year + YEAR0, tm->tm_mon + 1, tm->tm_mday);
GFX_setFont(gfx, u8g2_font_wqy9_t_lunar);
GFX_setCursor(gfx, x + 226, y);
GFX_printf(gfx, "农历: %s%s%s %s%s[%s]年", Lunar_MonthLeapString[Lunar->IsLeap], Lunar_MonthString[Lunar->Month],
Lunar_DateString[Lunar->Date], Lunar_StemStrig[LUNAR_GetStem(Lunar)],
Lunar_BranchStrig[LUNAR_GetBranch(Lunar)], Lunar_ZodiacString[LUNAR_GetZodiac(Lunar)]);
}
static void DrawWeekHeader(Adafruit_GFX *gfx, int16_t x, int16_t y)
{
GFX_setTextColor(gfx, GFX_WHITE, GFX_RED);
GFX_fillRect(gfx, x, y, 380, 18, GFX_RED);
for (int i = 0; i < 7; i++)
{
GFX_setCursor(gfx, x + 15 + i * 55, y + 14);
GFX_printf(gfx, "%s", Lunar_DayString[i]);
}
}
static void DrawMonthDay(Adafruit_GFX *gfx, int16_t x, int16_t y, tm_t *tm, struct Lunar_Date *Lunar, uint8_t day)
{
if (day == tm->tm_mday)
{
GFX_fillCircle(gfx, x + 10, y + 9, 22, GFX_RED);
GFX_setTextColor(gfx, GFX_WHITE, GFX_RED);
}
else
{
GFX_setTextColor(gfx, GFX_BLACK, GFX_WHITE);
}
GFX_setFont(gfx, u8g2_font_wqy12b_t_lunar);
GFX_setCursor(gfx, x + 2, y + 4);
GFX_printf(gfx, "%d", day);
GFX_setFont(gfx, u8g2_font_wqy9_t_lunar);
GFX_setCursor(gfx, x, y + 24);
uint8_t JQdate;
if (GetJieQi(tm->tm_year + YEAR0, tm->tm_mon + 1, day, &JQdate) && JQdate == day)
{
uint8_t JQ = (tm->tm_mon + 1 - 1) * 2;
if (day >= 15)
JQ++;
if (day != tm->tm_mday) GFX_setTextColor(gfx, GFX_RED, GFX_WHITE);
GFX_printf(gfx, "%s", JieQiStr[JQ]);
}
else
{
LUNAR_SolarToLunar(Lunar, tm->tm_year + YEAR0, tm->tm_mon + 1, day);
if (Lunar->Date == 1)
GFX_printf(gfx, "%s", Lunar_MonthString[Lunar->Month]);
else
GFX_printf(gfx, "%s", Lunar_DateString[Lunar->Date]);
}
}
void DrawCalendar(uint32_t timestamp)
{
tm_t tm = {0};
struct Lunar_Date Lunar;
epd_driver_t *driver = epd_driver_get();
transformTime(timestamp, &tm);
uint8_t firstDayWeek = get_first_day_week(tm.tm_year + YEAR0, tm.tm_mon + 1);
uint8_t monthMaxDays = thisMonthMaxDays(tm.tm_year + YEAR0, tm.tm_mon + 1);
Adafruit_GFX gfx;
if (driver->id == EPD_DRIVER_4IN2B_V2)
GFX_begin_3c(&gfx, driver->width, driver->height, PAGE_HEIGHT);
else
GFX_begin(&gfx, driver->width, driver->height, PAGE_HEIGHT);
GFX_firstPage(&gfx);
do {
GFX_fillScreen(&gfx, GFX_WHITE);
DrawDateHeader(&gfx, 10, 22, &tm, &Lunar);
DrawWeekHeader(&gfx, 10, 26);
for (uint8_t i = 0; i < monthMaxDays; i++)
{
DrawMonthDay(&gfx, 22 + (firstDayWeek + i) % 7 * 55, 60 + (firstDayWeek + i) / 7 * 50, &tm, &Lunar, i + 1);
}
} while(GFX_nextPage(&gfx, driver->write_image));
GFX_end(&gfx);
driver->display();
}

8
GUI/Calendar.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef __CALENDAR_H
#define __CALENDAR_H
#include <stdint.h>
void DrawCalendar(uint32_t timestamp);
#endif

550
GUI/Lunar.c Normal file
View File

@@ -0,0 +1,550 @@
#include "Lunar.h"
const char Lunar_MonthString[13][7] = {
"未知",
"正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月",
"冬月", "腊月"};
const char Lunar_MonthLeapString[2][4] = {
" ",
""};
const char Lunar_DateString[31][7] = {
"未知",
"初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十",
"十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
"廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"};
const char Lunar_DayString[7][4] = {
"",
"", "", "", "", "", ""};
const char Lunar_ZodiacString[12][4] = {
"", "", "", "", "", "", "", "", "", "", "", ""};
const char Lunar_StemStrig[10][4] = {
"", "", "", "", "", "", "", "", "", ""};
const char Lunar_BranchStrig[12][4] = {
"", "", "", "", "", "", "", "", "", "", "", ""};
/* 2000 ~ 2199 */
const uint32_t lunar_month_days[] = {
1997,
0x0000B26D, 0x0000125C, 0x0000192C, 0x00009A95, 0x00001A94, 0x00001B4A, 0x00004B55, 0x00000AD4, 0x0000F55B,
0x000004BA, 0x0000125A, 0x0000B92B, 0x0000152A, 0x00001694, 0x000096AA, 0x000015AA, 0x00012AB5, 0x00000974,
0x000014B6, 0x0000CA57, 0x00000A56, 0x00001526, 0x00008E95, 0x00000D54, 0x000015AA, 0x000049B5, 0x0000096C,
0x0000D4AE, 0x0000149C, 0x00001A4C, 0x0000BD26, 0x00001AA6, 0x00000B54, 0x00006D6A, 0x000012DA, 0x0001695D,
0x0000095A, 0x0000149A, 0x0000DA4B, 0x00001A4A, 0x00001AA4, 0x0000BB54, 0x000016B4, 0x00000ADA, 0x0000495B,
0x00000936, 0x0000F497, 0x00001496, 0x0000154A, 0x0000B6A5, 0x00000DA4, 0x000015B4, 0x00006AB6, 0x0000126E,
0x0001092F, 0x0000092E, 0x00000C96, 0x0000CD4A, 0x00001D4A, 0x00000D64, 0x0000956C, 0x0000155C, 0x0000125C,
0x0000792E, 0x0000192C, 0x0000FA95, 0x00001A94, 0x00001B4A, 0x0000AB55, 0x00000AD4, 0x000014DA, 0x00008A5D,
0x00000A5A, 0x0001152B, 0x0000152A, 0x00001694, 0x0000D6AA, 0x000015AA, 0x00000AB4, 0x000094BA, 0x000014B6,
0x00000A56, 0x00007527, 0x00000D26, 0x0000EE53, 0x00000D54, 0x000015AA, 0x0000A9B5, 0x0000096C, 0x000014AE,
0x00008A4E, 0x00001A4C, 0x00011D26, 0x00001AA4, 0x00001B54, 0x0000CD6A, 0x00000ADA, 0x0000095C, 0x0000949D,
0x0000149A, 0x00001A2A, 0x00005B25, 0x00001AA4, 0x0000FB52, 0x000016B4, 0x00000ABA, 0x0000A95B, 0x00000936,
0x00001496, 0x00009A4B, 0x0000154A, 0x000136A5, 0x00000DA4, 0x000015AC, 0x0000CAB6, 0x0000126E, 0x0000092E,
0x00008C97, 0x00000A96, 0x00000D4A, 0x00006DA5, 0x00000D54, 0x0000F56A, 0x0000155A, 0x00000A5C, 0x0000B92E,
0x0000152C, 0x00001A94, 0x00009D4A, 0x00001B2A, 0x00016B55, 0x00000AD4, 0x000014DA, 0x0000CA5D, 0x00000A5A,
0x0000151A, 0x0000BA95, 0x00001654, 0x000016AA, 0x00004AD5, 0x00000AB4, 0x0000F4BA, 0x000014B6, 0x00000A56,
0x0000B517, 0x00000D16, 0x00000E52, 0x000096AA, 0x00000D6A, 0x000165B5, 0x0000096C, 0x000014AE, 0x0000CA2E,
0x00001A2C, 0x00001D16, 0x0000AD52, 0x00001B52, 0x00000B6A, 0x0000656D, 0x0000055C, 0x0000F45D, 0x0000145A,
0x00001A2A, 0x0000DA95, 0x000016A4, 0x00001AD2, 0x00008B5A, 0x00000AB6, 0x0001455B, 0x000008B6, 0x00001456,
0x0000D52B, 0x0000152A, 0x00001694, 0x0000B6AA, 0x000015AA, 0x00000AB6, 0x000064B7, 0x000008AE, 0x0000EC57,
0x00000A56, 0x00000D2A, 0x0000CD95, 0x00000B54, 0x0000156A, 0x00008A6D, 0x0000095C, 0x000014AE, 0x00004A56,
0x00001A54, 0x0000DD2A, 0x00001AAA, 0x00000B54, 0x0000B56A, 0x000014DA, 0x0000095C, 0x000074AB, 0x0000149A,
0x0000FA4B, 0x00001652, 0x000016AA, 0x0000CAD5, 0x000005B4};
/* 2000 ~ 2199 */
const uint32_t solar_1_1[] = {
1997,
0x000F9C3C, 0x000F9E50, 0x000FA045, 0x000FA238, 0x000FA44C, 0x000FA641, 0x000FA836, 0x000FAA49, 0x000FAC3D,
0x000FAE52, 0x000FB047, 0x000FB23A, 0x000FB44E, 0x000FB643, 0x000FB837, 0x000FBA4A, 0x000FBC3F, 0x000FBE53,
0x000FC048, 0x000FC23C, 0x000FC450, 0x000FC645, 0x000FC839, 0x000FCA4C, 0x000FCC41, 0x000FCE36, 0x000FD04A,
0x000FD23D, 0x000FD451, 0x000FD646, 0x000FD83A, 0x000FDA4D, 0x000FDC43, 0x000FDE37, 0x000FE04B, 0x000FE23F,
0x000FE453, 0x000FE648, 0x000FE83C, 0x000FEA4F, 0x000FEC44, 0x000FEE38, 0x000FF04C, 0x000FF241, 0x000FF436,
0x000FF64A, 0x000FF83E, 0x000FFA51, 0x000FFC46, 0x000FFE3A, 0x0010004E, 0x00100242, 0x00100437, 0x0010064B,
0x00100841, 0x00100A53, 0x00100C48, 0x00100E3C, 0x0010104F, 0x00101244, 0x00101438, 0x0010164C, 0x00101842,
0x00101A35, 0x00101C49, 0x00101E3D, 0x00102051, 0x00102245, 0x0010243A, 0x0010264E, 0x00102843, 0x00102A37,
0x00102C4B, 0x00102E3F, 0x00103053, 0x00103247, 0x0010343B, 0x0010364F, 0x00103845, 0x00103A38, 0x00103C4C,
0x00103E42, 0x00104036, 0x00104249, 0x0010443D, 0x00104651, 0x00104846, 0x00104A3A, 0x00104C4E, 0x00104E43,
0x00105038, 0x0010524A, 0x0010543E, 0x00105652, 0x00105847, 0x00105A3B, 0x00105C4F, 0x00105E45, 0x00106039,
0x0010624C, 0x00106441, 0x00106635, 0x00106849, 0x00106A3D, 0x00106C51, 0x00106E47, 0x0010703C, 0x0010724F,
0x00107444, 0x00107638, 0x0010784C, 0x00107A3F, 0x00107C53, 0x00107E48, 0x0010803D, 0x00108250, 0x00108446,
0x0010863A, 0x0010884E, 0x00108A42, 0x00108C36, 0x00108E4A, 0x0010903E, 0x00109251, 0x00109447, 0x0010963B,
0x0010984F, 0x00109A43, 0x00109C37, 0x00109E4B, 0x0010A041, 0x0010A253, 0x0010A448, 0x0010A63D, 0x0010A851,
0x0010AA45, 0x0010AC39, 0x0010AE4D, 0x0010B042, 0x0010B236, 0x0010B44A, 0x0010B63E, 0x0010B852, 0x0010BA47,
0x0010BC3B, 0x0010BE4F, 0x0010C044, 0x0010C237, 0x0010C44B, 0x0010C641, 0x0010C854, 0x0010CA48, 0x0010CC3D,
0x0010CE50, 0x0010D045, 0x0010D239, 0x0010D44C, 0x0010D642, 0x0010D837, 0x0010DA4A, 0x0010DC3E, 0x0010DE52,
0x0010E047, 0x0010E23A, 0x0010E44E, 0x0010E643, 0x0010E838, 0x0010EA4B, 0x0010EC41, 0x0010EE54, 0x0010F049,
0x0010F23C, 0x0010F450, 0x0010F645, 0x0010F839, 0x0010FA4C, 0x0010FC42, 0x0010FE37, 0x0011004B, 0x0011023E,
0x00110452, 0x00110647, 0x0011083B, 0x00110A4E, 0x00110C43, 0x00110E38, 0x0011104C, 0x0011123F, 0x00111435,
0x00111648, 0x0011183C, 0x00111A4F, 0x00111C45, 0x00111E39, 0x0011204D, 0x00112242, 0x00112436, 0x0011264A,
0x0011283E, 0x00112A51, 0x00112C46, 0x00112E3B, 0x0011304F};
static uint32_t GetBitInt(uint32_t data, uint8_t length, uint8_t shift)
{
return (data & (((1 << length) - 1) << shift)) >> shift;
}
// WARNING: Dates before Oct. 1582 are inaccurate
static uint16_t SolarToInt(uint16_t y, uint8_t m, uint8_t d)
{
m = (m + 9) % 12;
y = y - m / 10;
return 365 * y + y / 4 - y / 100 + y / 400 + (m * 306 + 5) / 10 + (d - 1);
}
void LUNAR_SolarToLunar(struct Lunar_Date *lunar, uint16_t solar_year, uint8_t solar_month, uint8_t solar_date)
{
uint8_t i, lunarM, m, d, leap, dm;
uint16_t year_index, lunarY, y, offset;
uint32_t solar_data, solar11, days;
if (solar_month < 1 || solar_month > 12 || solar_date < 1 || solar_date > 31 ||
(solar_year - solar_1_1[0] < 3) || ((solar_year - solar_1_1[0]) > (sizeof(solar_1_1) / sizeof(uint32_t) - 2)))
{
lunar->Year = 0;
lunar->Month = 0;
lunar->Date = 0;
lunar->IsLeap = 0;
return;
}
year_index = solar_year - solar_1_1[0];
solar_data = ((uint32_t)solar_year << 9) | ((uint32_t)solar_month << 5) | ((uint32_t)solar_date);
if (solar_1_1[year_index] > solar_data)
{
year_index -= 1;
}
solar11 = solar_1_1[year_index];
y = GetBitInt(solar11, 12, 9);
m = GetBitInt(solar11, 4, 5);
d = GetBitInt(solar11, 5, 0);
offset = SolarToInt(solar_year, solar_month, solar_date) - SolarToInt(y, m, d);
days = lunar_month_days[year_index];
leap = GetBitInt(days, 4, 13);
lunarY = year_index + solar_1_1[0];
lunarM = 1;
offset += 1;
for (i = 0; i < 13; i++)
{
if (GetBitInt(days, 1, 12 - i) == 1)
{
dm = 30;
}
else
{
dm = 29;
}
if (offset > dm)
{
lunarM += 1;
offset -= dm;
}
else
{
break;
}
}
lunar->IsLeap = 0;
if (leap != 0 && lunarM > leap)
{
if (lunarM == leap + 1)
{
lunar->IsLeap = 1;
}
lunarM -= 1;
}
lunar->Month = lunarM;
lunar->Date = offset;
lunar->Year = lunarY;
}
uint8_t LUNAR_GetZodiac(const struct Lunar_Date *lunar)
{
return lunar->Year % 12;
}
uint8_t LUNAR_GetStem(const struct Lunar_Date *lunar)
{
return lunar->Year % 10;
}
uint8_t LUNAR_GetBranch(const struct Lunar_Date *lunar)
{
return lunar->Year % 12;
}
/*********************************************************************************************************
** 以下为24节气计算相关程序
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
/*
每年24节气标志表
有兴趣的朋友可按照上面给的原理添加其它年份的表格
不是很清楚的朋友可给我发EMAIL
*/
static const uint8_t YearMonthBit[160] =
{
0x4E, 0xA6, 0x99, // 2000
0x9C, 0xA2, 0x98, // 2001
0x80, 0x00, 0x18, // 2002
0x00, 0x10, 0x24, // 2003
0x4E, 0xA6, 0x99, // 2004
0x9C, 0xA2, 0x98, // 2005
0x80, 0x82, 0x18, // 2006
0x00, 0x10, 0x24, // 2007
0x4E, 0xA6, 0xD9, // 2008
0x9E, 0xA2, 0x98, // 2009
0x80, 0x82, 0x18, // 2010
0x00, 0x10, 0x04, // 2011
0x4E, 0xE6, 0xD9, // 2012
0x9E, 0xA6, 0xA8, // 2013
0x80, 0x82, 0x18, // 2014
0x00, 0x10, 0x00, // 2015
0x0F, 0xE6, 0xD9, // 2016
0xBE, 0xA6, 0x98, // 2017
0x88, 0x82, 0x18, // 2018
0x80, 0x00, 0x00, // 2019
0x0F, 0xEF, 0xD9, // 2020
0xBE, 0xA6, 0x99, // 2021
0x8C, 0x82, 0x98, // 2022
0x80, 0x00, 0x00, // 2023
0x0F, 0xEF, 0xDB, // 2024
0xBE, 0xA6, 0x99, // 2025
0x9C, 0xA2, 0x98, // 2026
0x80, 0x00, 0x18, // 2027
0x0F, 0xEF, 0xDB, // 2028
0xBE, 0xA6, 0x99, // 2029
0x9C, 0xA2, 0x98, // 2030
0x80, 0x00, 0x18, // 2031
0x0F, 0xEF, 0xDB, // 2032
0xBE, 0xA2, 0x99, // 2033
0x8C, 0xA0, 0x98, // 2034
0x80, 0x82, 0x18, // 2035
0x0B, 0xEF, 0xDB, // 2036
0xBE, 0xA6, 0x99, // 2037
0x8C, 0xA2, 0x98, // 2038
0x80, 0x82, 0x18, // 2039
0x0F, 0xEF, 0xDB, // 2040
0xBE, 0xE6, 0xD9, // 2041
0x9E, 0xA2, 0x98, // 2042
0x80, 0x82, 0x18, // 2043
0x0F, 0xEF, 0xFB, // 2044
0xBF, 0xE6, 0xD9, // 2045
0x9E, 0xA6, 0x98, // 2046
0x80, 0x82, 0x18, // 2047
0x0F, 0xFF, 0xFF, // 2048
0xFC, 0xEF, 0xD9, // 2049
0xBE, 0xA6, 0x18, // 2050
};
static const uint8_t days[24] =
{
6, 20, 4, 19, 6, 21, // 一月到三月 的节气基本日期
5, 20, 6, 21, 6, 21, // 四月到六月 的节气基本日期
7, 23, 8, 23, 8, 23, // 七月到九月 的节气基本日期
8, 24, 8, 22, 7, 22, // 十月到十二月的节气基本日期
};
/*立春、雨水、惊蛰、春分、清明、谷雨、立夏、小满、芒种、夏至、小暑、大暑、立秋、处暑、白露、秋分、寒露、霜降、立冬、小雪、大雪、冬至、小寒、大寒
*
*/
const char JieQiStr[24][7] = {
"小寒",
"大寒",
"立春",
"雨水",
"惊蛰",
"春分",
"清明",
"谷雨",
"立夏",
"小满",
"芒种",
"夏至",
"小暑",
"大暑",
"立秋",
"处暑",
"白露",
"秋分",
"寒露",
"霜降",
"立冬",
"小雪",
"大雪",
"冬至",
};
const uint8_t MonthDayMax[12] = {
31,
28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31,
};
/*********************************************************************************************************
** 函数名称:GetJieQi
** 功能描述:输入公历日期得到本月24节气日期 day<15返回上半月节气,反之返回下半月
** 如:GetJieQiStr(2007,02,08,str) 返回str[0]=4
** 输 入: year 公历年
** month 公历月
** day 公历日
** str 储存对应本月节气日期地址 1Byte
** 输 出: 1 成功
** 0 失败
** 作 者: 赖皮 ★〓个人原创〓★
** 日 期: 2007年02月08日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
uint8_t GetJieQi(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *JQdate)
{
uint8_t bak1, value, JQ;
if ((myear < 2000) || (myear > 2050))
return 0;
if ((mmonth == 0) || (mmonth > 12))
return 0;
JQ = (mmonth - 1) * 2; // 获得节气顺序标号(023
if (mday >= 15)
JQ++; // 判断是否是上半月
bak1 = YearMonthBit[(myear - 2000) * 3 + JQ / 8]; // 获得节气日期相对值所在字节
value = ((bak1 << (JQ % 8)) & 0x80); // 获得节气日期相对值状态
*JQdate = days[JQ];
if (value != 0)
{
// 判断年份,以决定节气相对值1代表1,还是1。
if ((JQ == 1 || JQ == 11 || JQ == 18 || JQ == 21) && myear < 2044)
(*JQdate)++;
else
(*JQdate)--;
}
return 1;
}
/*********************************************************************************************************
** 函数名称:GetJieQiStr位置
** 如:GetJieQiStr(2007,02,08,day) 返回str="离雨水还有11天" day式距离几天
** 输 入: year 公历年
** month 公历月
** day 公历日
** str 储存24节气字符串地址 15Byte
** 输 出: 1 成功
** 0xFF 失败
** 作 者: 赖皮 ★〓个人原创〓★
** 日 期: 2007年02月08日
**-------------------------------------------------------------------------------------------------------
** 修改人:
** 日 期:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
uint8_t GetJieQiStr(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *day)
{
uint8_t JQdate, JQ, MaxDay;
if (GetJieQi(myear, mmonth, mday, &JQdate) == 0)
return 0xFF;
JQ = (mmonth - 1) * 2; // 获得节气顺序标号(023
if (mday >= 15)
JQ++; // 判断是否是上半月
if (mday == JQdate) // 今天正是一个节气日
{
*day = 0;
return JQ;
}
// 今天不是一个节气日
// StrCopy(str, (uint8_t *)"离小寒还有??天", 15);
if (mday < JQdate) // 如果今天日期小于本月的节气日期
{
mday = JQdate - mday;
}
else // 如果今天日期大于本月的节气日期
{
JQ++;
if (mday < 15)
{
GetJieQi(myear, mmonth, 15, &JQdate);
mday = JQdate - mday;
}
else // 翻月
{
MaxDay = MonthDayMax[mmonth - 1];
if (mmonth == 2) // 润月问题
{
if ((myear % 4 == 0) && ((myear % 100 != 0) || (myear % 400 == 0)))
MaxDay++;
}
if (++mmonth == 13)
mmonth = 1;
GetJieQi(myear, mmonth, 1, &JQdate);
mday = MaxDay - mday + JQdate;
}
}
*day = mday;
return JQ;
}
uint32_t SEC_PER_YR[2] = {31536000, 31622400}; // 闰年和非闰年的秒数
uint32_t SEC_PER_MT[2][12] = {
{2678400, 2419200, 2678400, 2592000, 2678400, 2592000,
2678400, 2678400, 2592000, 2678400, 2592000, 2678400},
{2678400, 2505600, 2678400, 2592000, 2678400, 2592000,
2678400, 2678400, 2592000, 2678400, 2592000, 2678400},
};
#define SECOND_OF_DAY 86400 // 一天多少秒
/**
* @Name : static int is_leap(int yr)
* @Description: 判断是否为闰年
* "非整百年份能被4整除的是闰年。"
* "整百年份能被400整除的是闰年。"
* @In : 待机算的年份
* @Out : 1是闰年 0非闰年
* @Author : Denis
*/
int is_leap(int yr)
{
if (0 == (yr % 100))
return (yr % 400 == 0) ? 1 : 0;
else
return (yr % 4 == 0) ? 1 : 0;
}
/**
* @Name : static unsigned char day_of_week_get(unsigned char month, unsigned char day,
unsigned short year)
* @Description: 根据输入的年月日计算当天为星期几
* @In : 年、月、日
* @Out : 星期几
* @Author : Denis
*/
unsigned char day_of_week_get(unsigned char month, unsigned char day,
unsigned short year)
{
/* Month should be a number 0 to 11, Day should be a number 1 to 31 */
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
year -= (uint8_t)(month < 3);
return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7;
}
void transformTime(uint32_t unix_time, struct devtm *result)
{
int leapyr = 0;
uint32_t ltime = unix_time;
memset(result, 0, sizeof(struct devtm));
result->tm_year = EPOCH_YR;
while (1)
{
if (ltime < SEC_PER_YR[is_leap(result->tm_year)])
{
break;
}
ltime -= SEC_PER_YR[is_leap(result->tm_year)];
++(result->tm_year);
}
leapyr = is_leap(result->tm_year);
while (1)
{
if (ltime < SEC_PER_MT[leapyr][result->tm_mon])
break;
ltime -= SEC_PER_MT[leapyr][result->tm_mon];
++(result->tm_mon);
}
result->tm_mday = ltime / SEC_PER_DY;
++(result->tm_mday);
ltime = ltime % SEC_PER_DY;
result->tm_hour = ltime / SEC_PER_HR;
ltime = ltime % SEC_PER_HR;
result->tm_min = ltime / 60;
result->tm_sec = ltime % 60;
result->tm_wday =
day_of_week_get(result->tm_mon + 1, result->tm_mday,
result->tm_year);
/*
* The number of years since YEAR0"
*/
result->tm_year -= YEAR0;
}
uint8_t map[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/*
获取一个月最后一天值
*/
uint8_t get_last_day(uint16_t year, uint8_t month)
{
if (month % 12 == 1)
{
return map[month % 12] + is_leap(year);
}
return map[month % 12];
}
/*
获取一个月第一天星期值
*/
uint8_t get_first_day_week(uint16_t year, uint8_t month)
{
return day_of_week_get(month, 1, year);
}
// 时间结构体转时间戳
uint32_t transformTimeStruct(struct devtm *result)
{
uint32_t Cyear = 0;
for (uint16_t i = 1970; i < result->tm_year; i++)
{
if (is_leap(i) == 1)
Cyear++;
}
uint32_t CountDay = Cyear * (uint32_t)366 + (uint32_t)(result->tm_year - 1970 - Cyear) * (uint32_t)365 + result->tm_mday - 1;
for (uint8_t i = 0; i < result->tm_mon - 1; i++)
{
CountDay += get_last_day(result->tm_year, i);
}
return (CountDay * SECOND_OF_DAY + (uint32_t)result->tm_sec + (uint32_t)result->tm_min * 60 + (uint32_t)result->tm_hour * 3600);
}
uint8_t thisMonthMaxDays(uint8_t year, uint8_t month)
{
if (year % 4 == 0 && month == 2)
return MonthDayMax[month - 1] + 1;
else
return MonthDayMax[month - 1];
}

53
GUI/Lunar.h Normal file
View File

@@ -0,0 +1,53 @@
#ifndef _LUNAR_H_
#define _LUNAR_H_
#include <stdint.h>
#include <string.h>
#define YEAR0 (1900) /* The first year */
#define EPOCH_YR (1970) /* EPOCH = Jan 1 1970 00:00:00 */
#define SEC_PER_DY (86400) // 一天的秒数
#define SEC_PER_HR (3600) // 一小时的秒数
typedef struct devtm
{
uint16_t tm_year;
uint8_t tm_mon;
uint8_t tm_mday;
uint8_t tm_hour;
uint8_t tm_min;
uint8_t tm_sec;
uint8_t tm_wday;
} tm_t;
struct Lunar_Date
{
uint8_t IsLeap;
uint8_t Date;
uint8_t Month;
uint16_t Year;
};
extern const char Lunar_MonthString[13][7];
extern const char Lunar_MonthLeapString[2][4];
extern const char Lunar_DateString[31][7];
extern const char Lunar_DayString[7][4];
extern const char Lunar_ZodiacString[12][4];
extern const char Lunar_StemStrig[10][4];
extern const char Lunar_BranchStrig[12][4];
extern const char JieQiStr[24][7];
void LUNAR_SolarToLunar(struct Lunar_Date *lunar, uint16_t solar_year, uint8_t solar_month, uint8_t solar_date);
uint8_t LUNAR_GetZodiac(const struct Lunar_Date *lunar);
uint8_t LUNAR_GetStem(const struct Lunar_Date *lunar);
uint8_t LUNAR_GetBranch(const struct Lunar_Date *lunar);
uint8_t GetJieQiStr(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *day);
uint8_t GetJieQi(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *JQdate);
void transformTime(uint32_t unix_time, struct devtm *result);
uint32_t transformTimeStruct(struct devtm *result);
uint8_t get_first_day_week(uint16_t year, uint8_t month);
uint8_t get_last_day(uint16_t year, uint8_t month);
unsigned char day_of_week_get(unsigned char month, unsigned char day, unsigned short year);
uint8_t thisMonthMaxDays(uint8_t year, uint8_t month);
#endif

135
GUI/fonts.c Normal file
View File

@@ -0,0 +1,135 @@
#include "fonts.h"
/*
Fontname: -wenquanyi-wenquanyi bitmap song-medium-r-normal--12-120-75-75-P-119-ISO10646-1
Copyright: (null)
Glyphs: 96/30503
BBX Build Mode: 0
*/
const uint8_t u8g2_font_wqy9_t_lunar[3235] U8G2_FONT_SECTION("u8g2_font_wqy9_t_lunar") =
"\266\0\3\2\4\4\3\4\5\13\15\0\376\10\376\12\377\1a\2\317\4\30 \5\0L\13!\7\221F"
"\213S\0\42\7\64}\213\310\24#\16\226\304\233\250eX\242^\206%j\1$\17\245<\253l\251("
"\231\250%Je\213\0%\20\226<\233(\351\242%a\232DI\27-\1&\16\205D\253,\211\222\254"
"\62%Q\244\4'\6\61\376\212\1(\13\263=\253$J\242nQ\26)\14\263=\213,\312\242.Q"
"\22\1*\14uD\253J\345\240,M\21\0+\13wD\274\270\66\14Y\134\3,\7\62>\13E\1"
"-\6\25d\213A.\6!\306\12\1/\14\304<\273\246\254\224\225\262\32\0\60\12\205D\233%\363-"
"Y\0\61\11\205D\213\261O\203\0\62\13\205D\233%\13km\203\0\63\14\205D\213!\15\223\65\14"
"\7\5\64\16\206\304;-\211\272d\311\60\246\11\0\65\15\205D\213!\11\303!\15\303A\1\66\15\205"
"D\233%\14\207$\263%\13\0\67\13\205D\213A\254\205YX\2\70\15\205D\233%\323\222%\263%"
"\13\0\71\15\205D\233%\263%C\250%\13\0:\6aD\11I;\11\202>\213!V\24\0<\10"
"\225D\313\254k\7=\10\65\134\213A\35\4>\11\225D\213\264[G\0\77\15\225D\233%\323\302H"
"\313\241\60\2@\24\247<\254\255\222HZ\42)JE\251H\211\222e\23\0A\16\207D\274\70M\302"
"$+\15J\252\6B\15\206\304\213A\11\305a\11\215\303\2C\14\206\304\233!\11\325\216\311\220\0D"
"\15\207D\214A\12\223\324c\62H\0E\12\205D\213c\70\214\305AF\13\205D\213c\70$a#"
"\0G\15\206\304\233!\11\325\332(&\203\0H\13\206\304\213\320\70\14\242c\0I\10\203D\212%\352"
"eJ\10\243\64\252\376\264\0K\15\205D\213LJJ\232\226D\225,L\11\205D\213\260\217\203\0M"
"\20\207D\14m\310\226\212R\221\42)R\325\0N\15\206\304\213pS\42)\321Fc\0O\14\207D"
"\254\255\222\272&Y\66\1P\14\205D\213!\311l\203\22\26\1Q\16\227<\254\255\222\272&Y\266\3"
"\11\0R\20\206\304\213!\312\222,\311\222!jK\302\0S\14\205D\233AL\327\60\34\24\0T\11"
"\207D\214C\26\367\15U\12\206\304\213\320\217\311\220\0V\17\207D\214TM\262(\253\204I\32g\0"
"W\21\211D\215,\323\62\255\322)iJ\332\212Y\4X\15\206\304\213PL\242L\213ZB\61Y\13"
"\207D\214\64\311*i\334\15Z\12\207D\214C\332\347a\10[\11\263>\213!\352O\3\134\14\245<"
"\213\60\15\323\60\15\323\60]\11\263=\213\251\77\15\1^\10\65t\253,\251\5_\6\25<\213A`"
"\7\62\375\212$\12a\14eD\233%K\6MK\206\0b\14\205D\213\60\34\222\314mP\0c\10"
"d\304\232!k\34d\13\205D\313\312\240\271%C\0e\13eD\233%\33\206\60\35\2f\11\203D"
"\232i\210:\1g\14\205\64\233AsK\206\60Y\0h\13\205D\213\60\34\222\314[\0i\7\201D"
"\211d\30j\10\242\264\231,\351ek\15\205D\213\260\224\224\264$\252d\1l\7\201D\211\203\0m"
"\16gD\214E\211\42)\222\42)\222\12n\11eD\213!\311\274\5o\12eD\233%sK\26\0"
"p\14\205\64\213!\311\334\6%\14\1q\13\205\64\233AsK\206\260\0r\10cD\212!\352\4s"
"\14eD\233%K\324$K\26\0t\12\203D\212(\32\242\66\1u\11eD\213\314[\62\4v\14"
"eD\213LKJI\26F\0w\16gD\214(\222\42\245\242t\213\262\4x\13eD\213,\251U"
"jZ\0y\15\205\64\213LKJI\26fa\6z\12eD\213A\314\332\6\1{\13\243<\252$"
"\252dQ[\0|\7\261\276\212\7\1}\13\243<\212,\252%QK\4~\7&\334\33\311\2\200\17"
"\225D+\251\222\15Q\66Da\24)\0\0\0\0\4\377\377N\0\12+d~(\31\16\2N\1\25"
"\252=\216\207\64\207r(\207r(\207r(\207r`\4N\3\26\272=\316\34\312\241\34\312\304!\32"
"t(\207r(l\35\4N\11\17\253<\236\341\316\313\60\344|\34\16\2N\21\27\253<\236a\220\263"
"\70\213\263l\30\324\60\15\323\60\15\243\341 N\31\32\273<\216\7\65\307\342\341\224\225\62\251K\224\244"
"Q\16D\71\20\245\13\0NY\30\272=\216w$Gr$Gr$Gr$GrDG\222\341\0"
"N]\27\272=\276\34\312\241x\30\342(\216\342(\315\322,J\302H\36N\214\14\213D\236\341\316\77"
"\16\7\1N\224\26\253<\236\341\234c\71\226\3\207\70\213\263\70\213\263h\70\10N\245\27\272=\316\34"
"\13\207C\226#Y\70Hi\24J\231Y\212V\1QT\32\273<\276\34\33\324,\35.\245,\33\6"
"\71\207\222r\322\26e\211\70\4Qk\30\253D\356\34\210r \312\201(\7\262\70K\213i\226\3I"
"\16\5Qm\24\273<\316\34\314I\303Ag\314\342\260\34\345\210\16\5Q\234\33\273<\336x\70$Y"
"\250ia\224\3QMJ\262$+%Q*jq\0Q\254\30\273<\276\34\33T-\214\222\34\312\21"
"\333\24\315\71\240\203\71\30\2R\6\30\273<\276r\226\26\323,\7\222d\30\222\60\213\263\64\254F\242"
"\6R\35\33\273<\236\34\214\206\203T+\25\243D\211\42E\213*Q[\251\30%\231\2SA\27\273"
"<\336\34\313\261\34K\207\203\232c\71\226c\71\226c)\0SH\27\272=\256\34\32\206(\13\353P"
"\70\34\322\34\312\241\34\312\241\20So\33\272=\276x\32\306LJ\62)\311\244$S\224l\351\226D"
"Y\24j!\0S\206\32\273<\256\341\224c\345,N\206!\312JY\251\230da\22\245R\250\0V"
"\333\30\251=\216\207(\211\244$\222\222HJ\42%\32f\35x\320\201\0X\354\30\273<~ \207\266"
"A\307r\254\62\34\324\34\313\261\34\213\262\341\2Y\4\32\273<\256\60\15\323!I\243D\253\364\324\22"
"\305Y\232Da&\306C\0Y\17\31\273<\216\7\65G\206\65L\247\64\31\322\60\34\206,\252\205\362"
"\64\4Y'\30\273<\336\34\313\261t\70\250\71\226CI\216\324\201,-\351\200\0[P\30\273<\256"
"a\310\241\34\312\241\34K\207\203\232c\71\226#u(\6[\305\31\273<\336tx\207\224aH\322\34"
"\70\204Qq\30\302\250\70\14\321:[\322\33\273<\336tx\213\42e\30\222\60\312\206\203\30\305I\24"
"m\212\250\203\32\0\134\17\30\273<\336\34\313\261\34\210\212Q\26e\245,\24\253\71R\207b\0]\362"
"\26\252=\216\203\16\345P\71\32\6)\207rDGt$\31\16]\363\30\272=\216\203\24Gq\24G"
"\303 \345P\16\345\210\216\350H\62\34^t\27\273<\256\34\33.a\65\36\6\255\234\205\303A\316\261"
"\34\13\1^\232\33\273<\356x\70eq\62l\245l\70eQ\226\14[\224\204Q\26%\252\0^\377"
"\30\273<\276\60\15\323\60\32\16Z\230\206i\230\206i\230\16k\30\1`\312\36\273<\256\60M\206A"
"\321\201$\31\226R\226\224\6-L\243\244\226D%\245T\13\1b\12\31\273<\356$G\242l\70e"
"q\26e\245,\24KI\230\264e\223\32b\14\33\273<\356$G\242l\70eq\26e\203\224U\302"
"j&%Y\224H\242\0e\345\15\247>\216\203j\35\256\326\341\32e\366\34\273<~$\32\302(\32"
"NaT\211\242!J\242\226\250\30\25\243!\314\221\11f\16\31\273<\356\341\224I\65)\32N\231T"
"\223\242\341\224\245a-\211\324\4f\37\33\273<\256a\10\323p\30\302\64\34\206\60\212\207K\230\3\207"
"\34H\207\203\0f%\32\273<\336x\70\244\71pP\343\341 \211\212\62%Y\62\244a:L\0f"
"\221\33\273<\256a\10\323p\30\302\64\33\316I\66\34\304,\34\206H\11\323a\2g\10\31\271=\256"
"a\210\322(\215\206!J\243\64\32\206(\215\322$L\344\4g\37 \273<\236(\32\16I\224D-"
"C\64$Q\313\20U\242h\70$Q\16DIT\22%\1g*\27\273<\336\34\213\207s:\34\324"
"\34\332\201\244\32\225\264LM\1kc\32\253<\216\7\65\307r \312\201h\320\242\34\210r \312\201"
"(\35\16\2l\64\30\273<\336\34\313\261\312\220(iRN\252Q\61\252\265DIX\6n\5\36\273"
"<\236\264\62\14\71\220E\311 %Y\232\14CTK\264%\312\222)+e\221\2n\341 \273<\236"
"\60\11\223a\310\242$\212\206A\11\223\60\31\206(i\231\222NJ\242D-Q(r[\27\272=\336"
"\70\212\243t\30\224\60\207\302\341\220\346P\16\345P\10r\327\35\273<\216\250\232Dq\64,\215\222\262"
"DR\322)I\244h\311\342\244\226di\4s* \273<\216,\252T\206$\12\223(I\206!\312"
"RiP*\232\244\14Z\224%\245A\312\12s\64 \273<\216\244\62D\305\244\62\14\321\22'\311\240"
"\230*\265\60\31\206(\311\242\244\224D\225,u\62\26\271=\216\207,\323\262\341\240eZ\66\34\264b"
"\216\344H\10u\63\26\271=\316\34\11\207C\226\15\7-\323\262\341\240\25s$\4vx\32\273<\236"
"a\211\243\226(\11[\206$\312B\61\36\16i\222\3Y\266\12v}\20\270>\276\70\35\316\362p\210"
"\315\303!\16w\345\33\273<\256\34\313\241A\31\244,\312J\303)+e\245JT\311\222A\307\0y"
"\313\35\273<>)\33\323\60I\206\245\26%\332RT\242,\311\222\60K\302(\253\244\1y\315\33\273"
"<>)\33\323hx\211Z\242H)%\312\60(a\32\246a\32f\0y\322\33\273<\276\332\230F"
"IeHJ-Q\262\24\225(R\342,\15\63\65Q\1z\313\30\273<\336\34L\207CN\10\323\60"
"\216r \312\201$\307\302\341 \177\212\27\273<\256\264\26\16\347\34\313\201C\16\344X:\34\324\34K"
"\1\201J#\273<\236)\311\222(\311\222d\220\246$K\206A\251#\7)\251EI\62(Q\222%"
"\211\62(\0\201\363\27\273<\236\341\232CYZ\33\316\71\226\3\207\34\310\261t\70\10\202\222\30\273<"
"\276\332p\320\352H\16\206\303A\312\261\34\313\261\34\33\6\5\206N\34\273<\336A\216\207C\22\205\321"
"\60hQ\232D\303\220\344X\64\204QI\21\7\206\307\32\273<\256\60-F\303\243\322\230\64%\203\62"
"fqR\213\226l\212\206\0\206\360\36\273<\256\60\33\222A\13\223d\210\224\254\42Ia\64\14Z\224"
"e\303 g\311p\11\214\67\32\273<\316(\16KY\224ia\24\207\341\60(J\230da:\254a"
"\4\217\233\27\273<\336x\270\245\251\224\3I\70\34\324x\70\347X\216\245\0\217\260\34\273<\256\341\224"
"c\311\260\345\330pJ\312I)K\42-\312JI\224db\0\221I\33\273<\216\7\61\311\221\352p"
"\252D-Q\264M\71\20\15\247\34\210\206\13\0\225\360\33\273<\256h\30\242X\207\244A\22C\61\224"
"\6I\14\305P\31\206D\7\6\226M\36\273<\216!\12\243hX\42)Q\245$\222\246\254\224\14\203"
"\322\226$\303 gq\6\226\350\30\273<\216\7\65\307\342\341\224\225\222N\221\247J\247\254\224E\12\0"
"\226\352\31\273<\236\341\234\16\217\241\242$J\216\16w,\33\6\35\213\206\13\0\227\34\35\273<\236\341"
"\234\16OI\251\66$\203\22e\331\220I%%\31\222NY\66$\0\227\62\36\273<\236\341\234\16O"
"Ii\220\206$J\244d\310\304HZ\16I-J\206hH\0\232l\30\273<\236a\320\261\64L\263"
"\64L\207;\226c\303)\307rD\1\236!\35\273<~ \33\222AL\262$J\232\222nQ\61\32"
"\226r\22\15\212\16\345\210\2\237 \36\272=\216!\31\222\34H\206dHr \31\356\240\244DIE"
"\262$J\313\240L\1\237\231\32\273<\316(\7\262\70\36\16b\222#\245\60J\322H\315*\231I\32"
"\2\0";
/*
Fontname: -wenquanyi-wenquanyi bitmap song-bold-r-normal--16-160-75-75-P-80-iso10646-1
Copyright: (null)
Glyphs: 21/29889
BBX Build Mode: 0
*/
const uint8_t u8g2_font_wqy12b_t_lunar[491] U8G2_FONT_SECTION("u8g2_font_wqy12b_t_lunar") =
"\25\0\4\3\5\5\3\4\6\20\20\0\376\13\375\14\374\0\0\0\0\0\253\60\16g\25S\231\221P\303"
"o$\324\214\0\61\13f\25S\221\31!\322O\14\62\15g\25\323\250\220\241\221R\244W\7\63\21h"
"\21\323(\221\221\23\223\222\241SF#R\2\64\25h\21\323\222\32\242\221\20Q!#!#q\20%"
"\246\2\0\65\21h\21S\270\20Sf\62\42'&F#R\2\66\24h\21S\241\21\221\20\23\63\31"
"\221\20b$!\42C\2\67\21h\21S\70\10\223\22\223\22\223\22S%&\4\70\23h\21S\241\21"
"\321\33\32\21\11!F\22\42\62$\0\71\24h\21S\241\21\221\20b$!\62b\246BD\206\4\0"
"\0\0\0\4\377\377N\0\10\60\320cx N\11\20\220\21\343\70\270\307\335A=\336\35\34\10N\214"
"\15P\61c\71\250\307\237\36\34\10N\224\36\320\361\342\70\270\23\327\364\200PHPHPHPHN"
"JNJNJ\346\340@\0Qm \360\361b\223\7\220\7\20\227\207;\70\220G'\42*#(%"
"'&%'$)\42*\1V\333\37\256\365bx \242\204D\11\211\22\22%$J(dD(\204"
"\16\4+I\17\16H\5^t\37\20\322\342\21\27\77\250\21\22\24\222\223\222<\240\222\221\224\221\224\21"
";\70\20\24\327\31\0e\345\20\352\335b\70(\343\331\301\31\237\35\234\11f\37\36\316\365b\71\30\22"
"\23:\30\22\23:\30T\42x@\42#&$x\60(,vpg\10&\15\332\342\71\230\21\223\21"
"\223\21\223\21\223\71\230\21\223\21\223\21\223\71\230\21\223\21\23\221\23\221\223\20\63\224\0g\37.\17\322"
"bQ)\42aq\60\242\205\210\26\42\42\26&*D\264\20\21\261\20\321\302D\205\310\201\211\224\204\214"
"\210\10\215\204\220\210\221\12\0\0";

37
GUI/fonts.h Normal file
View File

@@ -0,0 +1,37 @@
#ifndef _FONTS_H
#define _FONTS_H
#include "u8g2_font.h"
/**
* 文字列表:
所有 ASCII 字符 (32-128)
未知
农历
正月二月三月四月五月六月七月八月九月十月
冬月腊月
初一初二初三初四初五初六初七初八初九初十
十一十二十三十四十五十六十七十八十九二十
廿一廿二廿三廿四廿五廿六廿七廿八廿九三十
一二三四五六
猴鸡狗猪鼠牛虎兔龙蛇马羊
庚辛壬癸甲乙丙丁戊已
申酉戌亥子丑寅卯辰巳午未
小寒大寒立春雨水惊蛰春分清明谷雨立夏小满芒种夏至小暑大暑立秋处暑白露秋分寒露霜降立冬小雪大雪冬至
年月日时分秒
星期
*/
extern const uint8_t u8g2_font_wqy9_t_lunar[] U8G2_FONT_SECTION("u8g2_font_wqy9_t_lunar");
/**
* 文字列表:
0123456789
年月日
星期
一二三四五六
*/
extern const uint8_t u8g2_font_wqy12b_t_lunar[] U8G2_FONT_SECTION("u8g2_font_wqy12b_t_lunar");
#endif

573
GUI/u8g2_font.c Normal file
View File

@@ -0,0 +1,573 @@
/*
U8g2_for_Adafruit_GFX.cpp
Add unicode support and U8g2 fonts to Adafruit GFX libraries.
U8g2 for Adafruit GFX Lib (https://github.com/olikraus/U8g2_for_Adafruit_GFX)
Copyright (c) 2018, olikraus@gmail.com
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.
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 THE COPYRIGHT HOLDER OR
CONTRIBUTORS 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 <stddef.h>
#include "u8g2_font.h"
static uint8_t u8g2_font_get_byte(const uint8_t *font, uint8_t offset)
{
font += offset;
return u8x8_pgm_read( font );
}
static uint16_t u8g2_font_get_word(const uint8_t *font, uint8_t offset) U8X8_NOINLINE;
static uint16_t u8g2_font_get_word(const uint8_t *font, uint8_t offset)
{
uint16_t pos;
font += offset;
pos = u8x8_pgm_read( font );
font++;
pos <<= 8;
pos += u8x8_pgm_read( font);
return pos;
}
/*========================================================================*/
/* new font format */
void u8g2_read_font_info(u8g2_font_info_t *font_info, const uint8_t *font)
{
/* offset 0 */
font_info->glyph_cnt = u8g2_font_get_byte(font, 0);
font_info->bbx_mode = u8g2_font_get_byte(font, 1);
font_info->bits_per_0 = u8g2_font_get_byte(font, 2);
font_info->bits_per_1 = u8g2_font_get_byte(font, 3);
/* offset 4 */
font_info->bits_per_char_width = u8g2_font_get_byte(font, 4);
font_info->bits_per_char_height = u8g2_font_get_byte(font, 5);
font_info->bits_per_char_x = u8g2_font_get_byte(font, 6);
font_info->bits_per_char_y = u8g2_font_get_byte(font, 7);
font_info->bits_per_delta_x = u8g2_font_get_byte(font, 8);
/* offset 9 */
font_info->max_char_width = u8g2_font_get_byte(font, 9);
font_info->max_char_height = u8g2_font_get_byte(font, 10);
font_info->x_offset = u8g2_font_get_byte(font, 11);
font_info->y_offset = u8g2_font_get_byte(font, 12);
/* offset 13 */
font_info->ascent_A = u8g2_font_get_byte(font, 13);
font_info->descent_g = u8g2_font_get_byte(font, 14);
font_info->ascent_para = u8g2_font_get_byte(font, 15);
font_info->descent_para = u8g2_font_get_byte(font, 16);
/* offset 17 */
font_info->start_pos_upper_A = u8g2_font_get_word(font, 17);
font_info->start_pos_lower_a = u8g2_font_get_word(font, 19);
/* offset 21 */
font_info->start_pos_unicode = u8g2_font_get_word(font, 21);
}
uint8_t u8g2_GetFontBBXWidth(u8g2_font_t *u8g2)
{
return u8g2->font_info.max_char_width; /* new font info structure */
}
uint8_t u8g2_GetFontBBXHeight(u8g2_font_t *u8g2)
{
return u8g2->font_info.max_char_height; /* new font info structure */
}
int8_t u8g2_GetFontBBXOffX(u8g2_font_t *u8g2)
{
return u8g2->font_info.x_offset; /* new font info structure */
}
int8_t u8g2_GetFontBBXOffY(u8g2_font_t *u8g2)
{
return u8g2->font_info.y_offset; /* new font info structure */
}
uint8_t u8g2_GetFontCapitalAHeight(u8g2_font_t *u8g2)
{
return u8g2->font_info.ascent_A; /* new font info structure */
}
static uint8_t u8g2_font_decode_get_unsigned_bits(u8g2_font_decode_t *f, uint8_t cnt) U8X8_NOINLINE;
static uint8_t u8g2_font_decode_get_unsigned_bits(u8g2_font_decode_t *f, uint8_t cnt)
{
uint8_t val;
uint8_t bit_pos = f->decode_bit_pos;
uint8_t bit_pos_plus_cnt;
//val = *(f->decode_ptr);
val = u8x8_pgm_read( f->decode_ptr );
val >>= bit_pos;
bit_pos_plus_cnt = bit_pos;
bit_pos_plus_cnt += cnt;
if ( bit_pos_plus_cnt >= 8 )
{
uint8_t s = 8;
s -= bit_pos;
f->decode_ptr++;
//val |= *(f->decode_ptr) << (8-bit_pos);
val |= u8x8_pgm_read( f->decode_ptr ) << (s);
//bit_pos -= 8;
bit_pos_plus_cnt -= 8;
}
val &= (1U<<cnt)-1;
//bit_pos += cnt;
f->decode_bit_pos = bit_pos_plus_cnt;
return val;
}
/*
2 bit --> cnt = 2
-2,-1,0. 1
3 bit --> cnt = 3
-2,-1,0. 1
-4,-3,-2,-1,0,1,2,3
if ( x < 0 )
r = bits(x-1)+1;
else
r = bits(x)+1;
*/
/* optimized */
static int8_t u8g2_font_decode_get_signed_bits(u8g2_font_decode_t *f, uint8_t cnt) U8X8_NOINLINE;
static int8_t u8g2_font_decode_get_signed_bits(u8g2_font_decode_t *f, uint8_t cnt)
{
int8_t v, d;
v = (int8_t)u8g2_font_decode_get_unsigned_bits(f, cnt);
d = 1;
cnt--;
d <<= cnt;
v -= d;
return v;
//return (int8_t)u8g2_font_decode_get_unsigned_bits(f, cnt) - ((1<<cnt)>>1);
}
static int16_t u8g2_add_vector_y(int16_t dy, int8_t x, int8_t y, uint8_t dir) U8X8_NOINLINE;
static int16_t u8g2_add_vector_y(int16_t dy, int8_t x, int8_t y, uint8_t dir)
{
switch(dir)
{
case 0:
dy += y;
break;
case 1:
dy += x;
break;
case 2:
dy -= y;
break;
default:
dy -= x;
break;
}
return dy;
}
static int16_t u8g2_add_vector_x(int16_t dx, int8_t x, int8_t y, uint8_t dir) U8X8_NOINLINE;
static int16_t u8g2_add_vector_x(int16_t dx, int8_t x, int8_t y, uint8_t dir)
{
switch(dir)
{
case 0:
dx += x;
break;
case 1:
dx -= y;
break;
case 2:
dx -= x;
break;
default:
dx += y;
break;
}
return dx;
}
/*
Description:
Draw a run-length area of the glyph. "len" can have any size and the line
length has to be wrapped at the glyph border.
Args:
len: Length of the line
is_foreground foreground/background?
u8g2->font_decode.target_x X position
u8g2->font_decode.target_y Y position
u8g2->font_decode.is_transparent Transparent mode
Return:
-
Calls:
u8g2_Draw90Line()
Called by:
u8g2_font_decode_glyph()
*/
/* optimized */
static void u8g2_font_decode_len(u8g2_font_t *u8g2, uint8_t len, uint8_t is_foreground)
{
uint8_t cnt; /* total number of remaining pixels, which have to be drawn */
uint8_t rem; /* remaining pixel to the right edge of the glyph */
uint8_t current; /* number of pixels, which need to be drawn for the draw procedure */
/* current is either equal to cnt or equal to rem */
/* local coordinates of the glyph */
uint8_t lx,ly;
/* target position on the screen */
int16_t x, y;
u8g2_font_decode_t *decode = &(u8g2->font_decode);
cnt = len;
/* get the local position */
lx = decode->x;
ly = decode->y;
for(;;)
{
/* calculate the number of pixel to the right edge of the glyph */
rem = decode->glyph_width;
rem -= lx;
/* calculate how many pixel to draw. This is either to the right edge */
/* or lesser, if not enough pixel are left */
current = rem;
if ( cnt < rem )
current = cnt;
/* now draw the line, but apply the rotation around the glyph target position */
//u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground);
/* get target position */
x = decode->target_x;
y = decode->target_y;
/* apply rotation */
x = u8g2_add_vector_x(x, lx, ly, decode->dir);
y = u8g2_add_vector_y(y, lx, ly, decode->dir);
/* draw foreground and background (if required) */
if ( current > 0 ) /* avoid drawing zero length lines, issue #4 */
{
if ( is_foreground )
{
u8g2->draw_hv_line(x, y, current, decode->dir, decode->fg_color, u8g2->draw_hv_line_arg);
}
else if ( decode->is_transparent == 0 )
{
u8g2->draw_hv_line(x, y, current, decode->dir, decode->bg_color, u8g2->draw_hv_line_arg);
}
}
/* check, whether the end of the run length code has been reached */
if ( cnt < rem )
break;
cnt -= rem;
lx = 0;
ly++;
}
lx += cnt;
decode->x = lx;
decode->y = ly;
}
static void u8g2_font_setup_decode(u8g2_font_t *u8g2, const uint8_t *glyph_data)
{
u8g2_font_decode_t *decode = &(u8g2->font_decode);
decode->decode_ptr = glyph_data;
decode->decode_bit_pos = 0;
/* 8 Nov 2015, this is already done in the glyph data search procedure */
/*
decode->decode_ptr += 1;
decode->decode_ptr += 1;
*/
decode->glyph_width = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_char_width);
decode->glyph_height = u8g2_font_decode_get_unsigned_bits(decode,u8g2->font_info.bits_per_char_height);
}
/*
Description:
Decode and draw a glyph.
Args:
glyph_data: Pointer to the compressed glyph data of the font
u8g2->font_decode.target_x X position
u8g2->font_decode.target_y Y position
u8g2->font_decode.is_transparent Transparent mode
Return:
Width (delta x advance) of the glyph.
Calls:
u8g2_font_decode_len()
*/
/* optimized */
static int8_t u8g2_font_decode_glyph(u8g2_font_t *u8g2, const uint8_t *glyph_data)
{
uint8_t a, b;
int8_t x, y;
int8_t d;
int8_t h;
u8g2_font_decode_t *decode = &(u8g2->font_decode);
u8g2_font_setup_decode(u8g2, glyph_data);
h = u8g2->font_decode.glyph_height;
x = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_x);
y = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_y);
d = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_delta_x);
if ( decode->glyph_width > 0 )
{
decode->target_x = u8g2_add_vector_x(decode->target_x, x, -(h+y), decode->dir);
decode->target_y = u8g2_add_vector_y(decode->target_y, x, -(h+y), decode->dir);
//u8g2_add_vector(&(decode->target_x), &(decode->target_y), x, -(h+y), decode->dir);
/* reset local x/y position */
decode->x = 0;
decode->y = 0;
/* decode glyph */
for(;;)
{
a = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_0);
b = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_1);
do
{
u8g2_font_decode_len(u8g2, a, 0);
u8g2_font_decode_len(u8g2, b, 1);
} while( u8g2_font_decode_get_unsigned_bits(decode, 1) != 0 );
if ( decode->y >= h )
break;
}
}
return d;
}
/*
Description:
Find the starting point of the glyph data.
Args:
encoding: Encoding (ASCII or Unicode) of the glyph
Return:
Address of the glyph data or NULL, if the encoding is not avialable in the font.
*/
const uint8_t *u8g2_font_get_glyph_data(u8g2_font_t *u8g2, uint16_t encoding)
{
const uint8_t *font = u8g2->font;
font += 23;
if ( encoding <= 255 )
{
if ( encoding >= 'a' )
{
font += u8g2->font_info.start_pos_lower_a;
}
else if ( encoding >= 'A' )
{
font += u8g2->font_info.start_pos_upper_A;
}
for(;;)
{
if ( u8x8_pgm_read( font + 1 ) == 0 )
break;
if ( u8x8_pgm_read( font ) == encoding )
{
return font+2; /* skip encoding and glyph size */
}
font += u8x8_pgm_read( font + 1 );
}
}
else
{
uint16_t e;
const uint8_t *unicode_lookup_table;
/* support for the new unicode lookup table */
font += u8g2->font_info.start_pos_unicode;
unicode_lookup_table = font;
/* u8g2 issue 596: search for the glyph start in the unicode lookup table */
do
{
font += u8g2_font_get_word(unicode_lookup_table, 0);
e = u8g2_font_get_word(unicode_lookup_table, 2);
unicode_lookup_table+=4;
} while( e < encoding );
/* variable "font" is now updated according to the lookup table */
for(;;)
{
e = u8x8_pgm_read( font );
e <<= 8;
e |= u8x8_pgm_read( font + 1 );
if ( e == 0 )
break;
if ( e == encoding )
{
return font+3; /* skip encoding and glyph size */
}
font += u8x8_pgm_read( font + 2 );
}
}
return NULL;
}
static int16_t u8g2_font_draw_glyph(u8g2_font_t *u8g2, int16_t x, int16_t y, uint16_t encoding)
{
int16_t dx = 0;
u8g2->font_decode.target_x = x;
u8g2->font_decode.target_y = y;
//u8g2->font_decode.is_transparent = is_transparent; this is already set
//u8g2->font_decode.dir = dir;
const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, encoding);
if ( glyph_data != NULL )
{
dx = u8g2_font_decode_glyph(u8g2, glyph_data);
}
return dx;
}
//========================================================
uint8_t u8g2_IsGlyph(u8g2_font_t *u8g2, uint16_t requested_encoding)
{
/* updated to new code */
if ( u8g2_font_get_glyph_data(u8g2, requested_encoding) != NULL )
return 1;
return 0;
}
/* side effect: updates u8g2->font_decode and u8g2->glyph_x_offset */
/* actually u8g2_GetGlyphWidth returns the glyph delta x and glyph width itself is set as side effect */
int8_t u8g2_GetGlyphWidth(u8g2_font_t *u8g2, uint16_t requested_encoding)
{
const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, requested_encoding);
if ( glyph_data == NULL )
return 0;
u8g2_font_setup_decode(u8g2, glyph_data);
u8g2->glyph_x_offset = u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_char_x);
u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_char_y);
/* glyph width is here: u8g2->font_decode.glyph_width */
return u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_delta_x);
}
void u8g2_SetFontMode(u8g2_font_t *u8g2, uint8_t is_transparent)
{
u8g2->font_decode.is_transparent = is_transparent; // new font procedures
}
void u8g2_SetFontDirection(u8g2_font_t *u8g2, uint8_t dir)
{
u8g2->font_decode.dir = dir;
}
int16_t u8g2_DrawGlyph(u8g2_font_t *u8g2, int16_t x, int16_t y, uint16_t encoding)
{
return u8g2_font_draw_glyph(u8g2, x, y, encoding);
}
int16_t u8g2_DrawStr(u8g2_font_t *u8g2, int16_t x, int16_t y, const char *s)
{
int16_t sum, delta;
sum = 0;
while( *s != '\0' )
{
delta = u8g2_DrawGlyph(u8g2, x, y, *s);
switch(u8g2->font_decode.dir)
{
case 0:
x += delta;
break;
case 1:
y += delta;
break;
case 2:
x -= delta;
break;
case 3:
y -= delta;
break;
}
sum += delta;
s++;
}
return sum;
}
void u8g2_SetFont(u8g2_font_t *u8g2, const uint8_t *font)
{
if ( u8g2->font != font )
{
u8g2->font = font;
u8g2->font_decode.is_transparent = 0;
u8g2_read_font_info(&(u8g2->font_info), font);
}
}
void u8g2_SetForegroundColor(u8g2_font_t *u8g2, uint16_t fg)
{
u8g2->font_decode.fg_color = fg;
}
void u8g2_SetBackgroundColor(u8g2_font_t *u8g2, uint16_t bg)
{
u8g2->font_decode.bg_color = bg;
}

157
GUI/u8g2_font.h Normal file
View File

@@ -0,0 +1,157 @@
/*
U8g2_for_Adafruit_GFX.h
Add unicode support and U8g2 fonts to Adafruit GFX libraries.
U8g2 for Adafruit GFX Lib (https://github.com/olikraus/U8g2_for_Adafruit_GFX)
Copyright (c) 2018, olikraus@gmail.com
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.
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 THE COPYRIGHT HOLDER OR
CONTRIBUTORS 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.
*/
#ifndef __U8G2_H
#define __U8G2_H
#include <stdint.h>
#ifdef __GNUC__
# define U8X8_NOINLINE __attribute__((noinline))
# define U8X8_SECTION(name) __attribute__ ((section (name)))
# define U8X8_UNUSED __attribute__((unused))
#else
# define U8X8_SECTION(name)
# define U8X8_NOINLINE
# define U8X8_UNUSED
#endif
#if defined(__GNUC__) && defined(__AVR__)
# define U8X8_FONT_SECTION(name) U8X8_SECTION(".progmem." name)
# define u8x8_pgm_read(adr) pgm_read_byte_near(adr)
# define U8X8_PROGMEM PROGMEM
#endif
#ifndef U8X8_FONT_SECTION
# define U8X8_FONT_SECTION(name)
#endif
#ifndef u8x8_pgm_read
# define u8x8_pgm_read(adr) (*(const uint8_t *)(adr))
#endif
#ifndef U8X8_PROGMEM
# define U8X8_PROGMEM
#endif
#define U8G2_FONT_SECTION(name) U8X8_FONT_SECTION(name)
/* the macro U8G2_USE_LARGE_FONTS enables large fonts (>32K) */
/* it can be enabled for those uC supporting larger arrays */
#if defined(unix) || defined(__arm__) || defined(__arc__) || defined(ESP8266) || defined(ESP_PLATFORM)
#ifndef U8G2_USE_LARGE_FONTS
#define U8G2_USE_LARGE_FONTS
#endif
#endif
typedef struct _u8g2_font_info_t
{
/* offset 0 */
uint8_t glyph_cnt;
uint8_t bbx_mode;
uint8_t bits_per_0;
uint8_t bits_per_1;
/* offset 4 */
uint8_t bits_per_char_width;
uint8_t bits_per_char_height;
uint8_t bits_per_char_x;
uint8_t bits_per_char_y;
uint8_t bits_per_delta_x;
/* offset 9 */
int8_t max_char_width;
int8_t max_char_height; /* overall height, NOT ascent. Instead ascent = max_char_height + y_offset */
int8_t x_offset;
int8_t y_offset;
/* offset 13 */
int8_t ascent_A;
int8_t descent_g; /* usually a negative value */
int8_t ascent_para;
int8_t descent_para;
/* offset 17 */
uint16_t start_pos_upper_A;
uint16_t start_pos_lower_a;
/* offset 21 */
uint16_t start_pos_unicode;
} u8g2_font_info_t;
typedef struct _u8g2_font_decode_t
{
const uint8_t *decode_ptr; /* pointer to the compressed data */
int16_t target_x;
int16_t target_y;
uint16_t fg_color;
uint16_t bg_color;
int8_t x; /* local coordinates, (0,0) is upper left */
int8_t y;
int8_t glyph_width;
int8_t glyph_height;
uint8_t decode_bit_pos; /* bitpos inside a byte of the compressed data */
uint8_t is_transparent;
uint8_t dir; /* direction */
} u8g2_font_decode_t;
typedef struct _u8g2_font_t
{
const uint8_t *font; /* current font for all text procedures */
u8g2_font_decode_t font_decode; /* new font decode structure */
u8g2_font_info_t font_info; /* new font info structure */
int8_t glyph_x_offset; /* set by u8g2_GetGlyphWidth as a side effect */
void *draw_hv_line_arg;
void (*draw_hv_line)(int16_t x, int16_t y, int16_t len, uint8_t dir, uint16_t color, void *arg);
} u8g2_font_t;
uint8_t u8g2_IsGlyph(u8g2_font_t *u8g2, uint16_t requested_encoding);
int8_t u8g2_GetGlyphWidth(u8g2_font_t *u8g2, uint16_t requested_encoding);
void u8g2_SetFontMode(u8g2_font_t *u8g2, uint8_t is_transparent);
void u8g2_SetFontDirection(u8g2_font_t *u8g2, uint8_t dir);
int16_t u8g2_DrawGlyph(u8g2_font_t *u8g2, int16_t x, int16_t y, uint16_t encoding);
int16_t u8g2_DrawStr(u8g2_font_t *u8g2, int16_t x, int16_t y, const char *s);
void u8g2_SetFont(u8g2_font_t *u8g2, const uint8_t *font);
void u8g2_SetForegroundColor(u8g2_font_t *u8g2, uint16_t fg);
void u8g2_SetBackgroundColor(u8g2_font_t *u8g2, uint16_t bg);
#endif