mirror of
https://github.com/tsl0922/EPD-nRF5.git
synced 2026-06-02 07:55:52 +08:00
add calendar support
This commit is contained in:
@@ -1,57 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* | File : DEV_Config.h
|
||||
* | Author : Waveshare team
|
||||
* | Function : debug with prntf
|
||||
* | Info :
|
||||
* Image scanning
|
||||
* Please use progressive scanning to generate images or fonts
|
||||
*----------------
|
||||
* | This version: V1.0
|
||||
* | Date : 2018-01-11
|
||||
* | Info : Basic version
|
||||
*
|
||||
******************************************************************************/
|
||||
#ifndef _DEV_CONFIG_H_
|
||||
#define _DEV_CONFIG_H_
|
||||
|
||||
#include "nrf_delay.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* data
|
||||
**/
|
||||
#define UBYTE uint8_t
|
||||
#define UWORD uint16_t
|
||||
#define UDOUBLE uint32_t
|
||||
|
||||
extern uint32_t EPD_MOSI_PIN;
|
||||
extern uint32_t EPD_SCLK_PIN;
|
||||
extern uint32_t EPD_CS_PIN;
|
||||
extern uint32_t EPD_DC_PIN;
|
||||
extern uint32_t EPD_RST_PIN;
|
||||
extern uint32_t EPD_BUSY_PIN;
|
||||
extern uint32_t EPD_BS_PIN;
|
||||
|
||||
/**
|
||||
* GPIO read and write
|
||||
**/
|
||||
#define DEV_Digital_Write(_pin, _value) nrf_gpio_pin_write(_pin, _value)
|
||||
#define DEV_Digital_Read(_pin) nrf_gpio_pin_read(_pin)
|
||||
|
||||
|
||||
/**
|
||||
* delay x ms
|
||||
**/
|
||||
#define DEV_Delay_ms(__xms) nrf_delay_ms(__xms);
|
||||
#define DEV_Delay_us(__xus) nrf_delay_us(__xus);
|
||||
|
||||
UBYTE DEV_Module_Init(void);
|
||||
void DEV_Module_Exit(void);
|
||||
|
||||
void DEV_SPI_WriteByte(UBYTE value);
|
||||
void DEV_SPI_WriteBytes(UBYTE *value, UBYTE len);
|
||||
UBYTE DEV_SPI_ReadByte(void);
|
||||
|
||||
#endif
|
||||
144
EPD/EPD_4in2.c
144
EPD/EPD_4in2.c
@@ -6,7 +6,6 @@
|
||||
*----------------
|
||||
* | This version: V3.0
|
||||
* | Date : 2019-06-13
|
||||
* | Info :
|
||||
* -----------------------------------------------------------------------------
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@@ -28,7 +27,11 @@
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
******************************************************************************/
|
||||
#include "EPD_4in2.h"
|
||||
#include "EPD_driver.h"
|
||||
|
||||
// Display resolution
|
||||
#define EPD_4IN2_WIDTH 400
|
||||
#define EPD_4IN2_HEIGHT 300
|
||||
|
||||
/******************************************************************************
|
||||
function : Software reset
|
||||
@@ -47,40 +50,6 @@ static void EPD_4IN2_Reset(void)
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : send command
|
||||
parameter:
|
||||
Reg : Command register
|
||||
******************************************************************************/
|
||||
void EPD_4IN2_SendCommand(UBYTE Reg)
|
||||
{
|
||||
DEV_Digital_Write(EPD_DC_PIN, 0);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_SPI_WriteByte(Reg);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : send data
|
||||
parameter:
|
||||
Data : Write data
|
||||
******************************************************************************/
|
||||
void EPD_4IN2_SendData(UBYTE Data)
|
||||
{
|
||||
DEV_Digital_Write(EPD_DC_PIN, 1);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_SPI_WriteByte(Data);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
|
||||
void EPD_4IN2_SendData2(UBYTE *Data, UBYTE Len)
|
||||
{
|
||||
DEV_Digital_Write(EPD_DC_PIN, 1);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_SPI_WriteBytes(Data, Len);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : Wait until the busy_pin goes LOW
|
||||
parameter:
|
||||
@@ -98,7 +67,7 @@ parameter:
|
||||
******************************************************************************/
|
||||
void EPD_4IN2_TurnOnDisplay(void)
|
||||
{
|
||||
EPD_4IN2_SendCommand(0x12);
|
||||
EPD_WriteCommand(0x12);
|
||||
DEV_Delay_ms(100);
|
||||
EPD_4IN2_ReadBusy();
|
||||
}
|
||||
@@ -111,20 +80,20 @@ void EPD_4IN2_Init(void)
|
||||
{
|
||||
EPD_4IN2_Reset();
|
||||
|
||||
EPD_4IN2_SendCommand(0x04); // POWER ON
|
||||
EPD_WriteCommand(0x04); // POWER ON
|
||||
EPD_4IN2_ReadBusy();
|
||||
|
||||
EPD_4IN2_SendCommand(0x00); // panel setting
|
||||
EPD_4IN2_SendData(0x1f); // 400x300 B/W mode, LUT from OTP
|
||||
EPD_WriteCommand(0x00); // panel setting
|
||||
EPD_WriteByte(0x1f); // 400x300 B/W mode, LUT from OTP
|
||||
|
||||
EPD_4IN2_SendCommand(0x61); // resolution setting
|
||||
EPD_4IN2_SendData (EPD_4IN2_WIDTH / 256);
|
||||
EPD_4IN2_SendData (EPD_4IN2_WIDTH % 256);
|
||||
EPD_4IN2_SendData (EPD_4IN2_HEIGHT / 256);
|
||||
EPD_4IN2_SendData (EPD_4IN2_HEIGHT % 256);
|
||||
EPD_WriteCommand(0x61); // resolution setting
|
||||
EPD_WriteByte (EPD_4IN2_WIDTH / 256);
|
||||
EPD_WriteByte (EPD_4IN2_WIDTH % 256);
|
||||
EPD_WriteByte (EPD_4IN2_HEIGHT / 256);
|
||||
EPD_WriteByte (EPD_4IN2_HEIGHT % 256);
|
||||
|
||||
EPD_4IN2_SendCommand(0x50); // VCOM AND DATA INTERVAL SETTING
|
||||
EPD_4IN2_SendData(0x97); // LUTB=0 LUTW=1 interval=10
|
||||
EPD_WriteCommand(0x50); // VCOM AND DATA INTERVAL SETTING
|
||||
EPD_WriteByte(0x97); // LUTB=0 LUTW=1 interval=10
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
@@ -137,48 +106,55 @@ void EPD_4IN2_Clear(void)
|
||||
Width = (EPD_4IN2_WIDTH % 8 == 0)? (EPD_4IN2_WIDTH / 8 ): (EPD_4IN2_WIDTH / 8 + 1);
|
||||
Height = EPD_4IN2_HEIGHT;
|
||||
|
||||
EPD_4IN2_SendCommand(0x10);
|
||||
EPD_WriteCommand(0x10);
|
||||
for (UWORD j = 0; j < Height; j++) {
|
||||
for (UWORD i = 0; i < Width; i++) {
|
||||
EPD_4IN2_SendData(0xFF);
|
||||
EPD_WriteByte(0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
EPD_4IN2_SendCommand(0x13);
|
||||
EPD_WriteCommand(0x13);
|
||||
for (UWORD j = 0; j < Height; j++) {
|
||||
for (UWORD i = 0; i < Width; i++) {
|
||||
EPD_4IN2_SendData(0xFF);
|
||||
EPD_WriteByte(0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
EPD_4IN2_TurnOnDisplay();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : Sends the image buffer in RAM to e-Paper and displays
|
||||
parameter:
|
||||
******************************************************************************/
|
||||
void EPD_4IN2_Display(UBYTE *Image)
|
||||
static void _setPartialRamArea(UWORD x, UWORD y, UWORD w, UWORD h)
|
||||
{
|
||||
UWORD Width, Height;
|
||||
Width = (EPD_4IN2_WIDTH % 8 == 0)? (EPD_4IN2_WIDTH / 8 ): (EPD_4IN2_WIDTH / 8 + 1);
|
||||
Height = EPD_4IN2_HEIGHT;
|
||||
uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte)
|
||||
uint16_t ye = y + h - 1;
|
||||
x &= 0xFFF8; // byte boundary
|
||||
EPD_WriteCommand(0x90); // partial window
|
||||
EPD_WriteByte(x / 256);
|
||||
EPD_WriteByte(x % 256);
|
||||
EPD_WriteByte(xe / 256);
|
||||
EPD_WriteByte(xe % 256);
|
||||
EPD_WriteByte(y / 256);
|
||||
EPD_WriteByte(y % 256);
|
||||
EPD_WriteByte(ye / 256);
|
||||
EPD_WriteByte(ye % 256);
|
||||
EPD_WriteByte(0x01);
|
||||
}
|
||||
|
||||
EPD_4IN2_SendCommand(0x10);
|
||||
for (UWORD j = 0; j < Height; j++) {
|
||||
for (UWORD i = 0; i < Width; i++) {
|
||||
EPD_4IN2_SendData(0x00);
|
||||
void EPD_4IN2_Write_Image(UBYTE *black, UBYTE *color, UWORD x, UWORD y, UWORD w, UWORD h)
|
||||
{
|
||||
UWORD wb = (w + 7) / 8; // width bytes, bitmaps are padded
|
||||
x -= x % 8; // byte boundary
|
||||
w = wb * 8; // byte boundary
|
||||
if (x + w > EPD_4IN2_WIDTH || y + h > EPD_4IN2_HEIGHT) return;
|
||||
EPD_WriteCommand(0x91); // partial in
|
||||
_setPartialRamArea(x, y, w, h);
|
||||
EPD_WriteCommand(0x13);
|
||||
for (UWORD i = 0; i < h; i++) {
|
||||
for (UWORD j = 0; j < w / 8; j++) {
|
||||
EPD_WriteByte(black[j + i * wb]);
|
||||
}
|
||||
}
|
||||
|
||||
EPD_4IN2_SendCommand(0x13);
|
||||
for (UWORD j = 0; j < Height; j++) {
|
||||
for (UWORD i = 0; i < Width; i++) {
|
||||
EPD_4IN2_SendData(Image[i + j * Width]);
|
||||
}
|
||||
}
|
||||
|
||||
EPD_4IN2_TurnOnDisplay();
|
||||
EPD_WriteCommand(0x92); // partial out
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
@@ -187,12 +163,26 @@ parameter:
|
||||
******************************************************************************/
|
||||
void EPD_4IN2_Sleep(void)
|
||||
{
|
||||
EPD_4IN2_SendCommand(0x50); // DEEP_SLEEP
|
||||
EPD_4IN2_SendData(0XF7);
|
||||
EPD_WriteCommand(0x50); // DEEP_SLEEP
|
||||
EPD_WriteByte(0XF7);
|
||||
|
||||
EPD_4IN2_SendCommand(0x02); // POWER_OFF
|
||||
EPD_WriteCommand(0x02); // POWER_OFF
|
||||
EPD_4IN2_ReadBusy();
|
||||
|
||||
EPD_4IN2_SendCommand(0x07); // DEEP_SLEEP
|
||||
EPD_4IN2_SendData(0XA5);
|
||||
EPD_WriteCommand(0x07); // DEEP_SLEEP
|
||||
EPD_WriteByte(0XA5);
|
||||
}
|
||||
|
||||
const epd_driver_t epd_driver_4in2 = {
|
||||
.id = EPD_DRIVER_4IN2,
|
||||
.width = EPD_4IN2_WIDTH,
|
||||
.height = EPD_4IN2_HEIGHT,
|
||||
.init = EPD_4IN2_Init,
|
||||
.clear = EPD_4IN2_Clear,
|
||||
.send_command = EPD_WriteCommand,
|
||||
.send_byte = EPD_WriteByte,
|
||||
.send_data = EPD_WriteData,
|
||||
.write_image = EPD_4IN2_Write_Image,
|
||||
.display = EPD_4IN2_TurnOnDisplay,
|
||||
.sleep = EPD_4IN2_Sleep,
|
||||
};
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* | File : EPD_4in2.h
|
||||
* | Author : Waveshare team
|
||||
* | Function : 4.2inch e-paper
|
||||
* | Info :
|
||||
*----------------
|
||||
* | This version: V3.0
|
||||
* | Date : 2019-06-13
|
||||
* | Info :
|
||||
* -----------------------------------------------------------------------------
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documnetation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
******************************************************************************/
|
||||
#ifndef _EPD_4IN2_H_
|
||||
#define _EPD_4IN2_H_
|
||||
|
||||
#include "DEV_Config.h"
|
||||
|
||||
// Display resolution
|
||||
#define EPD_4IN2_WIDTH 400
|
||||
#define EPD_4IN2_HEIGHT 300
|
||||
|
||||
void EPD_4IN2_Init(void);
|
||||
void EPD_4IN2_Clear(void);
|
||||
void EPD_4IN2_Display(UBYTE *Image);
|
||||
void EPD_4IN2_Sleep(void);
|
||||
|
||||
void EPD_4IN2_SendCommand(UBYTE Reg);
|
||||
void EPD_4IN2_SendData(UBYTE Data);
|
||||
void EPD_4IN2_SendData2(UBYTE *Data, UBYTE Len);
|
||||
void EPD_4IN2_TurnOnDisplay(void);
|
||||
|
||||
#endif
|
||||
@@ -6,7 +6,6 @@
|
||||
*----------------
|
||||
* | This version: V1.0
|
||||
* | Date : 2023-09-12
|
||||
* | Info :
|
||||
* -----------------------------------------------------------------------------
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@@ -28,7 +27,11 @@
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
******************************************************************************/
|
||||
#include "EPD_4in2_V2.h"
|
||||
#include "EPD_driver.h"
|
||||
|
||||
// Display resolution
|
||||
#define EPD_4IN2_V2_WIDTH 400
|
||||
#define EPD_4IN2_V2_HEIGHT 300
|
||||
|
||||
/******************************************************************************
|
||||
function : Software reset
|
||||
@@ -44,39 +47,6 @@ static void EPD_4IN2_V2_Reset(void)
|
||||
DEV_Delay_ms(100);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : send command
|
||||
parameter:
|
||||
Reg : Command register
|
||||
******************************************************************************/
|
||||
void EPD_4IN2_V2_SendCommand(UBYTE Reg)
|
||||
{
|
||||
DEV_Digital_Write(EPD_DC_PIN, 0);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_SPI_WriteByte(Reg);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : send data
|
||||
parameter:
|
||||
Data : Write data
|
||||
******************************************************************************/
|
||||
void EPD_4IN2_V2_SendData(UBYTE Data)
|
||||
{
|
||||
DEV_Digital_Write(EPD_DC_PIN, 1);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_SPI_WriteByte(Data);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
|
||||
void EPD_4IN2_V2_SendData2(UBYTE *Data, UBYTE Len)
|
||||
{
|
||||
DEV_Digital_Write(EPD_DC_PIN, 1);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_SPI_WriteBytes(Data, Len);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
/******************************************************************************
|
||||
function : Wait until the busy_pin goes LOW
|
||||
parameter:
|
||||
@@ -94,9 +64,9 @@ parameter:
|
||||
******************************************************************************/
|
||||
void EPD_4IN2_V2_TurnOnDisplay(void)
|
||||
{
|
||||
EPD_4IN2_V2_SendCommand(0x22);
|
||||
EPD_4IN2_V2_SendData(0xF7);
|
||||
EPD_4IN2_V2_SendCommand(0x20);
|
||||
EPD_WriteCommand(0x22);
|
||||
EPD_WriteByte(0xF7);
|
||||
EPD_WriteCommand(0x20);
|
||||
EPD_4IN2_V2_ReadBusy();
|
||||
}
|
||||
|
||||
@@ -106,15 +76,15 @@ parameter:
|
||||
******************************************************************************/
|
||||
static void EPD_4IN2_V2_SetWindows(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend)
|
||||
{
|
||||
EPD_4IN2_V2_SendCommand(0x44); // SET_RAM_X_ADDRESS_START_END_POSITION
|
||||
EPD_4IN2_V2_SendData((Xstart>>3) & 0xFF);
|
||||
EPD_4IN2_V2_SendData((Xend>>3) & 0xFF);
|
||||
EPD_WriteCommand(0x44); // SET_RAM_X_ADDRESS_START_END_POSITION
|
||||
EPD_WriteByte((Xstart>>3) & 0xFF);
|
||||
EPD_WriteByte((Xend>>3) & 0xFF);
|
||||
|
||||
EPD_4IN2_V2_SendCommand(0x45); // SET_RAM_Y_ADDRESS_START_END_POSITION
|
||||
EPD_4IN2_V2_SendData(Ystart & 0xFF);
|
||||
EPD_4IN2_V2_SendData((Ystart >> 8) & 0xFF);
|
||||
EPD_4IN2_V2_SendData(Yend & 0xFF);
|
||||
EPD_4IN2_V2_SendData((Yend >> 8) & 0xFF);
|
||||
EPD_WriteCommand(0x45); // SET_RAM_Y_ADDRESS_START_END_POSITION
|
||||
EPD_WriteByte(Ystart & 0xFF);
|
||||
EPD_WriteByte((Ystart >> 8) & 0xFF);
|
||||
EPD_WriteByte(Yend & 0xFF);
|
||||
EPD_WriteByte((Yend >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
@@ -123,12 +93,12 @@ parameter:
|
||||
******************************************************************************/
|
||||
static void EPD_4IN2_V2_SetCursor(UWORD Xstart, UWORD Ystart)
|
||||
{
|
||||
EPD_4IN2_V2_SendCommand(0x4E); // SET_RAM_X_ADDRESS_COUNTER
|
||||
EPD_4IN2_V2_SendData(Xstart & 0xFF);
|
||||
EPD_WriteCommand(0x4E); // SET_RAM_X_ADDRESS_COUNTER
|
||||
EPD_WriteByte(Xstart & 0xFF);
|
||||
|
||||
EPD_4IN2_V2_SendCommand(0x4F); // SET_RAM_Y_ADDRESS_COUNTER
|
||||
EPD_4IN2_V2_SendData(Ystart & 0xFF);
|
||||
EPD_4IN2_V2_SendData((Ystart >> 8) & 0xFF);
|
||||
EPD_WriteCommand(0x4F); // SET_RAM_Y_ADDRESS_COUNTER
|
||||
EPD_WriteByte(Ystart & 0xFF);
|
||||
EPD_WriteByte((Ystart >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
@@ -140,23 +110,23 @@ void EPD_4IN2_V2_Init(void)
|
||||
EPD_4IN2_V2_Reset();
|
||||
|
||||
EPD_4IN2_V2_ReadBusy();
|
||||
EPD_4IN2_V2_SendCommand(0x12); // soft reset
|
||||
EPD_WriteCommand(0x12); // soft reset
|
||||
EPD_4IN2_V2_ReadBusy();
|
||||
|
||||
// EPD_4IN2_V2_SendCommand(0x01); //Driver output control
|
||||
// EPD_4IN2_V2_SendData((EPD_4IN2_V2_HEIGHT-1)%256);
|
||||
// EPD_4IN2_V2_SendData((EPD_4IN2_V2_HEIGHT-1)/256);
|
||||
// EPD_4IN2_V2_SendData(0x00);
|
||||
// EPD_WriteCommand(0x01); //Driver output control
|
||||
// EPD_WriteByte((EPD_4IN2_V2_HEIGHT-1)%256);
|
||||
// EPD_WriteByte((EPD_4IN2_V2_HEIGHT-1)/256);
|
||||
// EPD_WriteByte(0x00);
|
||||
|
||||
EPD_4IN2_V2_SendCommand(0x21); // Display update control
|
||||
EPD_4IN2_V2_SendData(0x40);
|
||||
EPD_4IN2_V2_SendData(0x00);
|
||||
EPD_WriteCommand(0x21); // Display update control
|
||||
EPD_WriteByte(0x40);
|
||||
EPD_WriteByte(0x00);
|
||||
|
||||
EPD_4IN2_V2_SendCommand(0x3C); //BorderWavefrom
|
||||
EPD_4IN2_V2_SendData(0x05);
|
||||
EPD_WriteCommand(0x3C); //BorderWavefrom
|
||||
EPD_WriteByte(0x05);
|
||||
|
||||
EPD_4IN2_V2_SendCommand(0x11); // data entry mode
|
||||
EPD_4IN2_V2_SendData(0x03); // X-mode
|
||||
EPD_WriteCommand(0x11); // data entry mode
|
||||
EPD_WriteByte(0x03); // X-mode
|
||||
|
||||
EPD_4IN2_V2_SetWindows(0, 0, EPD_4IN2_V2_WIDTH-1, EPD_4IN2_V2_HEIGHT-1);
|
||||
|
||||
@@ -175,46 +145,54 @@ void EPD_4IN2_V2_Clear(void)
|
||||
Width = (EPD_4IN2_V2_WIDTH % 8 == 0)? (EPD_4IN2_V2_WIDTH / 8 ): (EPD_4IN2_V2_WIDTH / 8 + 1);
|
||||
Height = EPD_4IN2_V2_HEIGHT;
|
||||
|
||||
EPD_4IN2_V2_SendCommand(0x24);
|
||||
EPD_WriteCommand(0x24);
|
||||
for (UWORD j = 0; j < Height; j++) {
|
||||
for (UWORD i = 0; i < Width; i++) {
|
||||
EPD_4IN2_V2_SendData(0xFF);
|
||||
EPD_WriteByte(0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
EPD_4IN2_V2_SendCommand(0x26);
|
||||
EPD_WriteCommand(0x26);
|
||||
for (UWORD j = 0; j < Height; j++) {
|
||||
for (UWORD i = 0; i < Width; i++) {
|
||||
EPD_4IN2_V2_SendData(0xFF);
|
||||
EPD_WriteByte(0xFF);
|
||||
}
|
||||
}
|
||||
EPD_4IN2_V2_TurnOnDisplay();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : Sends the image buffer in RAM to e-Paper and displays
|
||||
parameter:
|
||||
******************************************************************************/
|
||||
void EPD_4IN2_V2_Display(UBYTE *Image)
|
||||
static void _setPartialRamArea(UWORD x, UWORD y, UWORD w, UWORD h)
|
||||
{
|
||||
UWORD Width, Height;
|
||||
Width = (EPD_4IN2_V2_WIDTH % 8 == 0)? (EPD_4IN2_V2_WIDTH / 8 ): (EPD_4IN2_V2_WIDTH / 8 + 1);
|
||||
Height = EPD_4IN2_V2_HEIGHT;
|
||||
EPD_WriteCommand(0x11); // set ram entry mode
|
||||
EPD_WriteByte(0x03); // x increase, y increase : normal mode
|
||||
EPD_WriteCommand(0x44);
|
||||
EPD_WriteByte(x / 8);
|
||||
EPD_WriteByte((x + w - 1) / 8);
|
||||
EPD_WriteCommand(0x45);
|
||||
EPD_WriteByte(y % 256);
|
||||
EPD_WriteByte(y / 256);
|
||||
EPD_WriteByte((y + h - 1) % 256);
|
||||
EPD_WriteByte((y + h - 1) / 256);
|
||||
EPD_WriteCommand(0x4e);
|
||||
EPD_WriteByte(x / 8);
|
||||
EPD_WriteCommand(0x4f);
|
||||
EPD_WriteByte(y % 256);
|
||||
EPD_WriteByte(y / 256);
|
||||
}
|
||||
|
||||
EPD_4IN2_V2_SendCommand(0x24);
|
||||
for (UWORD j = 0; j < Height; j++) {
|
||||
for (UWORD i = 0; i < Width; i++) {
|
||||
EPD_4IN2_V2_SendData(Image[i + j * Width]);
|
||||
void EPD_4IN2_V2_Write_Image(UBYTE *black, UBYTE *color, UWORD x, UWORD y, UWORD w, UWORD h)
|
||||
{
|
||||
int32_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
|
||||
x -= x % 8; // byte boundary
|
||||
w = wb * 8; // byte boundary
|
||||
if (x + w > EPD_4IN2_V2_WIDTH || y + h > EPD_4IN2_V2_HEIGHT) return;
|
||||
_setPartialRamArea(x, y, w, h);
|
||||
EPD_WriteCommand(0x24);
|
||||
for (UWORD i = 0; i < h; i++) {
|
||||
for (UWORD j = 0; j < w / 8; j++) {
|
||||
EPD_WriteByte(black[j + i * wb]);
|
||||
}
|
||||
}
|
||||
|
||||
EPD_4IN2_V2_SendCommand(0x26);
|
||||
for (UWORD j = 0; j < Height; j++) {
|
||||
for (UWORD i = 0; i < Width; i++) {
|
||||
EPD_4IN2_V2_SendData(Image[i + j * Width]);
|
||||
}
|
||||
}
|
||||
EPD_4IN2_V2_TurnOnDisplay();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
@@ -223,7 +201,21 @@ parameter:
|
||||
******************************************************************************/
|
||||
void EPD_4IN2_V2_Sleep(void)
|
||||
{
|
||||
EPD_4IN2_V2_SendCommand(0x10); // DEEP_SLEEP
|
||||
EPD_4IN2_V2_SendData(0x01);
|
||||
EPD_WriteCommand(0x10); // DEEP_SLEEP
|
||||
EPD_WriteByte(0x01);
|
||||
DEV_Delay_ms(200);
|
||||
}
|
||||
|
||||
const epd_driver_t epd_driver_4in2v2 = {
|
||||
.id = EPD_DRIVER_4IN2_V2,
|
||||
.width = EPD_4IN2_V2_WIDTH,
|
||||
.height = EPD_4IN2_V2_HEIGHT,
|
||||
.init = EPD_4IN2_V2_Init,
|
||||
.clear = EPD_4IN2_V2_Clear,
|
||||
.send_command = EPD_WriteCommand,
|
||||
.send_byte = EPD_WriteByte,
|
||||
.send_data = EPD_WriteData,
|
||||
.write_image = EPD_4IN2_V2_Write_Image,
|
||||
.display = EPD_4IN2_V2_TurnOnDisplay,
|
||||
.sleep = EPD_4IN2_V2_Sleep,
|
||||
};
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* | File : EPD_4in2_V2.h
|
||||
* | Author : Waveshare team
|
||||
* | Function : 4.2inch e-paper V2
|
||||
* | Info :
|
||||
*----------------
|
||||
* | This version: V1.0
|
||||
* | Date : 2023-09-12
|
||||
* | Info :
|
||||
* -----------------------------------------------------------------------------
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documnetation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
******************************************************************************/
|
||||
#ifndef _EPD_4IN2_V2_H_
|
||||
#define _EPD_4IN2_V2_H_
|
||||
|
||||
#include "DEV_Config.h"
|
||||
|
||||
// Display resolution
|
||||
#define EPD_4IN2_V2_WIDTH 400
|
||||
#define EPD_4IN2_V2_HEIGHT 300
|
||||
|
||||
#define Seconds_1_5S 0
|
||||
#define Seconds_1S 1
|
||||
|
||||
void EPD_4IN2_V2_Init(void);
|
||||
void EPD_4IN2_V2_Clear(void);
|
||||
void EPD_4IN2_V2_Display(UBYTE *Image);
|
||||
void EPD_4IN2_V2_Sleep(void);
|
||||
|
||||
void EPD_4IN2_V2_SendCommand(UBYTE Reg);
|
||||
void EPD_4IN2_V2_SendData(UBYTE Data);
|
||||
void EPD_4IN2_V2_SendData2(UBYTE *Data, UBYTE Len);
|
||||
void EPD_4IN2_V2_TurnOnDisplay(void);
|
||||
|
||||
#endif
|
||||
@@ -6,7 +6,7 @@
|
||||
*----------------
|
||||
* | This version: V1.0
|
||||
* | Date : 2020-11-27
|
||||
* | Info :
|
||||
* -----------------------------------------------------------------------------
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documnetation files (the "Software"), to deal
|
||||
@@ -27,7 +27,11 @@
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
******************************************************************************/
|
||||
#include "EPD_4in2b_V2.h"
|
||||
#include "EPD_driver.h"
|
||||
|
||||
// Display resolution
|
||||
#define EPD_4IN2B_V2_WIDTH 400
|
||||
#define EPD_4IN2B_V2_HEIGHT 300
|
||||
|
||||
/******************************************************************************
|
||||
function : Software reset
|
||||
@@ -43,40 +47,6 @@ static void EPD_4IN2B_V2_Reset(void)
|
||||
DEV_Delay_ms(200);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : send command
|
||||
parameter:
|
||||
Reg : Command register
|
||||
******************************************************************************/
|
||||
void EPD_4IN2B_V2_SendCommand(UBYTE Reg)
|
||||
{
|
||||
DEV_Digital_Write(EPD_DC_PIN, 0);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_SPI_WriteByte(Reg);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : send data
|
||||
parameter:
|
||||
Data : Write data
|
||||
******************************************************************************/
|
||||
void EPD_4IN2B_V2_SendData(UBYTE Data)
|
||||
{
|
||||
DEV_Digital_Write(EPD_DC_PIN, 1);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_SPI_WriteByte(Data);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
|
||||
void EPD_4IN2B_V2_SendData2(UBYTE *Data, UBYTE Len)
|
||||
{
|
||||
DEV_Digital_Write(EPD_DC_PIN, 1);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_SPI_WriteBytes(Data, Len);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : Wait until the busy_pin goes LOW
|
||||
parameter:
|
||||
@@ -84,7 +54,7 @@ parameter:
|
||||
void EPD_4IN2B_V2_ReadBusy(void)
|
||||
{
|
||||
do{
|
||||
EPD_4IN2B_V2_SendCommand(0x71);
|
||||
EPD_WriteCommand(0x71);
|
||||
DEV_Delay_ms(50);
|
||||
}while(!(DEV_Digital_Read(EPD_BUSY_PIN)));
|
||||
DEV_Delay_ms(50);
|
||||
@@ -96,7 +66,7 @@ parameter:
|
||||
******************************************************************************/
|
||||
void EPD_4IN2B_V2_TurnOnDisplay(void)
|
||||
{
|
||||
EPD_4IN2B_V2_SendCommand(0x12); // DISPLAY_REFRESH
|
||||
EPD_WriteCommand(0x12); // DISPLAY_REFRESH
|
||||
DEV_Delay_ms(100);
|
||||
EPD_4IN2B_V2_ReadBusy();
|
||||
}
|
||||
@@ -109,11 +79,11 @@ void EPD_4IN2B_V2_Init(void)
|
||||
{
|
||||
EPD_4IN2B_V2_Reset();
|
||||
|
||||
EPD_4IN2B_V2_SendCommand(0x04);
|
||||
EPD_WriteCommand(0x04);
|
||||
EPD_4IN2B_V2_ReadBusy();
|
||||
|
||||
EPD_4IN2B_V2_SendCommand(0x00);
|
||||
EPD_4IN2B_V2_SendData(0x0f);
|
||||
EPD_WriteCommand(0x00);
|
||||
EPD_WriteByte(0x0f);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
@@ -126,48 +96,62 @@ void EPD_4IN2B_V2_Clear(void)
|
||||
Width = (EPD_4IN2B_V2_WIDTH % 8 == 0)? (EPD_4IN2B_V2_WIDTH / 8 ): (EPD_4IN2B_V2_WIDTH / 8 + 1);
|
||||
Height = EPD_4IN2B_V2_HEIGHT;
|
||||
|
||||
EPD_4IN2B_V2_SendCommand(0x10);
|
||||
EPD_WriteCommand(0x10);
|
||||
for (UWORD j = 0; j < Height; j++) {
|
||||
for (UWORD i = 0; i < Width; i++) {
|
||||
EPD_4IN2B_V2_SendData(0xFF);
|
||||
EPD_WriteByte(0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
EPD_4IN2B_V2_SendCommand(0x13);
|
||||
EPD_WriteCommand(0x13);
|
||||
for (UWORD j = 0; j < Height; j++) {
|
||||
for (UWORD i = 0; i < Width; i++) {
|
||||
EPD_4IN2B_V2_SendData(0xFF);
|
||||
EPD_WriteByte(0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
EPD_4IN2B_V2_TurnOnDisplay();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function : Sends the image buffer in RAM to e-Paper and displays
|
||||
parameter:
|
||||
******************************************************************************/
|
||||
void EPD_4IN2B_V2_Display(const UBYTE *blackimage, const UBYTE *ryimage)
|
||||
static void _setPartialRamArea(UWORD x, UWORD y, UWORD w, UWORD h)
|
||||
{
|
||||
UWORD Width, Height;
|
||||
Width = (EPD_4IN2B_V2_WIDTH % 8 == 0)? (EPD_4IN2B_V2_WIDTH / 8 ): (EPD_4IN2B_V2_WIDTH / 8 + 1);
|
||||
Height = EPD_4IN2B_V2_HEIGHT;
|
||||
UWORD xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte)
|
||||
UWORD ye = y + h - 1;
|
||||
x &= 0xFFF8; // byte boundary
|
||||
xe |= 0x0007; // byte boundary
|
||||
EPD_WriteCommand(0x90); // partial window
|
||||
EPD_WriteByte(x / 256);
|
||||
EPD_WriteByte(x % 256);
|
||||
EPD_WriteByte(xe / 256);
|
||||
EPD_WriteByte(xe % 256);
|
||||
EPD_WriteByte(y / 256);
|
||||
EPD_WriteByte(y % 256);
|
||||
EPD_WriteByte(ye / 256);
|
||||
EPD_WriteByte(ye % 256);
|
||||
EPD_WriteByte(0x00); // distortion on right half
|
||||
}
|
||||
|
||||
EPD_4IN2B_V2_SendCommand(0x10);
|
||||
for (UWORD j = 0; j < Height; j++) {
|
||||
for (UWORD i = 0; i < Width; i++) {
|
||||
EPD_4IN2B_V2_SendData(blackimage[i + j * Width]);
|
||||
void EPD_4IN2B_V2_Write_Image(UBYTE *black, UBYTE *color, UWORD x, UWORD y, UWORD w, UWORD h)
|
||||
{
|
||||
UWORD wb = (w + 7) / 8; // width bytes, bitmaps are padded
|
||||
x -= x % 8; // byte boundary
|
||||
w = wb * 8; // byte boundary
|
||||
if (x + w > EPD_4IN2B_V2_WIDTH || y + h > EPD_4IN2B_V2_HEIGHT) return;
|
||||
EPD_WriteCommand(0x91); // partial in
|
||||
_setPartialRamArea(x, y, w, h);
|
||||
EPD_WriteCommand(0x10);
|
||||
for (UWORD i = 0; i < h; i++) {
|
||||
for (UWORD j = 0; j < w / 8; j++) {
|
||||
EPD_WriteByte(black ? black[j + i * wb] : 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
EPD_4IN2B_V2_SendCommand(0x13);
|
||||
for (UWORD j = 0; j < Height; j++) {
|
||||
for (UWORD i = 0; i < Width; i++) {
|
||||
EPD_4IN2B_V2_SendData(ryimage[i + j * Width]);
|
||||
EPD_WriteCommand(0x13);
|
||||
for (UWORD i = 0; i < h; i++) {
|
||||
for (UWORD j = 0; j < w / 8; j++) {
|
||||
EPD_WriteByte(color ? color[j + i * wb] : 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
EPD_4IN2B_V2_TurnOnDisplay();
|
||||
EPD_WriteCommand(0x92); // partial out
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
@@ -176,11 +160,25 @@ parameter:
|
||||
******************************************************************************/
|
||||
void EPD_4IN2B_V2_Sleep(void)
|
||||
{
|
||||
EPD_4IN2B_V2_SendCommand(0X50);
|
||||
EPD_4IN2B_V2_SendData(0xf7); //border floating
|
||||
EPD_WriteCommand(0X50);
|
||||
EPD_WriteByte(0xf7); //border floating
|
||||
|
||||
EPD_4IN2B_V2_SendCommand(0X02); //power off
|
||||
EPD_WriteCommand(0X02); //power off
|
||||
EPD_4IN2B_V2_ReadBusy(); //waiting for the electronic paper IC to release the idle signal
|
||||
EPD_4IN2B_V2_SendCommand(0X07); //deep sleep
|
||||
EPD_4IN2B_V2_SendData(0xA5);
|
||||
EPD_WriteCommand(0X07); //deep sleep
|
||||
EPD_WriteByte(0xA5);
|
||||
}
|
||||
|
||||
const epd_driver_t epd_driver_4in2bv2 = {
|
||||
.id = EPD_DRIVER_4IN2B_V2,
|
||||
.width = EPD_4IN2B_V2_WIDTH,
|
||||
.height = EPD_4IN2B_V2_HEIGHT,
|
||||
.init = EPD_4IN2B_V2_Init,
|
||||
.clear = EPD_4IN2B_V2_Clear,
|
||||
.send_command = EPD_WriteCommand,
|
||||
.send_byte = EPD_WriteByte,
|
||||
.send_data = EPD_WriteData,
|
||||
.write_image = EPD_4IN2B_V2_Write_Image,
|
||||
.display = EPD_4IN2B_V2_TurnOnDisplay,
|
||||
.sleep = EPD_4IN2B_V2_Sleep,
|
||||
};
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* | File : EPD_4in2b_V2.h
|
||||
* | Author : Waveshare team
|
||||
* | Function : 4.2inch e-paper b V2
|
||||
* | Info :
|
||||
*----------------
|
||||
* | This version: V1.0
|
||||
* | Date : 2020-11-27
|
||||
* | Info :
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documnetation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
******************************************************************************/
|
||||
#ifndef __EPD_4IN2B_V2_H_
|
||||
#define __EPD_4IN2B_V2_H_
|
||||
|
||||
#include "DEV_Config.h"
|
||||
|
||||
// Display resolution
|
||||
#define EPD_4IN2B_V2_WIDTH 400
|
||||
#define EPD_4IN2B_V2_HEIGHT 300
|
||||
|
||||
void EPD_4IN2B_V2_Init(void);
|
||||
void EPD_4IN2B_V2_Clear(void);
|
||||
void EPD_4IN2B_V2_Display(const UBYTE *blackimage, const UBYTE *ryimage);
|
||||
void EPD_4IN2B_V2_Sleep(void);
|
||||
|
||||
void EPD_4IN2B_V2_SendCommand(UBYTE Reg);
|
||||
void EPD_4IN2B_V2_SendData(UBYTE Data);
|
||||
void EPD_4IN2B_V2_SendData2(UBYTE *Data, UBYTE Len);
|
||||
void EPD_4IN2B_V2_TurnOnDisplay(void);
|
||||
|
||||
#endif
|
||||
@@ -17,17 +17,14 @@
|
||||
#include "nrf_gpio.h"
|
||||
#include "nrf_soc.h"
|
||||
#include "fstorage.h"
|
||||
#include "EPD_4in2.h"
|
||||
#include "EPD_4in2_V2.h"
|
||||
#include "EPD_4in2b_V2.h"
|
||||
#include "EPD_ble.h"
|
||||
#define NRF_LOG_MODULE_NAME "EPD_ble"
|
||||
#include "nrf_log.h"
|
||||
|
||||
#ifdef NRF51802
|
||||
#define EPD_CFG_DEFAULT {0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x03, 0x09, 0x03}
|
||||
#else
|
||||
#define EPD_CFG_DEFAULT {0x05, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x01, 0x07}
|
||||
|
||||
#ifndef EPD_CFG_DEFAULT
|
||||
#define EPD_CFG_DEFAULT {0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x03, 0x09, 0x03}
|
||||
#endif
|
||||
|
||||
#define BLE_EPD_BASE_UUID {{0XEC, 0X5A, 0X67, 0X1C, 0XC1, 0XB6, 0X46, 0XFB, \
|
||||
@@ -37,31 +34,6 @@
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#define EPD_CONFIG_SIZE (sizeof(epd_config_t) / sizeof(uint8_t))
|
||||
|
||||
/** EPD drivers */
|
||||
static epd_driver_t epd_drivers[] = {
|
||||
{EPD_DRIVER_4IN2, EPD_4IN2_Init, EPD_4IN2_Clear,
|
||||
EPD_4IN2_SendCommand, EPD_4IN2_SendData2,
|
||||
EPD_4IN2_TurnOnDisplay, EPD_4IN2_Sleep},
|
||||
{EPD_DRIVER_4IN2_V2, EPD_4IN2_V2_Init, EPD_4IN2_V2_Clear,
|
||||
EPD_4IN2_V2_SendCommand, EPD_4IN2_V2_SendData2,
|
||||
EPD_4IN2_V2_TurnOnDisplay, EPD_4IN2_V2_Sleep},
|
||||
{EPD_DRIVER_4IN2B_V2, EPD_4IN2B_V2_Init, EPD_4IN2B_V2_Clear,
|
||||
EPD_4IN2B_V2_SendCommand, EPD_4IN2B_V2_SendData2,
|
||||
EPD_4IN2B_V2_TurnOnDisplay, EPD_4IN2B_V2_Sleep},
|
||||
};
|
||||
|
||||
static epd_driver_t *epd_driver_get(uint8_t id)
|
||||
{
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(epd_drivers); i++)
|
||||
{
|
||||
if (epd_drivers[i].id == id)
|
||||
{
|
||||
return &epd_drivers[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void fs_evt_handler(fs_evt_t const * const evt, fs_ret_t result)
|
||||
{
|
||||
NRF_LOG_DEBUG("fs_evt_handler: %d\n", result);
|
||||
@@ -108,7 +80,6 @@ static void on_connect(ble_epd_t * p_epd, ble_evt_t * p_ble_evt)
|
||||
nrf_gpio_pin_toggle(p_epd->config.led_pin);
|
||||
}
|
||||
p_epd->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
DEV_Module_Init();
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +96,6 @@ static void on_disconnect(ble_epd_t * p_epd, ble_evt_t * p_ble_evt)
|
||||
nrf_gpio_pin_toggle(p_epd->config.led_pin);
|
||||
}
|
||||
p_epd->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
DEV_Module_Exit();
|
||||
}
|
||||
|
||||
static void epd_service_process(ble_epd_t * p_epd, uint8_t * p_data, uint16_t length)
|
||||
@@ -133,7 +103,10 @@ static void epd_service_process(ble_epd_t * p_epd, uint8_t * p_data, uint16_t le
|
||||
if (p_data == NULL || length <= 0) return;
|
||||
NRF_LOG_DEBUG("[EPD]: CMD=0x%02x, LEN=%d\n", p_data[0], length);
|
||||
|
||||
uint32_t err_code;
|
||||
if (p_epd->epd_cmd_cb != NULL) {
|
||||
if (p_epd->epd_cmd_cb(p_data[0], length > 1 ? &p_data[1] : NULL, length - 1))
|
||||
return;
|
||||
}
|
||||
|
||||
switch (p_data[0])
|
||||
{
|
||||
@@ -149,8 +122,7 @@ static void epd_service_process(ble_epd_t * p_epd, uint8_t * p_data, uint16_t le
|
||||
EPD_RST_PIN = p_epd->config.rst_pin = p_data[5];
|
||||
EPD_BUSY_PIN = p_epd->config.busy_pin = p_data[6];
|
||||
EPD_BS_PIN = p_epd->config.bs_pin = p_data[7];
|
||||
err_code = epd_config_save(&p_epd->config);
|
||||
NRF_LOG_DEBUG("epd_config_save: %d\n", err_code);
|
||||
epd_config_save(&p_epd->config);
|
||||
|
||||
DEV_Module_Init();
|
||||
break;
|
||||
@@ -158,13 +130,11 @@ static void epd_service_process(ble_epd_t * p_epd, uint8_t * p_data, uint16_t le
|
||||
case EPD_CMD_INIT:
|
||||
if (length > 1)
|
||||
{
|
||||
epd_driver_t *driver = epd_driver_get(p_data[1]);
|
||||
if (driver != NULL)
|
||||
if (epd_driver_set(p_data[1]))
|
||||
{
|
||||
p_epd->driver = driver;
|
||||
p_epd->config.driver_id = driver->id;
|
||||
err_code = epd_config_save(&p_epd->config);
|
||||
NRF_LOG_DEBUG("epd_config_save: %d\n", err_code);
|
||||
p_epd->driver = epd_driver_get();
|
||||
p_epd->config.driver_id = p_epd->driver->id;
|
||||
epd_config_save(&p_epd->config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,11 +350,8 @@ static void epd_config_init(ble_epd_t * p_epd)
|
||||
EPD_BUSY_PIN = p_epd->config.busy_pin;
|
||||
EPD_BS_PIN = p_epd->config.bs_pin;
|
||||
|
||||
p_epd->driver = epd_driver_get(p_epd->config.driver_id);
|
||||
if (p_epd->driver == NULL)
|
||||
{
|
||||
p_epd->driver = &epd_drivers[0];
|
||||
}
|
||||
epd_driver_set(p_epd->config.driver_id);
|
||||
p_epd->driver = epd_driver_get();
|
||||
}
|
||||
|
||||
void ble_epd_sleep_prepare(ble_epd_t * p_epd)
|
||||
@@ -401,17 +368,18 @@ void ble_epd_sleep_prepare(ble_epd_t * p_epd)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ble_epd_init(ble_epd_t * p_epd)
|
||||
uint32_t ble_epd_init(ble_epd_t * p_epd, epd_callback_t cmd_cb)
|
||||
{
|
||||
if (p_epd == NULL)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
p_epd->epd_cmd_cb = cmd_cb;
|
||||
|
||||
// Initialize the service structure.
|
||||
p_epd->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_epd->is_notification_enabled = false;
|
||||
|
||||
|
||||
uint32_t err_code;
|
||||
err_code = epd_config_load(&p_epd->config);
|
||||
if (err_code == NRF_SUCCESS)
|
||||
|
||||
@@ -18,12 +18,14 @@
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "sdk_config.h"
|
||||
#include "DEV_Config.h"
|
||||
#include "EPD_driver.h"
|
||||
|
||||
#define BLE_UUID_EPD_SERVICE 0x0001
|
||||
#define EPD_SERVICE_UUID_TYPE BLE_UUID_TYPE_VENDOR_BEGIN
|
||||
#define BLE_EPD_MAX_DATA_LEN (GATT_MTU_SIZE_DEFAULT - 3) /**< Maximum length of data (in bytes) that can be transmitted to the peer. */
|
||||
|
||||
typedef bool (*epd_callback_t)(uint8_t cmd, uint8_t *data, uint16_t len);
|
||||
|
||||
/**< EPD Service Configs */
|
||||
typedef struct
|
||||
{
|
||||
@@ -51,6 +53,8 @@ enum EPD_CMDS
|
||||
EPD_CMD_SEND_DATA, /**< send data to EPD */
|
||||
EPD_CMD_DISPLAY, /**< diaplay EPD ram on screen */
|
||||
EPD_CMD_SLEEP, /**< EPD enter sleep mode */
|
||||
|
||||
EPD_CMD_SET_TIME = 0x20, /** < set time with unix timestamp */
|
||||
|
||||
EPD_CMD_SET_CONFIG = 0x90, /**< set full EPD config */
|
||||
EPD_CMD_SYS_RESET = 0x91, /**< MCU reset */
|
||||
@@ -58,29 +62,6 @@ enum EPD_CMDS
|
||||
EPD_CMD_CFG_ERASE = 0x99, /**< Erase config and reset */
|
||||
};
|
||||
|
||||
/**< EPD driver IDs. */
|
||||
enum EPD_DRIVER_IDS
|
||||
{
|
||||
EPD_DRIVER_4IN2 = 1,
|
||||
EPD_DRIVER_4IN2_V2,
|
||||
EPD_DRIVER_4IN2B_V2,
|
||||
};
|
||||
|
||||
/**@brief EPD driver structure.
|
||||
*
|
||||
* @details This structure contains epd driver functions.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t id; /**< driver ID. */
|
||||
void (*init)(void); /**< Initialize the e-Paper register */
|
||||
void (*clear)(void); /**< Clear screen */
|
||||
void (*send_command)(UBYTE Reg); /**< send command */
|
||||
void (*send_data)(UBYTE *Data, UBYTE Len); /**< send data */
|
||||
void (*display)(void); /**< Sends the image buffer in RAM to e-Paper and displays */
|
||||
void (*sleep)(void); /**< Enter sleep mode */
|
||||
} epd_driver_t;
|
||||
|
||||
/**@brief EPD Service structure.
|
||||
*
|
||||
* @details This structure contains status information related to the service.
|
||||
@@ -94,6 +75,7 @@ typedef struct
|
||||
bool is_notification_enabled; /**< Variable to indicate if the peer has enabled notification of the RX characteristic.*/
|
||||
epd_driver_t *driver; /**< current EPD driver */
|
||||
epd_config_t config; /**< EPD config */
|
||||
epd_callback_t epd_cmd_cb; /**< EPD callback */
|
||||
} ble_epd_t;
|
||||
|
||||
/**@brief Function for preparing sleep mode.
|
||||
@@ -107,12 +89,12 @@ void ble_epd_sleep_prepare(ble_epd_t * p_epd);
|
||||
* @param[out] p_epd EPD Service structure. This structure must be supplied
|
||||
* by the application. It is initialized by this function and will
|
||||
* later be used to identify this particular service instance.
|
||||
* @param[in] p_epd_init Information needed to initialize the service.
|
||||
* @param[in] cmd_cb Time update callback
|
||||
*
|
||||
* @retval NRF_SUCCESS If the service was successfully initialized. Otherwise, an error code is returned.
|
||||
* @retval NRF_ERROR_NULL If either of the pointers p_epd or p_epd_init is NULL.
|
||||
*/
|
||||
uint32_t ble_epd_init(ble_epd_t * p_epd);
|
||||
uint32_t ble_epd_init(ble_epd_t * p_epd, epd_callback_t cmd_cb);
|
||||
|
||||
/**@brief Function for handling the EPD Service's BLE events.
|
||||
*
|
||||
|
||||
@@ -11,12 +11,9 @@
|
||||
* | Info : Basic version
|
||||
*
|
||||
******************************************************************************/
|
||||
#include "nrf_drv_spi.h"
|
||||
#include "DEV_Config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "nrf_drv_spi.h"
|
||||
#include "EPD_driver.h"
|
||||
|
||||
uint32_t EPD_MOSI_PIN = 5;
|
||||
uint32_t EPD_SCLK_PIN = 8;
|
||||
@@ -28,6 +25,50 @@ uint32_t EPD_BS_PIN = 13;
|
||||
|
||||
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(0);
|
||||
|
||||
extern epd_driver_t epd_driver_4in2;
|
||||
extern epd_driver_t epd_driver_4in2v2;
|
||||
extern epd_driver_t epd_driver_4in2bv2;
|
||||
|
||||
/** EPD drivers */
|
||||
static epd_driver_t *epd_drivers[] = {
|
||||
&epd_driver_4in2,
|
||||
&epd_driver_4in2v2,
|
||||
&epd_driver_4in2bv2,
|
||||
};
|
||||
|
||||
/**< current EPD driver */
|
||||
static epd_driver_t *m_driver = NULL;
|
||||
|
||||
epd_driver_t *epd_driver_get(void)
|
||||
{
|
||||
if (m_driver == NULL)
|
||||
m_driver = epd_drivers[0];
|
||||
return m_driver;
|
||||
}
|
||||
|
||||
epd_driver_t *epd_driver_by_id(uint8_t id)
|
||||
{
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(epd_drivers); i++)
|
||||
{
|
||||
if (epd_drivers[i]->id == id)
|
||||
{
|
||||
return epd_drivers[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool epd_driver_set(uint8_t id)
|
||||
{
|
||||
epd_driver_t *driver = epd_driver_by_id(id);
|
||||
if (driver )
|
||||
{
|
||||
m_driver = driver;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
function: Initialize Arduino, Initialize Pins, and SPI
|
||||
parameter:
|
||||
@@ -57,10 +98,21 @@ UBYTE DEV_Module_Init(void)
|
||||
DEV_Digital_Write(EPD_DC_PIN, 0);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_Digital_Write(EPD_RST_PIN, 1);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DEV_Module_Exit(void)
|
||||
{
|
||||
DEV_Digital_Write(EPD_DC_PIN, 0);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
|
||||
//close 5V
|
||||
DEV_Digital_Write(EPD_RST_PIN, 0);
|
||||
|
||||
nrf_drv_spi_uninit(&spi);
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
function: Hardware interface
|
||||
note:
|
||||
@@ -84,13 +136,26 @@ UBYTE DEV_SPI_ReadByte(void)
|
||||
return value;
|
||||
}
|
||||
|
||||
void DEV_Module_Exit(void)
|
||||
void EPD_WriteCommand(UBYTE Reg)
|
||||
{
|
||||
DEV_Digital_Write(EPD_DC_PIN, 0);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
|
||||
//close 5V
|
||||
DEV_Digital_Write(EPD_RST_PIN, 0);
|
||||
|
||||
nrf_drv_spi_uninit(&spi);
|
||||
DEV_SPI_WriteByte(Reg);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
|
||||
void EPD_WriteByte(UBYTE Data)
|
||||
{
|
||||
DEV_Digital_Write(EPD_DC_PIN, 1);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_SPI_WriteByte(Data);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
|
||||
void EPD_WriteData(UBYTE *Data, UBYTE Len)
|
||||
{
|
||||
DEV_Digital_Write(EPD_DC_PIN, 1);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||
DEV_SPI_WriteBytes(Data, Len);
|
||||
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||
}
|
||||
95
EPD/EPD_driver.h
Normal file
95
EPD/EPD_driver.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*****************************************************************************
|
||||
* | File : DEV_Config.h
|
||||
* | Author : Waveshare team
|
||||
* | Function : debug with prntf
|
||||
* | Info :
|
||||
* Image scanning
|
||||
* Please use progressive scanning to generate images or fonts
|
||||
*----------------
|
||||
* | This version: V1.0
|
||||
* | Date : 2018-01-11
|
||||
* | Info : Basic version
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __EPD_DRIVER_H
|
||||
#define __EPD_DRIVER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "nrf_delay.h"
|
||||
#include "nrf_gpio.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* data
|
||||
**/
|
||||
#define UBYTE uint8_t
|
||||
#define UWORD uint16_t
|
||||
#define UDOUBLE uint32_t
|
||||
|
||||
/**< EPD driver IDs. */
|
||||
enum EPD_DRIVER_IDS
|
||||
{
|
||||
EPD_DRIVER_4IN2 = 1,
|
||||
EPD_DRIVER_4IN2_V2,
|
||||
EPD_DRIVER_4IN2B_V2,
|
||||
};
|
||||
|
||||
/**@brief EPD driver structure.
|
||||
*
|
||||
* @details This structure contains epd driver functions.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t id; /**< driver ID. */
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
void (*init)(void); /**< Initialize the e-Paper register */
|
||||
void (*clear)(void); /**< Clear screen */
|
||||
void (*send_command)(UBYTE Reg); /**< send command */
|
||||
void (*send_byte)(UBYTE Reg); /**< send byte */
|
||||
void (*send_data)(UBYTE *Data, UBYTE Len); /**< send data */
|
||||
void (*write_image)(UBYTE *black, UBYTE *color, UWORD x, UWORD y, UWORD w, UWORD h); /**< write image */
|
||||
void (*display)(void); /**< Sends the image buffer in RAM to e-Paper and displays */
|
||||
void (*sleep)(void); /**< Enter sleep mode */
|
||||
} epd_driver_t;
|
||||
|
||||
extern uint32_t EPD_MOSI_PIN;
|
||||
extern uint32_t EPD_SCLK_PIN;
|
||||
extern uint32_t EPD_CS_PIN;
|
||||
extern uint32_t EPD_DC_PIN;
|
||||
extern uint32_t EPD_RST_PIN;
|
||||
extern uint32_t EPD_BUSY_PIN;
|
||||
extern uint32_t EPD_BS_PIN;
|
||||
|
||||
/**
|
||||
* GPIO read and write
|
||||
**/
|
||||
#define DEV_Digital_Write(_pin, _value) nrf_gpio_pin_write(_pin, _value)
|
||||
#define DEV_Digital_Read(_pin) nrf_gpio_pin_read(_pin)
|
||||
|
||||
/**
|
||||
* delay x ms
|
||||
**/
|
||||
#define DEV_Delay_ms(__xms) nrf_delay_ms(__xms);
|
||||
#define DEV_Delay_us(__xus) nrf_delay_us(__xus);
|
||||
|
||||
UBYTE DEV_Module_Init(void);
|
||||
void DEV_Module_Exit(void);
|
||||
|
||||
void DEV_SPI_WriteByte(UBYTE value);
|
||||
void DEV_SPI_WriteBytes(UBYTE *value, UBYTE len);
|
||||
|
||||
void EPD_WriteCommand(UBYTE Reg);
|
||||
void EPD_WriteByte(UBYTE Data);
|
||||
void EPD_WriteData(UBYTE *Data, UBYTE Len);
|
||||
|
||||
epd_driver_t *epd_driver_get(void);
|
||||
epd_driver_t *epd_driver_by_id(uint8_t id);
|
||||
bool epd_driver_set(uint8_t id);
|
||||
|
||||
#endif
|
||||
943
GUI/Adafruit_GFX.c
Normal file
943
GUI/Adafruit_GFX.c
Normal 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
91
GUI/Adafruit_GFX.h
Normal 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
106
GUI/Calendar.c
Normal 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
8
GUI/Calendar.h
Normal 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
550
GUI/Lunar.c
Normal 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; // 获得节气顺序标号(0~23
|
||||
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; // 获得节气顺序标号(0~23
|
||||
|
||||
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
53
GUI/Lunar.h
Normal 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
135
GUI/fonts.c
Normal 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
37
GUI/fonts.h
Normal 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
573
GUI/u8g2_font.c
Normal 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
157
GUI/u8g2_font.h
Normal 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
|
||||
1244
Keil/EPD.uvprojx
1244
Keil/EPD.uvprojx
File diff suppressed because it is too large
Load Diff
22
Makefile
22
Makefile
@@ -20,13 +20,8 @@ SRC_FILES += \
|
||||
$(SDK_ROOT)/components/libraries/fstorage/fstorage.c \
|
||||
$(SDK_ROOT)/components/drivers_nrf/common/nrf_drv_common.c \
|
||||
$(SDK_ROOT)/components/drivers_nrf/clock/nrf_drv_clock.c \
|
||||
$(SDK_ROOT)/components/drivers_nrf/gpiote/nrf_drv_gpiote.c \
|
||||
$(SDK_ROOT)/components/drivers_nrf/spi_master/nrf_drv_spi.c \
|
||||
$(PROJ_DIR)/main.c \
|
||||
$(PROJ_DIR)/EPD/DEV_Config.c \
|
||||
$(PROJ_DIR)/EPD/EPD_4in2.c \
|
||||
$(PROJ_DIR)/EPD/EPD_4in2_V2.c \
|
||||
$(PROJ_DIR)/EPD/EPD_4in2b_V2.c \
|
||||
$(PROJ_DIR)/EPD/EPD_ble.c \
|
||||
$(SDK_ROOT)/components/drivers_ext/segger_rtt/RTT_Syscalls_GCC.c \
|
||||
$(SDK_ROOT)/components/drivers_ext/segger_rtt/SEGGER_RTT.c \
|
||||
$(SDK_ROOT)/components/drivers_ext/segger_rtt/SEGGER_RTT_printf.c \
|
||||
@@ -36,17 +31,30 @@ SRC_FILES += \
|
||||
$(SDK_ROOT)/components/ble/common/ble_srv_common.c \
|
||||
$(SDK_ROOT)/components/toolchain/gcc/gcc_startup_nrf51.s \
|
||||
$(SDK_ROOT)/components/toolchain/system_nrf51.c \
|
||||
$(SDK_ROOT)/components/softdevice/common/softdevice_handler/softdevice_handler.c
|
||||
$(SDK_ROOT)/components/softdevice/common/softdevice_handler/softdevice_handler.c \
|
||||
$(PROJ_DIR)/main.c \
|
||||
$(PROJ_DIR)/EPD/EPD_4in2.c \
|
||||
$(PROJ_DIR)/EPD/EPD_4in2_V2.c \
|
||||
$(PROJ_DIR)/EPD/EPD_4in2b_V2.c \
|
||||
$(PROJ_DIR)/EPD/EPD_driver.c \
|
||||
$(PROJ_DIR)/EPD/EPD_ble.c \
|
||||
$(PROJ_DIR)/GUI/Calendar.c \
|
||||
$(PROJ_DIR)/GUI/Lunar.c \
|
||||
$(PROJ_DIR)/GUI/fonts.c \
|
||||
$(PROJ_DIR)/GUI/Adafruit_GFX.c \
|
||||
$(PROJ_DIR)/GUI/u8g2_font.c
|
||||
|
||||
# Include folders common to all targets
|
||||
INC_FOLDERS += \
|
||||
$(PROJ_DIR)/config \
|
||||
$(PROJ_DIR)/EPD \
|
||||
$(PROJ_DIR)/GUI \
|
||||
$(SDK_ROOT)/components/toolchain \
|
||||
$(SDK_ROOT)/components/drivers_nrf/clock \
|
||||
$(SDK_ROOT)/components/drivers_nrf/hal \
|
||||
$(SDK_ROOT)/components/drivers_nrf/common \
|
||||
$(SDK_ROOT)/components/drivers_nrf/delay \
|
||||
$(SDK_ROOT)/components/drivers_nrf/gpiote \
|
||||
$(SDK_ROOT)/components/drivers_nrf/spi_master \
|
||||
$(SDK_ROOT)/components/drivers_ext/segger_rtt \
|
||||
$(SDK_ROOT)/components/libraries/fstorage \
|
||||
|
||||
13
README.md
13
README.md
@@ -48,15 +48,14 @@
|
||||
## 开发
|
||||
|
||||
> **注意:**
|
||||
> - 必须使用 [Keil 5.36](https://img.anfulai.cn/bbs/96992/MDK536.EXE) 或以下版本,nRF51 SDK 只支持 V5 版本的 ARM 编译器,从 5.37 版本开始 Keil 已经不再内置 V5 版本编译器。
|
||||
> - `sdk10` 分支为旧版 SDK 代码归档(不再维护),好处是蓝牙协议栈占用的空间小一些,对于小 ROM 芯片友好一点点。
|
||||
> - 必须使用 [Keil 5.36](https://img.anfulai.cn/bbs/96992/MDK536.EXE) 或以下版本,nRF51 SDK 只支持 V5 版本的 ARM 编译器,从 5.37 版本开始 Keil 已经不再内置 V5 版本编译器
|
||||
> - `sdk10` 分支为旧版 SDK 代码,蓝牙协议栈占用的空间小一些,用于支持 128K Flash 芯片
|
||||
> - **交流群:** [1033086563](https://qm.qq.com/q/WEBAZgyyc2) (点击链接加入群聊)
|
||||
|
||||
项目配置有几个 `Target`:
|
||||
|
||||
- `nRF51822_xxAB`: 用于编译 nRF51822 固件, 内置黑白双色版本配置
|
||||
- `nRF51802_xxAA`: 用于编译 nRF51802 固件, 内置黑白红三色版本配置
|
||||
- `flash_softdevice` 结尾的 `Target`: 刷蓝牙协议栈用(只需刷一次)
|
||||
- `nRF51802_xxAA`: 用于编译 256K Flash 固件
|
||||
- `flash_softdevice`: 刷蓝牙协议栈用(只需刷一次)
|
||||
|
||||
烧录器可以使用 J-Link 或者 DAPLink(可使用 [RTTView](https://github.com/XIVN1987/RTTView) 查看 RTT 日志)。
|
||||
|
||||
@@ -65,8 +64,8 @@
|
||||
> 如不修改代码,建议到 [Releases](https://github.com/tsl0922/EPD-nRF51/releases) 下载二进制固件,开箱即用。
|
||||
|
||||
1. 全部擦除 (Keil 擦除后刷不了的话,使用烧录器的上位机软件擦除试试)
|
||||
2. 切换到 MCU 对应的 `flash_softdevice` `Target`,**不要编译直接下载**(只需刷一次)
|
||||
3. 切换到 MCU 对应的 `Target`,先编译再下载
|
||||
2. 切换到 `flash_softdevice`,**不要编译直接下载**(只需刷一次)
|
||||
3. 切换到 `nRF51802_xxAA`,先编译再下载
|
||||
|
||||
## 致谢
|
||||
|
||||
|
||||
@@ -638,7 +638,7 @@
|
||||
// <e> GPIOTE_ENABLED - nrf_drv_gpiote - GPIOTE peripheral driver
|
||||
//==========================================================
|
||||
#ifndef GPIOTE_ENABLED
|
||||
#define GPIOTE_ENABLED 0
|
||||
#define GPIOTE_ENABLED 1
|
||||
#endif
|
||||
#if GPIOTE_ENABLED
|
||||
// <o> GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS - Number of lower power input pins
|
||||
@@ -3558,7 +3558,7 @@
|
||||
// <4=> Debug
|
||||
|
||||
#ifndef NRF_LOG_DEFAULT_LEVEL
|
||||
#define NRF_LOG_DEFAULT_LEVEL 3
|
||||
#define NRF_LOG_DEFAULT_LEVEL 4
|
||||
#endif
|
||||
|
||||
// <e> NRF_LOG_DEFERRED - Enable deffered logger.
|
||||
@@ -3585,7 +3585,7 @@
|
||||
// <i> Function for getting the timestamp is provided by the user
|
||||
|
||||
#ifndef NRF_LOG_USES_TIMESTAMP
|
||||
#define NRF_LOG_USES_TIMESTAMP 0
|
||||
#define NRF_LOG_USES_TIMESTAMP 1
|
||||
#endif
|
||||
|
||||
#endif //NRF_LOG_ENABLED
|
||||
|
||||
176
main.c
176
main.c
@@ -24,7 +24,9 @@
|
||||
#include "fstorage.h"
|
||||
#include "app_error.h"
|
||||
#include "app_timer.h"
|
||||
#include "nrf_drv_gpiote.h"
|
||||
#include "EPD_ble.h"
|
||||
#include "Calendar.h"
|
||||
#define NRF_LOG_MODULE_NAME "main"
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_log_ctrl.h"
|
||||
@@ -33,8 +35,8 @@
|
||||
#define PERIPHERAL_LINK_COUNT 1 /**< Number of peripheral links used by the application. When changing this number remember to adjust the RAM settings*/
|
||||
|
||||
#define DEVICE_NAME "NRF_EPD" /**< Name of device. Will be included in the advertising data. */
|
||||
#define APP_ADV_INTERVAL 300 /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */
|
||||
#define APP_ADV_TIMEOUT_IN_SECONDS 180 /**< The advertising timeout (in units of seconds). */
|
||||
#define APP_ADV_INTERVAL 320 /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */
|
||||
#define APP_ADV_TIMEOUT_IN_SECONDS 120 /**< The advertising timeout (in units of seconds). */
|
||||
#define APP_TIMER_PRESCALER 0 /**< Value of the RTC1 PRESCALER register. */
|
||||
#define APP_TIMER_OP_QUEUE_SIZE 4 /**< Size of timer operation queues. */
|
||||
|
||||
@@ -47,11 +49,37 @@
|
||||
#define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(30000, APP_TIMER_PRESCALER) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
|
||||
#define MAX_CONN_PARAMS_UPDATE_COUNT 3 /**< Number of attempts before giving up the connection parameter negotiation. */
|
||||
|
||||
#define CLOCK_TIMER_INTERVAL APP_TIMER_TICKS(1000, APP_TIMER_PRESCALER) /**< Clock timer interval (ticks). */
|
||||
|
||||
#define DEAD_BEEF 0xDEADBEEF /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
|
||||
|
||||
static uint16_t m_driver_refs = 0;
|
||||
static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle of the current connection. */
|
||||
static ble_uuid_t m_adv_uuids[] = {{BLE_UUID_EPD_SERVICE, EPD_SERVICE_UUID_TYPE}}; /**< Universally unique service identifier. */
|
||||
static ble_epd_t m_epd; /**< Structure to identify the EPD Service. */
|
||||
static uint32_t m_timestamp = 1735689600; /**< Current timestamp. */
|
||||
static bool m_update_calendar = false; /**< Update calendar if true */
|
||||
static bool m_calendar_mode = false; /**< Whether we are in calendar mode */
|
||||
|
||||
APP_TIMER_DEF(m_clock_timer_id); /**< Clock timer. */
|
||||
|
||||
static void epd_driver_init()
|
||||
{
|
||||
if (m_driver_refs == 0) {
|
||||
NRF_LOG_DEBUG("[EPD]: driver init\n");
|
||||
DEV_Module_Init();
|
||||
}
|
||||
m_driver_refs++;
|
||||
}
|
||||
|
||||
static void epd_driver_exit()
|
||||
{
|
||||
m_driver_refs--;
|
||||
if (m_driver_refs == 0) {
|
||||
NRF_LOG_DEBUG("[EPD]: driver exit\n");
|
||||
DEV_Module_Exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**@brief Callback function for asserts in the SoftDevice.
|
||||
*
|
||||
@@ -69,6 +97,19 @@ void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
|
||||
app_error_handler(DEAD_BEEF, line_num, p_file_name);
|
||||
}
|
||||
|
||||
static void clock_timer_timeout_handler(void * p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(p_context);
|
||||
|
||||
m_timestamp++;
|
||||
|
||||
// Update calendar on 00:00:00
|
||||
if (m_calendar_mode && m_timestamp % 86400 == 0)
|
||||
{
|
||||
m_update_calendar = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**@brief Function for the Timer initialization.
|
||||
*
|
||||
* @details Initializes the timer module. This creates and starts application timers.
|
||||
@@ -77,6 +118,54 @@ static void timers_init(void)
|
||||
{
|
||||
// Initialize timer module.
|
||||
APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
|
||||
|
||||
// Create timers.
|
||||
uint32_t err_code = app_timer_create(&m_clock_timer_id,
|
||||
APP_TIMER_MODE_REPEATED,
|
||||
clock_timer_timeout_handler);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
/**@brief Function for starting application timers.
|
||||
*/
|
||||
static void application_timers_start(void)
|
||||
{
|
||||
// Start application timers.
|
||||
uint32_t err_code = app_timer_start(m_clock_timer_id, CLOCK_TIMER_INTERVAL, NULL);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
bool epd_cmd_callback(uint8_t cmd, uint8_t *data, uint16_t len)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case EPD_CMD_SET_TIME:
|
||||
if (len < 4) {
|
||||
NRF_LOG_DEBUG("invalid time data!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
NRF_LOG_DEBUG("time: %02x %02x %02x %02x\n", data[0], data[1], data[2], data[3]);
|
||||
if (len > 4) {
|
||||
NRF_LOG_DEBUG("timezone: %d\n", (int8_t)data[4]);
|
||||
}
|
||||
|
||||
app_timer_stop(m_clock_timer_id);
|
||||
m_timestamp = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
|
||||
m_timestamp += (len > 4 ? (int8_t)data[4] : 8) * 60 * 60; // timezone
|
||||
app_timer_start(m_clock_timer_id, CLOCK_TIMER_INTERVAL, NULL);
|
||||
|
||||
m_calendar_mode = true;
|
||||
m_update_calendar = true;
|
||||
return true;
|
||||
case EPD_CMD_CLEAR:
|
||||
case EPD_CMD_DISPLAY:
|
||||
m_calendar_mode = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**@brief Function for initializing services that will be used by the application.
|
||||
@@ -89,7 +178,7 @@ static void services_init(void)
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
memset(&m_epd, 0, sizeof(ble_epd_t));
|
||||
err_code = ble_epd_init(&m_epd);
|
||||
err_code = ble_epd_init(&m_epd, epd_cmd_callback);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
@@ -188,12 +277,21 @@ static void conn_params_init(void)
|
||||
}
|
||||
|
||||
|
||||
static void advertising_start(void)
|
||||
{
|
||||
NRF_LOG_INFO("advertising start\n");
|
||||
uint32_t err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
/**@brief Function for putting the chip into sleep mode.
|
||||
*
|
||||
* @note This function will not return.
|
||||
*/
|
||||
static void sleep_mode_enter(void)
|
||||
{
|
||||
NRF_LOG_DEBUG("Entering deep sleep mode\n");
|
||||
|
||||
// Prepare wakeup pin
|
||||
ble_epd_sleep_prepare(&m_epd);
|
||||
|
||||
@@ -202,6 +300,30 @@ static void sleep_mode_enter(void)
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
void gpiote_evt_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
|
||||
NRF_LOG_DEBUG("pin: %d, event: %d\n", pin, action);
|
||||
|
||||
nrf_drv_gpiote_in_event_disable(pin);
|
||||
nrf_drv_gpiote_in_uninit(pin);
|
||||
nrf_drv_gpiote_uninit();
|
||||
|
||||
advertising_start();
|
||||
}
|
||||
|
||||
static void setup_wakeup_pin(nrf_drv_gpiote_pin_t pin) {
|
||||
NRF_LOG_DEBUG("Setting up wakeup pin\n");
|
||||
|
||||
ret_code_t err_code = nrf_drv_gpiote_init();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
nrf_drv_gpiote_in_config_t config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(false);
|
||||
|
||||
err_code = nrf_drv_gpiote_in_init(pin, &config, gpiote_evt_handler);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
nrf_drv_gpiote_in_event_enable(pin, true);
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling advertising events.
|
||||
*
|
||||
@@ -216,7 +338,12 @@ static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
|
||||
case BLE_ADV_EVT_FAST:
|
||||
break;
|
||||
case BLE_ADV_EVT_IDLE:
|
||||
sleep_mode_enter();
|
||||
NRF_LOG_INFO("advertising timeout\n");
|
||||
if (m_calendar_mode) {
|
||||
setup_wakeup_pin(m_epd.config.wakeup_pin);
|
||||
} else {
|
||||
sleep_mode_enter();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -236,13 +363,14 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
NRF_LOG_INFO("CONNECTED\n");
|
||||
m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
epd_driver_init();
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
NRF_LOG_INFO("DISCONNECTED\n");
|
||||
m_conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
epd_driver_exit();
|
||||
advertising_start();
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
|
||||
@@ -404,13 +532,31 @@ static void power_manage(void)
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
static void calendar_update(void)
|
||||
{
|
||||
if (!m_update_calendar) return;
|
||||
|
||||
m_update_calendar = false;
|
||||
epd_driver_init();
|
||||
m_epd.driver->init();
|
||||
DrawCalendar(m_timestamp);
|
||||
epd_driver_exit();
|
||||
}
|
||||
|
||||
#if NRF_MODULE_ENABLED(NRF_LOG)
|
||||
static uint32_t timestamp_func(void)
|
||||
{
|
||||
return m_timestamp;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**@brief Function for application main entry.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
uint32_t err_code;
|
||||
|
||||
err_code = NRF_LOG_INIT(NULL);
|
||||
err_code = NRF_LOG_INIT(timestamp_func);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
NRF_LOG_DEBUG("init..\n");
|
||||
@@ -424,16 +570,20 @@ int main(void)
|
||||
conn_params_init();
|
||||
|
||||
NRF_LOG_DEBUG("start..\n");
|
||||
err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
// Start execution.
|
||||
application_timers_start();
|
||||
|
||||
advertising_start();
|
||||
|
||||
NRF_LOG_DEBUG("done.\n");
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (NRF_LOG_PROCESS() == false)
|
||||
{
|
||||
power_manage();
|
||||
}
|
||||
while(NRF_LOG_PROCESS());
|
||||
|
||||
calendar_update();
|
||||
|
||||
power_manage();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user