diff --git a/EPD/EPD_config.c b/EPD/EPD_config.c index 5040af6..281bb30 100644 --- a/EPD/EPD_config.c +++ b/EPD/EPD_config.c @@ -34,7 +34,7 @@ void epd_config_load(epd_config_t *cfg) fds_record_desc_t record_desc; fds_find_token_t ftok; - memset(cfg, 0xFF, sizeof(epd_config_t)); + memset(cfg, EPD_CONFIG_EMPTY, sizeof(epd_config_t)); memset(&ftok, 0x00, sizeof(fds_find_token_t)); if (fds_record_find(CONFIG_FILE_ID, CONFIG_REC_KEY, &record_desc, &ftok) != NRF_SUCCESS) { @@ -99,3 +99,12 @@ void epd_config_save(epd_config_t *cfg) NRF_LOG_ERROR("epd_config_save: record write/update failed!\n"); } } + +bool epd_config_empty(epd_config_t *cfg) +{ + for (uint8_t i = 0; i < EPD_CONFIG_SIZE; i++) { + if (((uint8_t *)cfg)[i] != EPD_CONFIG_EMPTY) + return false; + } + return true; +} diff --git a/EPD/EPD_config.h b/EPD/EPD_config.h index 724f6c2..d8044b2 100644 --- a/EPD/EPD_config.h +++ b/EPD/EPD_config.h @@ -1,3 +1,6 @@ +#ifndef EPD_CONFIG_H__ +#define EPD_CONFIG_H__ +#include #include typedef struct @@ -9,13 +12,19 @@ typedef struct uint8_t rst_pin; uint8_t busy_pin; uint8_t bs_pin; - uint8_t driver_id; + uint8_t model_id; uint8_t wakeup_pin; uint8_t led_pin; uint8_t en_pin; } epd_config_t; +#define EPD_CONFIG_SIZE (sizeof(epd_config_t) / sizeof(uint8_t)) +#define EPD_CONFIG_EMPTY 0xFF + void epd_config_init(epd_config_t *cfg); void epd_config_load(epd_config_t *cfg); void epd_config_clear(epd_config_t *cfg); void epd_config_save(epd_config_t *cfg); +bool epd_config_empty(epd_config_t *cfg); + +#endif diff --git a/EPD/EPD_driver.c b/EPD/EPD_driver.c index d55f1c5..634ede7 100644 --- a/EPD/EPD_driver.c +++ b/EPD/EPD_driver.c @@ -21,6 +21,7 @@ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +// GPIO Pins uint32_t EPD_MOSI_PIN = 5; uint32_t EPD_SCLK_PIN = 8; uint32_t EPD_CS_PIN = 9; @@ -31,6 +32,13 @@ uint32_t EPD_BS_PIN = 13; uint32_t EPD_EN_PIN = 0xFF; uint32_t EPD_LED_PIN = 0xFF; +// Display resolution +uint16_t EPD_WIDTH = 400; +uint16_t EPD_HEIGHT = 300; + +// BWR mode +bool EPD_BWR_MODE = true; + // Arduino like function wrappers void pinMode(uint32_t pin, uint32_t mode) @@ -82,50 +90,13 @@ void delay(uint32_t ms) nrf_delay_ms(ms); } -// GPIO -void DEV_Module_Init(void) -{ - pinMode(EPD_CS_PIN, OUTPUT); - pinMode(EPD_DC_PIN, OUTPUT); - pinMode(EPD_RST_PIN, OUTPUT); - pinMode(EPD_BUSY_PIN, INPUT); - - if (EPD_EN_PIN != 0xFF) { - pinMode(EPD_EN_PIN, OUTPUT); - digitalWrite(EPD_EN_PIN, HIGH); - } - - pinMode(EPD_BS_PIN, OUTPUT); - digitalWrite(EPD_BS_PIN, LOW); - - digitalWrite(EPD_DC_PIN, LOW); - digitalWrite(EPD_CS_PIN, LOW); - digitalWrite(EPD_RST_PIN, HIGH); - - if (EPD_LED_PIN != 0xFF) { - pinMode(EPD_LED_PIN, OUTPUT); - EPD_LED_ON(); - } -} - -void DEV_Module_Exit(void) -{ - digitalWrite(EPD_DC_PIN, LOW); - digitalWrite(EPD_CS_PIN, LOW); - digitalWrite(EPD_RST_PIN, LOW); - - DEV_SPI_Exit(); - - EPD_LED_OFF(); -} - // Hardware SPI (write only) #define SPI_INSTANCE 0 /**< SPI instance index. */ static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); /**< SPI instance. */ static bool spi_initialized = false; -void DEV_SPI_Init(void) +static void EPD_SPI_Init(void) { if (spi_initialized) return; nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; @@ -140,30 +111,30 @@ void DEV_SPI_Init(void) spi_initialized = true; } -void DEV_SPI_Exit(void) +static void EPD_SPI_Uninit(void) { if (!spi_initialized) return; nrf_drv_spi_uninit(&spi); spi_initialized = false; } -void DEV_SPI_WriteByte(uint8_t value) +void EPD_SPI_WriteByte(uint8_t value) { - DEV_SPI_Init(); + EPD_SPI_Init(); APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &value, 1, NULL, 0)); } -void DEV_SPI_WriteBytes(uint8_t *value, uint8_t len) +void EPD_SPI_WriteBytes(uint8_t *value, uint8_t len) { - DEV_SPI_Init(); + EPD_SPI_Init(); APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, value, len, NULL, 0)); } // Software SPI (read / write) -void DEV_SPI_WriteByte_SW(uint8_t data) +void EPD_SPI_WriteByte_SW(uint8_t data) { - DEV_SPI_Exit(); + EPD_SPI_Uninit(); pinMode(EPD_MOSI_PIN, OUTPUT); digitalWrite(EPD_CS_PIN, LOW); for (int i = 0; i < 8; i++) @@ -178,9 +149,9 @@ void DEV_SPI_WriteByte_SW(uint8_t data) digitalWrite(EPD_CS_PIN, HIGH); } -uint8_t DEV_SPI_ReadByte_SW(void) +uint8_t EPD_SPI_ReadByte_SW(void) { - DEV_SPI_Exit(); + EPD_SPI_Uninit(); uint8_t j = 0xff; pinMode(EPD_MOSI_PIN, INPUT); digitalWrite(EPD_CS_PIN, LOW); @@ -202,7 +173,7 @@ void EPD_WriteCommand_SW(uint8_t Reg) { digitalWrite(EPD_DC_PIN, LOW); digitalWrite(EPD_CS_PIN, LOW); - DEV_SPI_WriteByte_SW(Reg); + EPD_SPI_WriteByte_SW(Reg); digitalWrite(EPD_CS_PIN, HIGH); } @@ -210,14 +181,14 @@ void EPD_WriteByte_SW(uint8_t Data) { digitalWrite(EPD_DC_PIN, HIGH); digitalWrite(EPD_CS_PIN, LOW); - DEV_SPI_WriteByte_SW(Data); + EPD_SPI_WriteByte_SW(Data); digitalWrite(EPD_CS_PIN, HIGH); } uint8_t EPD_ReadByte_SW(void) { digitalWrite(EPD_DC_PIN, HIGH); - return DEV_SPI_ReadByte_SW(); + return EPD_SPI_ReadByte_SW(); } @@ -225,19 +196,19 @@ uint8_t EPD_ReadByte_SW(void) void EPD_WriteCommand(uint8_t Reg) { digitalWrite(EPD_DC_PIN, LOW); - DEV_SPI_WriteByte(Reg); + EPD_SPI_WriteByte(Reg); } void EPD_WriteByte(uint8_t Data) { digitalWrite(EPD_DC_PIN, HIGH); - DEV_SPI_WriteByte(Data); + EPD_SPI_WriteByte(Data); } void EPD_WriteData(uint8_t *Data, uint8_t Len) { digitalWrite(EPD_DC_PIN, HIGH); - DEV_SPI_WriteBytes(Data, Len); + EPD_SPI_WriteBytes(Data, Len); } void EPD_Reset(uint32_t value, uint16_t duration) @@ -266,6 +237,44 @@ void EPD_WaitBusy(uint32_t value, uint16_t timeout) NRF_LOG_DEBUG("[EPD]: busy release\n"); } +// GPIO +void EPD_GPIO_Init(void) +{ + pinMode(EPD_CS_PIN, OUTPUT); + pinMode(EPD_DC_PIN, OUTPUT); + pinMode(EPD_RST_PIN, OUTPUT); + pinMode(EPD_BUSY_PIN, INPUT); + + if (EPD_EN_PIN != 0xFF) { + pinMode(EPD_EN_PIN, OUTPUT); + digitalWrite(EPD_EN_PIN, HIGH); + } + + pinMode(EPD_BS_PIN, OUTPUT); + digitalWrite(EPD_BS_PIN, LOW); + + EPD_SPI_Init(); + + digitalWrite(EPD_DC_PIN, LOW); + digitalWrite(EPD_CS_PIN, LOW); + digitalWrite(EPD_RST_PIN, HIGH); + + if (EPD_LED_PIN != 0xFF) { + pinMode(EPD_LED_PIN, OUTPUT); + EPD_LED_ON(); + } +} + +void EPD_GPIO_Uninit(void) +{ + digitalWrite(EPD_DC_PIN, LOW); + digitalWrite(EPD_CS_PIN, LOW); + digitalWrite(EPD_RST_PIN, LOW); + + EPD_SPI_Uninit(); + + EPD_LED_OFF(); +} // lED void EPD_LED_ON(void) @@ -286,41 +295,28 @@ void EPD_LED_TOGGLE(void) nrf_gpio_pin_toggle(EPD_LED_PIN); } +// EPD models +extern epd_model_t epd_4in2; +extern epd_model_t epd_4in2bv2; -extern epd_driver_t epd_driver_4in2; -extern epd_driver_t epd_driver_4in2bv2; - -/** EPD drivers */ -static epd_driver_t *epd_drivers[] = { - &epd_driver_4in2, // UC8176: 4.2 inch, BW - &epd_driver_4in2bv2, // UC8176: 4.2 inch, BWR +static epd_model_t *epd_models[] = { + &epd_4in2, + &epd_4in2bv2, }; -/**< current EPD driver */ -static epd_driver_t *m_driver = NULL; - -epd_driver_t *epd_driver_get(void) +static epd_model_t *epd_model_get(epd_model_id_t id) { - if (m_driver == NULL) - m_driver = epd_drivers[0]; - return m_driver; -} - -epd_driver_t *epd_driver_by_id(uint8_t id) -{ - for (uint8_t i = 0; i < ARRAY_SIZE(epd_drivers); i++) { - if (epd_drivers[i]->id == id) - return epd_drivers[i]; + for (uint8_t i = 0; i < ARRAY_SIZE(epd_models); i++) { + if (epd_models[i]->id == id) { + return epd_models[i]; + } } - return NULL; + return epd_models[0]; } -bool epd_driver_set(uint8_t id) +epd_driver_t *epd_model_init(epd_model_id_t id) { - epd_driver_t *driver = epd_driver_by_id(id); - if (driver ) { - m_driver = driver; - return true; - } - return false; + epd_model_t *model = epd_model_get(id); + model->drv->init(model->res, model->bwr); + return model->drv; } diff --git a/EPD/EPD_driver.h b/EPD/EPD_driver.h index fe77a0e..c4490d7 100644 --- a/EPD/EPD_driver.h +++ b/EPD/EPD_driver.h @@ -19,12 +19,16 @@ #include #include -/**< EPD driver IDs. */ -enum EPD_DRIVER_IDS +#define BIT(n) (1UL << (n)) + +// Display resolution +typedef enum { - EPD_DRIVER_4IN2 = 1, - EPD_DRIVER_4IN2B_V2 = 3, -}; + EPD_RES_400x300, + EPD_RES_320x300, + EPD_RES_320x240, + EPD_RES_200x300, +} epd_res_t; /**@brief EPD driver structure. * @@ -32,14 +36,8 @@ enum EPD_DRIVER_IDS */ typedef struct { - uint8_t id; /**< driver ID. */ - uint16_t width; - uint16_t height; - void (*init)(void); /**< Initialize the e-Paper register */ + void (*init)(epd_res_t res, bool bwr); /**< Initialize the e-Paper register */ void (*clear)(void); /**< Clear screen */ - void (*send_command)(uint8_t Reg); /**< send command */ - void (*send_byte)(uint8_t Reg); /**< send byte */ - void (*send_data)(uint8_t *Data, uint8_t Len); /**< send data */ void (*write_image)(uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h); /**< write image */ void (*refresh)(void); /**< Sends the image buffer in RAM to e-Paper and displays */ void (*sleep)(void); /**< Enter sleep mode */ @@ -47,6 +45,21 @@ typedef struct void (*force_temp)(int8_t value); /**< Force temperature (will trigger OTP LUT switch) */ } epd_driver_t; +typedef enum +{ + EPD_4IN2 = 1, + EPD_4IN2_V2 = 2, + EPD_4IN2B_V2 = 3, +} epd_model_id_t; + +typedef struct +{ + epd_model_id_t id; + epd_driver_t *drv; + epd_res_t res; + bool bwr; +} epd_model_t; + extern uint32_t EPD_MOSI_PIN; extern uint32_t EPD_SCLK_PIN; extern uint32_t EPD_CS_PIN; @@ -57,6 +70,11 @@ extern uint32_t EPD_BS_PIN; extern uint32_t EPD_EN_PIN; extern uint32_t EPD_LED_PIN; +extern uint16_t EPD_WIDTH; +extern uint16_t EPD_HEIGHT; + +extern bool EPD_BWR_MODE; + #define LOW (0x0) #define HIGH (0x1) @@ -72,21 +90,19 @@ uint32_t digitalRead(uint32_t pin); void delay(uint32_t ms); // GPIO -void DEV_Module_Init(void); -void DEV_Module_Exit(void); +void EPD_GPIO_Init(void); +void EPD_GPIO_Uninit(void); // Software SPI (read / write) -void DEV_SPI_WriteByte_SW(uint8_t data); -uint8_t DEV_SPI_ReadByte_SW(void); +void EPD_SPI_WriteByte_SW(uint8_t data); +uint8_t EPD_SPI_ReadByte_SW(void); void EPD_WriteCommand_SW(uint8_t Reg); void EPD_WriteByte_SW(uint8_t Data); uint8_t EPD_ReadByte_SW(void); // Hardware SPI (write only) -void DEV_SPI_Init(void); -void DEV_SPI_Exit(void); -void DEV_SPI_WriteByte(uint8_t value); -void DEV_SPI_WriteBytes(uint8_t *value, uint8_t len); +void EPD_SPI_WriteByte(uint8_t value); +void EPD_SPI_WriteBytes(uint8_t *value, uint8_t len); void EPD_WriteCommand(uint8_t Reg); void EPD_WriteByte(uint8_t Data); void EPD_WriteData(uint8_t *Data, uint8_t Len); @@ -99,8 +115,6 @@ void EPD_LED_ON(void); void EPD_LED_OFF(void); void EPD_LED_TOGGLE(void); -epd_driver_t *epd_driver_get(void); -epd_driver_t *epd_driver_by_id(uint8_t id); -bool epd_driver_set(uint8_t id); +epd_driver_t *epd_model_init(epd_model_id_t id); #endif diff --git a/EPD/EPD_service.c b/EPD/EPD_service.c index ee14640..cfe9947 100644 --- a/EPD/EPD_service.c +++ b/EPD/EPD_service.c @@ -15,12 +15,14 @@ #include "ble_srv_common.h" #include "nrf_delay.h" #include "nrf_gpio.h" +#include "app_scheduler.h" #include "EPD_service.h" +#include "Calendar.h" #include "nrf_log.h" #if defined(S112) -#define EPD_CFG_DEFAULT {0x14, 0x13, 0x06, 0x05, 0x04, 0x03, 0x02, 0x03, 0xFF, 0x12, 0x07} // 52811 -//#define EPD_CFG_DEFAULT {0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x03, 0xFF, 0x0D, 0x02} // 52810 +//#define EPD_CFG_DEFAULT {0x14, 0x13, 0x06, 0x05, 0x04, 0x03, 0x02, 0x03, 0xFF, 0x12, 0x07} // 52811 +#define EPD_CFG_DEFAULT {0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x03, 0xFF, 0x0D, 0x02} // 52810 #else #define EPD_CFG_DEFAULT {0x05, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x01, 0x07} #endif @@ -33,8 +35,40 @@ 0X8D, 0X91, 0X28, 0XD8, 0X22, 0X36, 0X75, 0X62}} #define BLE_UUID_EPD_CHARACTERISTIC 0x0002 -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -#define EPD_CONFIG_SIZE (sizeof(epd_config_t) / sizeof(uint8_t)) +extern uint32_t timestamp(void); // defined in main.c + +static uint16_t m_driver_refs = 0; + +static void epd_gpio_init() +{ + if (m_driver_refs == 0) { + NRF_LOG_DEBUG("[EPD]: driver init\n"); + EPD_GPIO_Init(); + } + m_driver_refs++; +} + +static void epd_gpio_uninit() +{ + m_driver_refs--; + if (m_driver_refs == 0) { + NRF_LOG_DEBUG("[EPD]: driver exit\n"); + EPD_GPIO_Uninit(); + } +} + +static void calendar_update(void * p_event_data, uint16_t event_size) +{ + epd_calendar_update_event_t *event = (epd_calendar_update_event_t *)p_event_data; + ble_epd_t *p_epd = event->p_epd; + + p_epd->calendar_mode = true; + + epd_gpio_init(); + epd_driver_t *drv = epd_model_init((epd_model_id_t)p_epd->config.model_id); + DrawCalendar(drv, event->timestamp); + epd_gpio_uninit(); +} /**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the S110 SoftDevice. * @@ -44,9 +78,9 @@ 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; + epd_gpio_init(); } - /**@brief Function for handling the @ref BLE_GAP_EVT_DISCONNECTED event from the S110 SoftDevice. * * @param[in] p_epd EPD Service structure. @@ -56,6 +90,7 @@ static void on_disconnect(ble_epd_t * p_epd, ble_evt_t * p_ble_evt) { UNUSED_PARAMETER(p_ble_evt); p_epd->conn_handle = BLE_CONN_HANDLE_INVALID; + epd_gpio_uninit(); } static void epd_service_process(ble_epd_t * p_epd, uint8_t * p_data, uint16_t length) @@ -73,7 +108,7 @@ static void epd_service_process(ble_epd_t * p_epd, uint8_t * p_data, uint16_t le case EPD_CMD_SET_PINS: if (length < 8) return; - DEV_Module_Exit(); + EPD_GPIO_Uninit(); EPD_MOSI_PIN = p_epd->config.mosi_pin = p_data[1]; EPD_SCLK_PIN = p_epd->config.sclk_pin = p_data[2]; @@ -86,38 +121,34 @@ static void epd_service_process(ble_epd_t * p_epd, uint8_t * p_data, uint16_t le EPD_EN_PIN = p_epd->config.en_pin = p_data[8]; epd_config_save(&p_epd->config); - DEV_Module_Init(); + EPD_GPIO_Init(); break; - case EPD_CMD_INIT: - if (length > 1) - { - if (epd_driver_set(p_data[1])) - { - p_epd->driver = epd_driver_get(); - p_epd->config.driver_id = p_epd->driver->id; - epd_config_save(&p_epd->config); - } + case EPD_CMD_INIT: { + uint8_t id = length > 1 ? p_data[1] : p_epd->config.model_id; + if (id != p_epd->config.model_id) { + p_epd->config.model_id = id; + epd_config_save(&p_epd->config); } - - NRF_LOG_INFO("[EPD]: DRIVER=%d\n", p_epd->driver->id); - p_epd->driver->init(); - break; + p_epd->driver = epd_model_init((epd_model_id_t)id); + } break; case EPD_CMD_CLEAR: + p_epd->calendar_mode = false; p_epd->driver->clear(); break; case EPD_CMD_SEND_COMMAND: if (length < 2) return; - p_epd->driver->send_command(p_data[1]); + EPD_WriteCommand(p_data[1]); break; case EPD_CMD_SEND_DATA: - p_epd->driver->send_data(&p_data[1], length - 1); + EPD_WriteData(&p_data[1], length - 1); break; case EPD_CMD_DISPLAY: + p_epd->calendar_mode = false; p_epd->driver->refresh(); break; @@ -253,21 +284,11 @@ static uint32_t epd_service_init(ble_epd_t * p_epd) static void ble_epd_config_load(ble_epd_t * p_epd) { - bool is_empty_config = true; - - for (uint8_t i = 0; i < EPD_CONFIG_SIZE; i++) - { - if (((uint8_t *)&p_epd->config)[i] != 0xFF) - { - is_empty_config = false; - } - } - NRF_LOG_DEBUG("is_empty_config: %d\n", is_empty_config); // write default config - if (is_empty_config) + if (epd_config_empty(&p_epd->config)) { uint8_t cfg[] = EPD_CFG_DEFAULT; - memcpy(&p_epd->config, cfg, ARRAY_SIZE(cfg)); + memcpy(&p_epd->config, cfg, sizeof(cfg)); epd_config_save(&p_epd->config); } @@ -282,11 +303,8 @@ static void ble_epd_config_load(ble_epd_t * p_epd) EPD_EN_PIN = p_epd->config.en_pin; EPD_LED_PIN = p_epd->config.led_pin; - epd_driver_set(p_epd->config.driver_id); - p_epd->driver = epd_driver_get(); - // blink LED on start - if (EPD_LED_PIN != 0xFF) + if (EPD_LED_PIN != EPD_CONFIG_EMPTY) { pinMode(EPD_LED_PIN, OUTPUT); EPD_LED_ON(); @@ -352,3 +370,12 @@ uint32_t ble_epd_string_send(ble_epd_t * p_epd, uint8_t * p_string, uint16_t len 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) +{ + // Update calendar on 00:00:00 + if (force_update || (p_epd->calendar_mode && timestamp % 86400 == 0)) { + epd_calendar_update_event_t event = { p_epd, timestamp }; + app_sched_event_put(&event, sizeof(epd_calendar_update_event_t), calendar_update); + } +} diff --git a/EPD/EPD_service.h b/EPD/EPD_service.h index 5c1ca0c..f4d407a 100644 --- a/EPD/EPD_service.h +++ b/EPD/EPD_service.h @@ -10,8 +10,8 @@ * */ -#ifndef EPD_BLE_H__ -#define EPD_BLE_H__ +#ifndef EPD_SERVICE_H__ +#define EPD_SERVICE_H__ #include #include @@ -85,8 +85,17 @@ typedef struct epd_driver_t *driver; /**< current EPD driver */ epd_config_t config; /**< EPD config */ epd_callback_t epd_cmd_cb; /**< EPD callback */ + bool calendar_mode; /**< Calendar mode flag */ } ble_epd_t; +typedef struct +{ + ble_epd_t *p_epd; + uint32_t timestamp; +} epd_calendar_update_event_t; + +#define EPD_CALENDAR_SCHD_EVENT_DATA_SIZE sizeof(epd_calendar_update_event_t) + /**@brief Function for preparing sleep mode. * * @param[in] p_epd EPD Service structure. @@ -130,6 +139,8 @@ void ble_epd_on_ble_evt(ble_epd_t * p_epd, ble_evt_t * p_ble_evt); */ 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); + #endif // EPD_BLE_H__ /** @} */ diff --git a/EPD/UC8176.c b/EPD/UC8176.c index 948c7f1..ebc4d92 100644 --- a/EPD/UC8176.c +++ b/EPD/UC8176.c @@ -31,48 +31,52 @@ #include "nrf_log.h" // commands used by this driver -enum { - CMD_PSR = 0x00, // Panel Setting - CMD_POF = 0x02, // Power OFF - CMD_PON = 0x04, // Power ON - CMD_DSLP = 0x07, // Deep sleep - CMD_DTM1 = 0x10, // Display Start Transmission 1 - CMD_DRF = 0x12, // Display Refresh - CMD_DTM2 = 0x13, // Display Start transmission 2 - CMD_TSC = 0x40, // Temperature Sensor Calibration - CMD_CDI = 0x50, // Vcom and data interval setting - CMD_PTL = 0x90, // Partial Window - CMD_PTIN = 0x91, // Partial In - CMD_PTOUT = 0x92, // Partial Out - CMD_CCSET = 0xE0, // Cascade Setting - CMD_TSSET = 0xE5, // Force Temperauture -} UC8176_CMD; +#define CMD_PSR 0x00 // Panel Setting +#define CMD_POF 0x02 // Power OFF +#define CMD_PON 0x04 // Power ON +#define CMD_DSLP 0x07 // Deep sleep +#define CMD_DTM1 0x10 // Display Start Transmission 1 +#define CMD_DRF 0x12 // Display Refresh +#define CMD_DTM2 0x13 // Display Start transmission 2 +#define CMD_TSC 0x40 // Temperature Sensor Calibration +#define CMD_CDI 0x50 // Vcom and data interval setting +#define CMD_PTL 0x90 // Partial Window +#define CMD_PTIN 0x91 // Partial In +#define CMD_PTOUT 0x92 // Partial Out +#define CMD_CCSET 0xE0 // Cascade Setting +#define CMD_TSSET 0xE5 // Force Temperauture -// Display resolution -#define EPD_4IN2_WIDTH 400 -#define EPD_4IN2_HEIGHT 300 +// PSR registers +#define PSR_RES1 BIT(7) +#define PSR_RES0 BIT(6) +#define PSR_REG BIT(5) +#define PSR_BWR BIT(4) +#define PSR_UD BIT(3) +#define PSR_SHL BIT(2) +#define PSR_SHD BIT(1) +#define PSR_RST BIT(0) -static void EPD_4IN2_PowerOn(void) +static void UC8176_PowerOn(void) { EPD_WriteCommand(CMD_PON); EPD_WaitBusy(LOW, 100); } -static void EPD_4IN2_PowerOff(void) +static void UC8176_PowerOff(void) { EPD_WriteCommand(CMD_POF); EPD_WaitBusy(LOW, 100); } // Read temperature from driver chip -int8_t EPD_4IN2_Read_Temp(void) +int8_t UC8176_Read_Temp(void) { EPD_WriteCommand_SW(CMD_TSC); return (int8_t) EPD_ReadByte_SW(); } // Force temperature (will trigger OTP LUT switch) -void EPD_4IN2_Force_Temp(int8_t value) +void UC8176_Force_Temp(int8_t value) { EPD_WriteCommand_SW(CMD_CCSET); EPD_WriteByte_SW(0x02); @@ -84,15 +88,15 @@ void EPD_4IN2_Force_Temp(int8_t value) function : Turn On Display parameter: ******************************************************************************/ -void EPD_4IN2_Refresh(void) +void UC8176_Refresh(void) { NRF_LOG_DEBUG("[EPD]: refresh begin\n"); - EPD_4IN2_PowerOn(); - NRF_LOG_DEBUG("[EPD]: temperature: %d\n", EPD_4IN2_Read_Temp()); + UC8176_PowerOn(); + NRF_LOG_DEBUG("[EPD]: temperature: %d\n", UC8176_Read_Temp()); EPD_WriteCommand(CMD_DRF); delay(100); - EPD_WaitBusy(LOW, 20000); - EPD_4IN2_PowerOff(); + EPD_WaitBusy(LOW, 30000); + UC8176_PowerOff(); NRF_LOG_DEBUG("[EPD]: refresh end\n"); } @@ -100,34 +104,53 @@ void EPD_4IN2_Refresh(void) function : Initialize the e-Paper register parameter: ******************************************************************************/ -void EPD_4IN2_Init(void) +void UC8176_Init(epd_res_t res, bool bwr) { + EPD_BWR_MODE = bwr; EPD_Reset(HIGH, 10); - EPD_WriteCommand(CMD_PSR); // panel setting - EPD_WriteByte(0x1f); // 400x300 B/W mode, LUT from OTP - - EPD_WriteCommand(CMD_CDI); // VCOM AND DATA INTERVAL SETTING - EPD_WriteByte(0x97); // LUTB=0 LUTW=1 interval=10 -} - -void EPD_4IN2B_V2_Init(void) -{ - EPD_Reset(HIGH, 200); - + uint8_t psr = PSR_UD | PSR_SHL | PSR_SHD | PSR_RST; + if (!EPD_BWR_MODE) psr |= PSR_BWR; + switch (res) { + case EPD_RES_320x300: + EPD_WIDTH = 320; + EPD_HEIGHT = 300; + psr |= PSR_RES0; + break; + case EPD_RES_320x240: + EPD_WIDTH = 320; + EPD_HEIGHT = 240; + psr |= PSR_RES1; + break; + case EPD_RES_200x300: + EPD_WIDTH = 200; + EPD_HEIGHT = 300; + psr |= PSR_RES1 | PSR_RES0; + break; + case EPD_RES_400x300: + default: + EPD_WIDTH = 400; + EPD_HEIGHT = 300; + break; + } + NRF_LOG_DEBUG("[EPD]: PSR=%02x\n", psr); EPD_WriteCommand(CMD_PSR); - EPD_WriteByte(0x0f); // 400x300 B/W/R mode, LUT from OTP + EPD_WriteByte(psr); + + if (!EPD_BWR_MODE) { + EPD_WriteCommand(CMD_CDI); + EPD_WriteByte(0x97); + } } /****************************************************************************** function : Clear screen parameter: ******************************************************************************/ -void EPD_4IN2_Clear(void) +void UC8176_Clear(void) { - uint16_t Width, Height; - Width = (EPD_4IN2_WIDTH % 8 == 0)? (EPD_4IN2_WIDTH / 8 ): (EPD_4IN2_WIDTH / 8 + 1); - Height = EPD_4IN2_HEIGHT; + uint16_t Width = (EPD_WIDTH % 8 == 0)? (EPD_WIDTH / 8 ): (EPD_WIDTH / 8 + 1); + uint16_t Height = EPD_HEIGHT; EPD_WriteCommand(CMD_DTM1); for (uint16_t j = 0; j < Height; j++) { @@ -143,7 +166,7 @@ void EPD_4IN2_Clear(void) } } - EPD_4IN2_Refresh(); + UC8176_Refresh(); } static void _setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h) @@ -164,41 +187,29 @@ static void _setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h) EPD_WriteByte(0x01); } -void EPD_4IN2_Write_Image(uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h) +void UC8176_Write_Image(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 x -= x % 8; // byte boundary w = wb * 8; // byte boundary - if (x + w > EPD_4IN2_WIDTH || y + h > EPD_4IN2_HEIGHT) return; + if (x + w > EPD_WIDTH || y + h > EPD_HEIGHT) return; EPD_WriteCommand(CMD_PTIN); // partial in _setPartialRamArea(x, y, w, h); - EPD_WriteCommand(CMD_DTM2); - for (uint16_t i = 0; i < h; i++) { - for (uint16_t j = 0; j < w / 8; j++) { - EPD_WriteByte(black[j + i * wb]); - } - } - EPD_WriteCommand(CMD_PTOUT); // partial out -} - -void EPD_4IN2B_V2_Write_Image(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 - x -= x % 8; // byte boundary - w = wb * 8; // byte boundary - if (x + w > EPD_4IN2_WIDTH || y + h > EPD_4IN2_HEIGHT) return; - EPD_WriteCommand(CMD_PTIN); // partial in - _setPartialRamArea(x, y, w, h); - EPD_WriteCommand(CMD_DTM1); - 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); + if (EPD_BWR_MODE) { + EPD_WriteCommand(CMD_DTM1); + 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); + } } } EPD_WriteCommand(CMD_DTM2); for (uint16_t i = 0; i < h; i++) { for (uint16_t j = 0; j < w / 8; j++) { - EPD_WriteByte(color ? color[j + i * wb] : 0xFF); + if (EPD_BWR_MODE) + EPD_WriteByte(color ? color[j + i * wb] : 0xFF); + else + EPD_WriteByte(black[j + i * wb]); } } EPD_WriteCommand(CMD_PTOUT); // partial out @@ -208,42 +219,35 @@ void EPD_4IN2B_V2_Write_Image(uint8_t *black, uint8_t *color, uint16_t x, uint16 function : Enter sleep mode parameter: ******************************************************************************/ -void EPD_4IN2_Sleep(void) +void UC8176_Sleep(void) { - EPD_4IN2_PowerOff(); + UC8176_PowerOff(); EPD_WriteCommand(CMD_DSLP); EPD_WriteByte(0XA5); } -const epd_driver_t epd_driver_4in2 = { - .id = EPD_DRIVER_4IN2, - .width = EPD_4IN2_WIDTH, - .height = EPD_4IN2_HEIGHT, - .init = EPD_4IN2_Init, - .clear = EPD_4IN2_Clear, - .send_command = EPD_WriteCommand, - .send_byte = EPD_WriteByte, - .send_data = EPD_WriteData, - .write_image = EPD_4IN2_Write_Image, - .refresh = EPD_4IN2_Refresh, - .sleep = EPD_4IN2_Sleep, - .read_temp = EPD_4IN2_Read_Temp, - .force_temp = EPD_4IN2_Force_Temp, +// Declare driver and models +static epd_driver_t epd_drv_uc8176 = { + .init = UC8176_Init, + .clear = UC8176_Clear, + .write_image = UC8176_Write_Image, + .refresh = UC8176_Refresh, + .sleep = UC8176_Sleep, + .read_temp = UC8176_Read_Temp, + .force_temp = UC8176_Force_Temp, }; -const epd_driver_t epd_driver_4in2bv2 = { - .id = EPD_DRIVER_4IN2B_V2, - .width = EPD_4IN2_WIDTH, - .height = EPD_4IN2_HEIGHT, - .init = EPD_4IN2B_V2_Init, - .clear = EPD_4IN2_Clear, - .send_command = EPD_WriteCommand, - .send_byte = EPD_WriteByte, - .send_data = EPD_WriteData, - .write_image = EPD_4IN2B_V2_Write_Image, - .refresh = EPD_4IN2_Refresh, - .sleep = EPD_4IN2_Sleep, - .read_temp = EPD_4IN2_Read_Temp, - .force_temp = EPD_4IN2_Force_Temp, +const epd_model_t epd_4in2 = { + .id = EPD_4IN2, + .drv = &epd_drv_uc8176, + .res = EPD_RES_400x300, + .bwr = false, +}; + +const epd_model_t epd_4in2bv2 = { + .id = EPD_4IN2B_V2, + .drv = &epd_drv_uc8176, + .res = EPD_RES_400x300, + .bwr = true, }; diff --git a/GUI/Calendar.c b/GUI/Calendar.c index 546b36c..5eb8394 100644 --- a/GUI/Calendar.c +++ b/GUI/Calendar.c @@ -1,6 +1,5 @@ #include "Adafruit_GFX.h" #include "fonts.h" -#include "EPD_driver.h" #include "Lunar.h" #include "Calendar.h" #include "nrf_log.h" @@ -73,11 +72,10 @@ static void DrawMonthDay(Adafruit_GFX *gfx, int16_t x, int16_t y, tm_t *tm, stru } } -void DrawCalendar(uint32_t timestamp) +void DrawCalendar(epd_driver_t *driver, uint32_t timestamp) { tm_t tm = {0}; struct Lunar_Date Lunar; - epd_driver_t *driver = epd_driver_get(); transformTime(timestamp, &tm); @@ -87,10 +85,10 @@ void DrawCalendar(uint32_t timestamp) Adafruit_GFX gfx; - if (driver->id == EPD_DRIVER_4IN2B_V2) - GFX_begin_3c(&gfx, driver->width, driver->height, PAGE_HEIGHT); + if (EPD_BWR_MODE) + GFX_begin_3c(&gfx, EPD_WIDTH, EPD_HEIGHT, PAGE_HEIGHT); else - GFX_begin(&gfx, driver->width, driver->height, PAGE_HEIGHT); + GFX_begin(&gfx, EPD_WIDTH, EPD_HEIGHT, PAGE_HEIGHT); GFX_firstPage(&gfx); do { diff --git a/GUI/Calendar.h b/GUI/Calendar.h index 962b6c3..bc1c21e 100644 --- a/GUI/Calendar.h +++ b/GUI/Calendar.h @@ -2,7 +2,8 @@ #define __CALENDAR_H #include +#include "EPD_driver.h" -void DrawCalendar(uint32_t timestamp); +void DrawCalendar(epd_driver_t *driver, uint32_t timestamp); #endif diff --git a/main.c b/main.c index 51dc129..272a993 100644 --- a/main.c +++ b/main.c @@ -36,7 +36,6 @@ #include "nrf_drv_gpiote.h" #include "nrf_pwr_mgmt.h" #include "EPD_service.h" -#include "Calendar.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" @@ -74,7 +73,7 @@ #define NEXT_CONN_PARAMS_UPDATE_DELAY TIMER_TICKS(30000) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */ #define MAX_CONN_PARAMS_UPDATE_COUNT 3 /**< Number of attempts before giving up the connection parameter negotiation. */ -#define SCHED_MAX_EVENT_DATA_SIZE 0 /**< Maximum size of scheduler events. */ +#define SCHED_MAX_EVENT_DATA_SIZE EPD_CALENDAR_SCHD_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */ #define SCHED_QUEUE_SIZE 10 /**< Maximum number of events in the scheduler queue. */ #define CLOCK_TIMER_INTERVAL TIMER_TICKS(1000) /**< Clock timer interval (ticks). */ @@ -85,49 +84,14 @@ NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */ BLE_ADVERTISING_DEF(m_advertising); /**< Advertising module instance. */ #endif -static uint16_t m_driver_refs = 0; static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle of the current connection. */ static ble_uuid_t m_adv_uuids[] = {{BLE_UUID_EPD_SERVICE, \ EPD_SERVICE_UUID_TYPE}}; /**< Universally unique service identifier. */ BLE_EPD_DEF(m_epd); /**< Structure to identify the EPD Service. */ static uint32_t m_timestamp = 1735689600; /**< Current timestamp. */ -static bool m_calendar_mode = false; /**< Whether we are in calendar mode */ - APP_TIMER_DEF(m_clock_timer_id); /**< Clock timer. */ -static void epd_driver_init() -{ - if (m_driver_refs == 0) { - NRF_LOG_DEBUG("[EPD]: driver init\n"); - DEV_Module_Init(); - } - m_driver_refs++; -} - -static void epd_driver_exit() -{ - m_driver_refs--; - if (m_driver_refs == 0) { - NRF_LOG_DEBUG("[EPD]: driver exit\n"); - DEV_Module_Exit(); - } -} - -static void calendar_update(void * p_event_data, uint16_t event_size) -{ - m_calendar_mode = true; - epd_driver_init(); - m_epd.driver->init(); - DrawCalendar(m_timestamp); - epd_driver_exit(); -} - -static uint32_t calendar_update_schedule(void) -{ - return app_sched_event_put(NULL, 0, calendar_update); -} - /**@brief Callback function for asserts in the SoftDevice. * * @details This function will be called in case of an assert in the SoftDevice. @@ -150,9 +114,7 @@ static void clock_timer_timeout_handler(void * p_context) m_timestamp++; - // Update calendar on 00:00:00 - if (m_calendar_mode && m_timestamp % 86400 == 0) - calendar_update_schedule(); + ble_epd_on_timer(&m_epd, m_timestamp, false); } /**@brief Function for the Event Scheduler initialization. @@ -217,14 +179,9 @@ bool epd_cmd_callback(uint8_t cmd, uint8_t *data, uint16_t len) m_timestamp = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; m_timestamp += (len > 4 ? (int8_t)data[4] : 8) * 60 * 60; // timezone app_timer_start(m_clock_timer_id, CLOCK_TIMER_INTERVAL, NULL); - calendar_update_schedule(); + ble_epd_on_timer(&m_epd, m_timestamp, true); return true; - case EPD_CMD_CLEAR: - case EPD_CMD_DISPLAY: - m_calendar_mode = false; - break; - case EPD_CMD_SYS_SLEEP: sleep_mode_enter(); return true; @@ -385,7 +342,7 @@ static void on_adv_evt(ble_adv_evt_t ble_adv_evt) case BLE_ADV_EVT_IDLE: NRF_LOG_INFO("advertising timeout\n"); if (m_epd.config.wakeup_pin != 0xFF) { - if (m_calendar_mode) + if (m_epd.calendar_mode) setup_wakeup_pin(m_epd.config.wakeup_pin); else sleep_mode_enter(); @@ -409,13 +366,11 @@ static void on_ble_evt(ble_evt_t * p_ble_evt) case BLE_GAP_EVT_CONNECTED: NRF_LOG_INFO("CONNECTED\n"); m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; - epd_driver_init(); break; case BLE_GAP_EVT_DISCONNECTED: NRF_LOG_INFO("DISCONNECTED\n"); m_conn_handle = BLE_CONN_HANDLE_INVALID; - epd_driver_exit(); #if !defined(S112) advertising_start(); #endif @@ -642,18 +597,17 @@ static void advertising_init(void) #endif } -#if NRF_MODULE_ENABLED(NRF_LOG) -static uint32_t timestamp_func(void) +// return current timestamp +uint32_t timestamp(void) { return m_timestamp; } -#endif /**@brief Function for initializing the nrf log module. */ static void log_init(void) { - APP_ERROR_CHECK(NRF_LOG_INIT(timestamp_func)); + APP_ERROR_CHECK(NRF_LOG_INIT(timestamp)); #if defined(S112) NRF_LOG_DEFAULT_BACKENDS_INIT(); #endif