update to 1.1.1 version

This commit is contained in:
fsender
2023-10-20 18:41:20 +08:00
parent 8d19d9c1ea
commit 26a041c3b9
24 changed files with 21568 additions and 680 deletions

View File

@@ -59,17 +59,42 @@
// ------------------ definations - 定义 -
//#define INDEV_DEBUG 1 //debug专用, 正常开机从NVS读取引脚配置数据, 取消注释则每次开机需要重新配置
#define DYNAMIC_PIN_SETTINGS //使用静态的数据 !!!注意:注释此选项编写的程序是不支持跨平台运行的!!!
#define READGUY_ENABLE_WIFI //启用WIFI配网功能.必须先启用 #define DYNAMIC_PIN_SETTINGS
#define READGUY_USE_LITTLEFS 1 //取消注释以使用LittleFS,注释则用SPIFFS
#define BTN_LOOPTASK_STACK 1024 //ESP32按键服务任务的栈空间大小
#define BTN_LOOPTASK_CORE_ID 0 //ESP32按键服务任务运行在哪个核心
#define BTN_LOOPTASK_PRIORITY 4 //ESP32按键服务任务的优先级
#define BTN_LOOPTASK_DELAY 10 //按键任务间隔多久调用一次,单位毫秒
#define ESP8266_SPI_FREQUENCY 20000000 //使用ESP8266时, SPI速率
#define ESP32_DISP_FREQUENCY 20000000 //使用ESP32且屏幕与SD卡用不同的SPI总线时,屏幕速率
#define ESP32_SD_SPI_FREQUENCY 20000000 //注意ESP32在与SD卡共享SPI时,屏幕依据SD_SPI的速率
/// @brief 使用静态的数据 !!!注意:注释此选项编写的程序是不支持跨平台运行的!!!
/// @note 相比于禁用WiFi配网功能, 禁用此功能减少的flash并不多, 为保证程序可在不同屏幕上运行, 请不要注释此选项
#define DYNAMIC_PIN_SETTINGS
/// @brief 启用WIFI配网功能.必须先启用 #define DYNAMIC_PIN_SETTINGS. 此选项对 ESP32xx 会减少大量flash.
#define READGUY_ENABLE_WIFI
/// @brief 启用I2C功能. 可用于联网时钟, 温度计, 陀螺仪等外设. 目前暂不支持库内使用类似函数. 仅可以提供引脚定义
#define READGUY_ENABLE_I2C
/// @brief 使用LittleFS作为片上文件系统, 注释此行则用SPIFFS(功能少, 不好用)
#define READGUY_USE_LITTLEFS 1
/// @brief ESP32按键服务任务的栈空间大小, 不建议普通用户更改. 默认值1024字节. 小于此大小会使程序栈溢出.
#define BTN_LOOPTASK_STACK 1024
/// @brief ESP32按键服务任务运行在哪个核心. 通常运行在核心0上.
#define BTN_LOOPTASK_CORE_ID 0
/// @brief ESP32按键服务任务的优先级. 高于arduino默认任务即可
#define BTN_LOOPTASK_PRIORITY 3
/// @brief 按键任务间隔多久调用一次, 默认为20毫秒. 对于需要精确读取按钮的程序, 请酌情减小此数值
#define BTN_LOOPTASK_DELAY 20
/// @brief 使用ESP8266时, 屏幕和SD卡的SPI速率. 默认为20MHz.
#define ESP8266_SPI_FREQUENCY 20000000
/// @brief 使用ESP32且屏幕与SD卡用不同的SPI总线时, 驱动屏幕的SPI速率
#define ESP32_DISP_FREQUENCY 20000000
/// @brief ESP32驱动SD卡的速率. 当ESP32在与SD卡共享SPI时, 屏幕依据此处的速率.
#define ESP32_SD_SPI_FREQUENCY 20000000
/// @brief debug专用, 请保持处于注释状态. 正常开机从NVS读取引脚配置数据, 取消注释则每次开机需要重新配置
//#define INDEV_DEBUG 1
#ifndef DYNAMIC_PIN_SETTINGS
#ifdef ESP8266
@@ -86,8 +111,9 @@
#define READGUY_sd_miso -1 // 目标sd卡的 MISO 引脚, sd_share_spi == 1 时无效
#define READGUY_sd_mosi -1 // 目标sd卡的 MOSI 引脚, sd_share_spi == 1 时无效
#define READGUY_sd_sclk -1 // 目标sd卡的 SCLK 引脚, sd_share_spi == 1 时无效
#define READGUY_sd_cs 0 // 目标sd卡的 CS 引脚
#define READGUY_i2c_sda -1 // 目标i2c总线的SDA引脚, 当且仅当启用i2c总线时才生效
#define READGUY_i2c_scl -1 // 目标i2c总线的SCL引脚, 当且仅当启用i2c总线时才生效
//按键驱动部分, 为负代表高触发, 否则低触发,
//注意, 这里的io编号是加1的, 即 1或-1 代表 gpio0 的低触发/高触发
#define READGUY_btn1 ( 5+1) //按键1,注意需要+1,这里示例已经加了 设置为负的来允许高电平触发
@@ -112,6 +138,8 @@
#define READGUY_sd_mosi 15 // 目标sd卡的 MOSI 引脚, sd_share_spi == 1 时无效
#define READGUY_sd_sclk 14 // 目标sd卡的 SCLK 引脚, sd_share_spi == 1 时无效
#define READGUY_sd_cs 13 // 目标sd卡的 CS 引脚
#define READGUY_i2c_sda -1 // 目标i2c总线的SDA引脚, 当且仅当启用i2c总线时才生效
#define READGUY_i2c_scl -1 // 目标i2c总线的SCL引脚, 当且仅当启用i2c总线时才生效
//按键驱动部分, 为负代表高触发, 否则低触发,
//注意, 这里的io编号是加1的, 即 1或-1 代表 gpio0 的低触发/高触发

