clang-format code

This commit is contained in:
Shuanglei Tao
2025-10-27 20:52:09 +08:00
parent bf6df54f49
commit 8211ca3202
19 changed files with 1974 additions and 2468 deletions

6
.clang-format Normal file
View File

@@ -0,0 +1,6 @@
BasedOnStyle: Google
Language: Cpp
ColumnLimit: 120
IndentWidth: 4
TabWidth: 4
UseTab: Never

View File

@@ -1,26 +1,25 @@
#include <string.h>
#include "nordic_common.h"
#include "fds.h"
#include "app_scheduler.h"
#include "EPD_config.h" #include "EPD_config.h"
#include <string.h>
#include "app_scheduler.h"
#include "fds.h"
#include "nordic_common.h"
#include "nrf_log.h" #include "nrf_log.h"
#define CONFIG_FILE_ID 0x0000 #define CONFIG_FILE_ID 0x0000
#define CONFIG_REC_KEY 0x0001 #define CONFIG_REC_KEY 0x0001
static void fds_evt_handler(fds_evt_t const * const p_fds_evt) static void fds_evt_handler(fds_evt_t const* const p_fds_evt) {
{
NRF_LOG_DEBUG("fds evt: id=%d result=%d\n", p_fds_evt->id, p_fds_evt->result); NRF_LOG_DEBUG("fds evt: id=%d result=%d\n", p_fds_evt->id, p_fds_evt->result);
} }
static void run_fds_gc(void * p_event_data, uint16_t event_size) static void run_fds_gc(void* p_event_data, uint16_t event_size) {
{
NRF_LOG_DEBUG("run garbage collection (fds_gc)\n"); NRF_LOG_DEBUG("run garbage collection (fds_gc)\n");
fds_gc(); fds_gc();
} }
void epd_config_init(epd_config_t *cfg) void epd_config_init(epd_config_t* cfg) {
{
ret_code_t ret; ret_code_t ret;
ret = fds_register(fds_evt_handler); ret = fds_register(fds_evt_handler);
@@ -38,11 +37,10 @@ void epd_config_init(epd_config_t *cfg)
run_fds_gc(NULL, 0); run_fds_gc(NULL, 0);
} }
void epd_config_read(epd_config_t *cfg) void epd_config_read(epd_config_t* cfg) {
{ fds_flash_record_t flash_record;
fds_flash_record_t flash_record; fds_record_desc_t record_desc;
fds_record_desc_t record_desc; fds_find_token_t ftok;
fds_find_token_t ftok;
memset(cfg, 0xFF, sizeof(epd_config_t)); memset(cfg, 0xFF, sizeof(epd_config_t));
memset(&ftok, 0x00, sizeof(fds_find_token_t)); memset(&ftok, 0x00, sizeof(fds_find_token_t));
@@ -64,12 +62,11 @@ void epd_config_read(epd_config_t *cfg)
fds_record_close(&record_desc); fds_record_close(&record_desc);
} }
void epd_config_write(epd_config_t *cfg) void epd_config_write(epd_config_t* cfg) {
{ ret_code_t ret;
ret_code_t ret; fds_record_t record;
fds_record_t record; fds_record_desc_t record_desc;
fds_record_desc_t record_desc; fds_find_token_t ftok;
fds_find_token_t ftok;
record.file_id = CONFIG_FILE_ID; record.file_id = CONFIG_FILE_ID;
record.key = CONFIG_REC_KEY; record.key = CONFIG_REC_KEY;
@@ -93,16 +90,14 @@ void epd_config_write(epd_config_t *cfg)
if (ret != NRF_SUCCESS) { if (ret != NRF_SUCCESS) {
NRF_LOG_ERROR("epd_config_save: record write/update failed, code=%d\n", ret); NRF_LOG_ERROR("epd_config_save: record write/update failed, code=%d\n", ret);
if (ret == FDS_ERR_NO_SPACE_IN_FLASH) if (ret == FDS_ERR_NO_SPACE_IN_FLASH) app_sched_event_put(NULL, 0, run_fds_gc);
app_sched_event_put(NULL, 0, run_fds_gc);
} }
} }
void epd_config_clear(epd_config_t *cfg) void epd_config_clear(epd_config_t* cfg) {
{ ret_code_t ret;
ret_code_t ret; fds_record_desc_t record_desc;
fds_record_desc_t record_desc; fds_find_token_t ftok;
fds_find_token_t ftok;
memset(&ftok, 0x00, sizeof(fds_find_token_t)); memset(&ftok, 0x00, sizeof(fds_find_token_t));
if (fds_record_find(CONFIG_FILE_ID, CONFIG_REC_KEY, &record_desc, &ftok) != NRF_SUCCESS) { if (fds_record_find(CONFIG_FILE_ID, CONFIG_REC_KEY, &record_desc, &ftok) != NRF_SUCCESS) {
@@ -116,11 +111,9 @@ void epd_config_clear(epd_config_t *cfg)
} }
} }
bool epd_config_empty(epd_config_t *cfg) bool epd_config_empty(epd_config_t* cfg) {
{
for (uint8_t i = 0; i < EPD_CONFIG_SIZE; i++) { for (uint8_t i = 0; i < EPD_CONFIG_SIZE; i++) {
if (((uint8_t *)cfg)[i] != 0xFF) if (((uint8_t*)cfg)[i] != 0xFF) return false;
return false;
} }
return true; return true;
} }

View File

@@ -3,8 +3,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
typedef struct typedef struct {
{
uint8_t mosi_pin; uint8_t mosi_pin;
uint8_t sclk_pin; uint8_t sclk_pin;
uint8_t cs_pin; uint8_t cs_pin;
@@ -21,11 +20,11 @@ typedef struct
} epd_config_t; } epd_config_t;
#define EPD_CONFIG_SIZE (sizeof(epd_config_t) / sizeof(uint8_t)) #define EPD_CONFIG_SIZE (sizeof(epd_config_t) / sizeof(uint8_t))
void epd_config_init(epd_config_t *cfg); void epd_config_init(epd_config_t* cfg);
void epd_config_read(epd_config_t *cfg); void epd_config_read(epd_config_t* cfg);
void epd_config_write(epd_config_t *cfg); void epd_config_write(epd_config_t* cfg);
void epd_config_clear(epd_config_t *cfg); void epd_config_clear(epd_config_t* cfg);
bool epd_config_empty(epd_config_t *cfg); bool epd_config_empty(epd_config_t* cfg);
#endif #endif

View File

