Bump to 1.4.0 with many new feats

This commit is contained in:
fsender
2024-12-01 19:57:36 +08:00
parent a69456a09c
commit f289938a65
21 changed files with 1112 additions and 266 deletions

View File

@@ -59,6 +59,7 @@ SOFTWARE.
*/
#include "guy_button.h"
#include "guy_driver_config.h"
// initalize static counter
@@ -75,11 +76,11 @@ void guy_button::begin(uint8_t _pin, std_U8_function_U8 f, bool activeLow/*=true
prev_state = state ;
get_state_cb = f;
pin = _pin;
state = get_state_cb(pin);
min_debounce =25; //去抖时间
long_press_ms =300; //长按持续时间
double_press_ms =300; //双击识别间隔最大时间
long_repeat_ms =200; //长按连按间隔时间
state = get_state_cb(pin, activeLow);
min_debounce =READGUY_DEFAULT_MIN_DEBOUNCE_MS; //去抖时间
long_press_ms =READGUY_LONG_PRESS_MS; //长按持续时间
double_press_ms =READGUY_DOUBLE_PRESS_MS; //双击识别间隔最大时间
long_repeat_ms =READGUY_LONG_REPEAT_MS; //长按连按间隔时间
scanDT =1; // =1识别双击或三击, =0则不识别双击或三击等需要延时返回的情况
lk=0;
}
@@ -87,7 +88,7 @@ bool guy_button::isPressedRaw() {
int mi=millis();
while(lk) if(millis()-mi>GUYBTN_READ_TIMEOUT) return 0; //等待数据读完
lk=3;
bool willreturn = (get_state_cb(pin) == _pressedState);
bool willreturn = (get_state_cb(pin, !_pressedState) == _pressedState);
lk=0;
return willreturn;
}
@@ -116,7 +117,7 @@ void guy_button::loop() {
lk=1;
unsigned long now = millis();
prev_state = state;
state = get_state_cb(pin);
state = get_state_cb(pin, !_pressedState);
// is button pressed?
if (state == _pressedState) {

View File

@@ -109,7 +109,7 @@ class guy_button{
bool pressed_triggered = false;
bool trig_mode = false; //长按连按触发模式
typedef uint8_t (*std_U8_function_U8)(uint8_t);
typedef uint8_t (*std_U8_function_U8)(uint8_t, bool);
std_U8_function_U8 get_state_cb = NULL;
public:
@@ -118,7 +118,7 @@ class guy_button{
/// @param _pin 引脚ID. 传入的引脚在内部将会使用digitalRead函数实现
/// @param activeLow 设置为true时, 当读取到低电平视为按下
void begin(uint8_t _pin, bool activeLow = true){
begin(_pin,[](uint8_t p)->uint8_t { return digitalRead(p); },activeLow);
begin(_pin,[](uint8_t p, bool)->uint8_t { return digitalRead(p); },activeLow);
}
/// @brief 初始化
/// @param _pin 引脚ID. 传入的引脚在内部将会使用digitalRead函数实现

View File

@@ -52,9 +52,10 @@
//对于甘草酸不酸的新版本板子:
//busy 4 rst 2 dc 0 cs 15 sck / mosi / sdcs 5 btnL rx(3) btnM 0
//对于四个按钮的4.2屏开发板:
//对于四个按钮的4.2屏开发板: @十里画廊
//(https://oshwhub.com/shilihualang/han-jia-qian-gai-zhuang-ji-jian-kai-fa-ban)
//clk 14 cs 15 mosi 13 dc 27 rst 26 busy 25
//sd cs 4 miso 12 (共线) 按键 k1 5 k2 17 k3 16 k4 0 前置光 19/18/23
//sd cs 4 miso 12 (共线) 按键 k1 5 k2 17 k3 16 k4 0 前置光 19/18/23 (RGB)
//对于lilygo t-watch epaper 开发板:
//cs 5 dc 19 rst 27 busy 38 clk 18 mosi 23
@@ -64,30 +65,65 @@
// ------------------ definations - 定义 -
/// @brief 使用静态的数据 !!!注意:注释此选项编写的程序是不支持跨平台运行的!!!
/// @note 相比于禁用WiFi配网功能, 禁用此功能减少的flash并不多, 为保证程序可在不同屏幕上运行, 请不要注释此选项
// 关闭此选项自动禁用wifi功能. 如需wifi功能需要自己在程序里加.
/** @brief 使用静态的数据 !!!注意:注释此选项编写的程序是不支持跨平台运行的!!!
/ @note 相比于禁用WiFi配网功能, 禁用此功能减少的flash并不多, 为保证程序可在不同屏幕上运行, 请不要注释此选项
/ 关闭此选项自动禁用wifi功能. 如需wifi功能需要自己在程序里加. 但也可以大幅减少flash的占用 */
#define DYNAMIC_PIN_SETTINGS
/// @brief 启用WIFI配网功能.必须先启用 #define DYNAMIC_PIN_SETTINGS. 此选项对 ESP32xx 会减少大量flash.
/// @brief 启用WIFI配网功能.必须先启用 #define DYNAMIC_PIN_SETTINGS. 此选项对 ESP32xx 会减少大量可用flash.
#define READGUY_ENABLE_WIFI
/// @brief 启用I2C功能. 可用于联网时钟, 温度计, 陀螺仪等外设. 目前暂不支持库内使用类似函数. 仅可以提供引脚定义
//#define READGUY_ENABLE_I2C
/// @note 现在库不提供任何I2C驱动, 只提供引脚定义的存储和读取, 这几乎不增加多少代码. 因此本宏不再使用
/** @brief 启用I2C功能. 可用于联网时钟, 温度计, 陀螺仪等外设. 目前暂不支持库内使用类似函数. 仅可以提供引脚定义
/ @note 现在库提供了获取已存的I2C引脚的接口, 使用时请使用 getI2cSda() 和 getI2cScl() 函数获取I2C的引脚.
/ 本库内不提供任何I2C驱动, 只提供引脚定义的存储和读取, 这几乎不增加多少代码. 因此本宏不再使用 */
//#define READGUY_ENABLE_I2C
/** @brief 启用SD卡功能. 开启此功能将会使用内置SD卡管理功能. 关闭后仅可保存SD卡用到的引脚.
@note 会破坏兼容性. 若没有启用通用的SD卡驱动程序, 那么那些跨屏台编译的程序将无法用guyFS读取到SD卡.
若用户程序希望能从外部加载SD卡, 可以使用getSdMiso()等函数获取SD卡的Miso等引脚, 再由用户程序初始化SD卡. */
/ @note 会破坏兼容性. 若没有启用通用的SD卡驱动程序, 那么那些跨屏台编译的程序将无法用guyFS读取到SD卡.
/ 若用户程序希望能从外部加载SD卡, 可以使用getSdMiso()等函数获取SD卡的Miso等引脚, 再由用户程序初始化SD卡. */
#define READGUY_ENABLE_SD
/// @brief 使用LittleFS作为片上文件系统, 注释此行则用SPIFFS(功能少, 不好用)
#define READGUY_USE_LITTLEFS 1
/// @brief 使用esp8266时, EEPROM(类似NVS)的存储位置起点 (从起点开始的40字节被readguy所使用) 可选值: 0~4045
/// @note 对于单一项目来说, 此选项不建议更改, 请在项目初期就确定此变量的值.
/** @brief 使用esp8266时, EEPROM(类似NVS)的存储位置起点 (从起点开始的40字节被readguy所使用) 可选值: 0~4045
/ @note 对于单一项目来说, 此选项不建议更改, 请在项目初期就确定此变量的值. */
#define READGUY_ESP8266_EEPROM_OFFSET 2
/** @brief (实验性) 允许 EPD_DC 引脚复用作按键引脚. 当DC引脚直连主控且直连按键时 (按下按键后DC引脚电平被锁定)
/ 启用此项可以允许这样的按键复用 (如用于早期版本甘草酸不酸2.9阅读器板子) 但复用的引脚作为按钮长按时体验会变差
/ @note 即使注释此选项依旧可以允许DC引脚复用, 但需要在主控直连屏幕DC引脚, 并在按键一端和主控引脚之间接入一个
/ 220Ω~1kΩ的电阻 (推荐470Ω), 按键另一端接地, 这样才可以. 注释该选项后, 即使按键和DC引脚复用了, 也不会影响功
/ 能和长按体验. 注意如果按键有内阻(不按时按键两端电阻为∞, 按下后按键电阻较高) 可以酌情减小一些按键接入电阻.
/ 对于新版的甘草酸不酸2.9阅读器板子就可以注释此选项.
/ 没有需要兼容「复用DC引脚的硬件」的需求的用户, 建议注释此项. 一般仅建议ESP8266启用此选项*/
//#define READGUY_ALLOW_DC_AS_BUTTON
/** @brief (实验性) 允许复用 EPD 的 CS 引脚作为按钮. 这会让读取按钮电平的速度些许减慢.
/ @note 需要在按键一端和主控引脚之间接入一个220Ω~1kΩ的电阻 (推荐470Ω), 并要求EPD的CS引脚直连主控对应引脚. */
//#define READGUY_ALLOW_EPDCS_AS_BUTTON
/** @brief (不建议, 实验性) 允许复用 SD 卡的 CS 引脚作为按钮.
/ @details 这不仅会减慢读按钮速度, 而且十分不建议对「确定」按钮 (通常为按钮2) 启用此功能函数. 因为一些程序会
/ 在你按下「确定」后立即读取 SD 卡 (与按键循环读取功能冲突) 导致总线紊乱! 在ESP32上会引起无法预知的崩溃复位!
/ @attention 启用后每次读写SD卡时,都必须调用 setSDbusy(1) 来锁定引脚, 屏蔽按键读取, 调用 setSDbusy(0)解锁.
/ @note 需要在按键一端和主控引脚之间接入一个220Ω~1kΩ的电阻 (推荐470Ω), 并要求SD卡的CS引脚直连主控对应引脚.
/ 所有示例程序未针对此选项重写, 建议重新规划硬件再使用示例. 若硬件无法更改, 请手动对需要用 ReadGuy 库未提供的
/ SD卡IO操作的部分, 手动添加 setSDbusy() 函数. 由 ReadGuy 提供的函数已适配好了, 如ReadGuy::Screenshot() */
//#define READGUY_ALLOW_SDCS_AS_BUTTON
/// @brief 按键去抖时间
#define READGUY_DEFAULT_MIN_DEBOUNCE_MS 25
/// @brief 按键长按持续时间
#define READGUY_LONG_PRESS_MS 300
/// @brief 按键双击识别间隔最大时间
#define READGUY_DOUBLE_PRESS_MS 300
/// @brief 按键长按连按间隔时间
#define READGUY_LONG_REPEAT_MS 200
/// @brief ESP32按键服务任务的栈空间大小, 不建议普通用户更改. 默认值1024字节. 小于此大小会使程序栈溢出.
#ifdef CONFIG_IDF_TARGET_ESP32S3
#define BTN_LOOPTASK_STACK 1536
@@ -114,7 +150,10 @@
#define ESP32_SD_SPI_FREQUENCY 20000000
/// @brief debug专用, 请保持处于注释状态. 正常开机从NVS读取引脚配置数据, 取消注释则每次开机需要重新配置
//#define INDEV_DEBUG 1
//#define READGUY_INDEV_DEBUG 1
/// @brief 串口显示刷屏功能等的信息. 建议开启, 如果是对flash要求十分敏感 可以关闭
#define READGUY_SERIAL_DEBUG
#ifndef DYNAMIC_PIN_SETTINGS
#ifdef ESP8266
@@ -136,12 +175,23 @@
#define READGUY_i2c_scl -1 // 目标i2c总线的SCL引脚, 当且仅当启用i2c总线时才生效
//按键驱动部分, 为负代表高触发, 否则低触发,
//注意, 这里的io编号是加1的, 即 1或-1 代表 gpio0 的低触发/高触发
#define READGUY_btn1 ( 5+1) //按键1,注意需要+1,这里示例已经加了 设置为负的来允许高电平触发
#define READGUY_btn1 ( 5+1) //按键1,注意需要+1,这里示例已经加了 设置为负的来允许高电平触发 如 (-(5+1))
#define READGUY_btn2 (12+1) //按键2,注意需要+1
#define READGUY_btn3 ( 2+1) //按键3,注意需要+1
#define READGUY_bl_pin 4 //前置光接口引脚IO
#else //对于非ESP8266
#define READGUY_user1 -1 //useless
#define READGUY_user2 -1 //useless
#define READGUY_user3 -1 //useless
#define READGUY_user4 -1 //useless
#define READGUY_user5 -1 //useless
#define READGUY_user6 -1 //useless
#define READGUY_user7 -1 //useless
#define READGUY_user8 -1 //useless
#define READGUY_user9 -1 //useless
#define READGUY_user10 -1 //useless
#else //对于非ESP8266 (如 ESP32xx)
#define READGUY_shareSpi 0 //EPD和SD卡是否共享SPI, 此处不共享
#define READGUY_epd_type READGUY_DEV_154B // 对应的epd驱动程序代号, -1为未指定
@@ -167,9 +217,20 @@
#define READGUY_btn2 -(32+1) //按键2,注意需要+1,此处前面的负号表示允许高电平触发
#define READGUY_btn3 0 //按键3,注意需要+1, 不用的按钮应当设置为0
#define READGUY_bl_pin 12 //前置光接口引脚IO
#define READGUY_user1 -1 //useful with ESP32S3 SDMMC sd mode DAT2 pin
#define READGUY_user2 -1 //useful with ESP32S3 SDMMC sd mode DAT3 pin
#define READGUY_user3 -1 //useless
#define READGUY_user4 -1 //useless
#define READGUY_user5 -1 //useless
#define READGUY_user6 -1 //useless
#define READGUY_user7 -1 //useless
#define READGUY_user8 -1 //useless
#define READGUY_user9 -1 //useless
#define READGUY_user10 -1 //useless
#endif
#define READGUY_rtc_type 0 //使用的RTC型号(待定, 还没用上)
#define READGUY_rtc_type 0 //使用的RTC型号. 现已弃用 RTC 功能. 保留是为了兼容性 让代码更简单维护
#elif defined(READGUY_ENABLE_WIFI)
#define READGUY_ESP_ENABLE_WIFI //使用WIFI进行配网等功能
#endif

View File

@@ -145,7 +145,7 @@ void drvSSD168x::drv_init(){
}
void drvSSD168x::drv_fullpart(bool part){ //切换慢刷/快刷功能
if(lastRefresh) return;
if(!epd_PowerOn) part=0; //未上电 无法局刷
//if(!epd_PowerOn) part=0; //未上电 无法局刷
if(!part) { iLut=15; greyScaling=0; }
_part=part;
}

View File

@@ -59,7 +59,7 @@
//#define READGUY_DEV_154C 14 //(即将推出) 1.54寸M09墨水屏 (M5Stack Core-Ink 同款; GDEW0154M09)
//#define READGUY_DEV_370B 15 //(即将推出) 3.7寸低DPI墨水屏, 分辨率416*240, b站 @叫我武哒哒 的项目用
//#define READGUY_DEV_426A 16 //(即将推出) 4.26寸高分辨率墨水屏, 800*480. GDEQ0426T82 支持硬件四灰
#define READGUY_DEV_583A 17 //(即将推出) 5.83寸墨水屏幕, 分辨率为600*448. 有黑白有三色
#define READGUY_DEV_583A 17 // 5.83寸墨水屏幕, 分辨率为600*448. 有黑白有三色
//#define READGUY_DEV_583B 18 //(即将推出) 5.83寸高分辨率, 640*480. GDEQ0583T31 只有黑白
//#define READGUY_DEV_750A 19 //(即将推出) 7.5 寸墨水屏幕, 800*480. 只有三色(买不到黑白)
//#define READGUY_DEV_1020A 20 //(即将推出) 10.2寸墨水屏GDEQ102T90, 芯片SSD1677. 黑白色分辨率960*640
@@ -68,7 +68,7 @@
#define EPD_DRIVERS_NUM_MAX 21 //此选项请不要取消注释掉, 有几个屏幕就写多少.
#define READGUY_583A_DUAL_BUFFER //对于单缓存的5.83屏幕, 启用双缓存支持
#define READGUY_583A_DUAL_BUFFER //对于单缓存的5.83屏幕,启用双缓存支持. 相当不建议注释掉,否则不能刷白色
#endif /* END OF FILE. ReadGuy project.
Copyright (C) 2023 FriendshipEnder. */

View File

@@ -73,7 +73,11 @@
//#define _DEFINA_SD_CS_PIN 0
// * for NodeMcu ctg stack LCF board
#define WHITE_GAP 2
#define WHITE_GAP 2 //白边像素数
#define SIMULATE_BLINK 1 //额外的闪屏次数
#define SIMULATE_SLOW_REFRESH_DELAY 250 //慢刷延时
#define SIMULATE_FAST_REFRESH_DELAY 50 //快刷延时
#define SIMULATE_GREYSCALE_COLOUR //仿真灰度时, 读取屏幕像素决定色彩 (更逼真但更慢)
#ifdef ESP8266
#define DISPLAY_TYPE_ST7789_240320 //2.0寸的ST7789 IPS TFT模块

View File

@@ -45,25 +45,42 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷
if(!(m&1)) return; //stage 1
uint16_t dat[8];
unsigned short xbits=(drv_width()+7)/8;
ips.startWrite();
if(partMode==0){
ips.invertDisplay(1);
DelayMs(250);
DelayMs(SIMULATE_SLOW_REFRESH_DELAY);
#if ((SIMULATE_BLINK) > 1)
ips.invertDisplay(0);
DelayMs(250);
DelayMs(SIMULATE_SLOW_REFRESH_DELAY);
ips.invertDisplay(1);
DelayMs(250);
DelayMs(SIMULATE_SLOW_REFRESH_DELAY);
#endif
#if ((SIMULATE_BLINK) > 0)
ips.invertDisplay(0);
DelayMs(SIMULATE_SLOW_REFRESH_DELAY);
ips.invertDisplay(1);
DelayMs(SIMULATE_SLOW_REFRESH_DELAY);
#endif
ips.invertDisplay(0);
}
for(int j=0;j<drv_height();j++){
for(int i=0;i<xbits;i++){
uint_fast8_t readf=f(j*xbits+i);
#ifdef SIMULATE_GREYSCALE_COLOUR
if(readf == 0xff && i!=xbits-1)
#endif
ips.drawFastHLine(WHITE_GAP+i*8,WHITE_GAP+j,8,0xffff);
else {
#ifdef SIMULATE_GREYSCALE_COLOUR
else
#endif
{
int lineOK=0;
#ifdef SIMULATE_GREYSCALE_COLOUR
if(partMode)//注意这里 readrect函数已经自动化实现边界处理了
ips.readRect(WHITE_GAP+i*8,WHITE_GAP+j,8,1,dat);
else memset(dat,0xff,sizeof(dat));
else
#endif
memset(dat,0xff,sizeof(dat));
if(readf == 0x00 && i!=xbits-1){
for(int k=0;k<8;k++)
if((dat[k]&0x1f)==0x1f) lineOK++;
@@ -74,16 +91,23 @@ void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷
}
for(int k=0;k<8;k++){
if(i==xbits-1 && i*8+k>=drv_width()) break;
#ifdef SIMULATE_GREYSCALE_COLOUR
if((readf&(0x80>>k)))
ips.drawPixel(WHITE_GAP+i*8+k,WHITE_GAP+j,0xffff);
else if((dat[k]&0x1f)==0x1f)
ips.drawPixel(WHITE_GAP+i*8+k,WHITE_GAP+j,0x1082*(15-depth));
#else
if(!(readf&(0x80>>k))) {
ips.drawPixel(WHITE_GAP+i*8+k,WHITE_GAP+j,0x1082*(15-depth));
}
#endif
}
}
}
yield();
}
delay(50);
ips.endWrite();
DelayMs(SIMULATE_FAST_REFRESH_DELAY);
}
void drv::drv_sleep() {}
}