View File

@@ -228,7 +228,7 @@ void drv_base::drv_draw16grey_step(std::function<uint8_t(int)> f, int step){
if(step==1){
greyHQ=3;
drv_setDepth(3);
drv_fullpart(1); //开始
drv_fullpart(1); //开始
}
if(step==3) drv_setDepth(2);
if(step==5) drv_setDepth(1);

View File

@@ -32,24 +32,27 @@
//#define MEPD_DEBUG_WAVE 16 //取消此行注释来监视SPI的通信数据 (用于debug), 可以查看主控和屏幕的通信数据
//#define MEPD_DEBUG_WAITTIME //显示墨水屏的刷新时间, 单位是毫秒
#define FLOYD_STEINBERG_DITHERING //默认使用性能更好的floyd steinberg抖动算法, 取消注释则使用bayer图案抖动算法
#define FLOYD_STEINBERG_DITHERING //默认使用更好的floyd steinberg抖动算法,取消注释则用bayer图案抖动算法
#define FLOYD_DITHERING_16GREY //使用更好的floyd steinberg抖动算法显示16阶灰度,取消注释则使用阈值填充
// ***********************************************************************
//设备设置: 取消对应设备就可以直接禁用掉对应设备
//如果程序不想支持此型号(为了节省flash),请注释掉这一行, 实测根本不会节省多少空间
#define READGUY_DEV_154A 0
#define READGUY_DEV_154B 1
#define READGUY_DEV_213A 2
#define READGUY_DEV_213B 3
#define READGUY_DEV_266A 4
#define READGUY_DEV_270B 5
#define READGUY_DEV_290A 6
#define READGUY_DEV_290B 7
#define READGUY_DEV_370A 8
#define READGUY_DEV_420A 9
#define READGUY_DEV_420B 10
#define MEPD_DEBUG_DISPLAY 11 //使用LCD显示屏幕来debug
//非常不建议用户在应用程序中禁用掉设备. 实测根本不会节省很多的空间. 如果要节省代码占用的flash空间,
//请在字库上下功夫.
//如果程序不想支持此型号(为了节省flash),请注释掉这一行, 实测每个设备只能节省100字节左右的flash空间
#define READGUY_DEV_154A 0 //1.54寸标准, 甘草酸不酸使用的1.54默认屏幕型号. 1.54汉朔价签也选这个
#define READGUY_DEV_154B 1 //1.54寸Lilygo, lilygo的1.54触摸和1.54背光墨水屏. GDEH0154D67
#define READGUY_DEV_213A 2 //2.13寸汉朔价签, 价格便宜, 兼容性好. 夏襄居士单词卡用 GDE0213B1
#define READGUY_DEV_213B 3 //2.13寸三色, 分辨率低212x104, 部分价签也用这个屏 易老化
#define READGUY_DEV_266A 4 //2.66寸Vusion价签, 黑白双色.
#define READGUY_DEV_270B 5 //2.7寸佳显触摸墨水屏, 佳显官方店有售: 2.7寸触摸墨水屏.
#define READGUY_DEV_290A 6 //2.9寸A01, 甘草酸不酸2.9寸A01型号. 显示性能一般
#define READGUY_DEV_290B 7 //2.9寸T94背光, 甘草酸不酸2.9寸T94型号. 显示性能更好, 支持前置光
#define READGUY_DEV_370A 8 //3.7寸高DPI墨水屏, 480x280分辨率, 显示效果非常好
#define READGUY_DEV_420A 9 //4.2寸HINK黑白价签, 汉朔价签, 汉朔三色价签通用. 速度快, 但效果一般
#define READGUY_DEV_420B 10 //4.2寸WF丝印, 部分价签也用此型号屏, 排线有WF开头的丝印
#define MEPD_DEBUG_DISPLAY 11 //使用LCD显示屏幕来debug. 前往ctg_stack_c_defines.h修改兼容的屏幕.
#endif /* END OF FILE. ReadGuy project.
Copyright (C) 2023 FriendshipEnder. */

View File

@@ -178,7 +178,7 @@ void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
63, 31, 55, 23, 61, 29, 53, 21
};
#endif
const uint_fast16_t w = (spr.width()+7)>>3;
const uint32_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];
@@ -189,39 +189,39 @@ void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
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++){
for(int32_t i=0;i<(int32_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) {
for(int32_t j=0;j<(int32_t)spr.width();j++){
int32_t flodelta = floyd_tab[i&1][j]+(int32_t)((greysc(readBuff[j])<<8)|greysc(readBuff[j]));
if(flodelta>=0x8000) {
//spr.drawPixel(j,i,1);
buff8bit |= 1<<((~j)&7);
flodelta -= 4095;
flodelta -= 0xffff;
}
if((j&7)==7 || j==((int_fast16_t)spr.width()-1)){
if((j&7)==7 || j==((int32_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) {
/*if(j!=(int32_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)
if(j!=(int32_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)
if(j!=(int32_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++){
for(int32_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);
@@ -241,23 +241,46 @@ void readguyEpdBase::drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_
//不支持的话使用单色抖动刷屏
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;
const uint32_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_DITHERING_16GREY
int16_t *floyd_tab[2];
floyd_tab[0] = new int16_t [spr.width()];
floyd_tab[1] = new int16_t [spr.width()];
#endif
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的不用绘制,因为本来就是白色
#ifdef FLOYD_DITHERING_16GREY
for(int j=0;j<spr.width();j++){ floyd_tab[0][j] = 0; floyd_tab[1][j] = 0; }
#endif
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++){
for(uint32_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
#ifdef FLOYD_DITHERING_16GREY
uint_fast8_t cg=0;
int32_t fd = floyd_tab[i&1][(j<<3)+b]+(int32_t)((greysc(readBuff[(j<<3)+b])<<8)|greysc(readBuff[(j<<3)+b]));
while(fd>=0x800) {
cg++;
if(fd>=0) fd -= 0x1000;
}
if(fd<0) fd++;
if((j<<3)+b!=(uint32_t)spr.width()-1)
{ floyd_tab[i&1] [(j<<3)+b+1] += (fd*7)>>4; }
if((j<<3)+b) { floyd_tab[!(i&1)][(j<<3)+b-1] += (fd*3)>>4; }
{ floyd_tab[!(i&1)][(j<<3)+b ] += (fd*5)>>4; }
if((j<<3)+b!=(uint32_t)spr.width()-1)
{ floyd_tab[!(i&1)][(j<<3)+b+1] += (fd )>>4; }
#else
uint_fast8_t cg=greysc(readBuff[(j<<3)+b])>>4;
#endif
if(negativeOrder)
buff8bit |= (cg<k)<<((~b)&7);
else{
@@ -268,11 +291,18 @@ void readguyEpdBase::drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16
//sprbase.drawPixel(x+j,y+i,(greysc(readBuff[j])/16)==(15-k));
writeBuff[j]=buff8bit^0xff;
}
#ifdef FLOYD_DITHERING_16GREY
for(int floi=0;floi<spr.width();floi++) floyd_tab[i&1][floi]=0;
#endif
sprbase.drawBitmap(x,y+i,writeBuff,spr.width(),1,1,0);
}
drv_draw16grey_step((const uint8_t*)sprbase.getBuffer(),k); //使用灰度显示函数
}
delete []readBuff;
delete []writeBuff;
#ifdef FLOYD_DITHERING_16GREY
delete [] floyd_tab[0] ;
delete [] floyd_tab[1] ;
#endif
} /* END OF FILE. ReadGuy project.
Copyright (C) 2023 FriendshipEnder. */

View File

@@ -86,7 +86,7 @@ public:
* @param gamma_on 是否对灰度值进行gamma校正(速度慢)
* @return uint32_t 颜色的灰度值
*/
static int greysc(int got){ return (int)((got&0xf8)*299+(((got>>11)&0x1c)|((got<<5)&0xe0))*587+((got&0x1f00)>>5)*114)/978; }
static int greysc(int c){return(((c>>3)&0x1F)*79+(((c<<3)+(c>>13))&0x3F)*76+((c>>8)&0x1F)*30)>>5;}
void drv_drawImage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y); //分步完成灰度刷新
void drv_draw16grey(LGFX_Sprite &sprbase,LGFX_Sprite &spr,uint16_t x,uint16_t y);//省内存方式
void drv_draw16grey_step(const uint8_t *buf, int step){ //分步完成灰度刷新

View File

@@ -78,8 +78,6 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f){ //单色刷新
}
yield();
}
//ips.readPixel(i,j);
DelayMs(150);
}
void drv::drv_sleep() {}
}

View File

@@ -31,10 +31,10 @@
#define _READGUY_VERSION_H_FILE
#define READGUY_V_MAJOR 1
#define READGUY_V_MINOR 0
#define READGUY_V_PATCH 2
#define READGUY_V_MINOR 1
#define READGUY_V_PATCH 1
#define READGUY_VERSION_VAL (READGUY_V_MAJOR*1000+READGUY_V_MINOR*100+READGUY_V_PATCH*10)
#define READGUY_VERSION "1.0.2"
#define READGUY_VERSION "1.1.1"
#ifdef ESP8266
#define _READGUY_PLATFORM "ESP8266"
@@ -52,8 +52,8 @@
#endif
#endif
#define _GITHUB_LINK "https://github.com/fsender/readguy"
#define _BILIBILI_LINK "https://space.bilibili.com/180327370"
#define _GITHUB_LINK "github.com/fsender/readguy"
#define _BILIBILI_LINK "www.bilibili.com/video/BV1f94y187wz"
#endif /* END OF FILE. ReadGuy project.

File diff suppressed because it is too large Load Diff

View File

@@ -32,37 +32,35 @@
#define INPUT_PULLDOWN INPUT
#endif
guy_button readguy_driver::btn_rd[3];
int8_t readguy_driver::pin_cmx=-1;
guy_button ReadguyDriver::btn_rd[3];
int8_t ReadguyDriver::pin_cmx=-1;
const PROGMEM char readguy_driver::projname[8] = "readguy";
const PROGMEM char readguy_driver::tagname[9] = "hwconfig";
volatile uint8_t readguy_driver::spibz=0;
const PROGMEM char ReadguyDriver::projname[8] = "readguy";
const PROGMEM char ReadguyDriver::tagname[7] = "hwconf";
volatile uint8_t ReadguyDriver::spibz=0;
#ifndef ESP8266
SPIClass *readguy_driver::sd_spi =nullptr;
SPIClass *readguy_driver::epd_spi=nullptr;
TaskHandle_t readguy_driver::btn_handle;
SPIClass *ReadguyDriver::sd_spi =nullptr;
SPIClass *ReadguyDriver::epd_spi=nullptr;
TaskHandle_t ReadguyDriver::btn_handle;
#endif
readguy_driver::readguy_driver(){
ReadguyDriver::ReadguyDriver(){
READGUY_cali = 0; // config_data[0] 的初始值为0
READGUY_sd_ok = 0; //初始默认SD卡未成功初始化
READGUY_buttons = 0; //初始情况下没有按钮
}
uint8_t readguy_driver::init(){
uint8_t ReadguyDriver::init(uint8_t WiFiSet){ //WiFiSet: 是否保持AP服务器一直处于打开状态
if(READGUY_cali==127) //已经初始化过了一次了, 为了防止里面一些volatile的东西出现问题....还是退出吧
return 0;
#ifdef DYNAMIC_PIN_SETTINGS
//char config_data[18];
nvs_init();
#if (!defined(INDEV_DEBUG))
if(!nvs_read()){ //如果NVS没有录入数据, 需要打开WiFiAP模式初始化录入引脚数据
#endif
#ifdef READGUY_ESP_ENABLE_WIFI
//开启WiFi和服务器, 然后网页获取数据
//以下代码仅供测试
ap_setup();
server_setup();
ap_setup(); //开启WiFi和服务器, 然后网页获取数据. 如果保持WiFi AP模式打开, 则显示此标语.
if(WiFiSet) server_setup(F("引脚配置完成。请稍后访问<a href=\"/\">此页面</a>浏览更多内容。"));
else server_setup(F("引脚配置完成, WiFi即将关闭。")); //直接进入主页.
for(uint32_t i=UINT32_MAX;millis()<i;){
if(server_loop()){
if(i==UINT32_MAX) i=millis()+500;
@@ -71,15 +69,14 @@ uint8_t readguy_driver::init(){
}
//delay(300); //等待网页加载完再关掉WiFi. (有没有用存疑)
server_end();
WiFi.mode(WIFI_OFF);
if(!WiFiSet) WiFi.mode(WIFI_OFF);
fillScreen(1);
#endif
#if (!defined(INDEV_DEBUG))
}
else{ //看来NVS有数据, //从NVS加载数据, 哪怕前面的数据刚刚写入, 还没读取
//for(unsigned int i=0;i<sizeof(config_data);i++){
// Serial.printf_P(PSTR("data %u: %d\n"),i,config_data[i]);
//}
if(WiFiSet>=2) WiFi.begin(); //连接到上次存储在flash NVS中的WiFi.
else if(WiFiSet==1) ap_setup();
if(checkEpdDriver()!=127) setEpdDriver(); //初始化屏幕
else for(;;); //此处可能添加程序rollback等功能操作(比如返回加载上一个程序)
setSDcardDriver();
@@ -97,7 +94,7 @@ uint8_t readguy_driver::init(){
READGUY_cali=127;
return READGUY_sd_ok;
}
uint8_t readguy_driver::checkEpdDriver(){
uint8_t ReadguyDriver::checkEpdDriver(){
#ifdef DYNAMIC_PIN_SETTINGS
#ifdef ESP8266
#define TEST_ONLY_VALUE 5
@@ -155,7 +152,6 @@ uint8_t readguy_driver::checkEpdDriver(){
Serial.println(F("[ERR] EPD DRIVER IC NOT SUPPORTED!\n"));
return 127;
}
// this calls the peripheral hardware interface, see epdif 初始化硬件SPI层(HAL层)
#if (defined(ESP8266))
SPI.begin();
SPI.setFrequency(ESP8266_SPI_FREQUENCY); ///< 1MHz
@@ -176,7 +172,7 @@ uint8_t readguy_driver::checkEpdDriver(){
Serial.println(F("IfInit OK"));
return READGUY_epd_type;
}
void readguy_driver::setEpdDriver(){
void ReadguyDriver::setEpdDriver(){
guy_dev->spi_tr_release = in_release;
guy_dev->spi_tr_press = in_press;
guy_dev->drv_init(); //初始化epd驱动层
@@ -195,7 +191,7 @@ void readguy_driver::setEpdDriver(){
setTextColor(0);
fillScreen(1); //开始先全屏白色
}
bool readguy_driver::setSDcardDriver(){
bool ReadguyDriver::setSDcardDriver(){
/*重要信息: 有些引脚冲突是难以避免的, 比如8266 尤其需要重写这部分代码
对于esp32也要注意这个引脚是否是一个合法的引脚
对于esp8266真的要重写, 比如esp8266需要允许某些引脚是可以复用的
@@ -235,7 +231,7 @@ bool readguy_driver::setSDcardDriver(){
}
return READGUY_sd_ok;
}
void readguy_driver::setButtonDriver(){
void ReadguyDriver::setButtonDriver(){
if(READGUY_btn1) { //初始化按键. 注意高电平触发的引脚在初始化时要设置为下拉
int8_t btn_pin=abs(READGUY_btn1)-1;
#if defined(ESP8266) //只有ESP8266是支持16引脚pulldown功能的, 而不支持pullup
@@ -339,7 +335,7 @@ void readguy_driver::setButtonDriver(){
}
} //关于按键策略, 我们在此使用多个Button2的类, 然后在一个task共享变量来确定上一个按键状态
}
fs::FS &readguy_driver::guyFS(uint8_t initSD){
fs::FS &ReadguyDriver::guyFS(uint8_t initSD){
if(initSD==2 || (!READGUY_sd_ok && initSD)) setSDcardDriver();
if(READGUY_sd_ok){
#ifdef ESP8266
@@ -354,7 +350,7 @@ fs::FS &readguy_driver::guyFS(uint8_t initSD){
return SPIFFS;
#endif
}
void readguy_driver::setBright(int d){
void ReadguyDriver::setBright(int d){
if(currentBright>=0 && d>=0 && d<=255){
currentBright=d;
#ifdef ESP8266
@@ -368,7 +364,7 @@ void readguy_driver::setBright(int d){
digitalWrite(READGUY_bl_pin,d?HIGH:LOW);
}
}
void readguy_driver::display(bool part){
void ReadguyDriver::display(bool part){
//真的是我c++的盲区了啊....搜索了半天才找到可以这么玩的
//......可惜'dynamic_cast' not permitted with -fno-rtti
// static bool _part = 0; 记忆上次到底是full还是part, 注意启动时默认为full
@@ -379,7 +375,7 @@ void readguy_driver::display(bool part){
//in_release(); //恢复
}
}
void readguy_driver::display(std::function<uint8_t(int)> f, bool part){
void ReadguyDriver::display(std::function<uint8_t(int)> f, bool part){
if(READGUY_cali==127){
//in_press(); //暂停, 然后读取按键状态 spibz
guy_dev->drv_fullpart(part);
@@ -387,106 +383,113 @@ void readguy_driver::display(std::function<uint8_t(int)> f, bool part){
//in_release(); //恢复
}
}
void readguy_driver::drawImage(LGFX_Sprite &spr,uint16_t x,uint16_t y) {
void ReadguyDriver::drawImage(LGFX_Sprite &spr,uint16_t x,uint16_t y) {
if(READGUY_cali==127) guy_dev->drv_drawImage(*this, spr, x, y);
}
void readguy_driver::setDepth(uint8_t d){
void ReadguyDriver::setDepth(uint8_t d){
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling()) guy_dev->drv_setDepth(d);
}
void readguy_driver::draw16grey(LGFX_Sprite &spr,uint16_t x,uint16_t y){
void ReadguyDriver::draw16grey(LGFX_Sprite &spr,uint16_t x,uint16_t y){
if(READGUY_cali!=127) return;
if(guy_dev->drv_supportGreyscaling() && (spr.getColorDepth()&0xff)>1)
return guy_dev->drv_draw16grey(*this,spr,x,y);
guy_dev->drv_drawImage(*this, spr, x, y);
}
void readguy_driver::draw16greyStep(int step){
void ReadguyDriver::draw16greyStep(int step){
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling())
return guy_dev->drv_draw16grey_step((const uint8_t *)this->getBuffer(),step);
}
void readguy_driver::draw16greyStep(std::function<uint8_t(int)> f, int step){
void ReadguyDriver::draw16greyStep(std::function<uint8_t(int)> f, int step){
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling())
return guy_dev->drv_draw16grey_step(f,step);
}
void readguy_driver::invertDisplay(){
void ReadguyDriver::invertDisplay(){
if(READGUY_cali==127){
const int pixels=((guy_dev->drv_width()+7)>>3)*guy_dev->drv_height();
for(int i=0;i<pixels;i++)
((uint8_t*)(getBuffer()))[i]=uint8_t(~(((uint8_t*)(getBuffer()))[i]));
}
}
void readguy_driver::sleepEPD(){
void ReadguyDriver::sleepEPD(){
if(READGUY_cali==127) guy_dev->drv_sleep();
}
#if (!defined(DYNAMIC_PIN_SETTINGS)) //do nothing here.
#elif (defined(INDEV_DEBUG))
void readguy_driver::nvs_init(){
void ReadguyDriver::nvs_init(){
}
void readguy_driver::nvs_deinit(){
void ReadguyDriver::nvs_deinit(){
}
bool readguy_driver::nvs_read(){
bool ReadguyDriver::nvs_read(){
return 1;
}
void readguy_driver::nvs_write(){
void ReadguyDriver::nvs_write(){
}
#elif (defined(ESP8266))
void readguy_driver::nvs_init(){
EEPROM.begin(128);
void ReadguyDriver::nvs_init(){
EEPROM.begin(32);
}
void readguy_driver::nvs_deinit(){
void ReadguyDriver::nvs_deinit(){
EEPROM.commit();
EEPROM.end();
}
bool readguy_driver::nvs_read(){
bool ReadguyDriver::nvs_read(){
char s[8];
for(unsigned int i=0;i<sizeof(config_data)+8;i++){
int8_t rd=(int8_t)EEPROM.read(100+i);
int8_t rd=(int8_t)EEPROM.read(2+i);
if(i>=8) config_data[i-8] = rd;
else s[i]=(char)rd;
}
Serial.printf("Get NVS...%d\n", config_data[0]);
return !(strcmp_P(s,projname));
}
void readguy_driver::nvs_write(){
void ReadguyDriver::nvs_write(){
for(unsigned int i=0;i<sizeof(config_data)+8;i++){
EEPROM.write(100+i,(uint8_t)(i<8?pgm_read_byte(projname+i):config_data[i-8]));
EEPROM.write(2+i,(uint8_t)(i<8?pgm_read_byte(projname+i):config_data[i-8]));
}
}
#else
void readguy_driver::nvs_init(){
void ReadguyDriver::nvs_init(){
nvsData.begin(projname); //初始化NVS
}
void readguy_driver::nvs_deinit(){
void ReadguyDriver::nvs_deinit(){
nvsData.end(); //用完NVS记得关闭, 省内存
}
bool readguy_driver::nvs_read(){
bool suc = nvsData.isKey(tagname);
if(suc) nvsData.getBytes(tagname,config_data,sizeof(config_data));
return suc;
bool ReadguyDriver::nvs_read(){ //此处需要处理一些有关I2C的内容
if(!nvsData.isKey(tagname)) return 0; //没有这个键值
size_t len=nvsData.getBytes(tagname,config_data,sizeof(config_data)); //读取的数据长度
/*if(len<sizeof(config_data)){ //旧版本格式无法获取I2C相关数据, 设置为-1.
for(int i=sizeof(config_data)-1;i>=15;i--) //使用新版本格式来存储相关数据
config_data[i]=config_data[i-2];
READGUY_i2c_sda=-1;
READGUY_i2c_scl=-1;
nvsData.putBytes(tagname,config_data,sizeof(config_data)); //用新版本格式保存
}*/
return len==sizeof(config_data);
}
void readguy_driver::nvs_write(){
void ReadguyDriver::nvs_write(){
if(nvsData.isKey(tagname)) nvsData.remove(tagname);
nvsData.putBytes(tagname,config_data,sizeof(config_data)); //正式写入NVS
}
#endif
uint8_t readguy_driver::getBtn_impl(){ //按钮不可用, 返回0.
uint8_t ReadguyDriver::getBtn_impl(){ //按钮不可用, 返回0.
uint8_t res1,res2,res3,res4=0;
switch(READGUY_buttons){
case 1:
res1=btn_rd[0].read();
if(res1 == 1) res4 |= 1;
else if(res1 == 2) res4 |= 2;
else if(res1 == 4) res4 |= 4;
else if(res1 == 3) res4 |= 8;
if(res1 == 1) res4 |= 1; //点按
else if(res1 == 2) res4 |= 2; //双击
else if(res1 == 4) res4 |= 4; //长按-确定
else if(res1 == 3) res4 |= 8; //三击-返回
break;
case 2:
res1=btn_rd[0].read();
res1=btn_rd[0].read(); //两个按钮引脚都读取
res2=btn_rd[1].read();
if(res1 == 1) res4 |= 1;
else if(res1 == 4) res4 |= 2;
if(res2 == 1) res4 |= 4;
else if(res2 == 4) res4 |= 8;
if(res1 == 1) res4 |= 1; //左键点按-向下翻页
else if(res1 == 4) res4 |= 2; //左键长按-向上翻页
if(res2 == 1) res4 |= 4; //右键点按-确定
else if(res2 == 4) res4 |= 8; //右键长按-返回
break;
case 3:
res1=btn_rd[0].read();
@@ -500,20 +503,20 @@ uint8_t readguy_driver::getBtn_impl(){ //按钮不可用, 返回0.
}
return res4;
}
void readguy_driver::looptask(){ //均为类内静态数据
void ReadguyDriver::looptask(){ //均为类内静态数据
btn_rd[0].loop();
btn_rd[1].loop();
btn_rd[2].loop();
}
uint8_t readguy_driver::rd_btn_f(uint8_t btn){
uint8_t ReadguyDriver::rd_btn_f(uint8_t btn){
static uint8_t lstate=0; //上次从dc引脚读到的电平
#ifdef ESP8266
if(btn==readguy_driver::pin_cmx && spibz) return lstate;
if(btn==D5||btn==D6||btn==D7||btn==readguy_driver::pin_cmx)
if(btn==ReadguyDriver::pin_cmx && spibz) return lstate;
if(btn==D5||btn==D6||btn==D7||btn==ReadguyDriver::pin_cmx)
pinMode(btn,INPUT_PULLUP);//针对那些复用引脚做出的优化
uint8_t readb = digitalRead(btn);
if(btn==readguy_driver::pin_cmx) {
if(btn==ReadguyDriver::pin_cmx) {
//Serial.printf("rd D1.. %d\n",spibz);
pinMode(btn,OUTPUT); //如果有复用引脚, 它们的一部分默认需要保持输出状态, 比如复用的DC引脚
digitalWrite(btn,HIGH); //这些引脚的默认电平都是高电平
@@ -522,7 +525,7 @@ uint8_t readguy_driver::rd_btn_f(uint8_t btn){
else if(btn==D5||btn==D6||btn==D7) pinMode(btn,SPECIAL); //针对SPI引脚进行专门的优化
return readb;
#else //ESP32不再允许SPI相关引脚复用
if(btn!=readguy_driver::pin_cmx)
if(btn!=ReadguyDriver::pin_cmx)
return digitalRead(btn);
if(spibz) return lstate;
pinMode(btn,INPUT_PULLUP);

View File

@@ -36,7 +36,6 @@
#include <SPI.h>
#include <FS.h>
//#include <esp-fs-webserver.h>
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
@@ -120,25 +119,37 @@
#define READGUY_sd_mosi (config_data[10])// 目标sd卡的 MOSI 引脚, sd_share_spi == 1 时无效
#define READGUY_sd_sclk (config_data[11])// 目标sd卡的 SCLK 引脚, sd_share_spi == 1 时无效
#define READGUY_sd_cs (config_data[12])// 目标sd卡的 CS 引脚.
#define READGUY_i2c_sda (config_data[13])// 目标i2c总线的SDA引脚, 当且仅当启用i2c总线时才生效
#define READGUY_i2c_scl (config_data[14])// 目标i2c总线的SCL引脚, 当且仅当启用i2c总线时才生效
//按键驱动部分, 为负代表高触发, 否则低触发,
//注意, 这里的io编号是加1的, 即 1或-1 代表 gpio0 的低触发/高触发
#define READGUY_btn1 (config_data[13])
#define READGUY_btn2 (config_data[14])
#define READGUY_btn3 (config_data[15])
#define READGUY_bl_pin (config_data[16])//前置光接口引脚IO
#define READGUY_rtc_type (config_data[17])//使用的RTC型号(待定, 还没用上)
#define READGUY_sd_ok (config_data[18]) //SD卡已经成功初始化
#define READGUY_buttons (config_data[19]) //按钮个数, 0-3都有可能
#define READGUY_btn1 (config_data[15])
#define READGUY_btn2 (config_data[16])
#define READGUY_btn3 (config_data[17])
#define READGUY_bl_pin (config_data[18])//前置光接口引脚IO
#define READGUY_rtc_type (config_data[19])//使用的RTC型号(待定, 还没用上)
#define READGUY_sd_ok (config_data[20]) //SD卡已经成功初始化
#define READGUY_buttons (config_data[21]) //按钮个数, 0-3都有可能
#endif
class readguy_driver: public LGFX_Sprite{ // readguy 基础类
class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
public:
readguy_driver();
#ifdef READGUY_ESP_ENABLE_WIFI
#ifdef ESP8266
typedef ESP8266WebServer ReadguyWebServer;
typedef ESP8266HTTPUpdateServer ReadguyUpdateServer;
#else
typedef WebServer ReadguyWebServer;
typedef HTTPUpdateServer ReadguyUpdateServer;
#endif
#endif
ReadguyDriver();
/** @brief 初始化readguy
* @param WiFiSet 是否保持AP模式关闭. 0:配网完成自动关WiFi, 1:需要手动调用 WiFi.mode(WIFI_OFF) 关闭WiFi.
* 2:自动连接到已存的WiFi, 但不等待连接成功
* @return SD卡是否就绪
*/
uint8_t init();
//LGFX_Sprite g() const { return gfx; }; //使用 gfx 绘制内容.
uint8_t init(uint8_t WiFiSet = 0);
/// @brief 设置显示亮度
void setBright(int d);
/// @brief 返回显示亮度
@@ -187,22 +198,22 @@ class readguy_driver: public LGFX_Sprite{ // readguy 基础类
void sleepEPD(void);
/// @brief ap配网设置页面
typedef struct {
String event;
int method; //其实这里的method的类型应当为HTTPMethod, 但是为了兼容无wifi的功能, 使用了int格式
std::function<void()> func;
String linkname;
String event; //链接名称 事件URI
std::function<void(ReadguyWebServer*)> func; //触发时执行的函数
} serveFunc;
#ifdef READGUY_ESP_ENABLE_WIFI
/// @brief 初始化WiFi AP模式, 用于将来的连接WiFi 处于已连接状态下会断开原本的连接
void ap_setup();
/// @brief 初始化WiFi AP模式, 用于将来的连接WiFi 处于已连接状态下会断开原本的连接
void server_setup(const serveFunc *serveFuncs = nullptr, int funcs = 0);
void server_setup(const String &notify=emptyString, const serveFunc *serveFuncs = nullptr, int funcs = 0);
bool server_loop();
void server_end() { sv.stop(); MDNS.end(); }
void server_end();
#else
/// @brief 初始化WiFi AP模式, 用于将来的连接WiFi 处于已连接状态下会断开原本的连接
void ap_setup(){}
/// @brief 初始化WiFi AP模式, 用于将来的连接WiFi 处于已连接状态下会断开原本的连接
void server_setup(const serveFunc *serveFuncs = nullptr, int funcs = 0){}
/// @brief 初始化服务器模式, 用于将来的连接WiFi 处于已连接状态下会断开原本的连接
void server_setup(const String &notify=emptyString, const serveFunc *serveFuncs = nullptr, int funcs = 0){}
bool server_loop(){ return true; }
void server_end(){}
#endif
@@ -229,10 +240,10 @@ class readguy_driver: public LGFX_Sprite{ // readguy 基础类
//以下是支持的所有屏幕型号 Add devices here!
//添加屏幕驱动范例: 直接添加对应屏幕的类就可以用了
static const char projname[8];
static const char tagname[9];
//数据是否已经校准
#ifdef DYNAMIC_PIN_SETTINGS
int8_t config_data[20];
static const char tagname[7];
//uint8_t config_wifi=0; //是否强行在初始化期间设置WiFi.
#ifdef DYNAMIC_PIN_SETTINGS//数据是否已经校准
int8_t config_data[22];
char randomch[4]; //校验用字符串
void nvs_init(); //初始化持久存储器.
void nvs_deinit();//保存持久存储器的内容
@@ -245,7 +256,6 @@ class readguy_driver: public LGFX_Sprite{ // readguy 基础类
#endif
int epd_OK=0; //墨水屏可用
int currentBright = -3; //初始亮度
//.........敬请期待更多屏幕ic...........
//LGFX_Sprite gfx; // 图形引擎类指针, 可以用这个指针去操作屏幕缓冲区
readguyEpdBase *guy_dev = nullptr;
@@ -255,19 +265,9 @@ class readguy_driver: public LGFX_Sprite{ // readguy 基础类
//template <class T> void t_display(T t);
#if defined(ESP8266)
#ifdef READGUY_ESP_ENABLE_WIFI
ESP8266WebServer sv;
ESP8266HTTPUpdateServer httpUpdater;
String w_ssid;
String w_psk;
#endif
//对于esp8266, 需要注册到ticker
Ticker btnTask;
#else
#ifdef READGUY_ESP_ENABLE_WIFI
WebServer sv;
HTTPUpdateServer httpUpdater;
#endif
#ifdef DYNAMIC_PIN_SETTINGS
//NVS数据操作函数, 无NVS的使用EEProm的最后几个字节块
Preferences nvsData;
@@ -277,12 +277,18 @@ class readguy_driver: public LGFX_Sprite{ // readguy 基础类
static TaskHandle_t btn_handle;
#endif
#ifdef READGUY_ESP_ENABLE_WIFI
ReadguyWebServer sv;
ReadguyUpdateServer httpUpdater;
String guy_notify=emptyString; //嵌入在网页中的自定义标语
int sfuncs=-1;
String* sfnames=nullptr;
String* sfevents=nullptr;
void handleInit(); //服务器初始化系统(初次访问时, 跳转至引脚设定函数)
void handleInitPost(); //服务器响应初始化请求
void handlePinSetup(); //服务器-引脚设定函数
void handleFinal(); //服务器-校验屏幕是否正常
void handleFinalPost(); //服务器-校验屏幕是否正常回调函数
void handleWiFiPost(); //服务器-处理WiFi连接相关内容和API接口密钥功能
//void handleWiFi();//[已弃用]服务器-处理WiFi连接相关内容和API接口密钥功能
void handleNotFound(); //服务器-404响应
#endif
//按键驱动部分
@@ -295,28 +301,17 @@ class readguy_driver: public LGFX_Sprite{ // readguy 基础类
#ifdef READGUY_ESP_ENABLE_WIFI
//static constexpr size_t EPD_DRIVERS_NUM_MAX = READGUY_SUPPORT_DEVICES;
static const char *epd_drivers_list[EPD_DRIVERS_NUM_MAX];
static const PROGMEM char html_header[]; //HTML头的数据. 省内存, 能省一点是一点
static const PROGMEM char index_cn_html[];
/*static const PROGMEM char index_cn_html1[];
static const PROGMEM char index_cn_html2[];
static const PROGMEM char index_cn_html3[];
static const PROGMEM char index_cn_html4[];
static const PROGMEM char index_cn_html5[];
static const PROGMEM char index_cn_html6[];
static const PROGMEM char index_cn_html7[];
static const PROGMEM char index_cn_html8[];
static const PROGMEM char index_cn_html9[];
static const PROGMEM char index_cn_html10[];
static const PROGMEM char index_cn_html11[];
static const PROGMEM char index_cn_html12[];
static const PROGMEM char index_cn_html13[];
static const PROGMEM char index_cn_html14[];
static const PROGMEM char index_cn_html15[]; */
static const PROGMEM char index_cn_html16[];
static const PROGMEM char verify_html[];
static const PROGMEM char verify2_html[];
static const PROGMEM char verifybtn_html[3][200];
static const PROGMEM char final_html[];
static const PROGMEM char final2_html[];
static const PROGMEM char afterConfig_html[];
static const PROGMEM char home_html[];
static const PROGMEM char end_html[];
//static const PROGMEM uint8_t faviconData[1150];
#endif
@@ -335,6 +330,31 @@ class readguy_driver: public LGFX_Sprite{ // readguy 基础类
if(!spibz) epd_spi->endTransaction();
#endif
}
public: //增加了一些返回系统状态变量的函数, 它们是静态的, 而且不会对程序造成任何影响.
constexpr int getReadguyShareSpi() const { return config_data[1]; }
constexpr int getReadguyEpdType () const { return config_data[2]; } // 对应的epd驱动程序代号, -1为未指定
//显示驱动部分, 显示默认使用vspi (vspi也是默认SPI库的通道)
constexpr int getReadguyEpdMosi () const { return config_data[3]; } // 目标显示器的 MOSI 引脚
constexpr int getReadguyEpdSclk () const { return config_data[4]; } // 目标显示器的 SCLK 引脚
constexpr int getReadguyEpdCs () const { return config_data[5]; } // 目标显示器的 CS 引脚
constexpr int getReadguyEpdDc () const { return config_data[6]; } // 目标显示器的 DC 引脚
constexpr int getReadguyEpdRst () const { return config_data[7]; } // 目标显示器的 RST 引脚
constexpr int getReadguyEpdBusy () const { return config_data[8]; } // 目标显示器的 BUSY 引脚
//sd卡驱动部分, 默认使用hspi (sd卡建议用hspi)
constexpr int getReadguySdMiso () const { return config_data[9]; } // 目标sd卡的 MISO 引脚, sd_share_spi == 1 时无效
constexpr int getReadguySdMosi () const { return config_data[10]; }// 目标sd卡的 MOSI 引脚, sd_share_spi == 1 时无效
constexpr int getReadguySdSclk () const { return config_data[11]; }// 目标sd卡的 SCLK 引脚, sd_share_spi == 1 时无效
constexpr int getReadguySdCs () const { return config_data[12]; }// 目标sd卡的 CS 引脚.
constexpr int getReadguyI2cSda () const { return config_data[13]; }// 目标i2c总线的SDA引脚, 当且仅当启用i2c总线时才生效
constexpr int getReadguyI2cScl () const { return config_data[14]; }// 目标i2c总线的SCL引脚, 当且仅当启用i2c总线时才生效
//按键驱动部分, 为负代表高触发, 否则低触发,
//注意, 这里的io编号是加1的, 即 1或-1 代表 gpio0 的低触发/高触发
constexpr int getReadguyBtn1Pin () const { return config_data[15]; }
constexpr int getReadguyBtn2Pin () const { return config_data[16]; }
constexpr int getReadguyBtn3Pin () const { return config_data[17]; }
constexpr int getReadguyBlPin () const { return config_data[18]; }//前置光接口引脚IO
constexpr int getReadguyRtcType () const { return config_data[19]; }//使用的RTC型号(待定, 还没用上)
constexpr int getButtonsCount () const { return config_data[21]; } //按钮个数, 0-3都有可能
};
#endif /* END OF FILE. ReadGuy project.
Copyright (C) 2023 FriendshipEnder. */