mirror of
https://github.com/fsender/readguy.git
synced 2026-04-09 16:50:34 +08:00
274 lines
9.2 KiB
C++
274 lines
9.2 KiB
C++
/******************** F r i e n d s h i p E n d e r ********************
|
|
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
|
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
|
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
|
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
|
* @file guy_epdbase.cpp
|
|
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
|
* @brief readguy EPD 驱动程序 公共基类. 所有驱动都要依赖此文件.
|
|
* @version 1.0
|
|
* @date 2023-09-21
|
|
|
|
* @attention
|
|
* Copyright (c) 2022-2023 FriendshipEnder
|
|
*
|
|
* Apache License, Version 2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "guy_epdbase.h"
|
|
#include <spi.h>
|
|
|
|
readguyEpdBase::readguyEpdBase() {
|
|
};
|
|
|
|
readguyEpdBase::~readguyEpdBase() {
|
|
};
|
|
|
|
void readguyEpdBase::DigitalWrite(int pin, int value) {
|
|
if(pin>=0) digitalWrite(pin, value);
|
|
}
|
|
|
|
int readguyEpdBase::DigitalRead(int pin) {
|
|
return (pin>=0)?digitalRead(pin):1;
|
|
}
|
|
|
|
void readguyEpdBase::DelayMs(unsigned int delaytime) {
|
|
delay(delaytime);
|
|
}
|
|
void readguyEpdBase::BeginTransfer(){
|
|
if(spi_tr_press!=nullptr) spi_tr_press();
|
|
if(!in_trans && CS_PIN>=0) digitalWrite(CS_PIN, LOW);
|
|
in_trans++;
|
|
}
|
|
void readguyEpdBase::EndTransfer(){
|
|
if(in_trans) in_trans--;
|
|
if(!in_trans && CS_PIN>=0) digitalWrite(CS_PIN, HIGH);
|
|
if(spi_tr_release!=nullptr) spi_tr_release();
|
|
}
|
|
void readguyEpdBase::SpiTransfer(unsigned char data) {
|
|
if(in_trans) {
|
|
_spi->transfer(data);
|
|
return;
|
|
}
|
|
if(CS_PIN>=0) digitalWrite(CS_PIN, LOW);
|
|
_spi->transfer(data);
|
|
if(CS_PIN>=0) digitalWrite(CS_PIN, HIGH);
|
|
}
|
|
int readguyEpdBase::IfInit(SPIClass &c,int8_t cs,int8_t dc,int8_t rst,int8_t busy) {
|
|
//static uint8_t IfHadInit=0;
|
|
//if(IfHadInit) return;
|
|
CS_PIN = cs;
|
|
DC_PIN = dc;
|
|
RST_PIN = rst;
|
|
BUSY_PIN = busy;
|
|
if(CS_PIN>=0) pinMode(CS_PIN , OUTPUT);
|
|
if(RST_PIN>=0) pinMode(RST_PIN , OUTPUT);
|
|
DigitalWrite(RST_PIN,HIGH);
|
|
if(DC_PIN>=0) pinMode(DC_PIN , OUTPUT);
|
|
if(BUSY_PIN>=0) pinMode(BUSY_PIN, INPUT);
|
|
_spi = &c;
|
|
|
|
//_spi->begin();
|
|
//_spi->beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
|
|
//IfHadInit = 1;
|
|
return 0;
|
|
}
|
|
void readguyEpdBase::guy_epdCmd(unsigned char command)
|
|
{
|
|
#ifdef MEPD_DEBUG_WAVE
|
|
if(dat_combo) {
|
|
if(dat_combo>MEPD_DEBUG_WAVE) Serial.printf("\nTotal %d data written.",dat_combo);
|
|
Serial.write('\n');
|
|
}
|
|
dat_combo=0;
|
|
Serial.printf("Cmd %02x: ", command);
|
|
#endif
|
|
DigitalWrite(DC_PIN, LOW);
|
|
SpiTransfer(command);
|
|
DigitalWrite(DC_PIN, HIGH);
|
|
}
|
|
void readguyEpdBase::guy_epdParam(unsigned char data)
|
|
{
|
|
#ifdef MEPD_DEBUG_WAVE
|
|
if(dat_combo==MEPD_DEBUG_WAVE){
|
|
Serial.print("...");
|
|
}
|
|
else if(dat_combo<MEPD_DEBUG_WAVE){
|
|
Serial.printf("%02x ",data);
|
|
}
|
|
dat_combo++;
|
|
#endif
|
|
SpiTransfer(data);
|
|
}
|
|
void readguyEpdBase::guy_epdBusy(int32_t maxt) {
|
|
#if (defined(MEPD_DEBUG_WAVE) || defined(MEPD_DEBUG_WAITTIME))
|
|
Serial.printf("\nWaitUntilIdle: max %d ms.\n",maxt);
|
|
#endif
|
|
//if(spi_tr_release!=nullptr) spi_tr_release();
|
|
uint32_t mls = millis();
|
|
if(maxt<0){ //HIGH: idle, LOW: busy
|
|
while((BUSY_PIN<0 || !DigitalRead(BUSY_PIN)) && millis()-mls<=uint32_t(-maxt))
|
|
DelayMs(1);
|
|
}
|
|
else{ //LOW: idle, HIGH: busy
|
|
while(DigitalRead(BUSY_PIN) && millis()-mls<=uint32_t(maxt))
|
|
DelayMs(1);
|
|
}
|
|
#if (defined(MEPD_DEBUG_WAVE) || defined(MEPD_DEBUG_WAITTIME))
|
|
Serial.printf("Wait %lu ms.\n",millis()-mls);
|
|
#endif
|
|
//if(spi_tr_press!=nullptr) spi_tr_press();
|
|
}
|
|
void readguyEpdBase::SetMemory() {
|
|
guy_epdCmd(0x44);
|
|
/* x point must be the multiple of 8 or the last 3 bits will be ignored */
|
|
guy_epdParam(0);
|
|
guy_epdParam(((drv_width()-1) >> 3) & 0xFF);
|
|
guy_epdCmd(0x45);
|
|
guy_epdParam(0);
|
|
guy_epdParam(0);
|
|
guy_epdParam((drv_height()-1) & 0xFF);
|
|
guy_epdParam(((drv_height()-1) >> 8) & 0xFF);
|
|
|
|
guy_epdCmd(0x4E);
|
|
/* x point must be the multiple of 8 or the last 3 bits will be ignored */
|
|
guy_epdParam(0);
|
|
guy_epdCmd(0x4F);
|
|
guy_epdParam(0);
|
|
guy_epdParam(0);
|
|
}
|
|
void readguyEpdBase::Reset(uint32_t minTime)
|
|
{
|
|
if(RST_PIN<0) return;
|
|
//DigitalWrite(RST_PIN, HIGH);
|
|
//DelayMs(minTime);
|
|
DigitalWrite(RST_PIN, LOW); //module reset
|
|
DelayMs(minTime);
|
|
DigitalWrite(RST_PIN, HIGH);
|
|
DelayMs(minTime);
|
|
}
|
|
//void readguyEpdBase::drv_draw16grey(const uint8_t *d16bit){ //不支持的话什么都不做
|
|
|
|
void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y){
|
|
#ifndef FLOYD_STEINBERG_DITHERING
|
|
static const uint8_t bayer_tab [64]={
|
|
0, 32, 8, 40, 2, 34, 10, 42,
|
|
48, 16, 56, 24, 50, 18, 58, 26,
|
|
12, 44, 4, 36, 14, 46, 6, 38,
|
|
60, 28, 52, 20, 62, 30, 54, 22,
|
|
3, 35, 11, 43, 1, 33, 9, 41,
|
|
51, 19, 59, 27, 49, 17, 57, 25,
|
|
15, 47, 7, 39, 13, 45, 5, 37,
|
|
63, 31, 55, 23, 61, 29, 53, 21
|
|
};
|
|
#endif
|
|
const uint_fast16_t w = (spr.width()+7)>>3;
|
|
if((!w) || (!spr.height())) return;
|
|
uint16_t *readBuff = new uint16_t[spr.width()];
|
|
uint8_t *writeBuff = new uint8_t[w];
|
|
#ifdef FLOYD_STEINBERG_DITHERING
|
|
int16_t *floyd_tab[2];
|
|
floyd_tab[0] = new int16_t [spr.width()];
|
|
floyd_tab[1] = new int16_t [spr.width()];
|
|
for(int j=0;j<spr.width();j++){ floyd_tab[0][j] = 0; floyd_tab[1][j] = 0; }
|
|
#endif
|
|
sprbase.fillRect(x,y,spr.width(),spr.height(),1);
|
|
for(int_fast16_t i=0;i<(int_fast16_t)spr.height();i++){
|
|
spr.readRect(0,i,spr.width(),1,readBuff);
|
|
#ifdef FLOYD_STEINBERG_DITHERING
|
|
uint_fast8_t buff8bit=0;
|
|
for(int_fast16_t j=0;j<(int_fast16_t)spr.width();j++){
|
|
int_fast16_t flodelta = floyd_tab[i&1][j]+(int_fast16_t)(greysc(readBuff[j])<<4);
|
|
if(flodelta>=2048) {
|
|
//spr.drawPixel(j,i,1);
|
|
buff8bit |= 1<<((~j)&7);
|
|
flodelta -= 4095;
|
|
}
|
|
if((j&7)==7 || j==((int_fast16_t)spr.width()-1)){
|
|
writeBuff[j>>3]=buff8bit;
|
|
buff8bit=0;
|
|
}
|
|
//计算出读取到的颜色, 然后与128比较, 如果小于128, 显示黑色,否则显示白色
|
|
//else { spr.drawPixel(j,i,0); }
|
|
/*if(j!=(int_fast16_t)spr.width()-1) {
|
|
floyd_tab[ i&1 ][j+1] += (flodelta*7)>>4;
|
|
floyd_tab[!(i&1)][j+1] += (flodelta )>>4;
|
|
}
|
|
if(j) { floyd_tab[!(i&1)][j-1] += (flodelta*3)>>4; }
|
|
{ floyd_tab[!(i&1)][j ] += (flodelta*5)>>4; }*/
|
|
if(j!=(int_fast16_t)spr.width()-1)
|
|
{ floyd_tab[i&1] [j+1] += (flodelta*7)>>4; }
|
|
if(j) { floyd_tab[!(i&1)][j-1] += (flodelta*3)>>4; }
|
|
{ floyd_tab[!(i&1)][j ] += (flodelta*5)>>4; }
|
|
if(j!=(int_fast16_t)spr.width()-1)
|
|
{ floyd_tab[!(i&1)][j+1] += (flodelta )>>4; }
|
|
}
|
|
for(int floi=0;floi<spr.width();floi++) floyd_tab[i&1][floi]=0;
|
|
#else
|
|
for(int_fast16_t j=0;j<w;j++){
|
|
uint_fast8_t buff8bit=0;
|
|
for(uint_fast8_t b=0;b<8;b++)
|
|
buff8bit |= (bayer_tab[(b<<3)|(i&7)]<(greysc(readBuff[(j<<3)+b])>>2))<<(7-b);
|
|
writeBuff[j]=buff8bit;
|
|
}
|
|
#endif
|
|
sprbase.drawBitmap(x,y+i,writeBuff,spr.width(),1,1,0);
|
|
}
|
|
_display((const uint8_t*)sprbase.getBuffer());
|
|
delete []readBuff;
|
|
delete []writeBuff;
|
|
#ifdef FLOYD_STEINBERG_DITHERING
|
|
delete [] floyd_tab[0] ;
|
|
delete [] floyd_tab[1] ;
|
|
#endif
|
|
}
|
|
//不支持的话使用单色抖动刷屏
|
|
void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y){
|
|
//Serial.println("drv_draw16grey fx");
|
|
const uint_fast16_t w = (spr.width()+7)>>3;
|
|
if((!w) || (!spr.height())) return;
|
|
uint16_t *readBuff = new uint16_t[spr.width()];
|
|
uint8_t *writeBuff = new uint8_t[w];
|
|
sprbase.fillRect(x,y,spr.width(),spr.height(),1);
|
|
bool negativeOrder=(drv_supportGreyscaling()==-16);
|
|
drv_fullpart(0);
|
|
_display((const uint8_t*)sprbase.getBuffer()); //先对区域慢刷白屏确保颜色正确
|
|
drv_fullpart(1);
|
|
for(uint_fast8_t k=1;k<16;k++){ //亮度为15的不用绘制,因为本来就是白色
|
|
for(int i=0;i<spr.height();i++){
|
|
spr.readRect(0,i,spr.width(),1,readBuff);
|
|
for(uint_fast16_t j=0;j<w;j++){
|
|
uint_fast8_t buff8bit=0;
|
|
for(uint_fast8_t b=0;b<8;b++){
|
|
//uint_fast8_t cg=greysc(readBuff[j*8+b])/16
|
|
uint_fast8_t cg=greysc(readBuff[(j<<3)+b])>>4;
|
|
if(negativeOrder)
|
|
buff8bit |= (cg<k)<<((~b)&7);
|
|
else{
|
|
if(cg==15) continue; //白色不考虑
|
|
buff8bit |= (cg>=((~k)&15))<<((~b)&7);
|
|
}
|
|
}
|
|
//sprbase.drawPixel(x+j,y+i,(greysc(readBuff[j])/16)==(15-k));
|
|
writeBuff[j]=buff8bit^0xff;
|
|
}
|
|
sprbase.drawBitmap(x,y+i,writeBuff,spr.width(),1,1,0);
|
|
}
|
|
drv_draw16grey_step((const uint8_t*)sprbase.getBuffer(),k); //使用灰度显示函数
|
|
}
|
|
delete []readBuff;
|
|
delete []writeBuff;
|
|
} /* END OF FILE. ReadGuy project.
|
|
Copyright (C) 2023 FriendshipEnder. */ |