Files
blozi-etag/Firmware/src/epd.c
2022-04-29 18:46:35 +02:00

247 lines
6.3 KiB
C
Executable File

#include <stdint.h>
#include "tl_common.h"
#include "main.h"
#include "epd.h"
#include "epd_spi.h"
#include "epd_bw.h"
#include "epd_bwr.h"
#include "drivers.h"
#include "stack/ble/ble.h"
#include "battery.h"
#include "OneBitDisplay.h"
#include "TIFF_G4.h"
extern const uint8_t ucMirror[];
#include "Roboto_Black_80.h"
#include "font_60.h"
#include "font16.h"
#include "font30.h"
RAM uint8_t epd_model = 0; // 0 = Undetected, 1 = BW, 2 = BWR
const char* epd_model_string[] = {"NC","BW","BWR"};
RAM uint8_t epd_update_state = 0;
const char* BLE_conn_string[] = {"", "B"};
RAM uint8_t epd_temperature_is_read = 0;
RAM uint8_t epd_temperature = 0;
uint8_t epd_buffer[epd_buffer_size];
uint8_t epd_temp[epd_buffer_size]; // for OneBitDisplay to draw into
OBDISP obd; // virtual display structure
TIFFIMAGE tiff;
// Here we detect what E-Paper display is connected
_attribute_ram_code_ void EPD_detect_model(void)
{
EPD_init();
// system power
EPD_POWER_ON();
WaitMs(10);
// Reset the EPD driver IC
gpio_write(EPD_RESET, 0);
WaitMs(10);
gpio_write(EPD_RESET, 1);
WaitMs(10);
// Here we neeed to detect it
if (EPD_BWR_detect())
{
epd_model = 2;
}
else
{
epd_model = 1;
}
EPD_POWER_OFF();
}
_attribute_ram_code_ uint8_t EPD_read_temp(void)
{
if (epd_temperature_is_read)
return epd_temperature;
if (!epd_model)
{
EPD_detect_model();
}
EPD_init();
// system power
EPD_POWER_ON();
WaitMs(5);
// Reset the EPD driver IC
gpio_write(EPD_RESET, 0);
WaitMs(10);
gpio_write(EPD_RESET, 1);
WaitMs(10);
if (epd_model == 1)
epd_temperature = EPD_BW_read_temp();
else if (epd_model == 2)
epd_temperature = EPD_BWR_read_temp();
EPD_POWER_OFF();
epd_temperature_is_read = 1;
return epd_temperature;
}
_attribute_ram_code_ void EPD_Display(unsigned char *image, int size, uint8_t full_or_partial)
{
if (!epd_model)
{
EPD_detect_model();
}
EPD_init();
// system power
EPD_POWER_ON();
WaitMs(5);
// Reset the EPD driver IC
gpio_write(EPD_RESET, 0);
WaitMs(10);
gpio_write(EPD_RESET, 1);
WaitMs(10);
if (epd_model == 1)
epd_temperature = EPD_BW_Display(image, size, full_or_partial);
else if (epd_model == 2)
epd_temperature = EPD_BWR_Display(image, size, full_or_partial);
epd_temperature_is_read = 1;
epd_update_state = 1;
}
_attribute_ram_code_ void epd_set_sleep(void)
{
if (!epd_model)
{
EPD_detect_model();
}
if (epd_model == 1)
EPD_BW_set_sleep();
else if (epd_model == 2)
EPD_BWR_set_sleep();
EPD_POWER_OFF();
epd_update_state = 0;
}
_attribute_ram_code_ uint8_t epd_state_handler(void)
{
switch (epd_update_state)
{
case 0:
// Nothing todo
break;
case 1: // check if refresh is done and sleep epd if so
if (epd_model == 1)
{
if (!EPD_IS_BUSY())
epd_set_sleep();
}
else
{
if (EPD_IS_BUSY())
epd_set_sleep();
}
break;
}
return epd_update_state;
}
_attribute_ram_code_ void FixBuffer(uint8_t *pSrc, uint8_t *pDst)
{
int x, y;
uint8_t *s, *d;
for (y = 0; y < 16; y++)
{ // byte rows
d = &pDst[y];
s = &pSrc[y * 250];
for (x = 0; x < 250; x++)
{
d[x * 16] = ~ucMirror[s[249 - x]]; // invert and flip
} // for x
} // for y
}
_attribute_ram_code_ void TIFFDraw(TIFFDRAW *pDraw)
{
uint8_t uc = 0, ucSrcMask, ucDstMask, *s, *d;
int x, y;
s = pDraw->pPixels;
y = pDraw->y; // current line
d = &epd_buffer[(249 * 16) + (y / 8)]; // rotated 90 deg clockwise
ucDstMask = 0x80 >> (y & 7); // destination mask
ucSrcMask = 0; // src mask
for (x = 0; x < pDraw->iWidth; x++)
{
// Slower to draw this way, but it allows us to use a single buffer
// instead of drawing and then converting the pixels to be the EPD format
if (ucSrcMask == 0)
{ // load next source byte
ucSrcMask = 0x80;
uc = *s++;
}
if (!(uc & ucSrcMask))
{ // black pixel
d[-(x * 16)] &= ~ucDstMask;
}
ucSrcMask >>= 1;
}
}
_attribute_ram_code_ void epd_display_tiff(uint8_t *pData, int iSize)
{
// test G4 decoder
memset(epd_buffer, 0xff, epd_buffer_size); // clear to white
TIFF_openRAW(&tiff, 250, 122, BITDIR_MSB_FIRST, pData, iSize, TIFFDraw);
TIFF_setDrawParameters(&tiff, 65536, TIFF_PIXEL_1BPP, 0, 0, 250, 122, NULL);
TIFF_decode(&tiff);
TIFF_close(&tiff);
EPD_Display(epd_buffer, epd_buffer_size, 1);
}
extern uint8_t mac_public[6];
_attribute_ram_code_ void epd_display(uint32_t time_is, uint16_t battery_mv, int16_t temperature, uint8_t full_or_partial)
{
if (epd_update_state)
return;
obdCreateVirtualDisplay(&obd, 250, 122, epd_temp);
obdFill(&obd, 0, 0); // fill with white
char buff[100];
sprintf(buff, "ESL_%02X%02X%02X - %s", mac_public[2], mac_public[1], mac_public[0], epd_model_string[epd_model]);
obdWriteStringCustom(&obd, (GFXfont *)&Dialog_plain_16, 1, 17, (char *)buff, 1);
sprintf(buff, "%s", BLE_conn_string[ble_get_connected()]);
obdWriteStringCustom(&obd, (GFXfont *)&Dialog_plain_16, 232, 20, (char *)buff, 1);
sprintf(buff, "%02d:%02d", ((time_is / 60) / 60) % 24, (time_is / 60) % 60);
obdWriteStringCustom(&obd, (GFXfont *)&DSEG14_Classic_Mini_Regular_40, 50, 65, (char *)buff, 1);
sprintf(buff, "%d'C", EPD_read_temp());
obdWriteStringCustom(&obd, (GFXfont *)&Special_Elite_Regular_30, 10, 95, (char *)buff, 1);
sprintf(buff, "Battery %dmV", battery_mv);
obdWriteStringCustom(&obd, (GFXfont *)&Dialog_plain_16, 10, 120, (char *)buff, 1);
FixBuffer(epd_temp, epd_buffer);
EPD_Display(epd_buffer, epd_buffer_size, full_or_partial);
}
_attribute_ram_code_ void epd_display_char(uint8_t data)
{
int i;
for (i = 0; i < epd_buffer_size; i++)
{
epd_buffer[i] = data;
}
EPD_Display(epd_buffer, epd_buffer_size, 1);
}
_attribute_ram_code_ void epd_clear(void)
{
memset(epd_buffer, 0x00, epd_buffer_size);
}