View File

@@ -40,10 +40,10 @@
//务必保证这些版本号是一致的.
//另外, 在提交新版本之前, 不要忘记在github上创建release, 否则Arduino IDE会读不到
#define READGUY_V_MAJOR 1
#define READGUY_V_MINOR 3
#define READGUY_V_PATCH 7
#define READGUY_V_MINOR 4
#define READGUY_V_PATCH 0
#define READGUY_VERSION_VAL (READGUY_V_MAJOR*1000+READGUY_V_MINOR*100+READGUY_V_PATCH*10)
#define READGUY_VERSION "1.3.7"
#define READGUY_VERSION "1.4.0"
#ifdef ESP8266
#define _READGUY_PLATFORM "ESP8266"
@@ -61,8 +61,8 @@
#endif
#endif
#define _GITHUB_LINK "github.com/fsender/readguy"
#define _BILIBILI_LINK "www.bilibili.com/video/BV1f94y187wz"
#define _GITHUB_LINK "https://github.com/fsender/readguy"
#define _BILIBILI_LINK "https://www.bilibili.com/video/BV1f94y187wz"
#endif /* END OF FILE. ReadGuy project.

View File

@@ -28,11 +28,20 @@
*/
#include "readguy.h"
/* #if (!defined(ESP8266)) //for ESP32, ESP32S2, ESP32S3, ESP32C3
#include "esp_flash.h"
#endif */
#ifdef READGUY_ESP_ENABLE_WIFI
static const PROGMEM char NOT_SUPPORTED[] = "(不支持此屏幕)";
static const PROGMEM char TEXT_HTML[] = "text/html";
static const PROGMEM char TEXT_PLAIN [] = "text/plain";
static const PROGMEM char text_http_methods[8][8]={
"UPLOAD", "404", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"
};
static const HTTPMethod val_http_methods[6]={
HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS
};
static const PROGMEM char args_name[24][8]={
"share","epdtype","EpdMOSI","EpdSCLK","Epd_CS","Epd_DC","Epd_RST","EpdBusy",
"SD_MISO","SD_MOSI","SD_SCLK","SD_CS","I2C_SDA","I2C_SCL",
@@ -187,7 +196,9 @@ void ReadguyDriver::ap_setup(const char *ssid, const char *pass, int m){
IPAddress subnet(255,255,255,0);
WiFi.softAPConfig(local_IP, gateway, subnet);
WiFi.softAP(ssid,pass);
#ifdef READGUY_SERIAL_DEBUG
Serial.printf_P(PSTR("[Guy AP] ap_setup SSID: %s, Pass: %s\n"),ssid,pass);
#endif
}
void ReadguyDriver::server_setup(const String &notify, const serveFunc *serveFuncs, int funcs){
//启动WiFi服务器端, 这样就可以进行配网工作
@@ -198,6 +209,7 @@ void ReadguyDriver::server_setup(const String &notify, const serveFunc *serveFun
sv.on("/pinsetup", HTTP_GET, std::bind(&ReadguyDriver::handlePinSetup ,this));
sv.on("/final", HTTP_POST, std::bind(&ReadguyDriver::handleFinalPost,this)); //此时验证已经正确
//sv.on("/wifi", HTTP_GET, std::bind(&ReadguyDriver::handleWiFi ,this)); //此时验证已经正确
sv.onNotFound(std::bind(&ReadguyDriver::handleNotFound,this)); //处理404的情况
guy_notify=notify;
sfuncs=funcs; //设置服务函数列表
if(sfnames!=nullptr) { delete [] sfnames; delete [] sfevents; } //严防内存泄露
@@ -205,7 +217,14 @@ void ReadguyDriver::server_setup(const String &notify, const serveFunc *serveFun
sfnames=new String[sfuncs];
sfevents=new String[sfuncs];
for(int i=0;i<sfuncs;i++){ //set-up 第三方库内容, 初始化后即可使用
sv.on(serveFuncs[i].event,HTTP_GET,std::bind(serveFuncs[i].func,&sv));
int spec = -1;
for(int ij=0;ij<8;ij++){ //处理一些HTTP不同类型请求.
if(!strcmp_P(serveFuncs[i].linkname.c_str(),text_http_methods[ij])) spec = ij;
}
if(spec>1) sv.on(serveFuncs[i].event,val_http_methods[spec-2],std::bind(serveFuncs[i].func,&sv));
else if(spec==1) sv.onNotFound(std::bind(serveFuncs[i].func,&sv)); //404
else if(spec==0) sv.onFileUpload(std::bind(serveFuncs[i].func,&sv)); //文件上传
else sv.on(serveFuncs[i].event,HTTP_GET,std::bind(serveFuncs[i].func,&sv));
sfnames[i] = serveFuncs[i].linkname;
sfevents[i] = serveFuncs[i].event;
}
@@ -220,13 +239,14 @@ void ReadguyDriver::server_setup(const String &notify, const serveFunc *serveFun
"Connection: close\r\n\r\n"),89);
sv.client().write_P((const char *)faviconData,sizeof(faviconData));
});*/
sv.onNotFound(std::bind(&ReadguyDriver::handleNotFound,this)); //处理404的情况
sv.begin();
MDNS.begin("readguy");
//MDNS.addService("http","tcp",80);
#ifdef READGUY_SERIAL_DEBUG
Serial.print(F("[Guy server] Done! visit "));
if(WiFi.getMode() == WIFI_AP) Serial.println(F("192.168.4.1"));
else Serial.println(WiFi.localIP());
#endif
}
bool ReadguyDriver::server_loop(){ //此时等待网页操作完成响应...
sv.handleClient();
@@ -251,10 +271,16 @@ bool ReadguyDriver::server_loop(){ //此时等待网页操作完成响应...
refFlag=3;
}
if(refFlag!=127) {
Serial.printf("randch: %d %c\n",randomch[refFlag],(char)(randomch[refFlag]));
#ifdef READGUY_SERIAL_DEBUG
Serial.printf_P(PSTR("randch: %d %c\n"),randomch[refFlag],(char)(randomch[refFlag]));
#endif
drawChar((guy_dev->drv_width()>>1)-46+refFlag*24,(guy_dev->drv_height()>>1)-14,randomch[refFlag],true,false,4);
refresh_begin(0);
guy_dev->drv_fullpart(1);
guy_dev->_display((const uint8_t*)getBuffer());
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
refresh_end();
#endif
}
}
delay(1); //防止触发看门狗
@@ -279,7 +305,9 @@ void ReadguyDriver::handleInitPost(){
// 此时返回一个文本输入框, 定位到 handleFinalPost 函数
uint8_t btn_count_=0;
if(READGUY_cali){ //再次初始化已经初始化的东西, 此时需要关闭一些外设什么的
#ifdef READGUY_SERIAL_DEBUG
Serial.println(F("[Guy Pin] Reconfig pins and hardwares..."));
#endif
READGUY_cali=0;
READGUY_sd_ok=0;
#if defined(ESP8266)
@@ -301,13 +329,19 @@ void ReadguyDriver::handleInitPost(){
}
config_data[0]=1; //默认只要运行到此处, 就已经初始化好了的
for(int i=0;i<33;i++){
#ifdef READGUY_SERIAL_DEBUG
Serial.print(F("Argument "));
#endif
String a_name = String(FPSTR(args_name[23])) + (i-22);
if(i<=22) a_name = FPSTR(args_name[i]);
#ifdef READGUY_SERIAL_DEBUG
Serial.print(a_name);
Serial.write(':');
#endif
if(sv.hasArg(a_name)) {
#ifdef READGUY_SERIAL_DEBUG
Serial.println(sv.arg(a_name));
#endif
if(i<14){ //这12个引脚是不可以重复的, 如果有重复, config_data[0]设为0
config_data[i+1] = sv.arg(FPSTR(args_name[i])).toInt();
}
@@ -319,13 +353,15 @@ void ReadguyDriver::handleInitPost(){
else if(i==19&&btn_count_>2) config_data[17]=sv.arg(FPSTR(args_name[19])).toInt()+1;
else if(i==20&&btn_count_>2) config_data[17]=-config_data[17];
else if(i==21) config_data[18] = sv.arg(FPSTR(args_name[21])).toInt();
else if(i==22) config_data[19] = sv.arg(FPSTR(args_name[22])).toInt(); //保留RTC功能
else if(i==22) config_data[19] = sv.arg(FPSTR(args_name[22])).toInt(); //现已弃用 RTC 功能.
else if(i>22){ //用户数据
config_data[i-1] = sv.arg(a_name).toInt();
}
}
else {
#ifdef READGUY_SERIAL_DEBUG
Serial.write('\n');
#endif
if(i==0) READGUY_shareSpi = 0; //有的html响应是没有的.共享SPI默认值为true.
else if(i<14) config_data[i+1] = -1;//这12个引脚是不可以重复的, 如果有重复, config_data[0]设为0
}
@@ -350,7 +386,9 @@ void ReadguyDriver::handleInitPost(){
uint8_t ck=checkEpdDriver();
if(btn_count_<2) config_data[16]=0;
if(btn_count_<3) config_data[17]=0;
#ifdef READGUY_SERIAL_DEBUG
Serial.println(F("[Guy Pin] Config OK. Now init devices."));
#endif
if(ck>=125) {
const char *pNotify[3]={ PSTR("Necessary pin NOT connected."),\
PSTR("Pin conflicted."),PSTR("Display not supported.") };
@@ -374,12 +412,16 @@ void ReadguyDriver::handleInitPost(){
randomch[1] = 48+((rdm>>12)%10);//R2CHAR((rdm>>12)%10);
randomch[2] = 48+((rdm>> 6)%10);//R2CHAR((rdm>> 6)%10);
randomch[3] = 48+((rdm )%10);//R2CHAR((rdm )%10);
#ifdef READGUY_SERIAL_DEBUG
Serial.print(F("[Guy] rand string: "));
for(int i=0;i<4;i++) Serial.write(randomch[i]);
Serial.write('\n');
Serial.println(F("[Guy] Init EPD...")); //此时引脚io数据已经录入, 如果没有问题, 此处屏幕应当可以显示
#endif
setEpdDriver(); //尝试初始化屏幕
#ifdef READGUY_SERIAL_DEBUG
Serial.println(F("[Guy] Init details..."));
#endif
setTextSize(1);
drawCenterString(setSDcardDriver()?"SD Init OK!":"SD Init failed!",
guy_dev->drv_width()>>1,(guy_dev->drv_height()>>1)+20);
@@ -389,11 +431,15 @@ void ReadguyDriver::handleInitPost(){
drawRect((guy_dev->drv_width()>>1)-46+24,(guy_dev->drv_height()>>1)-14,20,28,0);
drawRect((guy_dev->drv_width()>>1)-46+48,(guy_dev->drv_height()>>1)-14,20,28,0);
drawRect((guy_dev->drv_width()>>1)-46+72,(guy_dev->drv_height()>>1)-14,20,28,0);
spibz++;
refresh_begin(0);
guy_dev->drv_fullpart(1);
guy_dev->_display((const uint8_t*)getBuffer());
spibz--;
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
refresh_end();
#endif
#ifdef READGUY_SERIAL_DEBUG
Serial.println(F("[Guy] Display done!"));
#endif
READGUY_cali=1; //显示初始化完成
}
void ReadguyDriver::handlePinSetup(){
@@ -408,7 +454,7 @@ void ReadguyDriver::handlePinSetup(){
args_name[15],args_name[17],args_name[19],args_name[21],args_name[12],args_name[13]
};
static const PROGMEM int dem_args_val[DRIVER_TEMPLATE_N][DRIVER_TEMPLATE_ARRAY_L]={
{ 6,15, 0, 2, 4, 5, 2, 0, 3,-1,-1,13,14},
{ 6,15, 0, 2, 4, 5, 2, 3, 0,-1,-1,13,14},
//{ 0,10, 9, 8, 7, 4, 3, 2, 3, 5, 6,SDA,SCL},
//{ 0,15, 4, 2, 5,-1, 1, 0,-1,-1,-1,-1,-1} //微雪官方例程板子不支持SD卡, 也不支持I2C. 按钮为boot按钮
};
@@ -593,7 +639,12 @@ void ReadguyDriver::handleFinal(){
s += F("</h3><hr/>");
if(sfuncs>0){
s+=F("以下链接来自<b>应用程序</b><br/>"); //换行
for(int i=0;i<sfuncs && sfnames[i]!=emptyString;i++){
for(int i=0;i<sfuncs;i++){
int spec = -1;
for(int ij=0;ij<8;ij++){
if(!strcmp_P(sfnames[i].c_str(),text_http_methods[ij])) spec = ij;
}
if(spec != -1 || sfnames[i]==emptyString) continue;
s+=F("<a href=\"");
s+=sfevents[i];
s+=F("\">");
@@ -635,7 +686,7 @@ void ReadguyDriver::handleFinal(){
#endif
#endif
s+=F("当前WiFi模式: ");
s+=(WiFi.getMode()==WIFI_STA)?F("正常联网模式"):F("AP配网模式");
s+=(WiFi.getMode()==WIFI_AP_STA)?F("热点联网模式"):((WiFi.getMode()==WIFI_STA)?F("正常联网模式"):F("热点配置模式"));
s+=F(", IP地址: ");
s+=WiFi.localIP().toString();
s+=F("<br/>芯片型号: ");
@@ -682,7 +733,9 @@ void ReadguyDriver::handleFinal(){
//s+=F("<br/>"); //换行
sv.send_P(200, TEXT_HTML, (s+FPSTR(end_html)).c_str());
if(READGUY_cali == 63){
#ifdef READGUY_SERIAL_DEBUG
Serial.println(F("[Guy NVS] Data saved to NVS."));
#endif
READGUY_cali = 127;
nvs_init();
nvs_write();

View File

@@ -28,12 +28,26 @@
*/
#include "readguy.h"
#if (!defined(INPUT_PULLDOWN))
/* #if (!defined(ESP8266)) //for ESP32, ESP32S2, ESP32S3, ESP32C3
#include "esp32-hal.h"
#endif */
#if (!defined(INPUT_PULLDOWN)) //not supported pinMode
#define INPUT_PULLDOWN INPUT
#endif
guy_button ReadguyDriver::btn_rd[3];
int8_t ReadguyDriver::pin_cmx=-1;
int8_t ReadguyDriver::pin_cmx=-1;
#ifdef READGUY_ALLOW_DC_AS_BUTTON
bool ReadguyDriver::refresh_state=1; //1: free; 0: busy(refreshing)
uint8_t ReadguyDriver::refresh_press=0x7f; //0x7f: no button pressed other:button pressed pin
#endif
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
uint8_t ReadguyDriver::static_epd_cs=0x7f;
#endif
#ifdef READGUY_ALLOW_SDCS_AS_BUTTON
uint8_t ReadguyDriver::static_sd_cs=0x7f;
volatile uint8_t ReadguyDriver::sd_cs_busy=0;
#endif
const PROGMEM char ReadguyDriver::projname[8] = "readguy";
const PROGMEM char ReadguyDriver::tagname[7] = "hwconf";
@@ -63,7 +77,7 @@ const int8_t ReadguyDriver::config_data[32] = {
READGUY_btn2 ,
READGUY_btn3 ,
READGUY_bl_pin ,//前置光接口引脚IO
READGUY_rtc_type ,//使用的RTC型号(待定, 还没用上)
READGUY_rtc_type ,//使用的RTC型号. 现已弃用 RTC 功能. 保留是为了兼容性 让代码更简单维护
0 ,//READGUY_sd_ok SD卡已经成功初始化
0 ,//READGUY_buttons 按钮个数, 0-3都有可能
-1, //用户自定义变量 同时用于esp32s3使用SDIO卡数据的DAT1 为-1代表不使用SDIO
@@ -79,16 +93,18 @@ TaskHandle_t ReadguyDriver::btn_handle;
ReadguyDriver::ReadguyDriver(){
READGUY_cali = 0; // config_data[0] 的初始值为0
#ifdef DYNAMIC_PIN_SETTINGS
for(unsigned int i=1;i<sizeof(config_data);i++) config_data[i] = -1;
#endif
READGUY_sd_ok = 0; //初始默认SD卡未成功初始化
READGUY_buttons = 0; //初始情况下没有按钮
} //WiFiSet: 是否保持AP服务器一直处于打开状态
uint8_t ReadguyDriver::init(uint8_t WiFiSet, bool initepd, bool initSD){
if(READGUY_cali==127) //已经初始化过了一次了, 为了防止里面一些volatile的东西出现问题....还是退出吧
return 0;
return READGUY_sd_ok;
#ifdef DYNAMIC_PIN_SETTINGS
nvs_init();
#if (!defined(INDEV_DEBUG))
#if (!defined(READGUY_INDEV_DEBUG))
if(!nvs_read()){ //如果NVS没有录入数据, 需要打开WiFiAP模式初始化录入引脚数据
#endif
#ifdef READGUY_ESP_ENABLE_WIFI
@@ -105,12 +121,24 @@ uint8_t ReadguyDriver::init(uint8_t WiFiSet, bool initepd, bool initSD){
server_end();
if(!WiFiSet) WiFi.mode(WIFI_OFF);
fillScreen(1);
#else //DYNAMIC_PIN_SETTINGS 已定义 and READGUY_ESP_ENABLE_WIFI 已定义 but NVS无数据, 此时无法配置引脚. 视为halt
(void)WiFiSet; //avoid warning
nvs_deinit(); //invalid
Serial.printf_P(PSTR("[Guy NVS] INVALID pin settings on " _READGUY_PLATFORM " (Readguy lib version " READGUY_VERSION ")!\n"\
"Please open guy_driver_config.h and uncomment #define READGUY_ESP_ENABLE_WIFI!\n"\
"You can also flash example binary with Wi-Fi, configure pins and re-flash this program.\n"\
"System will restart in 5 seconds..."));
delay(5000);
ESP.restart();
#endif
#if (!defined(INDEV_DEBUG))
#if (!defined(READGUY_INDEV_DEBUG))
}
else{ //看来NVS有数据, //从NVS加载数据, 哪怕前面的数据刚刚写入, 还没读取
#ifdef READGUY_ESP_ENABLE_WIFI
if(WiFiSet>=2) WiFi.begin(); //连接到上次存储在flash NVS中的WiFi.
else if(WiFiSet==1) ap_setup();
else
#endif
if(WiFiSet==1) ap_setup();
if(checkEpdDriver()!=127) setEpdDriver(initepd/* ,g_width,g_height */); //初始化屏幕
else for(;;); //此处可能添加程序rollback等功能操作(比如返回加载上一个程序)
if(initSD) setSDcardDriver();
@@ -119,6 +147,7 @@ uint8_t ReadguyDriver::init(uint8_t WiFiSet, bool initepd, bool initSD){
#endif
nvs_deinit();
#else
(void)WiFiSet; //avoid warning
nvs_init();
if(checkEpdDriver()!=127) setEpdDriver(initepd/* ,g_width,g_height */); //初始化屏幕
else for(;;); //此处可能添加程序rollback等功能操作(比如返回加载上一个程序)
@@ -129,7 +158,9 @@ uint8_t ReadguyDriver::init(uint8_t WiFiSet, bool initepd, bool initSD){
}
nvs_deinit();
#endif
#ifdef READGUY_SERIAL_DEBUG
Serial.println(F("[Guy init] init done."));
#endif
READGUY_cali=127;
return READGUY_sd_ok;
}
@@ -140,7 +171,9 @@ uint8_t ReadguyDriver::checkEpdDriver(){
#else
#define TEST_ONLY_VALUE 3
#endif
#ifdef READGUY_SERIAL_DEBUG
Serial.printf_P(PSTR("[Guy SPI] shareSpi? %d\n"),READGUY_shareSpi);
#endif
for(int i=TEST_ONLY_VALUE;i<8;i++){
if(i<7 && config_data[i]<0) return 125;//必要的引脚没连接
for(int j=1;j<=8-i;j++)
@@ -218,7 +251,9 @@ uint8_t ReadguyDriver::checkEpdDriver(){
#endif
//添加新屏幕型号 add displays here
default:
Serial.println(F("[GUY ERR] EPD DRIVER IC NOT SUPPORTED!\n"));
#ifdef READGUY_SERIAL_DEBUG
Serial.println(F("[Guy Error] EPD DRIVER IC NOT SUPPORTED!\n"));
#endif
return 127;
}
#else
@@ -285,7 +320,9 @@ uint8_t ReadguyDriver::checkEpdDriver(){
epd_spi->begin(READGUY_epd_sclk,READGUY_shareSpi?READGUY_sd_miso:-1,READGUY_epd_mosi);
guy_dev->IfInit(*epd_spi, READGUY_epd_cs, READGUY_epd_dc, READGUY_epd_rst, READGUY_epd_busy);
#endif
#ifdef READGUY_SERIAL_DEBUG
Serial.println(F("[Guy SPI] drvBase Init OK"));
#endif
return READGUY_epd_type;
}
void ReadguyDriver::setEpdDriver(bool initepd, bool initGFX){
@@ -311,7 +348,9 @@ void ReadguyDriver::setEpdDriver(bool initepd, bool initGFX){
setTextColor(0);
fillScreen(1); //开始先全屏白色
}
#ifdef READGUY_SERIAL_DEBUG
Serial.printf_P(PSTR("[Guy EPD] EPD init OK(%d): w: %d, h: %d\n"),guy_dev->drv_ID(),guy_dev->drv_width(),guy_dev->drv_height());
#endif
}
#ifdef READGUY_ENABLE_SD
bool ReadguyDriver::setSDcardDriver(){
@@ -326,8 +365,11 @@ bool ReadguyDriver::setSDcardDriver(){
#endif
&& READGUY_sd_cs!=READGUY_epd_cs && READGUY_sd_cs!=READGUY_epd_dc && READGUY_sd_cs!=READGUY_epd_rst && READGUY_sd_cs!=READGUY_epd_busy
){ //SD卡的CS检测程序和按键检测程序冲突, 故删掉 (可能引发引脚无冲突但是显示冲突的bug)
#if defined(ESP8266)
//Esp8266无视SPI的设定, 固定为唯一的硬件SPI (D5=SCK, D6=MISO, D7=MOSI)
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON))
setSDbusy(1);
#endif
#if defined(ESP8266) //Esp8266无视SPI的设定, 固定为唯一的硬件SPI (D5=SCK, D6=MISO, D7=MOSI)
SDFS.end();
SDFS.setConfig(SDFSConfig(READGUY_sd_cs));
READGUY_sd_ok = SDFS.begin();
#else
@@ -340,11 +382,16 @@ bool ReadguyDriver::setSDcardDriver(){
sd_spi->begin(READGUY_sd_sclk,READGUY_sd_miso,READGUY_sd_mosi); //初始化SPI
}
READGUY_sd_ok = SD.begin(READGUY_sd_cs,*sd_spi,ESP32_SD_SPI_FREQUENCY); //初始化频率为20MHz
#endif
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON))
setSDbusy(0);
#endif
}
else READGUY_sd_ok=0; //引脚不符合规则,或冲突或不可用
if(!READGUY_sd_ok){
#ifdef READGUY_SERIAL_DEBUG
Serial.println(F("[Guy SD] SD Init Failed!"));
#endif
//guyFS().begin(); //初始化内部FS
#ifdef READGUY_USE_LITTLEFS
LittleFS.begin();
@@ -367,7 +414,7 @@ bool ReadguyDriver::setSDcardDriver(){
#endif
void ReadguyDriver::setButtonDriver(){
if(READGUY_btn1) { //初始化按键. 注意高电平触发的引脚在初始化时要设置为下拉
int8_t btn_pin=abs(READGUY_btn1)-1;
int8_t btn_pin=abs((int)READGUY_btn1)-1;
#if defined(ESP8266) //只有ESP8266是支持16引脚pulldown功能的, 而不支持pullup
if(btn_pin == 16) pinMode(16,(READGUY_btn1>0)?INPUT:INPUT_PULLDOWN_16);
else if(btn_pin < 16 && btn_pin != D5 && btn_pin != D6 && btn_pin != D7)
@@ -404,6 +451,16 @@ void ReadguyDriver::setButtonDriver(){
|| abs(READGUY_btn3)-1==READGUY_epd_dc ) {
pin_cmx=READGUY_epd_dc; //DC引脚复用
}
#if ((defined (READGUY_ALLOW_EPDCS_AS_BUTTON)) || ((defined(READGUY_ALLOW_SDCS_AS_BUTTON)) && (defined(READGUY_ENABLE_SD))))
for(int j=15;j<=17;j++){ //btn1~3
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
if(READGUY_epd_cs == abs(config_data[j])-1) static_epd_cs = READGUY_epd_cs;
#endif
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON) && defined(READGUY_ENABLE_SD))
if(READGUY_sd_cs == abs(config_data[j])-1 && READGUY_sd_cs!=-1) static_sd_cs = READGUY_sd_cs;
#endif
}
#endif
//初始化按钮, 原计划要使用Button2库, 后来发现实在是太浪费内存, 于是决定自己写
if(READGUY_btn1) btn_rd[0].begin(abs(READGUY_btn1)-1,rd_btn_f,(READGUY_btn1>0));
if(READGUY_btn2) btn_rd[1].begin(abs(READGUY_btn2)-1,rd_btn_f,(READGUY_btn2>0));
@@ -519,56 +576,105 @@ void ReadguyDriver::display(uint8_t part){
//......可惜'dynamic_cast' not permitted with -fno-rtti
// static bool _part = 0; 记忆上次到底是full还是part, 注意启动时默认为full
if(READGUY_cali==127){
part = refresh_begin(part);
//in_press(); //暂停, 然后读取按键状态 spibz
guy_dev->drv_fullpart(part&1);
guy_dev->_display((const uint8_t*)getBuffer(),((part>>1)?part>>1:3));
//in_release(); //恢复
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
refresh_end();
#endif
}
}
void ReadguyDriver::displayBuffer(const uint8_t *buf, uint8_t part){
if(READGUY_cali==127){
part = refresh_begin(part);
//in_press(); //暂停, 然后读取按键状态 spibz
guy_dev->drv_fullpart(part&1);
epdPartRefresh++;
guy_dev->_display(buf,((part>>1)?part>>1:3));
//in_release(); //恢复
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
refresh_end();
#endif
}
}
void ReadguyDriver::display(std::function<uint8_t(int)> f, uint8_t part){
if(READGUY_cali==127){
part = refresh_begin(part);
//in_press(); //暂停, 然后读取按键状态 spibz
guy_dev->drv_fullpart(part&1);
guy_dev->drv_dispWriter(f,((part>>1)?part>>1:3));
//in_release(); //恢复
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
refresh_end();
#endif
}
}
void ReadguyDriver::drawImage(LGFX_Sprite &base, LGFX_Sprite &spr,int32_t x,int32_t y,int32_t zoomw, int32_t zoomh) {
if(READGUY_cali==127) guy_dev->drv_drawImage(base, spr, x, y, 0, zoomw, zoomh);
if(READGUY_cali==127) {
refresh_begin(0);
guy_dev->drv_drawImage(base, spr, x, y, 0, zoomw, zoomh);
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
refresh_end();
#endif
}
}
void ReadguyDriver::drawImageStage(LGFX_Sprite &sprbase,LGFX_Sprite &spr,int32_t x,int32_t y,uint8_t stage,
uint8_t totalstage,int32_t zoomw,int32_t zoomh) {
if(READGUY_cali!=127 || stage>=totalstage) return;
//Serial.printf("stage: %d/%d\n",stage+1,totalstage);
#ifdef READGUY_SERIAL_DEBUG
Serial.printf_P(PSTR("[Guy Draw] stage: %d/%d\n"),stage+1,totalstage);
#endif
refresh_begin(0);
guy_dev->drv_drawImage(sprbase, spr, x, y, (totalstage<=1)?0:(stage==0?1:(stage==(totalstage-1)?3:2)),zoomw,zoomh);
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
refresh_end();
#endif
}
void ReadguyDriver::setDepth(uint8_t d){
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling()) guy_dev->drv_setDepth(d);
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling()) {
// refresh_begin(0);
if(d==0 || d>15) { d=15; } //invalid. set to default value 15.
guy_dev->drv_setDepth(d);
current_depth = d;
//#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
// refresh_end();
//#endif
}
}
void ReadguyDriver::draw16grey(LGFX_Sprite &spr,int32_t x,int32_t y,int32_t zoomw,int32_t zoomh){
if(READGUY_cali!=127) return;
refresh_begin(0);
if(guy_dev->drv_supportGreyscaling() && (spr.getColorDepth()&0xff)>1)
return guy_dev->drv_draw16grey(*this,spr,x,y,zoomw,zoomh);
guy_dev->drv_drawImage(*this, spr, x, y, 0, zoomw, zoomh);
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
refresh_end();
#endif
}
void ReadguyDriver::draw16greyStep(int step){
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling() && step>0 && step<16 ){
if(step==1) guy_dev->drv_fullpart(1);
if(step==1) {
refresh_begin(0);
guy_dev->drv_fullpart(1);
}
guy_dev->drv_draw16grey_step((const uint8_t *)this->getBuffer(),step);
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
if(step>=15) refresh_end();
#endif
}
}
void ReadguyDriver::draw16greyStep(std::function<uint8_t(int)> f, int step){
if(READGUY_cali==127 && guy_dev->drv_supportGreyscaling() && step>0 && step<16 ){
if(step==1) guy_dev->drv_fullpart(1);
if(step==1) {
refresh_begin(0);
guy_dev->drv_fullpart(1);
}
guy_dev->drv_draw16grey_step(f,step);
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
if(step>=15) refresh_end();
#endif
}
}
void ReadguyDriver::invertDisplay(){
@@ -579,10 +685,100 @@ void ReadguyDriver::invertDisplay(){
}
}
void ReadguyDriver::sleepEPD(){
if(READGUY_cali==127) guy_dev->drv_sleep();
if(READGUY_cali==127) {
if(READGUY_bl_pin>=0) digitalWrite(READGUY_bl_pin, LOW); //关闭背光灯, 节省电量
guy_dev->drv_sleep();
}
}
#if (defined(INDEV_DEBUG))
uint8_t ReadguyDriver::refresh_begin(uint8_t freshType){
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
if(refresh_state){
refresh_state=0;
refresh_press = 0x7f; //clear state
for(uint8_t i=0;i<3;i++){ //修复老旧硬件 按键和DC引脚冲突
bool flag = 0;
if(config_data[15+i] == 0) break;
int ipin = abs((int)config_data[15+i])-1;
if(ipin == (int)READGUY_epd_dc){ //旨在解决部分老旧硬件共用DC引脚
while(btn_rd[i].isPressedRaw() == ((int)config_data[15+i] > 0)) { //这里需要按下的状态
flag = 1;
yield();
}
if(flag) {
#ifdef READGUY_SERIAL_DEBUG
Serial.printf_P(PSTR("[Guy Pin] refresh_begin pin %d mode output\n"), READGUY_epd_dc);
#endif //等待恢复到按键空闲电平 btn>0 代表低电平按下, 此时右边为1 btn<0 代表高电平按下
delay(btn_rd[i].min_debounce); //去抖动
//#ifdef ESP8266
// btnTask.detach();//暂时关闭任务, 避免引脚被设置为非法模式
//#else
// vTaskSuspend(btn_handle);//暂时关闭任务, 避免引脚被设置为非法模式
//#endif
spibz|=0x40; //set bit at 0x40
refresh_press = i;
//pinMode((uint8_t)READGUY_epd_dc, OUTPUT);
}
}
}
}
#endif
if((freshType&1)==1){ //隶属于快刷的范畴, 计数+1
if(epdPartRefresh >= epdForceFull) {
epdPartRefresh = 0;
return (freshType & 0xfe);
}
else {
if(!epdPartRefresh) guy_dev->drv_setDepth(current_depth); //慢刷完成后的首次快刷, 保存上次的刷新颜色深度
if(epdPartRefresh<0x7ffe) epdPartRefresh++;
}
}
else epdPartRefresh = 0; //全刷, 重置计数器
return freshType;
}
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
void ReadguyDriver::refresh_end(){
#ifdef READGUY_ALLOW_DC_AS_BUTTON
//for(uint8_t i=15;i<=17;i++){ //修复老旧硬件 按键和DC引脚冲突
// if(config_data[i] == 0) break;
// int ipin = abs((int)config_data[i])-1;
if(refresh_press != 0x7f && !refresh_state){ //旨在解决部分老旧硬件共用DC引脚的bug
#ifdef READGUY_SERIAL_DEBUG
Serial.printf_P(PSTR("[Guy Pin] refresh_end pin %d\n"), READGUY_epd_dc);
#endif //pinMode((uint8_t)READGUY_epd_dc, INPUT_PULLUP);
spibz&=0x3f; //reset bit at 0x40
//#ifdef ESP8266
// btnTask.attach_ms(BTN_LOOPTASK_DELAY,looptask);
//#else
// vTaskResume(btn_handle);
//#endif //开启任务后, 延时确保按键任务可以活跃而不是一直处于被暂停又刷屏的无限循环
delay((BTN_LOOPTASK_DELAY+btn_rd[refresh_press].min_debounce)*2);
}
refresh_state = 1;
#endif
}
#endif
void ReadguyDriver::setAutoFullRefresh(int16_t frames){
//epdPartRefresh = frames<0?-frames:0;
if(frames<0) epdPartRefresh = -frames;
if(frames) {
epdForceFull = (frames<0?-frames:frames);
}
else {
epdForceFull = 0x7fff;
}
}
#ifdef ESP8266
void ReadguyDriver::recoverI2C(){
if(READGUY_cali!=127) return;
for(int i=13;i<=14;i++){ // READGUY_i2c_scl == config_data[14]; READGUY_i2c_sda == config_data[13];
if(config_data[i] == 12 || config_data[i] == 13 || config_data[i] == 14) pinMode(config_data[i], SPECIAL);
for(int j=15;j<=17;j++){ // READGUY_btn1 == config_data[15]; b2 == config_data[15]; b3== config_data[17];
if(config_data[i] == abs((int)config_data[j])-1) pinMode(config_data[i], config_data[j]>0?INPUT_PULLUP:INPUT_PULLDOWN);
}
}
}
#endif
#if (defined(READGUY_INDEV_DEBUG))
void ReadguyDriver::nvs_init(){
}
void ReadguyDriver::nvs_deinit(){
@@ -614,7 +810,9 @@ bool ReadguyDriver::nvs_read(){
#endif
s[i]=(char)rd;
}
Serial.printf("[Guy NVS] Get EEPROM...%d\n", config_data[0]);
#ifdef READGUY_SERIAL_DEBUG
Serial.printf_P(PSTR("[Guy NVS] ReadGuy Ver " READGUY_VERSION " on " _READGUY_PLATFORM " Get EEPROM...%d\n"), config_data[0]);
#endif
return !(strcmp_P(s,projname));
}
void ReadguyDriver::nvs_write(){
@@ -725,19 +923,109 @@ void ReadguyDriver::looptask(){ //均为类内静态数据
btn_rd[1].loop();
btn_rd[2].loop();
}
bool ReadguyDriver::screenshot(const char *filename){
#ifdef READGUY_ENABLE_SD
if(!SDinside(false)) return 0;
uint16_t ibytes = ((width()+31)>>3)&0x7ffcu; //必须是4的倍数
uint16_t bmpHeader[] = { //0x3e == 62 字节
0x4d42, //[ 0]字符BM, 固定文件头
0x0f7e,0,0,0, //[ 1]File Size 文件总大小 文件大小0x0f7e == 3966; 位图数据大小32*122 == 3904
0x003e,0, //[ 5]Bitmap Data Offset (BDO) 信息头到数据段的字节数 (索引到0x3e后的第一个数据就是位图字节数据)
0x0028,0, //[ 7]Bitmap Header Size (BHS) 信息头长度
0x00fa,0, //[ 9]宽度 0xfa == 250
0x007a,0, //[11]高度 0x7a == 122
0x01, //[13]Planes 位面数(图层数) 锁定为1
0x01, //[14]Bits Per Pixel (BPP) 每像素位数 (1bit/pixel)
0,0, //[15]Compression 压缩方法 压缩说明0-无压缩
0x0f40,0, //[17]Bitmap Data Size 位图数据的字节数。该数必须是4的倍数 0x0f40 == 3904 == 32*122
0x0ec4,0, //[19]Horizontal Resolution 水平分辨率 0x0ec4==3780 (pixel/metre)==96.012 (pixel/inch)
0x0ec4,0, //[21]Vertical Resolution 水平分辨率 0x0ec4==3780 (pixel/metre)==96.012 (pixel/inch)
0,0, //[23]Colours 位图使用的所有颜色数。为0表示使用 2^比特数 种颜色 如8-比特/像素表示为100h或者 256.
0,0, //[25]Important Colours 指定重要的色彩数。当该域的值等于色彩数或者等于0时表示所有色彩都一样重要
0,0, //[27]重要颜色 0: 黑色 (#000000) R0 G0 B0 X0
0xffff,0xff //[29]重要颜色 1: 白色 (#ffffff) R255 G255 B255 X0
};
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON))
setSDbusy(1);
#endif
File bmpf = guyFS().open(filename,"w");
if(!bmpf) {
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON))
setSDbusy(0);
#endif
return 0;
}
uint32_t datsz = ibytes * height();
bmpHeader[ 1] = (datsz + sizeof(bmpHeader)) & 0xffffu;
bmpHeader[ 2] = (datsz + sizeof(bmpHeader)) >> 16;
bmpHeader[ 9] = width();
bmpHeader[11] = height();
bmpHeader[17] = datsz & 0xffffu;
bmpHeader[18] = datsz >> 16;
bmpf.write((uint8_t*)bmpHeader,sizeof(bmpHeader));
uint8_t *byteWrite = new uint8_t [ibytes];
for(int h=bmpHeader[11]-1;h>=0;h--){ //bmpHeader[11] == tft->height()
for(uint16_t i=0;i<ibytes;i++) byteWrite[i] = 0; //ibytes == (tft->width()+7)>>3
for(uint16_t w=0;w<=bmpHeader[9];w++){ //bmpHeader[ 9] == tft->width()
byteWrite[w>>3] |= !!(readPixel(w,h))<<((w&7)^7);
}
bmpf.write(byteWrite,ibytes);
yield();
}
bmpf.close();
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON))
setSDbusy(0);
#endif
delete [] byteWrite; //释放内存
//bmpf = guyFS().open(filename,"r");
//if(!bmpf || bmpf.size()!=datsz + sizeof(bmpHeader) || bmpf.peek() != 0x42) return 0; //检查
//bmpf.close();
return 1;
#else
return 0;
#endif
}
uint8_t ReadguyDriver::rd_btn_f(uint8_t btn){
uint8_t ReadguyDriver::rd_btn_f(uint8_t btn, bool activeLow){
static uint8_t lstate=0; //上次从dc引脚读到的电平
#ifdef ESP8266
if(btn==ReadguyDriver::pin_cmx && spibz) return lstate;
if(btn==D5||btn==D6||btn==D7||btn==ReadguyDriver::pin_cmx)
pinMode(btn,INPUT_PULLUP);//针对那些复用引脚做出的优化
if(btn==ReadguyDriver::pin_cmx && ReadguyDriver::spibz) return lstate;
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
static uint8_t epdcsstate=0; //上次从epd_cs引脚读到的电平
if(btn==ReadguyDriver::static_epd_cs && ReadguyDriver::spibz) return epdcsstate;
#endif
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON) && defined(READGUY_ENABLE_SD))
static uint8_t sdcsstate=0; //上次从sd_cs引脚读到的电平
if(btn==ReadguyDriver::static_sd_cs && ReadguyDriver::sd_cs_busy) return sdcsstate;
#endif
if(btn==D5||btn==D6||btn==D7||btn==ReadguyDriver::pin_cmx
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
|| btn==ReadguyDriver::static_epd_cs
#endif
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON) && defined(READGUY_ENABLE_SD))
|| btn==ReadguyDriver::static_sd_cs
#endif
)
pinMode(btn,activeLow?INPUT_PULLUP:INPUT_PULLDOWN);//针对那些复用引脚做出的优化
uint8_t readb = digitalRead(btn);
if(btn==ReadguyDriver::pin_cmx) {
if(btn==ReadguyDriver::pin_cmx
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
|| btn==ReadguyDriver::static_epd_cs
#endif
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON) && defined(READGUY_ENABLE_SD))
|| btn==ReadguyDriver::static_sd_cs
#endif
) {
//Serial.printf("rd D1.. %d\n",spibz);
pinMode(btn,OUTPUT); //如果有复用引脚, 它们的一部分默认需要保持输出状态, 比如复用的DC引脚
digitalWrite(btn,HIGH); //这些引脚的默认电平都是高电平
lstate = readb;
if(btn==ReadguyDriver::pin_cmx) lstate = readb;
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
else if(btn==ReadguyDriver::static_epd_cs) epdcsstate = readb;
#endif
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON) && defined(READGUY_ENABLE_SD))
else if(btn==ReadguyDriver::static_sd_cs) sdcsstate = readb;
#endif
}
else if(btn==D5||btn==D6||btn==D7) pinMode(btn,SPECIAL); //针对SPI引脚进行专门的优化
return readb;
@@ -745,7 +1033,7 @@ uint8_t ReadguyDriver::rd_btn_f(uint8_t btn){
if(btn!=ReadguyDriver::pin_cmx)
return digitalRead(btn);
if(spibz) return lstate;
pinMode(btn,INPUT_PULLUP);
pinMode(btn,activeLow?INPUT_PULLUP:INPUT_PULLDOWN);
uint8_t readb = digitalRead(btn);
pinMode(btn,OUTPUT);
digitalWrite(btn,HIGH);

View File

@@ -151,7 +151,7 @@
#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_rtc_type (config_data[19])//现已弃用 RTC 功能. 保留是为了兼容性 让代码更简单维护
#define READGUY_sd_ok (config_data[20]) //SD卡已经成功初始化
#define READGUY_buttons (config_data[21]) //按钮个数, 0-3都有可能
@@ -235,6 +235,8 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
void drawImage(LGFX_Sprite &base,LGFX_Sprite &spr,int32_t x,int32_t y,int32_t zoomw=0,int32_t zoomh=0);
/// @brief 设置显示对比度(灰度)
void setDepth(uint8_t d);
/// @brief 返回上次设置的显示对比度(灰度)
int16_t getDepth() const {return current_depth;}
/** @brief 返回目标屏幕是否支持16级灰度 返回非0代表支持.
* @note 返回负整数则代表调用draw16greyStep需要从深色到浅色刷新, 而不是从浅色到深色刷新 */
int supportGreyscaling() const{return READGUY_cali==127?guy_dev->drv_supportGreyscaling():0;}
@@ -249,16 +251,21 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
* @param step 步骤代号. 从1开始到15,依次调用此函数来自定义的灰度显示显存内容. 没有0和16.
* @note 必须按照 "慢刷全屏->绘图->设置参数1->绘图->设置参数2... 调用15次 来完成一次自定义灰度刷屏
* 连续调用多次此函数之间, 可以修改显存内的像素颜色, 但只能从白色改为黑色.
* @attention 需要先调用 supportGreyscaling() 来确定是否支持灰度分步刷新.为负时需要从深到浅刷新. 参见示例.
*/
* @attention 先调用 supportGreyscaling() 来确定是否支持灰度分步刷新. 为负时需要从深到浅刷新. 参见示例.
* 方法较为复杂用法参见示例. */
void draw16greyStep(int step);
/** @brief 分步刷新显示灰度, 详见 display(f,part) 和 draw16grey(spr,x,y) 的注释.
* @note 此函数不读取显存,而是通过调用该函数来确定像素颜色. */
* @note 此函数不读取显存,而是通过调用该函数来确定像素颜色, 不建议新手使用该函数. */
void draw16greyStep(std::function<uint8_t(int)> f, int step);
/// @brief 对缓冲区内所有像素进行反色.只对现在的缓冲区有效,之后的颜色该怎样就怎样. 灰度信息会被扔掉.
void invertDisplay();
/// @brief 进入EPD的低功耗模式
void sleepEPD(void);
/// @brief 设置自动全刷慢刷(连续快刷一定次数之后自动调用慢刷, 保护屏幕
/// @param frames 连续快刷多少次之后自动慢刷, 传入0来禁用自动慢刷
void setAutoFullRefresh(int16_t frames);
/// @brief 截屏并保存到SD卡上. 不支持灰度. 当SD卡不可用或者截屏失败时返回false
bool screenshot(const char *filename);
#ifdef READGUY_ESP_ENABLE_WIFI
/// @brief ap配网设置页面
typedef struct {
@@ -286,9 +293,10 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
} serveFunc;
/// @brief 初始化WiFi AP模式, 用于将来的连接WiFi 处于已连接状态下会断开原本的连接
void ap_setup(){}
void ap_setup(const char *ssid, const char *pass, int m=2){}
void ap_setup(const char *ssid, const char *pass, int m=2){(void)ssid; (void)pass; (void)m;} //avoid warning
/// @brief 初始化服务器模式, 用于将来的连接WiFi 处于已连接状态下会断开原本的连接
void server_setup(const String &notify=emptyString, const serveFunc *serveFuncs = nullptr, int funcs = 0){}
void server_setup(const String &notify=emptyString, const serveFunc *serveFuncs = nullptr, int funcs = 0)
{(void)notify;(void)serveFuncs;(void)funcs;} //avoid warning
bool server_loop(){ return true; }
void server_end(){}
#endif
@@ -306,16 +314,48 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
/** @brief 检查SD卡是否插入
* @param check 为true时, 如果SD卡不可用则初始化SD卡. 为false时, 当SD卡不可用则返回LittleFS. */
bool SDinside(bool check=true) { return check?setSDcardDriver():READGUY_sd_ok; };
void SDdeinit() { READGUY_sd_ok = 0; }; //当SD卡被检测到拔出或不可用时, 调用此函数标记
/// @brief 检查按钮. 当配置未完成时,按钮不可用, 返回0.
uint8_t getBtn() { return (READGUY_cali==127)?getBtn_impl():0; }
/// @brief [此函数已弃用 非常不建议使用] 根据按钮ID来检查按钮. 注意这里如果按下返回0, 没按下或者按钮无效返回1
//uint8_t getBtn(int btnID){return btnID<getButtonsCount()?(!(btn_rd[btnID].isPressedRaw())):1;}
/// @brief 该函数用于设置按键是否允许扫描连按
void setButtonSpecial(bool en = 1) { if(READGUY_buttons==3) btn_rd[1].enScanDT(en); }
/** @brief 返回可用的文件系统. 当SD卡可用时, 返回SD卡. 否则根据情况返回最近的可用文件系统
* @param initSD 2:总是重新初始化SD卡; 1:若SD卡不可用则初始化; 0:SD卡不可用则返回LittleFS. */
fs::FS &guyFS(uint8_t initSD = 0);
#ifdef ESP8266
/// @brief 恢复I2C复用SPI时的引脚功能, 仅ESP8266可用
void recoverI2C();
#else
/// @brief 恢复I2C引脚功能
void recoverI2C(){}
#endif
#if (defined(READGUY_ALLOW_SDCS_AS_BUTTON) && defined(READGUY_ENABLE_SD))
/// @brief 设置SD卡为忙状态或空闲状态
void setSDbusy(bool busy){ if(static_sd_cs!=0x7f) sd_cs_busy += (busy?1:(sd_cs_busy?-1:0)); }
#else
void setSDbusy(bool busy){ (void)busy; } //sd_cs as a btn pin
#endif
#if 0 // disabled because of useless
/// @brief 暂停按键扫描 (比如即将要开启中断或者中断, 定时器等硬件外设资源不足)
void stopKeyScan(){
#ifdef ESP8266
btnTask.detach();//暂时关闭任务, 避免引脚被设置为非法模式
#else
vTaskSuspend(btn_handle);//暂时关闭任务, 避免引脚被设置为非法模式
#endif
}
/// @brief 恢复按键扫描 (中断...等需要定时器的硬件外设用完了)
void keyScan(){
#ifdef ESP8266
btnTask.attach_ms(BTN_LOOPTASK_DELAY,looptask);
#else
vTaskResume(btn_handle); //开启任务后, 延时确保按键任务可以活跃而不是一直处于被暂停又刷屏的无限循环
#endif
}
#endif
//friend class EpdIf; //这样EpdIf就可以随意操作这个类的成员了
private:
//以下是支持的所有屏幕型号 Add devices here!
@@ -336,8 +376,14 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
int8_t READGUY_cali = 0;
int8_t READGUY_buttons = 0; //按钮个数, 0-3都有可能
#endif
int epd_OK=0; //墨水屏可用
int currentBright = -3; //初始亮度
int16_t epdPartRefresh = 0; //连续快刷次数
int16_t epdForceFull = 0x7fff; //连续快刷达到指定次数后, 强制全刷, 内部变量
int16_t currentBright = -3; //初始亮度
int16_t current_depth = 15; //初始灰度
uint8_t refresh_begin(uint8_t freshType); //设置快速刷新 频率调控
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
void refresh_end();
#endif
//LGFX_Sprite gfx; // 图形引擎类指针, 可以用这个指针去操作屏幕缓冲区
readguyEpdBase *guy_dev = nullptr;
@@ -375,9 +421,19 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
static guy_button btn_rd[3];
/// @brief 复用输出引脚1: 适用于按键引脚与屏幕DC引脚复用的情形
/// @note 只能解决屏幕DC引脚复用的情况, 其他引脚最好不要复用, 复用了我也解决不了
static int8_t pin_cmx;
static int8_t pin_cmx;
#ifdef READGUY_ALLOW_DC_AS_BUTTON
static bool refresh_state; //1: free; 0: busy(refreshing)
static uint8_t refresh_press; //0x7f: epd_dc btn released; others: epd_dc btn pressed
#endif
#ifdef READGUY_ALLOW_EPDCS_AS_BUTTON
static uint8_t static_epd_cs; //epd_cs as a btn pin
#endif
#ifdef READGUY_ALLOW_SDCS_AS_BUTTON
static uint8_t static_sd_cs; //sd_cs as a btn pin
static volatile uint8_t sd_cs_busy; //sd_cs as a btn pin
#endif
static volatile uint8_t spibz;
private:
#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];
@@ -396,22 +452,32 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
//static const PROGMEM uint8_t faviconData[1150];
#endif
static void looptask(); //按键服务函数
static uint8_t rd_btn_f(uint8_t btn);
static uint8_t rd_btn_f(uint8_t btn, bool activeLow);
uint8_t getBtn_impl(); //按钮不可用, 返回0.
static void in_press(){ //SPI开始传输屏幕数据
#ifdef ESP8266
if(!spibz) SPI.beginTransaction(SPISettings(ESP8266_SPI_FREQUENCY, MSBFIRST, SPI_MODE0));
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
if(!(spibz&0x3f))
#else
if(!spibz) epd_spi->beginTransaction(SPISettings(ESP32_DISP_FREQUENCY, MSBFIRST, SPI_MODE0));
if(!spibz)
#endif
#ifdef ESP8266
SPI.beginTransaction(SPISettings(ESP8266_SPI_FREQUENCY, MSBFIRST, SPI_MODE0));
#else
epd_spi->beginTransaction(SPISettings(ESP32_DISP_FREQUENCY, MSBFIRST, SPI_MODE0));
#endif
spibz ++;
}
static void in_release(){//SPI结束传输屏幕数据
spibz --;
#ifdef ESP8266
if(!spibz) SPI.endTransaction();
#if (defined(READGUY_ALLOW_DC_AS_BUTTON))
if(!(spibz&0x3f))
#else
if(!spibz) epd_spi->endTransaction();
if(!spibz)
#endif
#ifdef ESP8266
SPI.endTransaction();
#else
epd_spi->endTransaction();
#endif
}
public: //增加了一些返回系统状态变量的函数, 它们是静态的, 而且不会对程序造成任何影响.
@@ -433,11 +499,14 @@ class ReadguyDriver: public LGFX_Sprite{ // readguy 基础类
constexpr int getI2cScl () const { return READGUY_i2c_scl; }// 目标i2c总线的SCL引脚, 当且仅当启用i2c总线时才生效
//按键驱动部分, 为负代表高触发, 否则低触发,
//注意, 这里的io编号是加1的, 即 1或-1 代表 gpio0 的低触发/高触发
constexpr int getBtn1Pin () const { return READGUY_btn1; }
constexpr int getBtn2Pin () const { return READGUY_btn2; }
constexpr int getBtn3Pin () const { return READGUY_btn3; }
constexpr int getBtn1Pin () const { return abs((int)READGUY_btn1)-1; }
constexpr int getBtn2Pin () const { return abs((int)READGUY_btn2)-1; }
constexpr int getBtn3Pin () const { return abs((int)READGUY_btn3)-1; }
constexpr int getBtn1Info() const { return READGUY_btn1; }
constexpr int getBtn2Info() const { return READGUY_btn2; }
constexpr int getBtn3Info() const { return READGUY_btn3; }
constexpr int getBlPin () const { return READGUY_bl_pin; } //前置光接口引脚IO
constexpr int getRtcType () const { return READGUY_rtc_type; } //使用的RTC型号(待定, 还没用上)
constexpr int getRtcType () const { return READGUY_rtc_type; } //现已弃用 RTC 功能. 保留是为了兼容性 让代码更简单维护
constexpr int getButtonsCount() const { return READGUY_buttons; } //按钮个数, 0-3都有可能
constexpr int getReadguy_user1 () const { return READGUY_user1; } //用户变量
constexpr int getReadguy_user2 () const { return READGUY_user2; } //用户变量