@@ -1,6 +1,7 @@
#include "EPD_driver.h"
#include "app_error.h" #include "app_error.h"
#include "nrf_drv_spi.h" #include "nrf_drv_spi.h"
#include "EPD_driver.h"
#include "nrf_log.h" #include "nrf_log.h"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
@@ -17,26 +18,22 @@ static uint32_t EPD_BS_PIN = 13;
static uint32_t EPD_EN_PIN = 0xFF; static uint32_t EPD_EN_PIN = 0xFF;
static uint32_t EPD_LED_PIN = 0xFF; static uint32_t EPD_LED_PIN = 0xFF;
#define SPI_INSTANCE 0 /**< SPI instance index. */ #define SPI_INSTANCE 0 /**< SPI instance index. */
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); /**< SPI instance. */ static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); /**< SPI instance. */
#if defined(S112) #if defined(S112)
#define HAL_SPI_INSTANCE spi.u.spi.p_reg #define HAL_SPI_INSTANCE spi.u.spi.p_reg
#else #else
#define HAL_SPI_INSTANCE spi.p_registers #define HAL_SPI_INSTANCE spi.p_registers
nrf_gpio_pin_dir_t nrf_gpio_pin_dir_get(uint32_t pin) nrf_gpio_pin_dir_t nrf_gpio_pin_dir_get(uint32_t pin) {
{ NRF_GPIO_Type* reg = nrf_gpio_pin_port_decode(&pin);
NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin); return (nrf_gpio_pin_dir_t)((reg->PIN_CNF[pin] & GPIO_PIN_CNF_DIR_Msk) >> GPIO_PIN_CNF_DIR_Pos);
return (nrf_gpio_pin_dir_t)((reg->PIN_CNF[pin] &
GPIO_PIN_CNF_DIR_Msk) >> GPIO_PIN_CNF_DIR_Pos);
} }
#endif #endif
// Arduino like function wrappers // Arduino like function wrappers
void pinMode(uint32_t pin, uint32_t mode) void pinMode(uint32_t pin, uint32_t mode) {
{ switch (mode) {
switch (mode)
{
case INPUT: case INPUT:
nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL); nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL);
break; break;
@@ -59,8 +56,7 @@ void pinMode(uint32_t pin, uint32_t mode)
// GPIO // GPIO
static uint16_t m_driver_refs = 0; static uint16_t m_driver_refs = 0;
void EPD_GPIO_Load(epd_config_t *cfg) void EPD_GPIO_Load(epd_config_t* cfg) {
{
if (cfg == NULL) return; if (cfg == NULL) return;
EPD_MOSI_PIN = cfg->mosi_pin; EPD_MOSI_PIN = cfg->mosi_pin;
EPD_SCLK_PIN = cfg->sclk_pin; EPD_SCLK_PIN = cfg->sclk_pin;
@@ -73,8 +69,7 @@ void EPD_GPIO_Load(epd_config_t *cfg)
EPD_LED_PIN = cfg->led_pin; EPD_LED_PIN = cfg->led_pin;
} }
void EPD_GPIO_Init(void) void EPD_GPIO_Init(void) {
{
if (m_driver_refs++ > 0) return; if (m_driver_refs++ > 0) return;
pinMode(EPD_DC_PIN, OUTPUT); pinMode(EPD_DC_PIN, OUTPUT);
@@ -103,14 +98,12 @@ void EPD_GPIO_Init(void)
digitalWrite(EPD_DC_PIN, LOW); digitalWrite(EPD_DC_PIN, LOW);
digitalWrite(EPD_RST_PIN, HIGH); digitalWrite(EPD_RST_PIN, HIGH);
if (EPD_LED_PIN != 0xFF) if (EPD_LED_PIN != 0xFF) pinMode(EPD_LED_PIN, OUTPUT);
pinMode(EPD_LED_PIN, OUTPUT);
EPD_LED_ON(); EPD_LED_ON();
} }
void EPD_GPIO_Uninit(void) void EPD_GPIO_Uninit(void) {
{
if (--m_driver_refs > 0) return; if (--m_driver_refs > 0) return;
EPD_LED_OFF(); EPD_LED_OFF();
@@ -120,8 +113,7 @@ void EPD_GPIO_Uninit(void)
digitalWrite(EPD_DC_PIN, LOW); digitalWrite(EPD_DC_PIN, LOW);
digitalWrite(EPD_CS_PIN, LOW); digitalWrite(EPD_CS_PIN, LOW);
digitalWrite(EPD_RST_PIN, LOW); digitalWrite(EPD_RST_PIN, LOW);
if (EPD_EN_PIN != 0xFF) if (EPD_EN_PIN != 0xFF) digitalWrite(EPD_EN_PIN, LOW);
digitalWrite(EPD_EN_PIN, LOW);
// reset pin state // reset pin state
pinMode(EPD_MOSI_PIN, DEFAULT); pinMode(EPD_MOSI_PIN, DEFAULT);
@@ -136,8 +128,7 @@ void EPD_GPIO_Uninit(void)
} }
// SPI // SPI
void EPD_SPI_Write(uint8_t *value, uint8_t len) void EPD_SPI_Write(uint8_t* value, uint8_t len) {
{
nrf_gpio_pin_dir_t dir = nrf_gpio_pin_dir_get(EPD_MOSI_PIN); nrf_gpio_pin_dir_t dir = nrf_gpio_pin_dir_get(EPD_MOSI_PIN);
if (dir != NRF_GPIO_PIN_DIR_OUTPUT) { if (dir != NRF_GPIO_PIN_DIR_OUTPUT) {
pinMode(EPD_MOSI_PIN, OUTPUT); pinMode(EPD_MOSI_PIN, OUTPUT);
@@ -146,8 +137,7 @@ void EPD_SPI_Write(uint8_t *value, uint8_t len)
APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, value, len, NULL, 0)); APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, value, len, NULL, 0));
} }
void EPD_SPI_Read(uint8_t *value, uint8_t len) void EPD_SPI_Read(uint8_t* value, uint8_t len) {
{
nrf_gpio_pin_dir_t dir = nrf_gpio_pin_dir_get(EPD_MOSI_PIN); nrf_gpio_pin_dir_t dir = nrf_gpio_pin_dir_get(EPD_MOSI_PIN);
if (dir != NRF_GPIO_PIN_DIR_INPUT) { if (dir != NRF_GPIO_PIN_DIR_INPUT) {
pinMode(EPD_MOSI_PIN, INPUT); pinMode(EPD_MOSI_PIN, INPUT);
@@ -157,43 +147,36 @@ void EPD_SPI_Read(uint8_t *value, uint8_t len)
} }
// EPD // EPD
void EPD_WriteCmd(uint8_t cmd) void EPD_WriteCmd(uint8_t cmd) {
{
digitalWrite(EPD_DC_PIN, LOW); digitalWrite(EPD_DC_PIN, LOW);
EPD_SPI_Write(&cmd, 1); EPD_SPI_Write(&cmd, 1);
} }
void EPD_WriteData(uint8_t *value, uint8_t len) void EPD_WriteData(uint8_t* value, uint8_t len) {
{
digitalWrite(EPD_DC_PIN, HIGH); digitalWrite(EPD_DC_PIN, HIGH);
EPD_SPI_Write(value, len); EPD_SPI_Write(value, len);
} }
void EPD_ReadData(uint8_t *value, uint8_t len) void EPD_ReadData(uint8_t* value, uint8_t len) {
{
digitalWrite(EPD_DC_PIN, HIGH); digitalWrite(EPD_DC_PIN, HIGH);
EPD_SPI_Read(value, len); EPD_SPI_Read(value, len);
} }
void EPD_WriteByte(uint8_t value) void EPD_WriteByte(uint8_t value) {
{
digitalWrite(EPD_DC_PIN, HIGH); digitalWrite(EPD_DC_PIN, HIGH);
EPD_SPI_Write(&value, 1); EPD_SPI_Write(&value, 1);
} }
uint8_t EPD_ReadByte(void) uint8_t EPD_ReadByte(void) {
{
uint8_t value; uint8_t value;
digitalWrite(EPD_DC_PIN, HIGH); digitalWrite(EPD_DC_PIN, HIGH);
EPD_SPI_Read(&value, 1); EPD_SPI_Read(&value, 1);
return value; return value;
} }
void EPD_FillRAM(uint8_t cmd, uint8_t value, uint32_t len) void EPD_FillRAM(uint8_t cmd, uint8_t value, uint32_t len) {
{
uint8_t buffer[BUFFER_SIZE]; uint8_t buffer[BUFFER_SIZE];
for (uint8_t i = 0; i < BUFFER_SIZE; i++) for (uint8_t i = 0; i < BUFFER_SIZE; i++) buffer[i] = value;
buffer[i] = value;
EPD_WriteCmd(cmd); EPD_WriteCmd(cmd);
uint16_t remaining = len; uint16_t remaining = len;
@@ -204,8 +187,7 @@ void EPD_FillRAM(uint8_t cmd, uint8_t value, uint32_t len)
} }
} }
void EPD_Reset(uint32_t value, uint16_t duration) void EPD_Reset(uint32_t value, uint16_t duration) {
{
digitalWrite(EPD_RST_PIN, value); digitalWrite(EPD_RST_PIN, value);
delay(duration); delay(duration);
digitalWrite(EPD_RST_PIN, (value == LOW) ? HIGH : LOW); digitalWrite(EPD_RST_PIN, (value == LOW) ? HIGH : LOW);
@@ -214,8 +196,7 @@ void EPD_Reset(uint32_t value, uint16_t duration)
delay(duration); delay(duration);
} }
void EPD_WaitBusy(uint32_t value, uint16_t timeout) void EPD_WaitBusy(uint32_t value, uint16_t timeout) {
{
uint32_t led_status = digitalRead(EPD_LED_PIN); uint32_t led_status = digitalRead(EPD_LED_PIN);
NRF_LOG_DEBUG("[EPD]: check busy\n"); NRF_LOG_DEBUG("[EPD]: check busy\n");
@@ -238,26 +219,19 @@ void EPD_WaitBusy(uint32_t value, uint16_t timeout)
} }
// lED // lED
void EPD_LED_ON(void) void EPD_LED_ON(void) {
{ if (EPD_LED_PIN != 0xFF) digitalWrite(EPD_LED_PIN, LOW);
if (EPD_LED_PIN != 0xFF)
digitalWrite(EPD_LED_PIN, LOW);
} }
void EPD_LED_OFF(void) void EPD_LED_OFF(void) {
{ if (EPD_LED_PIN != 0xFF) digitalWrite(EPD_LED_PIN, HIGH);
if (EPD_LED_PIN != 0xFF)
digitalWrite(EPD_LED_PIN, HIGH);
} }
void EPD_LED_Toggle(void) void EPD_LED_Toggle(void) {
{ if (EPD_LED_PIN != 0xFF) nrf_gpio_pin_toggle(EPD_LED_PIN);
if (EPD_LED_PIN != 0xFF)
nrf_gpio_pin_toggle(EPD_LED_PIN);
} }
void EPD_LED_BLINK(void) void EPD_LED_BLINK(void) {
{
if (EPD_LED_PIN != 0xFF) { if (EPD_LED_PIN != 0xFF) {
pinMode(EPD_LED_PIN, OUTPUT); pinMode(EPD_LED_PIN, OUTPUT);
digitalWrite(EPD_LED_PIN, LOW); digitalWrite(EPD_LED_PIN, LOW);
@@ -268,18 +242,18 @@ void EPD_LED_BLINK(void)
} }
} }
float EPD_ReadVoltage(void) float EPD_ReadVoltage(void) {
{
#if defined(S112) #if defined(S112)
volatile int16_t value = 0; volatile int16_t value = 0;
NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_10bit; NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_10bit;
NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos); NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
NRF_SAADC->CH[0].CONFIG = ((SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos) & SAADC_CH_CONFIG_RESP_Msk) NRF_SAADC->CH[0].CONFIG =
| ((SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESN_Pos) & SAADC_CH_CONFIG_RESN_Msk) ((SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos) & SAADC_CH_CONFIG_RESP_Msk) |
| ((SAADC_CH_CONFIG_GAIN_Gain1_6 << SAADC_CH_CONFIG_GAIN_Pos) & SAADC_CH_CONFIG_GAIN_Msk) ((SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESN_Pos) & SAADC_CH_CONFIG_RESN_Msk) |
| ((SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk) ((SAADC_CH_CONFIG_GAIN_Gain1_6 << SAADC_CH_CONFIG_GAIN_Pos) & SAADC_CH_CONFIG_GAIN_Msk) |
| ((SAADC_CH_CONFIG_TACQ_3us << SAADC_CH_CONFIG_TACQ_Pos) & SAADC_CH_CONFIG_TACQ_Msk) ((SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk) |
| ((SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk); ((SAADC_CH_CONFIG_TACQ_3us << SAADC_CH_CONFIG_TACQ_Pos) & SAADC_CH_CONFIG_TACQ_Msk) |
((SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk);
NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELN_PSELN_NC; NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELN_PSELN_NC;
NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_VDD; NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_VDD;
NRF_SAADC->RESULT.PTR = (uint32_t)&value; NRF_SAADC->RESULT.PTR = (uint32_t)&value;
@@ -303,7 +277,7 @@ float EPD_ReadVoltage(void)
(ADC_CONFIG_PSEL_Disabled << ADC_CONFIG_PSEL_Pos) | (ADC_CONFIG_PSEL_Disabled << ADC_CONFIG_PSEL_Pos) |
(ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos); (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos);
NRF_ADC->TASKS_START = 1; NRF_ADC->TASKS_START = 1;
while(!NRF_ADC->EVENTS_END); while (!NRF_ADC->EVENTS_END);
NRF_ADC->EVENTS_END = 0; NRF_ADC->EVENTS_END = 0;
uint16_t value = NRF_ADC->RESULT; uint16_t value = NRF_ADC->RESULT;
NRF_ADC->TASKS_STOP = 1; NRF_ADC->TASKS_STOP = 1;
@@ -327,24 +301,14 @@ extern epd_model_t epd_ssd1677_750_bw;
extern epd_model_t epd_jd79668_420_bwry; extern epd_model_t epd_jd79668_420_bwry;
extern epd_model_t epd_jd79668_750_bwry; extern epd_model_t epd_jd79668_750_bwry;
static epd_model_t *epd_models[] = { static epd_model_t* epd_models[] = {
&epd_uc8176_420_bw, &epd_uc8176_420_bw, &epd_uc8176_420_bwr, &epd_uc8159_750_bw, &epd_uc8159_750_bwr,
&epd_uc8176_420_bwr, &epd_uc8179_750_bw, &epd_uc8179_750_bwr, &epd_ssd1619_420_bwr, &epd_ssd1619_420_bw,
&epd_uc8159_750_bw, &epd_ssd1677_750_bwr, &epd_ssd1677_750_bw, &epd_jd79668_420_bwry, &epd_jd79668_750_bwry,
&epd_uc8159_750_bwr,
&epd_uc8179_750_bw,
&epd_uc8179_750_bwr,
&epd_ssd1619_420_bwr,
&epd_ssd1619_420_bw,
&epd_ssd1677_750_bwr,
&epd_ssd1677_750_bw,
&epd_jd79668_420_bwry,
&epd_jd79668_750_bwry,
}; };
epd_model_t *epd_init(epd_model_id_t id) epd_model_t* epd_init(epd_model_id_t id) {
{ epd_model_t* epd = NULL;
epd_model_t *epd = NULL;
for (uint8_t i = 0; i < ARRAY_SIZE(epd_models); i++) { for (uint8_t i = 0; i < ARRAY_SIZE(epd_models); i++) {
if (epd_models[i]->id == id) { if (epd_models[i]->id == id) {
epd = epd_models[i]; epd = epd_models[i];

View File

@@ -4,13 +4,13 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include "EPD_config.h"
#include "nrf_delay.h" #include "nrf_delay.h"
#include "nrf_gpio.h" #include "nrf_gpio.h"
#include "EPD_config.h"
// EPD driver IC types // EPD driver IC types
typedef enum typedef enum {
{
EPD_DRIVER_IC_UC8159 = 0x10, EPD_DRIVER_IC_UC8159 = 0x10,
EPD_DRIVER_IC_UC8176 = 0x11, EPD_DRIVER_IC_UC8176 = 0x11,
EPD_DRIVER_IC_UC8179 = 0x12, EPD_DRIVER_IC_UC8179 = 0x12,
@@ -22,114 +22,112 @@ typedef enum
// UC81xx commands // UC81xx commands
enum { enum {
UC81xx_PSR = 0x00, // Panel Setting UC81xx_PSR = 0x00, // Panel Setting
UC81xx_PWR = 0x01, // Power Setting UC81xx_PWR = 0x01, // Power Setting
UC81xx_POF = 0x02, // Power OFF UC81xx_POF = 0x02, // Power OFF
UC81xx_PFS = 0x03, // Power OFF Sequence Setting UC81xx_PFS = 0x03, // Power OFF Sequence Setting
UC81xx_PON = 0x04, // Power ON UC81xx_PON = 0x04, // Power ON
UC81xx_PMES = 0x05, // Power ON Measure UC81xx_PMES = 0x05, // Power ON Measure
UC81xx_BTST = 0x06, // Booster Soft Start UC81xx_BTST = 0x06, // Booster Soft Start
UC81xx_DSLP = 0x07, // Deep sleep UC81xx_DSLP = 0x07, // Deep sleep
UC81xx_DTM1 = 0x10, // Display Start Transmission 1 UC81xx_DTM1 = 0x10, // Display Start Transmission 1
UC81xx_DSP = 0x11, // Data Stop UC81xx_DSP = 0x11, // Data Stop
UC81xx_DRF = 0x12, // Display Refresh UC81xx_DRF = 0x12, // Display Refresh
UC81xx_DTM2 = 0x13, // Display Start transmission 2 UC81xx_DTM2 = 0x13, // Display Start transmission 2
UC81xx_LUTC = 0x20, // VCOM LUT (LUTC) UC81xx_LUTC = 0x20, // VCOM LUT (LUTC)
UC81xx_LUTWW = 0x21, // W2W LUT (LUTWW) UC81xx_LUTWW = 0x21, // W2W LUT (LUTWW)
UC81xx_LUTBW = 0x22, // B2W LUT (LUTBW / LUTR) UC81xx_LUTBW = 0x22, // B2W LUT (LUTBW / LUTR)
UC81xx_LUTWB = 0x23, // W2B LUT (LUTWB / LUTW) UC81xx_LUTWB = 0x23, // W2B LUT (LUTWB / LUTW)
UC81xx_LUTBB = 0x24, // B2B LUT (LUTBB / LUTB) UC81xx_LUTBB = 0x24, // B2B LUT (LUTBB / LUTB)
UC81xx_PLL = 0x30, // PLL control UC81xx_PLL = 0x30, // PLL control
UC81xx_TSC = 0x40, // Temperature Sensor Calibration UC81xx_TSC = 0x40, // Temperature Sensor Calibration
UC81xx_TSE = 0x41, // Temperature Sensor Selection UC81xx_TSE = 0x41, // Temperature Sensor Selection
UC81xx_TSW = 0x42, // Temperature Sensor Write UC81xx_TSW = 0x42, // Temperature Sensor Write
UC81xx_TSR = 0x43, // Temperature Sensor Read UC81xx_TSR = 0x43, // Temperature Sensor Read
UC81xx_CDI = 0x50, // Vcom and data interval setting UC81xx_CDI = 0x50, // Vcom and data interval setting
UC81xx_LPD = 0x51, // Lower Power Detection UC81xx_LPD = 0x51, // Lower Power Detection
UC81xx_TCON = 0x60, // TCON setting UC81xx_TCON = 0x60, // TCON setting
UC81xx_TRES = 0x61, // Resolution setting UC81xx_TRES = 0x61, // Resolution setting
UC81xx_GSST = 0x65, // GSST Setting UC81xx_GSST = 0x65, // GSST Setting
UC81xx_REV = 0x70, // Revision UC81xx_REV = 0x70, // Revision
UC81xx_FLG = 0x71, // Get Status UC81xx_FLG = 0x71, // Get Status
UC81xx_AMV = 0x80, // Auto Measurement Vcom UC81xx_AMV = 0x80, // Auto Measurement Vcom
UC81xx_VV = 0x81, // Read Vcom Value UC81xx_VV = 0x81, // Read Vcom Value
UC81xx_VDCS = 0x82, // VCM_DC Setting UC81xx_VDCS = 0x82, // VCM_DC Setting
UC81xx_PTL = 0x90, // Partial Window UC81xx_PTL = 0x90, // Partial Window
UC81xx_PTIN = 0x91, // Partial In UC81xx_PTIN = 0x91, // Partial In
UC81xx_PTOUT = 0x92, // Partial Out UC81xx_PTOUT = 0x92, // Partial Out
UC81xx_PGM = 0xA0, // Program Mode UC81xx_PGM = 0xA0, // Program Mode
UC81xx_APG = 0xA1, // Active Progrmming UC81xx_APG = 0xA1, // Active Progrmming
UC81xx_ROTP = 0xA2, // Read OTP UC81xx_ROTP = 0xA2, // Read OTP
UC81xx_CCSET = 0xE0, // Cascade Setting UC81xx_CCSET = 0xE0, // Cascade Setting
UC81xx_PWS = 0xE3, // Power Saving UC81xx_PWS = 0xE3, // Power Saving
UC81xx_TSSET = 0xE5, // Force Temperauture UC81xx_TSSET = 0xE5, // Force Temperauture
}; };
// SSD16xx commands // SSD16xx commands
enum { enum {
SSD16xx_GDO_CTR = 0x01, // Driver Output control SSD16xx_GDO_CTR = 0x01, // Driver Output control
SSD16xx_GDV_CTRL = 0x03, // Gate Driving voltage Control SSD16xx_GDV_CTRL = 0x03, // Gate Driving voltage Control
SSD16xx_SDV_CTRL = 0x04, // Source Driving voltage Control SSD16xx_SDV_CTRL = 0x04, // Source Driving voltage Control
SSD16xx_SOFTSTART = 0x0C, // Booster Soft start Control SSD16xx_SOFTSTART = 0x0C, // Booster Soft start Control
SSD16xx_GSCAN_START = 0x0F, // Gate scan start position SSD16xx_GSCAN_START = 0x0F, // Gate scan start position
SSD16xx_SLEEP_MODE = 0x10, // Deep Sleep mode SSD16xx_SLEEP_MODE = 0x10, // Deep Sleep mode
SSD16xx_ENTRY_MODE = 0x11, // Data Entry mode setting SSD16xx_ENTRY_MODE = 0x11, // Data Entry mode setting
SSD16xx_SW_RESET = 0x12, // SW RESET SSD16xx_SW_RESET = 0x12, // SW RESET
SSD16xx_HV_RD_DETECT = 0x14, // HV Ready Detection SSD16xx_HV_RD_DETECT = 0x14, // HV Ready Detection
SSD16xx_VCI_DETECT = 0x15, // VCI Detection SSD16xx_VCI_DETECT = 0x15, // VCI Detection
SSD16xx_TSENSOR_CTRL = 0x18, // Temperature Sensor Control SSD16xx_TSENSOR_CTRL = 0x18, // Temperature Sensor Control
SSD16xx_TSENSOR_WRITE = 0x1A, // Temperature Sensor Control (Write to temperature register) SSD16xx_TSENSOR_WRITE = 0x1A, // Temperature Sensor Control (Write to temperature register)
SSD16xx_TSENSOR_READ = 0x1B, // Temperature Sensor Control (Read from temperature register) SSD16xx_TSENSOR_READ = 0x1B, // Temperature Sensor Control (Read from temperature register)
SSD16xx_TSENSOR_WRITE_EXT = 0x1C, // Temperature Sensor Control (Write Command to External temperature sensor) SSD16xx_TSENSOR_WRITE_EXT = 0x1C, // Temperature Sensor Control (Write Command to External temperature sensor)
SSD16xx_MASTER_ACTIVATE = 0x20, // Master Activation SSD16xx_MASTER_ACTIVATE = 0x20, // Master Activation
SSD16xx_DISP_CTRL1 = 0x21, // Display Update Control 1 SSD16xx_DISP_CTRL1 = 0x21, // Display Update Control 1
SSD16xx_DISP_CTRL2 = 0x22, // Display Update Control 2 SSD16xx_DISP_CTRL2 = 0x22, // Display Update Control 2
SSD16xx_WRITE_RAM1 = 0x24, // Write RAM (BW) SSD16xx_WRITE_RAM1 = 0x24, // Write RAM (BW)
SSD16xx_WRITE_RAM2 = 0x26, // Write RAM (RED) SSD16xx_WRITE_RAM2 = 0x26, // Write RAM (RED)
SSD16xx_READ_RAM = 0x27, // Read RAM SSD16xx_READ_RAM = 0x27, // Read RAM
SSD16xx_VCOM_SENSE = 0x28, // VCOM Sense SSD16xx_VCOM_SENSE = 0x28, // VCOM Sense
SSD16xx_VCOM_SENSE_DURATON = 0x29, // VCOM Sense Duration SSD16xx_VCOM_SENSE_DURATON = 0x29, // VCOM Sense Duration
SSD16xx_PRGM_VCOM_OTP = 0x2A, // Program VCOM OTP SSD16xx_PRGM_VCOM_OTP = 0x2A, // Program VCOM OTP
SSD16xx_VCOM_CTRL = 0x2B, // Write Register for VCOM Control SSD16xx_VCOM_CTRL = 0x2B, // Write Register for VCOM Control
SSD16xx_VCOM_VOLTAGE = 0x2C, // Write VCOM register SSD16xx_VCOM_VOLTAGE = 0x2C, // Write VCOM register
SSD16xx_READ_OTP_REG = 0x2D, // OTP Register Read for Display Option SSD16xx_READ_OTP_REG = 0x2D, // OTP Register Read for Display Option
SSD16xx_READ_USER_ID = 0x2E, // User ID Read SSD16xx_READ_USER_ID = 0x2E, // User ID Read
SSD16xx_READ_STATUS = 0x2F, // Status Bit Read SSD16xx_READ_STATUS = 0x2F, // Status Bit Read
SSD16xx_PRGM_WS_OTP = 0x30, // Program WS OTP SSD16xx_PRGM_WS_OTP = 0x30, // Program WS OTP
SSD16xx_LOAD_WS_OTP = 0x31, // Load WS OTP SSD16xx_LOAD_WS_OTP = 0x31, // Load WS OTP
SSD16xx_WRITE_LUT = 0x32, // Write LUT register SSD16xx_WRITE_LUT = 0x32, // Write LUT register
SSD16xx_READ_LUT = 0x33, // Read LUT SSD16xx_READ_LUT = 0x33, // Read LUT
SSD16xx_CRC_CALC = 0x34, // CRC calculation SSD16xx_CRC_CALC = 0x34, // CRC calculation
SSD16xx_CRC_STATUS = 0x35, // CRC Status Read SSD16xx_CRC_STATUS = 0x35, // CRC Status Read
SSD16xx_PRGM_OTP_SELECTION = 0x36, // Program OTP selection SSD16xx_PRGM_OTP_SELECTION = 0x36, // Program OTP selection
SSD16xx_OTP_SELECTION_CTRL = 0x37, // Write OTP selection SSD16xx_OTP_SELECTION_CTRL = 0x37, // Write OTP selection
SSD16xx_USER_ID_CTRL = 0x38, // Write Register for User ID SSD16xx_USER_ID_CTRL = 0x38, // Write Register for User ID
SSD16xx_OTP_PROG_MODE = 0x39, // OTP program mode SSD16xx_OTP_PROG_MODE = 0x39, // OTP program mode
SSD16xx_DUMMY_LINE = 0x3A, // Set dummy line period SSD16xx_DUMMY_LINE = 0x3A, // Set dummy line period
SSD16xx_GATE_LINE_WIDTH = 0x3B, // Set Gate line width SSD16xx_GATE_LINE_WIDTH = 0x3B, // Set Gate line width
SSD16xx_BORDER_CTRL = 0x3C, // Border Waveform Control SSD16xx_BORDER_CTRL = 0x3C, // Border Waveform Control
SSD16xx_RAM_READ_CTRL = 0x41, // Read RAM Option SSD16xx_RAM_READ_CTRL = 0x41, // Read RAM Option
SSD16xx_RAM_XPOS = 0x44, // Set RAM X - address Start / End position SSD16xx_RAM_XPOS = 0x44, // Set RAM X - address Start / End position
SSD16xx_RAM_YPOS = 0x45, // Set Ram Y- address Start / End position SSD16xx_RAM_YPOS = 0x45, // Set Ram Y- address Start / End position
SSD16xx_AUTO_WRITE_RED_RAM = 0x46, // Auto Write RED RAM for Regular Pattern SSD16xx_AUTO_WRITE_RED_RAM = 0x46, // Auto Write RED RAM for Regular Pattern
SSD16xx_AUTO_WRITE_BW_RAM = 0x47, // Auto Write B/W RAM for Regular Pattern SSD16xx_AUTO_WRITE_BW_RAM = 0x47, // Auto Write B/W RAM for Regular Pattern
SSD16xx_RAM_XCOUNT = 0x4E, // Set RAM X address counter SSD16xx_RAM_XCOUNT = 0x4E, // Set RAM X address counter
SSD16xx_RAM_YCOUNT = 0x4F, // Set RAM Y address counter SSD16xx_RAM_YCOUNT = 0x4F, // Set RAM Y address counter
SSD16xx_ANALOG_BLOCK_CTRL = 0x74, // Set Analog Block Control SSD16xx_ANALOG_BLOCK_CTRL = 0x74, // Set Analog Block Control
SSD16xx_DIGITAL_BLOCK_CTRL = 0x7E, // Set Digital Block Control SSD16xx_DIGITAL_BLOCK_CTRL = 0x7E, // Set Digital Block Control
SSD16xx_NOP = 0x7F, // NOP SSD16xx_NOP = 0x7F, // NOP
}; };
typedef enum typedef enum {
{
BW = 1, BW = 1,
BWR = 2, BWR = 2,
BWRY = 3, BWRY = 3,
} epd_color_t; } epd_color_t;
// Do not change the existing IDs! // Do not change the existing IDs!
typedef enum typedef enum {
{
EPD_UC8176_420_BW = 1, EPD_UC8176_420_BW = 1,
EPD_UC8176_420_BWR = 3, EPD_UC8176_420_BWR = 3,
EPD_SSD1619_420_BWR = 2, EPD_SSD1619_420_BWR = 2,
@@ -146,11 +144,10 @@ typedef enum
struct epd_driver; struct epd_driver;
typedef struct typedef struct {
{
epd_model_id_t id; epd_model_id_t id;
epd_color_t color; epd_color_t color;
struct epd_driver *drv; struct epd_driver* drv;
uint16_t width; uint16_t width;
uint16_t height; uint16_t height;
} epd_model_t; } epd_model_t;
@@ -159,26 +156,26 @@ typedef struct
* *
* @details This structure contains epd driver functions. * @details This structure contains epd driver functions.
*/ */
typedef struct epd_driver typedef struct epd_driver {
{ epd_driver_ic_t ic; /**< EPD driver IC type */
epd_driver_ic_t ic; /**< EPD driver IC type */ void (*init)(epd_model_t* epd); /**< Initialize the e-Paper register */
void (*init)(epd_model_t *epd); /**< Initialize the e-Paper register */ void (*clear)(epd_model_t* epd, bool refresh); /**< Clear screen */
void (*clear)(epd_model_t *epd, bool refresh); /**< Clear screen */ void (*write_image)(epd_model_t* epd, uint8_t* black, uint8_t* color, uint16_t x, uint16_t y, uint16_t w,
void (*write_image)(epd_model_t *epd, uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h); /**< write image */ uint16_t h); /**< write image */
void (*write_ram)(epd_model_t *epd, uint8_t cfg, uint8_t *data, uint8_t len); /* write data to epd ram */ void (*write_ram)(epd_model_t* epd, uint8_t cfg, uint8_t* data, uint8_t len); /* write data to epd ram */
void (*refresh)(epd_model_t *epd); /**< Sends the image buffer in RAM to e-Paper and displays */ void (*refresh)(epd_model_t* epd); /**< Sends the image buffer in RAM to e-Paper and displays */
void (*sleep)(epd_model_t *epd); /**< Enter sleep mode */ void (*sleep)(epd_model_t* epd); /**< Enter sleep mode */
int8_t (*read_temp)(epd_model_t *epd); /**< Read temperature from driver chip */ int8_t (*read_temp)(epd_model_t* epd); /**< Read temperature from driver chip */
} epd_driver_t; } epd_driver_t;
#define LOW (0x0) #define LOW (0x0)
#define HIGH (0x1) #define HIGH (0x1)
#define DEFAULT (0xFF) #define DEFAULT (0xFF)
#define INPUT (0x0) #define INPUT (0x0)
#define OUTPUT (0x1) #define OUTPUT (0x1)
#define INPUT_PULLUP (0x2) #define INPUT_PULLUP (0x2)
#define INPUT_PULLDOWN (0x3) #define INPUT_PULLDOWN (0x3)
// Arduino like function wrappers // Arduino like function wrappers
void pinMode(uint32_t pin, uint32_t mode); void pinMode(uint32_t pin, uint32_t mode);
@@ -187,24 +184,24 @@ void pinMode(uint32_t pin, uint32_t mode);
#define delay(ms) nrf_delay_ms(ms) #define delay(ms) nrf_delay_ms(ms)
// GPIO // GPIO
void EPD_GPIO_Load(epd_config_t *cfg); void EPD_GPIO_Load(epd_config_t* cfg);
void EPD_GPIO_Init(void); void EPD_GPIO_Init(void);
void EPD_GPIO_Uninit(void); void EPD_GPIO_Uninit(void);
// SPI // SPI
void EPD_SPI_Write(uint8_t *value, uint8_t len); void EPD_SPI_Write(uint8_t* value, uint8_t len);
void EPD_SPI_Read(uint8_t *value, uint8_t len); void EPD_SPI_Read(uint8_t* value, uint8_t len);
// EPD // EPD
void EPD_WriteCmd(uint8_t cmd); void EPD_WriteCmd(uint8_t cmd);
void EPD_WriteData(uint8_t *value, uint8_t len); void EPD_WriteData(uint8_t* value, uint8_t len);
void EPD_ReadData(uint8_t *value, uint8_t len); void EPD_ReadData(uint8_t* value, uint8_t len);
void EPD_WriteByte(uint8_t value); void EPD_WriteByte(uint8_t value);
uint8_t EPD_ReadByte(void); uint8_t EPD_ReadByte(void);
#define EPD_Write(cmd, ...) \ #define EPD_Write(cmd, ...) \
do { \ do { \
uint8_t _data[] = {__VA_ARGS__}; \ uint8_t _data[] = {__VA_ARGS__}; \
EPD_WriteCmd(cmd); \ EPD_WriteCmd(cmd); \
EPD_WriteData(_data, sizeof(_data)); \ EPD_WriteData(_data, sizeof(_data)); \
} while (0) } while (0)
void EPD_FillRAM(uint8_t cmd, uint8_t value, uint32_t len); void EPD_FillRAM(uint8_t cmd, uint8_t value, uint32_t len);
@@ -220,6 +217,6 @@ void EPD_LED_BLINK(void);
// VDD voltage // VDD voltage
float EPD_ReadVoltage(void); float EPD_ReadVoltage(void);
epd_model_t *epd_init(epd_model_id_t id); epd_model_t* epd_init(epd_model_id_t id);
#endif #endif

View File

@@ -10,16 +10,18 @@
* *
*/ */
#include "EPD_service.h"
#include <string.h> #include <string.h>
#include "sdk_macros.h"
#include "app_scheduler.h"
#include "ble_srv_common.h" #include "ble_srv_common.h"
#include "main.h"
#include "nrf_delay.h" #include "nrf_delay.h"
#include "nrf_gpio.h" #include "nrf_gpio.h"
#include "nrf_pwr_mgmt.h"
#include "app_scheduler.h"
#include "EPD_service.h"
#include "main.h"
#include "nrf_log.h" #include "nrf_log.h"
#include "nrf_pwr_mgmt.h"
#include "sdk_macros.h"
#if defined(S112) #if defined(S112)
#define EPD_CFG_52811 {0x14, 0x13, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0xFF, 0x12, 0x07} #define EPD_CFG_52811 {0x14, 0x13, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0xFF, 0x12, 0x07}
@@ -29,28 +31,26 @@
// #define EPD_CFG_DEFAULT {0x05, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x01, 0x07} // #define EPD_CFG_DEFAULT {0x05, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x01, 0x07}
#endif #endif
static void epd_gui_update(void * p_event_data, uint16_t event_size) static void epd_gui_update(void* p_event_data, uint16_t event_size) {
{ epd_gui_update_event_t* event = (epd_gui_update_event_t*)p_event_data;
epd_gui_update_event_t *event = (epd_gui_update_event_t *)p_event_data; ble_epd_t* p_epd = event->p_epd;
ble_epd_t *p_epd = event->p_epd;
EPD_GPIO_Init(); EPD_GPIO_Init();
epd_model_t *epd = epd_init((epd_model_id_t)p_epd->config.model_id); epd_model_t* epd = epd_init((epd_model_id_t)p_epd->config.model_id);
gui_data_t data = { gui_data_t data = {
.mode = (display_mode_t)p_epd->config.display_mode, .mode = (display_mode_t)p_epd->config.display_mode,
.color = epd->color, .color = epd->color,
.width = epd->width, .width = epd->width,
.height = epd->height, .height = epd->height,
.timestamp = event->timestamp, .timestamp = event->timestamp,
.week_start = p_epd->config.week_start, .week_start = p_epd->config.week_start,
.temperature = epd->drv->read_temp(epd), .temperature = epd->drv->read_temp(epd),
.voltage = EPD_ReadVoltage(), .voltage = EPD_ReadVoltage(),
}; };
uint16_t dev_name_len = sizeof(data.ssid); uint16_t dev_name_len = sizeof(data.ssid);
uint32_t err_code = sd_ble_gap_device_name_get((uint8_t *)data.ssid, &dev_name_len); uint32_t err_code = sd_ble_gap_device_name_get((uint8_t*)data.ssid, &dev_name_len);
if (err_code == NRF_SUCCESS && dev_name_len > 0) if (err_code == NRF_SUCCESS && dev_name_len > 0) data.ssid[dev_name_len] = '\0';
data.ssid[dev_name_len] = '\0';
DrawGUI(&data, (buffer_callback)epd->drv->write_image, epd); DrawGUI(&data, (buffer_callback)epd->drv->write_image, epd);
epd->drv->refresh(epd); epd->drv->refresh(epd);
@@ -64,8 +64,7 @@ static void epd_gui_update(void * p_event_data, uint16_t event_size)
* @param[in] p_epd EPD Service structure. * @param[in] p_epd EPD Service structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack. * @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/ */
static void on_connect(ble_epd_t * p_epd, ble_evt_t * p_ble_evt) static void on_connect(ble_epd_t* p_epd, ble_evt_t* p_ble_evt) {
{
p_epd->conn_handle = p_ble_evt->evt.gap_evt.conn_handle; p_epd->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
EPD_GPIO_Init(); EPD_GPIO_Init();
} }
@@ -75,132 +74,125 @@ static void on_connect(ble_epd_t * p_epd, ble_evt_t * p_ble_evt)
* @param[in] p_epd EPD Service structure. * @param[in] p_epd EPD Service structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack. * @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/ */
static void on_disconnect(ble_epd_t * p_epd, ble_evt_t * p_ble_evt) static void on_disconnect(ble_epd_t* p_epd, ble_evt_t* p_ble_evt) {
{
UNUSED_PARAMETER(p_ble_evt); UNUSED_PARAMETER(p_ble_evt);
p_epd->conn_handle = BLE_CONN_HANDLE_INVALID; p_epd->conn_handle = BLE_CONN_HANDLE_INVALID;
p_epd->epd->drv->sleep(p_epd->epd); p_epd->epd->drv->sleep(p_epd->epd);
nrf_delay_ms(200); // for sleep nrf_delay_ms(200); // for sleep
EPD_GPIO_Uninit(); EPD_GPIO_Uninit();
} }
static void epd_update_display_mode(ble_epd_t * p_epd, display_mode_t mode) static void epd_update_display_mode(ble_epd_t* p_epd, display_mode_t mode) {
{
if (p_epd->config.display_mode != mode) { if (p_epd->config.display_mode != mode) {
p_epd->config.display_mode = mode; p_epd->config.display_mode = mode;
epd_config_write(&p_epd->config); epd_config_write(&p_epd->config);
} }
} }
static void epd_send_time(ble_epd_t * p_epd) static void epd_send_time(ble_epd_t* p_epd) {
{
char buf[20] = {0}; char buf[20] = {0};
snprintf(buf, 20, "t=%"PRIu32, timestamp()); snprintf(buf, 20, "t=%" PRIu32, timestamp());
ble_epd_string_send(p_epd, (uint8_t *)buf, strlen(buf)); ble_epd_string_send(p_epd, (uint8_t*)buf, strlen(buf));
} }
static void epd_send_mtu(ble_epd_t * p_epd) static void epd_send_mtu(ble_epd_t* p_epd) {
{
char buf[10] = {0}; char buf[10] = {0};
snprintf(buf, sizeof(buf), "mtu=%d", p_epd->max_data_len); snprintf(buf, sizeof(buf), "mtu=%d", p_epd->max_data_len);
ble_epd_string_send(p_epd, (uint8_t *)buf, strlen(buf)); ble_epd_string_send(p_epd, (uint8_t*)buf, strlen(buf));
} }
static void epd_service_on_write(ble_epd_t * p_epd, uint8_t * p_data, uint16_t length) static void epd_service_on_write(ble_epd_t* p_epd, uint8_t* p_data, uint16_t length) {
{
NRF_LOG_DEBUG("[EPD]: on_write LEN=%d\n", length); NRF_LOG_DEBUG("[EPD]: on_write LEN=%d\n", length);
NRF_LOG_HEXDUMP_DEBUG(p_data, length); NRF_LOG_HEXDUMP_DEBUG(p_data, length);
if (p_data == NULL || length <= 0) return; if (p_data == NULL || length <= 0) return;
switch (p_data[0]) switch (p_data[0]) {
{ case EPD_CMD_SET_PINS:
case EPD_CMD_SET_PINS: if (length < 8) return;
if (length < 8) return;
p_epd->config.mosi_pin = p_data[1]; p_epd->config.mosi_pin = p_data[1];
p_epd->config.sclk_pin = p_data[2]; p_epd->config.sclk_pin = p_data[2];
p_epd->config.cs_pin = p_data[3]; p_epd->config.cs_pin = p_data[3];
p_epd->config.dc_pin = p_data[4]; p_epd->config.dc_pin = p_data[4];
p_epd->config.rst_pin = p_data[5]; p_epd->config.rst_pin = p_data[5];
p_epd->config.busy_pin = p_data[6]; p_epd->config.busy_pin = p_data[6];
p_epd->config.bs_pin = p_data[7]; p_epd->config.bs_pin = p_data[7];
if (length > 8) if (length > 8) p_epd->config.en_pin = p_data[8];
p_epd->config.en_pin = p_data[8]; epd_config_write(&p_epd->config);
epd_config_write(&p_epd->config);
EPD_GPIO_Uninit(); EPD_GPIO_Uninit();
EPD_GPIO_Load(&p_epd->config); EPD_GPIO_Load(&p_epd->config);
EPD_GPIO_Init(); EPD_GPIO_Init();
break; break;
case EPD_CMD_INIT: case EPD_CMD_INIT:
p_epd->epd = epd_init((epd_model_id_t)(length > 1 ? p_data[1] : p_epd->config.model_id)); p_epd->epd = epd_init((epd_model_id_t)(length > 1 ? p_data[1] : p_epd->config.model_id));
if (p_epd->epd->id != p_epd->config.model_id) { if (p_epd->epd->id != p_epd->config.model_id) {
p_epd->config.model_id = p_epd->epd->id; p_epd->config.model_id = p_epd->epd->id;
epd_config_write(&p_epd->config); epd_config_write(&p_epd->config);
} }
epd_send_mtu(p_epd); epd_send_mtu(p_epd);
epd_send_time(p_epd); epd_send_time(p_epd);
break; break;
case EPD_CMD_CLEAR: case EPD_CMD_CLEAR:
epd_update_display_mode(p_epd, MODE_PICTURE); epd_update_display_mode(p_epd, MODE_PICTURE);
p_epd->epd->drv->clear(p_epd->epd, length > 1 ? p_data[1] : true); p_epd->epd->drv->clear(p_epd->epd, length > 1 ? p_data[1] : true);
break; break;
case EPD_CMD_SEND_COMMAND: case EPD_CMD_SEND_COMMAND:
if (length < 2) return; if (length < 2) return;
EPD_WriteCmd(p_data[1]); EPD_WriteCmd(p_data[1]);
break; break;
case EPD_CMD_SEND_DATA: case EPD_CMD_SEND_DATA:
EPD_WriteData(&p_data[1], length - 1); EPD_WriteData(&p_data[1], length - 1);
break; break;
case EPD_CMD_REFRESH: case EPD_CMD_REFRESH:
epd_update_display_mode(p_epd, MODE_PICTURE); epd_update_display_mode(p_epd, MODE_PICTURE);
p_epd->epd->drv->refresh(p_epd->epd); p_epd->epd->drv->refresh(p_epd->epd);
break; break;
case EPD_CMD_SLEEP: case EPD_CMD_SLEEP:
p_epd->epd->drv->sleep(p_epd->epd); p_epd->epd->drv->sleep(p_epd->epd);
break; break;
case EPD_CMD_SET_TIME: { case EPD_CMD_SET_TIME: {
if (length < 5) return; if (length < 5) return;
NRF_LOG_DEBUG("time: %02x %02x %02x %02x\n", p_data[1], p_data[2], p_data[3], p_data[4]); NRF_LOG_DEBUG("time: %02x %02x %02x %02x\n", p_data[1], p_data[2], p_data[3], p_data[4]);
if (length > 5) NRF_LOG_DEBUG("timezone: %d\n", (int8_t)p_data[5]); if (length > 5) NRF_LOG_DEBUG("timezone: %d\n", (int8_t)p_data[5]);
uint32_t timestamp = (p_data[1] << 24) | (p_data[2] << 16) | (p_data[3] << 8) | p_data[4]; uint32_t timestamp = (p_data[1] << 24) | (p_data[2] << 16) | (p_data[3] << 8) | p_data[4];
timestamp += (length > 5 ? (int8_t)p_data[5] : 8) * 60 * 60; // timezone timestamp += (length > 5 ? (int8_t)p_data[5] : 8) * 60 * 60; // timezone
set_timestamp(timestamp); set_timestamp(timestamp);
epd_update_display_mode(p_epd, length > 6 ? (display_mode_t)p_data[6] : MODE_CALENDAR); epd_update_display_mode(p_epd, length > 6 ? (display_mode_t)p_data[6] : MODE_CALENDAR);
ble_epd_on_timer(p_epd, timestamp, true); ble_epd_on_timer(p_epd, timestamp, true);
} break; } break;
case EPD_CMD_SET_WEEK_START: case EPD_CMD_SET_WEEK_START:
if (length < 2) return; if (length < 2) return;
if (p_data[1] < 7 && p_data[1] != p_epd->config.week_start) { if (p_data[1] < 7 && p_data[1] != p_epd->config.week_start) {
p_epd->config.week_start = p_data[1]; p_epd->config.week_start = p_data[1];
epd_config_write(&p_epd->config); epd_config_write(&p_epd->config);
} }
break; break;
case EPD_CMD_WRITE_IMAGE: // MSB=0000: ram begin, LSB=1111: black case EPD_CMD_WRITE_IMAGE: // MSB=0000: ram begin, LSB=1111: black
if (length < 3) return; if (length < 3) return;
p_epd->epd->drv->write_ram(p_epd->epd, p_data[1], &p_data[2], length - 2); p_epd->epd->drv->write_ram(p_epd->epd, p_data[1], &p_data[2], length - 2);
break; break;
case EPD_CMD_SET_CONFIG: case EPD_CMD_SET_CONFIG:
if (length < 2) return; if (length < 2) return;
memcpy(&p_epd->config, &p_data[1], (length - 1 > EPD_CONFIG_SIZE) ? EPD_CONFIG_SIZE : length - 1); memcpy(&p_epd->config, &p_data[1], (length - 1 > EPD_CONFIG_SIZE) ? EPD_CONFIG_SIZE : length - 1);
epd_config_write(&p_epd->config); epd_config_write(&p_epd->config);
break; break;
case EPD_CMD_SYS_SLEEP: case EPD_CMD_SYS_SLEEP:
sleep_mode_enter(); sleep_mode_enter();
break; break;
case EPD_CMD_SYS_RESET: case EPD_CMD_SYS_RESET:
#if defined(S112) #if defined(S112)
@@ -208,16 +200,16 @@ static void epd_service_on_write(ble_epd_t * p_epd, uint8_t * p_data, uint16_t l
#else #else
NVIC_SystemReset(); NVIC_SystemReset();
#endif #endif
break; break;
case EPD_CMD_CFG_ERASE: case EPD_CMD_CFG_ERASE:
epd_config_clear(&p_epd->config); epd_config_clear(&p_epd->config);
nrf_delay_ms(100); // required nrf_delay_ms(100); // required
NVIC_SystemReset(); NVIC_SystemReset();
break; break;
default: default:
break; break;
} }
} }
@@ -226,60 +218,42 @@ static void epd_service_on_write(ble_epd_t * p_epd, uint8_t * p_data, uint16_t l
* @param[in] p_epd EPD Service structure. * @param[in] p_epd EPD Service structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack. * @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/ */
static void on_write(ble_epd_t * p_epd, ble_evt_t * p_ble_evt) static void on_write(ble_epd_t* p_epd, ble_evt_t* p_ble_evt) {
{ ble_gatts_evt_write_t* p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if ( if ((p_evt_write->handle == p_epd->char_handles.cccd_handle) && (p_evt_write->len == 2)) {
(p_evt_write->handle == p_epd->char_handles.cccd_handle) if (ble_srv_is_notification_enabled(p_evt_write->data)) {
&&
(p_evt_write->len == 2)
)
{
if (ble_srv_is_notification_enabled(p_evt_write->data))
{
NRF_LOG_DEBUG("notification enabled\n"); NRF_LOG_DEBUG("notification enabled\n");
p_epd->is_notification_enabled = true; p_epd->is_notification_enabled = true;
static uint16_t length = sizeof(epd_config_t); static uint16_t length = sizeof(epd_config_t);
NRF_LOG_DEBUG("send epd config\n"); NRF_LOG_DEBUG("send epd config\n");
uint32_t err_code = ble_epd_string_send(p_epd, (uint8_t *)&p_epd->config, length); uint32_t err_code = ble_epd_string_send(p_epd, (uint8_t*)&p_epd->config, length);
if (err_code != NRF_ERROR_INVALID_STATE) if (err_code != NRF_ERROR_INVALID_STATE) APP_ERROR_CHECK(err_code);
APP_ERROR_CHECK(err_code); } else {
}
else
{
p_epd->is_notification_enabled = false; p_epd->is_notification_enabled = false;
} }
} } else if (p_evt_write->handle == p_epd->char_handles.value_handle) {
else if (p_evt_write->handle == p_epd->char_handles.value_handle)
{
epd_service_on_write(p_epd, p_evt_write->data, p_evt_write->len); epd_service_on_write(p_epd, p_evt_write->data, p_evt_write->len);
} } else {
else
{
// Do Nothing. This event is not relevant for this service. // Do Nothing. This event is not relevant for this service.
} }
} }
#if defined(S112) #if defined(S112)
void ble_epd_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) void ble_epd_evt_handler(ble_evt_t const* p_ble_evt, void* p_context) {
{
if (p_context == NULL || p_ble_evt == NULL) return; if (p_context == NULL || p_ble_evt == NULL) return;
ble_epd_t *p_epd = (ble_epd_t *)p_context; ble_epd_t* p_epd = (ble_epd_t*)p_context;
ble_epd_on_ble_evt(p_epd, (ble_evt_t *)p_ble_evt); ble_epd_on_ble_evt(p_epd, (ble_evt_t*)p_ble_evt);
} }
#endif #endif
void ble_epd_on_ble_evt(ble_epd_t * p_epd, ble_evt_t * p_ble_evt) void ble_epd_on_ble_evt(ble_epd_t* p_epd, ble_evt_t* p_ble_evt) {
{ if ((p_epd == NULL) || (p_ble_evt == NULL)) {
if ((p_epd == NULL) || (p_ble_evt == NULL))
{
return; return;
} }
switch (p_ble_evt->header.evt_id) switch (p_ble_evt->header.evt_id) {
{
case BLE_GAP_EVT_CONNECTED: case BLE_GAP_EVT_CONNECTED:
on_connect(p_epd, p_ble_evt); on_connect(p_epd, p_ble_evt);
break; break;
@@ -298,75 +272,67 @@ void ble_epd_on_ble_evt(ble_epd_t * p_epd, ble_evt_t * p_ble_evt)
} }
} }
static uint32_t epd_service_init(ble_epd_t* p_epd) {
static uint32_t epd_service_init(ble_epd_t * p_epd) ble_uuid_t ble_uuid = {0};
{ ble_uuid128_t base_uuid = BLE_UUID_EPD_SVC_BASE;
ble_uuid_t ble_uuid = {0};
ble_uuid128_t base_uuid = BLE_UUID_EPD_SVC_BASE;
ble_add_char_params_t add_char_params; ble_add_char_params_t add_char_params;
uint8_t app_version = APP_VERSION; uint8_t app_version = APP_VERSION;
VERIFY_SUCCESS(sd_ble_uuid_vs_add(&base_uuid, &ble_uuid.type)); VERIFY_SUCCESS(sd_ble_uuid_vs_add(&base_uuid, &ble_uuid.type));
ble_uuid.type = ble_uuid.type; ble_uuid.type = ble_uuid.type;
ble_uuid.uuid = BLE_UUID_EPD_SVC; ble_uuid.uuid = BLE_UUID_EPD_SVC;
VERIFY_SUCCESS(sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, VERIFY_SUCCESS(sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_epd->service_handle));
&ble_uuid,
&p_epd->service_handle));
memset(&add_char_params, 0, sizeof(add_char_params)); memset(&add_char_params, 0, sizeof(add_char_params));
add_char_params.uuid = BLE_UUID_EPD_CHAR; add_char_params.uuid = BLE_UUID_EPD_CHAR;
add_char_params.uuid_type = ble_uuid.type; add_char_params.uuid_type = ble_uuid.type;
add_char_params.max_len = BLE_EPD_MAX_DATA_LEN; add_char_params.max_len = BLE_EPD_MAX_DATA_LEN;
add_char_params.init_len = sizeof(uint8_t); add_char_params.init_len = sizeof(uint8_t);
add_char_params.is_var_len = true; add_char_params.is_var_len = true;
add_char_params.char_props.notify = 1; add_char_params.char_props.notify = 1;
add_char_params.char_props.write = 1; add_char_params.char_props.write = 1;
add_char_params.char_props.write_wo_resp = 1; add_char_params.char_props.write_wo_resp = 1;
add_char_params.read_access = SEC_OPEN; add_char_params.read_access = SEC_OPEN;
add_char_params.write_access = SEC_OPEN; add_char_params.write_access = SEC_OPEN;
add_char_params.cccd_write_access = SEC_OPEN; add_char_params.cccd_write_access = SEC_OPEN;
VERIFY_SUCCESS(characteristic_add(p_epd->service_handle, &add_char_params, &p_epd->char_handles)); VERIFY_SUCCESS(characteristic_add(p_epd->service_handle, &add_char_params, &p_epd->char_handles));
memset(&add_char_params, 0, sizeof(add_char_params)); memset(&add_char_params, 0, sizeof(add_char_params));
add_char_params.uuid = BLE_UUID_APP_VER; add_char_params.uuid = BLE_UUID_APP_VER;
add_char_params.uuid_type = ble_uuid.type; add_char_params.uuid_type = ble_uuid.type;
add_char_params.max_len = sizeof(uint8_t); add_char_params.max_len = sizeof(uint8_t);
add_char_params.init_len = sizeof(uint8_t); add_char_params.init_len = sizeof(uint8_t);
add_char_params.p_init_value = &app_version; add_char_params.p_init_value = &app_version;
add_char_params.char_props.read = 1; add_char_params.char_props.read = 1;
add_char_params.read_access = SEC_OPEN; add_char_params.read_access = SEC_OPEN;
return characteristic_add(p_epd->service_handle, &add_char_params, &p_epd->app_ver_handles); return characteristic_add(p_epd->service_handle, &add_char_params, &p_epd->app_ver_handles);
} }
void ble_epd_sleep_prepare(ble_epd_t * p_epd) void ble_epd_sleep_prepare(ble_epd_t* p_epd) {
{
// Turn off led // Turn off led
EPD_LED_OFF(); EPD_LED_OFF();
// Prepare wakeup pin // Prepare wakeup pin
if (p_epd->config.wakeup_pin != 0xFF) if (p_epd->config.wakeup_pin != 0xFF) {
{
nrf_gpio_cfg_sense_input(p_epd->config.wakeup_pin, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH); nrf_gpio_cfg_sense_input(p_epd->config.wakeup_pin, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH);
} }
} }
uint32_t ble_epd_init(ble_epd_t * p_epd) uint32_t ble_epd_init(ble_epd_t* p_epd) {
{
if (p_epd == NULL) return NRF_ERROR_NULL; if (p_epd == NULL) return NRF_ERROR_NULL;
// Initialize the service structure. // Initialize the service structure.
p_epd->max_data_len = BLE_EPD_MAX_DATA_LEN; p_epd->max_data_len = BLE_EPD_MAX_DATA_LEN;
p_epd->conn_handle = BLE_CONN_HANDLE_INVALID; p_epd->conn_handle = BLE_CONN_HANDLE_INVALID;
p_epd->is_notification_enabled = false; p_epd->is_notification_enabled = false;
epd_config_init(&p_epd->config); epd_config_init(&p_epd->config);
epd_config_read(&p_epd->config); epd_config_read(&p_epd->config);
// write default config // write default config
if (epd_config_empty(&p_epd->config)) if (epd_config_empty(&p_epd->config)) {
{
#if defined(S112) #if defined(S112)
if (NRF_FICR->INFO.PART == 0x52810) { if (NRF_FICR->INFO.PART == 0x52810) {
uint8_t cfg[] = EPD_CFG_52810; uint8_t cfg[] = EPD_CFG_52810;
@@ -379,10 +345,8 @@ uint32_t ble_epd_init(ble_epd_t * p_epd)
uint8_t cfg[] = EPD_CFG_DEFAULT; uint8_t cfg[] = EPD_CFG_DEFAULT;
memcpy(&p_epd->config, cfg, sizeof(cfg)); memcpy(&p_epd->config, cfg, sizeof(cfg));
#endif #endif
if (p_epd->config.display_mode == 0xFF) if (p_epd->config.display_mode == 0xFF) p_epd->config.display_mode = MODE_CALENDAR;
p_epd->config.display_mode = MODE_CALENDAR; if (p_epd->config.week_start == 0xFF) p_epd->config.week_start = 0;
if (p_epd->config.week_start == 0xFF)
p_epd->config.week_start = 0;
epd_config_write(&p_epd->config); epd_config_write(&p_epd->config);
} }
@@ -396,12 +360,10 @@ uint32_t ble_epd_init(ble_epd_t * p_epd)
return epd_service_init(p_epd); return epd_service_init(p_epd);
} }
uint32_t ble_epd_string_send(ble_epd_t * p_epd, uint8_t * p_string, uint16_t length) uint32_t ble_epd_string_send(ble_epd_t* p_epd, uint8_t* p_string, uint16_t length) {
{
if ((p_epd->conn_handle == BLE_CONN_HANDLE_INVALID) || (!p_epd->is_notification_enabled)) if ((p_epd->conn_handle == BLE_CONN_HANDLE_INVALID) || (!p_epd->is_notification_enabled))
return NRF_ERROR_INVALID_STATE; return NRF_ERROR_INVALID_STATE;
if (length > p_epd->max_data_len) if (length > p_epd->max_data_len) return NRF_ERROR_INVALID_PARAM;
return NRF_ERROR_INVALID_PARAM;
ble_gatts_hvx_params_t hvx_params; ble_gatts_hvx_params_t hvx_params;
@@ -409,19 +371,17 @@ uint32_t ble_epd_string_send(ble_epd_t * p_epd, uint8_t * p_string, uint16_t len
hvx_params.handle = p_epd->char_handles.value_handle; hvx_params.handle = p_epd->char_handles.value_handle;
hvx_params.p_data = p_string; hvx_params.p_data = p_string;
hvx_params.p_len = &length; hvx_params.p_len = &length;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION; hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
return sd_ble_gatts_hvx(p_epd->conn_handle, &hvx_params); return sd_ble_gatts_hvx(p_epd->conn_handle, &hvx_params);
} }
void ble_epd_on_timer(ble_epd_t * p_epd, uint32_t timestamp, bool force_update) void ble_epd_on_timer(ble_epd_t* p_epd, uint32_t timestamp, bool force_update) {
{
// Update calendar on 00:00:00, clock on every minute // Update calendar on 00:00:00, clock on every minute
if (force_update || if (force_update || (p_epd->config.display_mode == MODE_CALENDAR && timestamp % 86400 == 0) ||
(p_epd->config.display_mode == MODE_CALENDAR && timestamp % 86400 == 0) ||
(p_epd->config.display_mode == MODE_CLOCK && timestamp % 60 == 0)) { (p_epd->config.display_mode == MODE_CLOCK && timestamp % 60 == 0)) {
epd_gui_update_event_t event = { p_epd, timestamp }; epd_gui_update_event_t event = {p_epd, timestamp};
app_sched_event_put(&event, sizeof(epd_gui_update_event_t), epd_gui_update); app_sched_event_put(&event, sizeof(epd_gui_update_event_t), epd_gui_update);
} }
} }

View File

@@ -15,15 +15,16 @@
#include <inttypes.h> #include <inttypes.h>
#include <stdbool.h> #include <stdbool.h>
#include "ble.h" #include "ble.h"
#include "ble_srv_common.h" #include "ble_srv_common.h"
#if defined(S112) #if defined(S112)
#include "nrf_sdh_ble.h" #include "nrf_sdh_ble.h"
#endif #endif
#include "sdk_config.h"
#include "EPD_driver.h"
#include "EPD_config.h" #include "EPD_config.h"
#include "EPD_driver.h"
#include "GUI.h" #include "GUI.h"
#include "sdk_config.h"
/**@brief Macro for defining a ble_hts instance. /**@brief Macro for defining a ble_hts instance.
* *
@@ -31,75 +32,75 @@
* @hideinitializer * @hideinitializer
*/ */
#if defined(S112) #if defined(S112)
void ble_epd_evt_handler(ble_evt_t const * p_ble_evt, void * p_context); void ble_epd_evt_handler(ble_evt_t const* p_ble_evt, void* p_context);
#define BLE_EPD_BLE_OBSERVER_PRIO 2 #define BLE_EPD_BLE_OBSERVER_PRIO 2
#define BLE_EPD_DEF(_name) \ #define BLE_EPD_DEF(_name) \
static ble_epd_t _name; \ static ble_epd_t _name; \
NRF_SDH_BLE_OBSERVER(_name ## _obs, \ NRF_SDH_BLE_OBSERVER(_name##_obs, BLE_EPD_BLE_OBSERVER_PRIO, ble_epd_evt_handler, &_name)
BLE_EPD_BLE_OBSERVER_PRIO, \
ble_epd_evt_handler, &_name)
#else #else
#define BLE_EPD_DEF(_name) static ble_epd_t _name; #define BLE_EPD_DEF(_name) static ble_epd_t _name;
#endif #endif
#define APP_VERSION 0x19 #define APP_VERSION 0x19
#define BLE_UUID_EPD_SVC_BASE {{0XEC, 0X5A, 0X67, 0X1C, 0XC1, 0XB6, 0X46, 0XFB, \ #define BLE_UUID_EPD_SVC_BASE \
0X8D, 0X91, 0X28, 0XD8, 0X22, 0X36, 0X75, 0X62}} {{0XEC, 0X5A, 0X67, 0X1C, 0XC1, 0XB6, 0X46, 0XFB, 0X8D, 0X91, 0X28, 0XD8, 0X22, 0X36, 0X75, 0X62}}
#define BLE_UUID_EPD_SVC 0x0001 #define BLE_UUID_EPD_SVC 0x0001
#define BLE_UUID_EPD_CHAR 0x0002 #define BLE_UUID_EPD_CHAR 0x0002
#define BLE_UUID_APP_VER 0x0003 #define BLE_UUID_APP_VER 0x0003
#define EPD_SVC_UUID_TYPE BLE_UUID_TYPE_VENDOR_BEGIN #define EPD_SVC_UUID_TYPE BLE_UUID_TYPE_VENDOR_BEGIN
#if defined(S112) #if defined(S112)
#define BLE_EPD_MAX_DATA_LEN (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - 3) #define BLE_EPD_MAX_DATA_LEN (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - 3)
#else #else
#define BLE_EPD_MAX_DATA_LEN (GATT_MTU_SIZE_DEFAULT - 3) /**< Maximum length of data (in bytes) that can be transmitted to the peer. */ #define BLE_EPD_MAX_DATA_LEN \
(GATT_MTU_SIZE_DEFAULT - 3) /**< Maximum length of data (in bytes) that can be transmitted to the peer. */
#endif #endif
/**< EPD Service command IDs. */ /**< EPD Service command IDs. */
enum EPD_CMDS enum EPD_CMDS {
{ EPD_CMD_SET_PINS = 0x00, /**< set EPD pin mapping. */
EPD_CMD_SET_PINS = 0x00, /**< set EPD pin mapping. */ EPD_CMD_INIT = 0x01, /**< init EPD display driver */
EPD_CMD_INIT = 0x01, /**< init EPD display driver */ EPD_CMD_CLEAR = 0x02, /**< clear EPD screen */
EPD_CMD_CLEAR = 0x02, /**< clear EPD screen */ EPD_CMD_SEND_COMMAND = 0x03, /**< send command to EPD */
EPD_CMD_SEND_COMMAND = 0x03, /**< send command to EPD */ EPD_CMD_SEND_DATA = 0x04, /**< send data to EPD */
EPD_CMD_SEND_DATA = 0x04, /**< send data to EPD */ EPD_CMD_REFRESH = 0x05, /**< diaplay EPD ram on screen */
EPD_CMD_REFRESH = 0x05, /**< diaplay EPD ram on screen */ EPD_CMD_SLEEP = 0x06, /**< EPD enter sleep mode */
EPD_CMD_SLEEP = 0x06, /**< EPD enter sleep mode */
EPD_CMD_SET_TIME = 0x20, /** < set time with unix timestamp */ EPD_CMD_SET_TIME = 0x20, /** < set time with unix timestamp */
EPD_CMD_SET_WEEK_START = 0x21, /** < set week start day (0: Sunday, 1: Monday, ...) */ EPD_CMD_SET_WEEK_START = 0x21, /** < set week start day (0: Sunday, 1: Monday, ...) */
EPD_CMD_WRITE_IMAGE = 0x30, /** < write image data to EPD ram */ EPD_CMD_WRITE_IMAGE = 0x30, /** < write image data to EPD ram */
EPD_CMD_SET_CONFIG = 0x90, /**< set full EPD config */ EPD_CMD_SET_CONFIG = 0x90, /**< set full EPD config */
EPD_CMD_SYS_RESET = 0x91, /**< MCU reset */ EPD_CMD_SYS_RESET = 0x91, /**< MCU reset */
EPD_CMD_SYS_SLEEP = 0x92, /**< MCU enter sleep mode */ EPD_CMD_SYS_SLEEP = 0x92, /**< MCU enter sleep mode */
EPD_CMD_CFG_ERASE = 0x99, /**< Erase config and reset */ EPD_CMD_CFG_ERASE = 0x99, /**< Erase config and reset */
}; };
/**@brief EPD Service structure. /**@brief EPD Service structure.
* *
* @details This structure contains status information related to the service. * @details This structure contains status information related to the service.
*/ */
typedef struct typedef struct {
{ uint16_t service_handle; /**< Handle of EPD Service (as provided by the S110 SoftDevice). */
uint16_t service_handle; /**< Handle of EPD Service (as provided by the S110 SoftDevice). */ ble_gatts_char_handles_t
ble_gatts_char_handles_t char_handles; /**< Handles related to the EPD characteristic (as provided by the SoftDevice). */ char_handles; /**< Handles related to the EPD characteristic (as provided by the SoftDevice). */
ble_gatts_char_handles_t app_ver_handles; /**< Handles related to the APP version characteristic (as provided by the SoftDevice). */ ble_gatts_char_handles_t
uint16_t conn_handle; /**< Handle of the current connection (as provided by the SoftDevice). BLE_CONN_HANDLE_INVALID if not in a connection. */ app_ver_handles; /**< Handles related to the APP version characteristic (as provided by the SoftDevice). */
uint16_t max_data_len; /**< Maximum length of data (in bytes) that can be transmitted to the peer */ uint16_t conn_handle; /**< Handle of the current connection (as provided by the SoftDevice). BLE_CONN_HANDLE_INVALID
bool is_notification_enabled; /**< Variable to indicate if the peer has enabled notification of the RX characteristic.*/ if not in a connection. */
epd_model_t *epd; /**< current EPD model */ uint16_t max_data_len; /**< Maximum length of data (in bytes) that can be transmitted to the peer */
epd_config_t config; /**< EPD config */ bool is_notification_enabled; /**< Variable to indicate if the peer has enabled notification of the RX
characteristic.*/
epd_model_t* epd; /**< current EPD model */
epd_config_t config; /**< EPD config */
} ble_epd_t; } ble_epd_t;
typedef struct typedef struct {
{ ble_epd_t* p_epd;
ble_epd_t *p_epd;
uint32_t timestamp; uint32_t timestamp;
} epd_gui_update_event_t; } epd_gui_update_event_t;
@@ -109,7 +110,7 @@ typedef struct
* *
* @param[in] p_epd EPD Service structure. * @param[in] p_epd EPD Service structure.
*/ */
void ble_epd_sleep_prepare(ble_epd_t * p_epd); void ble_epd_sleep_prepare(ble_epd_t* p_epd);
/**@brief Function for initializing the EPD Service. /**@brief Function for initializing the EPD Service.
* *
@@ -120,7 +121,7 @@ void ble_epd_sleep_prepare(ble_epd_t * p_epd);
* @retval NRF_SUCCESS If the service was successfully initialized. Otherwise, an error code is returned. * @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. * @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);
/**@brief Function for handling the EPD Service's BLE events. /**@brief Function for handling the EPD Service's BLE events.
* *
@@ -132,7 +133,7 @@ uint32_t ble_epd_init(ble_epd_t * p_epd);
* @param[in] p_epd EPD Service structure. * @param[in] p_epd EPD Service structure.
* @param[in] p_ble_evt Event received from the S110 SoftDevice. * @param[in] p_ble_evt Event received from the S110 SoftDevice.
*/ */
void ble_epd_on_ble_evt(ble_epd_t * p_epd, ble_evt_t * p_ble_evt); void ble_epd_on_ble_evt(ble_epd_t* p_epd, ble_evt_t* p_ble_evt);
/**@brief Function for sending a string to the peer. /**@brief Function for sending a string to the peer.
* *
@@ -145,10 +146,10 @@ void ble_epd_on_ble_evt(ble_epd_t * p_epd, ble_evt_t * p_ble_evt);
* *
* @retval NRF_SUCCESS If the string was sent successfully. Otherwise, an error code is returned. * @retval NRF_SUCCESS If the string was sent successfully. Otherwise, an error code is returned.
*/ */
uint32_t ble_epd_string_send(ble_epd_t * p_epd, uint8_t * p_string, uint16_t length); uint32_t ble_epd_string_send(ble_epd_t* p_epd, uint8_t* p_string, uint16_t length);
void ble_epd_on_timer(ble_epd_t * p_epd, uint32_t timestamp, bool force_update); void ble_epd_on_timer(ble_epd_t* p_epd, uint32_t timestamp, bool force_update);
#endif // EPD_BLE_H__ #endif // EPD_BLE_H__
/** @} */ /** @} */

View File

@@ -1,51 +1,35 @@
#include "EPD_driver.h" #include "EPD_driver.h"
#include "nrf_log.h" #include "nrf_log.h"
static void SSD16xx_WaitBusy(uint16_t timeout) static void SSD16xx_WaitBusy(uint16_t timeout) { EPD_WaitBusy(HIGH, timeout); }
{
EPD_WaitBusy(HIGH, timeout);
}
static void SSD16xx_Update(uint8_t seq) static void SSD16xx_Update(uint8_t seq) {
{
EPD_Write(SSD16xx_DISP_CTRL2, seq); EPD_Write(SSD16xx_DISP_CTRL2, seq);
EPD_WriteCmd(SSD16xx_MASTER_ACTIVATE); EPD_WriteCmd(SSD16xx_MASTER_ACTIVATE);
} }
int8_t SSD16xx_Read_Temp(epd_model_t *epd) int8_t SSD16xx_Read_Temp(epd_model_t* epd) {
{
SSD16xx_Update(0xB1); SSD16xx_Update(0xB1);
SSD16xx_WaitBusy(500); SSD16xx_WaitBusy(500);
EPD_WriteCmd(SSD16xx_TSENSOR_READ); EPD_WriteCmd(SSD16xx_TSENSOR_READ);
return (int8_t)EPD_ReadByte(); return (int8_t)EPD_ReadByte();
} }
static void _setPartialRamArea(epd_model_t *epd, uint16_t x, uint16_t y, uint16_t w, uint16_t h) static void _setPartialRamArea(epd_model_t* epd, uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
{ EPD_Write(SSD16xx_ENTRY_MODE, 0x03); // set ram entry mode: x increase, y increase
EPD_Write(SSD16xx_ENTRY_MODE, 0x03); // set ram entry mode: x increase, y increase
if (epd->drv->ic == EPD_DRIVER_IC_SSD1677) { if (epd->drv->ic == EPD_DRIVER_IC_SSD1677) {
EPD_Write(SSD16xx_RAM_XPOS, EPD_Write(SSD16xx_RAM_XPOS, x % 256, x / 256, (x + w - 1) % 256, (x + w - 1) / 256);
x % 256, x / 256,
(x + w - 1) % 256,
(x + w - 1) / 256);
EPD_Write(SSD16xx_RAM_XCOUNT, x % 256, x / 256); EPD_Write(SSD16xx_RAM_XCOUNT, x % 256, x / 256);
} else { } else {
EPD_Write(SSD16xx_RAM_XPOS, x / 8, (x + w - 1) / 8); EPD_Write(SSD16xx_RAM_XPOS, x / 8, (x + w - 1) / 8);
EPD_Write(SSD16xx_RAM_YPOS, EPD_Write(SSD16xx_RAM_YPOS, y % 256, y / 256, (y + h - 1) % 256, (y + h - 1) / 256);
y % 256, y / 256,
(y + h - 1) % 256,
(y + h - 1) / 256);
EPD_Write(SSD16xx_RAM_XCOUNT, x / 8); EPD_Write(SSD16xx_RAM_XCOUNT, x / 8);
} }
EPD_Write(SSD16xx_RAM_YPOS, EPD_Write(SSD16xx_RAM_YPOS, y % 256, y / 256, (y + h - 1) % 256, (y + h - 1) / 256);
y % 256, y / 256,
(y + h - 1) % 256,
(y + h - 1) / 256);
EPD_Write(SSD16xx_RAM_YCOUNT, y % 256, y / 256); EPD_Write(SSD16xx_RAM_YCOUNT, y % 256, y / 256);
} }
void SSD16xx_Dump_LUT(void) void SSD16xx_Dump_LUT(void) {
{
uint8_t lut[128]; uint8_t lut[128];
EPD_WriteCmd(SSD16xx_READ_LUT); EPD_WriteCmd(SSD16xx_READ_LUT);
@@ -56,8 +40,7 @@ void SSD16xx_Dump_LUT(void)
NRF_LOG_DEBUG("=== LUT END ===\n"); NRF_LOG_DEBUG("=== LUT END ===\n");
} }
void SSD16xx_Init(epd_model_t *epd) void SSD16xx_Init(epd_model_t* epd) {
{
EPD_Reset(HIGH, 10); EPD_Reset(HIGH, 10);
EPD_WriteCmd(SSD16xx_SW_RESET); EPD_WriteCmd(SSD16xx_SW_RESET);
@@ -69,8 +52,7 @@ void SSD16xx_Init(epd_model_t *epd)
_setPartialRamArea(epd, 0, 0, epd->width, epd->height); _setPartialRamArea(epd, 0, 0, epd->width, epd->height);
} }
static void SSD16xx_Refresh(epd_model_t *epd) static void SSD16xx_Refresh(epd_model_t* epd) {
{
EPD_Write(SSD16xx_DISP_CTRL1, epd->color == BWR ? 0x80 : 0x40, 0x00); EPD_Write(SSD16xx_DISP_CTRL1, epd->color == BWR ? 0x80 : 0x40, 0x00);
NRF_LOG_DEBUG("[EPD]: refresh begin\n"); NRF_LOG_DEBUG("[EPD]: refresh begin\n");
@@ -79,14 +61,13 @@ static void SSD16xx_Refresh(epd_model_t *epd)
SSD16xx_WaitBusy(30000); SSD16xx_WaitBusy(30000);
NRF_LOG_DEBUG("[EPD]: refresh end\n"); NRF_LOG_DEBUG("[EPD]: refresh end\n");
// SSD16xx_Dump_LUT(); // SSD16xx_Dump_LUT();
_setPartialRamArea(epd, 0, 0, epd->width, epd->height); // DO NOT REMOVE! _setPartialRamArea(epd, 0, 0, epd->width, epd->height); // DO NOT REMOVE!
SSD16xx_Update(0x83); // power off SSD16xx_Update(0x83); // power off
} }
void SSD16xx_Clear(epd_model_t *epd, bool refresh) void SSD16xx_Clear(epd_model_t* epd, bool refresh) {
{
uint32_t ram_bytes = ((epd->width + 7) / 8) * epd->height; uint32_t ram_bytes = ((epd->width + 7) / 8) * epd->height;
_setPartialRamArea(epd, 0, 0, epd->width, epd->height); _setPartialRamArea(epd, 0, 0, epd->width, epd->height);
@@ -94,30 +75,24 @@ void SSD16xx_Clear(epd_model_t *epd, bool refresh)
EPD_FillRAM(SSD16xx_WRITE_RAM1, 0xFF, ram_bytes); EPD_FillRAM(SSD16xx_WRITE_RAM1, 0xFF, ram_bytes);
EPD_FillRAM(SSD16xx_WRITE_RAM2, 0xFF, ram_bytes); EPD_FillRAM(SSD16xx_WRITE_RAM2, 0xFF, ram_bytes);
if (refresh) if (refresh) SSD16xx_Refresh(epd);
SSD16xx_Refresh(epd);
} }
void SSD16xx_Write_Image(epd_model_t *epd, uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h) void SSD16xx_Write_Image(epd_model_t* epd, uint8_t* black, uint8_t* color, uint16_t x, uint16_t y, uint16_t w,
{ uint16_t h) {
uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
x -= x % 8; // byte boundary x -= x % 8; // byte boundary
w = wb * 8; // byte boundary w = wb * 8; // byte boundary
if (x + w > epd->width || y + h > epd->height) if (x + w > epd->width || y + h > epd->height) return;
return;
_setPartialRamArea(epd, x, y, w, h); _setPartialRamArea(epd, x, y, w, h);
EPD_WriteCmd(SSD16xx_WRITE_RAM1); EPD_WriteCmd(SSD16xx_WRITE_RAM1);
for (uint16_t i = 0; i < h; i++) for (uint16_t i = 0; i < h; i++) {
{ for (uint16_t j = 0; j < w / 8; j++) EPD_WriteByte(black ? black[j + i * wb] : 0xFF);
for (uint16_t j = 0; j < w / 8; j++)
EPD_WriteByte(black ? black[j + i * wb] : 0xFF);
} }
EPD_WriteCmd(SSD16xx_WRITE_RAM2); EPD_WriteCmd(SSD16xx_WRITE_RAM2);
for (uint16_t i = 0; i < h; i++) for (uint16_t i = 0; i < h; i++) {
{ for (uint16_t j = 0; j < w / 8; j++) {
for (uint16_t j = 0; j < w / 8; j++)
{
if (epd->color == BWR) if (epd->color == BWR)
EPD_WriteByte(color ? color[j + i * wb] : 0xFF); EPD_WriteByte(color ? color[j + i * wb] : 0xFF);
else else
@@ -126,8 +101,7 @@ void SSD16xx_Write_Image(epd_model_t *epd, uint8_t *black, uint8_t *color, uint1
} }
} }
void SSD16xx_Write_Ram(epd_model_t *epd, uint8_t cfg, uint8_t *data, uint8_t len) void SSD16xx_Write_Ram(epd_model_t* epd, uint8_t cfg, uint8_t* data, uint8_t len) {
{
bool begin = (cfg >> 4) == 0x00; bool begin = (cfg >> 4) == 0x00;
bool black = (cfg & 0x0F) == 0x0F; bool black = (cfg & 0x0F) == 0x0F;
if (begin) { if (begin) {
@@ -139,8 +113,7 @@ void SSD16xx_Write_Ram(epd_model_t *epd, uint8_t cfg, uint8_t *data, uint8_t len
EPD_WriteData(data, len); EPD_WriteData(data, len);
} }
void SSD16xx_Sleep(epd_model_t *epd) void SSD16xx_Sleep(epd_model_t* epd) {
{
EPD_Write(SSD16xx_SLEEP_MODE, 0x01); EPD_Write(SSD16xx_SLEEP_MODE, 0x01);
delay(100); delay(100);
} }

View File

@@ -1,55 +1,40 @@
#include "EPD_driver.h" #include "EPD_driver.h"
#include "nrf_log.h" #include "nrf_log.h"
static void UC81xx_WaitBusy(uint16_t timeout) static void UC81xx_WaitBusy(uint16_t timeout) { EPD_WaitBusy(LOW, timeout); }
{
EPD_WaitBusy(LOW, timeout);
}
static void UC81xx_PowerOn(void) static void UC81xx_PowerOn(void) {
{
EPD_WriteCmd(UC81xx_PON); EPD_WriteCmd(UC81xx_PON);
UC81xx_WaitBusy(200); UC81xx_WaitBusy(200);
} }
static void UC81xx_PowerOff(void) static void UC81xx_PowerOff(void) {
{
EPD_WriteCmd(UC81xx_POF); EPD_WriteCmd(UC81xx_POF);
UC81xx_WaitBusy(200); UC81xx_WaitBusy(200);
} }
// Read temperature from driver chip // Read temperature from driver chip
int8_t UC81xx_Read_Temp(epd_model_t *epd) int8_t UC81xx_Read_Temp(epd_model_t* epd) {
{
EPD_WriteCmd(UC81xx_TSC); EPD_WriteCmd(UC81xx_TSC);
UC81xx_WaitBusy(100); UC81xx_WaitBusy(100);
return (int8_t)EPD_ReadByte(); return (int8_t)EPD_ReadByte();
} }
static void _setPartialRamArea(epd_model_t *epd, uint16_t x, uint16_t y, uint16_t w, uint16_t h) static void _setPartialRamArea(epd_model_t* epd, uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
{
if (epd->drv->ic == EPD_DRIVER_IC_JD79668 || epd->drv->ic == EPD_DRIVER_IC_JD79665) { if (epd->drv->ic == EPD_DRIVER_IC_JD79668 || epd->drv->ic == EPD_DRIVER_IC_JD79665) {
EPD_Write(0x83, // partial window EPD_Write(0x83, // partial window
x / 256, x % 256, x / 256, x % 256, (x + w - 1) / 256, (x + w - 1) % 256, y / 256, y % 256, (y + h - 1) / 256,
(x + w - 1) / 256, (x + w - 1) % 256, (y + h - 1) % 256, 0x01);
y / 256, y % 256,
(y + h - 1) / 256, (y + h - 1) % 256,
0x01);
} else { } else {
uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte) uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte)
uint16_t ye = y + h - 1; uint16_t ye = y + h - 1;
x &= 0xFFF8; // byte boundary x &= 0xFFF8; // byte boundary
EPD_Write(UC81xx_PTL, // partial window EPD_Write(UC81xx_PTL, // partial window
x / 256, x % 256, x / 256, x % 256, xe / 256, xe % 256, y / 256, y % 256, ye / 256, ye % 256, 0x00);
xe / 256, xe % 256,
y / 256, y % 256,
ye / 256, ye % 256,
0x00);
} }
} }
void UC81xx_Refresh(epd_model_t *epd) void UC81xx_Refresh(epd_model_t* epd) {
{
NRF_LOG_DEBUG("[EPD]: refresh begin\n"); NRF_LOG_DEBUG("[EPD]: refresh begin\n");
UC81xx_PowerOn(); UC81xx_PowerOn();
@@ -63,8 +48,7 @@ void UC81xx_Refresh(epd_model_t *epd)
NRF_LOG_DEBUG("[EPD]: refresh end\n"); NRF_LOG_DEBUG("[EPD]: refresh end\n");
} }
void JD79668_Refresh(epd_model_t *epd) void JD79668_Refresh(epd_model_t* epd) {
{
NRF_LOG_DEBUG("[EPD]: refresh begin\n"); NRF_LOG_DEBUG("[EPD]: refresh begin\n");
_setPartialRamArea(epd, 0, 0, epd->width, epd->height); _setPartialRamArea(epd, 0, 0, epd->width, epd->height);
@@ -76,8 +60,7 @@ void JD79668_Refresh(epd_model_t *epd)
NRF_LOG_DEBUG("[EPD]: refresh end\n"); NRF_LOG_DEBUG("[EPD]: refresh end\n");
} }
void UC81xx_Dump_OTP(void) void UC81xx_Dump_OTP(void) {
{
uint8_t data[128]; uint8_t data[128];
UC81xx_PowerOn(); UC81xx_PowerOn();
@@ -93,18 +76,16 @@ void UC81xx_Dump_OTP(void)
UC81xx_PowerOff(); UC81xx_PowerOff();
} }
void UC81xx_Init(epd_model_t *epd) void UC81xx_Init(epd_model_t* epd) {
{
EPD_Reset(HIGH, 10); EPD_Reset(HIGH, 10);
// UC81xx_Dump_OTP(); // UC81xx_Dump_OTP();
EPD_Write(UC81xx_PSR, epd->color == BWR ? 0x0F : 0x1F); EPD_Write(UC81xx_PSR, epd->color == BWR ? 0x0F : 0x1F);
EPD_Write(UC81xx_CDI, epd->color == BWR ? 0x77 : 0x97); EPD_Write(UC81xx_CDI, epd->color == BWR ? 0x77 : 0x97);
} }
void UC8159_Init(epd_model_t *epd) void UC8159_Init(epd_model_t* epd) {
{
EPD_Reset(HIGH, 10); EPD_Reset(HIGH, 10);
EPD_Write(UC81xx_PWR, 0x37, 0x00); EPD_Write(UC81xx_PWR, 0x37, 0x00);
@@ -114,17 +95,12 @@ void UC8159_Init(epd_model_t *epd)
EPD_Write(UC81xx_BTST, 0xc7, 0xcc, 0x15); EPD_Write(UC81xx_BTST, 0xc7, 0xcc, 0x15);
EPD_Write(UC81xx_CDI, 0x77); EPD_Write(UC81xx_CDI, 0x77);
EPD_Write(UC81xx_TCON, 0x22); EPD_Write(UC81xx_TCON, 0x22);
EPD_Write(0x65, 0x00); // FLASH CONTROL EPD_Write(0x65, 0x00); // FLASH CONTROL
EPD_Write(0xe5, 0x03); // FLASH MODE EPD_Write(0xe5, 0x03); // FLASH MODE
EPD_Write(UC81xx_TRES, EPD_Write(UC81xx_TRES, epd->width >> 8, epd->width & 0xff, epd->height >> 8, epd->height & 0xff);
epd->width >> 8,
epd->width & 0xff,
epd->height >> 8,
epd->height & 0xff);
} }
void JD79668_Init(epd_model_t *epd) void JD79668_Init(epd_model_t* epd) {
{
EPD_Reset(HIGH, 50); EPD_Reset(HIGH, 50);
EPD_Write(0x4D, 0x78); EPD_Write(0x4D, 0x78);
@@ -132,9 +108,7 @@ void JD79668_Init(epd_model_t *epd)
EPD_Write(UC81xx_BTST, 0x0D, 0x12, 0x24, 0x25, 0x12, 0x29, 0x10); EPD_Write(UC81xx_BTST, 0x0D, 0x12, 0x24, 0x25, 0x12, 0x29, 0x10);
EPD_Write(UC81xx_PLL, 0x08); EPD_Write(UC81xx_PLL, 0x08);
EPD_Write(UC81xx_CDI, 0x37); EPD_Write(UC81xx_CDI, 0x37);
EPD_Write(UC81xx_TRES, EPD_Write(UC81xx_TRES, epd->width / 256, epd->width % 256, epd->height / 256, epd->height % 256);
epd->width / 256, epd->width % 256,
epd->height / 256, epd->height % 256);
EPD_Write(0xAE, 0xCF); EPD_Write(0xAE, 0xCF);
EPD_Write(0xB0, 0x13); EPD_Write(0xB0, 0x13);
@@ -145,19 +119,16 @@ void JD79668_Init(epd_model_t *epd)
UC81xx_PowerOn(); UC81xx_PowerOn();
} }
void UC81xx_Clear(epd_model_t *epd, bool refresh) void UC81xx_Clear(epd_model_t* epd, bool refresh) {
{
uint32_t ram_bytes = ((epd->width + 7) / 8) * epd->height; uint32_t ram_bytes = ((epd->width + 7) / 8) * epd->height;
EPD_FillRAM(UC81xx_DTM1, 0xFF, ram_bytes); EPD_FillRAM(UC81xx_DTM1, 0xFF, ram_bytes);
EPD_FillRAM(UC81xx_DTM2, 0xFF, ram_bytes); EPD_FillRAM(UC81xx_DTM2, 0xFF, ram_bytes);
if (refresh) if (refresh) UC81xx_Refresh(epd);
UC81xx_Refresh(epd);
} }
void UC8159_Clear(epd_model_t *epd, bool refresh) void UC8159_Clear(epd_model_t* epd, bool refresh) {
{
uint32_t wb = (epd->width + 7) / 8; uint32_t wb = (epd->width + 7) / 8;
EPD_WriteCmd(UC81xx_DTM1); EPD_WriteCmd(UC81xx_DTM1);
@@ -169,87 +140,81 @@ void UC8159_Clear(epd_model_t *epd, bool refresh)
} }
} }
if (refresh) if (refresh) UC81xx_Refresh(epd);
UC81xx_Refresh(epd);
} }
void JD79668_Clear(epd_model_t *epd, bool refresh) void JD79668_Clear(epd_model_t* epd, bool refresh) {
{
uint32_t ram_bytes = ((epd->width + 3) / 4) * epd->height; uint32_t ram_bytes = ((epd->width + 3) / 4) * epd->height;
EPD_FillRAM(UC81xx_DTM1, 0x55, ram_bytes); EPD_FillRAM(UC81xx_DTM1, 0x55, ram_bytes);
if (refresh) if (refresh) UC81xx_Refresh(epd);
UC81xx_Refresh(epd);
} }
void UC81xx_Write_Image(epd_model_t *epd, uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h) void UC81xx_Write_Image(epd_model_t* epd, uint8_t* black, uint8_t* color, uint16_t x, uint16_t y, uint16_t w,
{ uint16_t h) {
uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
x -= x % 8; // byte boundary x -= x % 8; // byte boundary
w = wb * 8; // byte boundary w = wb * 8; // byte boundary
if (x + w > epd->width || y + h > epd->height) if (x + w > epd->width || y + h > epd->height) return;
return;
EPD_WriteCmd(UC81xx_PTIN); // partial in EPD_WriteCmd(UC81xx_PTIN); // partial in
_setPartialRamArea(epd, x, y, w, h); _setPartialRamArea(epd, x, y, w, h);
if (epd->color == BWR) if (epd->color == BWR) {
{
EPD_WriteCmd(UC81xx_DTM1); EPD_WriteCmd(UC81xx_DTM1);
for (uint16_t i = 0; i < h; i++) for (uint16_t i = 0; i < h; i++) {
{ for (uint16_t j = 0; j < w / 8; j++) EPD_WriteByte(black ? black[j + i * wb] : 0xFF);
for (uint16_t j = 0; j < w / 8; j++)
EPD_WriteByte(black ? black[j + i * wb] : 0xFF);
} }
} }
EPD_WriteCmd(UC81xx_DTM2); EPD_WriteCmd(UC81xx_DTM2);
for (uint16_t i = 0; i < h; i++) for (uint16_t i = 0; i < h; i++) {
{ for (uint16_t j = 0; j < w / 8; j++) {
for (uint16_t j = 0; j < w / 8; j++)
{
if (epd->color == BWR) if (epd->color == BWR)
EPD_WriteByte(color ? color[j + i * wb] : 0xFF); EPD_WriteByte(color ? color[j + i * wb] : 0xFF);
else else
EPD_WriteByte(black[j + i * wb]); EPD_WriteByte(black[j + i * wb]);
} }
} }
EPD_WriteCmd(UC81xx_PTOUT); // partial out EPD_WriteCmd(UC81xx_PTOUT); // partial out
} }
static void UC8159_Send_Pixel(uint8_t black_data, uint8_t color_data) { static void UC8159_Send_Pixel(uint8_t black_data, uint8_t color_data) {
uint8_t data; uint8_t data;
for (uint8_t j = 0; j < 8; j++) { for (uint8_t j = 0; j < 8; j++) {
if ((color_data & 0x80) == 0x00) data = 0x04; // red if ((color_data & 0x80) == 0x00)
else if ((black_data & 0x80) == 0x00) data = 0x00; // black data = 0x04; // red
else data = 0x03; // white else if ((black_data & 0x80) == 0x00)
data = 0x00; // black
else
data = 0x03; // white
data = (data << 4) & 0xFF; data = (data << 4) & 0xFF;
black_data = (black_data << 1) & 0xFF; black_data = (black_data << 1) & 0xFF;
color_data = (color_data << 1) & 0xFF; color_data = (color_data << 1) & 0xFF;
j++; j++;
if ((color_data & 0x80) == 0x00) data |= 0x04; // red if ((color_data & 0x80) == 0x00)
else if ((black_data & 0x80) == 0x00) data |= 0x00; // black data |= 0x04; // red
else data |= 0x03; // white else if ((black_data & 0x80) == 0x00)
data |= 0x00; // black
else
data |= 0x03; // white
black_data = (black_data << 1) & 0xFF; black_data = (black_data << 1) & 0xFF;
color_data = (color_data << 1) & 0xFF; color_data = (color_data << 1) & 0xFF;
EPD_WriteByte(data); EPD_WriteByte(data);
} }
} }
void UC8159_Write_Image(epd_model_t *epd, uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h) void UC8159_Write_Image(epd_model_t* epd, uint8_t* black, uint8_t* color, uint16_t x, uint16_t y, uint16_t w,
{ uint16_t h) {
uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
x -= x % 8; // byte boundary x -= x % 8; // byte boundary
w = wb * 8; // byte boundary w = wb * 8; // byte boundary
if (x + w > epd->width || y + h > epd->height) if (x + w > epd->width || y + h > epd->height) return;
return;
EPD_WriteCmd(UC81xx_PTIN); // partial in EPD_WriteCmd(UC81xx_PTIN); // partial in
_setPartialRamArea(epd, x, y, w, h); _setPartialRamArea(epd, x, y, w, h);
EPD_WriteCmd(UC81xx_DTM1); EPD_WriteCmd(UC81xx_DTM1);
for (uint16_t i = 0; i < h; i++) for (uint16_t i = 0; i < h; i++) {
{ for (uint16_t j = 0; j < w / 8; j++) {
for (uint16_t j = 0; j < w / 8; j++)
{
uint8_t black_data = 0xFF; uint8_t black_data = 0xFF;
uint8_t color_data = 0xFF; uint8_t color_data = 0xFF;
if (black) black_data = black[j + i * wb]; if (black) black_data = black[j + i * wb];
@@ -257,28 +222,25 @@ void UC8159_Write_Image(epd_model_t *epd, uint8_t *black, uint8_t *color, uint16
UC8159_Send_Pixel(black_data, color_data); UC8159_Send_Pixel(black_data, color_data);
} }
} }
EPD_WriteCmd(UC81xx_PTOUT); // partial out EPD_WriteCmd(UC81xx_PTOUT); // partial out
} }
void JD79668_Write_Image(epd_model_t *epd, uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h) void JD79668_Write_Image(epd_model_t* epd, uint8_t* black, uint8_t* color, uint16_t x, uint16_t y, uint16_t w,
{ uint16_t h) {
uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
x -= x % 8; // byte boundary x -= x % 8; // byte boundary
w = wb * 8; // byte boundary w = wb * 8; // byte boundary
if (x + w > epd->width || y + h > epd->height) if (x + w > epd->width || y + h > epd->height) return;
return;
_setPartialRamArea(epd, x, y, w, h); _setPartialRamArea(epd, x, y, w, h);
EPD_WriteCmd(UC81xx_DTM1); EPD_WriteCmd(UC81xx_DTM1);
for (uint16_t i = 0; i < h * 2; i++) // 2 bits per pixel for (uint16_t i = 0; i < h * 2; i++) // 2 bits per pixel
{ {
for (uint16_t j = 0; j < w / 8; j++) for (uint16_t j = 0; j < w / 8; j++) EPD_WriteByte(black ? black[j + i * wb] : 0x55);
EPD_WriteByte(black ? black[j + i * wb] : 0x55);
} }
} }
void UC81xx_Write_Ram(epd_model_t *epd, uint8_t cfg, uint8_t *data, uint8_t len) void UC81xx_Write_Ram(epd_model_t* epd, uint8_t cfg, uint8_t* data, uint8_t len) {
{
bool begin = (cfg >> 4) == 0x00; bool begin = (cfg >> 4) == 0x00;
bool black = (cfg & 0x0F) == 0x0F; bool black = (cfg & 0x0F) == 0x0F;
if (begin) { if (begin) {
@@ -291,16 +253,14 @@ void UC81xx_Write_Ram(epd_model_t *epd, uint8_t cfg, uint8_t *data, uint8_t len)
} }
// Write native data to ram, format should be 2pp or above // Write native data to ram, format should be 2pp or above
void UC81xx_Write_Ram_Native(epd_model_t *epd, uint8_t cfg, uint8_t *data, uint8_t len) void UC81xx_Write_Ram_Native(epd_model_t* epd, uint8_t cfg, uint8_t* data, uint8_t len) {
{
bool begin = (cfg >> 4) == 0x00; bool begin = (cfg >> 4) == 0x00;
bool black = (cfg & 0x0F) == 0x0F; bool black = (cfg & 0x0F) == 0x0F;
if (begin && black) EPD_WriteCmd(UC81xx_DTM1); if (begin && black) EPD_WriteCmd(UC81xx_DTM1);
EPD_WriteData(data, len); EPD_WriteData(data, len);
} }
void UC81xx_Sleep(epd_model_t *epd) void UC81xx_Sleep(epd_model_t* epd) {
{
UC81xx_PowerOff(); UC81xx_PowerOff();
delay(100); delay(100);
EPD_Write(UC81xx_DSLP, 0xA5); EPD_Write(UC81xx_DSLP, 0xA5);

File diff suppressed because it is too large Load Diff

View File

@@ -4,99 +4,99 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include "u8g2_font.h" #include "u8g2_font.h"
#define GFX_BLACK 0x0000 #define GFX_BLACK 0x0000
#define GFX_WHITE 0xFFFF #define GFX_WHITE 0xFFFF
#define GFX_RED 0xF800 // 255, 0, 0 #define GFX_RED 0xF800 // 255, 0, 0
#define GFX_YELLOW 0xFFE0 // 255, 255, 0 #define GFX_YELLOW 0xFFE0 // 255, 255, 0
#define GFX_BLUE 0x001F // 0, 0, 255 #define GFX_BLUE 0x001F // 0, 0, 255
#define GFX_GREEN 0x07E0 // 0, 255, 0 #define GFX_GREEN 0x07E0 // 0, 255, 0
#define GFX_ORANGE 0xFC00 // 255, 128, 0 #define GFX_ORANGE 0xFC00 // 255, 128, 0
typedef void (*buffer_callback)(void *user_data, uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h); typedef void (*buffer_callback)(void* user_data, uint8_t* black, uint8_t* color, uint16_t x, uint16_t y, uint16_t w,
uint16_t h);
typedef enum { typedef enum {
GFX_ROTATE_0 = 0, GFX_ROTATE_0 = 0,
GFX_ROTATE_90 = 1, GFX_ROTATE_90 = 1,
GFX_ROTATE_180 = 2, GFX_ROTATE_180 = 2,
GFX_ROTATE_270 = 3, GFX_ROTATE_270 = 3,
} GFX_Rotate; } GFX_Rotate;
// GRAPHICS CONTEXT // GRAPHICS CONTEXT
typedef struct { typedef struct {
int16_t WIDTH; // This is the 'raw' display width - never changes int16_t WIDTH; // This is the 'raw' display width - never changes
int16_t HEIGHT; // This is the 'raw' display height - 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 _width; // Display width as modified by current rotation
int16_t _height; // Display height as modified by current rotation int16_t _height; // Display height as modified by current rotation
GFX_Rotate rotation; // Display rotation (0 thru 3) GFX_Rotate rotation; // Display rotation (0 thru 3)
u8g2_font_t u8g2; u8g2_font_t u8g2;
int16_t tx, ty; // current position for the print command int16_t tx, ty; // current position for the print command
uint16_t encoding; // the unicode, detected by the utf-8 decoder 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
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* buffer; // black pixel buffer
uint8_t *color; // color pixel buffer (3c only) uint8_t* color; // color pixel buffer (3c only)
uint16_t px, py, pw, ph; // partial window offset and size uint16_t px, py, pw, ph; // partial window offset and size
int16_t page_height; // height to be drawn in one page int16_t page_height; // height to be drawn in one page
int16_t current_page; // index of the current drawing page int16_t current_page; // index of the current drawing page
int16_t total_pages; // total number of pages to be drawn int16_t total_pages; // total number of pages to be drawn
} Adafruit_GFX; } Adafruit_GFX;
// CONTROL API // CONTROL API
void GFX_begin(Adafruit_GFX *gfx, int16_t w, int16_t h, int16_t buffer_height); 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_begin_3c(Adafruit_GFX* gfx, int16_t w, int16_t h, int16_t buffer_height);
void GFX_begin_4c(Adafruit_GFX *gfx, int16_t w, int16_t h, int16_t buffer_height); void GFX_begin_4c(Adafruit_GFX* gfx, int16_t w, int16_t h, int16_t buffer_height);
void GFX_setRotation(Adafruit_GFX *gfx, GFX_Rotate r); void GFX_setRotation(Adafruit_GFX* gfx, GFX_Rotate r);
void GFX_setWindow(Adafruit_GFX *gfx, uint16_t x, uint16_t y, uint16_t w, uint16_t h); void GFX_setWindow(Adafruit_GFX* gfx, uint16_t x, uint16_t y, uint16_t w, uint16_t h);
void GFX_firstPage(Adafruit_GFX *gfx); void GFX_firstPage(Adafruit_GFX* gfx);
bool GFX_nextPage(Adafruit_GFX *gfx, buffer_callback callback, void *user_data); bool GFX_nextPage(Adafruit_GFX* gfx, buffer_callback callback, void* user_data);
void GFX_end(Adafruit_GFX *gfx); void GFX_end(Adafruit_GFX* gfx);
// DRAW API // DRAW API
void GFX_drawPixel(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t color); 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_drawLine(Adafruit_GFX* gfx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
void GFX_drawDottedLine(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, void GFX_drawDottedLine(Adafruit_GFX* gfx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color,
uint16_t color, uint8_t dot_len, uint8_t space_len); uint8_t dot_len, uint8_t space_len);
void GFX_drawFastVLine(Adafruit_GFX *gfx, int16_t x, int16_t y, int16_t h, 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_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_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_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_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_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, 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); uint16_t color);
void GFX_fillCircle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r, 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,
void GFX_fillCircleHelper(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color);
int16_t delta, 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,
void GFX_drawTriangle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, uint16_t color);
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_fillTriangle(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, void GFX_fillRoundRect(Adafruit_GFX* gfx, int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color);
int16_t y2, 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,
void GFX_drawRoundRect(Adafruit_GFX *gfx, int16_t x0, int16_t y0, int16_t w, int16_t h, uint16_t color, bool invert);
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 // U8G2 FONT API
void GFX_setCursor(Adafruit_GFX *gfx, int16_t x, int16_t y); void GFX_setCursor(Adafruit_GFX* gfx, int16_t x, int16_t y);
void GFX_setFont(Adafruit_GFX *gfx, const uint8_t *font); void GFX_setFont(Adafruit_GFX* gfx, const uint8_t* font);
void GFX_setFontMode(Adafruit_GFX *gfx, uint8_t is_transparent); void GFX_setFontMode(Adafruit_GFX* gfx, uint8_t is_transparent);
void GFX_setFontDirection(Adafruit_GFX *gfx, GFX_Rotate d); void GFX_setFontDirection(Adafruit_GFX* gfx, GFX_Rotate d);
void GFX_setTextColor(Adafruit_GFX *gfx, uint16_t fg, uint16_t bg); void GFX_setTextColor(Adafruit_GFX* gfx, uint16_t fg, uint16_t bg);
int8_t GFX_getFontAscent(Adafruit_GFX *gfx); int8_t GFX_getFontAscent(Adafruit_GFX* gfx);
int8_t GFX_getFontDescent(Adafruit_GFX *gfx); int8_t GFX_getFontDescent(Adafruit_GFX* gfx);
int8_t GFX_getFontHeight(Adafruit_GFX *gfx); int8_t GFX_getFontHeight(Adafruit_GFX* gfx);
int16_t GFX_drawGlyph(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t e); 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_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_drawUTF8(Adafruit_GFX* gfx, int16_t x, int16_t y, const char* str);
int16_t GFX_getUTF8Width(Adafruit_GFX *gfx, const char *str); int16_t GFX_getUTF8Width(Adafruit_GFX* gfx, const char* str);
int16_t GFX_getUTF8Widthf(Adafruit_GFX *gfx, const char* format, ...); int16_t GFX_getUTF8Widthf(Adafruit_GFX* gfx, const char* format, ...);
size_t GFX_print(Adafruit_GFX *gfx, const char c); 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_write(Adafruit_GFX* gfx, const char* buffer, size_t size);
size_t GFX_printf(Adafruit_GFX *gfx, const char* format, ...); size_t GFX_printf(Adafruit_GFX* gfx, const char* format, ...);
#endif // _ADAFRUIT_GFX_H #endif // _ADAFRUIT_GFX_H

140
GUI/GUI.c
View File

@@ -1,65 +1,43 @@
#include "fonts.h"
#include "Lunar.h"
#include "GUI.h" #include "GUI.h"
#include <time.h>
#include <stdio.h> #include <stdio.h>
#include <time.h>
#include "Lunar.h"
#include "fonts.h"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define GFX_printf_styled(gfx, fg, bg, font, ...) \ #define GFX_printf_styled(gfx, fg, bg, font, ...) \
GFX_setTextColor(gfx, fg, bg); \ GFX_setTextColor(gfx, fg, bg); \
GFX_setFont(gfx, font); \ GFX_setFont(gfx, font); \
GFX_printf(gfx, __VA_ARGS__); GFX_printf(gfx, __VA_ARGS__);
typedef struct { typedef struct {
uint8_t month; uint8_t month;
uint8_t day; uint8_t day;
char name[10]; // 3x3+1 char name[10]; // 3x3+1
} Festival; } Festival;
static const Festival festivals[] = { static const Festival festivals[] = {
{ 1, 1, "元旦"}, {1, 1, "元旦节"}, {2, 14, "情人节"}, {3, 8, "妇女节"}, {3, 12, "植树节"}, {4, 1, "愚人"},
{ 2, 14, "情人"}, {5, 1, "劳动节"}, {5, 4, "青年节"}, {6, 1, "儿童节"}, {7, 1, "建党节"}, {8, 1, "建军"},
{ 3, 8, "妇女"}, {9, 10, "教师节"}, {10, 1, "国庆节"}, {11, 1, "万圣节"}, {12, 24, "平安夜"}, {12, 25, "圣诞"},
{ 3, 12, "植树节"},
{ 4, 1, "愚人节"},
{ 5, 1, "劳动节"},
{ 5, 4, "青年节"},
{ 6, 1, "儿童节"},
{ 7, 1, "建党节"},
{ 8, 1, "建军节"},
{ 9, 10, "教师节"},
{10, 1, "国庆节"},
{11, 1, "万圣节"},
{12, 24, "平安夜"},
{12, 25, "圣诞节"},
}; };
static const Festival festivals_lunar[] = { static const Festival festivals_lunar[] = {
{ 1, 1, "" }, {1, 1, "春节"}, {1, 15, "元宵"}, {2, 2, "龙抬头"}, {5, 5, "端午节"}, {7, 7, "七夕节"}, {7, 15, "中元节"},
{ 1, 15, "元宵"}, {8, 15, "中秋节"}, {9, 9, "重阳节"}, {10, 1, "寒衣节"}, {12, 8, "腊八"}, {12, 30, "除夕"},
{ 2, 2, "龙抬头"},
{ 5, 5, "端午节"},
{ 7, 7, "七夕节"},
{ 7, 15, "中元节"},
{ 8, 15, "中秋节"},
{ 9, 9, "重阳节"},
{10, 1, "寒衣节"},
{12, 8, "腊八节"},
{12, 30, "除夕" },
}; };
// 放假和调休数据,每年更新 // 放假和调休数据,每年更新
#define HOLIDAY_YEAR 2025 #define HOLIDAY_YEAR 2025
static const uint16_t holidays[] = { static const uint16_t holidays[] = {
0x0101, 0x111A, 0x011C, 0x011D, 0x011E, 0x011F, 0x0201, 0x0202, 0x0101, 0x111A, 0x011C, 0x011D, 0x011E, 0x011F, 0x0201, 0x0202, 0x0202, 0x0203, 0x0204, 0x1208,
0x0202, 0x0203, 0x0204, 0x1208, 0x0404, 0x0405, 0x0406, 0x141B, 0x0404, 0x0405, 0x0406, 0x141B, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x051F, 0x0601, 0x0602,
0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x051F, 0x0601, 0x0602, 0x191C, 0x0A01, 0x0A02, 0x0A03, 0x0A04, 0x0A05, 0x0A06, 0x0A07, 0x0A08, 0x1A0B,
0x191C, 0x0A01, 0x0A02, 0x0A03, 0x0A04, 0x0A05, 0x0A06, 0x0A07,
0x0A08, 0x1A0B,
}; };
static bool GetHoliday(uint8_t mon, uint8_t day, bool *work) static bool GetHoliday(uint8_t mon, uint8_t day, bool* work) {
{
for (uint8_t i = 0; i < ARRAY_SIZE(holidays); i++) { for (uint8_t i = 0; i < ARRAY_SIZE(holidays); i++) {
if (((holidays[i] >> 8) & 0xF) == mon && (holidays[i] & 0xFF) == day) { if (((holidays[i] >> 8) & 0xF) == mon && (holidays[i] & 0xFF) == day) {
*work = ((holidays[i] >> 12) & 0xF) > 0; *work = ((holidays[i] >> 12) & 0xF) > 0;
@@ -69,9 +47,8 @@ static bool GetHoliday(uint8_t mon, uint8_t day, bool *work)
return false; return false;
} }
static bool GetFestival(uint16_t year, uint8_t mon, uint8_t day, uint8_t week, static bool GetFestival(uint16_t year, uint8_t mon, uint8_t day, uint8_t week, struct Lunar_Date* Lunar,
struct Lunar_Date *Lunar, char *festival) char* festival) {
{
// 农历节日 // 农历节日
for (uint8_t i = 0; i < ARRAY_SIZE(festivals_lunar); i++) { for (uint8_t i = 0; i < ARRAY_SIZE(festivals_lunar); i++) {
if (Lunar->Month == festivals_lunar[i].month && Lunar->Date == festivals_lunar[i].day) { if (Lunar->Month == festivals_lunar[i].month && Lunar->Date == festivals_lunar[i].day) {
@@ -121,19 +98,18 @@ static bool GetFestival(uint16_t year, uint8_t mon, uint8_t day, uint8_t week,
uint8_t JQ = (mon - 1) * 2; uint8_t JQ = (mon - 1) * 2;
if (day >= 15) JQ++; if (day >= 15) JQ++;
strcpy(festival, JieQiStr[JQ]); strcpy(festival, JieQiStr[JQ]);
if (JQ == 6) // 清明 if (JQ == 6) // 清明
strcat(festival, ""); strcat(festival, "");
return true; return true;
} }
return false; return false;
} }
static void DrawTimeSyncTip(Adafruit_GFX *gfx, gui_data_t *data) static void DrawTimeSyncTip(Adafruit_GFX* gfx, gui_data_t* data) {
{ const char* title = "SYNC TIME!";
const char *title = "SYNC TIME!"; const char* url = "https://tsl0922.github.io/EPD-nRF5";
const char *url = "https://tsl0922.github.io/EPD-nRF5";
GFX_setFont(gfx, u8g2_font_wqy9_t_lunar); GFX_setFont(gfx, u8g2_font_wqy9_t_lunar);
@@ -153,8 +129,7 @@ static void DrawTimeSyncTip(Adafruit_GFX *gfx, gui_data_t *data)
GFX_printf(gfx, url); GFX_printf(gfx, url);
} }
static void DrawBattery(Adafruit_GFX *gfx, int16_t x, int16_t y, uint8_t iw, float voltage) static void DrawBattery(Adafruit_GFX* gfx, int16_t x, int16_t y, uint8_t iw, float voltage) {
{
x -= iw; x -= iw;
uint8_t level = (uint8_t)(voltage * 100 / 3.6f); uint8_t level = (uint8_t)(voltage * 100 / 3.6f);
GFX_setFont(gfx, u8g2_font_wqy9_t_lunar); GFX_setFont(gfx, u8g2_font_wqy9_t_lunar);
@@ -166,8 +141,7 @@ static void DrawBattery(Adafruit_GFX *gfx, int16_t x, int16_t y, uint8_t iw, flo
GFX_fillRect(gfx, x + 2, y + 2, 16 * level / 100, 6, GFX_BLACK); GFX_fillRect(gfx, x + 2, y + 2, 16 * level / 100, 6, GFX_BLACK);
} }
static uint8_t GetWeekOfYear(uint8_t year, uint8_t mon, uint8_t mday, uint8_t wday) static uint8_t GetWeekOfYear(uint8_t year, uint8_t mon, uint8_t mday, uint8_t wday) {
{
struct tm tm = {0}; struct tm tm = {0};
tm.tm_year = year; tm.tm_year = year;
tm.tm_mon = mon; tm.tm_mon = mon;
@@ -180,8 +154,8 @@ static uint8_t GetWeekOfYear(uint8_t year, uint8_t mon, uint8_t mday, uint8_t wd
return atoi(buffer); return atoi(buffer);
} }
static void DrawDateHeader(Adafruit_GFX *gfx, int16_t x, int16_t y, tm_t *tm, struct Lunar_Date *Lunar, gui_data_t *data) static void DrawDateHeader(Adafruit_GFX* gfx, int16_t x, int16_t y, tm_t* tm, struct Lunar_Date* Lunar,
{ gui_data_t* data) {
GFX_setCursor(gfx, x, y - 2); GFX_setCursor(gfx, x, y - 2);
GFX_printf_styled(gfx, GFX_RED, GFX_WHITE, u8g2_font_helvB18_tn, "%d", tm->tm_year + YEAR0); GFX_printf_styled(gfx, GFX_RED, GFX_WHITE, u8g2_font_helvB18_tn, "%d", tm->tm_year + YEAR0);
GFX_printf_styled(gfx, GFX_BLACK, GFX_WHITE, u8g2_font_wqy12_t_lunar, ""); GFX_printf_styled(gfx, GFX_BLACK, GFX_WHITE, u8g2_font_wqy12_t_lunar, "");
@@ -195,10 +169,10 @@ static void DrawDateHeader(Adafruit_GFX *gfx, int16_t x, int16_t y, tm_t *tm, st
GFX_setCursor(gfx, tx, ty); GFX_setCursor(gfx, tx, ty);
if (Lunar->IsLeap) GFX_printf(gfx, " "); if (Lunar->IsLeap) GFX_printf(gfx, " ");
GFX_printf(gfx, "%s%s%s", Lunar_MonthLeapString[Lunar->IsLeap], Lunar_MonthString[Lunar->Month], GFX_printf(gfx, "%s%s%s", Lunar_MonthLeapString[Lunar->IsLeap], Lunar_MonthString[Lunar->Month],
Lunar_DateString[Lunar->Date]); Lunar_DateString[Lunar->Date]);
GFX_setTextColor(gfx, GFX_RED, GFX_WHITE); GFX_setTextColor(gfx, GFX_RED, GFX_WHITE);
GFX_printf(gfx, " [%d周]", GetWeekOfYear(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday)); GFX_printf(gfx, " [%d周]", GetWeekOfYear(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday));
GFX_setCursor(gfx, tx, ty - 14); GFX_setCursor(gfx, tx, ty - 14);
GFX_setTextColor(gfx, GFX_BLACK, GFX_WHITE); GFX_setTextColor(gfx, GFX_BLACK, GFX_WHITE);
GFX_printf(gfx, " %s%s年", Lunar_StemStrig[LUNAR_GetStem(Lunar)], Lunar_BranchStrig[LUNAR_GetBranch(Lunar)]); GFX_printf(gfx, " %s%s年", Lunar_StemStrig[LUNAR_GetStem(Lunar)], Lunar_BranchStrig[LUNAR_GetBranch(Lunar)]);
@@ -211,8 +185,7 @@ static void DrawDateHeader(Adafruit_GFX *gfx, int16_t x, int16_t y, tm_t *tm, st
GFX_printf(gfx, "%s", data->ssid); GFX_printf(gfx, "%s", data->ssid);
} }
static void DrawWeekHeader(Adafruit_GFX *gfx, int16_t x, int16_t y, gui_data_t *data) static void DrawWeekHeader(Adafruit_GFX* gfx, int16_t x, int16_t y, gui_data_t* data) {
{
GFX_setFont(gfx, data->height > 300 ? u8g2_font_wqy12_t_lunar : u8g2_font_wqy9_t_lunar); GFX_setFont(gfx, data->height > 300 ? u8g2_font_wqy12_t_lunar : u8g2_font_wqy9_t_lunar);
uint8_t w = (data->width - 2 * x) / 7; uint8_t w = (data->width - 2 * x) / 7;
uint8_t h = data->height > 300 ? 32 : 24; uint8_t h = data->height > 300 ? 32 : 24;
@@ -229,8 +202,8 @@ static void DrawWeekHeader(Adafruit_GFX *gfx, int16_t x, int16_t y, gui_data_t *
} }
} }
static void DrawMonthDays(Adafruit_GFX *gfx, int16_t x, int16_t y, tm_t *tm, struct Lunar_Date *Lunar, gui_data_t *data) static void DrawMonthDays(Adafruit_GFX* gfx, int16_t x, int16_t y, tm_t* tm, struct Lunar_Date* Lunar,
{ gui_data_t* data) {
uint8_t firstDayWeek = get_first_day_week(tm->tm_year + YEAR0, tm->tm_mon + 1); uint8_t firstDayWeek = get_first_day_week(tm->tm_year + YEAR0, tm->tm_mon + 1);
int8_t adjustedFirstDay = (firstDayWeek - data->week_start + 7) % 7; int8_t adjustedFirstDay = (firstDayWeek - data->week_start + 7) % 7;
uint8_t monthMaxDays = thisMonthMaxDays(tm->tm_year + YEAR0, tm->tm_mon + 1); uint8_t monthMaxDays = thisMonthMaxDays(tm->tm_year + YEAR0, tm->tm_mon + 1);
@@ -254,7 +227,7 @@ static void DrawMonthDays(Adafruit_GFX *gfx, int16_t x, int16_t y, tm_t *tm, str
int16_t actualWeek = (firstDayWeek + i) % 7; int16_t actualWeek = (firstDayWeek + i) % 7;
int16_t displayWeek = (adjustedFirstDay + i) % 7; int16_t displayWeek = (adjustedFirstDay + i) % 7;
bool weekend = (actualWeek == 0) || (actualWeek == 6); bool weekend = (actualWeek == 0) || (actualWeek == 6);
LUNAR_SolarToLunar(Lunar, year, month, day); LUNAR_SolarToLunar(Lunar, year, month, day);
@@ -272,15 +245,16 @@ static void DrawMonthDays(Adafruit_GFX *gfx, int16_t x, int16_t y, tm_t *tm, str
GFX_setFont(gfx, large ? u8g2_font_helvB18_tn : u8g2_font_helvB14_tn); GFX_setFont(gfx, large ? u8g2_font_helvB18_tn : u8g2_font_helvB14_tn);
GFX_setCursor(gfx, bx + (2 * cr - GFX_getUTF8Widthf(gfx, "%d", day)) / 2, by - (cr - GFX_getFontHeight(gfx))); GFX_setCursor(gfx, bx + (2 * cr - GFX_getUTF8Widthf(gfx, "%d", day)) / 2, by - (cr - GFX_getFontHeight(gfx)));
GFX_printf(gfx, "%d", day); GFX_printf(gfx, "%d", day);
char festival[10] = {0}; char festival[10] = {0};
GFX_setFont(gfx, large ? u8g2_font_wqy12_t_lunar : u8g2_font_wqy9_t_lunar); GFX_setFont(gfx, large ? u8g2_font_wqy12_t_lunar : u8g2_font_wqy9_t_lunar);
GFX_setFontMode(gfx, 1); // transparent GFX_setFontMode(gfx, 1); // transparent
if (GetFestival(year, month, day, actualWeek, Lunar, festival)) { if (GetFestival(year, month, day, actualWeek, Lunar, festival)) {
if (day != tm->tm_mday) GFX_setTextColor(gfx, GFX_RED, GFX_WHITE); if (day != tm->tm_mday) GFX_setTextColor(gfx, GFX_RED, GFX_WHITE);
} else { } else {
if (Lunar->Date == 1) if (Lunar->Date == 1)
snprintf(festival, sizeof(festival), "%s%s", Lunar_MonthLeapString[Lunar->IsLeap], Lunar_MonthString[Lunar->Month]); snprintf(festival, sizeof(festival), "%s%s", Lunar_MonthLeapString[Lunar->IsLeap],
Lunar_MonthString[Lunar->Month]);
else else
snprintf(festival, sizeof(festival), "%s", Lunar_DateString[Lunar->Date]); snprintf(festival, sizeof(festival), "%s", Lunar_DateString[Lunar->Date]);
} }
@@ -304,14 +278,14 @@ static void DrawMonthDays(Adafruit_GFX *gfx, int16_t x, int16_t y, tm_t *tm, str
} }
} }
static void DrawCalendar(Adafruit_GFX *gfx, tm_t *tm, struct Lunar_Date *Lunar, gui_data_t *data) static void DrawCalendar(Adafruit_GFX* gfx, tm_t* tm, struct Lunar_Date* Lunar, gui_data_t* data) {
{
bool large = data->height > 300; bool large = data->height > 300;
DrawDateHeader(gfx, 10, large ? 38 : 28, tm, Lunar, data); DrawDateHeader(gfx, 10, large ? 38 : 28, tm, Lunar, data);
DrawWeekHeader(gfx, 10, large ? 44 : 32, data); DrawWeekHeader(gfx, 10, large ? 44 : 32, data);
DrawMonthDays(gfx, 10, large ? 84 : 64, tm, Lunar, data); DrawMonthDays(gfx, 10, large ? 84 : 64, tm, Lunar, data);
} }
// clang-format off
/* Routine to Draw Large 7-Segment formated number /* Routine to Draw Large 7-Segment formated number
Contributed by William Zaggle. Contributed by William Zaggle.
@@ -341,19 +315,18 @@ static void Draw7Number(Adafruit_GFX *gfx, int n, unsigned int xLoc, unsigned in
} }
} }
} }
// clang-format on
static void DrawTime(Adafruit_GFX *gfx, tm_t *tm, int16_t x, int16_t y, uint16_t cS, uint16_t nD) static void DrawTime(Adafruit_GFX* gfx, tm_t* tm, int16_t x, int16_t y, uint16_t cS, uint16_t nD) {
{
Draw7Number(gfx, tm->tm_hour, x, y, cS, GFX_BLACK, GFX_WHITE, nD); Draw7Number(gfx, tm->tm_hour, x, y, cS, GFX_BLACK, GFX_WHITE, nD);
x += (nD*(11*cS+2)-2*cS) + 2*cS; x += (nD * (11 * cS + 2) - 2 * cS) + 2 * cS;
GFX_fillRect(gfx, x, y + 4.5*cS+1, 2*cS, 2*cS, GFX_BLACK); GFX_fillRect(gfx, x, y + 4.5 * cS + 1, 2 * cS, 2 * cS, GFX_BLACK);
GFX_fillRect(gfx, x, y + 13.5*cS+3, 2*cS, 2*cS, GFX_BLACK); GFX_fillRect(gfx, x, y + 13.5 * cS + 3, 2 * cS, 2 * cS, GFX_BLACK);
x += 4*cS; x += 4 * cS;
Draw7Number(gfx, tm->tm_min, x, y, cS, GFX_BLACK, GFX_WHITE, nD); Draw7Number(gfx, tm->tm_min, x, y, cS, GFX_BLACK, GFX_WHITE, nD);
} }
static void DrawClock(Adafruit_GFX *gfx, tm_t *tm, struct Lunar_Date *Lunar, gui_data_t *data) static void DrawClock(Adafruit_GFX* gfx, tm_t* tm, struct Lunar_Date* Lunar, gui_data_t* data) {
{
uint8_t padding = data->height > 300 ? 100 : 40; uint8_t padding = data->height > 300 ? 100 : 40;
GFX_setCursor(gfx, padding, 36); GFX_setCursor(gfx, padding, 36);
GFX_printf_styled(gfx, GFX_RED, GFX_WHITE, u8g2_font_helvB18_tn, "%d", tm->tm_year + YEAR0); GFX_printf_styled(gfx, GFX_RED, GFX_WHITE, u8g2_font_helvB18_tn, "%d", tm->tm_year + YEAR0);
@@ -368,7 +341,7 @@ static void DrawClock(Adafruit_GFX *gfx, tm_t *tm, struct Lunar_Date *Lunar, gui
GFX_printf(gfx, "星期%s", Lunar_DayString[tm->tm_wday]); GFX_printf(gfx, "星期%s", Lunar_DayString[tm->tm_wday]);
GFX_setCursor(gfx, 138, 58); GFX_setCursor(gfx, 138, 58);
GFX_printf(gfx, "%s%s%s", Lunar_MonthLeapString[Lunar->IsLeap], Lunar_MonthString[Lunar->Month], GFX_printf(gfx, "%s%s%s", Lunar_MonthLeapString[Lunar->IsLeap], Lunar_MonthString[Lunar->Month],
Lunar_DateString[Lunar->Date]); Lunar_DateString[Lunar->Date]);
DrawBattery(gfx, data->width - padding, 25, 20, data->voltage); DrawBattery(gfx, data->width - padding, 25, 20, data->voltage);
@@ -381,7 +354,7 @@ static void DrawClock(Adafruit_GFX *gfx, tm_t *tm, struct Lunar_Date *Lunar, gui
GFX_printf(gfx, "%d℃[%s]", data->temperature, ssid); GFX_printf(gfx, "%d℃[%s]", data->temperature, ssid);
GFX_drawFastHLine(gfx, padding - 10, 68, data->width - 2 * (padding - 10), GFX_BLACK); GFX_drawFastHLine(gfx, padding - 10, 68, data->width - 2 * (padding - 10), GFX_BLACK);
uint16_t cS = data->height / 45; uint16_t cS = data->height / 45;
uint16_t nD = 2; uint16_t nD = 2;
uint16_t time_width = 2 * (nD * (11 * cS + 2) - 2 * cS) + 4 * cS; uint16_t time_width = 2 * (nD * (11 * cS + 2) - 2 * cS) + 4 * cS;
@@ -389,7 +362,7 @@ static void DrawClock(Adafruit_GFX *gfx, tm_t *tm, struct Lunar_Date *Lunar, gui
int16_t time_x = (data->width - time_width) / 2; int16_t time_x = (data->width - time_width) / 2;
int16_t time_y = (68 + (data->height - 68)) / 2 - time_height / 2; int16_t time_y = (68 + (data->height - 68)) / 2 - time_height / 2;
DrawTime(gfx, tm, time_x, time_y, cS, nD); DrawTime(gfx, tm, time_x, time_y, cS, nD);
GFX_drawFastHLine(gfx, padding - 10, data->height - 68, data->width - 2 * (padding - 10), GFX_BLACK); GFX_drawFastHLine(gfx, padding - 10, data->height - 68, data->width - 2 * (padding - 10), GFX_BLACK);
GFX_setCursor(gfx, padding, data->height - 68 + 30); GFX_setCursor(gfx, padding, data->height - 68 + 30);
@@ -422,8 +395,7 @@ static void DrawClock(Adafruit_GFX *gfx, tm_t *tm, struct Lunar_Date *Lunar, gui
} }
} }
void DrawGUI(gui_data_t *data, buffer_callback callback, void *callback_data) void DrawGUI(gui_data_t* data, buffer_callback callback, void* callback_data) {
{
if (data->week_start > 6) data->week_start = 0; if (data->week_start > 6) data->week_start = 0;
tm_t tm = {0}; tm_t tm = {0};
@@ -435,11 +407,11 @@ void DrawGUI(gui_data_t *data, buffer_callback callback, void *callback_data)
int16_t ph = (__HEAP_SIZE - 512) / (data->width / 8); int16_t ph = (__HEAP_SIZE - 512) / (data->width / 8);
if (data->color == 2) if (data->color == 2)
GFX_begin_3c(&gfx, data->width, data->height, ph); GFX_begin_3c(&gfx, data->width, data->height, ph);
else if (data->color == 3) else if (data->color == 3)
GFX_begin_4c(&gfx, data->width, data->height, ph); GFX_begin_4c(&gfx, data->width, data->height, ph);
else else
GFX_begin(&gfx, data->width, data->height, ph); GFX_begin(&gfx, data->width, data->height, ph);
GFX_firstPage(&gfx); GFX_firstPage(&gfx);
do { do {
@@ -461,7 +433,7 @@ void DrawGUI(gui_data_t *data, buffer_callback callback, void *callback_data)
(tm.tm_year + YEAR0 == 2025 && tm.tm_mon + 1 == 1)) { (tm.tm_year + YEAR0 == 2025 && tm.tm_mon + 1 == 1)) {
DrawTimeSyncTip(&gfx, data); DrawTimeSyncTip(&gfx, data);
} }
} while(GFX_nextPage(&gfx, callback, callback_data)); } while (GFX_nextPage(&gfx, callback, callback_data));
GFX_end(&gfx); GFX_end(&gfx);
} }

View File

@@ -15,12 +15,12 @@ typedef struct {
uint16_t width; uint16_t width;
uint16_t height; uint16_t height;
uint32_t timestamp; uint32_t timestamp;
uint8_t week_start; // 0: Sunday, 1: Monday uint8_t week_start; // 0: Sunday, 1: Monday
int8_t temperature; int8_t temperature;
float voltage; float voltage;
char ssid[20]; char ssid[20];
} gui_data_t; } gui_data_t;
void DrawGUI(gui_data_t *data, buffer_callback callback, void *callback_data); void DrawGUI(gui_data_t* data, buffer_callback callback, void* callback_data);
#endif #endif

View File

@@ -1,32 +1,22 @@
#include "Lunar.h" #include "Lunar.h"
const char Lunar_MonthString[13][7] = { const char Lunar_MonthString[13][7] = {"----", "正月", "二月", "三月", "四月", "五月", "六月",
"----", "七月", "八月", "九月", "十月", "冬月", "腊月"};
"正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月",
"冬月", "腊月"};
const char Lunar_MonthLeapString[2][4] = { const char Lunar_MonthLeapString[2][4] = {" ", ""};
" ",
""};
const char Lunar_DateString[31][7] = { const char Lunar_DateString[31][7] = {"----", "初一", "初二", "初三", "初四", "初五", "初六", "初七",
"----", "初八", "初九", "初十", "十一", "十二", "十三", "十四", "十五",
"初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十", "十六", "十七", "十八", "十九", "二十", "廿一", "廿二", "廿三",
"十一", "十二", "十三", "", "", "", "", "", "", "", "廿", "廿", "廿", "廿", "廿", "廿", ""};
"廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"};
const char Lunar_DayString[7][4] = { const char Lunar_DayString[7][4] = {"", "", "", "", "", "", ""};
"",
"", "", "", "", "", ""};
const char Lunar_ZodiacString[12][4] = { const char Lunar_ZodiacString[12][4] = {"", "", "", "", "", "", "", "", "", "", "", ""};
"", "", "", "", "", "", "", "", "", "", "", ""};
const char Lunar_StemStrig[10][4] = { const char Lunar_StemStrig[10][4] = {"", "", "", "", "", "", "", "", "", ""};
"", "", "", "", "", "", "", "", "", ""};
const char Lunar_BranchStrig[12][4] = { const char Lunar_BranchStrig[12][4] = {"", "", "", "", "", "", "", "", "", "", "", ""};
"", "", "", "", "", "", "", "", "", "", "", ""};
/* 2000 ~ 2199 */ /* 2000 ~ 2199 */
const uint32_t lunar_month_days[] = { const uint32_t lunar_month_days[] = {
@@ -82,28 +72,24 @@ const uint32_t solar_1_1[] = {
0x00111648, 0x0011183C, 0x00111A4F, 0x00111C45, 0x00111E39, 0x0011204D, 0x00112242, 0x00112436, 0x0011264A, 0x00111648, 0x0011183C, 0x00111A4F, 0x00111C45, 0x00111E39, 0x0011204D, 0x00112242, 0x00112436, 0x0011264A,
0x0011283E, 0x00112A51, 0x00112C46, 0x00112E3B, 0x0011304F*/}; 0x0011283E, 0x00112A51, 0x00112C46, 0x00112E3B, 0x0011304F*/};
static uint32_t GetBitInt(uint32_t data, uint8_t length, uint8_t shift) static uint32_t GetBitInt(uint32_t data, uint8_t length, uint8_t shift) {
{
return (data & (((1 << length) - 1) << shift)) >> shift; return (data & (((1 << length) - 1) << shift)) >> shift;
} }
// WARNING: Dates before Oct. 1582 are inaccurate // WARNING: Dates before Oct. 1582 are inaccurate
static uint16_t SolarToInt(uint16_t y, uint8_t m, uint8_t d) static uint16_t SolarToInt(uint16_t y, uint8_t m, uint8_t d) {
{
m = (m + 9) % 12; m = (m + 9) % 12;
y = y - m / 10; y = y - m / 10;
return 365 * y + y / 4 - y / 100 + y / 400 + (m * 306 + 5) / 10 + (d - 1); 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) 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; uint8_t i, lunarM, m, d, leap, dm;
uint16_t year_index, lunarY, y, offset; uint16_t year_index, lunarY, y, offset;
uint32_t solar_data, solar11, days; uint32_t solar_data, solar11, days;
if (solar_month < 1 || solar_month > 12 || solar_date < 1 || solar_date > 31 || 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] < 3) || ((solar_year - solar_1_1[0]) > (sizeof(solar_1_1) / sizeof(uint32_t) - 2))) ((solar_year - solar_1_1[0]) > (sizeof(solar_1_1) / sizeof(uint32_t) - 2))) {
{
lunar->Year = 0; lunar->Year = 0;
lunar->Month = 0; lunar->Month = 0;
lunar->Date = 0; lunar->Date = 0;
@@ -113,8 +99,7 @@ void LUNAR_SolarToLunar(struct Lunar_Date *lunar, uint16_t solar_year, uint8_t s
year_index = solar_year - solar_1_1[0]; year_index = solar_year - solar_1_1[0];
solar_data = ((uint32_t)solar_year << 9) | ((uint32_t)solar_month << 5) | ((uint32_t)solar_date); solar_data = ((uint32_t)solar_year << 9) | ((uint32_t)solar_month << 5) | ((uint32_t)solar_date);
if (solar_1_1[year_index] > solar_data) if (solar_1_1[year_index] > solar_data) {
{
year_index -= 1; year_index -= 1;
} }
solar11 = solar_1_1[year_index]; solar11 = solar_1_1[year_index];
@@ -129,31 +114,22 @@ void LUNAR_SolarToLunar(struct Lunar_Date *lunar, uint16_t solar_year, uint8_t s
lunarY = year_index + solar_1_1[0]; lunarY = year_index + solar_1_1[0];
lunarM = 1; lunarM = 1;
offset += 1; offset += 1;
for (i = 0; i < 13; i++) for (i = 0; i < 13; i++) {
{ if (GetBitInt(days, 1, 12 - i) == 1) {
if (GetBitInt(days, 1, 12 - i) == 1)
{
dm = 30; dm = 30;
} } else {
else
{
dm = 29; dm = 29;
} }
if (offset > dm) if (offset > dm) {
{
lunarM += 1; lunarM += 1;
offset -= dm; offset -= dm;
} } else {
else
{
break; break;
} }
} }
lunar->IsLeap = 0; lunar->IsLeap = 0;
if (leap != 0 && lunarM > leap) if (leap != 0 && lunarM > leap) {
{ if (lunarM == leap + 1) {
if (lunarM == leap + 1)
{
lunar->IsLeap = 1; lunar->IsLeap = 1;
} }
lunarM -= 1; lunarM -= 1;
@@ -163,20 +139,11 @@ void LUNAR_SolarToLunar(struct Lunar_Date *lunar, uint16_t solar_year, uint8_t s
lunar->Year = lunarY; lunar->Year = lunarY;
} }
uint8_t LUNAR_GetZodiac(const struct Lunar_Date *lunar) uint8_t LUNAR_GetZodiac(const struct Lunar_Date* lunar) { return lunar->Year % 12; }
{
return lunar->Year % 12;
}
uint8_t LUNAR_GetStem(const struct Lunar_Date *lunar) uint8_t LUNAR_GetStem(const struct Lunar_Date* lunar) { return lunar->Year % 10; }
{
return lunar->Year % 10;
}
uint8_t LUNAR_GetBranch(const struct Lunar_Date *lunar) uint8_t LUNAR_GetBranch(const struct Lunar_Date* lunar) { return lunar->Year % 12; }
{
return lunar->Year % 12;
}
/********************************************************************************************************* /*********************************************************************************************************
** 以下为24节气计算相关程序 ** 以下为24节气计算相关程序
@@ -188,113 +155,78 @@ uint8_t LUNAR_GetBranch(const struct Lunar_Date *lunar)
有兴趣的朋友可按照上面给的原理添加其它年份的表格 有兴趣的朋友可按照上面给的原理添加其它年份的表格
不是很清楚的朋友可给我发EMAIL 不是很清楚的朋友可给我发EMAIL
*/ */
static const uint8_t YearMonthBit[160] = static const uint8_t YearMonthBit[160] = {
{ 0x4E, 0xA6, 0x99, // 2000
0x4E, 0xA6, 0x99, // 2000 0x9C, 0xA2, 0x98, // 2001
0x9C, 0xA2, 0x98, // 2001 0x80, 0x00, 0x18, // 2002
0x80, 0x00, 0x18, // 2002 0x00, 0x10, 0x24, // 2003
0x00, 0x10, 0x24, // 2003 0x4E, 0xA6, 0x99, // 2004
0x4E, 0xA6, 0x99, // 2004 0x9C, 0xA2, 0x98, // 2005
0x9C, 0xA2, 0x98, // 2005 0x80, 0x82, 0x18, // 2006
0x80, 0x82, 0x18, // 2006 0x00, 0x10, 0x24, // 2007
0x00, 0x10, 0x24, // 2007 0x4E, 0xA6, 0xD9, // 2008
0x4E, 0xA6, 0xD9, // 2008 0x9E, 0xA2, 0x98, // 2009
0x9E, 0xA2, 0x98, // 2009
0x80, 0x82, 0x18, // 2010 0x80, 0x82, 0x18, // 2010
0x00, 0x10, 0x04, // 2011 0x00, 0x10, 0x04, // 2011
0x4E, 0xE6, 0xD9, // 2012 0x4E, 0xE6, 0xD9, // 2012
0x9E, 0xA6, 0xA8, // 2013 0x9E, 0xA6, 0xA8, // 2013
0x80, 0x82, 0x18, // 2014 0x80, 0x82, 0x18, // 2014
0x00, 0x10, 0x00, // 2015 0x00, 0x10, 0x00, // 2015
0x0F, 0xE6, 0xD9, // 2016 0x0F, 0xE6, 0xD9, // 2016
0xBE, 0xA6, 0x98, // 2017 0xBE, 0xA6, 0x98, // 2017
0x88, 0x82, 0x18, // 2018 0x88, 0x82, 0x18, // 2018
0x80, 0x00, 0x00, // 2019 0x80, 0x00, 0x00, // 2019
0x0F, 0xEF, 0xD9, // 2020 0x0F, 0xEF, 0xD9, // 2020
0xBE, 0xA6, 0x99, // 2021 0xBE, 0xA6, 0x99, // 2021
0x8C, 0x82, 0x98, // 2022 0x8C, 0x82, 0x98, // 2022
0x80, 0x00, 0x00, // 2023 0x80, 0x00, 0x00, // 2023
0x0F, 0xEF, 0xDB, // 2024 0x0F, 0xEF, 0xDB, // 2024
0xBE, 0xA6, 0x99, // 2025 0xBE, 0xA6, 0x99, // 2025
0x9C, 0xA2, 0x98, // 2026 0x9C, 0xA2, 0x98, // 2026
0x80, 0x00, 0x18, // 2027 0x80, 0x00, 0x18, // 2027
0x0F, 0xEF, 0xDB, // 2028 0x0F, 0xEF, 0xDB, // 2028
0xBE, 0xA6, 0x99, // 2029 0xBE, 0xA6, 0x99, // 2029
0x9C, 0xA2, 0x98, // 2030 0x9C, 0xA2, 0x98, // 2030
0x80, 0x00, 0x18, // 2031 0x80, 0x00, 0x18, // 2031
0x0F, 0xEF, 0xDB, // 2032 0x0F, 0xEF, 0xDB, // 2032
0xBE, 0xA2, 0x99, // 2033 0xBE, 0xA2, 0x99, // 2033
0x8C, 0xA0, 0x98, // 2034 0x8C, 0xA0, 0x98, // 2034
0x80, 0x82, 0x18, // 2035 0x80, 0x82, 0x18, // 2035
0x0B, 0xEF, 0xDB, // 2036 0x0B, 0xEF, 0xDB, // 2036
0xBE, 0xA6, 0x99, // 2037 0xBE, 0xA6, 0x99, // 2037
0x8C, 0xA2, 0x98, // 2038 0x8C, 0xA2, 0x98, // 2038
0x80, 0x82, 0x18, // 2039 0x80, 0x82, 0x18, // 2039
0x0F, 0xEF, 0xDB, // 2040 0x0F, 0xEF, 0xDB, // 2040
0xBE, 0xE6, 0xD9, // 2041 0xBE, 0xE6, 0xD9, // 2041
0x9E, 0xA2, 0x98, // 2042 0x9E, 0xA2, 0x98, // 2042
0x80, 0x82, 0x18, // 2043 0x80, 0x82, 0x18, // 2043
0x0F, 0xEF, 0xFB, // 2044 0x0F, 0xEF, 0xFB, // 2044
0xBF, 0xE6, 0xD9, // 2045 0xBF, 0xE6, 0xD9, // 2045
0x9E, 0xA6, 0x98, // 2046 0x9E, 0xA6, 0x98, // 2046
0x80, 0x82, 0x18, // 2047 0x80, 0x82, 0x18, // 2047
0x0F, 0xFF, 0xFF, // 2048 0x0F, 0xFF, 0xFF, // 2048
0xFC, 0xEF, 0xD9, // 2049 0xFC, 0xEF, 0xD9, // 2049
0xBE, 0xA6, 0x18, // 2050 0xBE, 0xA6, 0x18, // 2050
}; };
static const uint8_t days[24] = static const uint8_t days[24] = {
{ 6, 20, 4, 19, 6, 21, // 一月到三月 的节气基本日期
6, 20, 4, 19, 6, 21, // 月到月 的节气基本日期 5, 20, 6, 21, 6, 21, // 月到月 的节气基本日期
5, 20, 6, 21, 6, 21, // 月到月 的节气基本日期 7, 23, 8, 23, 8, 23, // 月到月 的节气基本日期
7, 23, 8, 23, 8, 23, // 月到九月 的节气基本日期 8, 24, 8, 22, 7, 22, // 月到十二月的节气基本日期
8, 24, 8, 22, 7, 22, // 十月到十二月的节气基本日期
}; };
/*立春、雨水、惊蛰、春分、清明、谷雨、立夏、小满、芒种、夏至、小暑、大暑、立秋、处暑、白露、秋分、寒露、霜降、立冬、小雪、大雪、冬至、小寒、大寒 /*立春、雨水、惊蛰、春分、清明、谷雨、立夏、小满、芒种、夏至、小暑、大暑、立秋、处暑、白露、秋分、寒露、霜降、立冬、小雪、大雪、冬至、小寒、大寒
* *
*/ */
const char JieQiStr[24][7] = { const char JieQiStr[24][7] = {
"小寒", "小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至",
"大寒", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪", "冬至",
"立春",
"雨水",
"惊蛰",
"春分",
"清明",
"谷雨",
"立夏",
"小满",
"芒种",
"夏至",
"小暑",
"大暑",
"立秋",
"处暑",
"白露",
"秋分",
"寒露",
"霜降",
"立冬",
"小雪",
"大雪",
"冬至",
}; };
const uint8_t MonthDayMax[12] = { const uint8_t MonthDayMax[12] = {
31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31,
}; };
/********************************************************************************************************* /*********************************************************************************************************
@@ -314,24 +246,19 @@ const uint8_t MonthDayMax[12] = {
** 日 期: ** 日 期:
**------------------------------------------------------------------------------------------------------ **------------------------------------------------------------------------------------------------------
********************************************************************************************************/ ********************************************************************************************************/
uint8_t GetJieQi(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *JQdate) uint8_t GetJieQi(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t* JQdate) {
{
uint8_t bak1, value, JQ; uint8_t bak1, value, JQ;
if ((myear < 2000) || (myear > 2050)) if ((myear < 2000) || (myear > 2050)) return 0;
return 0; if ((mmonth == 0) || (mmonth > 12)) return 0;
if ((mmonth == 0) || (mmonth > 12)) JQ = (mmonth - 1) * 2; // 获得节气顺序标号(023
return 0; if (mday >= 15) JQ++; // 判断是否是上半月
JQ = (mmonth - 1) * 2; // 获得节气顺序标号(023
if (mday >= 15)
JQ++; // 判断是否是上半月
bak1 = YearMonthBit[(myear - 2000) * 3 + JQ / 8]; // 获得节气日期相对值所在字节 bak1 = YearMonthBit[(myear - 2000) * 3 + JQ / 8]; // 获得节气日期相对值所在字节
value = ((bak1 << (JQ % 8)) & 0x80); // 获得节气日期相对值状态 value = ((bak1 << (JQ % 8)) & 0x80); // 获得节气日期相对值状态
*JQdate = days[JQ]; *JQdate = days[JQ];
if (value != 0) if (value != 0) {
{
// 判断年份,以决定节气相对值1代表1,还是1。 // 判断年份,以决定节气相对值1代表1,还是1。
if ((JQ == 1 || JQ == 11 || JQ == 18 || JQ == 21) && myear < 2044) if ((JQ == 1 || JQ == 11 || JQ == 18 || JQ == 21) && myear < 2044)
(*JQdate)++; (*JQdate)++;
@@ -357,19 +284,16 @@ uint8_t GetJieQi(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *JQdate)
** 日 期: ** 日 期:
**------------------------------------------------------------------------------------------------------ **------------------------------------------------------------------------------------------------------
********************************************************************************************************/ ********************************************************************************************************/
uint8_t GetJieQiStr(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *day) uint8_t GetJieQiStr(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t* day) {
{
uint8_t JQdate, JQ, MaxDay; uint8_t JQdate, JQ, MaxDay;
if (GetJieQi(myear, mmonth, mday, &JQdate) == 0) if (GetJieQi(myear, mmonth, mday, &JQdate) == 0) return 0xFF;
return 0xFF;
JQ = (mmonth - 1) * 2; // 获得节气顺序标号(023 JQ = (mmonth - 1) * 2; // 获得节气顺序标号(023
if (mday >= 15) if (mday >= 15) JQ++; // 判断是否是上半月
JQ++; // 判断是否是上半月
if (mday == JQdate) // 今天正是一个节气日 if (mday == JQdate) // 今天正是一个节气日
{ {
*day = 0; *day = 0;
return JQ; return JQ;
@@ -377,30 +301,24 @@ uint8_t GetJieQiStr(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *day)
// 今天不是一个节气日 // 今天不是一个节气日
// StrCopy(str, (uint8_t *)"离小寒还有??天", 15); // StrCopy(str, (uint8_t *)"离小寒还有??天", 15);
if (mday < JQdate) // 如果今天日期小于本月的节气日期 if (mday < JQdate) // 如果今天日期小于本月的节气日期
{ {
mday = JQdate - mday; mday = JQdate - mday;
} } else // 如果今天日期大于本月的节气日期
else // 如果今天日期大于本月的节气日期
{ {
JQ++; JQ++;
if (mday < 15) if (mday < 15) {
{
GetJieQi(myear, mmonth, 15, &JQdate); GetJieQi(myear, mmonth, 15, &JQdate);
mday = JQdate - mday; mday = JQdate - mday;
} } else // 翻月
else // 翻月
{ {
MaxDay = MonthDayMax[mmonth - 1]; MaxDay = MonthDayMax[mmonth - 1];
if (mmonth == 2) // 润月问题 if (mmonth == 2) // 润月问题
{ {
if ((myear % 4 == 0) && ((myear % 100 != 0) || (myear % 400 == 0))) if ((myear % 4 == 0) && ((myear % 100 != 0) || (myear % 400 == 0))) MaxDay++;
MaxDay++;
} }
if (++mmonth == 13) if (++mmonth == 13) mmonth = 1;
mmonth = 1;
GetJieQi(myear, mmonth, 1, &JQdate); GetJieQi(myear, mmonth, 1, &JQdate);
mday = MaxDay - mday + JQdate; mday = MaxDay - mday + JQdate;
} }
@@ -409,14 +327,12 @@ uint8_t GetJieQiStr(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *day)
return JQ; return JQ;
} }
uint32_t SEC_PER_YR[2] = {31536000, 31622400}; // 闰年和非闰年的秒数 uint32_t SEC_PER_YR[2] = {31536000, 31622400}; // 闰年和非闰年的秒数
uint32_t SEC_PER_MT[2][12] = { uint32_t SEC_PER_MT[2][12] = {
{2678400, 2419200, 2678400, 2592000, 2678400, 2592000, {2678400, 2419200, 2678400, 2592000, 2678400, 2592000, 2678400, 2678400, 2592000, 2678400, 2592000, 2678400},
2678400, 2678400, 2592000, 2678400, 2592000, 2678400}, {2678400, 2505600, 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 // 一天多少秒 #define SECOND_OF_DAY 86400 // 一天多少秒
/** /**
* @Name : static int is_leap(int yr) * @Name : static int is_leap(int yr)
@@ -427,8 +343,7 @@ uint32_t SEC_PER_MT[2][12] = {
* @Out : 1是闰年 0非闰年 * @Out : 1是闰年 0非闰年
* @Author : Denis * @Author : Denis
*/ */
int is_leap(int yr) int is_leap(int yr) {
{
if (0 == (yr % 100)) if (0 == (yr % 100))
return (yr % 400 == 0) ? 1 : 0; return (yr % 400 == 0) ? 1 : 0;
else else
@@ -443,27 +358,22 @@ int is_leap(int yr)
* @Out : 星期几 * @Out : 星期几
* @Author : Denis * @Author : Denis
*/ */
unsigned char day_of_week_get(unsigned char month, unsigned char day, unsigned char day_of_week_get(unsigned char month, unsigned char day, unsigned short year) {
unsigned short year)
{
/* Month should be a number 0 to 11, Day should be a number 1 to 31 */ /* 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}; static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
year -= (uint8_t)(month < 3); year -= (uint8_t)(month < 3);
return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7; return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7;
} }
void transformTime(uint32_t unix_time, struct devtm *result) void transformTime(uint32_t unix_time, struct devtm* result) {
{
int leapyr = 0; int leapyr = 0;
uint32_t ltime = unix_time; uint32_t ltime = unix_time;
memset(result, 0, sizeof(struct devtm)); memset(result, 0, sizeof(struct devtm));
result->tm_year = EPOCH_YR; result->tm_year = EPOCH_YR;
while (1) while (1) {
{ if (ltime < SEC_PER_YR[is_leap(result->tm_year)]) {
if (ltime < SEC_PER_YR[is_leap(result->tm_year)])
{
break; break;
} }
ltime -= SEC_PER_YR[is_leap(result->tm_year)]; ltime -= SEC_PER_YR[is_leap(result->tm_year)];
@@ -472,10 +382,8 @@ void transformTime(uint32_t unix_time, struct devtm *result)
leapyr = is_leap(result->tm_year); leapyr = is_leap(result->tm_year);
while (1) while (1) {
{ if (ltime < SEC_PER_MT[leapyr][result->tm_mon]) break;
if (ltime < SEC_PER_MT[leapyr][result->tm_mon])
break;
ltime -= SEC_PER_MT[leapyr][result->tm_mon]; ltime -= SEC_PER_MT[leapyr][result->tm_mon];
++(result->tm_mon); ++(result->tm_mon);
} }
@@ -490,9 +398,7 @@ void transformTime(uint32_t unix_time, struct devtm *result)
result->tm_min = ltime / 60; result->tm_min = ltime / 60;
result->tm_sec = ltime % 60; result->tm_sec = ltime % 60;
result->tm_wday = result->tm_wday = day_of_week_get(result->tm_mon + 1, result->tm_mday, result->tm_year);
day_of_week_get(result->tm_mon + 1, result->tm_mday,
result->tm_year);
/* /*
* The number of years since YEAR0" * The number of years since YEAR0"
@@ -505,10 +411,8 @@ 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) uint8_t get_last_day(uint16_t year, uint8_t month) {
{ if (month % 12 == 1) {
if (month % 12 == 1)
{
return map[month % 12] + is_leap(year); return map[month % 12] + is_leap(year);
} }
return map[month % 12]; return map[month % 12];
@@ -517,32 +421,26 @@ uint8_t get_last_day(uint16_t year, uint8_t month)
/* /*
获取一个月第一天星期值 获取一个月第一天星期值
*/ */
uint8_t get_first_day_week(uint16_t year, uint8_t month) uint8_t get_first_day_week(uint16_t year, uint8_t month) { return day_of_week_get(month, 1, year); }
{
return day_of_week_get(month, 1, year);
}
// 时间结构体转时间戳 // 时间结构体转时间戳
uint32_t transformTimeStruct(struct devtm *result) uint32_t transformTimeStruct(struct devtm* result) {
{
uint32_t Cyear = 0; uint32_t Cyear = 0;
for (uint16_t i = 1970; i < result->tm_year; i++) for (uint16_t i = 1970; i < result->tm_year; i++) {
{ if (is_leap(i) == 1) Cyear++;
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; uint32_t CountDay =
for (uint8_t i = 0; i < result->tm_mon - 1; i++) 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); 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); 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) uint8_t thisMonthMaxDays(uint8_t year, uint8_t month) {
{
if (year % 4 == 0 && month == 2) if (year % 4 == 0 && month == 2)
return MonthDayMax[month - 1] + 1; return MonthDayMax[month - 1] + 1;
else else

View File

@@ -3,13 +3,12 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#define YEAR0 (1900) /* The first year */ #define YEAR0 (1900) /* The first year */
#define EPOCH_YR (1970) /* EPOCH = Jan 1 1970 00:00:00 */ #define EPOCH_YR (1970) /* EPOCH = Jan 1 1970 00:00:00 */
#define SEC_PER_DY (86400) // 一天的秒数 #define SEC_PER_DY (86400) // 一天的秒数
#define SEC_PER_HR (3600) // 一小时的秒数 #define SEC_PER_HR (3600) // 一小时的秒数
typedef struct devtm typedef struct devtm {
{
uint16_t tm_year; uint16_t tm_year;
uint8_t tm_mon; uint8_t tm_mon;
uint8_t tm_mday; uint8_t tm_mday;
@@ -19,8 +18,7 @@ typedef struct devtm
uint8_t tm_wday; uint8_t tm_wday;
} tm_t; } tm_t;
struct Lunar_Date struct Lunar_Date {
{
uint8_t IsLeap; uint8_t IsLeap;
uint8_t Date; uint8_t Date;
uint8_t Month; uint8_t Month;
@@ -36,15 +34,15 @@ extern const char Lunar_StemStrig[10][4];
extern const char Lunar_BranchStrig[12][4]; extern const char Lunar_BranchStrig[12][4];
extern const char JieQiStr[24][7]; 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); 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_GetZodiac(const struct Lunar_Date* lunar);
uint8_t LUNAR_GetStem(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 LUNAR_GetBranch(const struct Lunar_Date* lunar);
uint8_t GetJieQiStr(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t *day); 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); uint8_t GetJieQi(uint16_t myear, uint8_t mmonth, uint8_t mday, uint8_t* JQdate);
void transformTime(uint32_t unix_time, struct devtm *result); void transformTime(uint32_t unix_time, struct devtm* result);
uint32_t transformTimeStruct(struct devtm *result); uint32_t transformTimeStruct(struct devtm* result);
uint8_t get_first_day_week(uint16_t year, uint8_t month); uint8_t get_first_day_week(uint16_t year, uint8_t month);
uint8_t get_last_day(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); unsigned char day_of_week_get(unsigned char month, unsigned char day, unsigned short year);

View File

@@ -1,154 +1,135 @@
/* /*
U8g2_for_Adafruit_GFX.cpp U8g2_for_Adafruit_GFX.cpp
Add unicode support and U8g2 fonts to Adafruit GFX libraries. Add unicode support and U8g2 fonts to Adafruit GFX libraries.
U8g2 for Adafruit GFX Lib (https://github.com/olikraus/U8g2_for_Adafruit_GFX) U8g2 for Adafruit GFX Lib (https://github.com/olikraus/U8g2_for_Adafruit_GFX)
Copyright (c) 2018, olikraus@gmail.com Copyright (c) 2018, olikraus@gmail.com
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list * Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this * Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution. materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <stddef.h>
#include "u8g2_font.h" #include "u8g2_font.h"
static uint8_t u8g2_font_get_byte(const uint8_t *font, uint8_t offset) #include <stddef.h>
{
static uint8_t u8g2_font_get_byte(const uint8_t* font, uint8_t offset) {
font += offset; font += offset;
return u8x8_pgm_read( font ); 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) U8X8_NOINLINE;
static uint16_t u8g2_font_get_word(const uint8_t *font, uint8_t offset) static uint16_t u8g2_font_get_word(const uint8_t* font, uint8_t offset) {
{ uint16_t pos;
uint16_t pos; font += offset;
font += offset; pos = u8x8_pgm_read(font);
pos = u8x8_pgm_read( font ); font++;
font++; pos <<= 8;
pos <<= 8; pos += u8x8_pgm_read(font);
pos += u8x8_pgm_read( font); return pos;
return pos;
} }
/*========================================================================*/ /*========================================================================*/
/* new font format */ /* new font format */
void u8g2_read_font_info(u8g2_font_info_t *font_info, const uint8_t *font) void u8g2_read_font_info(u8g2_font_info_t* font_info, const uint8_t* font) {
{
/* offset 0 */ /* offset 0 */
font_info->glyph_cnt = u8g2_font_get_byte(font, 0); font_info->glyph_cnt = u8g2_font_get_byte(font, 0);
font_info->bbx_mode = u8g2_font_get_byte(font, 1); 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_0 = u8g2_font_get_byte(font, 2);
font_info->bits_per_1 = u8g2_font_get_byte(font, 3); font_info->bits_per_1 = u8g2_font_get_byte(font, 3);
/* offset 4 */ /* offset 4 */
font_info->bits_per_char_width = u8g2_font_get_byte(font, 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_height = u8g2_font_get_byte(font, 5);
font_info->bits_per_char_x = u8g2_font_get_byte(font, 6); 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_char_y = u8g2_font_get_byte(font, 7);
font_info->bits_per_delta_x = u8g2_font_get_byte(font, 8); font_info->bits_per_delta_x = u8g2_font_get_byte(font, 8);
/* offset 9 */ /* offset 9 */
font_info->max_char_width = u8g2_font_get_byte(font, 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->max_char_height = u8g2_font_get_byte(font, 10);
font_info->x_offset = u8g2_font_get_byte(font, 11); font_info->x_offset = u8g2_font_get_byte(font, 11);
font_info->y_offset = u8g2_font_get_byte(font, 12); font_info->y_offset = u8g2_font_get_byte(font, 12);
/* offset 13 */ /* offset 13 */
font_info->ascent_A = u8g2_font_get_byte(font, 13); font_info->ascent_A = u8g2_font_get_byte(font, 13);
font_info->descent_g = u8g2_font_get_byte(font, 14); font_info->descent_g = u8g2_font_get_byte(font, 14);
font_info->ascent_para = u8g2_font_get_byte(font, 15); font_info->ascent_para = u8g2_font_get_byte(font, 15);
font_info->descent_para = u8g2_font_get_byte(font, 16); font_info->descent_para = u8g2_font_get_byte(font, 16);
/* offset 17 */ /* offset 17 */
font_info->start_pos_upper_A = u8g2_font_get_word(font, 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); font_info->start_pos_lower_a = u8g2_font_get_word(font, 19);
/* offset 21 */ /* offset 21 */
font_info->start_pos_unicode = u8g2_font_get_word(font, 21); font_info->start_pos_unicode = u8g2_font_get_word(font, 21);
} }
uint8_t u8g2_GetFontBBXWidth(u8g2_font_t *u8g2) uint8_t u8g2_GetFontBBXWidth(u8g2_font_t* u8g2) { return u8g2->font_info.max_char_width; /* new font info structure */ }
{
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 */
} }
uint8_t u8g2_GetFontBBXHeight(u8g2_font_t *u8g2) int8_t u8g2_GetFontBBXOffX(u8g2_font_t* u8g2) { return u8g2->font_info.x_offset; /* new font info structure */ }
{
return u8g2->font_info.max_char_height; /* new font info structure */
}
int8_t u8g2_GetFontBBXOffX(u8g2_font_t *u8g2) int8_t u8g2_GetFontBBXOffY(u8g2_font_t* u8g2) { return u8g2->font_info.y_offset; /* new font info structure */ }
{
return u8g2->font_info.x_offset; /* new font info structure */
}
int8_t u8g2_GetFontBBXOffY(u8g2_font_t *u8g2) uint8_t u8g2_GetFontCapitalAHeight(u8g2_font_t* u8g2) { return u8g2->font_info.ascent_A; /* new font info structure */ }
{
return u8g2->font_info.y_offset; /* new font info structure */
}
uint8_t u8g2_GetFontCapitalAHeight(u8g2_font_t *u8g2) 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) {
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 val;
uint8_t bit_pos = f->decode_bit_pos; uint8_t bit_pos = f->decode_bit_pos;
uint8_t bit_pos_plus_cnt; uint8_t bit_pos_plus_cnt;
//val = *(f->decode_ptr); // val = *(f->decode_ptr);
val = u8x8_pgm_read( f->decode_ptr ); val = u8x8_pgm_read(f->decode_ptr);
val >>= bit_pos; val >>= bit_pos;
bit_pos_plus_cnt = bit_pos; bit_pos_plus_cnt = bit_pos;
bit_pos_plus_cnt += cnt; bit_pos_plus_cnt += cnt;
if ( bit_pos_plus_cnt >= 8 ) if (bit_pos_plus_cnt >= 8) {
{
uint8_t s = 8; uint8_t s = 8;
s -= bit_pos; s -= bit_pos;
f->decode_ptr++; f->decode_ptr++;
//val |= *(f->decode_ptr) << (8-bit_pos); // val |= *(f->decode_ptr) << (8-bit_pos);
val |= u8x8_pgm_read( f->decode_ptr ) << (s); val |= u8x8_pgm_read(f->decode_ptr) << (s);
//bit_pos -= 8; // bit_pos -= 8;
bit_pos_plus_cnt -= 8; bit_pos_plus_cnt -= 8;
} }
val &= (1U<<cnt)-1; val &= (1U << cnt) - 1;
//bit_pos += cnt; // bit_pos += cnt;
f->decode_bit_pos = bit_pos_plus_cnt; f->decode_bit_pos = bit_pos_plus_cnt;
return val; return val;
} }
/* /*
2 bit --> cnt = 2 2 bit --> cnt = 2
-2,-1,0. 1 -2,-1,0. 1
@@ -164,9 +145,8 @@ static uint8_t u8g2_font_decode_get_unsigned_bits(u8g2_font_decode_t *f, uint8_t
*/ */
/* optimized */ /* 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) U8X8_NOINLINE;
static int8_t u8g2_font_decode_get_signed_bits(u8g2_font_decode_t *f, uint8_t cnt) static int8_t u8g2_font_decode_get_signed_bits(u8g2_font_decode_t* f, uint8_t cnt) {
{
int8_t v, d; int8_t v, d;
v = (int8_t)u8g2_font_decode_get_unsigned_bits(f, cnt); v = (int8_t)u8g2_font_decode_get_unsigned_bits(f, cnt);
d = 1; d = 1;
@@ -174,15 +154,12 @@ static int8_t u8g2_font_decode_get_signed_bits(u8g2_font_decode_t *f, uint8_t cn
d <<= cnt; d <<= cnt;
v -= d; v -= d;
return v; return v;
//return (int8_t)u8g2_font_decode_get_unsigned_bits(f, cnt) - ((1<<cnt)>>1); // 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) U8X8_NOINLINE;
static int16_t u8g2_add_vector_y(int16_t dy, int8_t x, int8_t y, uint8_t dir) static int16_t u8g2_add_vector_y(int16_t dy, int8_t x, int8_t y, uint8_t dir) {
{ switch (dir) {
switch(dir)
{
case 0: case 0:
dy += y; dy += y;
break; break;
@@ -194,16 +171,14 @@ static int16_t u8g2_add_vector_y(int16_t dy, int8_t x, int8_t y, uint8_t dir)
break; break;
default: default:
dy -= x; dy -= x;
break; break;
} }
return dy; 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) U8X8_NOINLINE;
static int16_t u8g2_add_vector_x(int16_t dx, int8_t x, int8_t y, uint8_t dir) static int16_t u8g2_add_vector_x(int16_t dx, int8_t x, int8_t y, uint8_t dir) {
{ switch (dir) {
switch(dir)
{
case 0: case 0:
dx += x; dx += x;
break; break;
@@ -215,7 +190,7 @@ static int16_t u8g2_add_vector_x(int16_t dx, int8_t x, int8_t y, uint8_t dir)
break; break;
default: default:
dx += y; dx += y;
break; break;
} }
return dx; return dx;
} }
@@ -238,42 +213,38 @@ static int16_t u8g2_add_vector_x(int16_t dx, int8_t x, int8_t y, uint8_t dir)
u8g2_font_decode_glyph() u8g2_font_decode_glyph()
*/ */
/* optimized */ /* optimized */
static void u8g2_font_decode_len(u8g2_font_t *u8g2, uint8_t len, uint8_t is_foreground) 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 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 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 */
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 */
/* current is either equal to cnt or equal to rem */
/* local coordinates of the glyph */ /* local coordinates of the glyph */
uint8_t lx,ly; uint8_t lx, ly;
/* target position on the screen */ /* target position on the screen */
int16_t x, y; int16_t x, y;
u8g2_font_decode_t *decode = &(u8g2->font_decode); u8g2_font_decode_t* decode = &(u8g2->font_decode);
cnt = len; cnt = len;
/* get the local position */ /* get the local position */
lx = decode->x; lx = decode->x;
ly = decode->y; ly = decode->y;
for(;;) for (;;) {
{
/* calculate the number of pixel to the right edge of the glyph */ /* calculate the number of pixel to the right edge of the glyph */
rem = decode->glyph_width; rem = decode->glyph_width;
rem -= lx; rem -= lx;
/* calculate how many pixel to draw. This is either to the right edge */ /* calculate how many pixel to draw. This is either to the right edge */
/* or lesser, if not enough pixel are left */ /* or lesser, if not enough pixel are left */
current = rem; current = rem;
if ( cnt < rem ) if (cnt < rem) current = cnt;
current = cnt;
/* now draw the line, but apply the rotation around the glyph target position */ /* now draw the line, but apply the rotation around the glyph target position */
//u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground); // u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground);
/* get target position */ /* get target position */
x = decode->target_x; x = decode->target_x;
@@ -282,51 +253,43 @@ static void u8g2_font_decode_len(u8g2_font_t *u8g2, uint8_t len, uint8_t is_fore
/* apply rotation */ /* apply rotation */
x = u8g2_add_vector_x(x, lx, ly, decode->dir); x = u8g2_add_vector_x(x, lx, ly, decode->dir);
y = u8g2_add_vector_y(y, lx, ly, decode->dir); y = u8g2_add_vector_y(y, lx, ly, decode->dir);
/* draw foreground and background (if required) */ /* draw foreground and background (if required) */
if ( current > 0 ) /* avoid drawing zero length lines, issue #4 */ if (current > 0) /* avoid drawing zero length lines, issue #4 */
{ {
if ( is_foreground ) if (is_foreground) {
{
u8g2->draw_hv_line(u8g2, x, y, current, decode->dir, decode->fg_color); u8g2->draw_hv_line(u8g2, x, y, current, decode->dir, decode->fg_color);
} } else if (decode->is_transparent == 0) {
else if ( decode->is_transparent == 0 )
{
u8g2->draw_hv_line(u8g2, x, y, current, decode->dir, decode->bg_color); u8g2->draw_hv_line(u8g2, x, y, current, decode->dir, decode->bg_color);
} }
} }
/* check, whether the end of the run length code has been reached */ /* check, whether the end of the run length code has been reached */
if ( cnt < rem ) if (cnt < rem) break;
break;
cnt -= rem; cnt -= rem;
lx = 0; lx = 0;
ly++; ly++;
} }
lx += cnt; lx += cnt;
decode->x = lx; decode->x = lx;
decode->y = ly; decode->y = ly;
} }
static void u8g2_font_setup_decode(u8g2_font_t *u8g2, const uint8_t *glyph_data) static void u8g2_font_setup_decode(u8g2_font_t* u8g2, const uint8_t* glyph_data) {
{ u8g2_font_decode_t* decode = &(u8g2->font_decode);
u8g2_font_decode_t *decode = &(u8g2->font_decode);
decode->decode_ptr = glyph_data; decode->decode_ptr = glyph_data;
decode->decode_bit_pos = 0; decode->decode_bit_pos = 0;
/* 8 Nov 2015, this is already done in the glyph data search procedure */ /* 8 Nov 2015, this is already done in the glyph data search procedure */
/* /*
decode->decode_ptr += 1; decode->decode_ptr += 1;
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);
}
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: Description:
@@ -342,48 +305,40 @@ static void u8g2_font_setup_decode(u8g2_font_t *u8g2, const uint8_t *glyph_data)
u8g2_font_decode_len() u8g2_font_decode_len()
*/ */
/* optimized */ /* optimized */
static int8_t u8g2_font_decode_glyph(u8g2_font_t *u8g2, const uint8_t *glyph_data) static int8_t u8g2_font_decode_glyph(u8g2_font_t* u8g2, const uint8_t* glyph_data) {
{
uint8_t a, b; uint8_t a, b;
int8_t x, y; int8_t x, y;
int8_t d; int8_t d;
int8_t h; int8_t h;
u8g2_font_decode_t *decode = &(u8g2->font_decode); u8g2_font_decode_t* decode = &(u8g2->font_decode);
u8g2_font_setup_decode(u8g2, glyph_data); u8g2_font_setup_decode(u8g2, glyph_data);
h = u8g2->font_decode.glyph_height; h = u8g2->font_decode.glyph_height;
x = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_x); 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); 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); d = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_delta_x);
if (decode->glyph_width > 0) {
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);
decode->target_x = u8g2_add_vector_x(decode->target_x, x, -(h+y), decode->dir); // u8g2_add_vector(&(decode->target_x), &(decode->target_y), 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 */ /* reset local x/y position */
decode->x = 0; decode->x = 0;
decode->y = 0; decode->y = 0;
/* decode glyph */ /* decode glyph */
for(;;) for (;;) {
{
a = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_0); 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); b = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_1);
do do {
{
u8g2_font_decode_len(u8g2, a, 0); u8g2_font_decode_len(u8g2, a, 0);
u8g2_font_decode_len(u8g2, b, 1); u8g2_font_decode_len(u8g2, b, 1);
} while( u8g2_font_decode_get_unsigned_bits(decode, 1) != 0 ); } while (u8g2_font_decode_get_unsigned_bits(decode, 1) != 0);
if ( decode->y >= h ) if (decode->y >= h) break;
break;
} }
} }
return d; return d;
} }
@@ -396,140 +351,107 @@ static int8_t u8g2_font_decode_glyph(u8g2_font_t *u8g2, const uint8_t *glyph_dat
Return: Return:
Address of the glyph data or NULL, if the encoding is not avialable in the font. 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* u8g2_font_get_glyph_data(u8g2_font_t* u8g2, uint16_t encoding) {
{ const uint8_t* font = u8g2->font;
const uint8_t *font = u8g2->font;
font += 23; font += 23;
if (encoding <= 255) {
if ( encoding <= 255 ) if (encoding >= 'a') {
{
if ( encoding >= 'a' )
{
font += u8g2->font_info.start_pos_lower_a; font += u8g2->font_info.start_pos_lower_a;
} } else if (encoding >= 'A') {
else if ( encoding >= 'A' )
{
font += u8g2->font_info.start_pos_upper_A; font += u8g2->font_info.start_pos_upper_A;
} }
for(;;) for (;;) {
{ if (u8x8_pgm_read(font + 1) == 0) break;
if ( u8x8_pgm_read( font + 1 ) == 0 ) if (u8x8_pgm_read(font) == encoding) {
break; return font + 2; /* skip encoding and glyph size */
if ( u8x8_pgm_read( font ) == encoding )
{
return font+2; /* skip encoding and glyph size */
} }
font += u8x8_pgm_read( font + 1 ); font += u8x8_pgm_read(font + 1);
} }
} } else {
else
{
uint16_t e; uint16_t e;
const uint8_t *unicode_lookup_table; const uint8_t* unicode_lookup_table;
/* support for the new unicode lookup table */ /* support for the new unicode lookup table */
font += u8g2->font_info.start_pos_unicode; font += u8g2->font_info.start_pos_unicode;
unicode_lookup_table = font; unicode_lookup_table = font;
/* u8g2 issue 596: search for the glyph start in the unicode lookup table */ /* u8g2 issue 596: search for the glyph start in the unicode lookup table */
do do {
{
font += u8g2_font_get_word(unicode_lookup_table, 0); font += u8g2_font_get_word(unicode_lookup_table, 0);
e = u8g2_font_get_word(unicode_lookup_table, 2); e = u8g2_font_get_word(unicode_lookup_table, 2);
unicode_lookup_table+=4; unicode_lookup_table += 4;
} while( e < encoding ); } while (e < encoding);
/* variable "font" is now updated according to the lookup table */ /* variable "font" is now updated according to the lookup table */
for(;;) for (;;) {
{ e = u8x8_pgm_read(font);
e = u8x8_pgm_read( font );
e <<= 8; e <<= 8;
e |= u8x8_pgm_read( font + 1 ); e |= u8x8_pgm_read(font + 1);
if ( e == 0 ) if (e == 0) break;
break; if (e == encoding) {
if ( e == encoding ) return font + 3; /* skip encoding and glyph size */
{
return font+3; /* skip encoding and glyph size */
} }
font += u8x8_pgm_read( font + 2 ); font += u8x8_pgm_read(font + 2);
} }
} }
return NULL; return NULL;
} }
static int16_t u8g2_font_draw_glyph(u8g2_font_t *u8g2, int16_t x, int16_t y, uint16_t encoding) static int16_t u8g2_font_draw_glyph(u8g2_font_t* u8g2, int16_t x, int16_t y, uint16_t encoding) {
{
int16_t dx = 0; int16_t dx = 0;
u8g2->font_decode.target_x = x; u8g2->font_decode.target_x = x;
u8g2->font_decode.target_y = y; u8g2->font_decode.target_y = y;
//u8g2->font_decode.is_transparent = is_transparent; this is already set // u8g2->font_decode.is_transparent = is_transparent; this is already set
//u8g2->font_decode.dir = dir; // u8g2->font_decode.dir = dir;
const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, encoding); const uint8_t* glyph_data = u8g2_font_get_glyph_data(u8g2, encoding);
if ( glyph_data != NULL ) if (glyph_data != NULL) {
{
dx = u8g2_font_decode_glyph(u8g2, glyph_data); dx = u8g2_font_decode_glyph(u8g2, glyph_data);
} }
return dx; return dx;
} }
//======================================================== //========================================================
uint8_t u8g2_IsGlyph(u8g2_font_t *u8g2, uint16_t requested_encoding) uint8_t u8g2_IsGlyph(u8g2_font_t* u8g2, uint16_t requested_encoding) {
{
/* updated to new code */ /* updated to new code */
if ( u8g2_font_get_glyph_data(u8g2, requested_encoding) != NULL ) if (u8g2_font_get_glyph_data(u8g2, requested_encoding) != NULL) return 1;
return 1;
return 0; return 0;
} }
/* side effect: updates u8g2->font_decode and u8g2->glyph_x_offset */ /* 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 */ /* 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) 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);
const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, requested_encoding); if (glyph_data == NULL) return 0;
if ( glyph_data == NULL )
return 0;
u8g2_font_setup_decode(u8g2, glyph_data); 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->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); 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 */ /* 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); 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) {
void u8g2_SetFontMode(u8g2_font_t *u8g2, uint8_t is_transparent) u8g2->font_decode.is_transparent = is_transparent; // new font procedures
{
u8g2->font_decode.is_transparent = is_transparent; // new font procedures
} }
void u8g2_SetFontDirection(u8g2_font_t *u8g2, uint8_t dir) void u8g2_SetFontDirection(u8g2_font_t* u8g2, uint8_t dir) { u8g2->font_decode.dir = dir; }
{
u8g2->font_decode.dir = dir;
}
int16_t u8g2_DrawGlyph(u8g2_font_t* u8g2, int16_t x, int16_t y, uint16_t encoding) {
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); 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 u8g2_DrawStr(u8g2_font_t* u8g2, int16_t x, int16_t y, const char* s) {
{
int16_t sum, delta; int16_t sum, delta;
sum = 0; sum = 0;
while( *s != '\0' ) while (*s != '\0') {
{
delta = u8g2_DrawGlyph(u8g2, x, y, *s); delta = u8g2_DrawGlyph(u8g2, x, y, *s);
switch(u8g2->font_decode.dir) switch (u8g2->font_decode.dir) {
{
case 0: case 0:
x += delta; x += delta;
break; break;
@@ -543,31 +465,21 @@ int16_t u8g2_DrawStr(u8g2_font_t *u8g2, int16_t x, int16_t y, const char *s)
y -= delta; y -= delta;
break; break;
} }
sum += delta; sum += delta;
s++; s++;
} }
return sum; return sum;
} }
void u8g2_SetFont(u8g2_font_t* u8g2, const uint8_t* font) {
if (u8g2->font != font) {
void u8g2_SetFont(u8g2_font_t *u8g2, const uint8_t *font)
{
if ( u8g2->font != font )
{
u8g2->font = font; u8g2->font = font;
u8g2->font_decode.is_transparent = 0; u8g2->font_decode.is_transparent = 0;
u8g2_read_font_info(&(u8g2->font_info), font); u8g2_read_font_info(&(u8g2->font_info), font);
} }
} }
void u8g2_SetForegroundColor(u8g2_font_t *u8g2, uint16_t fg) void u8g2_SetForegroundColor(u8g2_font_t* u8g2, uint16_t fg) { u8g2->font_decode.fg_color = fg; }
{
u8g2->font_decode.fg_color = fg;
}
void u8g2_SetBackgroundColor(u8g2_font_t *u8g2, uint16_t bg) void u8g2_SetBackgroundColor(u8g2_font_t* u8g2, uint16_t bg) { u8g2->font_decode.bg_color = bg; }
{
u8g2->font_decode.bg_color = bg;
}

View File

@@ -1,37 +1,36 @@
/* /*
U8g2_for_Adafruit_GFX.h U8g2_for_Adafruit_GFX.h
Add unicode support and U8g2 fonts to Adafruit GFX libraries. Add unicode support and U8g2 fonts to Adafruit GFX libraries.
U8g2 for Adafruit GFX Lib (https://github.com/olikraus/U8g2_for_Adafruit_GFX) U8g2 for Adafruit GFX Lib (https://github.com/olikraus/U8g2_for_Adafruit_GFX)
Copyright (c) 2018, olikraus@gmail.com Copyright (c) 2018, olikraus@gmail.com
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list * Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this * Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution. materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef __U8G2_H #ifndef __U8G2_H
@@ -40,45 +39,44 @@
#include <stdint.h> #include <stdint.h>
#ifdef __GNUC__ #ifdef __GNUC__
# define U8X8_NOINLINE __attribute__((noinline)) #define U8X8_NOINLINE __attribute__((noinline))
# define U8X8_SECTION(name) __attribute__ ((section (name))) #define U8X8_SECTION(name) __attribute__((section(name)))
# define U8X8_UNUSED __attribute__((unused)) #define U8X8_UNUSED __attribute__((unused))
#else #else
# define U8X8_SECTION(name) #define U8X8_SECTION(name)
# define U8X8_NOINLINE #define U8X8_NOINLINE
# define U8X8_UNUSED #define U8X8_UNUSED
#endif #endif
#if defined(__GNUC__) && defined(__AVR__) #if defined(__GNUC__) && defined(__AVR__)
# define U8X8_FONT_SECTION(name) U8X8_SECTION(".progmem." name) #define U8X8_FONT_SECTION(name) U8X8_SECTION(".progmem." name)
# define u8x8_pgm_read(adr) pgm_read_byte_near(adr) #define u8x8_pgm_read(adr) pgm_read_byte_near(adr)
# define U8X8_PROGMEM PROGMEM #define U8X8_PROGMEM PROGMEM
#endif #endif
#ifndef U8X8_FONT_SECTION #ifndef U8X8_FONT_SECTION
# define U8X8_FONT_SECTION(name) #define U8X8_FONT_SECTION(name)
#endif #endif
#ifndef u8x8_pgm_read #ifndef u8x8_pgm_read
# define u8x8_pgm_read(adr) (*(const uint8_t *)(adr)) #define u8x8_pgm_read(adr) (*(const uint8_t*)(adr))
#endif #endif
#ifndef U8X8_PROGMEM #ifndef U8X8_PROGMEM
# define U8X8_PROGMEM #define U8X8_PROGMEM
#endif #endif
#define U8G2_FONT_SECTION(name) U8X8_FONT_SECTION(name) #define U8G2_FONT_SECTION(name) U8X8_FONT_SECTION(name)
/* the macro U8G2_USE_LARGE_FONTS enables large fonts (>32K) */ /* the macro U8G2_USE_LARGE_FONTS enables large fonts (>32K) */
/* it can be enabled for those uC supporting larger arrays */ /* it can be enabled for those uC supporting larger arrays */
#if defined(unix) || defined(__arm__) || defined(__arc__) || defined(ESP8266) || defined(ESP_PLATFORM) #if defined(unix) || defined(__arm__) || defined(__arc__) || defined(ESP8266) || defined(ESP_PLATFORM)
#ifndef U8G2_USE_LARGE_FONTS #ifndef U8G2_USE_LARGE_FONTS
#define U8G2_USE_LARGE_FONTS #define U8G2_USE_LARGE_FONTS
#endif #endif
#endif #endif
typedef struct _u8g2_font_info_t typedef struct _u8g2_font_info_t {
{
/* offset 0 */ /* offset 0 */
uint8_t glyph_cnt; uint8_t glyph_cnt;
uint8_t bbx_mode; uint8_t bbx_mode;
@@ -87,7 +85,7 @@ typedef struct _u8g2_font_info_t
/* offset 4 */ /* offset 4 */
uint8_t bits_per_char_width; uint8_t bits_per_char_width;
uint8_t bits_per_char_height; uint8_t bits_per_char_height;
uint8_t bits_per_char_x; uint8_t bits_per_char_x;
uint8_t bits_per_char_y; uint8_t bits_per_char_y;
uint8_t bits_per_delta_x; uint8_t bits_per_delta_x;
@@ -99,59 +97,56 @@ typedef struct _u8g2_font_info_t
int8_t y_offset; int8_t y_offset;
/* offset 13 */ /* offset 13 */
int8_t ascent_A; int8_t ascent_A;
int8_t descent_g; /* usually a negative value */ int8_t descent_g; /* usually a negative value */
int8_t ascent_para; int8_t ascent_para;
int8_t descent_para; int8_t descent_para;
/* offset 17 */ /* offset 17 */
uint16_t start_pos_upper_A; uint16_t start_pos_upper_A;
uint16_t start_pos_lower_a; uint16_t start_pos_lower_a;
/* offset 21 */ /* offset 21 */
uint16_t start_pos_unicode; uint16_t start_pos_unicode;
} u8g2_font_info_t; } u8g2_font_info_t;
typedef struct _u8g2_font_decode_t typedef struct _u8g2_font_decode_t {
{ const uint8_t* decode_ptr; /* pointer to the compressed data */
const uint8_t *decode_ptr; /* pointer to the compressed data */
int16_t target_x; int16_t target_x;
int16_t target_y; int16_t target_y;
uint16_t fg_color; uint16_t fg_color;
uint16_t bg_color; uint16_t bg_color;
int8_t x; /* local coordinates, (0,0) is upper left */ int8_t x; /* local coordinates, (0,0) is upper left */
int8_t y; int8_t y;
int8_t glyph_width; int8_t glyph_width;
int8_t glyph_height; int8_t glyph_height;
uint8_t decode_bit_pos; /* bitpos inside a byte of the compressed data */ uint8_t decode_bit_pos; /* bitpos inside a byte of the compressed data */
uint8_t is_transparent; uint8_t is_transparent;
uint8_t dir; /* direction */ uint8_t dir; /* direction */
} u8g2_font_decode_t; } u8g2_font_decode_t;
typedef struct _u8g2_font_t typedef struct _u8g2_font_t {
{ const uint8_t* font; /* current font for all text procedures */
const uint8_t *font; /* current font for all text procedures */
u8g2_font_decode_t font_decode; /* new font decode structure */ u8g2_font_decode_t font_decode; /* new font decode structure */
u8g2_font_info_t font_info; /* new font info structure */ u8g2_font_info_t font_info; /* new font info structure */
int8_t glyph_x_offset; /* set by u8g2_GetGlyphWidth as a side effect */ int8_t glyph_x_offset; /* set by u8g2_GetGlyphWidth as a side effect */
void (*draw_hv_line)(struct _u8g2_font_t *u8g2, int16_t x, int16_t y, void (*draw_hv_line)(struct _u8g2_font_t* u8g2, int16_t x, int16_t y, int16_t len, uint8_t dir, uint16_t color);
int16_t len, uint8_t dir, uint16_t color);
} u8g2_font_t; } u8g2_font_t;
uint8_t u8g2_IsGlyph(u8g2_font_t *u8g2, uint16_t requested_encoding); uint8_t u8g2_IsGlyph(u8g2_font_t* u8g2, uint16_t requested_encoding);
int8_t u8g2_GetGlyphWidth(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_SetFontMode(u8g2_font_t* u8g2, uint8_t is_transparent);
void u8g2_SetFontDirection(u8g2_font_t *u8g2, uint8_t dir); 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_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); 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_SetFont(u8g2_font_t* u8g2, const uint8_t* font);
void u8g2_SetForegroundColor(u8g2_font_t *u8g2, uint16_t fg); void u8g2_SetForegroundColor(u8g2_font_t* u8g2, uint16_t fg);
void u8g2_SetBackgroundColor(u8g2_font_t *u8g2, uint16_t bg); void u8g2_SetBackgroundColor(u8g2_font_t* u8g2, uint16_t bg);
#endif #endif

View File

@@ -1,53 +1,54 @@
// GUI emulator for Windows // GUI emulator for Windows
// This code is a simple Windows GUI application that emulates the display of an e-paper device. // This code is a simple Windows GUI application that emulates the display of an e-paper device.
#include <windows.h>
#include <stdint.h> #include <stdint.h>
#include <time.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <wchar.h> #include <wchar.h>
#include <windows.h>
#include "GUI.h" #include "GUI.h"
#define BITMAP_WIDTH 400 #define BITMAP_WIDTH 400
#define BITMAP_HEIGHT 300 #define BITMAP_HEIGHT 300
#define WINDOW_WIDTH 450 #define WINDOW_WIDTH 450
#define WINDOW_HEIGHT 380 #define WINDOW_HEIGHT 380
// Global variables // Global variables
HINSTANCE g_hInstance; HINSTANCE g_hInstance;
HWND g_hwnd; HWND g_hwnd;
HDC g_paintHDC = NULL; HDC g_paintHDC = NULL;
display_mode_t g_display_mode = MODE_CALENDAR; // Default to calendar mode display_mode_t g_display_mode = MODE_CALENDAR; // Default to calendar mode
BOOL g_bwr_mode = TRUE; // Default to BWR mode BOOL g_bwr_mode = TRUE; // Default to BWR mode
uint8_t g_week_start = 0; // Default week start (0=Sunday, 1=Monday, etc.) uint8_t g_week_start = 0; // Default week start (0=Sunday, 1=Monday, etc.)
time_t g_display_time; time_t g_display_time;
struct tm g_tm_time; struct tm g_tm_time;
// Implementation of the buffer_callback function // Implementation of the buffer_callback function
void DrawBitmap(void *user_data, uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h) { void DrawBitmap(void* user_data, uint8_t* black, uint8_t* color, uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
HDC hdc = g_paintHDC; HDC hdc = g_paintHDC;
if (!hdc) return; if (!hdc) return;
RECT clientRect; RECT clientRect;
int scale = 1; int scale = 1;
// Get client area for positioning // Get client area for positioning
GetClientRect(g_hwnd, &clientRect); GetClientRect(g_hwnd, &clientRect);
// Calculate position to center the entire bitmap in the window // Calculate position to center the entire bitmap in the window
int drawX = (clientRect.right - BITMAP_WIDTH * scale) / 2; int drawX = (clientRect.right - BITMAP_WIDTH * scale) / 2;
int drawY = (clientRect.bottom - BITMAP_HEIGHT * scale) / 2; int drawY = (clientRect.bottom - BITMAP_HEIGHT * scale) / 2;
// Use 4-bit approach (16 colors, but we only use 3) // Use 4-bit approach (16 colors, but we only use 3)
BITMAPINFO bmi; BITMAPINFO bmi;
ZeroMemory(&bmi, sizeof(BITMAPINFO)); ZeroMemory(&bmi, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = w; bmi.bmiHeader.biWidth = w;
bmi.bmiHeader.biHeight = -h; // Negative for top-down bitmap bmi.bmiHeader.biHeight = -h; // Negative for top-down bitmap
bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 4; // 4 bits per pixel bmi.bmiHeader.biBitCount = 4; // 4 bits per pixel
bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biClrUsed = 16; // 16 colors (2^4) bmi.bmiHeader.biClrUsed = 16; // 16 colors (2^4)
// Initialize all 16 palette entries to white first // Initialize all 16 palette entries to white first
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
bmi.bmiColors[i].rgbBlue = 255; bmi.bmiColors[i].rgbBlue = 255;
@@ -55,23 +56,23 @@ void DrawBitmap(void *user_data, uint8_t *black, uint8_t *color, uint16_t x, uin
bmi.bmiColors[i].rgbRed = 255; bmi.bmiColors[i].rgbRed = 255;
bmi.bmiColors[i].rgbReserved = 0; bmi.bmiColors[i].rgbReserved = 0;
} }
// Set specific colors for our pixel values // Set specific colors for our pixel values
// Color 0: White // Color 0: White
bmi.bmiColors[0].rgbBlue = 255; bmi.bmiColors[0].rgbBlue = 255;
bmi.bmiColors[0].rgbGreen = 255; bmi.bmiColors[0].rgbGreen = 255;
bmi.bmiColors[0].rgbRed = 255; bmi.bmiColors[0].rgbRed = 255;
// Color 1: Black // Color 1: Black
bmi.bmiColors[1].rgbBlue = 0; bmi.bmiColors[1].rgbBlue = 0;
bmi.bmiColors[1].rgbGreen = 0; bmi.bmiColors[1].rgbGreen = 0;
bmi.bmiColors[1].rgbRed = 0; bmi.bmiColors[1].rgbRed = 0;
// Color 2: Red // Color 2: Red
bmi.bmiColors[2].rgbBlue = 0; bmi.bmiColors[2].rgbBlue = 0;
bmi.bmiColors[2].rgbGreen = 0; bmi.bmiColors[2].rgbGreen = 0;
bmi.bmiColors[2].rgbRed = 255; bmi.bmiColors[2].rgbRed = 255;
// Create 4-bit bitmap data // Create 4-bit bitmap data
// Each byte contains 2 pixels (4 bits each) // Each byte contains 2 pixels (4 bits each)
int pixelsPerByte = 2; int pixelsPerByte = 2;
@@ -79,31 +80,31 @@ void DrawBitmap(void *user_data, uint8_t *black, uint8_t *color, uint16_t x, uin
// Align to DWORD boundary (4 bytes) // Align to DWORD boundary (4 bytes)
bytesPerRow = ((bytesPerRow + 3) / 4) * 4; bytesPerRow = ((bytesPerRow + 3) / 4) * 4;
int totalSize = bytesPerRow * h; int totalSize = bytesPerRow * h;
uint8_t *bitmap4bit = (uint8_t*)malloc(totalSize); uint8_t* bitmap4bit = (uint8_t*)malloc(totalSize);
if (!bitmap4bit) { if (!bitmap4bit) {
return; return;
} }
memset(bitmap4bit, 0, totalSize); // Initialize to white (0) memset(bitmap4bit, 0, totalSize); // Initialize to white (0)
int ePaperBytesPerRow = (w + 7) / 8; int ePaperBytesPerRow = (w + 7) / 8;
for (int row = 0; row < h; row++) { for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) { for (int col = 0; col < w; col++) {
int bytePos = row * ePaperBytesPerRow + col / 8; int bytePos = row * ePaperBytesPerRow + col / 8;
int bitPos = 7 - (col % 8); int bitPos = 7 - (col % 8);
int blackBit = !((black[bytePos] >> bitPos) & 0x01); int blackBit = !((black[bytePos] >> bitPos) & 0x01);
int colorBit = color ? !((color[bytePos] >> bitPos) & 0x01) : 0; int colorBit = color ? !((color[bytePos] >> bitPos) & 0x01) : 0;
// Determine pixel value: 0=white, 1=black, 2=red // Determine pixel value: 0=white, 1=black, 2=red
uint8_t pixelValue = colorBit ? 2 : (blackBit ? 1 : 0); uint8_t pixelValue = colorBit ? 2 : (blackBit ? 1 : 0);
// Pack into 4-bit format // Pack into 4-bit format
// Each byte stores 2 pixels: [pixel0][pixel1] // Each byte stores 2 pixels: [pixel0][pixel1]
// High nibble = first pixel, low nibble = second pixel // High nibble = first pixel, low nibble = second pixel
int bitmap4bitBytePos = row * bytesPerRow + col / pixelsPerByte; int bitmap4bitBytePos = row * bytesPerRow + col / pixelsPerByte;
int isHighNibble = (col % pixelsPerByte) == 0; int isHighNibble = (col % pixelsPerByte) == 0;
if (isHighNibble) { if (isHighNibble) {
// Clear high nibble and set new value // Clear high nibble and set new value
bitmap4bit[bitmap4bitBytePos] &= 0x0F; bitmap4bit[bitmap4bitBytePos] &= 0x0F;
@@ -115,15 +116,11 @@ void DrawBitmap(void *user_data, uint8_t *black, uint8_t *color, uint16_t x, uin
} }
} }
} }
// Draw the bitmap // Draw the bitmap
StretchDIBits(hdc, StretchDIBits(hdc, drawX + x * scale, drawY + y * scale, w * scale, h * scale, 0, 0, w, h, bitmap4bit, &bmi,
drawX + x * scale, drawY + y * scale, DIB_RGB_COLORS, SRCCOPY);
w * scale, h * scale,
0, 0, w, h,
bitmap4bit, &bmi,
DIB_RGB_COLORS, SRCCOPY);
free(bitmap4bit); free(bitmap4bit);
} }
@@ -132,14 +129,14 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
switch (message) { switch (message) {
case WM_CREATE: case WM_CREATE:
// Initialize the display time // Initialize the display time
g_display_time = time(NULL) + 8*3600; g_display_time = time(NULL) + 8 * 3600;
// Set a timer to update the CLOCK periodically (every second) // Set a timer to update the CLOCK periodically (every second)
SetTimer(hwnd, 1, 1000, NULL); SetTimer(hwnd, 1, 1000, NULL);
return 0; return 0;
case WM_TIMER: case WM_TIMER:
if (g_display_mode == MODE_CLOCK) { if (g_display_mode == MODE_CLOCK) {
g_display_time = time(NULL) + 8*3600; g_display_time = time(NULL) + 8 * 3600;
if (g_display_time % 60 == 0) { if (g_display_time % 60 == 0) {
InvalidateRect(hwnd, NULL, FALSE); InvalidateRect(hwnd, NULL, FALSE);
} }
@@ -149,10 +146,10 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_PAINT: { case WM_PAINT: {
PAINTSTRUCT ps; PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps); HDC hdc = BeginPaint(hwnd, &ps);
// Set the global HDC for DrawBitmap to use // Set the global HDC for DrawBitmap to use
g_paintHDC = hdc; g_paintHDC = hdc;
// Get client rect for calculations // Get client rect for calculations
RECT clientRect; RECT clientRect;
GetClientRect(hwnd, &clientRect); GetClientRect(hwnd, &clientRect);
@@ -161,94 +158,87 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
HBRUSH bgBrush = CreateSolidBrush(RGB(240, 240, 240)); HBRUSH bgBrush = CreateSolidBrush(RGB(240, 240, 240));
FillRect(hdc, &clientRect, bgBrush); FillRect(hdc, &clientRect, bgBrush);
DeleteObject(bgBrush); DeleteObject(bgBrush);
// Calculate border position (same as bitmap position) // Calculate border position (same as bitmap position)
int scale = 1; int scale = 1;
int drawX = (clientRect.right - BITMAP_WIDTH * scale) / 2; int drawX = (clientRect.right - BITMAP_WIDTH * scale) / 2;
int drawY = (clientRect.bottom - BITMAP_HEIGHT * scale) / 2; int drawY = (clientRect.bottom - BITMAP_HEIGHT * scale) / 2;
// Draw border around the bitmap area // Draw border around the bitmap area
HPEN borderPen = CreatePen(PS_DOT, 1, RGB(0, 0, 255)); HPEN borderPen = CreatePen(PS_DOT, 1, RGB(0, 0, 255));
HPEN oldPen = SelectObject(hdc, borderPen); HPEN oldPen = SelectObject(hdc, borderPen);
HBRUSH oldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH)); // No fill HBRUSH oldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH)); // No fill
Rectangle(hdc, drawX - 1, drawY - 1, Rectangle(hdc, drawX - 1, drawY - 1, drawX + BITMAP_WIDTH * scale + 1, drawY + BITMAP_HEIGHT * scale + 1);
drawX + BITMAP_WIDTH * scale + 1,
drawY + BITMAP_HEIGHT * scale + 1);
SelectObject(hdc, oldPen); SelectObject(hdc, oldPen);
SelectObject(hdc, oldBrush); SelectObject(hdc, oldBrush);
DeleteObject(borderPen); DeleteObject(borderPen);
// Display current mode at the top of the bitmap // Display current mode at the top of the bitmap
const wchar_t* modeText = (g_display_mode == MODE_CLOCK) ? L"时钟模式" : L"日历模式"; const wchar_t* modeText = (g_display_mode == MODE_CLOCK) ? L"时钟模式" : L"日历模式";
int modeTextY = drawY - 20; // Above the bitmap int modeTextY = drawY - 20; // Above the bitmap
SetTextColor(hdc, RGB(50, 50, 50)); SetTextColor(hdc, RGB(50, 50, 50));
SetBkMode(hdc, TRANSPARENT); SetBkMode(hdc, TRANSPARENT);
// Create a font for mode text // Create a font for mode text
HFONT modeFont = CreateFont( HFONT modeFont = CreateFont(16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial");
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial"
);
HFONT oldFont = SelectObject(hdc, modeFont); HFONT oldFont = SelectObject(hdc, modeFont);
// Calculate text width for centering mode text // Calculate text width for centering mode text
SIZE modeTextSize; SIZE modeTextSize;
GetTextExtentPoint32W(hdc, modeText, wcslen(modeText), &modeTextSize); GetTextExtentPoint32W(hdc, modeText, wcslen(modeText), &modeTextSize);
int modeCenteredX = drawX + (BITMAP_WIDTH - modeTextSize.cx) / 2; int modeCenteredX = drawX + (BITMAP_WIDTH - modeTextSize.cx) / 2;
TextOutW(hdc, modeCenteredX, modeTextY, modeText, wcslen(modeText)); TextOutW(hdc, modeCenteredX, modeTextY, modeText, wcslen(modeText));
// Draw help text below the bitmap // Draw help text below the bitmap
const wchar_t helpText[] = L"空格 - 切换模式 | R - 切换颜色 | W - 星期起点 | 方向键 - 调整日期/月份"; const wchar_t helpText[] = L"空格 - 切换模式 | R - 切换颜色 | W - 星期起点 | 方向键 - 调整日期/月份";
int helpTextY = drawY + BITMAP_HEIGHT * scale + 5; int helpTextY = drawY + BITMAP_HEIGHT * scale + 5;
SetTextColor(hdc, RGB(80, 80, 80)); SetTextColor(hdc, RGB(80, 80, 80));
// Create a smaller font for help text // Create a smaller font for help text
HFONT helpFont = CreateFont( HFONT helpFont =
14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CreateFont(14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial");
DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial"
);
SelectObject(hdc, modeFont); SelectObject(hdc, modeFont);
DeleteObject(modeFont); DeleteObject(modeFont);
SelectObject(hdc, helpFont); SelectObject(hdc, helpFont);
// Calculate text width for centering help text // Calculate text width for centering help text
SIZE textSize; SIZE textSize;
GetTextExtentPoint32W(hdc, helpText, wcslen(helpText), &textSize); GetTextExtentPoint32W(hdc, helpText, wcslen(helpText), &textSize);
int centeredX = drawX + (BITMAP_WIDTH - textSize.cx) / 2; int centeredX = drawX + (BITMAP_WIDTH - textSize.cx) / 2;
TextOutW(hdc, centeredX, helpTextY, helpText, wcslen(helpText)); TextOutW(hdc, centeredX, helpTextY, helpText, wcslen(helpText));
SelectObject(hdc, oldFont); SelectObject(hdc, oldFont);
DeleteObject(helpFont); DeleteObject(helpFont);
// Use the stored timestamp // Use the stored timestamp
gui_data_t data = { gui_data_t data = {
.mode = g_display_mode, .mode = g_display_mode,
.color = g_bwr_mode ? 2 : 1, .color = g_bwr_mode ? 2 : 1,
.width = BITMAP_WIDTH, .width = BITMAP_WIDTH,
.height = BITMAP_HEIGHT, .height = BITMAP_HEIGHT,
.timestamp = g_display_time, .timestamp = g_display_time,
.week_start = g_week_start, .week_start = g_week_start,
.temperature = 25, .temperature = 25,
.voltage = 3.2f, .voltage = 3.2f,
.ssid = "NRF_EPD_84AC", .ssid = "NRF_EPD_84AC",
}; };
// Call DrawGUI to render the interface // Call DrawGUI to render the interface
DrawGUI(&data, DrawBitmap, NULL); DrawGUI(&data, DrawBitmap, NULL);
// Clear the global HDC // Clear the global HDC
g_paintHDC = NULL; g_paintHDC = NULL;
EndPaint(hwnd, &ps); EndPaint(hwnd, &ps);
return 0; return 0;
} }
case WM_KEYDOWN: case WM_KEYDOWN:
// Toggle display mode with spacebar // Toggle display mode with spacebar
if (wParam == VK_SPACE) { if (wParam == VK_SPACE) {
@@ -256,7 +246,7 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
g_display_mode = MODE_CALENDAR; g_display_mode = MODE_CALENDAR;
else else
g_display_mode = MODE_CLOCK; g_display_mode = MODE_CLOCK;
InvalidateRect(hwnd, NULL, TRUE); InvalidateRect(hwnd, NULL, TRUE);
} }
// Toggle BWR mode with R key // Toggle BWR mode with R key
@@ -267,14 +257,14 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
// Increase week start with W key // Increase week start with W key
else if (wParam == 'W') { else if (wParam == 'W') {
g_week_start++; g_week_start++;
if (g_week_start > 6) g_week_start = 0; // Wrap around if (g_week_start > 6) g_week_start = 0; // Wrap around
InvalidateRect(hwnd, NULL, TRUE); InvalidateRect(hwnd, NULL, TRUE);
} }
// Handle arrow keys for month/day adjustment // Handle arrow keys for month/day adjustment
else if (wParam == VK_UP || wParam == VK_DOWN || wParam == VK_LEFT || wParam == VK_RIGHT) { else if (wParam == VK_UP || wParam == VK_DOWN || wParam == VK_LEFT || wParam == VK_RIGHT) {
// Get the current time structure // Get the current time structure
g_tm_time = *localtime(&g_display_time); g_tm_time = *localtime(&g_display_time);
// Up/Down adjusts month // Up/Down adjusts month
if (wParam == VK_UP) { if (wParam == VK_UP) {
g_tm_time.tm_mon++; g_tm_time.tm_mon++;
@@ -282,8 +272,7 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
g_tm_time.tm_mon = 0; g_tm_time.tm_mon = 0;
g_tm_time.tm_year++; g_tm_time.tm_year++;
} }
} } else if (wParam == VK_DOWN) {
else if (wParam == VK_DOWN) {
g_tm_time.tm_mon--; g_tm_time.tm_mon--;
if (g_tm_time.tm_mon < 0) { if (g_tm_time.tm_mon < 0) {
g_tm_time.tm_mon = 11; g_tm_time.tm_mon = 11;
@@ -293,24 +282,23 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
// Left/Right adjusts day // Left/Right adjusts day
else if (wParam == VK_RIGHT) { else if (wParam == VK_RIGHT) {
g_tm_time.tm_mday++; g_tm_time.tm_mday++;
} } else if (wParam == VK_LEFT) {
else if (wParam == VK_LEFT) {
g_tm_time.tm_mday--; g_tm_time.tm_mday--;
} }
// Convert back to time_t // Convert back to time_t
g_display_time = mktime(&g_tm_time); g_display_time = mktime(&g_tm_time);
// Force redraw // Force redraw
InvalidateRect(hwnd, NULL, TRUE); InvalidateRect(hwnd, NULL, TRUE);
} }
return 0; return 0;
case WM_DESTROY: case WM_DESTROY:
KillTimer(hwnd, 1); KillTimer(hwnd, 1);
PostQuitMessage(0); PostQuitMessage(0);
return 0; return 0;
default: default:
return DefWindowProcW(hwnd, message, wParam, lParam); return DefWindowProcW(hwnd, message, wParam, lParam);
} }
@@ -319,46 +307,40 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
// Main entry point // Main entry point
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
g_hInstance = hInstance; g_hInstance = hInstance;
// Register window class // Register window class
WNDCLASSW wc = {0}; WNDCLASSW wc = {0};
wc.style = CS_HREDRAW | CS_VREDRAW; wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc; wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance; wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = L"Emurator"; wc.lpszClassName = L"Emurator";
if (!RegisterClassW(&wc)) { if (!RegisterClassW(&wc)) {
MessageBoxW(NULL, L"Window Registration Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK); MessageBoxW(NULL, L"Window Registration Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK);
return 0; return 0;
} }
// Create the window // Create the window
g_hwnd = CreateWindowW( g_hwnd = CreateWindowW(L"Emurator", L"模拟器", WS_POPUPWINDOW | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
L"Emurator", CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
L"模拟器",
WS_POPUPWINDOW | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT,
WINDOW_WIDTH, WINDOW_HEIGHT,
NULL, NULL, hInstance, NULL
);
if (!g_hwnd) { if (!g_hwnd) {
MessageBoxW(NULL, L"Window Creation Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK); MessageBoxW(NULL, L"Window Creation Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK);
return 0; return 0;
} }
// Show window // Show window
ShowWindow(g_hwnd, nCmdShow); ShowWindow(g_hwnd, nCmdShow);
UpdateWindow(g_hwnd); UpdateWindow(g_hwnd);
// Main message loop // Main message loop
MSG msg; MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) { while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
} }
return (int)msg.wParam; return (int)msg.wParam;
} }

291
main.c
View File

@@ -12,41 +12,42 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "nordic_common.h"
#include "nrf.h"
#include "ble.h" #include "ble.h"
#include "ble_hci.h"
#include "ble_srv_common.h"
#include "ble_advdata.h" #include "ble_advdata.h"
#include "ble_advertising.h" #include "ble_advertising.h"
#include "ble_conn_params.h" #include "ble_conn_params.h"
#include "ble_dfu.h" #include "ble_dfu.h"
#include "ble_hci.h"
#include "ble_srv_common.h"
#include "nordic_common.h"
#include "nrf.h"
#if defined(S112) #if defined(S112)
#include "nrf_sdh.h"
#include "nrf_sdh_soc.h"
#include "nrf_sdh_ble.h"
#include "nrf_ble_gatt.h" #include "nrf_ble_gatt.h"
#include "nrf_bootloader_info.h" #include "nrf_bootloader_info.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "nrf_sdh_soc.h"
#else #else
#include "fstorage.h" #include "fstorage.h"
#include "softdevice_handler.h" #include "softdevice_handler.h"
#endif #endif
#include "nrf_power.h" #include "EPD_service.h"
#include "app_error.h" #include "app_error.h"
#include "app_timer.h"
#include "app_scheduler.h" #include "app_scheduler.h"
#include "app_timer.h"
#include "main.h"
#include "nrf_drv_gpiote.h" #include "nrf_drv_gpiote.h"
#include "nrf_drv_wdt.h" #include "nrf_drv_wdt.h"
#include "nrf_pwr_mgmt.h"
#include "EPD_service.h"
#include "main.h"
#include "nrf_log.h" #include "nrf_log.h"
#include "nrf_log_ctrl.h" #include "nrf_log_ctrl.h"
#include "nrf_power.h"
#include "nrf_pwr_mgmt.h"
#if defined(S112) #if defined(S112)
#include "nrf_log_default_backends.h" #include "nrf_log_default_backends.h"
#endif #endif
// clang-format off
#define CENTRAL_LINK_COUNT 0 /**< Number of central links used by the application. When changing this number remember to adjust the RAM settings*/ #define CENTRAL_LINK_COUNT 0 /**< Number of central links used by the application. When changing this number remember to adjust the RAM settings*/
#define PERIPHERAL_LINK_COUNT 1 /**< Number of peripheral links used by the application. When changing this number remember to adjust the RAM settings*/ #define PERIPHERAL_LINK_COUNT 1 /**< Number of peripheral links used by the application. When changing this number remember to adjust the RAM settings*/
@@ -100,6 +101,7 @@ APP_TIMER_DEF(m_clock_timer_id);
static nrf_drv_wdt_channel_id m_wdt_channel_id; static nrf_drv_wdt_channel_id m_wdt_channel_id;
static uint32_t m_wdt_last_feed_time = 0; static uint32_t m_wdt_last_feed_time = 0;
static uint32_t m_resetreas; static uint32_t m_resetreas;
// clang-format on
/**@brief Callback function for asserts in the SoftDevice. /**@brief Callback function for asserts in the SoftDevice.
* *
@@ -112,28 +114,22 @@ static uint32_t m_resetreas;
* @param[in] line_num Line number of the failing ASSERT call. * @param[in] line_num Line number of the failing ASSERT call.
* @param[in] file_name File name of the failing ASSERT call. * @param[in] file_name File name of the failing ASSERT call.
*/ */
void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name) void assert_nrf_callback(uint16_t line_num, const uint8_t* p_file_name) {
{
app_error_handler(DEAD_BEEF, line_num, p_file_name); app_error_handler(DEAD_BEEF, line_num, p_file_name);
} }
// return current timestamp // return current timestamp
uint32_t timestamp(void) uint32_t timestamp(void) { return m_timestamp; }
{
return m_timestamp;
}
// set the timestamp // set the timestamp
void set_timestamp(uint32_t timestamp) void set_timestamp(uint32_t timestamp) {
{
app_timer_stop(m_clock_timer_id); app_timer_stop(m_clock_timer_id);
m_timestamp = timestamp; m_timestamp = timestamp;
app_timer_start(m_clock_timer_id, CLOCK_TIMER_INTERVAL, NULL); app_timer_start(m_clock_timer_id, CLOCK_TIMER_INTERVAL, NULL);
} }
// reload the wdt channel // reload the wdt channel
void app_feed_wdt(void) void app_feed_wdt(void) {
{
if (m_timestamp - m_wdt_last_feed_time >= 30) { if (m_timestamp - m_wdt_last_feed_time >= 30) {
NRF_LOG_DEBUG("Feed WDT\n"); NRF_LOG_DEBUG("Feed WDT\n");
nrf_drv_wdt_channel_feed(m_wdt_channel_id); nrf_drv_wdt_channel_feed(m_wdt_channel_id);
@@ -142,39 +138,32 @@ void app_feed_wdt(void)
} }
#if defined(S112) #if defined(S112)
static void buttonless_dfu_sdh_state_observer(nrf_sdh_state_evt_t state, void * p_context) static void buttonless_dfu_sdh_state_observer(nrf_sdh_state_evt_t state, void* p_context) {
{ if (state == NRF_SDH_EVT_STATE_DISABLED) {
if (state == NRF_SDH_EVT_STATE_DISABLED)
{
// Softdevice was disabled before going into reset. Inform bootloader to skip CRC on next boot. // Softdevice was disabled before going into reset. Inform bootloader to skip CRC on next boot.
nrf_power_gpregret2_set(BOOTLOADER_DFU_SKIP_CRC); nrf_power_gpregret2_set(BOOTLOADER_DFU_SKIP_CRC);
//Go to system off. // Go to system off.
nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF); nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
} }
} }
/* nrf_sdh state observer. */ /* nrf_sdh state observer. */
NRF_SDH_STATE_OBSERVER(m_buttonless_dfu_state_obs, 0) = NRF_SDH_STATE_OBSERVER(m_buttonless_dfu_state_obs, 0) = {
{
.handler = buttonless_dfu_sdh_state_observer, .handler = buttonless_dfu_sdh_state_observer,
}; };
static void advertising_config_get(ble_adv_modes_config_t * p_config) static void advertising_config_get(ble_adv_modes_config_t* p_config) {
{
memset(p_config, 0, sizeof(ble_adv_modes_config_t)); memset(p_config, 0, sizeof(ble_adv_modes_config_t));
p_config->ble_adv_fast_enabled = true; p_config->ble_adv_fast_enabled = true;
p_config->ble_adv_fast_interval = APP_ADV_INTERVAL; p_config->ble_adv_fast_interval = APP_ADV_INTERVAL;
p_config->ble_adv_fast_timeout = APP_ADV_TIMEOUT_IN_SECONDS * 100; p_config->ble_adv_fast_timeout = APP_ADV_TIMEOUT_IN_SECONDS * 100;
} }
static void ble_dfu_evt_handler(ble_dfu_buttonless_evt_type_t event) static void ble_dfu_evt_handler(ble_dfu_buttonless_evt_type_t event) {
{ switch (event) {
switch (event) case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE: {
{
case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE:
{
NRF_LOG_INFO("Device is preparing to enter bootloader mode."); NRF_LOG_INFO("Device is preparing to enter bootloader mode.");
// Prevent device from advertising on disconnect. // Prevent device from advertising on disconnect.
@@ -210,10 +199,8 @@ static void ble_dfu_evt_handler(ble_dfu_buttonless_evt_type_t event)
} }
} }
#else #else
static void ble_dfu_evt_handler(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt) static void ble_dfu_evt_handler(ble_dfu_t* p_dfu, ble_dfu_evt_t* p_evt) {
{ switch (p_evt->type) {
switch (p_evt->type)
{
case BLE_DFU_EVT_INDICATION_DISABLED: case BLE_DFU_EVT_INDICATION_DISABLED:
NRF_LOG_INFO("Indication for BLE_DFU is disabled\r\n"); NRF_LOG_INFO("Indication for BLE_DFU is disabled\r\n");
break; break;
@@ -232,8 +219,7 @@ static void ble_dfu_evt_handler(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt)
} }
#endif #endif
static void clock_timer_timeout_handler(void * p_context) static void clock_timer_timeout_handler(void* p_context) {
{
UNUSED_PARAMETER(p_context); UNUSED_PARAMETER(p_context);
m_timestamp++; m_timestamp++;
@@ -243,17 +229,13 @@ static void clock_timer_timeout_handler(void * p_context)
/**@brief Function for the Event Scheduler initialization. /**@brief Function for the Event Scheduler initialization.
*/ */
static void scheduler_init(void) static void scheduler_init(void) { APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE); }
{
APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
}
/**@brief Function for the Timer initialization. /**@brief Function for the Timer initialization.
* *
* @details Initializes the timer module. This creates and starts application timers. * @details Initializes the timer module. This creates and starts application timers.
*/ */
static void timers_init(void) static void timers_init(void) {
{
// Initialize timer module. // Initialize timer module.
#if defined(S112) #if defined(S112)
APP_ERROR_CHECK(app_timer_init()); APP_ERROR_CHECK(app_timer_init());
@@ -261,15 +243,12 @@ static void timers_init(void)
APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false); APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
#endif #endif
// Create timers. // Create timers.
APP_ERROR_CHECK(app_timer_create(&m_clock_timer_id, APP_ERROR_CHECK(app_timer_create(&m_clock_timer_id, APP_TIMER_MODE_REPEATED, clock_timer_timeout_handler));
APP_TIMER_MODE_REPEATED,
clock_timer_timeout_handler));
} }
/**@brief Function for starting application timers. /**@brief Function for starting application timers.
*/ */
static void application_timers_start(void) static void application_timers_start(void) {
{
// Start application timers. // Start application timers.
APP_ERROR_CHECK(app_timer_start(m_clock_timer_id, CLOCK_TIMER_INTERVAL, NULL)); APP_ERROR_CHECK(app_timer_start(m_clock_timer_id, CLOCK_TIMER_INTERVAL, NULL));
} }
@@ -278,8 +257,7 @@ static void application_timers_start(void)
* *
* @note This function will not return. * @note This function will not return.
*/ */
void sleep_mode_enter(void) void sleep_mode_enter(void) {
{
NRF_LOG_DEBUG("Entering deep sleep mode\n"); NRF_LOG_DEBUG("Entering deep sleep mode\n");
NRF_LOG_FINAL_FLUSH(); NRF_LOG_FINAL_FLUSH();
nrf_delay_ms(100); nrf_delay_ms(100);
@@ -290,8 +268,7 @@ void sleep_mode_enter(void)
/**@brief Function for initializing services that will be used by the application. /**@brief Function for initializing services that will be used by the application.
*/ */
static void services_init(void) static void services_init(void) {
{
// Initialize EPD Service. // Initialize EPD Service.
memset(&m_epd, 0, sizeof(ble_epd_t)); memset(&m_epd, 0, sizeof(ble_epd_t));
APP_ERROR_CHECK(ble_epd_init(&m_epd)); APP_ERROR_CHECK(ble_epd_init(&m_epd));
@@ -304,9 +281,9 @@ static void services_init(void)
// Initialize the Device Firmware Update Service. // Initialize the Device Firmware Update Service.
ble_dfu_init_t dfus_init; ble_dfu_init_t dfus_init;
memset(&dfus_init, 0, sizeof(dfus_init)); memset(&dfus_init, 0, sizeof(dfus_init));
dfus_init.evt_handler = ble_dfu_evt_handler; dfus_init.evt_handler = ble_dfu_evt_handler;
dfus_init.ctrl_point_security_req_write_perm = SEC_SIGNED; dfus_init.ctrl_point_security_req_write_perm = SEC_SIGNED;
dfus_init.ctrl_point_security_req_cccd_write_perm = SEC_SIGNED; dfus_init.ctrl_point_security_req_cccd_write_perm = SEC_SIGNED;
APP_ERROR_CHECK(ble_dfu_init(&m_dfus, &dfus_init)); APP_ERROR_CHECK(ble_dfu_init(&m_dfus, &dfus_init));
#endif #endif
} }
@@ -316,11 +293,10 @@ static void services_init(void)
* @details This function will set up all the necessary GAP (Generic Access Profile) parameters of * @details This function will set up all the necessary GAP (Generic Access Profile) parameters of
* the device. It also sets the permissions and appearance. * the device. It also sets the permissions and appearance.
*/ */
static void gap_params_init(void) static void gap_params_init(void) {
{ char device_name[20];
char device_name[20]; ble_gap_addr_t addr;
ble_gap_addr_t addr; ble_gap_conn_params_t gap_conn_params;
ble_gap_conn_params_t gap_conn_params;
ble_gap_conn_sec_mode_t sec_mode; ble_gap_conn_sec_mode_t sec_mode;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
@@ -330,21 +306,18 @@ static void gap_params_init(void)
APP_ERROR_CHECK(sd_ble_gap_address_get(&addr)); APP_ERROR_CHECK(sd_ble_gap_address_get(&addr));
#endif #endif
NRF_LOG_INFO("Bluetooth MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n", NRF_LOG_INFO("Bluetooth MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n", addr.addr[5], addr.addr[4], addr.addr[3],
addr.addr[5], addr.addr[4], addr.addr[3], addr.addr[2], addr.addr[1], addr.addr[0]);
addr.addr[2], addr.addr[1], addr.addr[0]);
snprintf(device_name, 20, "%s_%02X%02X", DEVICE_NAME, addr.addr[1],addr.addr[0]); snprintf(device_name, 20, "%s_%02X%02X", DEVICE_NAME, addr.addr[1], addr.addr[0]);
APP_ERROR_CHECK(sd_ble_gap_device_name_set(&sec_mode, APP_ERROR_CHECK(sd_ble_gap_device_name_set(&sec_mode, (const uint8_t*)device_name, strlen(device_name)));
(const uint8_t *)device_name,
strlen(device_name)));
memset(&gap_conn_params, 0, sizeof(gap_conn_params)); memset(&gap_conn_params, 0, sizeof(gap_conn_params));
gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL; gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL; gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
gap_conn_params.slave_latency = SLAVE_LATENCY; gap_conn_params.slave_latency = SLAVE_LATENCY;
gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT; gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
APP_ERROR_CHECK(sd_ble_gap_ppcp_set(&gap_conn_params)); APP_ERROR_CHECK(sd_ble_gap_ppcp_set(&gap_conn_params));
} }
@@ -360,48 +333,38 @@ static void gap_params_init(void)
* *
* @param[in] p_evt Event received from the Connection Parameters Module. * @param[in] p_evt Event received from the Connection Parameters Module.
*/ */
static void on_conn_params_evt(ble_conn_params_evt_t * p_evt) static void on_conn_params_evt(ble_conn_params_evt_t* p_evt) {
{ if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED) {
if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
{
APP_ERROR_CHECK(sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE)); APP_ERROR_CHECK(sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE));
} }
} }
/**@brief Function for handling errors from the Connection Parameters module. /**@brief Function for handling errors from the Connection Parameters module.
* *
* @param[in] nrf_error Error code containing information about what went wrong. * @param[in] nrf_error Error code containing information about what went wrong.
*/ */
static void conn_params_error_handler(uint32_t nrf_error) static void conn_params_error_handler(uint32_t nrf_error) { APP_ERROR_HANDLER(nrf_error); }
{
APP_ERROR_HANDLER(nrf_error);
}
/**@brief Function for initializing the Connection Parameters module. /**@brief Function for initializing the Connection Parameters module.
*/ */
static void conn_params_init(void) static void conn_params_init(void) {
{
ble_conn_params_init_t cp_init; ble_conn_params_init_t cp_init;
memset(&cp_init, 0, sizeof(cp_init)); memset(&cp_init, 0, sizeof(cp_init));
cp_init.p_conn_params = NULL; cp_init.p_conn_params = NULL;
cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY; cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY; cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT; cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID; cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
cp_init.disconnect_on_fail = false; cp_init.disconnect_on_fail = false;
cp_init.evt_handler = on_conn_params_evt; cp_init.evt_handler = on_conn_params_evt;
cp_init.error_handler = conn_params_error_handler; cp_init.error_handler = conn_params_error_handler;
APP_ERROR_CHECK(ble_conn_params_init(&cp_init)); APP_ERROR_CHECK(ble_conn_params_init(&cp_init));
} }
static void advertising_start(void) {
static void advertising_start(void)
{
NRF_LOG_INFO("advertising start\n"); NRF_LOG_INFO("advertising start\n");
#if defined(S112) #if defined(S112)
APP_ERROR_CHECK(ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST)); APP_ERROR_CHECK(ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST));
@@ -432,17 +395,14 @@ static void setup_wakeup_pin(nrf_drv_gpiote_pin_t pin) {
nrf_drv_gpiote_in_event_enable(pin, true); nrf_drv_gpiote_in_event_enable(pin, true);
} }
/**@brief Function for handling advertising events. /**@brief Function for handling advertising events.
* *
* @details This function will be called for advertising events which are passed to the application. * @details This function will be called for advertising events which are passed to the application.
* *
* @param[in] ble_adv_evt Advertising event. * @param[in] ble_adv_evt Advertising event.
*/ */
static void on_adv_evt(ble_adv_evt_t ble_adv_evt) static void on_adv_evt(ble_adv_evt_t ble_adv_evt) {
{ switch (ble_adv_evt) {
switch (ble_adv_evt)
{
case BLE_ADV_EVT_FAST: case BLE_ADV_EVT_FAST:
break; break;
case BLE_ADV_EVT_IDLE: case BLE_ADV_EVT_IDLE:
@@ -465,10 +425,8 @@ static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
* *
* @param[in] p_ble_evt SoftDevice event. * @param[in] p_ble_evt SoftDevice event.
*/ */
static void on_ble_evt(ble_evt_t * p_ble_evt) static void on_ble_evt(ble_evt_t* p_ble_evt) {
{ switch (p_ble_evt->header.evt_id) {
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED: case BLE_GAP_EVT_CONNECTED:
NRF_LOG_INFO("CONNECTED\n"); NRF_LOG_INFO("CONNECTED\n");
m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
@@ -482,11 +440,9 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
#endif #endif
break; break;
#if defined(S112) #if defined(S112)
case BLE_GAP_EVT_PHY_UPDATE_REQUEST: case BLE_GAP_EVT_PHY_UPDATE_REQUEST: {
{
NRF_LOG_DEBUG("PHY update request."); NRF_LOG_DEBUG("PHY update request.");
ble_gap_phys_t const phys = ble_gap_phys_t const phys = {
{
.rx_phys = BLE_GAP_PHY_AUTO, .rx_phys = BLE_GAP_PHY_AUTO,
.tx_phys = BLE_GAP_PHY_AUTO, .tx_phys = BLE_GAP_PHY_AUTO,
}; };
@@ -496,24 +452,25 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
case BLE_GAP_EVT_SEC_PARAMS_REQUEST: case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
// Pairing not supported // Pairing not supported
APP_ERROR_CHECK(sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL)); APP_ERROR_CHECK(
sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL));
break; break;
case BLE_GATTS_EVT_SYS_ATTR_MISSING: case BLE_GATTS_EVT_SYS_ATTR_MISSING:
// No system attributes have been stored. // No system attributes have been stored.
APP_ERROR_CHECK(sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0)); APP_ERROR_CHECK(sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0));
break; break;
case BLE_GATTC_EVT_TIMEOUT: case BLE_GATTC_EVT_TIMEOUT:
// Disconnect on GATT Client timeout event. // Disconnect on GATT Client timeout event.
APP_ERROR_CHECK(sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle, APP_ERROR_CHECK(
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION)); sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION));
break; break;
case BLE_GATTS_EVT_TIMEOUT: case BLE_GATTS_EVT_TIMEOUT:
// Disconnect on GATT Server timeout event. // Disconnect on GATT Server timeout event.
APP_ERROR_CHECK(sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle, APP_ERROR_CHECK(
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION)); sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION));
break; break;
default: default:
@@ -522,18 +479,16 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
} }
} }
#if defined(S112) #if defined(S112)
/**@brief Function for handling BLE events. /**@brief Function for handling BLE events.
* *
* @param[in] p_ble_evt Bluetooth stack event. * @param[in] p_ble_evt Bluetooth stack event.
* @param[in] p_context Unused. * @param[in] p_context Unused.
*/ */
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) static void ble_evt_handler(ble_evt_t const* p_ble_evt, void* p_context) {
{
UNUSED_PARAMETER(p_context); UNUSED_PARAMETER(p_context);
on_ble_evt((ble_evt_t *)p_ble_evt); on_ble_evt((ble_evt_t*)p_ble_evt);
} }
#else #else
@@ -545,8 +500,7 @@ static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
* *
* @param[in] p_ble_evt SoftDevice event. * @param[in] p_ble_evt SoftDevice event.
*/ */
static void ble_evt_dispatch(ble_evt_t * p_ble_evt) static void ble_evt_dispatch(ble_evt_t* p_ble_evt) {
{
ble_conn_params_on_ble_evt(p_ble_evt); ble_conn_params_on_ble_evt(p_ble_evt);
ble_epd_on_ble_evt(&m_epd, p_ble_evt); ble_epd_on_ble_evt(&m_epd, p_ble_evt);
on_ble_evt(p_ble_evt); on_ble_evt(p_ble_evt);
@@ -554,7 +508,6 @@ static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
ble_dfu_on_ble_evt(&m_dfus, p_ble_evt); ble_dfu_on_ble_evt(&m_dfus, p_ble_evt);
} }
/**@brief Function for dispatching a system event to interested modules. /**@brief Function for dispatching a system event to interested modules.
* *
* @details This function is called from the System event interrupt handler after a system * @details This function is called from the System event interrupt handler after a system
@@ -562,8 +515,7 @@ static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
* *
* @param[in] sys_evt System stack event. * @param[in] sys_evt System stack event.
*/ */
static void sys_evt_dispatch(uint32_t sys_evt) static void sys_evt_dispatch(uint32_t sys_evt) {
{
// Dispatch the system event to the fstorage module, where it will be // Dispatch the system event to the fstorage module, where it will be
// dispatched to the Flash Data Storage (FDS) module. // dispatched to the Flash Data Storage (FDS) module.
fs_sys_event_handler(sys_evt); fs_sys_event_handler(sys_evt);
@@ -579,8 +531,7 @@ static void sys_evt_dispatch(uint32_t sys_evt)
* *
* @details This function initializes the SoftDevice and the BLE event interrupt. * @details This function initializes the SoftDevice and the BLE event interrupt.
*/ */
static void ble_stack_init(void) static void ble_stack_init(void) {
{
#if defined(S112) #if defined(S112)
APP_ERROR_CHECK(nrf_sdh_enable_request()); APP_ERROR_CHECK(nrf_sdh_enable_request());
@@ -595,20 +546,19 @@ static void ble_stack_init(void)
// Register a handler for BLE events. // Register a handler for BLE events.
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL); NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
#else #else
nrf_clock_lf_cfg_t clock_lf_cfg = NRF_CLOCK_LFCLKSRC; nrf_clock_lf_cfg_t clock_lf_cfg = NRF_CLOCK_LFCLKSRC;
// Initialize the SoftDevice handler module. // Initialize the SoftDevice handler module.
SOFTDEVICE_HANDLER_INIT(&clock_lf_cfg, NULL); SOFTDEVICE_HANDLER_INIT(&clock_lf_cfg, NULL);
ble_enable_params_t ble_enable_params; ble_enable_params_t ble_enable_params;
APP_ERROR_CHECK(softdevice_enable_get_default_config(CENTRAL_LINK_COUNT, APP_ERROR_CHECK(
PERIPHERAL_LINK_COUNT, softdevice_enable_get_default_config(CENTRAL_LINK_COUNT, PERIPHERAL_LINK_COUNT, &ble_enable_params));
&ble_enable_params));
ble_enable_params.common_enable_params.vs_uuid_count = 2; ble_enable_params.common_enable_params.vs_uuid_count = 2;
// Check the ram settings against the used number of links // Check the ram settings against the used number of links
CHECK_RAM_START_ADDR(CENTRAL_LINK_COUNT,PERIPHERAL_LINK_COUNT); CHECK_RAM_START_ADDR(CENTRAL_LINK_COUNT, PERIPHERAL_LINK_COUNT);
// Enable BLE stack. // Enable BLE stack.
APP_ERROR_CHECK(softdevice_enable(&ble_enable_params)); APP_ERROR_CHECK(softdevice_enable(&ble_enable_params));
@@ -622,29 +572,23 @@ static void ble_stack_init(void)
#if defined(S112) #if defined(S112)
/**@brief Function for handling events from the GATT library. */ /**@brief Function for handling events from the GATT library. */
void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt) void gatt_evt_handler(nrf_ble_gatt_t* p_gatt, nrf_ble_gatt_evt_t const* p_evt) {
{ if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)) {
if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED))
{
m_epd.max_data_len = p_evt->params.att_mtu_effective - 3; m_epd.max_data_len = p_evt->params.att_mtu_effective - 3;
NRF_LOG_INFO("Data len is set to 0x%X(%d)", m_epd.max_data_len, m_epd.max_data_len); NRF_LOG_INFO("Data len is set to 0x%X(%d)", m_epd.max_data_len, m_epd.max_data_len);
} }
NRF_LOG_DEBUG("ATT MTU exchange completed. central 0x%x peripheral 0x%x", NRF_LOG_DEBUG("ATT MTU exchange completed. central 0x%x peripheral 0x%x", p_gatt->att_mtu_desired_central,
p_gatt->att_mtu_desired_central,
p_gatt->att_mtu_desired_periph); p_gatt->att_mtu_desired_periph);
} }
/**@brief Function for initializing the GATT library. */ /**@brief Function for initializing the GATT library. */
void gatt_init(void) void gatt_init(void) {
{
APP_ERROR_CHECK(nrf_ble_gatt_init(&m_gatt, gatt_evt_handler)); APP_ERROR_CHECK(nrf_ble_gatt_init(&m_gatt, gatt_evt_handler));
APP_ERROR_CHECK(nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE)); APP_ERROR_CHECK(nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE));
} }
#else #else
// Set BW Config to HIGH. // Set BW Config to HIGH.
static void ble_options_set(void) static void ble_options_set(void) {
{
ble_opt_t ble_opt; ble_opt_t ble_opt;
memset(&ble_opt, 0, sizeof(ble_opt)); memset(&ble_opt, 0, sizeof(ble_opt));
@@ -659,47 +603,46 @@ static void ble_options_set(void)
/**@brief Function for initializing the Advertising functionality. /**@brief Function for initializing the Advertising functionality.
*/ */
static void advertising_init(void) static void advertising_init(void) {
{
#if defined(S112) #if defined(S112)
ble_advertising_init_t init; ble_advertising_init_t init;
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
init.advdata.name_type = BLE_ADVDATA_FULL_NAME; init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
init.advdata.include_appearance = false; init.advdata.include_appearance = false;
init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE; init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]); init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
init.srdata.uuids_complete.p_uuids = m_adv_uuids; init.srdata.uuids_complete.p_uuids = m_adv_uuids;
init.config.ble_adv_fast_enabled = true; init.config.ble_adv_fast_enabled = true;
init.config.ble_adv_fast_interval = APP_ADV_INTERVAL; init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
init.config.ble_adv_fast_timeout = APP_ADV_TIMEOUT_IN_SECONDS * 100; init.config.ble_adv_fast_timeout = APP_ADV_TIMEOUT_IN_SECONDS * 100;
init.evt_handler = on_adv_evt; init.evt_handler = on_adv_evt;
APP_ERROR_CHECK(ble_advertising_init(&m_advertising, &init)); APP_ERROR_CHECK(ble_advertising_init(&m_advertising, &init));
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG); ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
#else #else
ble_advdata_t advdata; ble_advdata_t advdata;
ble_advdata_t scanrsp; ble_advdata_t scanrsp;
ble_adv_modes_config_t options; ble_adv_modes_config_t options;
// Build advertising data struct to pass into @ref ble_advertising_init. // Build advertising data struct to pass into @ref ble_advertising_init.
memset(&advdata, 0, sizeof(advdata)); memset(&advdata, 0, sizeof(advdata));
advdata.name_type = BLE_ADVDATA_FULL_NAME; advdata.name_type = BLE_ADVDATA_FULL_NAME;
advdata.include_appearance = false; advdata.include_appearance = false;
advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE; advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
memset(&scanrsp, 0, sizeof(scanrsp)); memset(&scanrsp, 0, sizeof(scanrsp));
scanrsp.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]); scanrsp.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
scanrsp.uuids_complete.p_uuids = m_adv_uuids; scanrsp.uuids_complete.p_uuids = m_adv_uuids;
memset(&options, 0, sizeof(options)); memset(&options, 0, sizeof(options));
options.ble_adv_fast_enabled = true; options.ble_adv_fast_enabled = true;
options.ble_adv_fast_interval = APP_ADV_INTERVAL; options.ble_adv_fast_interval = APP_ADV_INTERVAL;
options.ble_adv_fast_timeout = APP_ADV_TIMEOUT_IN_SECONDS; options.ble_adv_fast_timeout = APP_ADV_TIMEOUT_IN_SECONDS;
APP_ERROR_CHECK(ble_advertising_init(&advdata, &scanrsp, &options, on_adv_evt, NULL)); APP_ERROR_CHECK(ble_advertising_init(&advdata, &scanrsp, &options, on_adv_evt, NULL));
#endif #endif
@@ -707,8 +650,7 @@ static void advertising_init(void)
/**@brief Function for initializing the nrf log module. /**@brief Function for initializing the nrf log module.
*/ */
static void log_init(void) static void log_init(void) {
{
APP_ERROR_CHECK(NRF_LOG_INIT(timestamp)); APP_ERROR_CHECK(NRF_LOG_INIT(timestamp));
#if defined(S112) #if defined(S112)
NRF_LOG_DEFAULT_BACKENDS_INIT(); NRF_LOG_DEFAULT_BACKENDS_INIT();
@@ -717,8 +659,7 @@ static void log_init(void)
/**@brief Function for initializing power management. /**@brief Function for initializing power management.
*/ */
static void power_management_init(void) static void power_management_init(void) {
{
#if defined(S112) #if defined(S112)
APP_ERROR_CHECK(nrf_pwr_mgmt_init()); APP_ERROR_CHECK(nrf_pwr_mgmt_init());
#else #else
@@ -730,28 +671,25 @@ static void power_management_init(void)
* *
* @details If there is no pending log operation, then sleep until next the next event occurs. * @details If there is no pending log operation, then sleep until next the next event occurs.
*/ */
static void idle_state_handle(void) static void idle_state_handle(void) {
{
app_feed_wdt(); app_feed_wdt();
if (NRF_LOG_PROCESS() == false) if (NRF_LOG_PROCESS() == false) nrf_pwr_mgmt_run();
nrf_pwr_mgmt_run();
} }
/** /**
* @brief WDT events handler. * @brief WDT events handler.
*/ */
void wdt_event_handler(void) void wdt_event_handler(void) {
{ // NOTE: The max amount of time we can spend in WDT interrupt is two cycles of 32768[Hz] clock - after that, reset
//NOTE: The max amount of time we can spend in WDT interrupt is two cycles of 32768[Hz] clock - after that, reset occurs // occurs
NRF_LOG_ERROR("WDT Rest!\r\n"); NRF_LOG_ERROR("WDT Rest!\r\n");
NRF_LOG_FINAL_FLUSH(); NRF_LOG_FINAL_FLUSH();
} }
/**@brief Function for application main entry. /**@brief Function for application main entry.
*/ */
int main(void) int main(void) {
{
log_init(); log_init();
// Save reset reason. // Save reset reason.
@@ -798,8 +736,7 @@ int main(void)
ble_epd_on_timer(&m_epd, m_timestamp, true); ble_epd_on_timer(&m_epd, m_timestamp, true);
} }
for (;;) for (;;) {
{
app_sched_execute(); app_sched_execute();
idle_state_handle(); idle_state_handle();
} }