diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/compile.ps1 b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/compile.ps1 new file mode 100644 index 00000000..1673ea4e --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/compile.ps1 @@ -0,0 +1,42 @@ +&(Join-Path $env:USERPROFILE '\esp\esp-idf\export.ps1') + +idf.py fullclean + +idf.py build + +#python -m esptool -p COM8 -b 460800 --before default_reset --after hard_reset --chip esp32c6 write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x0 build\bootloader\bootloader.bin 0x8000 build\partition_table\partition-table.bin 0x10000 build\OpenEPaperLink_esp32_C6.bin + + +#idf.py -p COM8 flash + + +#esptool.py v4.7.0 +#Serial port COM8 +#Connecting... +#Chip is ESP32-C6 (QFN40) (revision v0.0) +#Features: WiFi 6, BT 5, IEEE802.15.4 +#Crystal is 40MHz +#MAC: 40:4c:ca:ff:fe:47:b4:f0 +#BASE MAC: 40:4c:ca:47:b4:f0 +#MAC_EXT: ff:fe +#Uploading stub... +#Running stub... +#Stub running... +#Changing baud rate to 460800 +#Changed. +#Configuring flash size... +#Auto-detected Flash size: 4MB +#Flash will be erased from 0x00000000 to 0x00005fff... +#Flash will be erased from 0x00008000 to 0x00008fff... +#Flash will be erased from 0x00010000 to 0x00051fff... +#Compressed 22336 bytes to 13474... +#Wrote 22336 bytes (13474 compressed) at 0x00000000 in 0.3 seconds (effective 624.9 kbit/s)... +#Hash of data verified. +#Compressed 3072 bytes to 104... +#Wrote 3072 bytes (104 compressed) at 0x00008000 in 0.1 seconds (effective 361.3 kbit/s)... +#Hash of data verified. +#Compressed 268624 bytes to 140956... +#Wrote 268624 bytes (140956 compressed) at 0x00010000 in 1.2 seconds (effective 1725.6 kbit/s)... +#Hash of data verified. +#Leaving... +#Hard resetting via RTS pin... diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/.gitignore b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/.gitignore new file mode 100644 index 00000000..a932ece5 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/.gitignore @@ -0,0 +1,8 @@ +build +*.axf +# Allow +!*.bin + +.vscode +sdkconfig +sdkconfig.old diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/CMakeLists.txt b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/CMakeLists.txt new file mode 100644 index 00000000..031a676d --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(OpenEPaperLink_esp32_C6) diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/compile.ps1 b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/compile.ps1 new file mode 100644 index 00000000..84d0c3fa --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/compile.ps1 @@ -0,0 +1,45 @@ + +#| Function | ESP32H2 Pin | ESP32S3 Pin +#| :--------------------------------: | :-------------------: | :------------------ +#| Activate The BOOT Mode Of ESP32H2 | ESP32H2_IO9 | ESP32S3_IO33 +#| Reset ESP32H2 | ESP32H2_Pin Number 8 | ESP32S3_IO34 +#| Uart | ESP32H2_TX_IO24 | ESP32S3_RX_IO48 +#| Uart | ESP32H2_RX_IO23 | ESP32S3_TX_IO47 + +&(Join-Path $env:USERPROFILE '\esp\esp-idf\export.ps1') + +idf.py fullclean + +idf.py build + +#python -m esptool -p COM11 -b 460800 --before default_reset --after hard_reset --chip esp32h2 write_flash --flash_mode dio --flash_size detect --flash_freq 48m 0x0 build\bootloader\bootloader.bin 0x8000 build\partition_table\partition-table.bin 0x10000 build\OpenEPaperLink_esp32_H2.bin + + +#idf.py -p COM8 flash + + +#Chip is ESP32-H2 (revision v0.1) +#Features: BLE, IEEE802.15.4 +#Crystal is 32MHz +#MAC: 74:4d:bd:ff:fe:63:84:e8 +#BASE MAC: 74:4d:bd:63:84:e8 +#MAC_EXT: ff:fe +#Uploading stub... +#Running stub... +#Stub running... +#Changing baud rate to 460800 +#Changed. +#Configuring flash size... +#Auto-detected Flash size: 4MB +#Flash will be erased from 0x00000000 to 0x00005fff... +#Flash will be erased from 0x00008000 to 0x00008fff... +#Flash will be erased from 0x00010000 to 0x0004dfff... +#Compressed 22080 bytes to 13385... +#Wrote 22080 bytes (13385 compressed) at 0x00000000 in 0.3 seconds (effective 511.5 kbit/s)... +#Hash of data verified. +#Compressed 3072 bytes to 104... +#Wrote 3072 bytes (104 compressed) at 0x00008000 in 0.1 seconds (effective 309.1 kbit/s)... +#Hash of data verified. +#Compressed 253952 bytes to 133359... +#Wrote 253952 bytes (133359 compressed) at 0x00010000 in 1.9 seconds (effective 1098.1 kbit/s)... +#Hash of data verified. diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/CMakeLists.txt b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/CMakeLists.txt new file mode 100644 index 00000000..88baa379 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/CMakeLists.txt @@ -0,0 +1,9 @@ +idf_component_register( SRCS + SRCS "utils.c" + SRCS "second_uart.c" + SRCS "radio.c" + SRCS "SubGigRadio.c" + SRCS "cc1101_radio.c" + SRCS "led.c" + SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/Kconfig.projbuild b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/Kconfig.projbuild new file mode 100644 index 00000000..7bac71c1 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/Kconfig.projbuild @@ -0,0 +1,104 @@ +menu "OEPL Hardware config" + + choice OEPL_HARDWARE_PROFILE + prompt "Hardware profile" + default OEPL_HARDWARE_PROFILE_DEFAULT + + config OEPL_HARDWARE_PROFILE_DEFAULT + bool "Default" + + config OEPL_HARDWARE_PROFILE_POE_AP + bool "PoE-AP" + + config OEPL_HARDWARE_PROFILE_CUSTOM + bool "Custom" + + endchoice + + config OEPL_HARDWARE_UART_TX + depends on OEPL_HARDWARE_PROFILE_CUSTOM + int "GPIO - UART TX" + default 3 + + config OEPL_HARDWARE_UART_RX + depends on OEPL_HARDWARE_PROFILE_CUSTOM + int "GPIO - UART RX" + default 2 + + config OEPL_SUBGIG_SUPPORT + bool "Enable SubGhz Support" + default "n" + + menu "CC1101 Configuration" + depends on OEPL_SUBGIG_SUPPORT + + config GPIO_RANGE_MAX + int + default 33 if IDF_TARGET_ESP32 + default 46 if IDF_TARGET_ESP32S2 + default 48 if IDF_TARGET_ESP32S3 + default 18 if IDF_TARGET_ESP32C2 + default 19 if IDF_TARGET_ESP32C3 + default 30 if IDF_TARGET_ESP32C6 + default 30 if IDF_TARGET_ESP32H2 + + config MISO_GPIO + int "CC1101 MISO GPIO" + range 0 GPIO_RANGE_MAX + default 7 + help + Pin Number to be used as the MISO SPI signal. + + config SCK_GPIO + int "CC1101 SCK GPIO" + range 0 GPIO_RANGE_MAX + default 0 + help + Pin Number to be used as the SCK SPI signal. + + config MOSI_GPIO + int "CC1101 MOSI GPIO" + default 1 + help + Pin Number to be used as the MOSI SPI signal. + + config CSN_GPIO + int "CC1101 CSN GPIO" + range 0 GPIO_RANGE_MAX + default 4 + help + Pin Number to be used as the CSN SPI signal. + + config GDO0_GPIO + int "CC1101 GDO0 GPIO" + range 0 GPIO_RANGE_MAX + default 5 + help + Pin Number to be used as the GDO0 signal. + + config GDO2_GPIO + int "CC1101 GDO2 GPIO" + range 0 GPIO_RANGE_MAX + default 6 + help + Pin Number to be used as the GDO2 signal. + + choice SPI_HOST + prompt "SPI peripheral that controls this bus" + default SPI2_HOST + help + Select SPI peripheral that controls this bus. + config SPI2_HOST + bool "SPI2_HOST" + help + Use SPI2_HOST. This is also called HSPI_HOST. + config SPI3_HOST + depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + bool "SPI3_HOST" + help + USE SPI3_HOST. This is also called VSPI_HOST + endchoice + endmenu +endmenu + + diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/SubGigRadio.c b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/SubGigRadio.c new file mode 100644 index 00000000..6ad6c775 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/SubGigRadio.c @@ -0,0 +1,562 @@ +#include "sdkconfig.h" +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include +#include +#include "esp_log.h" + +#include "radio.h" +#include "proto.h" +#include "cc1101_radio.h" +#include "SubGigRadio.h" + +void DumpHex(void *AdrIn,int Len); + +#define LOGE(format, ... ) \ + printf("%s#%d: " format,__FUNCTION__,__LINE__,## __VA_ARGS__) + +#if 0 +#define LOG(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__) +#define LOG_RAW(format, ... ) printf(format,## __VA_ARGS__) +#define LOG_HEX(x,y) DumpHex(x,y) +#else +#define LOG(format, ... ) +#define LOG_RAW(format, ... ) +#define LOG_HEX(x,y) +#endif + + +// SPI Stuff +#if CONFIG_SPI2_HOST + #define HOST_ID SPI2_HOST +#elif CONFIG_SPI3_HOST + #define HOST_ID SPI3_HOST +#endif + +// Address Config = No address check +// Base Frequency = xxx.xxx +// CRC Enable = false +// Carrier Frequency = 915.000000 +// Channel Number = 0 +// Channel Spacing = 199.951172 +// Data Rate = 1.19948 +// Deviation = 5.157471 +// Device Address = 0 +// Manchester Enable = false +// Modulated = false +// Modulation Format = ASK/OOK +// PA Ramping = false +// Packet Length = 255 +// Packet Length Mode = Reserved +// Preamble Count = 4 +// RX Filter BW = 58.035714 +// Sync Word Qualifier Mode = No preamble/sync +// TX Power = 10 +// Whitening = false +// Rf settings for CC1110 +const RfSetting gCW[] = { + {CC1101_PKTCTRL0,0x22}, // PKTCTRL0: Packet Automation Control + {CC1101_FSCTRL1,0x06}, // FSCTRL1: Frequency Synthesizer Control + {CC1101_MDMCFG4,0xF5}, // MDMCFG4: Modem configuration + {CC1101_MDMCFG3,0x83}, // MDMCFG3: Modem Configuration + {CC1101_MDMCFG2,0xb0}, // MDMCFG2: Modem Configuration + {CC1101_DEVIATN,0x15}, // DEVIATN: Modem Deviation Setting + {CC1101_MCSM0,0x18}, // MCSM0: Main Radio Control State Machine Configuration + {CC1101_FOCCFG,0x17}, // FOCCFG: Frequency Offset Compensation Configuration + {CC1101_FSCAL3,0xE9}, // FSCAL3: Frequency Synthesizer Calibration + {CC1101_FSCAL2,0x2A}, // FSCAL2: Frequency Synthesizer Calibration + {CC1101_FSCAL1,0x00}, // FSCAL1: Frequency Synthesizer Calibration + {CC1101_FSCAL0,0x1F}, // FSCAL0: Frequency Synthesizer Calibration + {CC1101_TEST1,0x31}, // TEST1: Various Test Settings + {CC1101_TEST0,0x09}, // TEST0: Various Test Settings + {0xff,0} // end of table +}; + + +// Set Base Frequency to 865.999634 +const RfSetting g866Mhz[] = { + {CC1101_FREQ2,0x21}, // FREQ2: Frequency Control Word, High Byte + {CC1101_FREQ1,0x4e}, // FREQ1: Frequency Control Word, Middle Byte + {CC1101_FREQ0,0xc4}, // FREQ0: Frequency Control Word, Low Byte + {0xff,0} // end of table +}; + +// Set Base Frequency to 863.999756 +const RfSetting g864Mhz[] = { + {CC1101_FREQ2,0x21}, // FREQ2: Frequency Control Word, High Byte + {CC1101_FREQ1,0x3b}, // FREQ1: Frequency Control Word, Middle Byte + {CC1101_FREQ0,0x13}, // FREQ0: Frequency Control Word, Low Byte + {0xff,0} // end of table +}; + +// Set Base Frequency to 902.999756 +const RfSetting g903Mhz[] = { + {CC1101_FREQ2,0x22}, // FREQ2: Frequency Control Word, High Byte + {CC1101_FREQ1,0xbb}, // FREQ1: Frequency Control Word, Middle Byte + {CC1101_FREQ0,0x13}, // FREQ0: Frequency Control Word, Low Byte + {0xff,0} // end of table +}; + + +// Seet Base Frequency to 915.000000 +const RfSetting g915Mhz[] = { + {CC1101_FREQ2,0x23}, // FREQ2: Frequency Control Word, High Byte + {CC1101_FREQ1,0x31}, // FREQ1: Frequency Control Word, Middle Byte + {CC1101_FREQ0,0x3B}, // FREQ0: Frequency Control Word, Low Byte + {0xff,0} // end of table +}; + +// Address Config = No address check +// Base Frequency = 901.934937 (adjusted to compensate for the crappy crystal on the CC1101 board) +// CRC Enable = true +// Carrier Frequency = 901.934937 +// Channel Number = 0 +// Channel Spacing = 199.951172 +// Data Rate = 38.3835 +// Deviation = 20.629883 +// Device Address = ff +// Manchester Enable = false +// Modulated = true +// Modulation Format = GFSK +// PA Ramping = false +// Packet Length = 61 +// Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word +// Preamble Count = 4 +// RX Filter BW = 101.562500 +// Sync Word Qualifier Mode = 30/32 sync word bits detected +// TX Power = 10 +// Whitening = false +// The following was generated by setting the spec for Register to "{CC1101_@RN@,0x@VH@}," +const RfSetting gIDF_Basic[] = { + {CC1101_SYNC1,0xC7}, + {CC1101_SYNC0,0x0A}, + {CC1101_PKTLEN,0x3D}, + {CC1101_PKTCTRL0,0x05}, + {CC1101_ADDR,0xFF}, + {CC1101_FSCTRL1,0x08}, + {CC1101_FREQ2,0x22}, + {CC1101_FREQ1,0xB1}, + {CC1101_FREQ0,0x3B}, + {CC1101_MDMCFG4,0xCA}, + {CC1101_MDMCFG3,0x83}, + {CC1101_MDMCFG2,0x93}, + {CC1101_DEVIATN,0x35}, +// {CC1101_MCSM0,0x18}, FS_AUTOCAL = 1, PO_TIMEOUT = 2 + {CC1101_MCSM0,0x18}, + {CC1101_FOCCFG,0x16}, + {CC1101_AGCCTRL2,0x43}, + {CC1101_FSCAL3,0xEF}, + {CC1101_FSCAL2,0x2D}, + {CC1101_FSCAL1,0x25}, + {CC1101_FSCAL0,0x1F}, + {CC1101_TEST2,0x81}, + {CC1101_TEST1,0x35}, + {CC1101_TEST0,0x09}, + {0xff,0} // end of table +}; + +// RF configuration from Dimitry's orginal code +// Address Config = No address check +// Base Frequency = 902.999756 +// CRC Autoflush = false +// CRC Enable = true +// Carrier Frequency = 902.999756 +// Channel Number = 0 +// Channel Spacing = 335.632324 +// Data Format = Normal mode +// Data Rate = 249.939 +// Deviation = 165.039063 +// Device Address = 22 +// Manchester Enable = false +// Modulated = true +// Modulation Format = GFSK +// PA Ramping = false +// Packet Length = 255 +// Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word +// Preamble Count = 24 +// RX Filter BW = 650.000000 +// Sync Word Qualifier Mode = 30/32 sync word bits detected +// TX Power = 0 +// Whitening = true +// Rf settings for CC1101 +// The following was generated by setting the spec for Register to "{CC1101_@RN@,0x@VH@}," +const RfSetting gDmitry915[] = { + {CC1101_FREQ2,0x22}, + {CC1101_FREQ1,0xBB}, + {CC1101_FREQ0,0x13}, + {CC1101_MDMCFG4,0x1D}, + {CC1101_MDMCFG3,0x3B}, + {CC1101_MDMCFG2,0x13}, + {CC1101_MDMCFG1,0x73}, + {CC1101_MDMCFG0,0xA7}, + {CC1101_DEVIATN,0x65}, + {CC1101_MCSM0,0x18}, + {CC1101_FOCCFG,0x1E}, + {CC1101_BSCFG,0x1C}, + {CC1101_AGCCTRL2,0xC7}, + {CC1101_AGCCTRL1,0x00}, + {CC1101_AGCCTRL0,0xB0}, + {CC1101_FREND1,0xB6}, + {CC1101_FSCAL3,0xEA}, + {CC1101_FSCAL2,0x2A}, + {CC1101_FSCAL1,0x00}, + {CC1101_FSCAL0,0x1F}, + {CC1101_TEST0,0x09}, + {0xff,0} // end of table +}; + +SubGigData gSubGigData; + +int CheckSubGigState(void); +void SubGig_CC1101_reset(void); +void SubGig_CC1101_SetConfig(const RfSetting *pConfig); + +static void IRAM_ATTR gpio_isr_handler(void *arg) +{ + gSubGigData.RxAvailable = true; +} + +// return SUBGIG_ERR_NONE aka ESP_OK aka 0 if CC1101 is detected and all is good +SubGigErr SubGig_radio_init(uint8_t ch) +{ + esp_err_t Err; + spi_device_interface_config_t devcfg = { + .clock_speed_hz = 5000000, // SPI clock is 5 MHz! + .queue_size = 7, + .mode = 0, // SPI mode 0 + .spics_io_num = -1, // we will use manual CS control + .flags = SPI_DEVICE_NO_DUMMY + }; + gpio_config_t io_conf = { + .intr_type = GPIO_INTR_NEGEDGE, // GPIO interrupt type : falling edge + //bit mask of the pins + .pin_bit_mask = 1ULL<= FIRST_866_CHAN && ch < FIRST_866_CHAN + NUM_866_CHANNELS) { + // Base Frequency = 863.999756 + // total channels 6 (0 -> 5) (CHANNR 0 -> 15) + // Channel 100 / CHANNR 0: 863.999756 + // Channel 101 / CHANNR 3: 865.006 Mhz + // Channel 102 / CHANNR 6: 866.014 Mhz + // Channel 103 / CHANNR 9: 867.020 Mhz + // Channel 104 / CHANNR 12: 868.027 Mhz + // Channel 105 / CHANNR 15: 869.034 Mhz + SubGig_CC1101_SetConfig(g864Mhz); + SetChannr[0].Value = (ch - FIRST_866_CHAN) * 3; + } + else { + // Base Frequency = 902.999756 + // Dmitry's orginal code used 25 channels in 915 Mhz + // We don't want to have to scan that many so for OEPL we'll just use 6 + // to match 866. + // Channel 200 / CHANNR 0: 903.000 Mhz + // Channel 201 / CHANNR 12: 907.027 Mhz + // Channel 202 / CHANNR 24: 911.054 Mhz + // Channel 203 / CHANNR 24: 915.083 Mhz + // Channel 204 / CHANNR 48: 919.110 Mhz + // Channel 205 / CHANNR 60: 923.138 Mhz + SubGig_CC1101_SetConfig(g903Mhz); + + if(ch >= FIRST_915_CHAN && ch < FIRST_915_CHAN + NUM_915_CHANNELS) { + SetChannr[0].Value = (ch - FIRST_915_CHAN) * 12; + } + else { + Ret = SUBGIG_INVALID_CHANNEL; + SetChannr[0].Value = 0; // default to the first channel on 915 + } + } + SubGig_CC1101_SetConfig(SetChannr); + CC1101_setRxState(); + } while(false); + + return Ret; +} + +SubGigErr SubGig_radioTx(uint8_t *packet) +{ + SubGigErr Ret = SUBGIG_ERR_NONE; + + do { + if(gSubGigData.FreqTest) { + break; + } + if((Ret = CheckSubGigState()) != SUBGIG_ERR_NONE) { + break; + } + + if(packet[0] < 3 || packet[0] > RADIO_MAX_PACKET_LEN + RAW_PKT_PADDING) { + Ret = SUBGIG_TX_BAD_LEN; + break; + } + + // All packets seem to be padded by RAW_PKT_PADDING (2 bytes) + // Remove the padding before sending so the length is correct when received + packet[0] -= RAW_PKT_PADDING; + LOG("Sending %d byte subgig frame:\n",packet[0]); + LOG_HEX(&packet[1],packet[0]); + if(CC1101_Tx(packet)) { + Ret = SUBGIG_TX_FAILED; + } + // Clear RxAvailable, in TX GDO0 deasserts on TX FIFO underflows + gSubGigData.RxAvailable = false; + // restore original len just in case anyone cares + packet[0] += RAW_PKT_PADDING; + } while(false); + + return Ret; +} + +// returns packet size in bytes data in data +int8_t SubGig_commsRxUnencrypted(uint8_t *data) +{ + int RxBytes; + int8_t Ret = 0; + + do { + if(CheckSubGigState() != SUBGIG_ERR_NONE) { + break; + } + + if(gSubGigData.FreqTest) { + break; + } + CC1101_logState(); + + if(!gSubGigData.RxAvailable && gpio_get_level(CONFIG_GDO0_GPIO) == 1) { + // Did we miss an interrupt? + if(gpio_get_level(CONFIG_GDO0_GPIO) == 1) { + // Yup! + LOGE("SubGhz lost interrupt\n"); + gSubGigData.RxAvailable = true; + } + } + + if(gSubGigData.RxAvailable){ + gSubGigData.RxAvailable = false; + RxBytes = CC1101_Rx(data,128,NULL,NULL); + + if(RxBytes >= 2) { + // NB: RxBytes includes the CRC, deduct it + Ret = (uint8_t) RxBytes - 2; + LOG("Received %d byte subgig frame:\n",Ret); + LOG_HEX(data,Ret); + } + } + } while(false); + + return Ret; +} + +int CheckSubGigState() +{ + int Err = SUBGIG_ERR_NONE; + + if(!gSubGigData.Present) { + Err = SUBGIG_CC1101_NOT_FOUND; + } + else if(!gSubGigData.Initialized) { + Err = SUBGIG_NOT_INITIALIZED; + } + else if(!gSubGigData.Enabled) { + Err = SUBGIG_NOT_ENABLED; + } + + if(Err != SUBGIG_ERR_NONE) { + LOG("CheckSubGigState: returing %d\n",Err); + } + + return Err; +} + +SubGigErr SubGig_FreqTest(bool b866Mhz,bool bStart) +{ + SubGigErr Err = SUBGIG_ERR_NONE; +#if 0 + uint8_t TxData = 0; // len = 0 + + do { + if((Err = CheckSubGigState()) != SUBGIG_ERR_NONE) { + break; + } + if(bStart) { + LOG_RAW("Starting %sMhz Freq test\n",b866Mhz ? "866" : "915"); + SubGig_CC1101_reset(); + SubGig_CC1101_SetConfig(gCW); + SubGig_CC1101_SetConfig(b866Mhz ? g866Mhz : g915Mhz); + CC1101_cmdStrobe(CC1101_SIDLE); + CC1101_cmdStrobe(CC1101_SFTX); // flush Tx Fifo + CC1101_cmdStrobe(CC1101_STX); + gRfState = RFSTATE_TX; + gSubGigData.FreqTest = true; + } + else { + LOG_RAW("Ending Freq test\n"); + gSubGigData.FreqTest = false; + SubGig_CC1101_reset(); + SubGig_CC1101_SetConfig(gSubGigData.pConfig); + } + } while(false); +#endif + return Err; +} + +void SubGig_CC1101_reset() +{ + gSubGigData.Initialized = false; + gSubGigData.FixedRegsSet = false; + CC1101_reset(); +} + +void SubGig_CC1101_SetConfig(const RfSetting *pConfig) +{ + CC1101_SetConfig(pConfig); + gSubGigData.Initialized = true; +} + +void DumpHex(void *AdrIn,int Len) +{ + unsigned char *Adr = (unsigned char *) AdrIn; + int i = 0; + int j; + + while(i < Len) { + for(j = 0; j < 16; j++) { + if((i + j) == Len) { + break; + } + LOG_RAW("%02x ",Adr[i+j]); + } + + LOG_RAW(" "); + for(j = 0; j < 16; j++) { + if((i + j) == Len) { + break; + } + if(isprint(Adr[i+j])) { + LOG_RAW("%c",Adr[i+j]); + } + else { + LOG_RAW("."); + } + } + i += 16; + LOG_RAW("\n"); + } +} +#endif // CONFIG_OEPL_SUBGIG_SUPPORT + diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/SubGigRadio.h b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/SubGigRadio.h new file mode 100644 index 00000000..e41cf445 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/SubGigRadio.h @@ -0,0 +1,40 @@ +#ifndef _SUBGIG_RADIO_H_ +#define _SUBGIG_RADIO_H_ + +//sub-GHz 866 Mhz channels start at 100 +#define FIRST_866_CHAN (100) +#define NUM_866_CHANNELS (6) + +//sub-GHz 915 Mhz channels start at 200 +#define FIRST_915_CHAN (200) +#define NUM_915_CHANNELS (6) + +typedef enum { + SUBGIG_ERR_NONE, + SUBGIG_CC1101_NOT_FOUND, + SUBGIG_NOT_INITIALIZED, + SUBGIG_NOT_ENABLED, + SUBGIG_TX_FAILED, + SUBGIG_TX_BAD_LEN, + SUBGIG_INVALID_CHANNEL, +} SubGigErr; + +typedef struct { + uint8_t Present:1; + uint8_t Enabled:1; + uint8_t FreqTest:1; + uint8_t RxAvailable:1; + uint8_t Initialized:1; + uint8_t FixedRegsSet:1; +} SubGigData; + +extern SubGigData gSubGigData; + +SubGigErr SubGig_radio_init(uint8_t ch); +SubGigErr SubGig_radioTx(uint8_t *packet); +SubGigErr SubGig_radioSetChannel(uint8_t ch); +int8_t SubGig_commsRxUnencrypted(uint8_t *data); +SubGigErr SubGig_FreqTest(bool b866Mhz,bool bStart); + +#endif // _SUBGIG_RADIO_H_ + diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/cc1101_radio.c b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/cc1101_radio.c new file mode 100644 index 00000000..13ecaffe --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/cc1101_radio.c @@ -0,0 +1,790 @@ +// Large portions of this code was copied from: +// https://github.com/nopnop2002/esp-idf-cc1101 with the following copyright + +/* + * Copyright (c) 2011 panStamp + * Copyright (c) 2016 Tyler Sommer + * + * This file is part of the CC1101 project. + * + * CC1101 is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * CC1101 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CC1101; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * Author: Daniel Berenguer + * Creation date: 03/03/2011 + */ + +#include "sdkconfig.h" +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + +#include +#include +#include +#include +#include "proto.h" +#include "cc1101_radio.h" +#include "radio.h" + +#define ENABLE_LOGGING 0 + +// LOGA - generic logging, always enabled +#define LOGA(format, ... ) printf(format,## __VA_ARGS__) +// LOGE - error logging, always enabled +#define LOGE(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__) + +#if ENABLE_LOGGING +#define LOG(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__) +#define LOG_RAW(format, ... ) printf(format,## __VA_ARGS__) +#else +#define LOG(format, ... ) +#define LOG_RAW(format, ... ) +#endif + +#define ENABLE_VERBOSE_LOGGING 0 + +#if ENABLE_VERBOSE_LOGGING +#define LOGV(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__) +#define LOGV_RAW(format, ... ) printf(format,## __VA_ARGS__) +#else +#define LOGV(format, ... ) +#define LOGB_RAW(format, ... ) +#endif + +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include +#include +#include "esp_log.h" + +#include "sdkconfig.h" + +/** + * RF STATES + */ +enum RFSTATE { + RFSTATE_IDLE = 0, + RFSTATE_RX, + RFSTATE_TX +}; + +/** + * Type of transfers + */ +#define WRITE_BURST 0x40 +#define READ_SINGLE 0x80 +#define READ_BURST 0xC0 + +/** + * Type of register + */ +#define CC1101_CONFIG_REGISTER READ_SINGLE +#define CC1101_STATUS_REGISTER READ_BURST + +/** + * PATABLE & FIFO's + */ +#define CC1101_PATABLE 0x3E // PATABLE address +#define CC1101_TXFIFO 0x3F // TX FIFO address +#define CC1101_RXFIFO 0x3F // RX FIFO address + +/** + * Command strobes + */ +#define CC1101_SRES 0x30 // Reset CC1101 chip +#define CC1101_SFSTXON 0x31 // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). If in RX (with CCA): +// Go to a wait state where only the synthesizer is running (for quick RX / TX turnaround). +#define CC1101_SXOFF 0x32 // Turn off crystal oscillator +#define CC1101_SCAL 0x33 // Calibrate frequency synthesizer and turn it off. SCAL can be strobed from IDLE mode without +// setting manual calibration mode (MCSM0.FS_AUTOCAL=0) +#define CC1101_SRX 0x34 // Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1 +#define CC1101_STX 0x35 // In IDLE state: Enable TX. Perform calibration first if MCSM0.FS_AUTOCAL=1. +// If in RX state and CCA is enabled: Only go to TX if channel is clear +#define CC1101_SIDLE 0x36 // Exit RX / TX, turn off frequency synthesizer and exit Wake-On-Radio mode if applicable +#define CC1101_SWOR 0x38 // Start automatic RX polling sequence (Wake-on-Radio) as described in Section 19.5 if +// WORCTRL.RC_PD=0 +#define CC1101_SPWD 0x39 // Enter power down mode when CSn goes high +#define CC1101_SFRX 0x3A // Flush the RX FIFO buffer. Only issue SFRX in IDLE or RXFIFO_OVERFLOW states +#define CC1101_SFTX 0x3B // Flush the TX FIFO buffer. Only issue SFTX in IDLE or TXFIFO_UNDERFLOW states +#define CC1101_SWORRST 0x3C // Reset real time clock to Event1 value +#define CC1101_SNOP 0x3D // No operation. May be used to get access to the chip status byte + +#define CC1101_STATE_SLEEP 0x00 +#define CC1101_STATE_IDLE 0x01 +#define CC1101_STATE_XOFF 0x02 +#define CC1101_STATE_VCOON_MC 0x03 +#define CC1101_STATE_REGON_MC 0x04 +#define CC1101_STATE_MANCAL 0x05 +#define CC1101_STATE_VCOON 0x06 +#define CC1101_STATE_REGON 0x07 +#define CC1101_STATE_STARTCAL 0x08 +#define CC1101_STATE_BWBOOST 0x09 +#define CC1101_STATE_FS_LOCK 0x0A +#define CC1101_STATE_IFADCON 0x0B +#define CC1101_STATE_ENDCAL 0x0C +#define CC1101_STATE_RX 0x0D +#define CC1101_STATE_RX_END 0x0E +#define CC1101_STATE_RX_RST 0x0F +#define CC1101_STATE_TXRX_SWITCH 0x10 +#define CC1101_STATE_RXFIFO_OVERFLOW 0x11 +#define CC1101_STATE_FSTXON 0x12 +#define CC1101_STATE_TX 0x13 +#define CC1101_STATE_TX_END 0x14 +#define CC1101_STATE_RXTX_SWITCH 0x15 +#define CC1101_STATE_TXFIFO_UNDERFLOW 0x16 + +// Masks for first byte read from RXFIFO +#define CC1101_NUM_RXBYTES_MASK 0x7f +#define CC1101_RXFIFO_OVERFLOW_MASK 0x80 + +// Masks for last byte read from RXFIFO +#define CC1101_LQI_MASK 0x7f +#define CC1101_CRC_OK_MASK 0x80 + +// IOCFG2 GDO2: high when TX FIFO at or above the TX FIFO threshold +#define CC1101_DEFVAL_IOCFG2 0x02 + +// IOCFG1 GDO1: High impedance (3-state) +#define CC1101_DEFVAL_IOCFG1 0x2E + +// GDO0 goes high when sync word has been sent / received, and +// goes low at the end of the packet. +// In TX mode the pin will go low if the TX FIFO underflows. +#define CC1101_DEFVAL_IOCFG0 0x06 + +// Threshold = 32 bytes (1/2 of FIFO len) +#define CC1101_DEFVAL_FIFOTHR 0x07 +#define CC1101_DEFVAL_RCCTRL1 0x41 +#define CC1101_DEFVAL_RCCTRL0 0x00 +#define CC1101_DEFVAL_AGCTEST 0x3F +#define CC1101_DEFVAL_MCSM1 0x20 +#define CC1101_DEFVAL_WORCTRL 0xFB +#define CC1101_DEFVAL_FSCTRL0 0 + +#define CC1101_DEFVAL_PATABLE 0xc0 // full power + +RfSetting gFixedConfig[] = { + {CC1101_IOCFG2,CC1101_DEFVAL_IOCFG2}, + {CC1101_IOCFG1,CC1101_DEFVAL_IOCFG1}, + {CC1101_IOCFG0,CC1101_DEFVAL_IOCFG0}, + {CC1101_FIFOTHR,CC1101_DEFVAL_FIFOTHR}, + {CC1101_FSCTRL0,CC1101_DEFVAL_FSCTRL0}, + {CC1101_RCCTRL1,CC1101_DEFVAL_RCCTRL1}, + {CC1101_RCCTRL0,CC1101_DEFVAL_RCCTRL0}, + {CC1101_MCSM1,CC1101_DEFVAL_MCSM1}, + {CC1101_WORCTRL,CC1101_DEFVAL_WORCTRL}, + {0xff,0}, +}; + +void CC1101_readBurstReg(uint8_t *buffer,uint8_t regAddr,uint8_t len); +void CC1101_cmdStrobe(uint8_t cmd); +void CC1101_wakeUp(void); +uint8_t CC1101_readReg(uint8_t regAddr, uint8_t regType); +void CC1101_writeReg(uint8_t regAddr, uint8_t value); +void CC1101_setTxState(void); + +void setIdleState(void); + +spi_device_handle_t gSpiHndl; + +#define readConfigReg(regAddr) CC1101_readReg(regAddr, CC1101_CONFIG_REGISTER) +#define readStatusReg(regAddr) CC1101_readReg(regAddr, CC1101_STATUS_REGISTER) +#define flushRxFifo() CC1101_cmdStrobe(CC1101_SFRX) +#define flushTxFifo() CC1101_cmdStrobe(CC1101_SFTX) + +const char *RegNamesCC1101[] = { + "IOCFG2", // 0x00 GDO2 output pin configuration + "IOCFG1", // 0x01 GDO1 output pin configuration + "IOCFG0", // 0x02 GDO0 output pin configuration + "FIFOTHR", // 0x03 RX FIFO and TX FIFO thresholds + "SYNC1", // 0x04 Sync word, high INT8U + "SYNC0", // 0x05 Sync word, low INT8U + "PKTLEN", // 0x06 Packet length + "PKTCTRL1", // 0x07 Packet automation control + "PKTCTRL0", // 0x08 Packet automation control + "ADDR", // 0x09 Device address + "CHANNR", // 0x0A Channel number + "FSCTRL1", // 0x0B Frequency synthesizer control + "FSCTRL0", // 0x0C Frequency synthesizer control + "FREQ2", // 0x0D Frequency control word, high INT8U + "FREQ1", // 0x0E Frequency control word, middle INT8U + "FREQ0", // 0x0F Frequency control word, low INT8U + "MDMCFG4", // 0x10 Modem configuration + "MDMCFG3", // 0x11 Modem configuration + "MDMCFG2", // 0x12 Modem configuration + "MDMCFG1", // 0x13 Modem configuration + "MDMCFG0", // 0x14 Modem configuration + "DEVIATN", // 0x15 Modem deviation setting + "MCSM2", // 0x16 Main Radio Control State Machine configuration + "MCSM1", // 0x17 Main Radio Control State Machine configuration + "MCSM0", // 0x18 Main Radio Control State Machine configuration + "FOCCFG", // 0x19 Frequency Offset Compensation configuration + "BSCFG", // 0x1A Bit Synchronization configuration + "AGCCTRL2", // 0x1B AGC control + "AGCCTRL1", // 0x1C AGC control + "AGCCTRL0", // 0x1D AGC control + "WOREVT1", // 0x1E High INT8U Event 0 timeout + "WOREVT0", // 0x1F Low INT8U Event 0 timeout + "WORCTRL", // 0x20 Wake On Radio control + "FREND1", // 0x21 Front end RX configuration + "FREND0", // 0x22 Front end TX configuration + "FSCAL3", // 0x23 Frequency synthesizer calibration + "FSCAL2", // 0x24 Frequency synthesizer calibration + "FSCAL1", // 0x25 Frequency synthesizer calibration + "FSCAL0", // 0x26 Frequency synthesizer calibration + "RCCTRL1", // 0x27 RC oscillator configuration + "RCCTRL0", // 0x28 RC oscillator configuration + "FSTEST", // 0x29 Frequency synthesizer calibration control + "PTEST", // 0x2A Production test + "AGCTEST", // 0x2B AGC test + "TEST2", // 0x2C Various test settings + "TEST1", // 0x2D Various test settings + "TEST0", // 0x2E Various test settings + "0x2f", // 0x2f +//CC1101 Strobe commands + "SRES", // 0x30 Reset chip. + "SFSTXON", // 0x31 Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). + "SXOFF", // 0x32 Turn off crystal oscillator. + "SCAL", // 0x33 Calibrate frequency synthesizer and turn it off + "SRX", // 0x34 Enable RX. Perform calibration first if coming from IDLE and + "STX", // 0x35 In IDLE state: Enable TX. Perform calibration first if + "SIDLE", // 0x36 Exit RX / TX, turn off frequency synthesizer and exit + "SAFC", // 0x37 Perform AFC adjustment of the frequency synthesizer + "SWOR", // 0x38 Start automatic RX polling sequence (Wake-on-Radio) + "SPWD", // 0x39 Enter power down mode when CSn goes high. + "SFRX", // 0x3A Flush the RX FIFO buffer. + "SFTX", // 0x3B Flush the TX FIFO buffer. + "SWORRST", // 0x3C Reset real time clock. + "SNOP", // 0x3D No operation. May be used to pad strobe commands to two + "PATABLE" // 0x3E +}; + + +// SPI Stuff +#if CONFIG_SPI2_HOST + #define HOST_ID SPI2_HOST +#elif CONFIG_SPI3_HOST + #define HOST_ID SPI3_HOST +#endif + +/* + * RF state + */ +static uint8_t gRfState; + +#define cc1101_Select() gpio_set_level(CONFIG_CSN_GPIO, LOW) +#define cc1101_Deselect() gpio_set_level(CONFIG_CSN_GPIO, HIGH) +#define wait_Miso() while(gpio_get_level(CONFIG_MISO_GPIO)>0) +#define getGDO0state() gpio_get_level(CONFIG_GDO0_GPIO) +#define wait_GDO0_high() while(!getGDO0state()) +#define wait_GDO0_low() while(getGDO0state()) +#define getGDO2state() gpio_get_level(CONFIG_GDO2_GPIO) +#define wait_GDO2_low() while(getGDO2state()) + +/** + * Arduino Macros + */ +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit)) +#define delayMicroseconds(us) esp_rom_delay_us(us) +#define LOW 0 +#define HIGH 1 + +int32_t gFreqErrSum; +uint8_t gFreqErrSumCount; +int8_t gFreqCorrection; + +bool spi_write_byte(uint8_t* Dataout,size_t DataLength) +{ + spi_transaction_t SPITransaction; + + if(DataLength > 0) { + memset(&SPITransaction,0,sizeof(spi_transaction_t)); + SPITransaction.length = DataLength * 8; + SPITransaction.tx_buffer = Dataout; + SPITransaction.rx_buffer = NULL; + spi_device_transmit(gSpiHndl,&SPITransaction); + } + + return true; +} + +bool spi_read_byte(uint8_t* Datain,uint8_t* Dataout,size_t DataLength) +{ + spi_transaction_t SPITransaction; + + if(DataLength > 0) { + memset(&SPITransaction,0,sizeof(spi_transaction_t)); + SPITransaction.length = DataLength * 8; + SPITransaction.tx_buffer = Dataout; + SPITransaction.rx_buffer = Datain; + spi_device_transmit(gSpiHndl,&SPITransaction); + } + + return true; +} + +uint8_t spi_transfer(uint8_t address) +{ + uint8_t datain[1]; + uint8_t dataout[1]; + dataout[0] = address; + //spi_write_byte(dev, dataout, 1 ); + //spi_read_byte(datain, dataout, 1 ); + + spi_transaction_t SPITransaction; + memset(&SPITransaction,0,sizeof(spi_transaction_t)); + SPITransaction.length = 8; + SPITransaction.tx_buffer = dataout; + SPITransaction.rx_buffer = datain; + spi_device_transmit(gSpiHndl,&SPITransaction); + + return datain[0]; +} + +/** + * CC1101_wakeUp + * + * Wake up CC1101 from Power Down state + */ +void CC1101_wakeUp(void) +{ + cc1101_Select(); + wait_Miso(); + cc1101_Deselect(); +} + +/** + * CC1101_writeReg + * + * Write single register into the CC1101 IC via SPI + * + * @param regAddr Register address + * @param value Value to be writen + */ +void CC1101_writeReg(uint8_t regAddr, uint8_t value) +{ + if(regAddr < 0x3f) { + LOGV("0x%x -> %s(0x%x)\n",value,RegNamesCC1101[regAddr],regAddr); + } + else { + LOGV("0x%x -> 0x%x\n",value,regAddr); + } + cc1101_Select(); // Select CC1101 + wait_Miso(); // Wait until MISO goes low + spi_transfer(regAddr); // Send register address + spi_transfer(value); // Send value + cc1101_Deselect(); // Deselect CC1101 +} + + +/** + * CC1101_cmdStrobe + * + * Send command strobe to the CC1101 IC via SPI + * + * @param cmd Command strobe + */ +void CC1101_cmdStrobe(uint8_t cmd) +{ + cc1101_Select(); + wait_Miso(); + spi_transfer(cmd); + cc1101_Deselect(); +} + +/** + * CC1101_readReg + * + * Read CC1101 register via SPI + * + * @param regAddr Register address + * @param regType Type of register: CONFIG_REGISTER or STATUS_REGISTER + * + * Return: + * Data uint8_t returned by the CC1101 IC + */ +uint8_t CC1101_readReg(uint8_t regAddr,uint8_t regType) +{ + uint8_t addr, val; + + addr = regAddr | regType; + cc1101_Select(); + wait_Miso(); + spi_transfer(addr); + val = spi_transfer(0x00); // Read result + cc1101_Deselect(); + + return val; +} + +/** + * CC1101_readBurstReg + * + * Read burst data from CC1101 via SPI + * + * @param buffer Buffer where to copy the result to + * @param regAddr Register address + * @param len Data length + */ +void CC1101_readBurstReg(uint8_t *buffer,uint8_t regAddr,uint8_t len) +{ + uint8_t addr, i; + + addr = regAddr | READ_BURST; + cc1101_Select(); + wait_Miso(); + spi_transfer(addr); // Send register address + for(i = 0; i < len; i++) { + buffer[i] = spi_transfer(0x00); // Read result uint8_t by uint8_t + } + cc1101_Deselect(); +} + +/** + * reset + * + * Reset CC1101 + */ +void CC1101_reset(void) +{ +// See sectin 19.1.2 of the CC1101 spec sheet for reasons for the following + cc1101_Deselect(); + delayMicroseconds(5); + cc1101_Select(); + delayMicroseconds(10); + cc1101_Deselect(); + delayMicroseconds(41); + cc1101_Select(); + +// Wait until MISO goes low indicating XOSC stable + wait_Miso(); + spi_transfer(CC1101_SRES); // Send reset command strobe + wait_Miso(); + cc1101_Deselect(); +} + + +/** + * CC1101_setRxState + * + * Enter Rx state + */ +void CC1101_setRxState(void) +{ + CC1101_cmdStrobe(CC1101_SRX); + gRfState = RFSTATE_RX; +} + +/** + * CC1101_setTxState + * + * Enter Tx state + */ +void CC1101_setTxState(void) +{ + CC1101_cmdStrobe(CC1101_STX); + gRfState = RFSTATE_TX; +} + + +void CC1101_DumpRegs() +{ +#if ENABLE_LOGGING + uint8_t regAddr; + uint8_t value; + + LOG("\n"); + for(regAddr = 0; regAddr < 0x2f; regAddr++) { + value = CC1101_readReg(regAddr,READ_SINGLE); + LOG("%02x %s: 0x%02X\n",regAddr,RegNamesCC1101[regAddr],value); + } + +#if 0 + for(regAddr = 0; regAddr < 0x2f; regAddr++) { + value = CC1101_readReg(regAddr,READ_SINGLE); + LOG("%s0x%02X\n",RegNamesCC1101[regAddr],value); + } +#endif +#endif +} + + +bool CC1101_Tx(uint8_t *TxData) +{ + bool Ret = false; + int ErrLine = 0; + spi_transaction_t SPITransaction; + uint8_t BytesSent = 0; + uint8_t Bytes2Send; + uint8_t len; + uint8_t CanSend; + esp_err_t Err; + + do { + // The first byte in the buffer is the number of data bytes to send, + // we also need to send the first byte + len = 1 + *TxData; + memset(&SPITransaction,0,sizeof(spi_transaction_t)); + SPITransaction.tx_buffer = TxData; + + setIdleState(); + flushTxFifo(); + + while(BytesSent < len) { + Bytes2Send = len - BytesSent; + if(BytesSent == 0) { + // First chunk, the FIFO is empty and can take 64 bytes + if(Bytes2Send > 64) { + Bytes2Send = 64; + } + } + else { + // Not the first chunk, we can only send FIFO_THRESHOLD bytes + // and only when GDO2 says we can + if(getGDO2state()) { + wait_GDO2_low(); + } + CanSend = readStatusReg(CC1101_TXBYTES); + if(CanSend & 0x80) { + LOGE("TX FIFO underflow, BytesSent %d\n",BytesSent); + ErrLine = __LINE__; + break; + } + CanSend = 64 - CanSend; + if(CanSend == 0) { + LOGE("CanSend == 0, GDO2 problem\n"); + ErrLine = __LINE__; + break; + } + + if(Bytes2Send > CanSend) { + Bytes2Send = CanSend; + } + } + SPITransaction.length = Bytes2Send * 8; + SPITransaction.rxlength = 0; + cc1101_Select(); + wait_Miso(); + spi_transfer(CC1101_TXFIFO | WRITE_BURST); + if((Err = spi_device_transmit(gSpiHndl,&SPITransaction)) != ESP_OK) { + ErrLine = __LINE__; + LOGE("spi_device_transmit failed %d\n",Err); + break; + } + cc1101_Deselect(); +// LOG("Sending %d bytes\n",Bytes2Send); + if(BytesSent == 0) { + // some or all of the tx data has been written to the FIFO, + // start transmitting +// LOG("Start tx\n"); + CC1101_setTxState(); + // Wait for the sync word to be transmitted + wait_GDO0_high(); + } + SPITransaction.tx_buffer += Bytes2Send; + BytesSent += Bytes2Send; + } + + // Wait until the end of the TxData transmission + wait_GDO0_low(); + Ret = true; + } while(false); + + setIdleState(); + CC1101_setRxState(); + + if(ErrLine != 0) { + LOGE("%s#%d: failure\n",__FUNCTION__,ErrLine); + } + + return Ret; +} + +// Called when GDO0 goes low, i.e. end of packet. +// Everything has been received. +// NB: this means the entire packet must fit in the FIFO so maximum +// message length is 64 bytes. +int CC1101_Rx(uint8_t *RxBuf,size_t RxBufLen,uint8_t *pRssi,uint8_t *pLqi) +{ + uint8_t rxBytes = readStatusReg(CC1101_RXBYTES); + uint8_t Rssi; + uint8_t Lqi; + int Ret; + int8_t FreqErr; + int8_t FreqCorrection; + +// Any data waiting to be read and no overflow? + do { + if(rxBytes & CC1101_RXFIFO_OVERFLOW_MASK) { + LOGE("RxFifo overflow\n"); + Ret = -2; + break; + } + + if(rxBytes < 2) { + // should have at least 2 bytes, packet len and one byte of data + LOGE("Internal error, rxBytes = %d\n",rxBytes); + Ret = -2; + break; + } + + // Get packet length + Ret = readConfigReg(CC1101_RXFIFO); + if(Ret > RxBufLen) { + // Toss the data + LOGE("RxBuf too small %d < %d\n",RxBufLen,Ret); + Ret = -1; + break; + } + // Read the data + CC1101_readBurstReg(RxBuf,CC1101_RXFIFO,Ret); + // Read RSSI + Rssi = readConfigReg(CC1101_RXFIFO); + // Read LQI and CRC_OK + Lqi = readConfigReg(CC1101_RXFIFO); + if(!(Lqi & CC1101_CRC_OK_MASK)) { + // Crc error, ignore the packet + LOG("Ignoring %d byte packet, CRC error\n",Ret); + Ret = 0; + break; + } + // CRC is valid + if(pRssi != NULL) { + *pRssi = Rssi; + } + if(pLqi != NULL) { + *pLqi = Lqi & CC1101_LQI_MASK; + } + FreqErr = (int8_t) CC1101_readReg(CC1101_FREQEST,CC1101_STATUS_REGISTER); + if(FreqErr != 0 && gFreqErrSumCount < 255) { + gFreqErrSum += FreqErr + gFreqCorrection; + gFreqErrSumCount++; + FreqCorrection = (int8_t) (gFreqErrSum / gFreqErrSumCount); + if(gFreqCorrection != FreqCorrection) { + LOGA("FreqCorrection %d -> %d\n",gFreqCorrection,FreqCorrection); + gFreqCorrection = FreqCorrection; + CC1101_writeReg(CC1101_FSCTRL0,gFreqCorrection); + } + if(gFreqErrSumCount == 255) { + LOGA("Final FreqCorrection %d\n",gFreqCorrection); + } + } + } while(false); + + setIdleState(); + flushRxFifo(); + CC1101_setRxState(); + + return Ret; +} + +bool CC1101_Present() +{ + bool Ret = false; + uint8_t PartNum = CC1101_readReg(CC1101_PARTNUM, CC1101_STATUS_REGISTER); + uint8_t ChipVersion = CC1101_readReg(CC1101_VERSION, CC1101_STATUS_REGISTER); + + if(PartNum == 0 && (ChipVersion == 20 || ChipVersion == 4)) { + LOGA("CC1101 detected\n"); + Ret = true; + } + else { + if(PartNum != 0) { + LOGA("Invalid PartNum 0x%x\n",PartNum); + } + else { + LOGA("Invalid or unsupported ChipVersion 0x%x\n",ChipVersion); + } + } + + return Ret; +} + +void CC1101_SetConfig(const RfSetting *pConfig) +{ + int i; + uint8_t RegWasSet[CC1101_TEST0 + 1]; + uint8_t Reg; + + memset(RegWasSet,0,sizeof(RegWasSet)); + setIdleState(); + + if(pConfig == NULL) { +// Just set the fixed registers + LOG("Setting fixed registers\n"); + for(i = 0; (Reg = gFixedConfig[i].Reg) != 0xff; i++) { + CC1101_writeReg(Reg,gFixedConfig[i].Value); + } + // Set TX power + CC1101_writeReg(CC1101_PATABLE,CC1101_DEFVAL_PATABLE); + } + else { + for(i = 0; (Reg = gFixedConfig[i].Reg) != 0xff; i++) { + RegWasSet[Reg] = 1; + } + + while((Reg = pConfig->Reg) != 0xff) { + if(RegWasSet[Reg] == 1) { + LOG("%s value ignored\n",RegNamesCC1101[Reg]); + } + else { + if(RegWasSet[Reg] == 2) { + LOG("%s value set before\n",RegNamesCC1101[Reg]); + } + CC1101_writeReg(pConfig->Reg,pConfig->Value); + RegWasSet[Reg] = 2; + } + pConfig++; + } +#if 0 + for(Reg = 0; Reg <= CC1101_TEST0; Reg++) { + if(RegWasSet[Reg] == 0) { + LOG("%s value not set\n",RegNamesCC1101[Reg]); + } + } +#endif + } +} + +void setIdleState() +{ + uint8_t MarcState; + CC1101_cmdStrobe(CC1101_SIDLE); +// Wait for it + do { + MarcState = readStatusReg(CC1101_MARCSTATE); + } while(MarcState != CC1101_STATE_IDLE); +} + + +void CC1101_logState() +{ + static uint8_t LastMarcState = 0xff; + uint8_t MarcState; + + MarcState = readStatusReg(CC1101_MARCSTATE); + if(LastMarcState != MarcState) { + LOG("MarcState 0x%x -> 0x%x\n",LastMarcState,MarcState); + LastMarcState = MarcState; + } +} + +#endif // CONFIG_OEPL_SUBGIG_SUPPORT + diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/cc1101_radio.h b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/cc1101_radio.h new file mode 100644 index 00000000..a8335be6 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/cc1101_radio.h @@ -0,0 +1,118 @@ +// Large portions of this code was copied from: +// https://github.com/nopnop2002/esp-idf-cc1101 with the following copyright + +/* + * Copyright (c) 2011 panStamp + * Copyright (c) 2016 Tyler Sommer + * + * This file is part of the CC1101 project. + * + * CC1101 is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * CC1101 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with CC1101; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * Author: Daniel Berenguer + * Creation date: 03/03/2011 + */ + +#ifndef __CC1101_RADIO_H_ +#define __CC1101_RADIO_H_ + +/** + * CC1101 configuration registers + */ +#define CC1101_IOCFG2 0x00 // GDO2 Output Pin Configuration +#define CC1101_IOCFG1 0x01 // GDO1 Output Pin Configuration +#define CC1101_IOCFG0 0x02 // GDO0 Output Pin Configuration +#define CC1101_FIFOTHR 0x03 // RX FIFO and TX FIFO Thresholds +#define CC1101_SYNC1 0x04 // Sync Word, High Byte +#define CC1101_SYNC0 0x05 // Sync Word, Low Byte +#define CC1101_PKTLEN 0x06 // Packet Length +#define CC1101_PKTCTRL1 0x07 // Packet Automation Control +#define CC1101_PKTCTRL0 0x08 // Packet Automation Control +#define CC1101_ADDR 0x09 // Device Address +#define CC1101_CHANNR 0x0A // Channel Number +#define CC1101_FSCTRL1 0x0B // Frequency Synthesizer Control +#define CC1101_FSCTRL0 0x0C // Frequency Synthesizer Control +#define CC1101_FREQ2 0x0D // Frequency Control Word, High Byte +#define CC1101_FREQ1 0x0E // Frequency Control Word, Middle Byte +#define CC1101_FREQ0 0x0F // Frequency Control Word, Low Byte +#define CC1101_MDMCFG4 0x10 // Modem Configuration +#define CC1101_MDMCFG3 0x11 // Modem Configuration +#define CC1101_MDMCFG2 0x12 // Modem Configuration +#define CC1101_MDMCFG1 0x13 // Modem Configuration +#define CC1101_MDMCFG0 0x14 // Modem Configuration +#define CC1101_DEVIATN 0x15 // Modem Deviation Setting +#define CC1101_MCSM2 0x16 // Main Radio Control State Machine Configuration +#define CC1101_MCSM1 0x17 // Main Radio Control State Machine Configuration +#define CC1101_MCSM0 0x18 // Main Radio Control State Machine Configuration +#define CC1101_FOCCFG 0x19 // Frequency Offset Compensation Configuration +#define CC1101_BSCFG 0x1A // Bit Synchronization Configuration +#define CC1101_AGCCTRL2 0x1B // AGC Control +#define CC1101_AGCCTRL1 0x1C // AGC Control +#define CC1101_AGCCTRL0 0x1D // AGC Control +#define CC1101_WOREVT1 0x1E // High Byte Event0 Timeout +#define CC1101_WOREVT0 0x1F // Low Byte Event0 Timeout +#define CC1101_WORCTRL 0x20 // Wake On Radio Control +#define CC1101_FREND1 0x21 // Front End RX Configuration +#define CC1101_FREND0 0x22 // Front End TX Configuration +#define CC1101_FSCAL3 0x23 // Frequency Synthesizer Calibration +#define CC1101_FSCAL2 0x24 // Frequency Synthesizer Calibration +#define CC1101_FSCAL1 0x25 // Frequency Synthesizer Calibration +#define CC1101_FSCAL0 0x26 // Frequency Synthesizer Calibration +#define CC1101_RCCTRL1 0x27 // RC Oscillator Configuration +#define CC1101_RCCTRL0 0x28 // RC Oscillator Configuration +#define CC1101_FSTEST 0x29 // Frequency Synthesizer Calibration Control +#define CC1101_PTEST 0x2A // Production Test +#define CC1101_AGCTEST 0x2B // AGC Test +#define CC1101_TEST2 0x2C // Various Test Settings +#define CC1101_TEST1 0x2D // Various Test Settings +#define CC1101_TEST0 0x2E // Various Test Settings + +/** + * Status registers + */ +#define CC1101_PARTNUM 0x30 // Chip ID +#define CC1101_VERSION 0x31 // Chip ID +#define CC1101_FREQEST 0x32 // Frequency Offset Estimate from Demodulator +#define CC1101_LQI 0x33 // Demodulator Estimate for Link Quality +#define CC1101_RSSI 0x34 // Received Signal Strength Indication +#define CC1101_MARCSTATE 0x35 // Main Radio Control State Machine State +#define CC1101_WORTIME1 0x36 // High Byte of WOR Time +#define CC1101_WORTIME0 0x37 // Low Byte of WOR Time +#define CC1101_PKTSTATUS 0x38 // Current GDOx Status and Packet Status +#define CC1101_VCO_VC_DAC 0x39 // Current Setting from PLL Calibration Module +#define CC1101_TXBYTES 0x3A // Underflow and Number of Bytes +#define CC1101_RXBYTES 0x3B // Overflow and Number of Bytes +#define CC1101_RCCTRL1_STATUS 0x3C // Last RC Oscillator Calibration Result +#define CC1101_RCCTRL0_STATUS 0x3D // Last RC Oscillator Calibration Result + +typedef struct { + uint16_t Reg; + uint8_t Value; +} RfSetting; + +extern spi_device_handle_t gSpiHndl; + +void CC1101_SetConfig(const RfSetting *pConfig); +int CC1101_Rx(uint8_t *RxBuf,size_t RxBufLen,uint8_t *pRssi,uint8_t *pLqi); +bool CC1101_Tx(uint8_t *TxData); +bool CC1101_Present(void); +void CC1101_DumpRegs(void); +void CC1101_reset(void); +void CC1101_logState(void); +void CC1101_setRxState(void); + +#endif // __CC1101_RADIO_H_ + diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/led.c b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/led.c new file mode 100644 index 00000000..87469298 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/led.c @@ -0,0 +1,48 @@ +#include "led.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "freertos/timers.h" +#include "proto.h" +#include +#include +#include +#include + +#define NUM_LEDS 2 + +const gpio_num_t led_pins[NUM_LEDS] = {LED1, LED2}; +TimerHandle_t led_timers[NUM_LEDS] = {0}; + +void led_timer_callback(TimerHandle_t xTimer) { + int led_index = (int)pvTimerGetTimerID(xTimer); + if (led_index >= 0 && led_index < NUM_LEDS) { + gpio_set_level(led_pins[led_index], 0); + } +} + +void init_led() { + gpio_config_t led1 = {}; + led1.intr_type = GPIO_INTR_DISABLE; + led1.mode = GPIO_MODE_OUTPUT; + led1.pin_bit_mask = ((1ULL << LED1) | (1ULL << LED2)); + led1.pull_down_en = 0; + led1.pull_up_en = 0; + gpio_config(&led1); + + for (int i = 0; i < NUM_LEDS; i++) { + led_timers[i] = xTimerCreate("led_timer", pdMS_TO_TICKS(50), pdFALSE, (void *)i, led_timer_callback); + } +} + +void led_flash(int nr) { + gpio_set_level(led_pins[nr], 1); + if (nr >= 0 && nr < NUM_LEDS) { + xTimerStart(led_timers[nr], 0); + } +} + +void led_set(int nr, bool state) { + gpio_set_level(nr, state); +} \ No newline at end of file diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/led.h b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/led.h new file mode 100644 index 00000000..a76467c7 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/led.h @@ -0,0 +1,6 @@ +#pragma once +#include + +void init_led(); +void led_set(int nr, bool state); +void led_flash(int nr); diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/main.c b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/main.c new file mode 100644 index 00000000..f675bb0f --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/main.c @@ -0,0 +1,833 @@ +// Ported to ESP32-H2 By ATC1441(ATCnetz.de) for OpenEPaperLink at ~08.2023 + +#include "main.h" +#include "driver/gpio.h" +#include "driver/uart.h" +#include "esp_err.h" +#include "esp_event.h" +#include "esp_ieee802154.h" +#include "esp_log.h" +#include "esp_phy_init.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "led.h" +#include "proto.h" +#include "radio.h" +#include "sdkconfig.h" +#include "second_uart.h" +//#include "soc/lp_uart_reg.h" +#include "soc/uart_struct.h" +#include "utils.h" +#include +#include +#include +#include +#include +#include +#include "SubGigRadio.h" + + +static const char *TAG = "MAIN"; + +const uint8_t channelList[6] = {11, 15, 20, 25, 26, 27}; + +#define DATATYPE_NOUPDATE 0 +#define HW_TYPE 0xC6 + +#define MAX_PENDING_MACS 250 +#define HOUSEKEEPING_INTERVAL 60UL + +struct pendingData pendingDataArr[MAX_PENDING_MACS]; + +// VERSION GOES HERE! +uint16_t version = 0x001d; + +#define RAW_PKT_PADDING 2 + +uint8_t radiotxbuffer[128]; +uint8_t radiorxbuffer[128]; + +static uint32_t housekeepingTimer; + +struct blockRequest requestedData = {0}; // holds which data was requested by the tag + +uint8_t dstMac[8]; // target for the block transfer +uint16_t dstPan; // + +static uint32_t blockStartTimer = 0; // reference that holds when the AP sends the next block +uint32_t nextBlockAttempt = 0; // reference time for when the AP can request a new block from the ESP32 +uint8_t seq = 0; // holds current sequence number for transmission +uint8_t blockbuffer[BLOCK_XFER_BUFFER_SIZE + 5]; // block transfer buffer +uint8_t lastAckMac[8] = {0}; + +// these variables hold the current mac were talking to +#define CONCURRENT_REQUEST_DELAY 1200UL +uint32_t lastBlockRequest = 0; +uint8_t lastBlockMac[8]; +uint8_t lastTagReturn[8]; + +#define NO_SUBGHZ_CHANNEL 255 +uint8_t curSubGhzChannel; +uint8_t curChannel = 25; +uint8_t curPower = 10; + +uint8_t curPendingData = 0; +uint8_t curNoUpdate = 0; + +bool highspeedSerial = false; + +void sendXferCompleteAck(uint8_t *dst); +void sendCancelXfer(uint8_t *dst); +void espNotifyAPInfo(); + +// tools +void addCRC(void *p, uint8_t len) { + uint8_t total = 0; + for (uint8_t c = 1; c < len; c++) { + total += ((uint8_t *) p)[c]; + } + ((uint8_t *) p)[0] = total; +} +bool checkCRC(void *p, uint8_t len) { + uint8_t total = 0; + for (uint8_t c = 1; c < len; c++) { + total += ((uint8_t *) p)[c]; + } + return ((uint8_t *) p)[0] == total; +} + +uint8_t getPacketType(void *buffer) { + struct MacFcs *fcs = buffer; + if ((fcs->frameType == 1) && (fcs->destAddrType == 2) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 0)) { + // broadcast frame + uint8_t type = ((uint8_t *) buffer)[sizeof(struct MacFrameBcast)]; + return type; + } else if ((fcs->frameType == 1) && (fcs->destAddrType == 3) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 1)) { + // normal frame + uint8_t type = ((uint8_t *) buffer)[sizeof(struct MacFrameNormal)]; + return type; + } + return 0; +} +uint8_t getBlockDataLength() { + uint8_t partNo = 0; + for (uint8_t c = 0; c < BLOCK_MAX_PARTS; c++) { + if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) { + partNo++; + } + } + return partNo; +} + +// pendingdata slot stuff +int8_t findSlotForMac(const uint8_t *mac) { + for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) { + if (memcmp(mac, ((uint8_t *) &(pendingDataArr[c].targetMac)), 8) == 0) { + if (pendingDataArr[c].attemptsLeft != 0) { + return c; + } + } + } + return -1; +} +int8_t findFreeSlot() { + for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) { + if (pendingDataArr[c].attemptsLeft == 0) { + return c; + } + } + return -1; +} +int8_t findSlotForVer(const uint8_t *ver) { + for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) { + if (memcmp(ver, ((uint8_t *) &(pendingDataArr[c].availdatainfo.dataVer)), 8) == 0) { + if (pendingDataArr[c].attemptsLeft != 0) return c; + } + } + return -1; +} +void deleteAllPendingDataForVer(const uint8_t *ver) { + int8_t slot = -1; + do { + slot = findSlotForVer(ver); + if (slot != -1) pendingDataArr[slot].attemptsLeft = 0; + } while (slot != -1); +} +void deleteAllPendingDataForMac(const uint8_t *mac) { + int8_t slot = -1; + do { + slot = findSlotForMac(mac); + if (slot != -1) pendingDataArr[slot].attemptsLeft = 0; + } while (slot != -1); +} + +void countSlots() { + curPendingData = 0; + curNoUpdate = 0; + for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) { + if (pendingDataArr[c].attemptsLeft != 0) { + if (pendingDataArr[c].availdatainfo.dataType != 0) { + curPendingData++; + } else { + curNoUpdate++; + } + } + } +} + +// processing serial data +#define ZBS_RX_WAIT_HEADER 0 +#define ZBS_RX_WAIT_SDA 1 // send data avail +#define ZBS_RX_WAIT_CANCEL 2 // cancel traffic for mac +#define ZBS_RX_WAIT_SCP 3 // set channel power +#define ZBS_RX_WAIT_BLOCKDATA 4 + +bool isSame(uint8_t *in1, char *in2, int len) { + bool flag = 1; + for (int i = 0; i < len; i++) { + if (in1[i] != in2[i]) flag = 0; + } + return flag; +} + +int blockPosition = 0; +void processSerial(uint8_t lastchar) { + static uint8_t cmdbuffer[4]; + static uint8_t RXState = 0; + static uint8_t serialbuffer[48]; + static uint8_t *serialbufferp; + static uint8_t bytesRemain = 0; + static uint32_t lastSerial = 0; + static uint32_t blockStartTime = 0; + if ((RXState != ZBS_RX_WAIT_HEADER) && ((getMillis() - lastSerial) > 1000)) { + RXState = ZBS_RX_WAIT_HEADER; + ESP_LOGI(TAG, "UART Timeout"); + } + lastSerial = getMillis(); + switch (RXState) { + case ZBS_RX_WAIT_HEADER: + // shift characters in + for (uint8_t c = 0; c < 3; c++) { + cmdbuffer[c] = cmdbuffer[c + 1]; + } + cmdbuffer[3] = lastchar; + + if (isSame(cmdbuffer + 1, ">D>", 3)) { + pr("ACK>"); + blockStartTime = getMillis(); + ESP_LOGI(TAG, "Starting BlkData, %lu ms after request", blockStartTime - nextBlockAttempt ); + blockPosition = 0; + RXState = ZBS_RX_WAIT_BLOCKDATA; + } + + if (isSame(cmdbuffer, "SDA>", 4)) { + ESP_LOGI(TAG, "SDA In"); + RXState = ZBS_RX_WAIT_SDA; + bytesRemain = sizeof(struct pendingData); + serialbufferp = serialbuffer; + break; + } + if (isSame(cmdbuffer, "CXD>", 4)) { + ESP_LOGI(TAG, "CXD In"); + RXState = ZBS_RX_WAIT_CANCEL; + bytesRemain = sizeof(struct pendingData); + serialbufferp = serialbuffer; + break; + } + if (isSame(cmdbuffer, "SCP>", 4)) { + ESP_LOGI(TAG, "SCP In"); + RXState = ZBS_RX_WAIT_SCP; + bytesRemain = sizeof(struct espSetChannelPower); + serialbufferp = serialbuffer; + break; + } + if (isSame(cmdbuffer, "NFO?", 4)) { + pr("ACK>"); + ESP_LOGI(TAG, "NFO? In"); + espNotifyAPInfo(); + RXState = ZBS_RX_WAIT_HEADER; + } + if (isSame(cmdbuffer, "RDY?", 4)) { + pr("ACK>"); + ESP_LOGI(TAG, "RDY? In"); + RXState = ZBS_RX_WAIT_HEADER; + } + if (isSame(cmdbuffer, "RSET", 4)) { + pr("ACK>"); + ESP_LOGI(TAG, "RSET In"); + delay(100); + // TODO RESET US HERE + RXState = ZBS_RX_WAIT_HEADER; + } + if (isSame(cmdbuffer, "HSPD", 4)) { + pr("ACK>"); + ESP_LOGI(TAG, "HSPD In, switching to 2000000"); + delay(100); + uart_switch_speed(2000000); + delay(100); + highspeedSerial = true; + pr("ACK>"); + RXState = ZBS_RX_WAIT_HEADER; + } + break; + case ZBS_RX_WAIT_BLOCKDATA: + blockbuffer[blockPosition++] = 0xAA ^ lastchar; + if (blockPosition >= 4100) { + ESP_LOGI(TAG, "Blockdata fully received in %lu ms, %lu ms after the request", getMillis() - blockStartTime, getMillis() - nextBlockAttempt); + RXState = ZBS_RX_WAIT_HEADER; + } + break; + + case ZBS_RX_WAIT_SDA: + *serialbufferp = lastchar; + serialbufferp++; + bytesRemain--; + if (bytesRemain == 0) { + if (checkCRC(serialbuffer, sizeof(struct pendingData))) { + struct pendingData *pd = (struct pendingData *) serialbuffer; + int8_t slot = findSlotForMac(pd->targetMac); + if (slot == -1) slot = findFreeSlot(); + if (slot != -1) { + memcpy(&(pendingDataArr[slot]), serialbuffer, sizeof(struct pendingData)); + pr("ACK>"); + } else { + pr("NOQ>"); + } + } else { + pr("NOK>"); + } + + RXState = ZBS_RX_WAIT_HEADER; + } + break; + case ZBS_RX_WAIT_CANCEL: + *serialbufferp = lastchar; + serialbufferp++; + bytesRemain--; + if (bytesRemain == 0) { + if (checkCRC(serialbuffer, sizeof(struct pendingData))) { + struct pendingData *pd = (struct pendingData *) serialbuffer; + deleteAllPendingDataForMac((uint8_t *) &pd->targetMac); + pr("ACK>"); + } else { + pr("NOK>"); + } + + RXState = ZBS_RX_WAIT_HEADER; + } + break; + case ZBS_RX_WAIT_SCP: + *serialbufferp = lastchar; + serialbufferp++; + bytesRemain--; + if (bytesRemain == 0) { + if (checkCRC(serialbuffer, sizeof(struct espSetChannelPower))) { + struct espSetChannelPower *scp = (struct espSetChannelPower *) serialbuffer; +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + if(curSubGhzChannel != scp->subghzchannel + && curSubGhzChannel != NO_SUBGHZ_CHANNEL) + { + curSubGhzChannel = scp->subghzchannel; + ESP_LOGI(TAG,"Set SubGhz channel: %d",curSubGhzChannel); + SubGig_radioSetChannel(scp->subghzchannel); + if(scp->channel == 0) { + // Not setting 802.15.4 channel + goto SCPchannelFound; + } + } +#endif + for (uint8_t c = 0; c < sizeof(channelList); c++) { + if (channelList[c] == scp->channel) goto SCPchannelFound; + } + goto SCPfailed; + SCPchannelFound: + pr("ACK>"); + if (curChannel != scp->channel) { + radioSetChannel(scp->channel); + curChannel = scp->channel; + } + curPower = scp->power; + radioSetTxPower(scp->power); + ESP_LOGI(TAG, "Set channel: %d power: %d", curChannel, curPower); + } else { + SCPfailed: + pr("NOK>"); + } + RXState = ZBS_RX_WAIT_HEADER; + } + break; + } +} + +// sending data to the ESP +void espBlockRequest(const struct blockRequest *br, uint8_t *src) { + struct espBlockRequest *ebr = (struct espBlockRequest *) blockbuffer; + uartTx('R'); + uartTx('Q'); + uartTx('B'); + uartTx('>'); + memcpy(&(ebr->ver), &(br->ver), 8); + memcpy(&(ebr->src), src, 8); + ebr->blockId = br->blockId; + addCRC(ebr, sizeof(struct espBlockRequest)); + for (uint8_t c = 0; c < sizeof(struct espBlockRequest); c++) { + uartTx(((uint8_t *) ebr)[c]); + } +} +void espNotifyAvailDataReq(const struct AvailDataReq *adr, const uint8_t *src) { + uartTx('A'); + uartTx('D'); + uartTx('R'); + uartTx('>'); + + struct espAvailDataReq eadr = {0}; + memcpy((void *) eadr.src, (void *) src, 8); + memcpy((void *) &eadr.adr, (void *) adr, sizeof(struct AvailDataReq)); + addCRC(&eadr, sizeof(struct espAvailDataReq)); + for (uint8_t c = 0; c < sizeof(struct espAvailDataReq); c++) { + uartTx(((uint8_t *) &eadr)[c]); + } +} +void espNotifyXferComplete(const uint8_t *src) { + struct espXferComplete exfc; + memcpy(&exfc.src, src, 8); + uartTx('X'); + uartTx('F'); + uartTx('C'); + uartTx('>'); + addCRC(&exfc, sizeof(exfc)); + for (uint8_t c = 0; c < sizeof(exfc); c++) { + uartTx(((uint8_t *) &exfc)[c]); + } +} +void espNotifyTimeOut(const uint8_t *src) { + struct espXferComplete exfc; + memcpy(&exfc.src, src, 8); + uartTx('X'); + uartTx('T'); + uartTx('O'); + uartTx('>'); + addCRC(&exfc, sizeof(exfc)); + for (uint8_t c = 0; c < sizeof(exfc); c++) { + uartTx(((uint8_t *) &exfc)[c]); + } +} +void espNotifyAPInfo() { + pr("TYP>%02X", HW_TYPE); + pr("VER>%04X", version); + pr("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]); + pr("%02X%02X", mSelfMac[2], mSelfMac[3]); + pr("%02X%02X", mSelfMac[4], mSelfMac[5]); + pr("%02X%02X", mSelfMac[6], mSelfMac[7]); + pr("ZCH>%02X", curChannel); +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + pr("SCH>%03d",curSubGhzChannel); +#endif + pr("ZPW>%02X", curPower); + countSlots(); + pr("PEN>%02X", curPendingData); + pr("NOP>%02X", curNoUpdate); +} + +void espNotifyTagReturnData(uint8_t *src, uint8_t len) { + struct tagReturnData *trd = (struct tagReturnData *)(radiorxbuffer + sizeof(struct MacFrameBcast) + 1); // oh how I'd love to pass this as an argument, but sdcc won't let me + struct espTagReturnData *etrd = (struct espTagReturnData *)radiotxbuffer; + + if (memcmp((void *) & trd->dataVer, lastTagReturn, 8) == 0) { + return; + } else { + memcpy(lastTagReturn, &trd->dataVer, 8); + } + + memcpy(etrd->src, src, 8); + etrd->len = len; + memcpy(&etrd->returnData, trd, len); + addCRC(etrd, len + 10); + + uartTx('T'); + uartTx('R'); + uartTx('D'); + uartTx('>'); + for (uint8_t c = 0; c < len + 10; c++) { + uartTx(((uint8_t *)etrd)[c]); + } +} + +// process data from tag +void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) { + struct MacFrameNormal *rxHeader = (struct MacFrameNormal *) buffer; + struct blockRequest *blockReq = (struct blockRequest *) (buffer + sizeof(struct MacFrameNormal) + 1); + if (!checkCRC(blockReq, sizeof(struct blockRequest))) return; + + // check if we're already talking to this mac + if (memcmp(rxHeader->src, lastBlockMac, 8) == 0) { + lastBlockRequest = getMillis(); + } else { + // we weren't talking to this mac, see if there was a transfer in progress from another mac, recently + if ((getMillis() - lastBlockRequest) > CONCURRENT_REQUEST_DELAY) { + // mark this mac as the new current mac we're talking to + memcpy((void *) lastBlockMac, (void *) rxHeader->src, 8); + lastBlockRequest = getMillis(); + } else { + // we're talking to another mac, let this mac know we can't accomodate another request right now + pr("BUSY!\n"); + sendCancelXfer(rxHeader->src); + return; + } + } + + // check if we have data for this mac + if (findSlotForMac(rxHeader->src) == -1) { + // no data for this mac, politely tell it to fuck off + sendCancelXfer(rxHeader->src); + return; + } + + bool requestDataDownload = false; + if ((blockReq->blockId != requestedData.blockId) || (blockReq->ver != requestedData.ver)) { + // requested block isn't already in the buffer + requestDataDownload = true; + } else { + // requested block is already in the buffer + if (forceBlockDownload) { + if ((getMillis() - nextBlockAttempt) > 380) { + requestDataDownload = true; + pr("FORCED\n"); + } else { + pr("IGNORED\n"); + } + } + } + + // copy blockrequest into requested data + memcpy(&requestedData, blockReq, sizeof(struct blockRequest)); + + struct MacFrameNormal *txHeader = (struct MacFrameNormal *) (radiotxbuffer + 1); + struct blockRequestAck *blockRequestAck = (struct blockRequestAck *) (radiotxbuffer + sizeof(struct MacFrameNormal) + 2); + radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + sizeof(struct blockRequestAck) + RAW_PKT_PADDING; + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_REQUEST_ACK; + + if (blockStartTimer == 0) { + if (requestDataDownload) { + if (highspeedSerial == true) { + blockRequestAck->pleaseWaitMs = 140; + } else { + blockRequestAck->pleaseWaitMs = 550; + } + } else { + // block is already in buffer + blockRequestAck->pleaseWaitMs = 30; + } + } else { + blockRequestAck->pleaseWaitMs = 30; + } + blockStartTimer = getMillis() + blockRequestAck->pleaseWaitMs; + + memcpy(txHeader->src, mSelfMac, 8); + memcpy(txHeader->dst, rxHeader->src, 8); + + txHeader->pan = rxHeader->pan; + txHeader->fcs.frameType = 1; + txHeader->fcs.panIdCompressed = 1; + txHeader->fcs.destAddrType = 3; + txHeader->fcs.srcAddrType = 3; + txHeader->seq = seq++; + + addCRC((void *) blockRequestAck, sizeof(struct blockRequestAck)); + + radioTx(radiotxbuffer); + + // save the target for the blockdata + memcpy(dstMac, rxHeader->src, 8); + dstPan = rxHeader->pan; + + if (requestDataDownload) { + blockPosition = 0; + espBlockRequest(&requestedData, rxHeader->src); + nextBlockAttempt = getMillis(); + } +} + +void processAvailDataReq(uint8_t *buffer) { + struct MacFrameBcast *rxHeader = (struct MacFrameBcast *) buffer; + struct AvailDataReq *availDataReq = (struct AvailDataReq *) (buffer + sizeof(struct MacFrameBcast) + 1); + + if (!checkCRC(availDataReq, sizeof(struct AvailDataReq))) return; + + // prepare tx buffer to send a response + memset(radiotxbuffer, 0, sizeof(struct MacFrameNormal) + sizeof(struct AvailDataInfo) + 2); // 120); + struct MacFrameNormal *txHeader = (struct MacFrameNormal *) (radiotxbuffer + 1); + struct AvailDataInfo *availDataInfo = (struct AvailDataInfo *) (radiotxbuffer + sizeof(struct MacFrameNormal) + 2); + radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + sizeof(struct AvailDataInfo) + RAW_PKT_PADDING; + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_AVAIL_DATA_INFO; + + // check to see if we have data available for this mac + bool haveData = false; + for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) { + if (pendingDataArr[c].attemptsLeft) { + if (memcmp(pendingDataArr[c].targetMac, rxHeader->src, 8) == 0) { + haveData = true; + memcpy((void *) availDataInfo, &(pendingDataArr[c].availdatainfo), sizeof(struct AvailDataInfo)); + break; + } + } + } + + // couldn't find data for this mac + if (!haveData) availDataInfo->dataType = DATATYPE_NOUPDATE; + + memcpy(txHeader->src, mSelfMac, 8); + memcpy(txHeader->dst, rxHeader->src, 8); + txHeader->pan = rxHeader->dstPan; + txHeader->fcs.frameType = 1; + txHeader->fcs.panIdCompressed = 1; + txHeader->fcs.destAddrType = 3; + txHeader->fcs.srcAddrType = 3; + txHeader->seq = seq++; + addCRC(availDataInfo, sizeof(struct AvailDataInfo)); + radioTx(radiotxbuffer); + memset(lastAckMac, 0, 8); // reset lastAckMac, so we can record if we've received exactly one ack packet + espNotifyAvailDataReq(availDataReq, rxHeader->src); +} +void processXferComplete(uint8_t *buffer) { + struct MacFrameNormal *rxHeader = (struct MacFrameNormal *) buffer; + sendXferCompleteAck(rxHeader->src); + if (memcmp(lastAckMac, rxHeader->src, 8) != 0) { + memcpy((void *) lastAckMac, (void *) rxHeader->src, 8); + espNotifyXferComplete(rxHeader->src); + int8_t slot = findSlotForMac(rxHeader->src); + if (slot != -1) pendingDataArr[slot].attemptsLeft = 0; + } +} + +void processTagReturnData(uint8_t *buffer, uint8_t len) { + struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buffer; + struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1); + + if (!checkCRC((buffer + sizeof(struct MacFrameBcast) + 1), len - (sizeof(struct MacFrameBcast) + 1))) { + return; + } + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_TAG_RETURN_DATA_ACK; + radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING; + memcpy(frameHeader->src, mSelfMac, 8); + memcpy(frameHeader->dst, rxframe->src, 8); + radiotxbuffer[1] = 0x41; // fast way to set the appropriate bits + radiotxbuffer[2] = 0xCC; // normal frame + frameHeader->seq = seq++; + frameHeader->pan = rxframe->srcPan; + radioTx(radiotxbuffer); + + espNotifyTagReturnData(rxframe->src, len - (sizeof(struct MacFrameBcast) + 1)); +} + +// send block data to the tag +void sendPart(uint8_t partNo) { + struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1); + struct blockPart *blockPart = (struct blockPart *) (radiotxbuffer + sizeof(struct MacFrameNormal) + 2); + memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal)); + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_PART; + radiotxbuffer[0] = sizeof(struct MacFrameNormal) + sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE + 1 + RAW_PKT_PADDING; + memcpy(frameHeader->src, mSelfMac, 8); + memcpy(frameHeader->dst, dstMac, 8); + blockPart->blockId = requestedData.blockId; + blockPart->blockPart = partNo; + memcpy(&(blockPart->data), blockbuffer + (partNo * BLOCK_PART_DATA_SIZE), BLOCK_PART_DATA_SIZE); + addCRC(blockPart, sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE); + frameHeader->fcs.frameType = 1; + frameHeader->fcs.panIdCompressed = 1; + frameHeader->fcs.destAddrType = 3; + frameHeader->fcs.srcAddrType = 3; + frameHeader->seq = seq++; + frameHeader->pan = dstPan; + radioTx(radiotxbuffer); +} +void sendBlockData() { + if (getBlockDataLength() == 0) { + pr("Invalid block request received, 0 parts..\n"); + requestedData.requestedParts[0] |= 0x01; + } + + pr("Sending parts:"); + for (uint8_t c = 0; (c < BLOCK_MAX_PARTS); c++) { + if (c % 10 == 0) pr(" "); + if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) { + pr("X"); + } else { + pr("."); + } + } + pr("\n"); + + uint8_t partNo = 0; + while (partNo < BLOCK_MAX_PARTS) { + for (uint8_t c = 0; (c < BLOCK_MAX_PARTS) && (partNo < BLOCK_MAX_PARTS); c++) { + if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) { + sendPart(c); + partNo++; + } + } + if(dstPan == PROTO_PAN_ID_SUBGHZ) { + // Don't send BLOCK_MAX_PARTS for subgig, it requests what it + // can handle with its limited RAM + break; + } + } +} +void sendXferCompleteAck(uint8_t *dst) { + struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1); + memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal)); + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_XFER_COMPLETE_ACK; + radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING; + memcpy(frameHeader->src, mSelfMac, 8); + memcpy(frameHeader->dst, dst, 8); + frameHeader->fcs.frameType = 1; + frameHeader->fcs.panIdCompressed = 1; + frameHeader->fcs.destAddrType = 3; + frameHeader->fcs.srcAddrType = 3; + frameHeader->seq = seq++; + frameHeader->pan = dstPan; + radioTx(radiotxbuffer); +} +void sendCancelXfer(uint8_t *dst) { + struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1); + memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal)); + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_CANCEL_XFER; + radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING; + memcpy(frameHeader->src, mSelfMac, 8); + memcpy(frameHeader->dst, dst, 8); + frameHeader->fcs.frameType = 1; + frameHeader->fcs.panIdCompressed = 1; + frameHeader->fcs.destAddrType = 3; + frameHeader->fcs.srcAddrType = 3; + frameHeader->seq = seq++; + frameHeader->pan = dstPan; + radioTx(radiotxbuffer); +} +void sendPong(void *buf) { + struct MacFrameBcast *rxframe = (struct MacFrameBcast *) buf; + struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1); + radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_PONG; +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + if(rxframe->srcPan == PROTO_PAN_ID_SUBGHZ) { + radiotxbuffer[sizeof(struct MacFrameNormal) + 2] = curSubGhzChannel; + } + else +#endif + radiotxbuffer[sizeof(struct MacFrameNormal) + 2] = curChannel; + radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + 1 + RAW_PKT_PADDING; + memcpy(frameHeader->src, mSelfMac, 8); + memcpy(frameHeader->dst, rxframe->src, 8); + radiotxbuffer[1] = 0x41; // fast way to set the appropriate bits + radiotxbuffer[2] = 0xCC; // normal frame + frameHeader->seq = seq++; + frameHeader->pan = rxframe->srcPan; + radioTx(radiotxbuffer); +} + +void app_main(void) { + esp_event_loop_create_default(); + + init_nvs(); + init_led(); + init_second_uart(); + + requestedData.blockId = 0xFF; + // clear the array with pending information + memset(pendingDataArr, 0, sizeof(pendingDataArr)); + + radio_init(curChannel); +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + if(SubGig_radio_init(curSubGhzChannel)) { + // Ether we don't have a cc1101 or it's not working + curSubGhzChannel = NO_SUBGHZ_CHANNEL; + ESP_LOGI(TAG,"CC1101 NOT detected."); + } + else { + ESP_LOGI(TAG,"CC1101 detected."); + } +#endif + radioSetTxPower(10); + + pr("RES>"); + pr("RDY>"); + ESP_LOGI(TAG, "H2 ready!"); + + housekeepingTimer = getMillis(); + while (1) { + while ((getMillis() - housekeepingTimer) < ((1000 * HOUSEKEEPING_INTERVAL) - 100)) { + int8_t ret = commsRxUnencrypted(radiorxbuffer); + if (ret > 1) { + led_flash(0); + // received a packet, lets see what it is + switch (getPacketType(radiorxbuffer)) { + case PKT_AVAIL_DATA_REQ: + if (ret == 28) { + // old version of the AvailDataReq struct, set all the new fields to zero, so it will pass the CRC + memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast) + sizeof(struct oldAvailDataReq), 0, + sizeof(struct AvailDataReq) - sizeof(struct oldAvailDataReq) + 2); + processAvailDataReq(radiorxbuffer); + } else if (ret == 40) { + // new version of the AvailDataReq struct + processAvailDataReq(radiorxbuffer); + } + break; + case PKT_BLOCK_REQUEST: + processBlockRequest(radiorxbuffer, 1); + break; + case PKT_BLOCK_PARTIAL_REQUEST: + processBlockRequest(radiorxbuffer, 0); + break; + case PKT_XFER_COMPLETE: + processXferComplete(radiorxbuffer); + break; + case PKT_PING: + sendPong(radiorxbuffer); + break; + case PKT_AVAIL_DATA_SHORTREQ: + // a short AvailDataReq is basically a very short (1 byte payload) packet that requires little preparation on the tx side, for optimal + // battery use bytes of the struct are set 0, so it passes the checksum test, and the ESP32 can detect that no interesting payload is + // sent + if (ret == 18) { + memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast), 0, sizeof(struct AvailDataReq) + 2); + processAvailDataReq(radiorxbuffer); + } + break; + case PKT_TAG_RETURN_DATA: + processTagReturnData(radiorxbuffer, ret); + break; + default: + ESP_LOGI(TAG, "t=%02X" , getPacketType(radiorxbuffer)); + break; + } + } else if (blockStartTimer == 0) { + vTaskDelay(10 / portTICK_PERIOD_MS); + } + + uint8_t curr_char; + while (getRxCharSecond(&curr_char)) processSerial(curr_char); + + if (blockStartTimer) { + if (getMillis() > blockStartTimer) { + sendBlockData(); + blockStartTimer = 0; + } + } + } + + memset(&lastTagReturn, 0, 8); + for (uint8_t cCount = 0; cCount < MAX_PENDING_MACS; cCount++) { + if (pendingDataArr[cCount].attemptsLeft == 1) { + if (pendingDataArr[cCount].availdatainfo.dataType != DATATYPE_NOUPDATE) { + espNotifyTimeOut(pendingDataArr[cCount].targetMac); + } + pendingDataArr[cCount].attemptsLeft = 0; + } else if (pendingDataArr[cCount].attemptsLeft > 1) { + pendingDataArr[cCount].attemptsLeft--; + if (pendingDataArr[cCount].availdatainfo.nextCheckIn) pendingDataArr[cCount].availdatainfo.nextCheckIn--; + } + } + housekeepingTimer = getMillis(); + } +} diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/main.h b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/main.h new file mode 100644 index 00000000..7b9637ef --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/main.h @@ -0,0 +1 @@ +#pragma once \ No newline at end of file diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/proto.h b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/proto.h new file mode 100644 index 00000000..0e02d1ea --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/proto.h @@ -0,0 +1,194 @@ +#ifndef _PROTO_H_ +#define _PROTO_H_ +#include + +#define LED1 22 +#define LED2 25 + +#define PROTO_PAN_ID (0x4447) // PAN ID compression shall be used +#define PROTO_PAN_ID_SUBGHZ (0x1337) // PAN ID compression shall be used + +#define RADIO_MAX_PACKET_LEN (125) // useful payload, not including the crc + +#define ADDR_MODE_NONE (0) +#define ADDR_MODE_SHORT (2) +#define ADDR_MODE_LONG (3) + +#define FRAME_TYPE_BEACON (0) +#define FRAME_TYPE_DATA (1) +#define FRAME_TYPE_ACK (2) +#define FRAME_TYPE_MAC_CMD (3) + +#define SHORT_MAC_UNUSED (0x10000000UL) // for radioRxFilterCfg's myShortMac + +struct MacFcs { + uint8_t frameType : 3; + uint8_t secure : 1; + uint8_t framePending : 1; + uint8_t ackReqd : 1; + uint8_t panIdCompressed : 1; + uint8_t rfu1 : 1; + uint8_t rfu2 : 2; + uint8_t destAddrType : 2; + uint8_t frameVer : 2; + uint8_t srcAddrType : 2; +} __attribute__((packed, aligned(1))); + +struct MacFrameFromMaster { + struct MacFcs fcs; + uint8_t seq; + uint16_t pan; + uint8_t dst[8]; + uint16_t from; +} __attribute__((packed, aligned(1))); + +struct MacFrameNormal { + struct MacFcs fcs; + uint8_t seq; + uint16_t pan; + uint8_t dst[8]; + uint8_t src[8]; +} __attribute__((packed, aligned(1))); + +struct MacFrameBcast { + struct MacFcs fcs; + uint8_t seq; + uint16_t dstPan; + uint16_t dstAddr; + uint16_t srcPan; + uint8_t src[8]; +} __attribute__((packed, aligned(1))); + +#define PKT_TAG_RETURN_DATA 0xE1 +#define PKT_TAG_RETURN_DATA_ACK 0xE2 +#define PKT_AVAIL_DATA_SHORTREQ 0xE3 +#define PKT_AVAIL_DATA_REQ 0xE5 +#define PKT_AVAIL_DATA_INFO 0xE6 +#define PKT_BLOCK_PARTIAL_REQUEST 0xE7 +#define PKT_BLOCK_REQUEST_ACK 0xE9 +#define PKT_BLOCK_REQUEST 0xE4 +#define PKT_BLOCK_PART 0xE8 +#define PKT_XFER_COMPLETE 0xEA +#define PKT_XFER_COMPLETE_ACK 0xEB +#define PKT_CANCEL_XFER 0xEC +#define PKT_PING 0xED +#define PKT_PONG 0xEE + +struct AvailDataReq { + uint8_t checksum; + uint8_t lastPacketLQI; + int8_t lastPacketRSSI; + int8_t temperature; + uint16_t batteryMv; + uint8_t hwType; + uint8_t wakeupReason; + uint8_t capabilities; + uint16_t tagSoftwareVersion; + uint8_t currentChannel; + uint8_t customMode; + uint8_t reserved[8]; +} __attribute__((packed, aligned(1))); + +struct oldAvailDataReq { + uint8_t checksum; + uint8_t lastPacketLQI; + int8_t lastPacketRSSI; + int8_t temperature; + uint16_t batteryMv; + uint8_t hwType; + uint8_t wakeupReason; + uint8_t capabilities; +} __attribute__((packed, aligned(1))); + +struct AvailDataInfo { + uint8_t checksum; + uint64_t dataVer; // MD5 of potential traffic + uint32_t dataSize; + uint8_t dataType; + uint8_t dataTypeArgument; // extra specification or instruction for the tag (LUT to be used for drawing image) + uint16_t nextCheckIn; // when should the tag check-in again? Measured in minutes +} __attribute__((packed, aligned(1))); + +struct pendingData { + struct AvailDataInfo availdatainfo; + uint16_t attemptsLeft; + uint8_t targetMac[8]; +} __attribute__((packed, aligned(1))); + +struct blockPart { + uint8_t checksum; + uint8_t blockId; + uint8_t blockPart; + uint8_t data[]; +} __attribute__((packed, aligned(1))); + +struct blockData { + uint16_t size; + uint16_t checksum; + uint8_t data[]; +} __attribute__((packed, aligned(1))); + +#define TAG_RETURN_DATA_SIZE 90 + +struct tagReturnData { + uint8_t checksum; + uint8_t partId; + uint64_t dataVer; + uint8_t dataType; + uint8_t data[TAG_RETURN_DATA_SIZE]; +} __attribute__((packed, aligned(1))); + +#define BLOCK_PART_DATA_SIZE 99 +#define BLOCK_MAX_PARTS 42 +#define BLOCK_DATA_SIZE 4096UL +#define BLOCK_XFER_BUFFER_SIZE BLOCK_DATA_SIZE + sizeof(struct blockData) +#define BLOCK_REQ_PARTS_BYTES 6 + +struct blockRequest { + uint8_t checksum; + uint64_t ver; + uint8_t blockId; + uint8_t type; + uint8_t requestedParts[BLOCK_REQ_PARTS_BYTES]; +} __attribute__((packed, aligned(1))); + +struct blockRequestAck { + uint8_t checksum; + uint16_t pleaseWaitMs; +} __attribute__((packed, aligned(1))); + +struct espBlockRequest { + uint8_t checksum; + uint64_t ver; + uint8_t blockId; + uint8_t src[8]; +} __attribute__((packed, aligned(1))); + +struct espXferComplete { + uint8_t checksum; + uint8_t src[8]; +} __attribute__((packed, aligned(1))); + +struct espAvailDataReq { + uint8_t checksum; + uint8_t src[8]; + struct AvailDataReq adr; +} __attribute__((packed, aligned(1))); + +struct espSetChannelPower { + uint8_t checksum; + uint8_t channel; + uint8_t power; +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + uint8_t subghzchannel; +#endif +} __attribute__((packed, aligned(1))); + +struct espTagReturnData { + uint8_t checksum; + uint8_t src[8]; + uint8_t len; + struct tagReturnData returnData; +} __attribute__((packed, aligned(1))); + +#endif diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/radio.c b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/radio.c new file mode 100644 index 00000000..e919b5f4 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/radio.c @@ -0,0 +1,150 @@ +#include +#include "radio.h" +#include "driver/gpio.h" +#include "driver/uart.h" +#include "esp_err.h" +#include "esp_event.h" +#include "esp_ieee802154.h" +#include "esp_log.h" +#include "esp_phy_init.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "led.h" +#include "main.h" +#include "proto.h" +#include "sdkconfig.h" +// if you get an error about soc/lp_uart_reg.h not being found, +// you didn't choose the right build target. :-) +//#include "soc/lp_uart_reg.h" +#include "soc/uart_struct.h" +#include "utils.h" +#include +#include +#include +#include +#include "SubGigRadio.h" + + +static const char *TAG = "RADIO"; + +uint8_t mSelfMac[8]; +volatile uint8_t isInTransmit = 0; +QueueHandle_t packet_buffer = NULL; +void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info) { + ESP_EARLY_LOGI(TAG, "RX %d", frame[0]); + BaseType_t xHigherPriorityTaskWoken; + static uint8_t inner_rxPKT[130]; + memcpy(inner_rxPKT, &frame[0], frame[0] + 1); + xQueueSendFromISR(packet_buffer, (void *)&inner_rxPKT, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken); + esp_ieee802154_receive_sfd_done(); +} + +void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) { + isInTransmit = 0; + ESP_EARLY_LOGE(TAG, "TX Err: %d", error); +} + +void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info) { + isInTransmit = 0; + ESP_EARLY_LOGI(TAG, "TX %d", frame[0]); + esp_ieee802154_receive_sfd_done(); +} +static bool zigbee_is_enabled = false; +void radio_init(uint8_t ch) { + if (packet_buffer == NULL) packet_buffer = xQueueCreate(32, 130); + + // this will trigger a "IEEE802154 MAC sleep init failed" when called a second time, but it works + if(zigbee_is_enabled) + { + zigbee_is_enabled = false; + esp_ieee802154_disable(); + } + zigbee_is_enabled = true; + esp_ieee802154_enable(); + esp_ieee802154_set_channel(ch); + // esp_ieee802154_set_txpower(int8_t power); + esp_ieee802154_set_panid(PROTO_PAN_ID); + esp_ieee802154_set_promiscuous(false); + esp_ieee802154_set_coordinator(false); + esp_ieee802154_set_pending_mode(ESP_IEEE802154_AUTO_PENDING_ZIGBEE); + + // esp_ieee802154_set_extended_address needs the MAC in reversed byte order + esp_read_mac(mSelfMac, ESP_MAC_IEEE802154); + uint8_t eui64_rev[8] = {0}; + for (int i = 0; i < 8; i++) { + eui64_rev[7 - i] = mSelfMac[i]; + } + esp_ieee802154_set_extended_address(eui64_rev); + esp_ieee802154_get_extended_address(mSelfMac); + + esp_ieee802154_set_short_address(0xFFFE); + esp_ieee802154_set_rx_when_idle(true); + esp_ieee802154_receive(); + + led_flash(1); + vTaskDelay(100 / portTICK_PERIOD_MS); + led_flash(0); + vTaskDelay(100 / portTICK_PERIOD_MS); + led_flash(1); + vTaskDelay(100 / portTICK_PERIOD_MS); + led_flash(0); + + ESP_LOGI(TAG, "Receiver ready, panId=0x%04x, channel=%d, long=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, short=%04x", + esp_ieee802154_get_panid(), esp_ieee802154_get_channel(), + mSelfMac[0], mSelfMac[1], mSelfMac[2], mSelfMac[3], + mSelfMac[4], mSelfMac[5], mSelfMac[6], mSelfMac[7], + esp_ieee802154_get_short_address()); +} + +// uint32_t lastZbTx = 0; +bool radioTx(uint8_t *packet) { +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT +// The subghz driver uses DMA + static DMA_ATTR uint8_t txPKT[130]; +#else + static uint8_t txPKT[130]; +#endif + led_flash(1); + // while (getMillis() - lastZbTx < 6) { + // } + // lastZbTx = getMillis(); + memcpy(txPKT, packet, packet[0]); +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + struct MacFrameNormal *txHeader = (struct MacFrameNormal *) (packet + 1); + + if(txHeader->pan == PROTO_PAN_ID_SUBGHZ) { + return SubGig_radioTx(packet); + } +#endif + while (isInTransmit) { + } + isInTransmit = 1; + esp_ieee802154_transmit(txPKT, false); + return true; +} + +void radioSetChannel(uint8_t ch) { + radio_init(ch); +} + +void radioSetTxPower(uint8_t power) {} + +int8_t commsRxUnencrypted(uint8_t *data) { + static uint8_t inner_rxPKT_out[130]; + if (xQueueReceive(packet_buffer, (void *)&inner_rxPKT_out, pdMS_TO_TICKS(100)) == pdTRUE) { + memcpy(data, &inner_rxPKT_out[1], inner_rxPKT_out[0] + 1); + return inner_rxPKT_out[0] - 2; + } +#ifdef CONFIG_OEPL_SUBGIG_SUPPORT + if(gSubGigData.Enabled) { + int8_t Ret = SubGig_commsRxUnencrypted(data); + if(Ret > 0) { + return Ret; + } + } +#endif + return 0; +} diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/radio.h b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/radio.h new file mode 100644 index 00000000..6bd55d42 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/radio.h @@ -0,0 +1,20 @@ +#pragma once +#include +#include + +#define RAW_PKT_PADDING 2 +extern uint8_t mSelfMac[8]; + +void radio_init(uint8_t ch); +bool radioTx(uint8_t *packet); +void radioSetChannel(uint8_t ch); +void radioSetTxPower(uint8_t power); +int8_t commsRxUnencrypted(uint8_t *data); + +#ifdef SUBGIG_SUPPORT +void SubGig_radio_init(uint8_t ch); +bool SubGig_radioTx(uint8_t *packet); +void SubGig_radioSetChannel(uint8_t ch); +void SubGig_radioSetTxPower(uint8_t power); +int8_t SubGig_commsRxUnencrypted(uint8_t *data); +#endif \ No newline at end of file diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/second_uart.c b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/second_uart.c new file mode 100644 index 00000000..6bb109c6 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/second_uart.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include "driver/gpio.h" +#include "driver/uart.h" +#include "esp_err.h" +#include "esp_event.h" +#include "esp_ieee802154.h" +#include "esp_log.h" +#include "esp_phy_init.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "main.h" +#include "nvs.h" +#include "nvs_flash.h" +#include "proto.h" +#include "sdkconfig.h" +#include "soc/uart_struct.h" +//#include "soc/lp_uart_reg.h" +#include "second_uart.h" + +//static const char *TAG = "SECOND_UART"; + +#define BUF_SIZE (1024) +#define RD_BUF_SIZE (BUF_SIZE) +static QueueHandle_t uart0_queue; + +#define MAX_BUFF_POS 8000 +volatile int curr_buff_pos = 0; +volatile int worked_buff_pos = 0; +volatile uint8_t buff_pos[MAX_BUFF_POS + 5]; + +static void uart_event_task(void *pvParameters); +void init_second_uart() { + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + }; + ESP_ERROR_CHECK(uart_driver_install(1, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0)); + ESP_ERROR_CHECK(uart_param_config(1, &uart_config)); + ESP_ERROR_CHECK(uart_set_pin(1, CONFIG_OEPL_HARDWARE_UART_TX, CONFIG_OEPL_HARDWARE_UART_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + xTaskCreate(uart_event_task, "uart_event_task", 16384, NULL, 12, NULL); +} + +void uart_switch_speed(int baudrate) { + uart_config_t uart_config = { + .baud_rate = baudrate, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + }; + ESP_ERROR_CHECK(uart_param_config(1, &uart_config)); +} + +void uartTx(uint8_t data) { uart_write_bytes(1, (const char *) &data, 1); } + + +bool getRxCharSecond(uint8_t *newChar) { + if (curr_buff_pos != worked_buff_pos) { + *newChar = buff_pos[worked_buff_pos]; + worked_buff_pos++; + worked_buff_pos %= MAX_BUFF_POS; + return true; + } + return false; +} + +static void uart_event_task(void *pvParameters) { + uart_event_t event; + uint8_t *dtmp = (uint8_t *) malloc(RD_BUF_SIZE); + for (;;) { + if (xQueueReceive(uart0_queue, (void *) &event, (TickType_t) portMAX_DELAY)) { + bzero(dtmp, RD_BUF_SIZE); + switch (event.type) { + case UART_DATA: + uart_read_bytes(1, dtmp, event.size, portMAX_DELAY); + for (int i = 0; i < event.size; i++) { + buff_pos[curr_buff_pos] = dtmp[i]; + curr_buff_pos++; + curr_buff_pos %= MAX_BUFF_POS; + } + break; + default: + // ESP_LOGI(TAG, "uart event type: %d", event.type); + break; + } + } + } + free(dtmp); + dtmp = NULL; + vTaskDelete(NULL); +} + +void uart_printf(const char *format, ...) { + va_list args; + va_start(args, format); + + char buffer[128]; + int len = vsnprintf(buffer, sizeof(buffer), format, args); + + va_end(args); + + if (len > 0) { + uart_write_bytes(1, buffer, len); + } +} \ No newline at end of file diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/second_uart.h b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/second_uart.h new file mode 100644 index 00000000..48e5698a --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/second_uart.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +void init_second_uart(); +void uart_switch_speed(int baudrate); + +void uartTx(uint8_t data); +bool getRxCharSecond(uint8_t *newChar); + +void uart_printf(const char *format, ...); + +#define pr uart_printf + + + + #define CONFIG_OEPL_HARDWARE_UART_TX 24 + #define CONFIG_OEPL_HARDWARE_UART_RX 23 diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/utils.c b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/utils.c new file mode 100644 index 00000000..5771ccf5 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/utils.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include "driver/gpio.h" +#include "driver/uart.h" +#include "esp_err.h" +#include "esp_event.h" +#include "esp_ieee802154.h" +#include "esp_log.h" +#include "esp_phy_init.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "main.h" +#include "proto.h" +#include "sdkconfig.h" +#include "soc/uart_struct.h" +//#include "soc/lp_uart_reg.h" +#include "nvs_flash.h" + +void delay(int ms) { vTaskDelay(pdMS_TO_TICKS(ms)); } + +uint32_t getMillis() { return (uint32_t) (esp_timer_get_time() / 1000); } + +void init_nvs() +{ + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK( ret ); +} \ No newline at end of file diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/utils.h b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/utils.h new file mode 100644 index 00000000..7109b160 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/main/utils.h @@ -0,0 +1,5 @@ +#pragma once + +void delay(int ms); +uint32_t getMillis(); +void init_nvs(); \ No newline at end of file diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/partitions.csv b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/partitions.csv new file mode 100644 index 00000000..40643958 --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/partitions.csv @@ -0,0 +1,5 @@ +# ESP-IDF Partition Table +# Name, Type, SubType, Offset, Size, Flags +nvs,data,nvs,0x9000,0x6000,, +factory,app,factory,0x10000,1M,, +littlefs,data,spiffs,,3008K,, diff --git a/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/sdkconfig.defaults b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/sdkconfig.defaults new file mode 100644 index 00000000..717f35ea --- /dev/null +++ b/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/sdkconfig.defaults @@ -0,0 +1,8 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32h2" +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y +CONFIG_PARTITION_TABLE_CUSTOM=y diff --git a/ESP32_AP-Flasher/compile.ps1 b/ESP32_AP-Flasher/compile.ps1 new file mode 100644 index 00000000..e571dabb --- /dev/null +++ b/ESP32_AP-Flasher/compile.ps1 @@ -0,0 +1,76 @@ + +#| Function | ESP32H2 Pin | ESP32S3 Pin +#| :--------------------------------: | :-------------------: | :------------------ +#| Activate The BOOT Mode Of ESP32H2 | ESP32H2_IO9 | ESP32S3_IO33 +#| Reset ESP32H2 | ESP32H2_Pin Number 8 | ESP32S3_IO34 +#| Uart | ESP32H2_TX_IO24 | ESP32S3_RX_IO48 +#| Uart | ESP32H2_RX_IO23 | ESP32S3_TX_IO47 + +# cd ESP32_AP-Flasher + +# export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA" + +python gzip_wwwfiles.py + +&(Join-Path $env:USERPROFILE '\.platformio\penv\Scripts\pio') run --environment ESP32_S3_16_8_LILYGO_AP + +&(Join-Path $env:USERPROFILE '\.platformio\penv\Scripts\pio') run --target buildfs --environment ESP32_S3_16_8_LILYGO_AP + +# mkdir ESP32_S3_16_8_LILYGO_AP + +copy "$env:USERPROFILE\.platformio\packages\framework-arduinoespressif32\tools\partitions\boot_app0.bin" ESP32_S3_16_8_LILYGO_AP\boot_app0.bin + +copy .pio\build\ESP32_S3_16_8_LILYGO_AP\firmware.bin ESP32_S3_16_8_LILYGO_AP\firmware.bin + +copy .pio\build\ESP32_S3_16_8_LILYGO_AP\bootloader.bin ESP32_S3_16_8_LILYGO_AP\bootloader.bin + +copy .pio\build\ESP32_S3_16_8_LILYGO_AP\partitions.bin ESP32_S3_16_8_LILYGO_AP\partitions.bin + +copy .pio\build\ESP32_S3_16_8_LILYGO_AP\littlefs.bin ESP32_S3_16_8_LILYGO_AP\littlefs.bin + +copy ESP32_S3_16_8_LILYGO_AP\firmware.bin espbinaries\ESP32_S3_16_8_LILYGO_AP.bin + +copy ESP32_S3_16_8_LILYGO_AP\merged-firmware.bin espbinaries\ESP32_S3_16_8_LILYGO_AP_full.bin + +cd ESP32_S3_16_8_LILYGO_AP + +#python -m esptool --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 16MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x00910000 littlefs.bin + +#python -m esptool -p COM12 -b 460800 --before default_reset --after hard_reset --chip esp32s3 write_flash --flash_mode dio --flash_size detect 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x00910000 littlefs.bin + +cd .. + +#esptool.py v4.7.0 +#Serial port COM12 +#Connecting... +#Chip is ESP32-S3 (QFN56) (revision v0.2) +#Features: WiFi, BLE +#Crystal is 40MHz +#MAC: f4:12:fa:af:5b:9c +#Uploading stub... +#Running stub... +#Stub running... +#Changing baud rate to 460800 +#Changed. +#Configuring flash size... +#Auto-detected Flash size: 16MB +#Flash will be erased from 0x00000000 to 0x00003fff... +#Flash will be erased from 0x00008000 to 0x00008fff... +#Flash will be erased from 0x0000e000 to 0x0000ffff... +#Flash will be erased from 0x00010000 to 0x00203fff... +#Flash will be erased from 0x00910000 to 0x00feffff... +#Compressed 15104 bytes to 10401... +#Wrote 15104 bytes (10401 compressed) at 0x00000000 in 0.3 seconds (effective 375.1 kbit/s)... +#Hash of data verified. +#Compressed 3072 bytes to 146... +#Wrote 3072 bytes (146 compressed) at 0x00008000 in 0.1 seconds (effective 272.1 kbit/s)... +#Hash of data verified. +#Compressed 8192 bytes to 47... +#Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.1 seconds (effective 447.3 kbit/s)... +#Hash of data verified. +#Compressed 2047040 bytes to 1259376... +#Wrote 2047040 bytes (1259376 compressed) at 0x00010000 in 18.7 seconds (effective 876.9 kbit/s)... +#Hash of data verified. +#Compressed 7208960 bytes to 302805... +#Wrote 7208960 bytes (302805 compressed) at 0x00910000 in 47.0 seconds (effective 1227.2 kbit/s)... +#Hash of data verified. diff --git a/ESP32_AP-Flasher/compileyellow.ps1 b/ESP32_AP-Flasher/compileyellow.ps1 new file mode 100644 index 00000000..20065dab --- /dev/null +++ b/ESP32_AP-Flasher/compileyellow.ps1 @@ -0,0 +1,69 @@ +# cd ESP32_AP-Flasher + +# export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA" + +python gzip_wwwfiles.py + +&(Join-Path $env:USERPROFILE '\.platformio\penv\Scripts\pio') run --environment ESP32_S3_16_8_YELLOW_AP + +&(Join-Path $env:USERPROFILE '\.platformio\penv\Scripts\pio') run --target buildfs --environment ESP32_S3_16_8_YELLOW_AP + +# mkdir ESP32_S3_16_8_YELLOW_AP + +copy "$env:USERPROFILE\.platformio\packages\framework-arduinoespressif32\tools\partitions\boot_app0.bin" ESP32_S3_16_8_YELLOW_AP\boot_app0.bin + +copy .pio\build\ESP32_S3_16_8_YELLOW_AP\firmware.bin ESP32_S3_16_8_YELLOW_AP\firmware.bin + +copy .pio\build\ESP32_S3_16_8_YELLOW_AP\bootloader.bin ESP32_S3_16_8_YELLOW_AP\bootloader.bin + +copy .pio\build\ESP32_S3_16_8_YELLOW_AP\partitions.bin ESP32_S3_16_8_YELLOW_AP\partitions.bin + +copy .pio\build\ESP32_S3_16_8_YELLOW_AP\littlefs.bin ESP32_S3_16_8_YELLOW_AP\littlefs.bin + +copy ESP32_S3_16_8_YELLOW_AP\firmware.bin espbinaries\ESP32_S3_16_8_YELLOW_AP.bin + +copy ESP32_S3_16_8_YELLOW_AP\merged-firmware.bin espbinaries\ESP32_S3_16_8_YELLOW_AP_full.bin + +cd ESP32_S3_16_8_YELLOW_AP + +#python -m esptool --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 16MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x00910000 littlefs.bin + +#python -m esptool -p COM4 -b 460800 --before default_reset --after hard_reset --chip esp32s3 write_flash --flash_mode dio --flash_size detect 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x00910000 littlefs.bin + +cd .. + +#esptool.py v4.7.0 +#Serial port COM4 +#Connecting... +#Chip is ESP32-S3 (QFN56) (revision v0.2) +#Features: WiFi, BLE, Embedded PSRAM 8MB (AP_3v3) +#Crystal is 40MHz +#MAC: dc:da:0c:16:cf:4c +#Uploading stub... +#Running stub... +#Stub running... +#Changing baud rate to 460800 +#Changed. +#Configuring flash size... +#Auto-detected Flash size: 16MB +#Flash will be erased from 0x00000000 to 0x00003fff... +#Flash will be erased from 0x00008000 to 0x00008fff... +#Flash will be erased from 0x0000e000 to 0x0000ffff... +#Flash will be erased from 0x00010000 to 0x001dbfff... +#Flash will be erased from 0x00910000 to 0x00feffff... +#Compressed 15104 bytes to 10401... +#Wrote 15104 bytes (10401 compressed) at 0x00000000 in 0.4 seconds (effective 277.3 kbit/s)... +#Hash of data verified. +#Compressed 3072 bytes to 146... +#Wrote 3072 bytes (146 compressed) at 0x00008000 in 0.1 seconds (effective 425.0 kbit/s)... +#Hash of data verified. +#Compressed 8192 bytes to 47... +#Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.1 seconds (effective 632.5 kbit/s)... +#Hash of data verified. +#Compressed 1881424 bytes to 1196500... +#Wrote 1881424 bytes (1196500 compressed) at 0x00010000 in 27.6 seconds (effective 544.8 kbit/s)... +#Hash of data verified. +#Compressed 7208960 bytes to 302804... +#Wrote 7208960 bytes (302804 compressed) at 0x00910000 in 35.0 seconds (effective 1648.8 kbit/s)... +#Hash of data verified. + diff --git a/ESP32_AP-Flasher/data/tagtypes/E2.json b/ESP32_AP-Flasher/data/tagtypes/E2.json new file mode 100644 index 00000000..591ce03b --- /dev/null +++ b/ESP32_AP-Flasher/data/tagtypes/E2.json @@ -0,0 +1,64 @@ +{ + "version": 1, + "name": "LILYGO TPANEL 4\"", + "width": 480, + "height": 480, + "rotatebuffer": 0, + "bpp": 16, + "colortable": { + "white": [ 255, 255, 255 ], + "black": [ 0, 0, 0 ], + "red": [ 255, 0, 0 ] + }, + "shortlut": 0, + "options": [ ], + "contentids": [ 22, 1, 2, 3, 4, 8, 7, 19, 10, 11, 21 ], + "template": { + "21": [ + { "box": [ 0, 0, 480, 480, 1 ] }, + { "text": [ 10, 15, "OpenEpaperLink AP", "calibrib30", 2, 0, 0, 1 ] }, + { "text": [ 10, 70, "IP address:", "bahnschrift30", "#888888", 0, 0, 1 ] }, + { "text": [ 180, 70, "{ap_ip}", "bahnschrift30", 0, 0, 0, 1 ] }, + { "text": [ 10, 110, "Channel:", "bahnschrift30", "#888888", 0, 0, 1 ] }, + { "text": [ 180, 110, "{ap_ch}", "bahnschrift30", 0, 0, 0, "1" ] }, + { "text": [ 10, 150, "Tag count:", "bahnschrift30", "#888888", 0, 0, 1 ] }, + { "text": [ 180, 150, "{ap_tagcount}", "bahnschrift30", 0, 0, 0, "1" ] } + ], + "1": { + "weekday": [ 240, 30, "Signika-SB.ttf", 90 ], + "month": [ 240, 330, "Signika-SB.ttf", 90 ], + "day": [ 240, 80, "Signika-SB.ttf", 250 ] + }, + "4": { + "location": [ 20, 20, "fonts/calibrib30" ], + "wind": [ 90, 95, "fonts/calibrib50" ], + "temp": [ 20, 200, "fonts/calibrib100" ], + "icon": [ 400, 30, 150, 2 ], + "dir": [ 40, 70, 80 ], + "umbrella": [ 325, 250, 150 ] + }, + "2": { + "fonts": [ "Signika-SB.ttf", 150, 150, 110, 80, 60, 50 ], + "xy": [ 240, 240 ] + }, + "8": { + "location": [ 10, 20, "fonts/calibrib50" ], + "column": [ 6, 80 ], + "day": [ 40, 100, "fonts/bahnschrift30", 144, 270 ], + "rain": [ 40, 320 ], + "icon": [ 40, 180, 50 ], + "wind": [ 17, 120 ], + "line": [ 100, 340 ] + }, + "10": { + "title": [ 240, 10, "fonts/bahnschrift20" ], + "pos": [ 240, 35 ] + }, + "11": { + "rotate": 0, + "mode": 1, + "days": 4, + "gridparam": [ 5, 17, 20, "calibrib16.vlw", "tahoma9.vlw", 14 ] + } + } +} diff --git a/ESP32_AP-Flasher/data/www/content_cards.json.gz b/ESP32_AP-Flasher/data/www/content_cards.json.gz index 050d8291..4bb80d90 100644 Binary files a/ESP32_AP-Flasher/data/www/content_cards.json.gz and b/ESP32_AP-Flasher/data/www/content_cards.json.gz differ diff --git a/ESP32_AP-Flasher/data/www/flash.js.gz b/ESP32_AP-Flasher/data/www/flash.js.gz index 572e6792..59348f32 100644 Binary files a/ESP32_AP-Flasher/data/www/flash.js.gz and b/ESP32_AP-Flasher/data/www/flash.js.gz differ diff --git a/ESP32_AP-Flasher/data/www/index.html.gz b/ESP32_AP-Flasher/data/www/index.html.gz index 7b5cd87d..415955f6 100644 Binary files a/ESP32_AP-Flasher/data/www/index.html.gz and b/ESP32_AP-Flasher/data/www/index.html.gz differ diff --git a/ESP32_AP-Flasher/data/www/jsontemplate-demo.html.gz b/ESP32_AP-Flasher/data/www/jsontemplate-demo.html.gz index 0d7ef3ce..ce0f8439 100644 Binary files a/ESP32_AP-Flasher/data/www/jsontemplate-demo.html.gz and b/ESP32_AP-Flasher/data/www/jsontemplate-demo.html.gz differ diff --git a/ESP32_AP-Flasher/data/www/main.js.gz b/ESP32_AP-Flasher/data/www/main.js.gz index bc957f57..67d0ee08 100644 Binary files a/ESP32_AP-Flasher/data/www/main.js.gz and b/ESP32_AP-Flasher/data/www/main.js.gz differ diff --git a/ESP32_AP-Flasher/data/www/ota.js.gz b/ESP32_AP-Flasher/data/www/ota.js.gz index 96ae51fd..18cabc8e 100644 Binary files a/ESP32_AP-Flasher/data/www/ota.js.gz and b/ESP32_AP-Flasher/data/www/ota.js.gz differ diff --git a/ESP32_AP-Flasher/include/ips_display.h b/ESP32_AP-Flasher/include/ips_display.h index e373e2d1..7401b026 100644 --- a/ESP32_AP-Flasher/include/ips_display.h +++ b/ESP32_AP-Flasher/include/ips_display.h @@ -1,6 +1,98 @@ +#pragma once + #include #include +#ifdef HAS_LILYGO_TPANEL + +#define LV_ATTRIBUTE_TICK_INC IRAM_ATTR +#define TOUCH_MODULES_CST_MUTUAL + +// SD +#define SD_CS 38 +#define SD_SCLK 36 +#define SD_MOSI 35 +#define SD_MISO 37 + +// IIC +#define IIC_SDA 17 +#define IIC_SCL 18 + +// ESP32H2 +#define ESP32H2_TX 48 +#define ESP32H2_RX 47 + +// #define T_Panel_V1_0_RS485 + #define T_Panel_V1_2_RS485 +// #define T_Panel_V1_2_CAN + +#if defined T_Panel_V1_0_RS485 +#define RS485_TX 15 +#define RS485_RX 16 +#endif + +#if defined T_Panel_V1_2_RS485 +#define RS485_TX 16 +#define RS485_RX 15 +#endif + +#if defined T_Panel_V1_2_CAN +#define CAN_TX 16 +#define CAN_RX 15 +#endif + +// YDP395BT001-V2 +#define LCD_WIDTH 480 +#define LCD_HEIGHT 480 +#define LCD_VSYNC 40 +#define LCD_HSYNC 39 +#define LCD_PCLK 41 +#define LCD_B0 1 +#define LCD_B1 2 +#define LCD_B2 3 +#define LCD_B3 4 +#define LCD_B4 5 +#define LCD_G0 6 +#define LCD_G1 7 +#define LCD_G2 8 +#define LCD_G3 9 +#define LCD_G4 10 +#define LCD_G5 11 +#define LCD_R0 12 +#define LCD_R1 13 +#define LCD_R2 42 +#define LCD_R3 46 +#define LCD_R4 45 +#define LCD_BL 14 + +// CST3240 +#define CST3240_ADDRESS 0x5A +#define TOUCH_SDA 17 +#define TOUCH_SCL 18 +#define TOUCH_INT 21 +#define TOUCH_RST 4 + +// XL95x5 +#define XL95X5_CS 17 +#define XL95X5_SCLK 15 +#define XL95X5_MOSI 16 +#define XL95X5_TOUCH_RST 4 +#define XL95X5_RS485_CON 7 +#define XL95X5_LCD_RST 5 +#define XL95X5_ESP32H2_IO12 1 +#define XL95X5_ESP32H2_IO4 2 +#define XL95X5_ESP32H2_IO5 3 + +// ESP32H2 +#define ESP32H2_EN 34 +#define ESP32H2_BOOT 33 + +#include "Arduino_GFX_Library.h" + +extern Arduino_RGB_Display *gfx; + +#endif + #ifdef HAS_TFT extern TFT_eSPI tft2; @@ -10,4 +102,4 @@ extern bool tftOverride; void TFTLog(String text); void sendAvail(uint8_t wakeupReason); -#endif +#endif \ No newline at end of file diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_DataBus.cpp b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_DataBus.cpp new file mode 100644 index 00000000..5460f872 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_DataBus.cpp @@ -0,0 +1,167 @@ +/* + * start rewrite from: + * https://github.com/adafruit/Adafruit-GFX-Library.git + */ +#include "Arduino_DataBus.h" + +Arduino_DataBus::Arduino_DataBus() {} + +void Arduino_DataBus::writeC8D8(uint8_t c, uint8_t d) +{ + writeCommand(c); + write(d); +} + +void Arduino_DataBus::writeC8D16(uint8_t c, uint16_t d) +{ + writeCommand(c); + write16(d); +} + +void Arduino_DataBus::writeC16D16(uint16_t c, uint16_t d) +{ + writeCommand16(c); + write16(d); +} + +void Arduino_DataBus::writeC8D16D16(uint8_t c, uint16_t d1, uint16_t d2) +{ + writeCommand(c); + write16(d1); + write16(d2); +} + +void Arduino_DataBus::writeC8D16D16Split(uint8_t c, uint16_t d1, uint16_t d2) +{ + writeCommand(c); + _data16.value = d1; + write(_data16.msb); + write(_data16.lsb); + _data16.value = d2; + write(_data16.msb); + write(_data16.lsb); +} + +void Arduino_DataBus::sendCommand(uint8_t c) +{ + beginWrite(); + writeCommand(c); + endWrite(); +} + +void Arduino_DataBus::sendCommand16(uint16_t c) +{ + beginWrite(); + writeCommand16(c); + endWrite(); +} + +void Arduino_DataBus::sendData(uint8_t d) +{ + beginWrite(); + write(d); + endWrite(); +} + +void Arduino_DataBus::sendData16(uint16_t d) +{ + beginWrite(); + write16(d); + endWrite(); +} + +void Arduino_DataBus::batchOperation(const uint8_t *operations, size_t len) +{ + for (size_t i = 0; i < len; ++i) + { + uint8_t l = 0; + switch (operations[i]) + { + case BEGIN_WRITE: + beginWrite(); + break; + case WRITE_C8_D16: + writeCommand(operations[++i]); + l = 2; + break; + case WRITE_C8_D8: + writeC8D8(operations[++i], operations[++i]); + break; + case WRITE_COMMAND_8: + writeCommand(operations[++i]); + break; + case WRITE_C16_D16: + + break; + case WRITE_COMMAND_16: + + break; + case WRITE_DATA_8: + l = 1; + break; + case WRITE_DATA_16: + l = 2; + break; + case WRITE_BYTES: + l = operations[++i]; + break; + case END_WRITE: + endWrite(); + break; + case DELAY: + delay(operations[++i]); + break; + default: + printf("Unknown operation id at %d: %d", i, operations[i]); + break; + } + while (l--) + { + write(operations[++i]); + } + } +} + +#if !defined(LITTLE_FOOT_PRINT) +void Arduino_DataBus::writePattern(uint8_t *data, uint8_t len, uint32_t repeat) +{ + while (repeat--) + { + writeBytes(data, len); + } +} + +void Arduino_DataBus::writeIndexedPixels(uint8_t *data, uint16_t *idx, uint32_t len) +{ + while (len--) + { + write16(idx[*(data++)]); + } +} + +void Arduino_DataBus::writeIndexedPixelsDouble(uint8_t *data, uint16_t *idx, uint32_t len) +{ + uint8_t *d = data; + while (len--) + { + _data16.value = idx[*(d++)]; + write(_data16.msb); + write(_data16.lsb); + write(_data16.msb); + write(_data16.lsb); + } +} +#endif // !defined(LITTLE_FOOT_PRINT) + +void Arduino_DataBus::pinMode(uint8_t pin, uint8_t mode) +{ +} + +void Arduino_DataBus::digitalWrite(uint8_t pin, uint8_t val) +{ +} + +int Arduino_DataBus::digitalRead(uint8_t pin) +{ +} + diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_DataBus.h b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_DataBus.h new file mode 100644 index 00000000..7038c2c8 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_DataBus.h @@ -0,0 +1,293 @@ +/* + * start rewrite from: + * https://github.com/adafruit/Adafruit-GFX-Library.git + */ +#ifndef _ARDUINO_DATABUS_H_ +#define _ARDUINO_DATABUS_H_ + +#include + +#define GFX_SKIP_OUTPUT_BEGIN -2 +#define GFX_NOT_DEFINED -1 +#define GFX_STR_HELPER(x) #x +#define GFX_STR(x) GFX_STR_HELPER(x) + +#if defined(__AVR__) +#define LITTLE_FOOT_PRINT // reduce program size for limited flash MCU +#define USE_FAST_PINIO ///< Use direct PORT register access +typedef uint8_t ARDUINOGFX_PORT_t; +#elif defined(ARDUINO_ARCH_NRF52840) +#define USE_FAST_PINIO ///< Use direct PORT register access +#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers +typedef uint32_t ARDUINOGFX_PORT_t; +#elif defined(TARGET_RP2040) +#define USE_FAST_PINIO ///< Use direct PORT register access +#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers +typedef uint32_t ARDUINOGFX_PORT_t; +#elif defined(ESP32) +#define USE_FAST_PINIO ///< Use direct PORT register access +#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers +typedef uint32_t ARDUINOGFX_PORT_t; +#elif defined(ESP8266) +#define ESP8266SAFEBATCHBITSIZE (2048 * 8 * 9) +#define USE_FAST_PINIO ///< Use direct PORT register access +typedef uint32_t ARDUINOGFX_PORT_t; +#elif defined(ARDUINO_ARCH_STM32) +#define USE_FAST_PINIO ///< Use direct PORT register access +typedef uint32_t ARDUINOGFX_PORT_t; +#elif defined(__arm__) +#if defined(ARDUINO_ARCH_SAMD) +// Adafruit M0, M4 +#define USE_FAST_PINIO ///< Use direct PORT register access +#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers +typedef uint32_t ARDUINOGFX_PORT_t; +#elif defined(CONFIG_ARCH_CHIP_CXD56XX) // Sony Spresense +#define USE_FAST_PINIO ///< Use direct PORT register access +typedef uint8_t ARDUINOGFX_PORT_t; +#elif defined(RTL8722DM) +#define USE_FAST_PINIO ///< Use direct PORT register access +typedef uint32_t ARDUINOGFX_PORT_t; +#elif defined(CORE_TEENSY) +#define USE_FAST_PINIO ///< Use direct PORT register access +#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers +#if defined(__IMXRT1052__) || defined(__IMXRT1062__) +// PJRC Teensy 4.x +typedef uint32_t ARDUINOGFX_PORT_t; +#else +// PJRC Teensy 3.x +typedef uint8_t ARDUINOGFX_PORT_t; +#endif +#else +// Arduino Due? +// USE_FAST_PINIO not available here (yet)...Due has a totally different +// GPIO register set and will require some changes elsewhere (e.g. in +// constructors especially). +#endif +#else // !ARM +// Unknow architecture, USE_FAST_PINIO is not available here (yet) +// but don't worry about it too much...the digitalWrite() implementation +// on these platforms is reasonably efficient and already RAM-resident, +// only gotcha then is no parallel connection support for now. +#endif // !ARM + +#ifdef USE_FAST_PINIO +typedef volatile ARDUINOGFX_PORT_t *PORTreg_t; +#endif + +#if defined(ARDUINO_ARCH_ARC32) || defined(ARDUINO_MAXIM) +#define SPI_DEFAULT_FREQ 16000000 +// Teensy 3.0, 3.1/3.2, 3.5, 3.6 +#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) +#define SPI_DEFAULT_FREQ 40000000 +// Teensy 4.x +#elif defined(__IMXRT1052__) || defined(__IMXRT1062__) +#define SPI_DEFAULT_FREQ 40000000 +#elif defined(__AVR__) || defined(TEENSYDUINO) +#define SPI_DEFAULT_FREQ 8000000 +#elif defined(ARDUINO_ARCH_NRF52840) +#define SPI_DEFAULT_FREQ 8000000 +#elif defined(ESP8266) || defined(ESP32) +#define SPI_DEFAULT_FREQ 40000000 +#elif defined(RTL8722DM) +#define SPI_DEFAULT_FREQ 20000000 +#elif defined(RASPI) +#define SPI_DEFAULT_FREQ 80000000 +#elif defined(ARDUINO_ARCH_STM32F1) +#define SPI_DEFAULT_FREQ 36000000 +#elif defined(ARDUINO_BLACKPILL_F411CE) +#define SPI_DEFAULT_FREQ 50000000 +#elif defined(F_CPU) +#define SPI_DEFAULT_FREQ (F_CPU / 4) +#else +#define SPI_DEFAULT_FREQ 24000000 ///< Default SPI data clock frequency +#endif + +#ifndef UNUSED +#define UNUSED(x) (void)(x) +#endif +#define ATTR_UNUSED __attribute__((unused)) + +#define MSB_16(val) (((val)&0xFF00) >> 8) | (((val)&0xFF) << 8) +#define MSB_16_SET(var, val) \ + { \ + (var) = MSB_16(val); \ + } +#define MSB_32_SET(var, val) \ + { \ + uint8_t *v = (uint8_t *)&(val); \ + (var) = v[3] | (v[2] << 8) | (v[1] << 16) | (v[0] << 24); \ + } +#define MSB_32_16_16_SET(var, v1, v2) \ + { \ + (var) = (((uint32_t)v2 & 0xff00) << 8) | (((uint32_t)v2 & 0xff) << 24) | ((v1 & 0xff00) >> 8) | ((v1 & 0xff) << 8); \ + } +#define MSB_32_8_ARRAY_SET(var, a) \ + { \ + (var) = ((uint32_t)a[0] << 8 | a[1] | a[2] << 24 | a[3] << 16); \ + } + +#if defined(ESP32) +#define INLINE __attribute__((always_inline)) inline +#else +#define INLINE inline +#endif + +#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct esp_lcd_i80_bus_t esp_lcd_i80_bus_t; +typedef struct lcd_panel_io_i80_t lcd_panel_io_i80_t; +typedef struct lcd_i80_trans_descriptor_t lcd_i80_trans_descriptor_t; + +struct esp_lcd_i80_bus_t +{ + int bus_id; // Bus ID, index from 0 + portMUX_TYPE spinlock; // spinlock used to protect i80 bus members(hal, device_list, cur_trans) + lcd_hal_context_t hal; // Hal object + size_t bus_width; // Number of data lines + intr_handle_t intr; // LCD peripheral interrupt handle + esp_pm_lock_handle_t pm_lock; // Power management lock + size_t num_dma_nodes; // Number of DMA descriptors + uint8_t *format_buffer; // The driver allocates an internal buffer for DMA to do data format transformer + size_t resolution_hz; // LCD_CLK resolution, determined by selected clock source + gdma_channel_handle_t dma_chan; // DMA channel handle + size_t psram_trans_align; // DMA transfer alignment for data allocated from PSRAM + size_t sram_trans_align; // DMA transfer alignment for data allocated from SRAM + lcd_i80_trans_descriptor_t *cur_trans; // Current transaction + lcd_panel_io_i80_t *cur_device; // Current working device + LIST_HEAD(i80_device_list, lcd_panel_io_i80_t) + device_list; // Head of i80 device list + struct + { + unsigned int exclusive : 1; // Indicate whether the I80 bus is owned by one device (whose CS GPIO is not assigned) exclusively + } flags; + dma_descriptor_t dma_nodes[]; // DMA descriptor pool, the descriptors are shared by all i80 devices +}; + +struct lcd_i80_trans_descriptor_t +{ + lcd_panel_io_i80_t *i80_device; // i80 device issuing this transaction + int cmd_value; // Command value + uint32_t cmd_cycles; // Command cycles + const void *data; // Data buffer + uint32_t data_length; // Data buffer size + void *user_ctx; // private data used by trans_done_cb + esp_lcd_panel_io_color_trans_done_cb_t trans_done_cb; // transaction done callback +}; + +struct lcd_panel_io_i80_t +{ + esp_lcd_panel_io_t base; // Base class of generic lcd panel io + esp_lcd_i80_bus_t *bus; // Which bus the device is attached to + int cs_gpio_num; // GPIO used for CS line + unsigned int pclk_hz; // PCLK clock frequency + size_t clock_prescale; // Prescaler coefficient, determined by user's configured PCLK frequency + QueueHandle_t trans_queue; // Transaction queue, transactions in this queue are pending for scheduler to dispatch + QueueHandle_t done_queue; // Transaction done queue, transactions in this queue are finished but not recycled by the caller + size_t queue_size; // Size of transaction queue + size_t num_trans_inflight; // Number of transactions that are undergoing (the descriptor not recycled yet) + int lcd_cmd_bits; // Bit width of LCD command + int lcd_param_bits; // Bit width of LCD parameter + void *user_ctx; // private data used when transfer color data + esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; // color data trans done callback + LIST_ENTRY(lcd_panel_io_i80_t) + device_list_entry; // Entry of i80 device list + struct + { + unsigned int dc_idle_level : 1; // Level of DC line in IDLE phase + unsigned int dc_cmd_level : 1; // Level of DC line in CMD phase + unsigned int dc_dummy_level : 1; // Level of DC line in DUMMY phase + unsigned int dc_data_level : 1; // Level of DC line in DATA phase + } dc_levels; + struct + { + unsigned int cs_active_high : 1; // Whether the CS line is active on high level + unsigned int reverse_color_bits : 1; // Reverse the data bits, D[N:0] -> D[0:N] + unsigned int swap_color_bytes : 1; // Swap adjacent two data bytes before sending out + unsigned int pclk_active_neg : 1; // The display will write data lines when there's a falling edge on WR line + unsigned int pclk_idle_low : 1; // The WR line keeps at low level in IDLE phase + } flags; + lcd_i80_trans_descriptor_t trans_pool[]; // Transaction pool +}; +#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3) + +typedef enum +{ + BEGIN_WRITE, + WRITE_COMMAND_8, + WRITE_COMMAND_16, + WRITE_DATA_8, + WRITE_DATA_16, + WRITE_BYTES, + WRITE_C8_D8, + WRITE_C8_D16, + WRITE_C16_D16, + END_WRITE, + DELAY, +} spi_operation_type_t; + +union +{ + uint16_t value; + struct + { + uint8_t lsb; + uint8_t msb; + }; +} _data16; + +class Arduino_DataBus +{ +public: + Arduino_DataBus(); + + void unused() { UNUSED(_data16); } // avoid compiler warning + + virtual bool begin(int32_t speed = SPI_DEFAULT_FREQ, int8_t dataMode = GFX_NOT_DEFINED) = 0; + virtual void beginWrite() = 0; + virtual void endWrite() = 0; + virtual void writeCommand(uint8_t c) = 0; + virtual void writeCommand16(uint16_t c) = 0; + virtual void write(uint8_t) = 0; + virtual void write16(uint16_t) = 0; + virtual void writeC8D8(uint8_t c, uint8_t d); + virtual void writeC16D16(uint16_t c, uint16_t d); + virtual void writeC8D16(uint8_t c, uint16_t d); + virtual void writeC8D16D16(uint8_t c, uint16_t d1, uint16_t d2); + virtual void writeC8D16D16Split(uint8_t c, uint16_t d1, uint16_t d2); + virtual void writeRepeat(uint16_t p, uint32_t len) = 0; + virtual void writePixels(uint16_t *data, uint32_t len) = 0; + + void sendCommand(uint8_t c); + void sendCommand16(uint16_t c); + void sendData(uint8_t d); + void sendData16(uint16_t d); + + void batchOperation(const uint8_t *operations, size_t len); + +#if !defined(LITTLE_FOOT_PRINT) + virtual void writeBytes(uint8_t *data, uint32_t len) = 0; + virtual void writePattern(uint8_t *data, uint8_t len, uint32_t repeat); + virtual void writeIndexedPixels(uint8_t *data, uint16_t *idx, uint32_t len); + virtual void writeIndexedPixelsDouble(uint8_t *data, uint16_t *idx, uint32_t len); +#endif // !defined(LITTLE_FOOT_PRINT) + + virtual void pinMode(uint8_t pin, uint8_t mode); + virtual void digitalWrite(uint8_t pin, uint8_t val); + virtual int digitalRead(uint8_t pin); + +protected: + int32_t _speed; + int8_t _dataMode; +}; + +#endif // _ARDUINO_DATABUS_H_ diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_G.cpp b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_G.cpp new file mode 100644 index 00000000..8d9dfd36 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_G.cpp @@ -0,0 +1,279 @@ +#if !defined(LITTLE_FOOT_PRINT) + +#include "Arduino_G.h" + +/**************************************************************************/ +/*! + @brief Instatiate a GFX context for graphics! Can only be done by a superclass + @param w Display width, in pixels + @param h Display height, in pixels +*/ +/**************************************************************************/ +Arduino_G::Arduino_G(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h) +{ +} + +// utility functions +bool gfx_draw_bitmap_to_framebuffer( + uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h, + uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h) +{ + int16_t max_X = framebuffer_w - 1; + int16_t max_Y = framebuffer_h - 1; + if ( + ((x + bitmap_w - 1) < 0) || // Outside left + ((y + bitmap_h - 1) < 0) || // Outside top + (x > max_X) || // Outside right + (y > max_Y) // Outside bottom + ) + { + return false; + } + else + { + int16_t xskip = 0; + if ((y + bitmap_h - 1) > max_Y) + { + bitmap_h -= (y + bitmap_h - 1) - max_Y; + } + if (y < 0) + { + from_bitmap -= y * bitmap_w; + bitmap_h += y; + y = 0; + } + if ((x + bitmap_w - 1) > max_X) + { + xskip = (x + bitmap_w - 1) - max_X; + bitmap_w -= xskip; + } + if (x < 0) + { + from_bitmap -= x; + xskip -= x; + bitmap_w += x; + x = 0; + } + + uint16_t *row = framebuffer; + row += y * framebuffer_w; // shift framebuffer to y offset + row += x; // shift framebuffer to x offset + if (((framebuffer_w & 1) == 0) && ((xskip & 1) == 0) && ((bitmap_w & 1) == 0)) + { + uint32_t *row2 = (uint32_t *)row; + uint32_t *from_bitmap2 = (uint32_t *)from_bitmap; + int16_t framebuffer_w2 = framebuffer_w >> 1; + int16_t xskip2 = xskip >> 1; + int16_t w2 = bitmap_w >> 1; + + int16_t j = bitmap_h; + while (j--) + { + for (int16_t i = 0; i < w2; ++i) + { + row2[i] = *from_bitmap2++; + } + from_bitmap2 += xskip2; + row2 += framebuffer_w2; + } + } + else + { + int16_t j = bitmap_h; + while (j--) + { + for (int i = 0; i < bitmap_w; ++i) + { + row[i] = *from_bitmap++; + } + from_bitmap += xskip; + row += framebuffer_w; + } + } + return true; + } +} + +bool gfx_draw_bitmap_to_framebuffer_rotate_1( + uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h, + uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h) +{ + int16_t max_X = framebuffer_w - 1; + int16_t max_Y = framebuffer_h - 1; + if ( + ((x + bitmap_w - 1) < 0) || // Outside left + ((y + bitmap_h - 1) < 0) || // Outside top + (x > max_X) || // Outside right + (y > max_Y) // Outside bottom + ) + { + return false; + } + else + { + int16_t xskip = 0; + if ((y + bitmap_h - 1) > max_Y) + { + bitmap_h -= (y + bitmap_h - 1) - max_Y; + } + if (y < 0) + { + from_bitmap -= y * bitmap_w; + bitmap_h += y; + y = 0; + } + if ((x + bitmap_w - 1) > max_X) + { + xskip = (x + bitmap_w - 1) - max_X; + bitmap_w -= xskip; + } + if (x < 0) + { + from_bitmap -= x; + xskip -= x; + bitmap_w += x; + x = 0; + } + + uint16_t *p; + int16_t i; + for (int16_t j = 0; j < bitmap_h; j++) + { + p = framebuffer; + p += (x * framebuffer_h); // shift framebuffer to y offset + p += (framebuffer_h - y - j); // shift framebuffer to x offset + + i = bitmap_w; + while (i--) + { + *p = *from_bitmap++; + p += framebuffer_h; + } + from_bitmap += xskip; + } + return true; + } +} + +bool gfx_draw_bitmap_to_framebuffer_rotate_2( + uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h, + uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h) +{ + int16_t max_X = framebuffer_w - 1; + int16_t max_Y = framebuffer_h - 1; + if ( + ((x + bitmap_w - 1) < 0) || // Outside left + ((y + bitmap_h - 1) < 0) || // Outside top + (x > max_X) || // Outside right + (y > max_Y) // Outside bottom + ) + { + return false; + } + else + { + int16_t xskip = 0; + if ((y + bitmap_h - 1) > max_Y) + { + bitmap_h -= (y + bitmap_h - 1) - max_Y; + } + if (y < 0) + { + from_bitmap -= y * bitmap_w; + bitmap_h += y; + y = 0; + } + if ((x + bitmap_w - 1) > max_X) + { + xskip = (x + bitmap_w - 1) - max_X; + bitmap_w -= xskip; + } + if (x < 0) + { + from_bitmap -= x; + xskip -= x; + bitmap_w += x; + x = 0; + } + + uint16_t *row = framebuffer; + row += (max_Y - y) * framebuffer_w; // shift framebuffer to y offset + row += framebuffer_w - x - bitmap_w; // shift framebuffer to x offset + int16_t i; + int16_t j = bitmap_h; + while (j--) + { + i = bitmap_w; + while (i--) + { + row[i] = *from_bitmap++; + } + from_bitmap += xskip; + row -= framebuffer_w; + } + return true; + } +} + +bool gfx_draw_bitmap_to_framebuffer_rotate_3( + uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h, + uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h) +{ + int16_t max_X = framebuffer_w - 1; + int16_t max_Y = framebuffer_h - 1; + if ( + ((x + bitmap_w - 1) < 0) || // Outside left + ((y + bitmap_h - 1) < 0) || // Outside top + (x > max_X) || // Outside right + (y > max_Y) // Outside bottom + ) + { + return false; + } + else + { + int16_t xskip = 0; + if ((y + bitmap_h - 1) > max_Y) + { + bitmap_h -= (y + bitmap_h - 1) - max_Y; + } + if (y < 0) + { + from_bitmap -= y * bitmap_w; + bitmap_h += y; + y = 0; + } + if ((x + bitmap_w - 1) > max_X) + { + xskip = (x + bitmap_w - 1) - max_X; + bitmap_w -= xskip; + } + if (x < 0) + { + from_bitmap -= x; + xskip -= x; + bitmap_w += x; + x = 0; + } + + uint16_t *p; + int16_t i; + for (int16_t j = 0; j < bitmap_h; j++) + { + p = framebuffer; + p += ((max_X - x) * framebuffer_h); // shift framebuffer to y offset + p += y + j; // shift framebuffer to x offset + + i = bitmap_w; + while (i--) + { + *p = *from_bitmap++; + p -= framebuffer_h; + } + from_bitmap += xskip; + } + return true; + } +} + +#endif // !defined(LITTLE_FOOT_PRINT) diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_G.h b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_G.h new file mode 100644 index 00000000..81a89d44 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_G.h @@ -0,0 +1,50 @@ +#if !defined(LITTLE_FOOT_PRINT) + +#ifndef _ARDUINO_G_H_ +#define _ARDUINO_G_H_ + +#include + +#include "Arduino_DataBus.h" + +/// A generic graphics superclass that can handle all sorts of drawing. At a minimum you can subclass and provide drawPixel(). At a maximum you can do a ton of overriding to optimize. Used for any/all Adafruit displays! +class Arduino_G +{ +public: + Arduino_G(int16_t w, int16_t h); // Constructor + + // This MUST be defined by the subclass: + virtual bool begin(int32_t speed = GFX_NOT_DEFINED) = 0; + + virtual void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) = 0; + virtual void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip = 0) = 0; + virtual void draw3bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h) = 0; + virtual void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h) = 0; + virtual void draw24bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h) = 0; + +protected: + int16_t + WIDTH, ///< This is the 'raw' display width - never changes + HEIGHT; ///< This is the 'raw' display height - never changes +}; + +#endif // _ARDUINO_G_H_ + +// utility functions +bool gfx_draw_bitmap_to_framebuffer( + uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h, + uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h); + +bool gfx_draw_bitmap_to_framebuffer_rotate_1( + uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h, + uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h); + +bool gfx_draw_bitmap_to_framebuffer_rotate_2( + uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h, + uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h); + +bool gfx_draw_bitmap_to_framebuffer_rotate_3( + uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h, + uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h); + +#endif // !defined(LITTLE_FOOT_PRINT) diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_GFX.cpp b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_GFX.cpp new file mode 100644 index 00000000..7820ad32 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_GFX.cpp @@ -0,0 +1,2898 @@ +/* + * start rewrite from: + * https://github.com/adafruit/Adafruit-GFX-Library.git + * + * Arc function come from: + * https://github.com/lovyan03/LovyanGFX.git + */ +#include "Arduino_DataBus.h" +#include "Arduino_GFX.h" +#include "font/glcdfont.h" +#include "float.h" +#ifdef __AVR__ +#include +#elif defined(ESP8266) || defined(ESP32) +#include +#endif + +/**************************************************************************/ +/*! + @brief Instatiate a GFX context for graphics! Can only be done by a superclass + @param w Display width, in pixels + @param h Display height, in pixels +*/ +/**************************************************************************/ +#if defined(LITTLE_FOOT_PRINT) +Arduino_GFX::Arduino_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h) +#else +Arduino_GFX::Arduino_GFX(int16_t w, int16_t h) : Arduino_G(w, h) +#endif // !defined(LITTLE_FOOT_PRINT) +{ + _width = WIDTH; + _height = HEIGHT; + _max_x = _width - 1; ///< x zero base bound + _max_y = _height - 1; ///< y zero base bound + _rotation = 0; + cursor_y = cursor_x = 0; + textsize_x = textsize_y = 1; + text_pixel_margin = 0; + textcolor = textbgcolor = 0xFFFF; + wrap = true; +#if !defined(ATTINY_CORE) + gfxFont = NULL; +#if defined(U8G2_FONT_SUPPORT) + u8g2Font = NULL; +#endif // defined(U8G2_FONT_SUPPORT) +#endif // !defined(ATTINY_CORE) +} + +/**************************************************************************/ +/*! + @brief Write a line. Check straight or slash line and call corresponding function + @param x0 Start point x coordinate + @param y0 Start point y coordinate + @param x1 End point x coordinate + @param y1 End point y coordinate + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Arduino_GFX::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t color) +{ + if (x0 == x1) + { + if (y0 > y1) + { + _swap_int16_t(y0, y1); + } + writeFastVLine(x0, y0, y1 - y0 + 1, color); + } + else if (y0 == y1) + { + if (x0 > x1) + { + _swap_int16_t(x0, x1); + } + writeFastHLine(x0, y0, x1 - x0 + 1, color); + } + else + { + writeSlashLine(x0, y0, x1, y1, color); + } +} + +/**************************************************************************/ +/*! + @brief Write a line. Bresenham's algorithm - thx wikpedia + @param x0 Start point x coordinate + @param y0 Start point y coordinate + @param x1 End point x coordinate + @param y1 End point y coordinate + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Arduino_GFX::writeSlashLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t color) +{ + bool steep = _diff(y1, y0) > _diff(x1, x0); + if (steep) + { + _swap_int16_t(x0, y0); + _swap_int16_t(x1, y1); + } + + if (x0 > x1) + { + _swap_int16_t(x0, x1); + _swap_int16_t(y0, y1); + } + + int16_t dx = x1 - x0; + int16_t dy = _diff(y1, y0); + int16_t err = dx >> 1; + int16_t step = (y0 < y1) ? 1 : -1; + + for (; x0 <= x1; x0++) + { + if (steep) + { + writePixel(y0, x0, color); + } + else + { + writePixel(x0, y0, color); + } + err -= dy; + if (err < 0) + { + err += dx; + y0 += step; + } + } +} + +/**************************************************************************/ +/*! + @brief Start a display-writing routine, overwrite in subclasses. +*/ +/**************************************************************************/ +INLINE void Arduino_GFX::startWrite() +{ +} + +void Arduino_GFX::writePixel(int16_t x, int16_t y, uint16_t color) +{ + if (_ordered_in_range(x, 0, _max_x) && _ordered_in_range(y, 0, _max_y)) + { + writePixelPreclipped(x, y, color); + } +} + +/**************************************************************************/ +/*! + @brief Write a pixel, overwrite in subclasses if startWrite is defined! + @param x x coordinate + @param y y coordinate + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Arduino_GFX::drawPixel(int16_t x, int16_t y, uint16_t color) +{ + startWrite(); + writePixel(x, y, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Write a perfectly vertical line, overwrite in subclasses if startWrite is defined! + @param x Top-most x coordinate + @param y Top-most y coordinate + @param h Height in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Arduino_GFX::writeFastVLine(int16_t x, int16_t y, + int16_t h, uint16_t color) +{ + for (int16_t i = y; i < y + h; i++) + { + writePixel(x, i, color); + } +} + +/**************************************************************************/ +/*! + @brief Write a perfectly horizontal line, overwrite in subclasses if startWrite is defined! + @param x Left-most x coordinate + @param y Left-most y coordinate + @param w Width in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Arduino_GFX::writeFastHLine(int16_t x, int16_t y, + int16_t w, uint16_t color) +{ + for (int16_t i = x; i < x + w; i++) + { + writePixel(i, y, color); + } +} + +/**************************************************************************/ +/*! + @brief Draw a filled rectangle to the display. Not self-contained; + should follow startWrite(). Typically used by higher-level + graphics primitives; user code shouldn't need to call this and + is likely to use the self-contained fillRect() instead. + writeFillRect() performs its own edge clipping and rejection; + see writeFillRectPreclipped() for a more 'raw' implementation. + @param x Horizontal position of first corner. + @param y Vertical position of first corner. + @param w Rectangle width in pixels (positive = right of first + corner, negative = left of first corner). + @param h Rectangle height in pixels (positive = below first + corner, negative = above first corner). + @param color 16-bit fill color in '565' RGB format. + @note Written in this deep-nested way because C by definition will + optimize for the 'if' case, not the 'else' -- avoids branches + and rejects clipped rectangles at the least-work possibility. +*/ +/**************************************************************************/ +void Arduino_GFX::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) +{ + if (w && h) + { // Nonzero width and height? + if (w < 0) + { // If negative width... + x += w + 1; // Move X to left edge + w = -w; // Use positive width + } + if (x <= _max_x) + { // Not off right + if (h < 0) + { // If negative height... + y += h + 1; // Move Y to top edge + h = -h; // Use positive height + } + if (y <= _max_y) + { // Not off bottom + int16_t x2 = x + w - 1; + if (x2 >= 0) + { // Not off left + int16_t y2 = y + h - 1; + if (y2 >= 0) + { // Not off top + // Rectangle partly or fully overlaps screen + if (x < 0) + { + x = 0; + w = x2 + 1; + } // Clip left + if (y < 0) + { + y = 0; + h = y2 + 1; + } // Clip top + if (x2 > _max_x) + { + w = _max_x - x + 1; + } // Clip right + if (y2 > _max_y) + { + h = _max_y - y + 1; + } // Clip bottom + writeFillRectPreclipped(x, y, w, h, color); + } + } + } + } + } +} + +/**************************************************************************/ +/*! + @brief Write a rectangle completely with one color, overwrite in subclasses if startWrite is defined! + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Arduino_GFX::writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) +{ + // Overwrite in subclasses if desired! + for (int16_t i = y; i < y + h; i++) + { + writeFastHLine(x, i, w, color); + } +} + +/**************************************************************************/ +/*! + @brief End a display-writing routine, overwrite in subclasses if startWrite is defined! +*/ +/**************************************************************************/ +INLINE void Arduino_GFX::endWrite() +{ +} + +/**************************************************************************/ +/*! + @brief Draw a perfectly vertical line (this is often optimized in a subclass!) + @param x Top-most x coordinate + @param y Top-most y coordinate + @param h Height in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Arduino_GFX::drawFastVLine(int16_t x, int16_t y, + int16_t h, uint16_t color) +{ + startWrite(); + writeFastVLine(x, y, h, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a perfectly horizontal line (this is often optimized in a subclass!) + @param x Left-most x coordinate + @param y Left-most y coordinate + @param w Width in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Arduino_GFX::drawFastHLine(int16_t x, int16_t y, + int16_t w, uint16_t color) +{ + startWrite(); + writeFastHLine(x, y, w, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Fill a rectangle completely with one color. Update in subclasses if desired! + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Arduino_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) +{ + startWrite(); + writeFillRect(x, y, w, h, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Fill the screen completely with one color. Update in subclasses if desired! + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Arduino_GFX::fillScreen(uint16_t color) +{ + fillRect(0, 0, _width, _height, color); +} + +/**************************************************************************/ +/*! + @brief Draw a line + @param x0 Start point x coordinate + @param y0 Start point y coordinate + @param x1 End point x coordinate + @param y1 End point y coordinate + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Arduino_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t color) +{ + // Update in subclasses if desired! + startWrite(); + writeLine(x0, y0, x1, y1, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a circle outline + @param x Center-point x coordinate + @param y Center-point y coordinate + @param r Radius of circle + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Arduino_GFX::drawCircle(int16_t x, int16_t y, + int16_t r, uint16_t color) +{ + startWrite(); + drawEllipseHelper(x, y, r, r, 0xf, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Quarter-ellipse drawer, used to do circles and roundrects + @param x Center-point x coordinate + @param y Center-point y coordinate + @param rx radius of x coordinate + @param ry radius of y coordinate + @param cornername Mask bit #1 or bit #2 to indicate which quarters of the circle we're doing + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Arduino_GFX::drawEllipseHelper(int32_t x, int32_t y, + int32_t rx, int32_t ry, + uint8_t cornername, uint16_t color) +{ + if (rx < 0 || ry < 0 || ((rx == 0) && (ry == 0))) + { + return; + } + if (ry == 0) + { + drawFastHLine(x - rx, y, (ry << 2) + 1, color); + return; + } + if (rx == 0) + { + drawFastVLine(x, y - ry, (rx << 2) + 1, color); + return; + } + + int32_t xt, yt, s, i; + int32_t rx2 = rx * rx; + int32_t ry2 = ry * ry; + + i = -1; + xt = 0; + yt = ry; + s = (ry2 << 1) + rx2 * (1 - (ry << 1)); + do + { + while (s < 0) + s += ry2 * ((++xt << 2) + 2); + if (cornername & 0x1) + { + writeFastHLine(x - xt, y - yt, xt - i, color); + } + if (cornername & 0x2) + { + writeFastHLine(x + i + 1, y - yt, xt - i, color); + } + if (cornername & 0x4) + { + writeFastHLine(x + i + 1, y + yt, xt - i, color); + } + if (cornername & 0x8) + { + writeFastHLine(x - xt, y + yt, xt - i, color); + } + i = xt; + s -= (--yt) * rx2 << 2; + } while (ry2 * xt <= rx2 * yt); + + i = -1; + yt = 0; + xt = rx; + s = (rx2 << 1) + ry2 * (1 - (rx << 1)); + do + { + while (s < 0) + s += rx2 * ((++yt << 2) + 2); + if (cornername & 0x1) + { + writeFastVLine(x - xt, y - yt, yt - i, color); + } + if (cornername & 0x2) + { + writeFastVLine(x + xt, y - yt, yt - i, color); + } + if (cornername & 0x4) + { + writeFastVLine(x + xt, y + i + 1, yt - i, color); + } + if (cornername & 0x8) + { + writeFastVLine(x - xt, y + i + 1, yt - i, color); + } + i = yt; + s -= (--xt) * ry2 << 2; + } while (rx2 * yt <= ry2 * xt); +} + +/**************************************************************************/ +/*! + @brief Draw a circle with filled color + @param x Center-point x coordinate + @param y Center-point y coordinate + @param r Radius of circle + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Arduino_GFX::fillCircle(int16_t x, int16_t y, + int16_t r, uint16_t color) +{ + startWrite(); + fillEllipseHelper(x, y, r, r, 3, 0, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Quarter-circle drawer with fill, used for circles and roundrects + @param x Center-point x coordinate + @param y Center-point y coordinate + @param rx Radius of x coordinate + @param ry Radius of y coordinate + @param corners Mask bits indicating which quarters we're doing + @param delta Offset from center-point, used for round-rects + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Arduino_GFX::fillEllipseHelper(int32_t x, int32_t y, + int32_t rx, int32_t ry, + uint8_t corners, int16_t delta, uint16_t color) +{ + if (rx < 0 || ry < 0 || ((rx == 0) && (ry == 0))) + { + return; + } + if (ry == 0) + { + drawFastHLine(x - rx, y, (ry << 2) + 1, color); + return; + } + if (rx == 0) + { + drawFastVLine(x, y - ry, (rx << 2) + 1, color); + return; + } + + int32_t xt, yt, i; + int32_t rx2 = (int32_t)rx * rx; + int32_t ry2 = (int32_t)ry * ry; + int32_t s; + + writeFastHLine(x - rx, y, (rx << 1) + 1, color); + i = 0; + yt = 0; + xt = rx; + s = (rx2 << 1) + ry2 * (1 - (rx << 1)); + do + { + while (s < 0) + { + s += rx2 * ((++yt << 2) + 2); + } + if (corners & 1) + { + writeFillRect(x - xt, y - yt, (xt << 1) + 1 + delta, yt - i, color); + } + if (corners & 2) + { + writeFillRect(x - xt, y + i + 1, (xt << 1) + 1 + delta, yt - i, color); + } + i = yt; + s -= (--xt) * ry2 << 2; + } while (rx2 * yt <= ry2 * xt); + + xt = 0; + yt = ry; + s = (ry2 << 1) + rx2 * (1 - (ry << 1)); + do + { + while (s < 0) + { + s += ry2 * ((++xt << 2) + 2); + } + if (corners & 1) + { + writeFastHLine(x - xt, y - yt, (xt << 1) + 1 + delta, color); + } + if (corners & 2) + { + writeFastHLine(x - xt, y + yt, (xt << 1) + 1 + delta, color); + } + s -= (--yt) * rx2 << 2; + } while (ry2 * xt <= rx2 * yt); +} + +/**************************************************************************/ +/*! + @brief Draw an ellipse outline + @param x Center-point x coordinate + @param y Center-point y coordinate + @param rx radius of x coordinate + @param ry radius of y coordinate + @param start degree of ellipse start + @param end degree of ellipse end + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Arduino_GFX::drawEllipse(int16_t x, int16_t y, int16_t rx, int16_t ry, uint16_t color) +{ + startWrite(); + drawEllipseHelper(x, y, rx, ry, 0xf, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw an ellipse with filled color + @param x Center-point x coordinate + @param y Center-point y coordinate + @param rx radius of x coordinate + @param ry radius of y coordinate + @param start degree of ellipse start + @param end degree of ellipse end + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Arduino_GFX::fillEllipse(int16_t x, int16_t y, int16_t rx, int16_t ry, uint16_t color) +{ + startWrite(); + fillEllipseHelper(x, y, rx, ry, 3, 0, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw an arc outline + @param x Center-point x coordinate + @param y Center-point y coordinate + @param r1 Outer radius of arc + @param r2 Inner radius of arc + @param start degree of arc start + @param end degree of arc end + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Arduino_GFX::drawArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color) +{ + if (r1 < r2) + { + _swap_int16_t(r1, r2); + } + if (r1 < 1) + { + r1 = 1; + } + if (r2 < 1) + { + r2 = 1; + } + bool equal = fabsf(start - end) < FLT_EPSILON; + start = fmodf(start, 360); + end = fmodf(end, 360); + if (start < 0) + start += 360.0; + if (end < 0) + end += 360.0; + + startWrite(); + fillArcHelper(x, y, r1, r2, start, start, color); + fillArcHelper(x, y, r1, r2, end, end, color); + if (!equal && (fabsf(start - end) <= 0.0001)) + { + start = .0; + end = 360.0; + } + fillArcHelper(x, y, r1, r1, start, end, color); + fillArcHelper(x, y, r2, r2, start, end, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw an arc with filled color + @param x Center-point x coordinate + @param y Center-point y coordinate + @param r1 Outer radius of arc + @param r2 Inner radius of arc + @param start degree of arc start + @param end degree of arc end + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Arduino_GFX::fillArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color) +{ + if (r1 < r2) + { + _swap_int16_t(r1, r2); + } + if (r1 < 1) + { + r1 = 1; + } + if (r2 < 1) + { + r2 = 1; + } + bool equal = fabsf(start - end) < FLT_EPSILON; + start = fmodf(start, 360); + end = fmodf(end, 360); + if (start < 0) + start += 360.0; + if (end < 0) + end += 360.0; + if (!equal && (fabsf(start - end) <= 0.0001)) + { + start = .0; + end = 360.0; + } + + startWrite(); + fillArcHelper(x, y, r1, r2, start, end, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Arc drawer with fill + @param cx Center-point x coordinate + @param cy Center-point y coordinate + @param oradius Outer radius of arc + @param iradius Inner radius of arc + @param start degree of arc start + @param end degree of arc end + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Arduino_GFX::fillArcHelper(int16_t cx, int16_t cy, int16_t oradius, int16_t iradius, float start, float end, uint16_t color) +{ + if ((start == 90.0) || (start == 180.0) || (start == 270.0) || (start == 360.0)) + { + start -= 0.1; + } + + if ((end == 90.0) || (end == 180.0) || (end == 270.0) || (end == 360.0)) + { + end -= 0.1; + } + + float s_cos = (cos(start * DEGTORAD)); + float e_cos = (cos(end * DEGTORAD)); + float sslope = s_cos / (sin(start * DEGTORAD)); + float eslope = e_cos / (sin(end * DEGTORAD)); + float swidth = 0.5 / s_cos; + float ewidth = -0.5 / e_cos; + --iradius; + int32_t ir2 = iradius * iradius + iradius; + int32_t or2 = oradius * oradius + oradius; + + bool start180 = !(start < 180.0); + bool end180 = end < 180.0; + bool reversed = start + 180.0 < end || (end < start && start < end + 180.0); + + int32_t xs = -oradius; + int32_t y = -oradius; + int32_t ye = oradius; + int32_t xe = oradius + 1; + if (!reversed) + { + if ((end >= 270 || end < 90) && (start >= 270 || start < 90)) + { + xs = 0; + } + else if (end < 270 && end >= 90 && start < 270 && start >= 90) + { + xe = 1; + } + if (end >= 180 && start >= 180) + { + ye = 0; + } + else if (end < 180 && start < 180) + { + y = 0; + } + } + do + { + int32_t y2 = y * y; + int32_t x = xs; + if (x < 0) + { + while (x * x + y2 >= or2) + { + ++x; + } + if (xe != 1) + { + xe = 1 - x; + } + } + float ysslope = (y + swidth) * sslope; + float yeslope = (y + ewidth) * eslope; + int32_t len = 0; + do + { + bool flg1 = start180 != (x <= ysslope); + bool flg2 = end180 != (x <= yeslope); + int32_t distance = x * x + y2; + if (distance >= ir2 && ((flg1 && flg2) || (reversed && (flg1 || flg2))) && x != xe && distance < or2) + { + ++len; + } + else + { + if (len) + { + writeFastHLine(cx + x - len, cy + y, len, color); + len = 0; + } + if (distance >= or2) + break; + if (x < 0 && distance < ir2) + { + x = -x; + } + } + } while (++x <= xe); + } while (++y <= ye); +} + +/**************************************************************************/ +/*! + @brief Draw a rectangle with no fill color + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Arduino_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) +{ + startWrite(); + writeFastHLine(x, y, w, color); + writeFastHLine(x, y + h - 1, w, color); + writeFastVLine(x, y, h, color); + writeFastVLine(x + w - 1, y, h, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a rounded rectangle with no fill color + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param r Radius of corner rounding + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Arduino_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w, + int16_t h, int16_t r, uint16_t color) +{ + int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis + if (r > max_radius) + r = max_radius; + // smarter version + startWrite(); + writeFastHLine(x + r, y, w - 2 * r, color); // Top + writeFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom + writeFastVLine(x, y + r, h - 2 * r, color); // Left + writeFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right + // draw four corners + drawEllipseHelper(x + r, y + r, r, r, 1, color); + drawEllipseHelper(x + w - r - 1, y + r, r, r, 2, color); + drawEllipseHelper(x + w - r - 1, y + h - r - 1, r, r, 4, color); + drawEllipseHelper(x + r, y + h - r - 1, r, r, 8, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a rounded rectangle with fill color + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param r Radius of corner rounding + @param color 16-bit 5-6-5 Color to draw/fill with +*/ +/**************************************************************************/ +void Arduino_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w, + int16_t h, int16_t r, uint16_t color) +{ + int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis + if (r > max_radius) + r = max_radius; + // smarter version + startWrite(); + writeFillRect(x, y + r, w, h - (r << 1), color); + // draw four corners + fillEllipseHelper(x + r, y + r, r, r, 1, w - 2 * r - 1, color); + fillEllipseHelper(x + r, y + h - r - 1, r, r, 2, w - 2 * r - 1, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a triangle with no fill color + @param x0 Vertex #0 x coordinate + @param y0 Vertex #0 y coordinate + @param x1 Vertex #1 x coordinate + @param y1 Vertex #1 y coordinate + @param x2 Vertex #2 x coordinate + @param y2 Vertex #2 y coordinate + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Arduino_GFX::drawTriangle(int16_t x0, int16_t y0, + int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) +{ + startWrite(); + writeLine(x0, y0, x1, y1, color); + writeLine(x1, y1, x2, y2, color); + writeLine(x2, y2, x0, y0, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a triangle with color-fill + @param x0 Vertex #0 x coordinate + @param y0 Vertex #0 y coordinate + @param x1 Vertex #1 x coordinate + @param y1 Vertex #1 y coordinate + @param x2 Vertex #2 x coordinate + @param y2 Vertex #2 y coordinate + @param color 16-bit 5-6-5 Color to fill/draw with +*/ +/**************************************************************************/ +void Arduino_GFX::fillTriangle(int16_t x0, int16_t y0, + int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) +{ + int16_t a, b, y, last; + + // Sort coordinates by Y order (y2 >= y1 >= y0) + if (y0 > y1) + { + _swap_int16_t(y0, y1); + _swap_int16_t(x0, x1); + } + if (y1 > y2) + { + _swap_int16_t(y2, y1); + _swap_int16_t(x2, x1); + } + if (y0 > y1) + { + _swap_int16_t(y0, y1); + _swap_int16_t(x0, x1); + } + + startWrite(); + if (y0 == y2) + { // Handle awkward all-on-same-line case as its own thing + a = b = x0; + if (x1 < a) + a = x1; + else if (x1 > b) + b = x1; + if (x2 < a) + a = x2; + else if (x2 > b) + b = x2; + writeFastHLine(a, y0, b - a + 1, color); + endWrite(); + return; + } + + int16_t + dx01 = x1 - x0, + dy01 = y1 - y0, + dx02 = x2 - x0, + dy02 = y2 - y0, + dx12 = x2 - x1, + dy12 = y2 - y1; + int32_t + sa = 0, + sb = 0; + + // For upper part of triangle, find scanline crossings for segments + // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 + // is included here (and second loop will be skipped, avoiding a /0 + // error there), otherwise scanline y1 is skipped here and handled + // in the second loop...which also avoids a /0 error here if y0=y1 + // (flat-topped triangle). + if (y1 == y2) + { + last = y1; // Include y1 scanline + } + else + { + last = y1 - 1; // Skip it + } + + for (y = y0; y <= last; y++) + { + a = x0 + sa / dy01; + b = x0 + sb / dy02; + sa += dx01; + sb += dx02; + /* longhand: + a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if (a > b) + { + _swap_int16_t(a, b); + } + writeFastHLine(a, y, b - a + 1, color); + } + + // For lower part of triangle, find scanline crossings for segments + // 0-2 and 1-2. This loop is skipped if y1=y2. + sa = (int32_t)dx12 * (y - y1); + sb = (int32_t)dx02 * (y - y0); + for (; y <= y2; y++) + { + a = x1 + sa / dy12; + b = x0 + sb / dy02; + sa += dx12; + sb += dx02; + /* longhand: + a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if (a > b) + { + _swap_int16_t(a, b); + } + writeFastHLine(a, y, b - a + 1, color); + } + endWrite(); +} + +// BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS --------------------- + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent). + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Arduino_GFX::drawBitmap(int16_t x, int16_t y, + const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) +{ + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + if (i & 7) + { + byte <<= 1; + } + else + { + byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); + } + if (byte & 0x80) + { + writePixel(x + i, y, color); + } + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw pixels with + @param bg 16-bit 5-6-5 Color to draw background with +*/ +/**************************************************************************/ +void Arduino_GFX::drawBitmap(int16_t x, int16_t y, + const uint8_t bitmap[], int16_t w, int16_t h, + uint16_t color, uint16_t bg) +{ + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + if (i & 7) + { + byte <<= 1; + } + else + { + byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); + } + writePixel(x + i, y, (byte & 0x80) ? color : bg); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent). + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Arduino_GFX::drawBitmap(int16_t x, int16_t y, + uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) +{ + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + if (i & 7) + { + byte <<= 1; + } + else + { + byte = bitmap[j * byteWidth + i / 8]; + } + if (byte & 0x80) + { + writePixel(x + i, y, color); + } + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw pixels with + @param bg 16-bit 5-6-5 Color to draw background with +*/ +/**************************************************************************/ +void Arduino_GFX::drawBitmap(int16_t x, int16_t y, + uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) +{ + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + if (i & 7) + { + byte <<= 1; + } + else + { + byte = bitmap[j * byteWidth + i / 8]; + } + writePixel(x + i, y, (byte & 0x80) ? color : bg); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw PROGMEM-resident XBitMap Files (*.xbm), exported from GIMP. + Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor. + C Array can be directly used with this function. + There is no RAM-resident version of this function; if generating bitmaps + in RAM, use the format defined by drawBitmap() and call that instead. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw pixels with +*/ +/**************************************************************************/ +void Arduino_GFX::drawXBitmap(int16_t x, int16_t y, + const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) +{ + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + if (i & 7) + { + byte >>= 1; + } + else + { + byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); + } + // Nearly identical to drawBitmap(), only the bit order + // is reversed here (left-to-right = LSB to MSB): + if (byte & 0x01) + { + writePixel(x + i, y, color); + } + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 8-bit image (grayscale) at the specified (x,y) pos. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with grayscale bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, + const uint8_t bitmap[], int16_t w, int16_t h) +{ + uint8_t v; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + v = (uint8_t)pgm_read_byte(&bitmap[j * w + i]); + writePixel(x + i, y, color565(v, v, v)); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 8-bit image (grayscale) at the specified (x,y) pos. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with grayscale bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, + uint8_t *bitmap, int16_t w, int16_t h) +{ + uint8_t v; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + v = bitmap[j * w + i]; + writePixel(x + i, y, color565(v, v, v)); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 8-bit image (grayscale) with a 1-bit mask + (set bits = opaque, unset bits = clear) at the specified (x,y) position. + BOTH buffers (grayscale and mask) must be PROGMEM-resident. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with grayscale bitmap + @param mask byte array with mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, + const uint8_t bitmap[], const uint8_t mask[], + int16_t w, int16_t h) +{ + int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte + uint8_t byte = 0; + uint8_t v; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + if (i & 7) + { + byte <<= 1; + } + else + { + byte = pgm_read_byte(&mask[j * bw + i / 8]); + } + if (byte & 0x80) + { + v = (uint8_t)pgm_read_byte(&bitmap[j * w + i]); + writePixel(x + i, y, color565(v, v, v)); + } + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 8-bit image (grayscale) with a 1-bit mask + (set bits = opaque, unset bits = clear) at the specified (x,y) position. + BOTH buffers (grayscale and mask) must be RAM-residentt, no mix-and-match + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with grayscale bitmap + @param mask byte array with mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, + uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h) +{ + int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte + uint8_t byte = 0; + uint8_t v; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + if (i & 7) + { + byte <<= 1; + } + else + { + byte = mask[j * bw + i / 8]; + } + if (byte & 0x80) + { + v = bitmap[j * w + i]; + writePixel(x + i, y, color565(v, v, v)); + } + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a Indexed 16-bit image (RGB 5/6/5) at the specified (x,y) position. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array of Indexed color bitmap + @param color_index byte array of 16-bit color index + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param x_skip number of pixels required to skip for every bitmap row +*/ +/**************************************************************************/ +void Arduino_GFX::drawIndexedBitmap( + int16_t x, int16_t y, + uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip) +{ + int32_t offset = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + writePixel(x + i, y, color_index[bitmap[offset++]]); + } + offset += x_skip; + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a Indexed 16-bit image (RGB 5/6/5) at the specified (x,y) position. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array of Indexed color bitmap + @param color_index byte array of 16-bit color index + @param chroma_key transparent color index + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param x_skip number of pixels required to skip for every bitmap row +*/ +/**************************************************************************/ +void Arduino_GFX::drawIndexedBitmap( + int16_t x, int16_t y, + uint8_t *bitmap, uint16_t *color_index, uint8_t chroma_key, int16_t w, int16_t h, int16_t x_skip) +{ + int32_t offset = 0; + uint8_t color_key; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + color_key = bitmap[offset++]; + if (color_key != chroma_key) + { + writePixel(x + i, y, color_index[color_key]); + } + offset += x_skip; + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 3-bit image (RGB 1/1/1) at the specified (x,y) position. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 3-bit color bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::draw3bitRGBBitmap(int16_t x, int16_t y, + uint8_t *bitmap, int16_t w, int16_t h) +{ + int32_t offset = 0, idx = 0; + uint8_t c = 0; + uint16_t d; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + if (offset & 1) + { + d = (((c & 0b100) ? RED : 0) | + ((c & 0b010) ? GREEN : 0) | + ((c & 0b001) ? BLUE : 0)); + } + else + { + c = bitmap[idx++]; + d = (((c & 0b100000) ? RED : 0) | + ((c & 0b010000) ? GREEN : 0) | + ((c & 0b001000) ? BLUE : 0)); + } + writePixel(x + i, y, d); + offset++; + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y, + const uint16_t bitmap[], int16_t w, int16_t h) +{ + int32_t offset = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + writePixel(x + i, y, pgm_read_word(&bitmap[offset++])); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y, + uint16_t *bitmap, int16_t w, int16_t h) +{ + int32_t offset = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + writePixel(x + i, y, bitmap[offset++]); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param transparent_color + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::draw16bitRGBBitmap( + int16_t x, int16_t y, + uint16_t *bitmap, uint16_t transparent_color, int16_t w, int16_t h) +{ + int32_t offset = 0; + uint16_t color; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + color = bitmap[offset++]; + if (color != transparent_color) + { + writePixel(x + i, y, color); + } + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 16-bit Big Endian image (RGB 5/6/5) at the specified (x,y) position. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::draw16bitBeRGBBitmap(int16_t x, int16_t y, + uint16_t *bitmap, int16_t w, int16_t h) +{ + int32_t offset = 0; + uint16_t p; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + p = bitmap[offset++]; + MSB_16_SET(p, p); + writePixel(x + i, y, p); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask + (set bits = opaque, unset bits = clear) at the specified (x,y) position. + BOTH buffers (color and mask) must be PROGMEM-resident. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param mask byte array with monochrome mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y, + const uint16_t bitmap[], const uint8_t mask[], + int16_t w, int16_t h) +{ + int32_t offset = 0; + int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte + uint8_t byte = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + if (i & 7) + { + byte <<= 1; + } + else + { + byte = pgm_read_byte(&mask[j * bw + i / 8]); + } + if (byte & 0x80) + { + writePixel(x + i, y, pgm_read_word(&bitmap[offset])); + } + offset++; + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask + (set bits = opaque, unset bits = clear) at the specified (x,y) position. + BOTH buffers (color and mask) must be RAM-resident. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param mask byte array with monochrome mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y, + uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h) +{ + int32_t offset = 0, maskIdx = 0; + uint8_t byte = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + if (i & 7) + { + byte <<= 1; + } + else + { + byte = mask[maskIdx++]; + } + if (byte & 0x80) + { + writePixel(x + i, y, bitmap[offset]); + } + offset++; + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 24-bit image (RGB 5/6/5) at the specified (x,y) position. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y, + const uint8_t bitmap[], int16_t w, int16_t h) +{ + int32_t offset = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + writePixel(x + i, y, color565(pgm_read_byte(&bitmap[offset]), pgm_read_byte(&bitmap[offset + 1]), pgm_read_byte(&bitmap[offset + 2]))); + offset += 3; + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 24-bit image (RGB 5/6/5) at the specified (x,y) position. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y, + uint8_t *bitmap, int16_t w, int16_t h) +{ + int32_t offset = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + writePixel(x + i, y, color565(bitmap[offset], bitmap[offset + 1], bitmap[offset + 2])); + offset += 3; + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 24-bit image (RGB 5/6/5) with a 1-bit mask + (set bits = opaque, unset bits = clear) at the specified (x,y) position. + BOTH buffers (color and mask) must be PROGMEM-resident. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param mask byte array with monochrome mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y, + const uint8_t bitmap[], const uint8_t mask[], + int16_t w, int16_t h) +{ + int32_t offset = 0; + int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte + uint8_t byte = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + if (i & 7) + { + byte <<= 1; + } + else + { + byte = pgm_read_byte(&mask[j * bw + i / 8]); + } + if (byte & 0x80) + { + writePixel(x + i, y, color565(pgm_read_byte(&bitmap[offset]), pgm_read_byte(&bitmap[offset + 1]), pgm_read_byte(&bitmap[offset + 2]))); + } + offset += 3; + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 24-bit image (RGB 5/6/5) with a 1-bit mask + (set bits = opaque, unset bits = clear) at the specified (x,y) position. + BOTH buffers (color and mask) must be RAM-resident. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param mask byte array with monochrome mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y, + uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h) +{ + int32_t offset = 0; + int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte + uint8_t byte = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) + { + for (int16_t i = 0; i < w; i++) + { + if (i & 7) + { + byte <<= 1; + } + else + { + byte = mask[j * bw + i / 8]; + } + if (byte & 0x80) + { + writePixel(x + i, y, color565(bitmap[offset], bitmap[offset + 1], bitmap[offset + 2])); + } + offset += 3; + } + } + endWrite(); +} + +#if defined(U8G2_FONT_SUPPORT) +uint16_t Arduino_GFX::u8g2_font_get_word(const uint8_t *font, uint8_t offset) +{ + uint16_t pos; + font += offset; + pos = pgm_read_byte(font); + font++; + pos <<= 8; + pos += pgm_read_byte(font); + + return pos; +} + +uint8_t Arduino_GFX::u8g2_font_decode_get_unsigned_bits(uint8_t cnt) +{ + uint8_t val; + uint8_t bit_pos = _u8g2_decode_bit_pos; + uint8_t bit_pos_plus_cnt; + + val = pgm_read_byte(_u8g2_decode_ptr); + + val >>= bit_pos; + bit_pos_plus_cnt = bit_pos; + bit_pos_plus_cnt += cnt; + if (bit_pos_plus_cnt >= 8) + { + uint8_t s = 8; + s -= bit_pos; + _u8g2_decode_ptr++; + val |= pgm_read_byte(_u8g2_decode_ptr) << (s); + bit_pos_plus_cnt -= 8; + } + val &= (1U << cnt) - 1; + + _u8g2_decode_bit_pos = bit_pos_plus_cnt; + + return val; +} + +int8_t Arduino_GFX::u8g2_font_decode_get_signed_bits(uint8_t cnt) +{ + int8_t v, d; + v = (int8_t)u8g2_font_decode_get_unsigned_bits(cnt); + d = 1; + cnt--; + d <<= cnt; + v -= d; + + return v; +} + +void Arduino_GFX::u8g2_font_decode_len(uint8_t len, uint8_t is_foreground, uint16_t color, uint16_t bg) +{ + uint8_t cnt; /* total number of remaining pixels, which have to be drawn */ + uint8_t rem; /* remaining pixel to the right edge of the glyph */ + uint8_t current; /* number of pixels, which need to be drawn for the draw procedure */ + /* current is either equal to cnt or equal to rem */ + + /* target position on the screen */ + uint16_t x, y; + + cnt = len; + + /* get the local position */ + uint8_t lx = _u8g2_dx; + uint8_t ly = _u8g2_dy; + + for (;;) + { + /* calculate the number of pixel to the right edge of the glyph */ + rem = _u8g2_char_width; + rem -= lx; + + /* calculate how many pixel to draw. This is either to the right edge */ + /* or lesser, if not enough pixel are left */ + current = rem; + if (cnt < rem) + current = cnt; + + /* now draw the line, but apply the rotation around the glyph target position */ + // u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground); + + if (textsize_x == 1 && textsize_y == 1) + { + /* get target position */ + x = _u8g2_target_x + lx; + y = _u8g2_target_y + ly; + + /* draw foreground and background (if required) */ + if (is_foreground) + { + writeFastHLine(x, y, current, color); + } + else if (bg != color) + { + writeFastHLine(x, y, current, bg); + } + } + else + { + /* get target position */ + x = _u8g2_target_x + (lx * textsize_x); + y = _u8g2_target_y + (ly * textsize_y); + + /* draw foreground and background (if required) */ + if (is_foreground) + { + writeFillRect(x, y, (current * textsize_x) - text_pixel_margin, + textsize_y - text_pixel_margin, color); + } + else if (bg != color) + { + writeFillRect(x, y, (current * textsize_x) - text_pixel_margin, + textsize_y - text_pixel_margin, bg); + } + } + + /* check, whether the end of the run length code has been reached */ + if (cnt < rem) + break; + cnt -= rem; + lx = 0; + ly++; + } + lx += cnt; + + _u8g2_dx = lx; + _u8g2_dy = ly; +} +#endif // defined(U8G2_FONT_SUPPORT) + +// TEXT- AND CHARACTER-HANDLING FUNCTIONS ---------------------------------- + +// Draw a character +/**************************************************************************/ +/*! + @brief Draw a single character + @param x Bottom left corner x coordinate + @param y Bottom left corner y coordinate + @param c The 8-bit font-indexed character (likely ascii) + @param color 16-bit 5-6-5 Color to draw chraracter with + @param bg 16-bit 5-6-5 Color to fill background with (if same as color, no background) +*/ +/**************************************************************************/ +void Arduino_GFX::drawChar(int16_t x, int16_t y, unsigned char c, + uint16_t color, uint16_t bg) +{ + int16_t block_w; + int16_t block_h; + +#if !defined(ATTINY_CORE) + if (gfxFont) // custom font + { + // Character is assumed previously filtered by write() to eliminate + // newlines, returns, non-printable characters, etc. Calling + // drawChar() directly with 'bad' characters of font may cause mayhem! + + c -= (uint8_t)pgm_read_byte(&gfxFont->first); + GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c); + uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont); + + uint16_t bo = pgm_read_word(&glyph->bitmapOffset); + uint8_t w = pgm_read_byte(&glyph->width), + h = pgm_read_byte(&glyph->height), + xAdvance = pgm_read_byte(&glyph->xAdvance), + yAdvance = pgm_read_byte(&gfxFont->yAdvance), + baseline = yAdvance * 2 / 3; // TODO: baseline is an arbitrary currently, may be define in font file + int8_t xo = pgm_read_byte(&glyph->xOffset), + yo = pgm_read_byte(&glyph->yOffset); + uint8_t xx, yy, bits = 0, bit = 0; + int16_t xo16 = xo, yo16 = yo; + + if (xAdvance < w) + { + xAdvance = w; // Don't know why it exists + } + + block_w = xAdvance * textsize_x; + block_h = yAdvance * textsize_y; + if ( + (x > _max_x) || // Clip right + (y > _max_y) || // Clip bottom + ((x + block_w - 1) < 0) || // Clip left + ((y + block_h - 1) < 0) // Clip top + ) + { + return; + } + + // NOTE: Different from Adafruit_GFX design, Adruino_GFX also cater background. + // Since it may introduce many ugly output, it should limited using on mono font only. + startWrite(); + if (bg != color) // have background color + { + writeFillRect(x, y - (baseline * textsize_y), block_w, block_h, bg); + } + for (yy = 0; yy < h; yy++) + { + for (xx = 0; xx < w; xx++) + { + if (!(bit++ & 7)) + { + bits = pgm_read_byte(&bitmap[bo++]); + } + if (bits & 0x80) + { + if (textsize_x == 1 && textsize_y == 1) + { + writePixel(x + xo + xx, y + yo + yy, color); + } + else + { + writeFillRect(x + (xo16 + xx) * textsize_x, y + (yo16 + yy) * textsize_y, + textsize_x - text_pixel_margin, textsize_y - text_pixel_margin, color); + } + } + bits <<= 1; + } + } + endWrite(); + } + else // 'Classic' built-in font +#endif // !defined(ATTINY_CORE) +#if defined(U8G2_FONT_SUPPORT) + if (u8g2Font) + { + if ((_u8g2_decode_ptr) && (_u8g2_char_width > 0)) + { + uint8_t a, b; + + _u8g2_target_x = x + (_u8g2_char_x * textsize_x); + _u8g2_target_y = y - ((_u8g2_char_height + _u8g2_char_y) * textsize_y); + // log_d("_u8g2_target_x: %d, _u8g2_target_y: %d", _u8g2_target_x, _u8g2_target_y); + + /* reset local x/y position */ + _u8g2_dx = 0; + _u8g2_dy = 0; + /* decode glyph */ + startWrite(); + for (;;) + { + a = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_0); + b = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_1); + // log_d("a: %d, b: %d", a, b); + do + { + u8g2_font_decode_len(a, 0, color, bg); + u8g2_font_decode_len(b, 1, color, bg); + } while (u8g2_font_decode_get_unsigned_bits(1) != 0); + + if (_u8g2_dy >= _u8g2_char_height) + break; + } + endWrite(); + } + } + else // glcdfont +#endif // defined(U8G2_FONT_SUPPORT) + { + block_w = 6 * textsize_x; + block_h = 8 * textsize_y; + if ( + (x > _max_x) || // Clip right + (y > _max_y) || // Clip bottom + ((x + block_w - 1) < 0) || // Clip left + ((y + block_h - 1) < 0) // Clip top + ) + { + return; + } + + startWrite(); + for (int8_t i = 0; i < 5; i++) + { // Char bitmap = 5 columns + uint8_t line = pgm_read_byte(&font[c * 5 + i]); + for (int8_t j = 0; j < 8; j++, line >>= 1) + { + if (line & 1) + { + if (textsize_x == 1 && textsize_y == 1) + { + writePixel(x + i, y + j, color); + } + else + { + if (text_pixel_margin > 0) + { + writeFillRect(x + (i * textsize_x), y + j * textsize_y, textsize_x - text_pixel_margin, textsize_y - text_pixel_margin, color); + writeFillRect(x + ((i + 1) * textsize_x) - text_pixel_margin, y + j * textsize_y, text_pixel_margin, textsize_y, bg); + writeFillRect(x + (i * textsize_x), y + ((j + 1) * textsize_y) - text_pixel_margin, textsize_x - text_pixel_margin, text_pixel_margin, bg); + } + else + { + writeFillRect(x + i * textsize_x, y + j * textsize_y, textsize_x, textsize_y, color); + } + } + } + else if (bg != color) + { + if (textsize_x == 1 && textsize_y == 1) + { + writePixel(x + i, y + j, bg); + } + else + { + writeFillRect(x + i * textsize_x, y + j * textsize_y, textsize_x, textsize_y, bg); + } + } + } + } + if (bg != color) + { // If opaque, draw vertical line for last column + if (textsize_x == 1 && textsize_y == 1) + { + writeFastVLine(x + 5, y, 8, bg); + } + else + { + writeFillRect(x + 5 * textsize_x, y, textsize_x, 8 * textsize_y, bg); + } + } + endWrite(); + } +} + +/**************************************************************************/ +/*! + @brief Print one byte/character of data, used to support print() + @param c The 8-bit ascii character to write +*/ +/**************************************************************************/ +size_t Arduino_GFX::write(uint8_t c) +{ +#if !defined(ATTINY_CORE) + if (gfxFont) // custom font + { + if (c == '\n') // Newline + { + cursor_x = 0; // Reset x to zero, advance y by one line + cursor_y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } + else if (c != '\r') // Not a carriage return; is normal char + { + uint8_t first = pgm_read_byte(&gfxFont->first), + last = pgm_read_byte(&gfxFont->last); + if ((c >= first) && (c <= last)) // Char present in this font? + { + GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first); + uint8_t gw = pgm_read_byte(&glyph->width), + xa = pgm_read_byte(&glyph->xAdvance); + int16_t xo = pgm_read_byte(&glyph->xOffset); + if (wrap && ((cursor_x + ((xo + gw) * textsize_x) - 1) > _max_x)) + { + cursor_x = 0; // Reset x to zero, advance y by one line + cursor_y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } + drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor); + cursor_x += (int16_t)textsize_x * xa; + } + } + } + else // not gfxFont +#endif // !defined(ATTINY_CORE) +#if defined(U8G2_FONT_SUPPORT) + if (u8g2Font) + { + _u8g2_decode_ptr = 0; + + if (_enableUTF8Print) + { + if (_utf8_state == 0) + { + if (c >= 0xfc) /* 6 byte sequence */ + { + _utf8_state = 5; + c &= 1; + } + else if (c >= 0xf8) + { + _utf8_state = 4; + c &= 3; + } + else if (c >= 0xf0) + { + _utf8_state = 3; + c &= 7; + } + else if (c >= 0xe0) + { + _utf8_state = 2; + c &= 15; + } + else if (c >= 0xc0) + { + _utf8_state = 1; + c &= 0x01f; + } + _encoding = c; + } + else + { + _utf8_state--; + /* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */ + _encoding <<= 6; + c &= 0x03f; + _encoding |= c; + } + } // _enableUTF8Print + else + { + _encoding = c; + } + + if (_utf8_state == 0) + { + if (_encoding == '\n') + { + cursor_x = 0; + cursor_y += (int16_t)textsize_y * _u8g2_max_char_height; + } + else if (_encoding != '\r') + { // Ignore carriage returns + uint8_t *font = u8g2Font; + const uint8_t *glyph_data = 0; + + // extract from u8g2_font_get_glyph_data() + font += 23; // U8G2_FONT_DATA_STRUCT_SIZE + if (_encoding <= 255) + { + if (_encoding >= 'a') + { + font += _u8g2_start_pos_lower_a; + } + else if (_encoding >= 'A') + { + font += _u8g2_start_pos_upper_A; + } + + for (;;) + { + if (pgm_read_byte(font + 1) == 0) + break; + if (pgm_read_byte(font) == _encoding) + { + glyph_data = font + 2; /* skip encoding and glyph size */ + } + font += pgm_read_byte(font + 1); + } + } +#ifdef U8G2_WITH_UNICODE + else + { + uint16_t e; + font += _u8g2_start_pos_unicode; + const uint8_t *unicode_lookup_table = font; + + /* issue 596: search for the glyph start in the unicode lookup table */ + do + { + font += u8g2_font_get_word(unicode_lookup_table, 0); + e = u8g2_font_get_word(unicode_lookup_table, 2); + unicode_lookup_table += 4; + } while (e < _encoding); + + for (;;) + { + e = u8g2_font_get_word(font, 0); + + if (e == 0) + break; + + if (e == _encoding) + { + glyph_data = font + 3; /* skip encoding and glyph size */ + break; + } + font += pgm_read_byte(font + 2); + } + } +#endif + + if (glyph_data) + { + // u8g2_font_decode_glyph + _u8g2_decode_ptr = glyph_data; + _u8g2_decode_bit_pos = 0; + + _u8g2_char_width = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_width); + _u8g2_char_height = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_height); + _u8g2_char_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_x); + _u8g2_char_y = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_y); + _u8g2_delta_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_delta_x); + // log_d("c: %c, _encoding: %d, _u8g2_char_width: %d, _u8g2_char_height: %d, _u8g2_char_x: %d, _u8g2_char_y: %d, _u8g2_delta_x: %d", + // c, _encoding, _u8g2_char_width, _u8g2_char_height, _u8g2_char_x, _u8g2_char_y, _u8g2_delta_x); + + if (_u8g2_char_width > 0) + { + if (wrap && ((cursor_x + (textsize_x * _u8g2_char_width) - 1) > _max_x)) + { + cursor_x = 0; + cursor_y += (int16_t)textsize_y * _u8g2_max_char_height; + } + } + + drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor); + cursor_x += (int16_t)textsize_x * _u8g2_delta_x; + } + } + } + } + else // glcdfont +#endif // defined(U8G2_FONT_SUPPORT) + { + if (c == '\n') + { // Newline? + cursor_x = 0; // Reset x to zero, + cursor_y += textsize_y * 8; // advance y one line + } + else if (c != '\r') // Normal char; ignore carriage returns + { + if (wrap && ((cursor_x + (textsize_x * 6) - 1) > _max_x)) // Off right? + { + cursor_x = 0; // Reset x to zero, + cursor_y += textsize_y * 8; // advance y one line + } + drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor); + cursor_x += textsize_x * 6; // Advance x one char + } + } + return 1; +} + +/**************************************************************************/ +/*! + @brief Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger. + @param s Desired text size. 1 is default 6x8, 2 is 12x16, 3 is 18x24, etc +*/ +/**************************************************************************/ +void Arduino_GFX::setTextSize(uint8_t s) +{ + setTextSize(s, s, 0); +} + +/**************************************************************************/ +/*! + @brief Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger. + @param s_x Desired text width magnification level in X-axis. 1 is default + @param s_y Desired text width magnification level in Y-axis. 1 is default +*/ +/**************************************************************************/ +void Arduino_GFX::setTextSize(uint8_t s_x, uint8_t s_y) +{ + setTextSize(s_x, s_y, 0); +} + +/**************************************************************************/ +/*! + @brief Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger. + @param s_x Desired text width magnification level in X-axis. 1 is default + @param s_y Desired text width magnification level in Y-axis. 1 is default + @param pixel_margin Margin for each text pixel. 0 is default +*/ +/**************************************************************************/ +void Arduino_GFX::setTextSize(uint8_t s_x, uint8_t s_y, uint8_t pixel_margin) +{ + text_pixel_margin = ((pixel_margin < s_x) && (pixel_margin < s_y)) ? pixel_margin : 0; + textsize_x = (s_x > 0) ? s_x : 1; + textsize_y = (s_y > 0) ? s_y : 1; +} + +/**************************************************************************/ +/*! + @brief Set rotation setting for display + @param r 0 thru 3 corresponding to 4 cardinal rotations +*/ +/**************************************************************************/ +void Arduino_GFX::setRotation(uint8_t r) +{ + _rotation = (r & 7); + switch (_rotation) + { + case 7: + case 5: + case 3: + case 1: + _width = HEIGHT; + _height = WIDTH; + _max_x = _width - 1; ///< x zero base bound + _max_y = _height - 1; ///< y zero base bound + break; + case 6: + case 4: + case 2: + default: // case 0: + _width = WIDTH; + _height = HEIGHT; + _max_x = _width - 1; ///< x zero base bound + _max_y = _height - 1; ///< y zero base bound + break; + } +} + +#if !defined(ATTINY_CORE) +/**************************************************************************/ +/*! + @brief Set the font to display when print()ing, either custom or default + @param f The GFXfont object, if NULL use built in 6x8 font +*/ +/**************************************************************************/ +void Arduino_GFX::setFont(const GFXfont *f) +{ + gfxFont = (GFXfont *)f; +#if defined(U8G2_FONT_SUPPORT) + u8g2Font = NULL; +#endif // defined(U8G2_FONT_SUPPORT) +} + +/**************************************************************************/ +/*! + @brief flush framebuffer to output (for Canvas or NeoPixel sub-class) +*/ +/**************************************************************************/ +void Arduino_GFX::flush() +{ +} +#endif // !defined(ATTINY_CORE) + +#if defined(U8G2_FONT_SUPPORT) +void Arduino_GFX::setFont(const uint8_t *font) +{ + gfxFont = NULL; + u8g2Font = (uint8_t *)font; + + // extract from u8g2_read_font_info() + /* offset 0 */ + _u8g2_glyph_cnt = pgm_read_byte(font); + // uint8_t bbx_mode = pgm_read_byte(font + 1); + _u8g2_bits_per_0 = pgm_read_byte(font + 2); + _u8g2_bits_per_1 = pgm_read_byte(font + 3); + // log_d("_u8g2_glyph_cnt: %d, bbx_mode: %d, _u8g2_bits_per_0: %d, _u8g2_bits_per_1: %d", + // _u8g2_glyph_cnt, bbx_mode, _u8g2_bits_per_0, _u8g2_bits_per_1); + + /* offset 4 */ + _u8g2_bits_per_char_width = pgm_read_byte(font + 4); + _u8g2_bits_per_char_height = pgm_read_byte(font + 5); + _u8g2_bits_per_char_x = pgm_read_byte(font + 6); + _u8g2_bits_per_char_y = pgm_read_byte(font + 7); + _u8g2_bits_per_delta_x = pgm_read_byte(font + 8); + // log_d("_u8g2_bits_per_char_width: %d, _u8g2_bits_per_char_height: %d, _u8g2_bits_per_char_x: %d, _u8g2_bits_per_char_y: %d, _u8g2_bits_per_delta_x: %d", + // _u8g2_bits_per_char_width, _u8g2_bits_per_char_height, _u8g2_bits_per_char_x, _u8g2_bits_per_char_y, _u8g2_bits_per_delta_x); + + /* offset 9 */ + _u8g2_max_char_width = pgm_read_byte(font + 9); + _u8g2_max_char_height = pgm_read_byte(font + 10); + // int8_t x_offset = pgm_read_byte(font + 11); + // int8_t y_offset = pgm_read_byte(font + 12); + // log_d("_u8g2_max_char_width: %d, _u8g2_max_char_height: %d, x_offset: %d, y_offset: %d", + // _u8g2_max_char_width, _u8g2_max_char_height, x_offset, y_offset); + + /* offset 13 */ + // int8_t ascent_A = pgm_read_byte(font + 13); + // int8_t descent_g = pgm_read_byte(font + 14); + // int8_t ascent_para = pgm_read_byte(font + 15); + // int8_t descent_para = pgm_read_byte(font + 16); + // log_d("ascent_A: %d, descent_g: %d, ascent_para: %d, descent_para: %d", + // ascent_A, descent_g, ascent_para, descent_para); + + /* offset 17 */ + _u8g2_start_pos_upper_A = u8g2_font_get_word(font, 17); + _u8g2_start_pos_lower_a = u8g2_font_get_word(font, 19); +#ifdef U8G2_WITH_UNICODE + _u8g2_start_pos_unicode = u8g2_font_get_word(font, 21); +#endif + _u8g2_first_char = pgm_read_byte(font + 23); + // log_d("_u8g2_start_pos_upper_A: %d, _u8g2_start_pos_lower_a: %d, _u8g2_start_pos_unicode: %d, _u8g2_first_char: %d", + // _u8g2_start_pos_upper_A, _u8g2_start_pos_lower_a, _u8g2_start_pos_unicode, _u8g2_first_char); +} + +void Arduino_GFX::setUTF8Print(bool isEnable) +{ + _enableUTF8Print = isEnable; +} +#endif // defined(U8G2_FONT_SUPPORT) + +/**************************************************************************/ +/*! + @brief Helper to determine size of a character with current font/size. + Broke this out as it's used by both the PROGMEM- and RAM-resident getTextBounds() functions. + @param c The ascii character in question + @param x Pointer to x location of character + @param y Pointer to y location of character + @param minx Minimum clipping value for X + @param miny Minimum clipping value for Y + @param maxx Maximum clipping value for X + @param maxy Maximum clipping value for Y +*/ +/**************************************************************************/ +void Arduino_GFX::charBounds(char c, int16_t *x, int16_t *y, + int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy) +{ +#if !defined(ATTINY_CORE) + if (gfxFont) // custom font + { + if (c == '\n') // Newline + { + *x = 0; // Reset x to zero, advance y by one line + *y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } + else if (c != '\r') // Not a carriage return; is normal char + { + uint8_t first = pgm_read_byte(&gfxFont->first), + last = pgm_read_byte(&gfxFont->last); + if ((c >= first) && (c <= last)) // Char present in this font? + { + GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first); + uint8_t gw = pgm_read_byte(&glyph->width), + gh = pgm_read_byte(&glyph->height), + xa = pgm_read_byte(&glyph->xAdvance); + int8_t xo = pgm_read_byte(&glyph->xOffset), + yo = pgm_read_byte(&glyph->yOffset); + if (wrap && ((*x + ((xo + gw) * textsize_x) - 1) > _max_x)) + { + *x = 0; // Reset x to zero, advance y by one line + *y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } + int16_t x1 = *x + ((int16_t)xo * textsize_x), + y1 = *y + ((int16_t)yo * textsize_y), + x2 = x1 + ((int16_t)gw * textsize_x) - 1, + y2 = y1 + ((int16_t)gh * textsize_y) - 1; + if (x1 < *minx) + { + *minx = x1; + } + if (y1 < *miny) + { + *miny = y1; + } + if (x2 > *maxx) + { + *maxx = x2; + } + if (y2 > *maxy) + { + *maxy = y2; + } + *x += (int16_t)textsize_x * xa; + } + } + } + else // not gfxFont +#endif // !defined(ATTINY_CORE) +#if defined(U8G2_FONT_SUPPORT) + if (u8g2Font) + { + _u8g2_decode_ptr = 0; + + if (_enableUTF8Print) + { + if (_utf8_state == 0) + { + if (c >= 0xfc) /* 6 byte sequence */ + { + _utf8_state = 5; + c &= 1; + } + else if (c >= 0xf8) + { + _utf8_state = 4; + c &= 3; + } + else if (c >= 0xf0) + { + _utf8_state = 3; + c &= 7; + } + else if (c >= 0xe0) + { + _utf8_state = 2; + c &= 15; + } + else if (c >= 0xc0) + { + _utf8_state = 1; + c &= 0x01f; + } + _encoding = c; + } + else + { + _utf8_state--; + /* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */ + _encoding <<= 6; + c &= 0x03f; + _encoding |= c; + } + } // _enableUTF8Print + else + { + _encoding = c; + } + + if (_utf8_state == 0) + { + if (_encoding == '\n') + { + *x = 0; + *y += (int16_t)textsize_y * _u8g2_max_char_height; + } + else if (_encoding != '\r') + { // Ignore carriage returns + uint8_t *font = u8g2Font; + const uint8_t *glyph_data = 0; + + // extract from u8g2_font_get_glyph_data() + font += 23; // U8G2_FONT_DATA_STRUCT_SIZE + if (_encoding <= 255) + { + if (_encoding >= 'a') + { + font += _u8g2_start_pos_lower_a; + } + else if (_encoding >= 'A') + { + font += _u8g2_start_pos_upper_A; + } + + for (;;) + { + if (pgm_read_byte(font + 1) == 0) + break; + if (pgm_read_byte(font) == _encoding) + { + glyph_data = font + 2; /* skip encoding and glyph size */ + } + font += pgm_read_byte(font + 1); + } + } +#ifdef U8G2_WITH_UNICODE + else + { + uint16_t e; + font += _u8g2_start_pos_unicode; + const uint8_t *unicode_lookup_table = font; + + /* issue 596: search for the glyph start in the unicode lookup table */ + do + { + font += u8g2_font_get_word(unicode_lookup_table, 0); + e = u8g2_font_get_word(unicode_lookup_table, 2); + unicode_lookup_table += 4; + } while (e < _encoding); + + for (;;) + { + e = u8g2_font_get_word(font, 0); + + if (e == 0) + break; + + if (e == _encoding) + { + glyph_data = font + 3; /* skip encoding and glyph size */ + break; + } + font += pgm_read_byte(font + 2); + } + } +#endif + + if (glyph_data) + { + // u8g2_font_decode_glyph + _u8g2_decode_ptr = glyph_data; + _u8g2_decode_bit_pos = 0; + + _u8g2_char_width = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_width); + _u8g2_char_height = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_height); + _u8g2_char_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_x); + _u8g2_char_y = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_y); + _u8g2_delta_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_delta_x); + // log_d("c: %c, _encoding: %d, _u8g2_char_width: %d, _u8g2_char_height: %d, _u8g2_char_x: %d, _u8g2_char_y: %d, _u8g2_delta_x: %d", + // c, _encoding, _u8g2_char_width, _u8g2_char_height, _u8g2_char_x, _u8g2_char_y, _u8g2_delta_x); + + if (_u8g2_char_width > 0) + { + if (wrap && ((*x + (textsize_x * _u8g2_char_width) - 1) > _max_x)) + { + *x = 0; + *y += (int16_t)textsize_y * _u8g2_max_char_height; + } + } + + int16_t x1 = *x + ((int16_t)_u8g2_char_x * textsize_x), + y1 = *y - (((int16_t)_u8g2_char_height + _u8g2_char_y) * textsize_y), + x2 = x1 + ((int16_t)_u8g2_char_width * textsize_x) - 1, + y2 = y1 + ((int16_t)_u8g2_char_height * textsize_y) - 1; + if (x1 < *minx) + { + *minx = x1; + } + if (y1 < *miny) + { + *miny = y1; + } + if (x2 > *maxx) + { + *maxx = x2; + } + if (y2 > *maxy) + { + *maxy = y2; + } + *x += (int16_t)textsize_x * _u8g2_delta_x; + } + } + } + } + else // glcdfont +#endif // defined(U8G2_FONT_SUPPORT) + { + if (c == '\n') + { // Newline? + *x = 0; // Reset x to zero, + *y += textsize_y * 8; // advance y one line + // min/max x/y unchaged -- that waits for next 'normal' character + } + else if (c != '\r') // Normal char; ignore carriage returns + { + if (wrap && ((*x + (textsize_x * 6) - 1) > _max_x)) // Off right? + { + *x = 0; // Reset x to zero, + *y += textsize_y * 8; // advance y one line + } + int16_t x2 = *x + textsize_x * 6 - 1; // Lower-right pixel of char + int16_t y2 = *y + textsize_y * 8 - 1; + if (x2 > *maxx) + { + *maxx = x2; // Track max x, y + } + if (y2 > *maxy) + { + *maxy = y2; + } + if (*x < *minx) + { + *minx = *x; // Track min x, y + } + if (*y < *miny) + { + *miny = *y; + } + *x += textsize_x * 6; // Advance x one char + } + } +} + +/**************************************************************************/ +/*! + @brief Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H. + @param str The ascii string to measure + @param x The current cursor X + @param y The current cursor Y + @param x1 The boundary X coordinate, set by function + @param y1 The boundary Y coordinate, set by function + @param w The boundary width, set by function + @param h The boundary height, set by function +*/ +/**************************************************************************/ +void Arduino_GFX::getTextBounds(const char *str, int16_t x, int16_t y, + int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) +{ + uint8_t c; // Current character + + *x1 = x; + *y1 = y; + *w = *h = 0; + + int16_t minx = _width, miny = _height, maxx = -1, maxy = -1; + + while ((c = *str++)) + { + charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy); + } + + if (maxx >= minx) + { + *x1 = minx; + *w = maxx - minx + 1; + } + if (maxy >= miny) + { + *y1 = miny; + *h = maxy - miny + 1; + } +} + +/**************************************************************************/ +/*! + @brief Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H. + @param str The ascii string to measure (as an arduino String() class) + @param x The current cursor X + @param y The current cursor Y + @param x1 The boundary X coordinate, set by function + @param y1 The boundary Y coordinate, set by function + @param w The boundary width, set by function + @param h The boundary height, set by function +*/ +/**************************************************************************/ +void Arduino_GFX::getTextBounds(const String &str, int16_t x, int16_t y, + int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) +{ + if (str.length() != 0) + { + getTextBounds(const_cast(str.c_str()), x, y, x1, y1, w, h); + } +} + +/**************************************************************************/ +/*! + @brief Helper to determine size of a PROGMEM string with current font/size. Pass string and a cursor position, returns UL corner and W,H. + @param str The flash-memory ascii string to measure + @param x The current cursor X + @param y The current cursor Y + @param x1 The boundary X coordinate, set by function + @param y1 The boundary Y coordinate, set by function + @param w The boundary width, set by function + @param h The boundary height, set by function +*/ +/**************************************************************************/ +void Arduino_GFX::getTextBounds(const __FlashStringHelper *str, + int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) +{ + uint8_t *s = (uint8_t *)str, c; + + *x1 = x; + *y1 = y; + *w = *h = 0; + + int16_t minx = _width, miny = _height, maxx = -1, maxy = -1; + + while ((c = pgm_read_byte(s++))) + charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy); + + if (maxx >= minx) + { + *x1 = minx; + *w = maxx - minx + 1; + } + if (maxy >= miny) + { + *y1 = miny; + *h = maxy - miny + 1; + } +} + +/**************************************************************************/ +/*! + @brief Invert the display (ideally using built-in hardware command) + @param i True if you want to invert, false to make 'normal' +*/ +/**************************************************************************/ +void Arduino_GFX::invertDisplay(bool i) +{ + // Do nothing, must be subclassed if supported by hardware + UNUSED(i); +} + +/**************************************************************************/ +/*! + @brief Turn on display after turned off +*/ +/**************************************************************************/ +void Arduino_GFX::displayOn() +{ +} + +/**************************************************************************/ +/*! + @brief Turn off display +*/ +/**************************************************************************/ +void Arduino_GFX::displayOff() +{ +} diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_GFX.h b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_GFX.h new file mode 100644 index 00000000..596c99ef --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_GFX.h @@ -0,0 +1,447 @@ +/* + * start rewrite from: + * https://github.com/adafruit/Adafruit-GFX-Library.git + */ +#ifndef _ARDUINO_GFX_H_ +#define _ARDUINO_GFX_H_ + +#include +#include +#include "Arduino_G.h" +#include "Arduino_DataBus.h" + +#if !defined(ATTINY_CORE) +#include "gfxfont.h" +#endif // !defined(ATTINY_CORE) + +#ifndef DEGTORAD +#define DEGTORAD 0.017453292519943295769236907684886F +#endif + + +#define RGB565(r, g, b) ((((r)&0xF8) << 8) | (((g)&0xFC) << 3) | ((b) >> 3)) +#define RGB16TO24(c) ((((uint32_t)c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x1F) << 3)) + +#define RGB565_BLACK RGB565(0, 0, 0) +#define RGB565_NAVY RGB565(0, 0, 123) +#define RGB565_DARKGREEN RGB565(0, 125, 0) +#define RGB565_DARKCYAN RGB565(0, 125, 123) +#define RGB565_MAROON RGB565(123, 0, 0) +#define RGB565_PURPLE RGB565(123, 0, 123) +#define RGB565_OLIVE RGB565(123, 125, 0) +#define RGB565_LIGHTGREY RGB565(198, 195, 198) +#define RGB565_DARKGREY RGB565(123, 125, 123) +#define RGB565_BLUE RGB565(0, 0, 255) +#define RGB565_GREEN RGB565(0, 255, 0) +#define RGB565_CYAN RGB565(0, 255, 255) +#define RGB565_RED RGB565(255, 0, 0) +#define RGB565_MAGENTA RGB565(255, 0, 255) +#define RGB565_YELLOW RGB565(255, 255, 0) +#define RGB565_WHITE RGB565(255, 255, 255) +#define RGB565_ORANGE RGB565(255, 165, 0) +#define RGB565_GREENYELLOW RGB565(173, 255, 41) +#define RGB565_PINK RGB565(255, 130, 198) + +// Color definitions +#ifndef DISABLE_COLOR_DEFINES +#define BLACK RGB565_BLACK +#define NAVY RGB565_NAVY +#define DARKGREEN RGB565_DARKGREEN +#define DARKCYAN RGB565_DARKCYAN +#define MAROON RGB565_MAROON +#define PURPLE RGB565_PURPLE +#define OLIVE RGB565_OLIVE +#define LIGHTGREY RGB565_LIGHTGREY +#define DARKGREY RGB565_DARKGREY +#define BLUE RGB565_BLUE +#define GREEN RGB565_GREEN +#define CYAN RGB565_CYAN +#define RED RGB565_RED +#define MAGENTA RGB565_MAGENTA +#define YELLOW RGB565_YELLOW +#define WHITE RGB565_WHITE +#define ORANGE RGB565_ORANGE +#define GREENYELLOW RGB565_GREENYELLOW +#define PINK RGB565_PINK +#endif + +// Many (but maybe not all) non-AVR board installs define macros +// for compatibility with existing PROGMEM-reading AVR code. +// Do our own checks and defines here for good measure... + +#ifndef pgm_read_byte +#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#endif +#ifndef pgm_read_word +#define pgm_read_word(addr) (*(const unsigned short *)(addr)) +#endif +#ifndef pgm_read_dword +#define pgm_read_dword(addr) (*(const unsigned long *)(addr)) +#endif +// workaround of a15 asm compile error +#ifdef ESP8266 +#undef pgm_read_word +#define pgm_read_word(addr) (*(const unsigned short *)(addr)) +#endif + +// Pointers are a peculiar case...typically 16-bit on AVR boards, +// 32 bits elsewhere. Try to accommodate both... + +#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF) +#define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr)) +#else +#define pgm_read_pointer(addr) ((void *)pgm_read_word(addr)) +#endif + +#ifndef _swap_uint8_t +#define _swap_uint8_t(a, b) \ + { \ + uint8_t t = a; \ + a = b; \ + b = t; \ + } +#endif + +#ifndef _swap_int16_t +#define _swap_int16_t(a, b) \ + { \ + int16_t t = a; \ + a = b; \ + b = t; \ + } +#endif + +#ifndef _diff +#define _diff(a, b) ((a > b) ? (a - b) : (b - a)) +#endif + +#ifndef _ordered_in_range +#define _ordered_in_range(v, a, b) ((a <= v) && (v <= b)) +#endif + +#ifndef _in_range +#define _in_range(v, a, b) ((a > b) ? _ordered_in_range(v, b, a) : _ordered_in_range(v, a, b)) +#endif + +#if !defined(ATTINY_CORE) +INLINE GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) +{ +#ifdef __AVR__ + return &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); +#else + // expression in __AVR__ section may generate "dereferencing type-punned pointer will break strict-aliasing rules" warning + // In fact, on other platforms (such as STM32) there is no need to do this pointer magic as program memory may be read in a usual way + // So expression may be simplified + return gfxFont->glyph + c; +#endif //__AVR__ +} + +INLINE uint8_t *pgm_read_bitmap_ptr(const GFXfont *gfxFont) +{ +#ifdef __AVR__ + return (uint8_t *)pgm_read_pointer(&gfxFont->bitmap); +#else + // expression in __AVR__ section generates "dereferencing type-punned pointer will break strict-aliasing rules" warning + // In fact, on other platforms (such as STM32) there is no need to do this pointer magic as program memory may be read in a usual way + // So expression may be simplified + return gfxFont->bitmap; +#endif //__AVR__ +} +#endif // !defined(ATTINY_CORE) + +/// A generic graphics superclass that can handle all sorts of drawing. At a minimum you can subclass and provide drawPixel(). At a maximum you can do a ton of overriding to optimize. Used for any/all Adafruit displays! +#if defined(LITTLE_FOOT_PRINT) +class Arduino_GFX : public Print +#else +class Arduino_GFX : public Print, public Arduino_G +#endif // !defined(LITTLE_FOOT_PRINT) +{ +public: + Arduino_GFX(int16_t w, int16_t h); // Constructor + + // This MUST be defined by the subclass: + virtual bool begin(int32_t speed = GFX_NOT_DEFINED) = 0; + virtual void writePixelPreclipped(int16_t x, int16_t y, uint16_t color) = 0; + + // TRANSACTION API / CORE DRAW API + // These MAY be overridden by the subclass to provide device-specific + // optimized code. Otherwise 'generic' versions are used. + virtual void startWrite(); + virtual void writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + virtual void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + virtual void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); + virtual void endWrite(void); + + // CONTROL API + // These MAY be overridden by the subclass to provide device-specific + // optimized code. Otherwise 'generic' versions are used. + virtual void setRotation(uint8_t r); + virtual void invertDisplay(bool i); + virtual void displayOn(); + virtual void displayOff(); + + // BASIC DRAW API + // These MAY be overridden by the subclass to provide device-specific + // optimized code. Otherwise 'generic' versions are used. + // It's good to implement those, even if using transaction API + void writePixel(int16_t x, int16_t y, uint16_t color); + void drawPixel(int16_t x, int16_t y, uint16_t color); + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void fillScreen(uint16_t color); + void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color); + void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color); + void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color); + void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color); + void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color); + void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color); + void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color); + void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color); + void drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color); + void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[], const uint8_t mask[], int16_t w, int16_t h); + void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h); + void draw16bitRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], const uint8_t mask[], int16_t w, int16_t h); + void draw24bitRGBBitmap(int16_t x, int16_t y, const uint8_t bitmap[], const uint8_t mask[], int16_t w, int16_t h); + void draw24bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h); + void getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); + void getTextBounds(const __FlashStringHelper *s, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); + void getTextBounds(const String &str, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); + void setTextSize(uint8_t s); + void setTextSize(uint8_t sx, uint8_t sy); + void setTextSize(uint8_t sx, uint8_t sy, uint8_t pixel_margin); + +#if !defined(ATTINY_CORE) + void setFont(const GFXfont *f = NULL); +#if defined(U8G2_FONT_SUPPORT) + void setFont(const uint8_t *font); + void setUTF8Print(bool isEnable); + uint16_t u8g2_font_get_word(const uint8_t *font, uint8_t offset); + uint8_t u8g2_font_decode_get_unsigned_bits(uint8_t cnt); + int8_t u8g2_font_decode_get_signed_bits(uint8_t cnt); + void u8g2_font_decode_len(uint8_t len, uint8_t is_foreground, uint16_t color, uint16_t bg); +#endif // defined(U8G2_FONT_SUPPORT) + virtual void flush(void); +#endif // !defined(ATTINY_CORE) + + // adopt from LovyanGFX + void drawEllipse(int16_t x, int16_t y, int16_t rx, int16_t ry, uint16_t color); + void drawEllipseHelper(int32_t x, int32_t y, int32_t rx, int32_t ry, uint8_t cornername, uint16_t color); + void fillEllipse(int16_t x, int16_t y, int16_t rx, int16_t ry, uint16_t color); + void fillEllipseHelper(int32_t x, int32_t y, int32_t rx, int32_t ry, uint8_t cornername, int16_t delta, uint16_t color); + void drawArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color); + void fillArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color); + void fillArcHelper(int16_t cx, int16_t cy, int16_t oradius, int16_t iradius, float start, float end, uint16_t color); + +// TFT optimization code, too big for ATMEL family +#if defined(LITTLE_FOOT_PRINT) + void writeSlashLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); + void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color, uint16_t bg); + void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg); + void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h); + void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h); + void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip = 0); + void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, uint8_t chroma_key, int16_t w, int16_t h, int16_t x_skip = 0); + void draw3bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h); + void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h); + void draw16bitRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h); + void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h); + void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, uint16_t transparent_color, int16_t w, int16_t h); + void draw16bitBeRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h); + void draw24bitRGBBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h); + void draw24bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h); + void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg); +#else // !defined(LITTLE_FOOT_PRINT) + virtual void writeSlashLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); + virtual void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color, uint16_t bg); + virtual void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg); + virtual void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h); + virtual void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h); + virtual void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip = 0); + virtual void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, uint8_t chroma_key, int16_t w, int16_t h, int16_t x_skip = 0); + virtual void draw3bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h); + virtual void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h); + virtual void draw16bitRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h); + virtual void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h); + virtual void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, uint16_t transparent_color, int16_t w, int16_t h); + virtual void draw16bitBeRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h); + virtual void draw24bitRGBBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h); + virtual void draw24bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h); + virtual void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg); +#endif // !defined(LITTLE_FOOT_PRINT) + + /**********************************************************************/ + /*! + @brief Set text cursor location + @param x X coordinate in pixels + @param y Y coordinate in pixels + */ + /**********************************************************************/ + void setCursor(int16_t x, int16_t y) + { + cursor_x = x; + cursor_y = y; + } + + /**********************************************************************/ + /*! + @brief Set text font color with transparant background + @param c 16-bit 5-6-5 Color to draw text with + @note For 'transparent' background, background and foreground + are set to same color rather than using a separate flag. + */ + /**********************************************************************/ + void setTextColor(uint16_t c) { textcolor = textbgcolor = c; } + + /**********************************************************************/ + /*! + @brief Set text font color with custom background color + @param c 16-bit 5-6-5 Color to draw text with + @param bg 16-bit 5-6-5 Color to draw background/fill with + */ + /**********************************************************************/ + void setTextColor(uint16_t c, uint16_t bg) + { + textcolor = c; + textbgcolor = bg; + } + + /**********************************************************************/ + /*! + @brief Set whether text that is too long for the screen width should + automatically wrap around to the next line (else clip right). + @param w true for wrapping, false for clipping + */ + /**********************************************************************/ + void setTextWrap(bool w) { wrap = w; } + + virtual size_t write(uint8_t); + + /************************************************************************/ + /*! + @brief Get width of the display, accounting for current rotation + @returns Width in pixels + */ + /************************************************************************/ + int16_t width(void) const { return _width; }; + + /************************************************************************/ + /*! + @brief Get height of the display, accounting for current rotation + @returns Height in pixels + */ + /************************************************************************/ + int16_t height(void) const { return _height; } + + /************************************************************************/ + /*! + @brief Get rotation setting for display + @returns 0 thru 3 corresponding to 4 cardinal rotations + */ + /************************************************************************/ + uint8_t getRotation(void) const { return _rotation; } + + // get current cursor position (get rotation safe maximum values, + // using: width() for x, height() for y) + /************************************************************************/ + /*! + @brief Get text cursor X location + @returns X coordinate in pixels + */ + /************************************************************************/ + int16_t getCursorX(void) const { return cursor_x; } + + /************************************************************************/ + /*! + @brief Get text cursor Y location + @returns Y coordinate in pixels + */ + /************************************************************************/ + int16_t getCursorY(void) const { return cursor_y; }; + + /*! + @brief Given 8-bit red, green and blue values, return a 'packed' + 16-bit color value in '565' RGB format (5 bits red, 6 bits + green, 5 bits blue). This is just a mathematical operation, + no hardware is touched. + @param red 8-bit red brightnesss (0 = off, 255 = max). + @param green 8-bit green brightnesss (0 = off, 255 = max). + @param blue 8-bit blue brightnesss (0 = off, 255 = max). + @return 'Packed' 16-bit color value (565 format). + */ + uint16_t color565(uint8_t red, uint8_t green, uint8_t blue) + { + return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3); + } + +protected: + void charBounds(char c, int16_t *x, int16_t *y, int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy); + int16_t + _width, ///< Display width as modified by current rotation + _height, ///< Display height as modified by current rotation + _max_x, ///< x zero base bound (_width - 1) + _max_y, ///< y zero base bound (_height - 1) + cursor_x, ///< x location to start print()ing text + cursor_y; ///< y location to start print()ing text + uint16_t + textcolor, ///< 16-bit background color for print() + textbgcolor; ///< 16-bit text color for print() + uint8_t + textsize_x, ///< Desired magnification in X-axis of text to print() + textsize_y, ///< Desired magnification in Y-axis of text to print() + text_pixel_margin, ///< Margin for each text pixel + _rotation; ///< Display rotation (0 thru 3) + bool + wrap; ///< If set, 'wrap' text at right edge of display +#if !defined(ATTINY_CORE) + GFXfont *gfxFont; ///< Pointer to special font +#endif // !defined(ATTINY_CORE) + +#if defined(U8G2_FONT_SUPPORT) + uint8_t *u8g2Font; + bool _enableUTF8Print = false; + uint8_t _utf8_state = 0; + uint16_t _encoding; + + uint8_t _u8g2_glyph_cnt; + uint8_t _u8g2_bits_per_0; + uint8_t _u8g2_bits_per_1; + uint8_t _u8g2_bits_per_char_width; + uint8_t _u8g2_bits_per_char_height; + uint8_t _u8g2_bits_per_char_x; + uint8_t _u8g2_bits_per_char_y; + uint8_t _u8g2_bits_per_delta_x; + int8_t _u8g2_max_char_width; + int8_t _u8g2_max_char_height; + uint16_t _u8g2_start_pos_upper_A; + uint16_t _u8g2_start_pos_lower_a; + uint16_t _u8g2_start_pos_unicode; + uint8_t _u8g2_first_char; + + uint8_t _u8g2_char_width; + uint8_t _u8g2_char_height; + int8_t _u8g2_char_x; + int8_t _u8g2_char_y; + int8_t _u8g2_delta_x; + + int8_t _u8g2_dx; + int8_t _u8g2_dy; + uint16_t _u8g2_target_x; + uint16_t _u8g2_target_y; + + const uint8_t *_u8g2_decode_ptr; + uint8_t _u8g2_decode_bit_pos; +#endif // defined(U8G2_FONT_SUPPORT) + +#if defined(LITTLE_FOOT_PRINT) + int16_t + WIDTH, ///< This is the 'raw' display width - never changes + HEIGHT; ///< This is the 'raw' display height - never changes +#endif // defined(LITTLE_FOOT_PRINT) +}; + +#endif // _ARDUINO_GFX_H_ diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_GFX_Library.h b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_GFX_Library.h new file mode 100644 index 00000000..10c709f4 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/Arduino_GFX_Library.h @@ -0,0 +1,208 @@ +#ifndef _ARDUINO_GFX_LIBRARIES_H_ +#define _ARDUINO_GFX_LIBRARIES_H_ + +#include "Arduino_DataBus.h" +#include "databus/Arduino_ESP32RGBPanel.h" +#include "databus/Arduino_XL9535SWSPI.h" + +#include "Arduino_GFX.h" // Core graphics library + +#include "display/Arduino_RGB_Display.h" + +#if defined(ARDUINO_ARCH_SAMD) && defined(SEEED_GROVE_UI_WIRELESS) +#define DISPLAY_DEV_KIT +#define WIO_TERMINAL +#define DF_GFX_CS LCD_SS_PIN +#define DF_GFX_DC LCD_DC +#define DF_GFX_RST GFX_NOT_DEFINED +#define DF_GFX_BL LCD_BACKLIGHT +#elif defined(ARDUINO_ESP32_S3_BOX) +#define DISPLAY_DEV_KIT +#define ESP32_S3_BOX +#define DF_GFX_SCK TFT_CLK +#define DF_GFX_MOSI TFT_MOSI +#define DF_GFX_MISO TFT_MISO +#define DF_GFX_CS TFT_CS +#define DF_GFX_DC TFT_DC +#define DF_GFX_RST TFT_RST +#define DF_GFX_BL TFT_BL +#elif defined(ARDUINO_M5Stack_Core_ESP32) || defined(ARDUINO_M5STACK_FIRE) +#define DISPLAY_DEV_KIT +#define M5STACK_CORE +#define DF_GFX_SCK 18 +#define DF_GFX_MOSI 23 +#define DF_GFX_MISO 19 +#define DF_GFX_CS 14 +#define DF_GFX_DC 27 +#define DF_GFX_RST 33 +#define DF_GFX_BL 32 +#elif defined(ARDUINO_M5Stack_ATOMS3) +#define DISPLAY_DEV_KIT +#define M5STACK_ATOMS3 +#define DF_GFX_SCK 17 +#define DF_GFX_MOSI 21 +#define DF_GFX_MISO GFX_NOT_DEFINED +#define DF_GFX_CS 15 +#define DF_GFX_DC 33 +#define DF_GFX_RST 34 +#define DF_GFX_BL 16 +#elif defined(ARDUINO_ODROID_ESP32) +#define DISPLAY_DEV_KIT +#define ODROID_GO +#define DF_GFX_SCK 18 +#define DF_GFX_MOSI 23 +#define DF_GFX_MISO 19 +#define DF_GFX_CS 5 +#define DF_GFX_DC 21 +#define DF_GFX_RST GFX_NOT_DEFINED +#define DF_GFX_BL 14 +/* TTGO T-Watch */ +#elif defined(ARDUINO_T) || defined(ARDUINO_TWATCH_BASE) || defined(ARDUINO_TWATCH_2020_V1) || defined(ARDUINO_TWATCH_2020_V2) +#define DISPLAY_DEV_KIT +#define TTGO_T_WATCH +#define DF_GFX_SCK 18 +#define DF_GFX_MOSI 19 +#define DF_GFX_MISO GFX_NOT_DEFINED +#define DF_GFX_CS 5 +#define DF_GFX_DC 27 +#define DF_GFX_RST GFX_NOT_DEFINED +#define DF_GFX_BL 12 +/* Waveshare RP2040-LCD-1.28 */ +#elif defined(ARDUINO_WAVESHARE_RP2040_LCD_1_28) +#define DISPLAY_DEV_KIT +#define WAVESHARE_RP2040_LCD_1_28 +#define DF_GFX_SCK 10 +#define DF_GFX_MOSI 11 +#define DF_GFX_MISO 12 +#define DF_GFX_CS 9 +#define DF_GFX_DC 8 +#define DF_GFX_RST 12 +#define DF_GFX_BL 25 +#define DF_GFX_SPI spi1 +#elif defined(ARDUINO_ARCH_NRF52840) +#define DF_GFX_SCK 13 +#define DF_GFX_MOSI 11 +#define DF_GFX_MISO 12 +#define DF_GFX_CS 9 +#define DF_GFX_DC 8 +#define DF_GFX_RST 7 +#define DF_GFX_BL 6 +#elif defined(__IMXRT1052__) || defined(__IMXRT1062__) +// PJRC Teensy 4.x +#define DF_GFX_SCK 13 +#define DF_GFX_MOSI 11 +#define DF_GFX_MISO 12 +#define DF_GFX_CS 39 // GFX_NOT_DEFINED for display without CS pin +#define DF_GFX_DC 41 +#define DF_GFX_RST 40 +#define DF_GFX_BL 22 +#elif defined(ARDUINO_BLACKPILL_F411CE) +#define DF_GFX_SCK 5 +#define DF_GFX_MOSI 7 +#define DF_GFX_MISO 6 +#define DF_GFX_CS 4 +#define DF_GFX_DC 3 +#define DF_GFX_RST 2 +#define DF_GFX_BL 1 +#elif defined(TARGET_RP2040) +#define DF_GFX_SCK 18 +#define DF_GFX_MOSI 19 +#define DF_GFX_MISO 16 +#define DF_GFX_CS 17 +#define DF_GFX_DC 27 +#define DF_GFX_RST 26 +#define DF_GFX_BL 28 +#define DF_GFX_SPI spi0 +#elif defined(ESP32) && (CONFIG_IDF_TARGET_ESP32) +#define DF_GFX_SCK 18 +#define DF_GFX_MOSI 23 +#define DF_GFX_MISO GFX_NOT_DEFINED +#define DF_GFX_CS 5 +#define DF_GFX_DC 27 +#define DF_GFX_RST 33 +#define DF_GFX_BL 22 +#elif defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S2) +#define DF_GFX_SCK 36 +#define DF_GFX_MOSI 35 +#define DF_GFX_MISO GFX_NOT_DEFINED +#define DF_GFX_CS 34 +#define DF_GFX_DC 38 +#define DF_GFX_RST 33 +#define DF_GFX_BL 21 +#elif defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3) +#define DF_GFX_SCK 36 +#define DF_GFX_MOSI 35 +#define DF_GFX_MISO GFX_NOT_DEFINED +#define DF_GFX_CS 40 +#define DF_GFX_DC 41 +#define DF_GFX_RST 42 +#define DF_GFX_BL 48 +#elif defined(ESP32) && (CONFIG_IDF_TARGET_ESP32C3) +#define DF_GFX_SCK 4 +#define DF_GFX_MOSI 6 +#define DF_GFX_MISO GFX_NOT_DEFINED +#define DF_GFX_CS 7 +#define DF_GFX_DC 2 +#define DF_GFX_RST 1 +#define DF_GFX_BL 3 +#elif defined(ESP8266) +#define DF_GFX_SCK 14 +#define DF_GFX_MOSI 13 +#define DF_GFX_MISO 12 +#define DF_GFX_CS 15 +#define DF_GFX_DC 4 +#define DF_GFX_RST 2 +#define DF_GFX_BL 5 +#elif defined(RTL8722DM) +#if defined(BOARD_RTL8720DN_BW16) +#define DF_GFX_SCK 10 +#define DF_GFX_MOSI 12 +#define DF_GFX_MISO 11 +#define DF_GFX_CS 9 +#define DF_GFX_DC 8 +#define DF_GFX_RST 6 +#define DF_GFX_BL 3 +#elif defined(BOARD_RTL8722DM) +#define DF_GFX_SCK 13 +#define DF_GFX_MOSI 11 +#define DF_GFX_MISO 12 +#define DF_GFX_CS 18 +#define DF_GFX_DC 17 +#define DF_GFX_RST 22 +#define DF_GFX_BL 23 +#elif defined(BOARD_RTL8722DM_MINI) +#define DF_GFX_SCK 11 +#define DF_GFX_MOSI 9 +#define DF_GFX_MISO 10 +#define DF_GFX_CS 12 +#define DF_GFX_DC 14 +#define DF_GFX_RST 15 +#define DF_GFX_BL 13 +#else // old version +#define DF_GFX_SCK 19 +#define DF_GFX_MOSI 21 +#define DF_GFX_MISO 20 +#define DF_GFX_CS 18 // GFX_NOT_DEFINED for display without CS pin +#define DF_GFX_DC 17 +#define DF_GFX_RST 2 +#define DF_GFX_BL 23 +#endif +#elif defined(SEEED_XIAO_M0) +#define DF_GFX_SCK 8 +#define DF_GFX_MOSI 10 +#define DF_GFX_MISO 9 +#define DF_GFX_CS 3 // GFX_NOT_DEFINED for display without CS pin +#define DF_GFX_DC 2 +#define DF_GFX_RST 1 +#define DF_GFX_BL 0 +#else // default pins for Arduino Nano, Mini, Micro and more +#define DF_GFX_SCK 13 +#define DF_GFX_MOSI 11 +#define DF_GFX_MISO 12 +#define DF_GFX_CS 9 +#define DF_GFX_DC 8 +#define DF_GFX_RST 7 +#define DF_GFX_BL 6 +#endif + +#endif // _ARDUINO_GFX_LIBRARIES_H_ diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/databus/Arduino_ESP32RGBPanel.cpp b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/databus/Arduino_ESP32RGBPanel.cpp new file mode 100644 index 00000000..265be506 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/databus/Arduino_ESP32RGBPanel.cpp @@ -0,0 +1,129 @@ +#include "Arduino_ESP32RGBPanel.h" + +#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3) + +Arduino_ESP32RGBPanel::Arduino_ESP32RGBPanel( + int8_t de, int8_t vsync, int8_t hsync, int8_t pclk, + int8_t r0, int8_t r1, int8_t r2, int8_t r3, int8_t r4, + int8_t g0, int8_t g1, int8_t g2, int8_t g3, int8_t g4, int8_t g5, + int8_t b0, int8_t b1, int8_t b2, int8_t b3, int8_t b4, + uint16_t hsync_polarity, uint16_t hsync_front_porch, uint16_t hsync_pulse_width, uint16_t hsync_back_porch, + uint16_t vsync_polarity, uint16_t vsync_front_porch, uint16_t vsync_pulse_width, uint16_t vsync_back_porch, + uint16_t pclk_active_neg, int32_t prefer_speed, bool useBigEndian, + uint16_t de_idle_high, uint16_t pclk_idle_high) + : _de(de), _vsync(vsync), _hsync(hsync), _pclk(pclk), + _r0(r0), _r1(r1), _r2(r2), _r3(r3), _r4(r4), + _g0(g0), _g1(g1), _g2(g2), _g3(g3), _g4(g4), _g5(g5), + _b0(b0), _b1(b1), _b2(b2), _b3(b3), _b4(b4), + _hsync_polarity(hsync_polarity), _hsync_front_porch(hsync_front_porch), _hsync_pulse_width(hsync_pulse_width), _hsync_back_porch(hsync_back_porch), + _vsync_polarity(vsync_polarity), _vsync_front_porch(vsync_front_porch), _vsync_pulse_width(vsync_pulse_width), _vsync_back_porch(vsync_back_porch), + _pclk_active_neg(pclk_active_neg), _prefer_speed(prefer_speed), _useBigEndian(useBigEndian), + _de_idle_high(de_idle_high), _pclk_idle_high(pclk_idle_high) +{ +} + +bool Arduino_ESP32RGBPanel::begin(int32_t speed) +{ + if (speed == GFX_NOT_DEFINED) + { +#ifdef CONFIG_SPIRAM_MODE_QUAD + _speed = 6000000L; +#else + _speed = 12000000L; +#endif + } + else + { + _speed = speed; + } + + return true; +} + +uint16_t *Arduino_ESP32RGBPanel::getFrameBuffer(int16_t w, int16_t h) +{ + esp_lcd_rgb_panel_config_t *_panel_config = (esp_lcd_rgb_panel_config_t *)heap_caps_calloc(1, sizeof(esp_lcd_rgb_panel_config_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + + _panel_config->clk_src = LCD_CLK_SRC_PLL160M; + + _panel_config->timings.pclk_hz = (_prefer_speed == GFX_NOT_DEFINED) ? _speed : _prefer_speed; + _panel_config->timings.h_res = w; + _panel_config->timings.v_res = h; + // The following parameters should refer to LCD spec + _panel_config->timings.hsync_pulse_width = _hsync_pulse_width; + _panel_config->timings.hsync_back_porch = _hsync_back_porch; + _panel_config->timings.hsync_front_porch = _hsync_front_porch; + _panel_config->timings.vsync_pulse_width = _vsync_pulse_width; + _panel_config->timings.vsync_back_porch = _vsync_back_porch; + _panel_config->timings.vsync_front_porch = _vsync_front_porch; + _panel_config->timings.flags.hsync_idle_low = (_hsync_polarity == 0) ? 1 : 0; + _panel_config->timings.flags.vsync_idle_low = (_vsync_polarity == 0) ? 1 : 0; + _panel_config->timings.flags.de_idle_high = _de_idle_high; + _panel_config->timings.flags.pclk_active_neg = _pclk_active_neg; + _panel_config->timings.flags.pclk_idle_high = _pclk_idle_high; + + _panel_config->data_width = 16; // RGB565 in parallel mode, thus 16bit in width + _panel_config->sram_trans_align = 8; + _panel_config->psram_trans_align = 64; + _panel_config->hsync_gpio_num = _hsync; + _panel_config->vsync_gpio_num = _vsync; + _panel_config->de_gpio_num = _de; + _panel_config->pclk_gpio_num = _pclk; + + if (_useBigEndian) + { + _panel_config->data_gpio_nums[0] = _g3; + _panel_config->data_gpio_nums[1] = _g4; + _panel_config->data_gpio_nums[2] = _g5; + _panel_config->data_gpio_nums[3] = _r0; + _panel_config->data_gpio_nums[4] = _r1; + _panel_config->data_gpio_nums[5] = _r2; + _panel_config->data_gpio_nums[6] = _r3; + _panel_config->data_gpio_nums[7] = _r4; + _panel_config->data_gpio_nums[8] = _b0; + _panel_config->data_gpio_nums[9] = _b1; + _panel_config->data_gpio_nums[10] = _b2; + _panel_config->data_gpio_nums[11] = _b3; + _panel_config->data_gpio_nums[12] = _b4; + _panel_config->data_gpio_nums[13] = _g0; + _panel_config->data_gpio_nums[14] = _g1; + _panel_config->data_gpio_nums[15] = _g2; + } + else + { + _panel_config->data_gpio_nums[0] = _b0; + _panel_config->data_gpio_nums[1] = _b1; + _panel_config->data_gpio_nums[2] = _b2; + _panel_config->data_gpio_nums[3] = _b3; + _panel_config->data_gpio_nums[4] = _b4; + _panel_config->data_gpio_nums[5] = _g0; + _panel_config->data_gpio_nums[6] = _g1; + _panel_config->data_gpio_nums[7] = _g2; + _panel_config->data_gpio_nums[8] = _g3; + _panel_config->data_gpio_nums[9] = _g4; + _panel_config->data_gpio_nums[10] = _g5; + _panel_config->data_gpio_nums[11] = _r0; + _panel_config->data_gpio_nums[12] = _r1; + _panel_config->data_gpio_nums[13] = _r2; + _panel_config->data_gpio_nums[14] = _r3; + _panel_config->data_gpio_nums[15] = _r4; + } + + _panel_config->disp_gpio_num = GPIO_NUM_NC; + + _panel_config->flags.disp_active_low = 0; + _panel_config->flags.relax_on_idle = 0; + _panel_config->flags.fb_in_psram = 1; // allocate frame buffer in PSRAM + + ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(_panel_config, &_panel_handle)); + ESP_ERROR_CHECK(esp_lcd_panel_reset(_panel_handle)); + ESP_ERROR_CHECK(esp_lcd_panel_init(_panel_handle)); + + uint16_t color = random(0xffff); + ESP_ERROR_CHECK(_panel_handle->draw_bitmap(_panel_handle, 0, 0, 1, 1, &color)); + + _rgb_panel = __containerof(_panel_handle, esp_rgb_panel_t, base); + + return (uint16_t *)_rgb_panel->fb; +} +#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3) diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/databus/Arduino_ESP32RGBPanel.h b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/databus/Arduino_ESP32RGBPanel.h new file mode 100644 index 00000000..3f701116 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/databus/Arduino_ESP32RGBPanel.h @@ -0,0 +1,100 @@ +#include "Arduino_DataBus.h" + +#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3) + +#ifndef _ARDUINO_ESP32RGBPANEL_H_ +#define _ARDUINO_ESP32RGBPANEL_H_ + +#include "esp_lcd_panel_io.h" +#include "esp_lcd_panel_rgb.h" +#include "esp_lcd_panel_vendor.h" +#include "esp_lcd_panel_ops.h" +#include "esp_lcd_panel_interface.h" +#include "esp_private/gdma.h" +#include "esp_pm.h" +#include "hal/dma_types.h" + +#include "hal/lcd_hal.h" +#include "hal/lcd_ll.h" + +#include "esp32s3/rom/cache.h" +// This function is located in ROM (also see esp_rom/${target}/ld/${target}.rom.ld) +extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size); + +// extract from esp-idf esp_lcd_rgb_panel.c +struct esp_rgb_panel_t +{ + esp_lcd_panel_t base; // Base class of generic lcd panel + int panel_id; // LCD panel ID + lcd_hal_context_t hal; // Hal layer object + size_t data_width; // Number of data lines (e.g. for RGB565, the data width is 16) + size_t sram_trans_align; // Alignment for framebuffer that allocated in SRAM + size_t psram_trans_align; // Alignment for framebuffer that allocated in PSRAM + int disp_gpio_num; // Display control GPIO, which is used to perform action like "disp_off" + intr_handle_t intr; // LCD peripheral interrupt handle + esp_pm_lock_handle_t pm_lock; // Power management lock + size_t num_dma_nodes; // Number of DMA descriptors that used to carry the frame buffer + uint8_t *fb; // Frame buffer + size_t fb_size; // Size of frame buffer + int data_gpio_nums[SOC_LCD_RGB_DATA_WIDTH]; // GPIOs used for data lines, we keep these GPIOs for action like "invert_color" + size_t resolution_hz; // Peripheral clock resolution + esp_lcd_rgb_timing_t timings; // RGB timing parameters (e.g. pclk, sync pulse, porch width) + gdma_channel_handle_t dma_chan; // DMA channel handle + esp_lcd_rgb_panel_frame_trans_done_cb_t on_frame_trans_done; // Callback, invoked after frame trans done + void *user_ctx; // Reserved user's data of callback functions + int x_gap; // Extra gap in x coordinate, it's used when calculate the flush window + int y_gap; // Extra gap in y coordinate, it's used when calculate the flush window + struct + { + unsigned int disp_en_level : 1; // The level which can turn on the screen by `disp_gpio_num` + unsigned int stream_mode : 1; // If set, the LCD transfers data continuously, otherwise, it stops refreshing the LCD when transaction done + unsigned int fb_in_psram : 1; // Whether the frame buffer is in PSRAM + } flags; + dma_descriptor_t dma_nodes[]; // DMA descriptor pool of size `num_dma_nodes` +}; + +class Arduino_ESP32RGBPanel +{ +public: + Arduino_ESP32RGBPanel( + int8_t de, int8_t vsync, int8_t hsync, int8_t pclk, + int8_t r0, int8_t r1, int8_t r2, int8_t r3, int8_t r4, + int8_t g0, int8_t g1, int8_t g2, int8_t g3, int8_t g4, int8_t g5, + int8_t b0, int8_t b1, int8_t b2, int8_t b3, int8_t b4, + uint16_t hsync_polarity, uint16_t hsync_front_porch, uint16_t hsync_pulse_width, uint16_t hsync_back_porch, + uint16_t vsync_polarity, uint16_t vsync_front_porch, uint16_t vsync_pulse_width, uint16_t vsync_back_porch, + uint16_t pclk_active_neg = 0, int32_t prefer_speed = GFX_NOT_DEFINED, bool useBigEndian = false, + uint16_t de_idle_high = 0, uint16_t pclk_idle_high = 0); + + bool begin(int32_t speed = GFX_NOT_DEFINED); + + uint16_t *getFrameBuffer(int16_t w, int16_t h); + +protected: +private: + int32_t _speed; + int8_t _de, _vsync, _hsync, _pclk; + int8_t _r0, _r1, _r2, _r3, _r4; + int8_t _g0, _g1, _g2, _g3, _g4, _g5; + int8_t _b0, _b1, _b2, _b3, _b4; + uint16_t _hsync_polarity; + uint16_t _hsync_front_porch; + uint16_t _hsync_pulse_width; + uint16_t _hsync_back_porch; + uint16_t _vsync_polarity; + uint16_t _vsync_front_porch; + uint16_t _vsync_pulse_width; + uint16_t _vsync_back_porch; + uint16_t _pclk_active_neg; + int32_t _prefer_speed; + bool _useBigEndian; + uint16_t _de_idle_high; + uint16_t _pclk_idle_high; + + esp_lcd_panel_handle_t _panel_handle = NULL; + esp_rgb_panel_t *_rgb_panel; +}; + +#endif // _ARDUINO_ESP32RGBPANEL_H_ + +#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3) diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/databus/Arduino_XL9535SWSPI.cpp b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/databus/Arduino_XL9535SWSPI.cpp new file mode 100644 index 00000000..2fd54af3 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/databus/Arduino_XL9535SWSPI.cpp @@ -0,0 +1,276 @@ +#include "Arduino_XL9535SWSPI.h" + +Arduino_XL9535SWSPI::Arduino_XL9535SWSPI(int8_t sda, int8_t scl, int8_t pwd, int8_t cs, int8_t sck, int8_t mosi, TwoWire *wire) + : _sda(sda), _scl(scl), _pwd(pwd), _cs(cs), _sck(sck), _mosi(mosi), _wire(wire) +{ +} + +bool Arduino_XL9535SWSPI::begin(int32_t speed, int8_t dataMode) +{ + UNUSED(speed); + UNUSED(dataMode); + + _address = XL9535_IIC_ADDRESS; + _wire->beginTransmission(_address); + if (!_wire->endTransmission()) + { + Serial.println("Found xl9535"); + is_found = true; + + if (_pwd != GFX_NOT_DEFINED) + { + this->pinMode(_pwd, OUTPUT); + } + this->pinMode(_cs, OUTPUT); + this->pinMode(_sck, OUTPUT); + this->pinMode(_mosi, OUTPUT); + + if (_pwd != GFX_NOT_DEFINED) + { + this->digitalWrite(_pwd, 1); + } + this->digitalWrite(_cs, 1); + this->digitalWrite(_sck, 1); + this->digitalWrite(_mosi, 1); + + // while(1) + // { + // this->digitalWrite(4, 0); + // delay(1000); + // this->digitalWrite(4, 1); + // delay(1000); + // } + + // this->digitalWrite(_cs, 0); + // this->digitalWrite(5, 1); + // delay(100); + // this->digitalWrite(5, 0); + // delay(800); + // this->digitalWrite(5, 1); + // delay(800); + // this->digitalWrite(_cs, 1); + } + else + { + Serial.println("xl9535 not found"); + is_found = false; + } + + return true; +} + +void Arduino_XL9535SWSPI::beginWrite() +{ + this->digitalWrite(_cs, 0); +} + +void Arduino_XL9535SWSPI::endWrite() +{ + this->digitalWrite(_cs, 1); +} + +void Arduino_XL9535SWSPI::writeCommand(uint8_t c) +{ + // D/C bit, command + this->digitalWrite(_mosi, 0); + this->digitalWrite(_sck, 0); + this->digitalWrite(_sck, 1); + + uint8_t bit = 0x80; + while (bit) + { + if (c & bit) + { + this->digitalWrite(_mosi, 1); + } + else + { + this->digitalWrite(_mosi, 0); + } + this->digitalWrite(_sck, 0); + bit >>= 1; + this->digitalWrite(_sck, 1); + } +} + +void Arduino_XL9535SWSPI::writeCommand16(uint16_t) +{ +} + +void Arduino_XL9535SWSPI::write(uint8_t d) +{ + // D/C bit, data + this->digitalWrite(_mosi, 1); + this->digitalWrite(_sck, 0); + this->digitalWrite(_sck, 1); + + uint8_t bit = 0x80; + while (bit) + { + if (d & bit) + { + this->digitalWrite(_mosi, 1); + } + else + { + this->digitalWrite(_mosi, 0); + } + this->digitalWrite(_sck, 0); + bit >>= 1; + this->digitalWrite(_sck, 1); + } +} + +void Arduino_XL9535SWSPI::write16(uint16_t) +{ + // not implemented +} + +void Arduino_XL9535SWSPI::writeRepeat(uint16_t p, uint32_t len) +{ + // not implemented +} + +void Arduino_XL9535SWSPI::writePixels(uint16_t *data, uint32_t len) +{ + // not implemented +} + +#if !defined(LITTLE_FOOT_PRINT) +void Arduino_XL9535SWSPI::writeBytes(uint8_t *data, uint32_t len) +{ + // not implemented +} +#endif // !defined(LITTLE_FOOT_PRINT) + +void Arduino_XL9535SWSPI::writeRegister(uint8_t reg, uint8_t *data, size_t len) +{ + _wire->beginTransmission(_address); + _wire->write(reg); + for (size_t i = 0; i < len; i++) + { + _wire->write(data[i]); + } + _wire->endTransmission(); +} + +uint8_t Arduino_XL9535SWSPI::readRegister(uint8_t reg, uint8_t *data, size_t len) +{ + _wire->beginTransmission(_address); + _wire->write(reg); + _wire->endTransmission(); + _wire->requestFrom(_address, len); + size_t index = 0; + while (index < len) + data[index++] = _wire->read(); + return 0; +} + +void Arduino_XL9535SWSPI::pinMode(uint8_t pin, uint8_t mode) +{ + if (is_found) + { + uint8_t port = 0; + if (pin > 7) + { + this->readRegister(XL9535_CONFIG_PORT_1_REG, &port, 1); + if (mode == OUTPUT) + { + port = port & (~(1 << (pin - 10))); + } + else + { + port = port | (1 << (pin - 10)); + } + this->writeRegister(XL9535_CONFIG_PORT_1_REG, &port, 1); + } + else + { + this->readRegister(XL9535_CONFIG_PORT_0_REG, &port, 1); + if (mode == OUTPUT) + { + port = port & (~(1 << pin)); + } + else + { + port = port | (1 << pin); + } + this->writeRegister(XL9535_CONFIG_PORT_0_REG, &port, 1); + } + } + else + { + Serial.println("xl9535 not found"); + } +} +void Arduino_XL9535SWSPI::pinMode8(uint8_t port, uint8_t pin, uint8_t mode) +{ + if (is_found) + { + uint8_t _pin = (mode != OUTPUT) ? pin : ~pin; + if (port) + { + this->writeRegister(XL9535_CONFIG_PORT_1_REG, &_pin, 1); + } + else + { + this->writeRegister(XL9535_CONFIG_PORT_0_REG, &_pin, 1); + } + } + else + { + Serial.println("xl9535 not found"); + } +} + +void Arduino_XL9535SWSPI::digitalWrite(uint8_t pin, uint8_t val) +{ + if (is_found) + { + uint8_t port = 0; + uint8_t reg_data = 0; + if (pin > 7) + { + this->readRegister(XL9535_OUTPUT_PORT_1_REG, ®_data, 1); + reg_data = reg_data & (~(1 << (pin - 10))); + port = reg_data | val << (pin - 10); + this->writeRegister(XL9535_OUTPUT_PORT_1_REG, &port, 1); + } + else + { + this->readRegister(XL9535_OUTPUT_PORT_0_REG, ®_data, 1); + reg_data = reg_data & (~(1 << pin)); + port = reg_data | val << pin; + this->writeRegister(XL9535_OUTPUT_PORT_0_REG, &port, 1); + } + } + else + { + Serial.println("xl9535 not found"); + } +} + +int Arduino_XL9535SWSPI::digitalRead(uint8_t pin) +{ + if (is_found) + { + int state = 0; + uint8_t port = 0; + if (pin > 7) + { + this->readRegister(XL9535_INPUT_PORT_1_REG, &port, 1); + state = port >> (pin - 10) & 0x01 ? 1 : 0; + } + else + { + this->readRegister(XL9535_INPUT_PORT_0_REG, &port, 1); + state = port >> pin & 0x01 ? 1 : 0; + } + return state; + } + else + { + Serial.println("xl9535 not found"); + } + return 0; +} diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/databus/Arduino_XL9535SWSPI.h b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/databus/Arduino_XL9535SWSPI.h new file mode 100644 index 00000000..9c838d90 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/databus/Arduino_XL9535SWSPI.h @@ -0,0 +1,57 @@ +#ifndef _ARDUINO_XL9535SWSPI_H_ +#define _ARDUINO_XL9535SWSPI_H_ + +#include + +#include "Arduino_DataBus.h" + +#define XL9535_IIC_ADDRESS 0X20 + +#define XL9535_INPUT_PORT_0_REG 0X00 +#define XL9535_INPUT_PORT_1_REG 0X01 +#define XL9535_OUTPUT_PORT_0_REG 0X02 +#define XL9535_OUTPUT_PORT_1_REG 0X03 +#define XL9535_INVERSION_PORT_0_REG 0X04 +#define XL9535_INVERSION_PORT_1_REG 0X05 +#define XL9535_CONFIG_PORT_0_REG 0X06 +#define XL9535_CONFIG_PORT_1_REG 0X07 + +class Arduino_XL9535SWSPI : public Arduino_DataBus +{ +public: + Arduino_XL9535SWSPI(int8_t sda, int8_t scl, int8_t pwd, int8_t cs, int8_t sck, int8_t mosi, TwoWire *wire = &Wire); + + bool begin(int32_t speed = GFX_NOT_DEFINED, int8_t dataMode = GFX_NOT_DEFINED) override; + void beginWrite() override; + void endWrite() override; + void writeCommand(uint8_t) override; + void writeCommand16(uint16_t) override; + void write(uint8_t) override; + void write16(uint16_t) override; + void writeRepeat(uint16_t p, uint32_t len) override; + void writePixels(uint16_t *data, uint32_t len) override; + +#if !defined(LITTLE_FOOT_PRINT) + void writeBytes(uint8_t *data, uint32_t len) override; +#endif // !defined(LITTLE_FOOT_PRINT) + + void pinMode(uint8_t pin, uint8_t mode)override; + void pinMode8(uint8_t port, uint8_t pin, uint8_t mode); + + void digitalWrite(uint8_t pin, uint8_t val) override; + int digitalRead(uint8_t pin) override; + +protected: + void writeRegister(uint8_t reg, uint8_t *data, size_t len); + uint8_t readRegister(uint8_t reg, uint8_t *data, size_t len); + + uint8_t _address; + bool is_found; + + int8_t _sda, _scl, _pwd, _cs, _sck, _mosi; + TwoWire *_wire; + +private: +}; + +#endif // _ARDUINO_XL9535SWSPI_H_ diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/display/Arduino_RGB_Display.cpp b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/display/Arduino_RGB_Display.cpp new file mode 100644 index 00000000..63bd7c13 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/display/Arduino_RGB_Display.cpp @@ -0,0 +1,498 @@ +#include "../Arduino_DataBus.h" + +#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3) + +#include "../Arduino_GFX.h" +#include "Arduino_RGB_Display.h" + +Arduino_RGB_Display::Arduino_RGB_Display( + int16_t w, int16_t h, Arduino_ESP32RGBPanel *rgbpanel, uint8_t r, bool auto_flush, + Arduino_DataBus *bus, int8_t rst, const uint8_t *init_operations, size_t init_operations_len) + : Arduino_GFX(w, h), _rgbpanel(rgbpanel), _auto_flush(auto_flush), + _bus(bus), _rst(rst), _init_operations(init_operations), _init_operations_len(init_operations_len) +{ + _framebuffer_size = w * h * 2; + MAX_X = WIDTH - 1; + MAX_Y = HEIGHT - 1; + setRotation(r); +} + +bool Arduino_RGB_Display::begin(int32_t speed) +{ + if (_bus) + { + if (!_bus->begin()) + { + return false; + } + } + + if (_rst != GFX_NOT_DEFINED) + { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(120); + digitalWrite(_rst, HIGH); + delay(120); + } + else + { + if (_bus) + { + // Software Rest + _bus->sendCommand(0x01); + delay(120); + } + } + + if (_bus) + { + if (_init_operations_len > 0) + { + _bus->batchOperation((uint8_t *)_init_operations, _init_operations_len); + } + } + + _rgbpanel->begin(speed); + _framebuffer = _rgbpanel->getFrameBuffer(WIDTH, HEIGHT); + + if (!_framebuffer) + { + return false; + } + + return true; +} + +void Arduino_RGB_Display::writePixelPreclipped(int16_t x, int16_t y, uint16_t color) +{ + uint16_t *fb = _framebuffer; + switch (_rotation) + { + case 1: + fb += (int32_t)x * _height; + fb += _max_y - y; + *fb = color; + if (_auto_flush) + { + Cache_WriteBack_Addr((uint32_t)fb, 2); + } + break; + case 2: + fb += (int32_t)(_max_y - y) * _width; + fb += _max_x - x; + *fb = color; + if (_auto_flush) + { + Cache_WriteBack_Addr((uint32_t)fb, 2); + } + break; + case 3: + fb += (int32_t)(_max_x - x) * _height; + fb += y; + *fb = color; + if (_auto_flush) + { + Cache_WriteBack_Addr((uint32_t)fb, 2); + } + break; + default: // case 0: + fb += (int32_t)y * _width; + fb += x; + *fb = color; + if (_auto_flush) + { + Cache_WriteBack_Addr((uint32_t)fb, 2); + } + } +} + +void Arduino_RGB_Display::writeFastVLine(int16_t x, int16_t y, + int16_t h, uint16_t color) +{ + // log_i("writeFastVLine(x: %d, y: %d, h: %d)", x, y, h); + switch (_rotation) + { + case 1: + writeFastHLineCore(_height - y - h, x, h, color); + break; + case 2: + writeFastVLineCore(_max_x - x, _height - y - h, h, color); + break; + case 3: + writeFastHLineCore(y, _max_x - x, h, color); + break; + default: // case 0: + writeFastVLineCore(x, y, h, color); + } +} + +void Arduino_RGB_Display::writeFastVLineCore(int16_t x, int16_t y, + int16_t h, uint16_t color) +{ + // log_i("writeFastVLineCore(x: %d, y: %d, h: %d)", x, y, h); + if (_ordered_in_range(x, 0, MAX_X) && h) + { // X on screen, nonzero height + if (h < 0) + { // If negative height... + y += h + 1; // Move Y to top edge + h = -h; // Use positive height + } + if (y <= MAX_Y) + { // Not off bottom + int16_t y2 = y + h - 1; + if (y2 >= 0) + { // Not off top + // Line partly or fully overlaps screen + if (y < 0) + { + y = 0; + h = y2 + 1; + } // Clip top + if (y2 > MAX_Y) + { + h = MAX_Y - y + 1; + } // Clip bottom + + uint16_t *fb = _framebuffer + ((int32_t)y * WIDTH) + x; + if (_auto_flush) + { + while (h--) + { + *fb = color; + Cache_WriteBack_Addr((uint32_t)fb, 2); + fb += WIDTH; + } + } + else + { + while (h--) + { + *fb = color; + fb += WIDTH; + } + } + } + } + } +} + +void Arduino_RGB_Display::writeFastHLine(int16_t x, int16_t y, + int16_t w, uint16_t color) +{ + // log_i("writeFastHLine(x: %d, y: %d, w: %d)", x, y, w); + switch (_rotation) + { + case 1: + writeFastVLineCore(_max_y - y, x, w, color); + break; + case 2: + writeFastHLineCore(_width - x - w, _max_y - y, w, color); + break; + case 3: + writeFastVLineCore(y, _width - x - w, w, color); + break; + default: // case 0: + writeFastHLineCore(x, y, w, color); + } +} + +void Arduino_RGB_Display::writeFastHLineCore(int16_t x, int16_t y, + int16_t w, uint16_t color) +{ + // log_i("writeFastHLineCore(x: %d, y: %d, w: %d)", x, y, w); + if (_ordered_in_range(y, 0, MAX_Y) && w) + { // Y on screen, nonzero width + if (w < 0) + { // If negative width... + x += w + 1; // Move X to left edge + w = -w; // Use positive width + } + if (x <= MAX_X) + { // Not off right + int16_t x2 = x + w - 1; + if (x2 >= 0) + { // Not off left + // Line partly or fully overlaps screen + if (x < 0) + { + x = 0; + w = x2 + 1; + } // Clip left + if (x2 > MAX_X) + { + w = MAX_X - x + 1; + } // Clip right + + uint16_t *fb = _framebuffer + ((int32_t)y * WIDTH) + x; + uint32_t cachePos = (uint32_t)fb; + int16_t writeSize = w * 2; + while (w--) + { + *(fb++) = color; + } + if (_auto_flush) + { + Cache_WriteBack_Addr(cachePos, writeSize); + } + } + } + } +} + +void Arduino_RGB_Display::writeFillRectPreclipped(int16_t x, int16_t y, + int16_t w, int16_t h, uint16_t color) +{ + // log_i("writeFillRectPreclipped(x: %d, y: %d, w: %d, h: %d)", x, y, w, h); + if (_rotation > 0) + { + int16_t t = x; + switch (_rotation) + { + case 1: + x = WIDTH - y - h; + y = t; + t = w; + w = h; + h = t; + break; + case 2: + x = WIDTH - x - w; + y = HEIGHT - y - h; + break; + case 3: + x = y; + y = HEIGHT - t - w; + t = w; + w = h; + h = t; + break; + } + } + // log_i("adjusted writeFillRectPreclipped(x: %d, y: %d, w: %d, h: %d)", x, y, w, h); + uint16_t *row = _framebuffer; + row += y * WIDTH; + uint32_t cachePos = (uint32_t)row; + row += x; + for (int j = 0; j < h; j++) + { + for (int i = 0; i < w; i++) + { + row[i] = color; + } + row += WIDTH; + } + if (_auto_flush) + { + Cache_WriteBack_Addr(cachePos, WIDTH * h * 2); + } +} + +void Arduino_RGB_Display::drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip) +{ + if ( + ((x + w - 1) < 0) || // Outside left + ((y + h - 1) < 0) || // Outside top + (x > _max_x) || // Outside right + (y > _max_y) // Outside bottom + ) + { + return; + } + else + { + if (_rotation > 0) + { + Arduino_GFX::drawIndexedBitmap(x, y, bitmap, color_index, w, h, x_skip); + } + else + { + if ((y + h - 1) > _max_y) + { + h -= (y + h - 1) - _max_y; + } + if (y < 0) + { + bitmap -= y * w; + h += y; + y = 0; + } + if ((x + w - 1) > _max_x) + { + x_skip += (x + w - 1) - _max_x; + w -= (x + w - 1) - _max_x; + } + if (x < 0) + { + bitmap -= x; + x_skip -= x; + w += x; + x = 0; + } + uint16_t *row = _framebuffer; + row += y * _width; + uint32_t cachePos = (uint32_t)row; + row += x; + for (int j = 0; j < h; j++) + { + for (int i = 0; i < w; i++) + { + row[i] = color_index[*bitmap++]; + } + bitmap += x_skip; + row += _width; + } + if (_auto_flush) + { + Cache_WriteBack_Addr(cachePos, _width * h * 2); + } + } + } +} + +void Arduino_RGB_Display::draw16bitRGBBitmap(int16_t x, int16_t y, + uint16_t *bitmap, int16_t w, int16_t h) +{ + bool result; + + switch (_rotation) + { + case 1: + result = gfx_draw_bitmap_to_framebuffer_rotate_1(bitmap, w, h, _framebuffer, x, y, _width, _height); + break; + case 2: + result = gfx_draw_bitmap_to_framebuffer_rotate_2(bitmap, w, h, _framebuffer, x, y, _width, _height); + break; + case 3: + result = gfx_draw_bitmap_to_framebuffer_rotate_3(bitmap, w, h, _framebuffer, x, y, _width, _height); + break; + default: // case 0: + result = gfx_draw_bitmap_to_framebuffer(bitmap, w, h, _framebuffer, x, y, _width, _height); + } + + if (result) + { + if (_auto_flush) + { + uint32_t cachePos; + size_t cache_size; + switch (_rotation) + { + case 1: + cachePos = (uint32_t)(_framebuffer + (x * WIDTH)); + cache_size = HEIGHT * w * 2; + break; + case 2: + cachePos = (uint32_t)(_framebuffer + ((MAX_Y - y) * WIDTH)); + cache_size = HEIGHT * h * 2; + break; + case 3: + cachePos = (uint32_t)(_framebuffer + ((MAX_Y - x) * WIDTH)); + cache_size = HEIGHT * w * 2; + break; + default: // case 0: + cachePos = (uint32_t)(_framebuffer + (y * WIDTH) + x); + cache_size = (WIDTH * (h - 1) + w) * 2; + } + Cache_WriteBack_Addr(cachePos, cache_size); + } + } +} + +void Arduino_RGB_Display::draw16bitBeRGBBitmap(int16_t x, int16_t y, + uint16_t *bitmap, int16_t w, int16_t h) +{ + if ( + ((x + w - 1) < 0) || // Outside left + ((y + h - 1) < 0) || // Outside top + (x > _max_x) || // Outside right + (y > _max_y) // Outside bottom + ) + { + return; + } + else + { + if (_rotation > 0) + { + Arduino_GFX::draw16bitBeRGBBitmap(x, y, bitmap, w, h); + } + else + { + int16_t xskip = 0; + if ((y + h - 1) > _max_y) + { + h -= (y + h - 1) - _max_y; + } + if (y < 0) + { + bitmap -= y * w; + h += y; + y = 0; + } + if ((x + w - 1) > _max_x) + { + xskip = (x + w - 1) - _max_x; + w -= xskip; + } + if (x < 0) + { + bitmap -= x; + xskip -= x; + w += x; + x = 0; + } + uint16_t *row = _framebuffer; + row += y * _width; + uint32_t cachePos = (uint32_t)row; + row += x; + uint16_t color; + for (int j = 0; j < h; j++) + { + for (int i = 0; i < w; i++) + { + color = *bitmap++; + MSB_16_SET(row[i], color); + } + bitmap += xskip; + row += _width; + } + if (_auto_flush) + { + Cache_WriteBack_Addr(cachePos, _width * h * 2); + } + } + } +} + +void Arduino_RGB_Display::flush(void) +{ + if (!_auto_flush) + { + Cache_WriteBack_Addr((uint32_t)_framebuffer, _framebuffer_size); + } +} + +uint16_t *Arduino_RGB_Display::getFramebuffer() +{ + return _framebuffer; +} + +#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3) + +void Arduino_RGB_Display::XL_pinMode(uint8_t pin, uint8_t mode) +{ + _bus->pinMode(pin, mode); +} + +void Arduino_RGB_Display::XL_digitalWrite(uint8_t pin, uint8_t val) +{ + _bus->digitalWrite(pin, val); +} + +int Arduino_RGB_Display::XL_digitalRead(uint8_t pin) +{ + return _bus->digitalRead(pin); +} diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/display/Arduino_RGB_Display.h b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/display/Arduino_RGB_Display.h new file mode 100644 index 00000000..98de2390 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/display/Arduino_RGB_Display.h @@ -0,0 +1,1325 @@ +#include "../Arduino_DataBus.h" + +#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3) + +#ifndef _ARDUINO_RGB_DISPLAY_H_ +#define _ARDUINO_RGB_DISPLAY_H_ + +#include "../Arduino_GFX.h" +#include "../databus/Arduino_ESP32RGBPanel.h" + +static const uint8_t gc9503v_type1_init_operations[] = { + BEGIN_WRITE, + WRITE_COMMAND_8, 0xF0, + WRITE_BYTES, 5, 0x55, 0xAA, 0x52, 0x08, 0x00, + + WRITE_C8_D16, 0xF6, 0x5A, 0x87, + + WRITE_C8_D8, 0xC1, 0x3F, + WRITE_C8_D8, 0xC2, 0x0E, + WRITE_C8_D8, 0xC6, 0xF8, + WRITE_C8_D8, 0xC9, 0x10, + WRITE_C8_D8, 0xCD, 0x25, + WRITE_C8_D8, 0xF8, 0x8A, + WRITE_C8_D8, 0xAC, 0x45, + WRITE_C8_D8, 0xA0, 0xDD, + WRITE_C8_D8, 0xA7, 0x47, + + WRITE_COMMAND_8, 0xFA, + WRITE_BYTES, 4, 0x00, 0x00, 0x00, 0x04, + + WRITE_C8_D8, 0xA3, 0xEE, + + WRITE_COMMAND_8, 0xFD, + WRITE_BYTES, 3, 0x28, 0x28, 0x00, + + WRITE_C8_D8, 0x71, 0x48, + WRITE_C8_D8, 0x72, 0x48, + WRITE_C8_D16, 0x73, 0x00, 0x44, + WRITE_C8_D8, 0x97, 0xEE, + WRITE_C8_D8, 0x83, 0x93, + WRITE_C8_D8, 0x9A, 0x72, + WRITE_C8_D8, 0x9B, 0x5a, + WRITE_C8_D16, 0x82, 0x2c, 0x2c, + WRITE_C8_D8, 0xB1, 0x10, + + WRITE_COMMAND_8, 0x6D, + WRITE_BYTES, 32, + 0x00, 0x1F, 0x19, 0x1A, + 0x10, 0x0e, 0x0c, 0x0a, + 0x02, 0x07, 0x1E, 0x1E, + 0x1E, 0x1E, 0x1E, 0x1E, + 0x1E, 0x1E, 0x1E, 0x1E, + 0x1E, 0x1E, 0x08, 0x01, + 0x09, 0x0b, 0x0D, 0x0F, + 0x1a, 0x19, 0x1f, 0x00, + + WRITE_COMMAND_8, 0x64, + WRITE_BYTES, 16, + 0x38, 0x05, 0x01, 0xdb, + 0x03, 0x03, 0x38, 0x04, + 0x01, 0xdc, 0x03, 0x03, + 0x7A, 0x7A, 0x7A, 0x7A, + + WRITE_COMMAND_8, 0x65, + WRITE_BYTES, 16, + 0x38, 0x03, 0x01, 0xdd, + 0x03, 0x03, 0x38, 0x02, + 0x01, 0xde, 0x03, 0x03, + 0x7A, 0x7A, 0x7A, 0x7A, + + WRITE_COMMAND_8, 0x66, + WRITE_BYTES, 16, + 0x38, 0x01, 0x01, 0xdf, + 0x03, 0x03, 0x38, 0x00, + 0x01, 0xe0, 0x03, 0x03, + 0x7A, 0x7A, 0x7A, 0x7A, + + WRITE_COMMAND_8, 0x67, + WRITE_BYTES, 16, + 0x30, 0x01, 0x01, 0xe1, + 0x03, 0x03, 0x30, 0x02, + 0x01, 0xe2, 0x03, 0x03, + 0x7A, 0x7A, 0x7A, 0x7A, + + WRITE_COMMAND_8, 0x68, + WRITE_BYTES, 13, + 0x00, 0x08, 0x15, 0x08, + 0x15, 0x7A, 0x7A, 0x08, + 0x15, 0x08, 0x15, 0x7A, + 0x7A, + + WRITE_COMMAND_8, 0x60, + WRITE_BYTES, 8, + 0x38, 0x08, 0x7A, 0x7A, + 0x38, 0x09, 0x7A, 0x7A, + + WRITE_COMMAND_8, 0x63, + WRITE_BYTES, 8, + 0x31, 0xe4, 0x7A, 0x7A, + 0x31, 0xe5, 0x7A, 0x7A, + + WRITE_C8_D8, 0x6B, 0x07, + + WRITE_C8_D16, 0x7A, 0x08, 0x13, + + WRITE_C8_D16, 0x7B, 0x08, 0x13, + + WRITE_COMMAND_8, 0xD1, + WRITE_BYTES, 52, + 0x00, 0x00, 0x00, 0x04, + 0x00, 0x12, 0x00, 0x18, + 0x00, 0x21, 0x00, 0x2a, + 0x00, 0x35, 0x00, 0x47, + 0x00, 0x56, 0x00, 0x90, + 0x00, 0xe5, 0x01, 0x68, + 0x01, 0xd5, 0x01, 0xd7, + 0x02, 0x36, 0x02, 0xa6, + 0x02, 0xee, 0x03, 0x48, + 0x03, 0xa0, 0x03, 0xba, + 0x03, 0xc5, 0x03, 0xd0, + 0x03, 0xE0, 0x03, 0xea, + 0x03, 0xFa, 0x03, 0xFF, + + WRITE_COMMAND_8, 0xD2, + WRITE_BYTES, 52, + 0x00, 0x00, 0x00, 0x04, + 0x00, 0x12, 0x00, 0x18, + 0x00, 0x21, 0x00, 0x2a, + 0x00, 0x35, 0x00, 0x47, + 0x00, 0x56, 0x00, 0x90, + 0x00, 0xe5, 0x01, 0x68, + 0x01, 0xd5, 0x01, 0xd7, + 0x02, 0x36, 0x02, 0xa6, + 0x02, 0xee, 0x03, 0x48, + 0x03, 0xa0, 0x03, 0xba, + 0x03, 0xc5, 0x03, 0xd0, + 0x03, 0xE0, 0x03, 0xea, + 0x03, 0xFa, 0x03, 0xFF, + + WRITE_COMMAND_8, 0xD3, + WRITE_BYTES, 52, + 0x00, 0x00, 0x00, 0x04, + 0x00, 0x12, 0x00, 0x18, + 0x00, 0x21, 0x00, 0x2a, + 0x00, 0x35, 0x00, 0x47, + 0x00, 0x56, 0x00, 0x90, + 0x00, 0xe5, 0x01, 0x68, + 0x01, 0xd5, 0x01, 0xd7, + 0x02, 0x36, 0x02, 0xa6, + 0x02, 0xee, 0x03, 0x48, + 0x03, 0xa0, 0x03, 0xba, + 0x03, 0xc5, 0x03, 0xd0, + 0x03, 0xE0, 0x03, 0xea, + 0x03, 0xFa, 0x03, 0xFF, + + WRITE_COMMAND_8, 0xD4, + WRITE_BYTES, 52, + 0x00, 0x00, 0x00, 0x04, + 0x00, 0x12, 0x00, 0x18, + 0x00, 0x21, 0x00, 0x2a, + 0x00, 0x35, 0x00, 0x47, + 0x00, 0x56, 0x00, 0x90, + 0x00, 0xe5, 0x01, 0x68, + 0x01, 0xd5, 0x01, 0xd7, + 0x02, 0x36, 0x02, 0xa6, + 0x02, 0xee, 0x03, 0x48, + 0x03, 0xa0, 0x03, 0xba, + 0x03, 0xc5, 0x03, 0xd0, + 0x03, 0xE0, 0x03, 0xea, + 0x03, 0xFa, 0x03, 0xFF, + + WRITE_COMMAND_8, 0xD5, + WRITE_BYTES, 52, + 0x00, 0x00, 0x00, 0x04, + 0x00, 0x12, 0x00, 0x18, + 0x00, 0x21, 0x00, 0x2a, + 0x00, 0x35, 0x00, 0x47, + 0x00, 0x56, 0x00, 0x90, + 0x00, 0xe5, 0x01, 0x68, + 0x01, 0xd5, 0x01, 0xd7, + 0x02, 0x36, 0x02, 0xa6, + 0x02, 0xee, 0x03, 0x48, + 0x03, 0xa0, 0x03, 0xba, + 0x03, 0xc5, 0x03, 0xd0, + 0x03, 0xE0, 0x03, 0xea, + 0x03, 0xFa, 0x03, 0xFF, + + WRITE_COMMAND_8, 0xD6, + WRITE_BYTES, 52, + 0x00, 0x00, 0x00, 0x04, + 0x00, 0x12, 0x00, 0x18, + 0x00, 0x21, 0x00, 0x2a, + 0x00, 0x35, 0x00, 0x47, + 0x00, 0x56, 0x00, 0x90, + 0x00, 0xe5, 0x01, 0x68, + 0x01, 0xd5, 0x01, 0xd7, + 0x02, 0x36, 0x02, 0xa6, + 0x02, 0xee, 0x03, 0x48, + 0x03, 0xa0, 0x03, 0xba, + 0x03, 0xc5, 0x03, 0xd0, + 0x03, 0xE0, 0x03, 0xea, + 0x03, 0xFa, 0x03, 0xFF, + + WRITE_C8_D8, 0x3a, 0x66, + + WRITE_COMMAND_8, 0x11, + END_WRITE, + + DELAY, 200, + + BEGIN_WRITE, + WRITE_COMMAND_8, 0x29, + END_WRITE}; + +static const uint8_t st7701_type1_init_operations[] = { + BEGIN_WRITE, + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10, + + WRITE_C8_D16, 0xC0, 0x3B, 0x00, + WRITE_C8_D16, 0xC1, 0x0D, 0x02, + WRITE_C8_D16, 0xC2, 0x31, 0x05, + WRITE_C8_D8, 0xCD, 0x08, + + WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control + WRITE_BYTES, 16, + 0x00, 0x11, 0x18, 0x0E, + 0x11, 0x06, 0x07, 0x08, + 0x07, 0x22, 0x04, 0x12, + 0x0F, 0xAA, 0x31, 0x18, + + WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control + WRITE_BYTES, 16, + 0x00, 0x11, 0x19, 0x0E, + 0x12, 0x07, 0x08, 0x08, + 0x08, 0x22, 0x04, 0x11, + 0x11, 0xA9, 0x32, 0x18, + + // PAGE1 + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11, + + WRITE_C8_D8, 0xB0, 0x60, // Vop=4.7375v + WRITE_C8_D8, 0xB1, 0x32, // VCOM=32 + WRITE_C8_D8, 0xB2, 0x07, // VGH=15v + WRITE_C8_D8, 0xB3, 0x80, + WRITE_C8_D8, 0xB5, 0x49, // VGL=-10.17v + WRITE_C8_D8, 0xB7, 0x85, + WRITE_C8_D8, 0xB8, 0x21, // AVDD=6.6 & AVCL=-4.6 + WRITE_C8_D8, 0xC1, 0x78, + WRITE_C8_D8, 0xC2, 0x78, + + WRITE_COMMAND_8, 0xE0, + WRITE_BYTES, 3, 0x00, 0x1B, 0x02, + + WRITE_COMMAND_8, 0xE1, + WRITE_BYTES, 11, + 0x08, 0xA0, 0x00, 0x00, + 0x07, 0xA0, 0x00, 0x00, + 0x00, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE2, + WRITE_BYTES, 12, + 0x11, 0x11, 0x44, 0x44, + 0xED, 0xA0, 0x00, 0x00, + 0xEC, 0xA0, 0x00, 0x00, + + WRITE_COMMAND_8, 0xE3, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11, + + WRITE_C8_D16, 0xE4, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE5, + WRITE_BYTES, 16, + 0x0A, 0xE9, 0xD8, 0xA0, + 0x0C, 0xEB, 0xD8, 0xA0, + 0x0E, 0xED, 0xD8, 0xA0, + 0x10, 0xEF, 0xD8, 0xA0, + + WRITE_COMMAND_8, 0xE6, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11, + + WRITE_C8_D16, 0xE7, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE8, + WRITE_BYTES, 16, + 0x09, 0xE8, 0xD8, 0xA0, + 0x0B, 0xEA, 0xD8, 0xA0, + 0x0D, 0xEC, 0xD8, 0xA0, + 0x0F, 0xEE, 0xD8, 0xA0, + + WRITE_COMMAND_8, 0xEB, + WRITE_BYTES, 7, + 0x02, 0x00, 0xE4, 0xE4, + 0x88, 0x00, 0x40, + + WRITE_C8_D16, 0xEC, 0x3C, 0x00, + + WRITE_COMMAND_8, 0xED, + WRITE_BYTES, 16, + 0xAB, 0x89, 0x76, 0x54, + 0x02, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x20, + 0x45, 0x67, 0x98, 0xBA, + + //-----------VAP & VAN--------------- + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13, + + WRITE_C8_D8, 0xE5, 0xE4, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0x21, // 0x20 normal, 0x21 IPS + WRITE_C8_D8, 0x3A, 0x60, // 0x70 RGB888, 0x60 RGB666, 0x50 RGB565 + + WRITE_COMMAND_8, 0x11, // Sleep Out + END_WRITE, + + DELAY, 120, + + BEGIN_WRITE, + WRITE_COMMAND_8, 0x29, // Display On + END_WRITE}; + +static const uint8_t st7701_type2_init_operations[] = { + BEGIN_WRITE, + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10, + + WRITE_C8_D16, 0xC0, 0xE9, 0x03, + WRITE_C8_D16, 0xC1, 0x11, 0x02, + WRITE_C8_D16, 0xC2, 0x31, 0x08, + + WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control + WRITE_BYTES, 16, + 0x00, 0x0D, 0x14, 0x0D, + 0x10, 0x05, 0x02, 0x08, + 0x08, 0x1E, 0x05, 0x13, + 0x11, 0xA3, 0x29, 0x18, + + WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control + WRITE_BYTES, 16, + 0x00, 0x0C, 0x14, 0x0C, + 0x10, 0x05, 0x03, 0x08, + 0x07, 0x20, 0x05, 0x13, + 0x11, 0xA4, 0x29, 0x18, + + // PAGE1 + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11, + + WRITE_C8_D8, 0xB0, 0x6C, + WRITE_C8_D8, 0xB1, 0x43, + WRITE_C8_D8, 0xB2, 0x07, + WRITE_C8_D8, 0xB3, 0x80, + WRITE_C8_D8, 0xB5, 0x47, + WRITE_C8_D8, 0xB7, 0x8A, + WRITE_C8_D8, 0xB8, 0x20, + WRITE_C8_D8, 0xC1, 0x78, + WRITE_C8_D8, 0xC2, 0x78, + + WRITE_C8_D8, 0xD0, 0x88, + + WRITE_COMMAND_8, 0xE0, + WRITE_BYTES, 3, 0x00, 0x00, 0x02, + + WRITE_COMMAND_8, 0xE1, + WRITE_BYTES, 11, + 0x08, 0x00, 0x0A, 0x00, + 0x07, 0x00, 0x09, 0x00, + 0x00, 0x33, 0x33, + + WRITE_COMMAND_8, 0xE2, + WRITE_BYTES, 12, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0xE3, + WRITE_BYTES, 4, 0x00, 0x00, 0x33, 0x33, + + WRITE_C8_D16, 0xE4, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE5, + WRITE_BYTES, 16, + 0x0E, 0x60, 0xA0, 0xA0, + 0x10, 0x60, 0xA0, 0xA0, + 0x0A, 0x60, 0xA0, 0xA0, + 0x0C, 0x60, 0xA0, 0xA0, + + WRITE_COMMAND_8, 0xE6, + WRITE_BYTES, 4, 0x00, 0x00, 0x33, 0x33, + + WRITE_C8_D16, 0xE7, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE8, + WRITE_BYTES, 16, + 0x0D, 0x60, 0xA0, 0xA0, + 0x0F, 0x60, 0xA0, 0xA0, + 0x09, 0x60, 0xA0, 0xA0, + 0x0B, 0x60, 0xA0, 0xA0, + + WRITE_COMMAND_8, 0xEB, + WRITE_BYTES, 7, + 0x02, 0x01, 0xE4, 0xE4, + 0x44, 0x00, 0x40, + + WRITE_C8_D16, 0xEC, 0x02, 0x01, + + WRITE_COMMAND_8, 0xED, + WRITE_BYTES, 16, + 0xAB, 0x89, 0x76, 0x54, + 0x01, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x10, + 0x45, 0x67, 0x98, 0xBA, + + //-----------------------------------------End GIP Setting-----------------------------------------// + //--------------------------- Power Control Registers Initial End------------------------------// + //-------------------------------------Bank1 Setting------------------------------------------------// + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0x21, // 0x20 normal, 0x21 IPS + WRITE_C8_D8, 0x3A, 0x77, // RGB 24bits D[23:0] + + WRITE_COMMAND_8, 0x11, // Sleep Out + END_WRITE, + + DELAY, 100, + + BEGIN_WRITE, + WRITE_COMMAND_8, 0x29, // Display On + END_WRITE}; + +static const uint8_t st7701_type3_init_operations[] = { + BEGIN_WRITE, + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10, + + WRITE_C8_D16, 0xC0, 0x3B, 0x00, + WRITE_C8_D16, 0xC1, 0x0B, 0x02, // VBP + WRITE_C8_D16, 0xC2, 0x00, 0x02, + WRITE_C8_D8, 0xCC, 0x10, + WRITE_C8_D8, 0xCD, 0x08, + + WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control + WRITE_BYTES, 16, + 0x02, 0x13, 0x1B, 0x0D, + 0x10, 0x05, 0x08, 0x07, + 0x07, 0x24, 0x04, 0x11, + 0x0E, 0x2C, 0x33, 0x1D, + + WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control + WRITE_BYTES, 16, + 0x05, 0x13, 0x1B, 0x0D, + 0x11, 0x05, 0x08, 0x07, + 0x07, 0x24, 0x04, 0x11, + 0x0E, 0x2C, 0x33, 0x1D, + + // PAGE1 + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11, + + WRITE_C8_D8, 0xB0, 0x5d, // 5d + WRITE_C8_D8, 0xB1, 0x43, // VCOM amplitude setting + WRITE_C8_D8, 0xB2, 0x81, // VGH Voltage setting, 12V + WRITE_C8_D8, 0xB3, 0x80, + WRITE_C8_D8, 0xB5, 0x43, // VGL Voltage setting, -8.3V + WRITE_C8_D8, 0xB7, 0x85, + WRITE_C8_D8, 0xB8, 0x20, + + WRITE_C8_D8, 0xC1, 0x78, + WRITE_C8_D8, 0xC2, 0x78, + + WRITE_C8_D8, 0xD0, 0x88, + + WRITE_COMMAND_8, 0xE0, + WRITE_BYTES, 3, 0x00, 0x00, 0x02, + + WRITE_COMMAND_8, 0xE1, + WRITE_BYTES, 11, + 0x03, 0xA0, 0x00, 0x00, + 0x04, 0xA0, 0x00, 0x00, + 0x00, 0x20, 0x20, + + WRITE_COMMAND_8, 0xE2, + WRITE_BYTES, 12, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0xE3, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x00, + + WRITE_C8_D16, 0xE4, 0x22, 0x00, + + WRITE_COMMAND_8, 0xE5, + WRITE_BYTES, 16, + 0x05, 0xEC, 0xA0, 0xA0, + 0x07, 0xEE, 0xA0, 0xA0, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0xE6, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x00, + + WRITE_C8_D16, 0xE7, 0x22, 0x00, + + WRITE_COMMAND_8, 0xE8, + WRITE_BYTES, 16, + 0x06, 0xED, 0xA0, 0xA0, + 0x08, 0xEF, 0xA0, 0xA0, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0xEB, + WRITE_BYTES, 7, + 0x00, 0x00, 0x40, 0x40, + 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0xED, + WRITE_BYTES, 16, + 0xFF, 0xFF, 0xFF, 0xBA, + 0x0A, 0xBF, 0x45, 0xFF, + 0xFF, 0x54, 0xFB, 0xA0, + 0xAB, 0xFF, 0xFF, 0xFF, + + WRITE_COMMAND_8, 0xEF, + WRITE_BYTES, 6, + 0x10, 0x0D, 0x04, 0x08, + 0x3F, 0x1F, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13, + + WRITE_C8_D8, 0xEF, 0x08, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0x11, // Sleep Out + END_WRITE, + + DELAY, 120, + + BEGIN_WRITE, + WRITE_COMMAND_8, 0x29, // Display On + WRITE_COMMAND_8, 0x21, // 0x20 normal, 0x21 IPS + WRITE_C8_D8, 0x36, 0x00, // Display data access control + WRITE_C8_D8, 0x3A, 0x60, // 0x60 18bit 0x50 16bit + END_WRITE}; + +static const uint8_t st7701_type4_init_operations[] = { + BEGIN_WRITE, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10, + + WRITE_C8_D16, 0xC0, 0x3b, 0x00, + WRITE_C8_D16, 0xC1, 0x0b, 0x02, + WRITE_C8_D16, 0xC2, 0x07, 0x02, + WRITE_C8_D8, 0xCC, 0x10, + WRITE_C8_D8, 0xCD, 0x08, + + WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control + WRITE_BYTES, 16, + 0x00, 0x11, 0x16, 0x0e, + 0x11, 0x06, 0x05, 0x09, + 0x08, 0x21, 0x06, 0x13, + 0x10, 0x29, 0x31, 0x18, + + WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control + WRITE_BYTES, 16, + 0x00, 0x11, 0x16, 0x0e, + 0x11, 0x07, 0x05, 0x09, + 0x09, 0x21, 0x05, 0x13, + 0x11, 0x2a, 0x31, 0x18, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11, + + WRITE_C8_D8, 0xb0, 0x6d, + WRITE_C8_D8, 0xb1, 0x37, + WRITE_C8_D8, 0xb2, 0x81, + WRITE_C8_D8, 0xb3, 0x80, + WRITE_C8_D8, 0xb5, 0x43, + WRITE_C8_D8, 0xb7, 0x85, + WRITE_C8_D8, 0xb8, 0x20, + + WRITE_C8_D8, 0xc1, 0x78, + WRITE_C8_D8, 0xc2, 0x78, + WRITE_C8_D8, 0xc3, 0x8c, + + WRITE_C8_D8, 0xd0, 0x88, + + WRITE_COMMAND_8, 0xe0, + WRITE_BYTES, 3, 0x00, 0x00, 0x02, + WRITE_COMMAND_8, 0xe1, + WRITE_BYTES, 11, + 0x03, 0xa0, 0x00, 0x00, + 0x04, 0xa0, 0x00, 0x00, + 0x00, 0x20, 0x20, + WRITE_COMMAND_8, 0xe2, + WRITE_BYTES, 13, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, + WRITE_COMMAND_8, 0xe3, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x00, + WRITE_C8_D16, 0xe4, 0x22, 0x00, + WRITE_COMMAND_8, 0xe5, + WRITE_BYTES, 16, + 0x05, 0xec, 0xa0, 0xa0, + 0x07, 0xee, 0xa0, 0xa0, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + WRITE_COMMAND_8, 0xe6, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x00, + WRITE_C8_D16, 0xe7, 0x22, 0x00, + WRITE_COMMAND_8, 0xe8, + WRITE_BYTES, 16, + 0x06, 0xed, 0xa0, 0xa0, + 0x08, 0xef, 0xa0, 0xa0, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + WRITE_COMMAND_8, 0xeb, + WRITE_BYTES, 7, + 0x00, 0x00, 0x40, 0x40, + 0x00, 0x00, 0x00, + WRITE_COMMAND_8, 0xed, + WRITE_BYTES, 16, + 0xff, 0xff, 0xff, 0xba, + 0x0a, 0xbf, 0x45, 0xff, + 0xff, 0x54, 0xfb, 0xa0, + 0xab, 0xff, 0xff, 0xff, + WRITE_COMMAND_8, 0xef, + WRITE_BYTES, 6, + 0x10, 0x0d, 0x04, 0x08, + 0x3f, 0x1f, + WRITE_COMMAND_8, 0xff, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13, + WRITE_C8_D8, 0xef, 0x08, + WRITE_COMMAND_8, 0xff, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x00, + WRITE_C8_D8, 0x36, 0x08, + WRITE_C8_D8, 0x3a, 0x66, + WRITE_C8_D8, 0x11, 0x00, + WRITE_C8_D8, 0x29, 0x00, + + WRITE_COMMAND_8, 0x11, // Sleep Out + END_WRITE, + + DELAY, 120, + + BEGIN_WRITE, + WRITE_COMMAND_8, 0x29, // Display On + WRITE_C8_D8, 0x36, 0x08, // Display data access control + WRITE_C8_D8, 0x3A, 0x60, // 0x60 18bit 0x50 16bit + END_WRITE}; + +static const uint8_t st7701_type5_init_operations[] = { + BEGIN_WRITE, + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10, + + WRITE_C8_D16, 0xC0, 0x3B, 0x00, + WRITE_C8_D16, 0xC1, 0x0B, 0x02, // VBP + WRITE_C8_D16, 0xC2, 0x00, 0x02, + + WRITE_C8_D8, 0xCC, 0x10, + WRITE_C8_D8, 0xCD, 0x08, + + WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control + WRITE_BYTES, 16, + 0x02, 0x13, 0x1B, 0x0D, + 0x10, 0x05, 0x08, 0x07, + 0x07, 0x24, 0x04, 0x11, + 0x0E, 0x2C, 0x33, 0x1D, + + WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control + WRITE_BYTES, 16, + 0x05, 0x13, 0x1B, 0x0D, + 0x11, 0x05, 0x08, 0x07, + 0x07, 0x24, 0x04, 0x11, + 0x0E, 0x2C, 0x33, 0x1D, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11, + + WRITE_C8_D8, 0xB0, 0x5d, // 5d + WRITE_C8_D8, 0xB1, 0x43, // VCOM amplitude setting + WRITE_C8_D8, 0xB2, 0x81, // VGH Voltage setting, 12V + WRITE_C8_D8, 0xB3, 0x80, + + WRITE_C8_D8, 0xB5, 0x43, // VGL Voltage setting, -8.3V + + WRITE_C8_D8, 0xB7, 0x85, + WRITE_C8_D8, 0xB8, 0x20, + + WRITE_C8_D8, 0xC1, 0x78, + WRITE_C8_D8, 0xC2, 0x78, + + WRITE_C8_D8, 0xD0, 0x88, + + WRITE_COMMAND_8, 0xE0, + WRITE_BYTES, 3, 0x00, 0x00, 0x02, + + WRITE_COMMAND_8, 0xE1, + WRITE_BYTES, 11, + 0x03, 0xA0, 0x00, 0x00, + 0x04, 0xA0, 0x00, 0x00, + 0x00, 0x20, 0x20, + + WRITE_COMMAND_8, 0xE2, + WRITE_BYTES, 13, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, + + WRITE_COMMAND_8, 0xE3, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x00, + + WRITE_C8_D16, 0xE4, 0x22, 0x00, + + WRITE_COMMAND_8, 0xE5, + WRITE_BYTES, 16, + 0x05, 0xEC, 0xA0, 0xA0, + 0x07, 0xEE, 0xA0, 0xA0, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0xE6, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x00, + + WRITE_C8_D16, 0xE7, 0x22, 0x00, + + WRITE_COMMAND_8, 0xE8, + WRITE_BYTES, 16, + 0x06, 0xED, 0xA0, 0xA0, + 0x08, 0xEF, 0xA0, 0xA0, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0xEB, + WRITE_BYTES, 7, + 0x00, 0x00, 0x40, 0x40, + 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0xED, + WRITE_BYTES, 16, + 0xFF, 0xFF, 0xFF, 0xBA, + 0x0A, 0xBF, 0x45, 0xFF, + 0xFF, 0x54, 0xFB, 0xA0, + 0xAB, 0xFF, 0xFF, 0xFF, + + WRITE_COMMAND_8, 0xEF, + WRITE_BYTES, 6, + 0x10, 0x0D, 0x04, 0x08, + 0x3F, 0x1F, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13, + + WRITE_C8_D8, 0xEF, 0x08, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x00, + + WRITE_C8_D8, 0x36, 0x08, + WRITE_C8_D8, 0x3A, 0x60, // 0x70 RGB888, 0x60 RGB666, 0x50 RGB565 + + WRITE_COMMAND_8, 0x11, // Sleep Out + END_WRITE, + + DELAY, 100, + + BEGIN_WRITE, + WRITE_COMMAND_8, 0x29, // Display On + END_WRITE, + + DELAY, 50}; + +static const uint8_t st7701_type6_init_operations[] = { + BEGIN_WRITE, + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13, + WRITE_C8_D8, 0xEF, 0x08, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10, + + WRITE_C8_D16, 0xC0, 0x3B, 0x00, + + WRITE_C8_D16, 0xC1, 0x10, 0x0C, + + WRITE_C8_D16, 0xC2, 0x07, 0x0A, + + WRITE_C8_D8, 0xC7, 0x00, + + WRITE_C8_D8, 0xCC, 0x10, + + WRITE_COMMAND_8, 0xB0, + WRITE_BYTES, 16, + 0x05, 0x12, 0x98, 0x0E, + 0x0F, 0x07, 0x07, 0x09, + 0x09, 0x23, 0x05, 0x52, + 0x0F, 0x67, 0x2C, 0x11, + + WRITE_COMMAND_8, 0xB1, + WRITE_BYTES, 16, + 0x0B, 0x11, 0x97, 0x0C, + 0x12, 0x06, 0x06, 0x08, + 0x08, 0x22, 0x03, 0x51, + 0x11, 0x66, 0x2B, 0x0F, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11, + + WRITE_C8_D8, 0xB0, 0x5D, + WRITE_C8_D8, 0xB1, 0x2D, + WRITE_C8_D8, 0xB2, 0x81, + WRITE_C8_D8, 0xB3, 0x80, + + WRITE_C8_D8, 0xB5, 0x4E, + + WRITE_C8_D8, 0xB7, 0x85, + WRITE_C8_D8, 0xB8, 0x20, + + WRITE_C8_D8, 0xC1, 0x78, + WRITE_C8_D8, 0xC2, 0x78, + + WRITE_C8_D8, 0xD0, 0x88, + + WRITE_COMMAND_8, 0xE0, + WRITE_BYTES, 3, 0x00, 0x00, 0x02, + + WRITE_COMMAND_8, 0xE1, + WRITE_BYTES, 11, + 0x06, 0x30, 0x08, 0x30, + 0x05, 0x30, 0x07, 0x30, + 0x00, 0x33, 0x33, + + WRITE_COMMAND_8, 0xE2, + WRITE_BYTES, 12, + 0x11, 0x11, 0x33, 0x33, + 0xF4, 0x00, 0x00, 0x00, + 0xF4, 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0xE3, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11, + + WRITE_C8_D16, 0xE4, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE5, + WRITE_BYTES, 16, + 0x0D, 0xF5, 0x30, 0xF0, + 0x0F, 0xF7, 0x30, 0xF0, + 0x09, 0xF1, 0x30, 0xF0, + 0x0B, 0xF3, 0x30, 0xF0, + + WRITE_COMMAND_8, 0xE6, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11, + + WRITE_C8_D16, 0xE7, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE8, + WRITE_BYTES, 16, + 0x0C, 0xF4, 0x30, 0xF0, + 0x0E, 0xF6, 0x30, 0xF0, + 0x08, 0xF0, 0x30, 0xF0, + 0x0A, 0xF2, 0x30, 0xF0, + + WRITE_C8_D16, 0xE9, 0x36, 0x01, + + WRITE_COMMAND_8, 0xEB, + WRITE_BYTES, 7, + 0x00, 0x01, 0xE4, 0xE4, + 0x44, 0x88, 0x40, + + WRITE_COMMAND_8, 0xED, + WRITE_BYTES, 16, + 0xFF, 0x10, 0xAF, 0x76, + 0x54, 0x2B, 0xCF, 0xFF, + 0xFF, 0xFC, 0xB2, 0x45, + 0x67, 0xFA, 0x01, 0xFF, + + WRITE_COMMAND_8, 0xEF, + WRITE_BYTES, 6, + 0x08, 0x08, 0x08, 0x45, + 0x3F, 0x54, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0x11, + END_WRITE, + + DELAY, 120, // ms + + BEGIN_WRITE, + WRITE_C8_D8, 0x3A, 0x66, + + WRITE_C8_D8, 0x36, 0x00, + + WRITE_C8_D8, 0x35, 0x00, + + WRITE_COMMAND_8, 0x29, // Display On + END_WRITE}; + +static const uint8_t st7701_type7_init_operations[] = { + BEGIN_WRITE, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10, + + WRITE_C8_D16, 0xC0, 0x3b, 0x00, + WRITE_C8_D16, 0xC1, 0x0b, 0x02, + WRITE_C8_D16, 0xC2, 0x07, 0x02, + WRITE_C8_D8, 0xCC, 0x10, + WRITE_C8_D8, 0xCD, 0x08, + + WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control + WRITE_BYTES, 16, + 0x00, 0x11, 0x16, 0x0e, + 0x11, 0x06, 0x05, 0x09, + 0x08, 0x21, 0x06, 0x13, + 0x10, 0x29, 0x31, 0x18, + + WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control + WRITE_BYTES, 16, + 0x00, 0x11, 0x16, 0x0e, + 0x11, 0x07, 0x05, 0x09, + 0x09, 0x21, 0x05, 0x13, + 0x11, 0x2a, 0x31, 0x18, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11, + + WRITE_C8_D8, 0xb0, 0x6d, + WRITE_C8_D8, 0xb1, 0x37, + WRITE_C8_D8, 0xb2, 0x81, + WRITE_C8_D8, 0xb3, 0x80, + WRITE_C8_D8, 0xb5, 0x43, + WRITE_C8_D8, 0xb7, 0x85, + WRITE_C8_D8, 0xb8, 0x20, + + WRITE_C8_D8, 0xc1, 0x78, + WRITE_C8_D8, 0xc2, 0x78, + + WRITE_C8_D8, 0xd0, 0x88, + + WRITE_COMMAND_8, 0xe0, + WRITE_BYTES, 3, 0x00, 0x00, 0x02, + WRITE_COMMAND_8, 0xe1, + WRITE_BYTES, 11, + 0x03, 0xa0, 0x00, 0x00, + 0x04, 0xa0, 0x00, 0x00, + 0x00, 0x20, 0x20, + WRITE_COMMAND_8, 0xe2, + WRITE_BYTES, 13, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, + WRITE_COMMAND_8, 0xe3, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x00, + WRITE_C8_D16, 0xe4, 0x22, 0x00, + WRITE_COMMAND_8, 0xe5, + WRITE_BYTES, 16, + 0x05, 0xec, 0xa0, 0xa0, + 0x07, 0xee, 0xa0, 0xa0, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + WRITE_COMMAND_8, 0xe6, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x00, + WRITE_C8_D16, 0xe7, 0x22, 0x00, + WRITE_COMMAND_8, 0xe8, + WRITE_BYTES, 16, + 0x06, 0xed, 0xa0, 0xa0, + 0x08, 0xef, 0xa0, 0xa0, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + WRITE_COMMAND_8, 0xeb, + WRITE_BYTES, 7, + 0x00, 0x00, 0x40, 0x40, + 0x00, 0x00, 0x00, + WRITE_COMMAND_8, 0xed, + WRITE_BYTES, 16, + 0xff, 0xff, 0xff, 0xba, + 0x0a, 0xbf, 0x45, 0xff, + 0xff, 0x54, 0xfb, 0xa0, + 0xab, 0xff, 0xff, 0xff, + WRITE_COMMAND_8, 0xef, + WRITE_BYTES, 6, + 0x10, 0x0d, 0x04, 0x08, + 0x3f, 0x1f, + WRITE_COMMAND_8, 0xff, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13, + WRITE_C8_D8, 0xef, 0x08, + WRITE_COMMAND_8, 0xff, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x00, + WRITE_C8_D8, 0x36, 0x00, + WRITE_C8_D8, 0x3a, 0x66, + WRITE_C8_D8, 0x11, 0x00, + + WRITE_COMMAND_8, 0x11, // Sleep Out + END_WRITE, + + DELAY, 120, + + BEGIN_WRITE, + WRITE_COMMAND_8, 0x29, // Display On + END_WRITE}; + +static const uint8_t st7701_type8_init_operations[] = { + BEGIN_WRITE, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13, + + WRITE_C8_D8, 0xEF, 0x08, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10, + + WRITE_C8_D16, 0xC0, 0x2C, 0x00, + WRITE_C8_D16, 0xC1, 0x0D, 0x02, + WRITE_C8_D16, 0xC2, 0x31, 0x05, + WRITE_C8_D8, 0xCC, 0x10, + + WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control + WRITE_BYTES, 16, + 0x0A, 0x14, 0x1B, 0x0D, + 0x10, 0x05, 0x07, 0x08, + 0x06, 0x22, 0x03, 0x11, + 0x10, 0xAD, 0x31, 0x1B, + + WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control + WRITE_BYTES, 16, + 0x0A, 0x14, 0x1B, 0x0D, + 0x10, 0x05, 0x07, 0x08, + 0x06, 0x22, 0x03, 0x11, + 0x10, 0xAD, 0x31, 0x1B, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11, + + WRITE_C8_D8, 0xB0, 0x50, + WRITE_C8_D8, 0xB1, 0x5E, + WRITE_C8_D8, 0xB2, 0x87, + WRITE_C8_D8, 0xB3, 0x80, + WRITE_C8_D8, 0xB5, 0x47, + WRITE_C8_D8, 0xB7, 0x85, + WRITE_C8_D8, 0xB8, 0x21, + + WRITE_C8_D8, 0xC1, 0x78, + WRITE_C8_D8, 0xC2, 0x78, + + WRITE_C8_D8, 0xD0, 0x88, + + WRITE_C8_D8, 0xE0, 0x00, + + WRITE_C8_D8, 0x1B, 0x02, + + WRITE_COMMAND_8, 0xE1, + WRITE_BYTES, 11, + 0x08, 0xA0, 0x00, 0x00, + 0x07, 0xA0, 0x00, 0x00, + 0x00, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE2, + WRITE_BYTES, 12, + 0x11, 0x11, 0x44, 0x44, + 0x75, 0xA0, 0x00, 0x00, + 0x74, 0xA0, 0x00, 0x00, + + WRITE_COMMAND_8, 0xE3, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11, + + WRITE_C8_D16, 0xE4, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE5, + WRITE_BYTES, 16, + 0x0A, 0x71, 0xD8, 0xA0, + 0x0C, 0x73, 0xD8, 0xA0, + 0x0E, 0x75, 0xD8, 0xA0, + 0x10, 0x77, 0xD8, 0xA0, + + WRITE_COMMAND_8, 0xE6, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11, + + WRITE_C8_D16, 0xE7, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE8, + WRITE_BYTES, 16, + 0x09, 0x70, 0xD8, 0xA0, + 0x0B, 0x72, 0xD8, 0xA0, + 0x0D, 0x74, 0xD8, 0xA0, + 0x0F, 0x76, 0xD8, 0xA0, + + WRITE_COMMAND_8, 0xEB, + WRITE_BYTES, 7, + 0x02, 0x00, 0xE4, 0xE4, + 0x88, 0x00, 0x40, + + WRITE_C8_D16, 0xEC, 0x3C, 0x00, + + WRITE_COMMAND_8, 0xED, + WRITE_BYTES, 16, + 0xAB, 0x89, 0x76, 0x54, + 0x02, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x20, + 0x45, 0x67, 0x98, 0xBA, + + WRITE_COMMAND_8, 0xEF, + WRITE_BYTES, 6, + 0x08, 0x08, 0x08, 0x45, + 0x3F, 0x54, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13, + + WRITE_C8_D16, 0xE8, 0x00, 0x0E, + + WRITE_COMMAND_8, 0x20, // 0x20 normal, 0x21 IPS + WRITE_C8_D8, 0x3A, 0x50, // 0x70 RGB888, 0x60 RGB666, 0x50 RGB565 + + WRITE_COMMAND_8, 0x11, // Sleep Out + END_WRITE, + + DELAY, 150, + + BEGIN_WRITE, + WRITE_C8_D16, 0xE8, 0x00, 0x0C, + END_WRITE, + + DELAY, 100, + + BEGIN_WRITE, + WRITE_C8_D16, 0xE8, 0x00, 0x00, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x00, + + WRITE_COMMAND_8, 0x29, // Display On + END_WRITE, + DELAY, 20}; + +static const uint8_t st7701_type9_init_operations[] = { + + BEGIN_WRITE, + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13, + + WRITE_C8_D8, 0xEF, 0x08, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10, + + WRITE_C8_D16, 0xC0, 0x3B, 0x00, + WRITE_C8_D16, 0xC1, 0x0B, 0x02, + + WRITE_COMMAND_8, 0xC2, + WRITE_BYTES, 3, 0x30, 0x02, 0x37, + + WRITE_C8_D8, 0xCC, 0x10, + + WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control + WRITE_BYTES, 16, + 0x00, 0x0F, 0x16, 0x0E, + 0x11, 0x07, 0x09, 0x09, + 0x08, 0x23, 0x05, 0x11, + 0x0F, 0x28, 0x2D, 0x18, + + WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control + WRITE_BYTES, 16, + 0x00, 0x0F, 0x16, 0x0E, + 0x11, 0x07, 0x09, 0x08, + 0x09, 0x23, 0x05, 0x11, + 0x0F, 0x28, 0x2D, 0x18, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11, + + WRITE_C8_D8, 0xB0, 0x4D, + WRITE_C8_D8, 0xB1, 0x33, + WRITE_C8_D8, 0xB2, 0x87, + WRITE_C8_D8, 0xB5, 0x4B, + WRITE_C8_D8, 0xB7, 0x8C, + WRITE_C8_D8, 0xB8, 0x20, + WRITE_C8_D8, 0xC1, 0x78, + WRITE_C8_D8, 0xC2, 0x78, + WRITE_C8_D8, 0xD0, 0x88, + + WRITE_COMMAND_8, 0xE0, + WRITE_BYTES, 3, 0x00, 0x00, 0x02, + + WRITE_COMMAND_8, 0xE1, + WRITE_BYTES, 11, + 0x02, 0xF0, 0x00, 0x00, + 0x03, 0xF0, 0x00, 0x00, + 0x00, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE2, + WRITE_BYTES, 12, + 0x10, 0x10, 0x40, 0x40, + 0xF2, 0xF0, 0x00, 0x00, + 0xF2, 0xF0, 0x00, 0x00, + + WRITE_COMMAND_8, 0xE3, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11, + + WRITE_C8_D16, 0xE4, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE5, + WRITE_BYTES, 16, + 0x07, 0xEF, 0xF0, 0xF0, + 0x09, 0xF1, 0xF0, 0xF0, + 0x03, 0xF3, 0xF0, 0xF0, + 0x05, 0xED, 0xF0, 0xF0, + + WRITE_COMMAND_8, 0xE6, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11, + + WRITE_C8_D16, 0xE7, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE8, + WRITE_BYTES, 16, + 0x08, 0xF0, 0xF0, 0xF0, + 0x0A, 0xF2, 0xF0, 0xF0, + 0x04, 0xF4, 0xF0, 0xF0, + 0x06, 0xEE, 0xF0, 0xF0, + + WRITE_COMMAND_8, 0xEB, + WRITE_BYTES, 7, + 0x00, 0x00, 0xE4, 0xE4, + 0x44, 0x88, 0x40, + + WRITE_C8_D16, 0xEC, 0x78, 0x00, + + WRITE_COMMAND_8, 0xED, + WRITE_BYTES, 16, + 0x20, 0xF9, 0x87, 0x76, + 0x65, 0x54, 0x4F, 0xFF, + 0xFF, 0xF4, 0x45, 0x56, + 0x67, 0x78, 0x9F, 0x02, + + WRITE_COMMAND_8, 0xEF, + WRITE_BYTES, 6, + 0x10, 0x0D, 0x04, 0x08, + 0x3F, 0x1F, + + // WRITE_C8_D8, 0xCD, 0x05,//Test + + WRITE_C8_D8, 0x3A, 0x55, + + WRITE_C8_D8, 0x36, 0x08, + + WRITE_COMMAND_8, 0x11, + + // WRITE_COMMAND_8, 0xFF,//Test + // WRITE_BYTES, 5, + // 0x77, 0x01, 0x00, 0x00, + // 0x12, + + // WRITE_C8_D8, 0xD1, 0x81,//Test + // WRITE_C8_D8, 0xD2, 0x08,//Test + + WRITE_COMMAND_8, 0x29, // Display On + + // WRITE_C8_D8, 0x35, 0x00,//Test + // WRITE_C8_D8, 0xCE, 0x04,//Test + + // WRITE_COMMAND_8, 0xF2,//Test + // WRITE_BYTES, 4, + // 0xF0, 0xA3, 0xA3, 0x71, + + END_WRITE}; + +class Arduino_RGB_Display : public Arduino_GFX +{ +public: + Arduino_RGB_Display( + int16_t w, int16_t h, Arduino_ESP32RGBPanel *rgbpanel, uint8_t r = 0, bool auto_flush = true, + Arduino_DataBus *bus = NULL, int8_t rst = GFX_NOT_DEFINED, const uint8_t *init_operations = NULL, size_t init_operations_len = GFX_NOT_DEFINED); + + bool begin(int32_t speed = GFX_NOT_DEFINED) override; + void writePixelPreclipped(int16_t x, int16_t y, uint16_t color) override; + void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override; + void writeFastVLineCore(int16_t x, int16_t y, int16_t h, uint16_t color); + void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override; + void writeFastHLineCore(int16_t x, int16_t y, int16_t w, uint16_t color); + void writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) override; + void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip = 0) override; + void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h) override; + void draw16bitBeRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h) override; + void flush(void) override; + + uint16_t *getFramebuffer(); + + void XL_pinMode(uint8_t pin, uint8_t mode); + void XL_digitalWrite(uint8_t pin, uint8_t val); + int XL_digitalRead(uint8_t pin); + +protected: + uint16_t *_framebuffer; + size_t _framebuffer_size; + Arduino_ESP32RGBPanel *_rgbpanel; + bool _auto_flush; + Arduino_DataBus *_bus; + int8_t _rst; + const uint8_t *_init_operations; + size_t _init_operations_len; + int16_t MAX_X, MAX_Y; + +private: +}; + +#endif // _ARDUINO_RGB_DISPLAY_H_ + +#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3) diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/font/glcdfont.h b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/font/glcdfont.h new file mode 100644 index 00000000..630cba63 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/font/glcdfont.h @@ -0,0 +1,280 @@ +// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0. +// See gfxfont.h for newer custom bitmap font info. + +#ifndef FONT5X7_H +#define FONT5X7_H + +#ifdef __AVR__ +#include +#include +#elif defined(ESP8266) +#include +#elif defined(__IMXRT1052__) || defined(__IMXRT1062__) +// PROGMEM is defefind for T4 to place data in specific memory section +#undef PROGMEM +#define PROGMEM +#else +#define PROGMEM +#endif + +// Standard ASCII 5x7 font + +static const unsigned char font[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, + 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, + 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, + 0x18, 0x3C, 0x7E, 0x3C, 0x18, + 0x1C, 0x57, 0x7D, 0x57, 0x1C, + 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, + 0x00, 0x18, 0x3C, 0x18, 0x00, + 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, + 0x00, 0x18, 0x24, 0x18, 0x00, + 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, + 0x30, 0x48, 0x3A, 0x06, 0x0E, + 0x26, 0x29, 0x79, 0x29, 0x26, + 0x40, 0x7F, 0x05, 0x05, 0x07, + 0x40, 0x7F, 0x05, 0x25, 0x3F, + 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, + 0x7F, 0x3E, 0x1C, 0x1C, 0x08, + 0x08, 0x1C, 0x1C, 0x3E, 0x7F, + 0x14, 0x22, 0x7F, 0x22, 0x14, + 0x5F, 0x5F, 0x00, 0x5F, 0x5F, + 0x06, 0x09, 0x7F, 0x01, 0x7F, + 0x00, 0x66, 0x89, 0x95, 0x6A, + 0x60, 0x60, 0x60, 0x60, 0x60, + 0x94, 0xA2, 0xFF, 0xA2, 0x94, + 0x08, 0x04, 0x7E, 0x04, 0x08, + 0x10, 0x20, 0x7E, 0x20, 0x10, + 0x08, 0x08, 0x2A, 0x1C, 0x08, + 0x08, 0x1C, 0x2A, 0x08, 0x08, + 0x1E, 0x10, 0x10, 0x10, 0x10, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, + 0x30, 0x38, 0x3E, 0x38, 0x30, + 0x06, 0x0E, 0x3E, 0x0E, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x07, 0x00, + 0x14, 0x7F, 0x14, 0x7F, 0x14, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, + 0x23, 0x13, 0x08, 0x64, 0x62, + 0x36, 0x49, 0x56, 0x20, 0x50, + 0x00, 0x08, 0x07, 0x03, 0x00, + 0x00, 0x1C, 0x22, 0x41, 0x00, + 0x00, 0x41, 0x22, 0x1C, 0x00, + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, + 0x08, 0x08, 0x3E, 0x08, 0x08, + 0x00, 0x80, 0x70, 0x30, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x60, 0x60, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x02, + 0x3E, 0x51, 0x49, 0x45, 0x3E, + 0x00, 0x42, 0x7F, 0x40, 0x00, + 0x72, 0x49, 0x49, 0x49, 0x46, + 0x21, 0x41, 0x49, 0x4D, 0x33, + 0x18, 0x14, 0x12, 0x7F, 0x10, + 0x27, 0x45, 0x45, 0x45, 0x39, + 0x3C, 0x4A, 0x49, 0x49, 0x31, + 0x41, 0x21, 0x11, 0x09, 0x07, + 0x36, 0x49, 0x49, 0x49, 0x36, + 0x46, 0x49, 0x49, 0x29, 0x1E, + 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x40, 0x34, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x00, 0x41, 0x22, 0x14, 0x08, + 0x02, 0x01, 0x59, 0x09, 0x06, + 0x3E, 0x41, 0x5D, 0x59, 0x4E, + 0x7C, 0x12, 0x11, 0x12, 0x7C, + 0x7F, 0x49, 0x49, 0x49, 0x36, + 0x3E, 0x41, 0x41, 0x41, 0x22, + 0x7F, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x49, 0x49, 0x49, 0x41, + 0x7F, 0x09, 0x09, 0x09, 0x01, + 0x3E, 0x41, 0x41, 0x51, 0x73, + 0x7F, 0x08, 0x08, 0x08, 0x7F, + 0x00, 0x41, 0x7F, 0x41, 0x00, + 0x20, 0x40, 0x41, 0x3F, 0x01, + 0x7F, 0x08, 0x14, 0x22, 0x41, + 0x7F, 0x40, 0x40, 0x40, 0x40, + 0x7F, 0x02, 0x1C, 0x02, 0x7F, + 0x7F, 0x04, 0x08, 0x10, 0x7F, + 0x3E, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x09, 0x09, 0x09, 0x06, + 0x3E, 0x41, 0x51, 0x21, 0x5E, + 0x7F, 0x09, 0x19, 0x29, 0x46, + 0x26, 0x49, 0x49, 0x49, 0x32, + 0x03, 0x01, 0x7F, 0x01, 0x03, + 0x3F, 0x40, 0x40, 0x40, 0x3F, + 0x1F, 0x20, 0x40, 0x20, 0x1F, + 0x3F, 0x40, 0x38, 0x40, 0x3F, + 0x63, 0x14, 0x08, 0x14, 0x63, + 0x03, 0x04, 0x78, 0x04, 0x03, + 0x61, 0x59, 0x49, 0x4D, 0x43, + 0x00, 0x7F, 0x41, 0x41, 0x41, + 0x02, 0x04, 0x08, 0x10, 0x20, + 0x00, 0x41, 0x41, 0x41, 0x7F, + 0x04, 0x02, 0x01, 0x02, 0x04, + 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x03, 0x07, 0x08, 0x00, + 0x20, 0x54, 0x54, 0x78, 0x40, + 0x7F, 0x28, 0x44, 0x44, 0x38, + 0x38, 0x44, 0x44, 0x44, 0x28, + 0x38, 0x44, 0x44, 0x28, 0x7F, + 0x38, 0x54, 0x54, 0x54, 0x18, + 0x00, 0x08, 0x7E, 0x09, 0x02, + 0x18, 0xA4, 0xA4, 0x9C, 0x78, + 0x7F, 0x08, 0x04, 0x04, 0x78, + 0x00, 0x44, 0x7D, 0x40, 0x00, + 0x20, 0x40, 0x40, 0x3D, 0x00, + 0x7F, 0x10, 0x28, 0x44, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, + 0x7C, 0x04, 0x78, 0x04, 0x78, + 0x7C, 0x08, 0x04, 0x04, 0x78, + 0x38, 0x44, 0x44, 0x44, 0x38, + 0xFC, 0x18, 0x24, 0x24, 0x18, + 0x18, 0x24, 0x24, 0x18, 0xFC, + 0x7C, 0x08, 0x04, 0x04, 0x08, + 0x48, 0x54, 0x54, 0x54, 0x24, + 0x04, 0x04, 0x3F, 0x44, 0x24, + 0x3C, 0x40, 0x40, 0x20, 0x7C, + 0x1C, 0x20, 0x40, 0x20, 0x1C, + 0x3C, 0x40, 0x30, 0x40, 0x3C, + 0x44, 0x28, 0x10, 0x28, 0x44, + 0x4C, 0x90, 0x90, 0x90, 0x7C, + 0x44, 0x64, 0x54, 0x4C, 0x44, + 0x00, 0x08, 0x36, 0x41, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, + 0x00, 0x41, 0x36, 0x08, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x02, + 0x3C, 0x26, 0x23, 0x26, 0x3C, + 0x1E, 0xA1, 0xA1, 0x61, 0x12, + 0x3A, 0x40, 0x40, 0x20, 0x7A, + 0x38, 0x54, 0x54, 0x55, 0x59, + 0x21, 0x55, 0x55, 0x79, 0x41, + 0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut + 0x21, 0x55, 0x54, 0x78, 0x40, + 0x20, 0x54, 0x55, 0x79, 0x40, + 0x0C, 0x1E, 0x52, 0x72, 0x12, + 0x39, 0x55, 0x55, 0x55, 0x59, + 0x39, 0x54, 0x54, 0x54, 0x59, + 0x39, 0x55, 0x54, 0x54, 0x58, + 0x00, 0x00, 0x45, 0x7C, 0x41, + 0x00, 0x02, 0x45, 0x7D, 0x42, + 0x00, 0x01, 0x45, 0x7C, 0x40, + 0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut + 0xF0, 0x28, 0x25, 0x28, 0xF0, + 0x7C, 0x54, 0x55, 0x45, 0x00, + 0x20, 0x54, 0x54, 0x7C, 0x54, + 0x7C, 0x0A, 0x09, 0x7F, 0x49, + 0x32, 0x49, 0x49, 0x49, 0x32, + 0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut + 0x32, 0x4A, 0x48, 0x48, 0x30, + 0x3A, 0x41, 0x41, 0x21, 0x7A, + 0x3A, 0x42, 0x40, 0x20, 0x78, + 0x00, 0x9D, 0xA0, 0xA0, 0x7D, + 0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut + 0x3D, 0x40, 0x40, 0x40, 0x3D, + 0x3C, 0x24, 0xFF, 0x24, 0x24, + 0x48, 0x7E, 0x49, 0x43, 0x66, + 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, + 0xFF, 0x09, 0x29, 0xF6, 0x20, + 0xC0, 0x88, 0x7E, 0x09, 0x03, + 0x20, 0x54, 0x54, 0x79, 0x41, + 0x00, 0x00, 0x44, 0x7D, 0x41, + 0x30, 0x48, 0x48, 0x4A, 0x32, + 0x38, 0x40, 0x40, 0x22, 0x7A, + 0x00, 0x7A, 0x0A, 0x0A, 0x72, + 0x7D, 0x0D, 0x19, 0x31, 0x7D, + 0x26, 0x29, 0x29, 0x2F, 0x28, + 0x26, 0x29, 0x29, 0x29, 0x26, + 0x30, 0x48, 0x4D, 0x40, 0x20, + 0x38, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x38, + 0x2F, 0x10, 0xC8, 0xAC, 0xBA, + 0x2F, 0x10, 0x28, 0x34, 0xFA, + 0x00, 0x00, 0x7B, 0x00, 0x00, + 0x08, 0x14, 0x2A, 0x14, 0x22, + 0x22, 0x14, 0x2A, 0x14, 0x08, + 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code + 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block + 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block + 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x10, 0x10, 0x10, 0xFF, 0x00, + 0x14, 0x14, 0x14, 0xFF, 0x00, + 0x10, 0x10, 0xFF, 0x00, 0xFF, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x14, 0x14, 0x14, 0xFC, 0x00, + 0x14, 0x14, 0xF7, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x14, 0x14, 0xF4, 0x04, 0xFC, + 0x14, 0x14, 0x17, 0x10, 0x1F, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0x1F, 0x00, + 0x10, 0x10, 0x10, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0xF0, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xFF, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x14, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x1F, 0x10, 0x17, + 0x00, 0x00, 0xFC, 0x04, 0xF4, + 0x14, 0x14, 0x17, 0x10, 0x17, + 0x14, 0x14, 0xF4, 0x04, 0xF4, + 0x00, 0x00, 0xFF, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0xF7, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x17, 0x14, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0xF4, 0x14, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x00, 0x00, 0x1F, 0x10, 0x1F, + 0x00, 0x00, 0x00, 0x1F, 0x14, + 0x00, 0x00, 0x00, 0xFC, 0x14, + 0x00, 0x00, 0xF0, 0x10, 0xF0, + 0x10, 0x10, 0xFF, 0x10, 0xFF, + 0x14, 0x14, 0x14, 0xFF, 0x14, + 0x10, 0x10, 0x10, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x10, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x38, 0x44, 0x44, 0x38, 0x44, + 0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta + 0x7E, 0x02, 0x02, 0x06, 0x06, + 0x02, 0x7E, 0x02, 0x7E, 0x02, + 0x63, 0x55, 0x49, 0x41, 0x63, + 0x38, 0x44, 0x44, 0x3C, 0x04, + 0x40, 0x7E, 0x20, 0x1E, 0x20, + 0x06, 0x02, 0x7E, 0x02, 0x02, + 0x99, 0xA5, 0xE7, 0xA5, 0x99, + 0x1C, 0x2A, 0x49, 0x2A, 0x1C, + 0x4C, 0x72, 0x01, 0x72, 0x4C, + 0x30, 0x4A, 0x4D, 0x4D, 0x30, + 0x30, 0x48, 0x78, 0x48, 0x30, + 0xBC, 0x62, 0x5A, 0x46, 0x3D, + 0x3E, 0x49, 0x49, 0x49, 0x00, + 0x7E, 0x01, 0x01, 0x01, 0x7E, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x44, 0x44, 0x5F, 0x44, 0x44, + 0x40, 0x51, 0x4A, 0x44, 0x40, + 0x40, 0x44, 0x4A, 0x51, 0x40, + 0x00, 0x00, 0xFF, 0x01, 0x03, + 0xE0, 0x80, 0xFF, 0x00, 0x00, + 0x08, 0x08, 0x6B, 0x6B, 0x08, + 0x36, 0x12, 0x36, 0x24, 0x36, + 0x00, 0x06, 0x09, 0x09, 0x06, + 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x00, + 0x30, 0x40, 0xFF, 0x01, 0x01, + 0x00, 0x1F, 0x01, 0x01, 0x1E, + 0x00, 0x19, 0x1D, 0x17, 0x12, + 0x00, 0x3C, 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP +}; +#endif // FONT5X7_H diff --git a/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/gfxfont.h b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/gfxfont.h new file mode 100644 index 00000000..42cfcfc6 --- /dev/null +++ b/ESP32_AP-Flasher/lib2/Arduino_GFX-1.3.7/src/gfxfont.h @@ -0,0 +1,31 @@ +// Font structures for newer Adafruit_GFX (1.1 and later). +// Example fonts are included in 'Fonts' directory. +// To use a font in your Arduino sketch, #include the corresponding .h +// file and pass address of GFXfont struct to setFont(). Pass NULL to +// revert to 'classic' fixed-space bitmap font. + +#ifndef _GFXFONT_H_ +#define _GFXFONT_H_ + +/// Font data stored PER GLYPH +typedef struct +{ + uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap + uint8_t width; ///< Bitmap dimensions in pixels + uint8_t height; ///< Bitmap dimensions in pixels + uint8_t xAdvance; ///< Distance to advance cursor (x axis) + int8_t xOffset; ///< X dist from cursor pos to UL corner + int8_t yOffset; ///< Y dist from cursor pos to UL corner +} GFXglyph; + +/// Data stored for FONT AS A WHOLE +typedef struct +{ + uint8_t *bitmap; ///< Glyph bitmaps, concatenated + GFXglyph *glyph; ///< Glyph array + uint8_t first; ///< ASCII extents (first char) + uint8_t last; ///< ASCII extents (last char) + uint8_t yAdvance; ///< Newline distance (y axis) +} GFXfont; + +#endif // _GFXFONT_H_ diff --git a/ESP32_AP-Flasher/platformio.ini b/ESP32_AP-Flasher/platformio.ini index 57a3f5c6..bba91667 100644 --- a/ESP32_AP-Flasher/platformio.ini +++ b/ESP32_AP-Flasher/platformio.ini @@ -260,6 +260,73 @@ board_build.psram_type=qspi_opi board_upload.maximum_size = 16777216 board_upload.maximum_ram_size = 327680 board_upload.flash_size = 16MB +[env:ESP32_S3_16_8_LILYGO_AP] +board = esp32-s3-devkitc-1 +board_build.partitions = large_spiffs_16MB.csv +build_unflags = + -std=gnu++11 + -D ARDUINO_USB_MODE=1 + -D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y + ;-D ILI9341_DRIVER +lib_deps = + ${env.lib_deps} + lib2\Arduino_GFX-1.3.7 +build_flags = + -std=gnu++17 + ${env.build_flags} + -D HAS_TFT + -D HAS_LILYGO_TPANEL + -D CORE_DEBUG_LEVEL=0 + -D ARDUINO_USB_MODE=0 + -D CONFIG_ESP32S3_SPIRAM_SUPPORT=1 + -D CONFIG_SPIRAM_USE_MALLOC=1 + -D POWER_NO_SOFT_POWER + -D BOARD_HAS_PSRAM + -D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y + -D HAS_BLE_WRITER + -D FLASHER_AP_SS=-1 + -D FLASHER_AP_CLK=-1 + -D FLASHER_AP_MOSI=-1 + -D FLASHER_AP_MISO=-1 + -D FLASHER_AP_RESET=34 + -D FLASHER_AP_POWER={-1} + -D FLASHER_AP_TEST=-1 + + -D FLASHER_AP_TXD=48 + -D FLASHER_AP_RXD=47 + + -D FLASHER_DEBUG_TXD=43 + -D FLASHER_DEBUG_RXD=44 + -D FLASHER_DEBUG_PROG=33 + -D FLASHER_LED=-1 + ;-D HAS_RGB_LED + ;-D FLASHER_RGB_LED=48 + ;-D ST7789_DRIVER + -D TFT_WIDTH=480 + -D TFT_HEIGHT=480 + ;-D TFT_MISO=-1 + ;-D TFT_MOSI=13 + ;-D TFT_SCLK=12 + ;-D TFT_CS=10 + ;-D TFT_DC=11 + ;-D TFT_RST=1 + ;-D TFT_RGB_ORDER=TFT_BGR + -D USE_HSPI_PORT + -D LOAD_FONT2 + -D MD5_ENABLED=1 + -D SERIAL_FLASHER_INTERFACE_UART=1 + -D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50 + -D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100 + ;-D C6_OTA_FLASHING + ;-D HAS_SUBGHZ +build_src_filter = + +<*>--- +board_build.flash_mode=qio +board_build.arduino.memory_type = qio_qspi ;Enable external PSRAM +board_build.psram_type=qspi_opi +board_upload.maximum_size = 16777216 +board_upload.maximum_ram_size = 327680 +board_upload.flash_size = 16MB ; ---------------------------------------------------------------------------------------- ; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM ; ---------------------------------------------------------------------------------------- diff --git a/ESP32_AP-Flasher/src/ips_display.cpp b/ESP32_AP-Flasher/src/ips_display.cpp index 50926e4b..b4f0fdd1 100644 --- a/ESP32_AP-Flasher/src/ips_display.cpp +++ b/ESP32_AP-Flasher/src/ips_display.cpp @@ -19,7 +19,191 @@ uint8_t YellowSense = 0; bool tftLogscreen = true; bool tftOverride = false; +#ifdef HAS_LILYGO_TPANEL + + +static const uint8_t st7701_type9_init_operations_lilygo[] = { + + BEGIN_WRITE, + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13, + + WRITE_C8_D8, 0xEF, 0x08, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10, + + WRITE_C8_D16, 0xC0, 0x3B, 0x00, + WRITE_C8_D16, 0xC1, 0x0B, 0x02, + + WRITE_COMMAND_8, 0xC2, + WRITE_BYTES, 3, 0x30, 0x02, 0x37, + + WRITE_C8_D8, 0xCC, 0x10, + + WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control + WRITE_BYTES, 16, + 0x00, 0x0F, 0x16, 0x0E, + 0x11, 0x07, 0x09, 0x09, + 0x08, 0x23, 0x05, 0x11, + 0x0F, 0x28, 0x2D, 0x18, + + WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control + WRITE_BYTES, 16, + 0x00, 0x0F, 0x16, 0x0E, + 0x11, 0x07, 0x09, 0x08, + 0x09, 0x23, 0x05, 0x11, + 0x0F, 0x28, 0x2D, 0x18, + + WRITE_COMMAND_8, 0xFF, + WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11, + + WRITE_C8_D8, 0xB0, 0x4D, + WRITE_C8_D8, 0xB1, 0x33, + WRITE_C8_D8, 0xB2, 0x87, + WRITE_C8_D8, 0xB5, 0x4B, + WRITE_C8_D8, 0xB7, 0x8C, + WRITE_C8_D8, 0xB8, 0x20, + WRITE_C8_D8, 0xC1, 0x78, + WRITE_C8_D8, 0xC2, 0x78, + WRITE_C8_D8, 0xD0, 0x88, + + WRITE_COMMAND_8, 0xE0, + WRITE_BYTES, 3, 0x00, 0x00, 0x02, + + WRITE_COMMAND_8, 0xE1, + WRITE_BYTES, 11, + 0x02, 0xF0, 0x00, 0x00, + 0x03, 0xF0, 0x00, 0x00, + 0x00, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE2, + WRITE_BYTES, 12, + 0x10, 0x10, 0x40, 0x40, + 0xF2, 0xF0, 0x00, 0x00, + 0xF2, 0xF0, 0x00, 0x00, + + WRITE_COMMAND_8, 0xE3, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11, + + WRITE_C8_D16, 0xE4, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE5, + WRITE_BYTES, 16, + 0x07, 0xEF, 0xF0, 0xF0, + 0x09, 0xF1, 0xF0, 0xF0, + 0x03, 0xF3, 0xF0, 0xF0, + 0x05, 0xED, 0xF0, 0xF0, + + WRITE_COMMAND_8, 0xE6, + WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11, + + WRITE_C8_D16, 0xE7, 0x44, 0x44, + + WRITE_COMMAND_8, 0xE8, + WRITE_BYTES, 16, + 0x08, 0xF0, 0xF0, 0xF0, + 0x0A, 0xF2, 0xF0, 0xF0, + 0x04, 0xF4, 0xF0, 0xF0, + 0x06, 0xEE, 0xF0, 0xF0, + + WRITE_COMMAND_8, 0xEB, + WRITE_BYTES, 7, + 0x00, 0x00, 0xE4, 0xE4, + 0x44, 0x88, 0x40, + + WRITE_C8_D16, 0xEC, 0x78, 0x00, + + WRITE_COMMAND_8, 0xED, + WRITE_BYTES, 16, + 0x20, 0xF9, 0x87, 0x76, + 0x65, 0x54, 0x4F, 0xFF, + 0xFF, 0xF4, 0x45, 0x56, + 0x67, 0x78, 0x9F, 0x02, + + WRITE_COMMAND_8, 0xEF, + WRITE_BYTES, 6, + 0x10, 0x0D, 0x04, 0x08, + 0x3F, 0x1F, + + // WRITE_C8_D8, 0xCD, 0x05,//Test + + WRITE_C8_D8, 0x3A, 0x55, + + WRITE_C8_D8, 0x36, 0x08, + + WRITE_COMMAND_8, 0x11, + + // WRITE_COMMAND_8, 0xFF,//Test + // WRITE_BYTES, 5, + // 0x77, 0x01, 0x00, 0x00, + // 0x12, + + // WRITE_C8_D8, 0xD1, 0x81,//Test + // WRITE_C8_D8, 0xD2, 0x08,//Test + + WRITE_COMMAND_8, 0x29, // Display On + + // WRITE_C8_D8, 0x35, 0x00,//Test + // WRITE_C8_D8, 0xCE, 0x04,//Test + + // WRITE_COMMAND_8, 0xF2,//Test + // WRITE_BYTES, 4, + // 0xF0, 0xA3, 0xA3, 0x71, + + END_WRITE}; + +Arduino_DataBus *bus = new Arduino_XL9535SWSPI(IIC_SDA /* SDA */, IIC_SCL /* SCL */, -1 /* XL PWD */, + XL95X5_CS /* XL CS */, XL95X5_SCLK /* XL SCK */, XL95X5_MOSI /* XL MOSI */); +Arduino_ESP32RGBPanel *rgbpanel = new Arduino_ESP32RGBPanel( + -1 /* DE */, LCD_VSYNC /* VSYNC */, LCD_HSYNC /* HSYNC */, LCD_PCLK /* PCLK */, + LCD_B0 /* B0 */, LCD_B1 /* B1 */, LCD_B2 /* B2 */, LCD_B3 /* B3 */, LCD_B4 /* B4 */, + LCD_G0 /* G0 */, LCD_G1 /* G1 */, LCD_G2 /* G2 */, LCD_G3 /* G3 */, LCD_G4 /* G4 */, LCD_G5 /* G5 */, + LCD_R0 /* R0 */, LCD_R1 /* R1 */, LCD_R2 /* R2 */, LCD_R3 /* R3 */, LCD_R4 /* R4 */, + 1 /* hsync_polarity */, 20 /* hsync_front_porch */, 2 /* hsync_pulse_width */, 0 /* hsync_back_porch */, + 1 /* vsync_polarity */, 30 /* vsync_front_porch */, 8 /* vsync_pulse_width */, 1 /* vsync_back_porch */, + 10 /* pclk_active_neg */, 6000000L /* prefer_speed */, false /* useBigEndian */, + 0 /* de_idle_high*/, 0 /* pclk_idle_high */); +Arduino_RGB_Display *gfx = new Arduino_RGB_Display( + LCD_WIDTH /* width */, LCD_HEIGHT /* height */, rgbpanel, 0 /* rotation */, true /* auto_flush */, + bus, -1 /* RST */, st7701_type9_init_operations_lilygo, sizeof(st7701_type9_init_operations_lilygo)); + +#endif + void TFTLog(String text) { + + #ifdef HAS_LILYGO_TPANEL + + gfx->setTextSize(2); + + if (tftLogscreen == false) { + gfx->fillScreen(BLACK); + gfx->setCursor(0, 0); + tftLogscreen = true; + } + if (text.isEmpty()) return; + gfx->setTextColor(LIGHTGREY); + if (text.startsWith("!")) { + gfx->setTextColor(RED); + text = text.substring(1); + } else if (text.indexOf("http") != -1) { + int httpIndex = text.indexOf("http"); + gfx->print(text.substring(0, httpIndex)); + gfx->setTextColor(YELLOW); + text = text.substring(httpIndex); + } else if (text.indexOf(":") != -1) { + int colonIndex = text.indexOf(":"); + gfx->setTextColor(LIGHTGREY); + gfx->print(text.substring(0, colonIndex + 1)); + gfx->setTextColor(WHITE); + text = text.substring(colonIndex + 1); + } else if (text.endsWith("!")) { + gfx->setTextColor(GREEN); + } + gfx->println(text); + + #else + if (tftLogscreen == false) { tft2.fillScreen(TFT_BLACK); tft2.setCursor(0, 0, (tft2.width() == 160 ? 1 : 2)); @@ -53,6 +237,7 @@ void TFTLog(String text) { tft2.setTextColor(TFT_GREEN); } tft2.println(text); + #endif } int32_t findId(uint8_t mac[8]) { @@ -72,7 +257,11 @@ void sendAvail(uint8_t wakeupReason) { memcpy(&eadr.src, mac, 6); eadr.adr.lastPacketRSSI = WiFi.RSSI(); eadr.adr.currentChannel = config.channel; + #ifdef HAS_LILYGO_TPANEL + eadr.adr.hwType = 0xE2; + #else eadr.adr.hwType = (tft2.width() == 160 ? 0xE1 : 0xE0); + #endif eadr.adr.wakeupReason = wakeupReason; eadr.adr.capabilities = 0; eadr.adr.tagSoftwareVersion = 0; @@ -81,6 +270,20 @@ void sendAvail(uint8_t wakeupReason) { } void yellow_ap_display_init(void) { + + #ifdef HAS_LILYGO_TPANEL + + tftLogscreen = true; + + pinMode(LCD_BL, OUTPUT); + digitalWrite(LCD_BL, HIGH); + + Wire.begin(IIC_SDA, IIC_SCL); + + gfx->begin(); + gfx->fillScreen(BLACK); + + #else pinMode(YELLOW_SENSE, INPUT_PULLDOWN); vTaskDelay(100 / portTICK_PERIOD_MS); if (digitalRead(YELLOW_SENSE) == HIGH) YellowSense = 1; @@ -105,6 +308,7 @@ void yellow_ap_display_init(void) { GPIO.func_out_sel_cfg[TFT_BACKLIGHT].inv_sel = 1; } ledcWrite(6, config.tft); + #endif } void yellow_ap_display_loop(void) { @@ -146,7 +350,28 @@ void yellow_ap_display_loop(void) { void* spriteData = spr.getPointer(); size_t bytesRead = file.readBytes((char*)spriteData, spr.width() * spr.height() * 2); file.close(); + + #ifdef HAS_LILYGO_TPANEL + long dy = spr.height(); + long dx = spr.width(); + + uint16_t* data = static_cast(const_cast(spriteData)); + + for (int16_t j = 0; j < dy; j++) + { + for (int16_t i = 0; i < dx; i++) + { + uint16_t color = *data; + color = color<<8 | color>>8; + *data = color; + data++; + } + } + gfx->draw16bitRGBBitmap(0, 0, (uint16_t *)spriteData, dx, dy); + #else spr.pushSprite(0, 0); + #endif + tftLogscreen = false; struct espXferComplete xfc = {0}; diff --git a/ESP32_AP-Flasher/src/makeimage.cpp b/ESP32_AP-Flasher/src/makeimage.cpp index f3d1c5a5..49b1116d 100644 --- a/ESP32_AP-Flasher/src/makeimage.cpp +++ b/ESP32_AP-Flasher/src/makeimage.cpp @@ -80,6 +80,7 @@ uint32_t colorDistance(Color &c1, Color &c2, Error &e1) { } void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t buffer_size, bool is_red) { + uint8_t rotate = imageParams.rotate; long bufw = spr.width(), bufh = spr.height(); @@ -286,7 +287,29 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) { size_t dataSize = spr.width() * spr.height() * (spr.getColorDepth() / 8); memcpy(spriteData2, spriteData, dataSize); + #ifdef HAS_LILYGO_TPANEL + if (spr.getColorDepth() == 16) + { + long dy = spr.height(); + long dx = spr.width(); + + uint16_t* data = static_cast(const_cast(spriteData2)); + + for (int16_t j = 0; j < dy; j++) + { + for (int16_t i = 0; i < dx; i++) + { + uint16_t color = *data; + color = color<<8 | color>>8; + *data = color; + data++; + } + } + gfx->draw16bitRGBBitmap(0, 0, (uint16_t *)spriteData2, dx, dy); + } + #else spr2.pushSprite(0, 0); + #endif } return; } diff --git a/resources/tagtypes/E2.json b/resources/tagtypes/E2.json new file mode 100644 index 00000000..591ce03b --- /dev/null +++ b/resources/tagtypes/E2.json @@ -0,0 +1,64 @@ +{ + "version": 1, + "name": "LILYGO TPANEL 4\"", + "width": 480, + "height": 480, + "rotatebuffer": 0, + "bpp": 16, + "colortable": { + "white": [ 255, 255, 255 ], + "black": [ 0, 0, 0 ], + "red": [ 255, 0, 0 ] + }, + "shortlut": 0, + "options": [ ], + "contentids": [ 22, 1, 2, 3, 4, 8, 7, 19, 10, 11, 21 ], + "template": { + "21": [ + { "box": [ 0, 0, 480, 480, 1 ] }, + { "text": [ 10, 15, "OpenEpaperLink AP", "calibrib30", 2, 0, 0, 1 ] }, + { "text": [ 10, 70, "IP address:", "bahnschrift30", "#888888", 0, 0, 1 ] }, + { "text": [ 180, 70, "{ap_ip}", "bahnschrift30", 0, 0, 0, 1 ] }, + { "text": [ 10, 110, "Channel:", "bahnschrift30", "#888888", 0, 0, 1 ] }, + { "text": [ 180, 110, "{ap_ch}", "bahnschrift30", 0, 0, 0, "1" ] }, + { "text": [ 10, 150, "Tag count:", "bahnschrift30", "#888888", 0, 0, 1 ] }, + { "text": [ 180, 150, "{ap_tagcount}", "bahnschrift30", 0, 0, 0, "1" ] } + ], + "1": { + "weekday": [ 240, 30, "Signika-SB.ttf", 90 ], + "month": [ 240, 330, "Signika-SB.ttf", 90 ], + "day": [ 240, 80, "Signika-SB.ttf", 250 ] + }, + "4": { + "location": [ 20, 20, "fonts/calibrib30" ], + "wind": [ 90, 95, "fonts/calibrib50" ], + "temp": [ 20, 200, "fonts/calibrib100" ], + "icon": [ 400, 30, 150, 2 ], + "dir": [ 40, 70, 80 ], + "umbrella": [ 325, 250, 150 ] + }, + "2": { + "fonts": [ "Signika-SB.ttf", 150, 150, 110, 80, 60, 50 ], + "xy": [ 240, 240 ] + }, + "8": { + "location": [ 10, 20, "fonts/calibrib50" ], + "column": [ 6, 80 ], + "day": [ 40, 100, "fonts/bahnschrift30", 144, 270 ], + "rain": [ 40, 320 ], + "icon": [ 40, 180, 50 ], + "wind": [ 17, 120 ], + "line": [ 100, 340 ] + }, + "10": { + "title": [ 240, 10, "fonts/bahnschrift20" ], + "pos": [ 240, 35 ] + }, + "11": { + "rotate": 0, + "mode": 1, + "days": 4, + "gridparam": [ 5, 17, 20, "calibrib16.vlw", "tahoma9.vlw", 14 ] + } + } +}