diff --git a/MicroPython_BUILD/.settings/language.settings.xml b/MicroPython_BUILD/.settings/language.settings.xml index a3d2bfd4..e93938fc 100644 --- a/MicroPython_BUILD/.settings/language.settings.xml +++ b/MicroPython_BUILD/.settings/language.settings.xml @@ -4,8 +4,8 @@ - - + + diff --git a/MicroPython_BUILD/BUILD.sh b/MicroPython_BUILD/BUILD.sh index a2c039a5..5db2b7b7 100755 --- a/MicroPython_BUILD/BUILD.sh +++ b/MicroPython_BUILD/BUILD.sh @@ -26,6 +26,8 @@ # size - display static memory footprint of the firmware # size-components - display detailed memory footprint of the firmware # size-files - display detailed memory footprint of the firmware +# miniterm - start pySerial command line program miniterm +# monitor - start esp-idf terminal emulator # Options: # -jN - make with multicore option, N should be the number of cores used @@ -50,8 +52,8 @@ #======================= -TOOLS_VER=ver20180628.id -BUILD_VER=ver20180628.id +TOOLS_VER=ver20180827.id +BUILD_VER=ver20180827.id #======================= # ----------------------------- diff --git a/MicroPython_BUILD/build_func.sh b/MicroPython_BUILD/build_func.sh index 5115f1b8..3588d89b 100755 --- a/MicroPython_BUILD/build_func.sh +++ b/MicroPython_BUILD/build_func.sh @@ -660,6 +660,13 @@ executeCommand() { echo "======================" make erase_flash${BUILD_COMPORT}${BUILD_BDRATE} + # ------------------------------------ + elif [ "${arg}" == "miniterm" ]; then + echo "=====================" + echo "Executing miniterm..." + echo "=====================" + make simple_monitor${BUILD_COMPORT} + # ---------------------------------- elif [ "${arg}" == "monitor" ]; then echo "============================" diff --git a/MicroPython_BUILD/components/curl/include/curl/curl.h b/MicroPython_BUILD/components/curl/include/curl/curl.h index 86b9b708..af21768d 100644 --- a/MicroPython_BUILD/components/curl/include/curl/curl.h +++ b/MicroPython_BUILD/components/curl/include/curl/curl.h @@ -30,6 +30,8 @@ * https://cool.haxx.se/mailman/listinfo/curl-library/ */ +#include "sdkconfig.h" + #define SIZEOF_CURL_OFF_T 4 #ifdef CURL_NO_OLDIES @@ -218,7 +220,7 @@ typedef int (*curl_xferinfo_callback)(void *clientp, #ifndef CURL_MAX_READ_SIZE /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */ -#define CURL_MAX_READ_SIZE 524288 +#define CURL_MAX_READ_SIZE 16384 #endif #ifndef CURL_MAX_WRITE_SIZE @@ -228,8 +230,12 @@ typedef int (*curl_xferinfo_callback)(void *clientp, time for those who feel adventurous. The practical minimum is about 400 bytes since libcurl uses a buffer of this size as a scratch area (unrelated to network send operations). */ +#ifdef CONFIG_MICROPY_CURL_MAX_WRITE_SIZE +#define CURL_MAX_WRITE_SIZE CONFIG_MICROPY_CURL_MAX_WRITE_SIZE +#else #define CURL_MAX_WRITE_SIZE 16384 #endif +#endif #ifndef CURL_MAX_HTTP_HEADER /* The only reason to have a max limit for this is to avoid the risk of a bad diff --git a/MicroPython_BUILD/components/curl/lib/connect.c b/MicroPython_BUILD/components/curl/lib/connect.c index 3edb71eb..6eb38c26 100644 --- a/MicroPython_BUILD/components/curl/lib/connect.c +++ b/MicroPython_BUILD/components/curl/lib/connect.c @@ -1409,11 +1409,13 @@ void Curl_conncontrol(struct connectdata *conn, bool closeit = (ctrl == CONNCTRL_CONNECTION) || ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM)); if((ctrl == CONNCTRL_STREAM) && - (conn->handler->flags & PROTOPT_STREAM)) - DEBUGF(infof(conn->data, "Kill stream: %s\n", reason)); + (conn->handler->flags & PROTOPT_STREAM)) { + //DEBUGF(infof(conn->data, "Kill stream: %s\n", reason)); + DEBUGF(infof(conn->data, "Kill stream\n")); + } else if(closeit != conn->bits.close) { - DEBUGF(infof(conn->data, "Marked for [%s]: %s\n", - closeit?"closure":"keep alive", reason)); + //DEBUGF(infof(conn->data, "Marked for [%s]: %s\n", closeit?"closure":"keep alive", reason)); + DEBUGF(infof(conn->data, "Marked for [%s]\n", closeit?"closure":"keep alive")); conn->bits.close = closeit; /* the only place in the source code that should assign this bit */ } diff --git a/MicroPython_BUILD/components/micropython/Kconfig.projbuild b/MicroPython_BUILD/components/micropython/Kconfig.projbuild index 603d64ac..10c6ee14 100644 --- a/MicroPython_BUILD/components/micropython/Kconfig.projbuild +++ b/MicroPython_BUILD/components/micropython/Kconfig.projbuild @@ -322,14 +322,73 @@ menu "MicroPython" default n help Include Display module into build - Display module includes support for various SPI TFT displays + + config MICROPY_USE_TFT + depends on MICROPY_USE_DISPLAY + bool "Enable support for SPI TFT displays" + default y + help + Include support for various SPI TFT displays + + config MICROPY_USE_EPD + depends on MICROPY_USE_DISPLAY + bool "Enable support for ePaper displays (NOT COMPLETE, DO NOT ENABLE)" + default n + help + Include support for ePaper displays into build config MICROPY_USE_EVE - bool "Use EVE display module (experimental, do not enable)" + depends on MICROPY_USE_DISPLAY + bool "Enable support for EVE (FT8xx) displays" default n help - Include EVE display module into build - Display module includes support for EVE displays (FT80x, FT81x) + Includes support for EVE displays (FT80x, FT81x) + + menu "EVE Configuration" + depends on MICROPY_USE_EVE + config MICROPY_EVE_FT81X + bool "EVE FT81X type" + depends on MICROPY_USE_EVE + default y + help + Used FT8xx chip is FT81x + If not set, the code for FT80x will be compiled + + config EVE_MODE_TYPE + int + default 0 if FT8_USER_TYPE + default 1 if FT8_FT810CB_HY50HD + default 2 if FT8_FT811CB_HY50HD + default 3 if FT8_VM800B35A + default 4 if FT8_VM800B43A + default 5 if FT8_VM800B50A + default 6 if FT8_EVE2_50G + default 6 if FT8_EVE2_TEST + + choice + prompt "Select predefined EVE display type" + default EVE_MODE_TYPE1 + help + Select predefined EVE display type + + config FT8_USER_TYPE + bool "User defined" + config FT8_FT810CB_HY50HD + bool "FT810CB-HY50HD: FT810 800x480 5\", HAOYU" + config FT8_FT811CB_HY50HD + bool "FT811CB-HY50HD: FT810 800x480 5\", HAOYU" + config FT8_VM800B35A + bool "VM800B35A: FT800 320x240 3.5\", FTDI" + config FT8_VM800B43A + bool "VM800B43A: FT800 480x272 4.4\", FTDI/BRT" + config FT8_VM800B50A + bool "VM800B50A: FT800 480x272 5\", FTDI/BRT" + config FT8_EVE2_50G + bool "800x480 5.0\" capacitive touch, FT813" + config FT8_EVE2_TEST + bool "TEST display" + endchoice + endmenu config MICROPY_USE_GSM bool "Use GSM module" @@ -384,6 +443,13 @@ menu "MicroPython" help Include mDNS module into build + config MICROPY_USE_REQUESTS + bool "Use requests module" + default y + help + Include requests module into build + The module ofers less features than curl, but uses far les resources + config MICROPY_USE_CURL bool "Use Curl module" default n @@ -391,6 +457,15 @@ menu "MicroPython" Include CURL module into build Using CURL module will add ~230 KB to your flash code size + config MICROPY_CURL_MAX_WRITE_SIZE + int "Curl max write buffer size" + depends on MICROPY_USE_CURL + range 1024 16384 + default 8192 + help + Curl buffer size used in many Curl functions + If not using SPIRAM, it may be necessary to set the size to the lower value + config MICROPY_USE_CURL_TLS bool "Enable TLS in Curl module" depends on MICROPY_USE_CURL diff --git a/MicroPython_BUILD/components/micropython/component.mk b/MicroPython_BUILD/components/micropython/component.mk index 695f86f1..effba065 100644 --- a/MicroPython_BUILD/components/micropython/component.mk +++ b/MicroPython_BUILD/components/micropython/component.mk @@ -261,8 +261,9 @@ LIBS_SRC_C = $(addprefix esp32/libs/,\ littleflash.c \ ) -ifdef CONFIG_MICROPY_USE_DISPLAY +ifdef CONFIG_MICROPY_USE_TFT LIBS_SRC_C += \ + esp32/moddisplay_tft.c \ esp32/libs/tft/tftspi.c \ esp32/libs/tft/tft.c \ esp32/libs/tft/comic24.c \ @@ -278,7 +279,8 @@ endif ifdef CONFIG_MICROPY_USE_EVE LIBS_SRC_C += \ - esp32/libs/eve/FT8_commands.c + esp32/libs/eve/FT8_commands.c \ + esp32/moddisplay_eve.c endif ifeq ($(MICROPY_PY_BTREE),1) diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/curl_mail.c b/MicroPython_BUILD/components/micropython/esp32/libs/curl_mail.c index 129ee374..d95f0980 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/curl_mail.c +++ b/MicroPython_BUILD/components/micropython/esp32/libs/curl_mail.c @@ -640,6 +640,8 @@ const char* curlmail_protocol_send(curl_mail mail_object, const char* smtpserver if (curl_progress) curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1L); + curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 2048); + //send the message MP_THREAD_GIL_EXIT(); result = curl_easy_perform(curl); diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/curl_mail.h b/MicroPython_BUILD/components/micropython/esp32/libs/curl_mail.h index a7660728..747f3f33 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/curl_mail.h +++ b/MicroPython_BUILD/components/micropython/esp32/libs/curl_mail.h @@ -39,6 +39,9 @@ extern "C" { #define CURLMAIL_PROTOCOL_SMTP 1 #define CURLMAIL_PROTOCOL_SMTPS 2 +#define CURLMAIL_PROTOCOL_IMAP 3 +#define CURLMAIL_PROTOCOL_IMAPS 4 + #define CURLMAIL_MAX_ATTACHMENTS 4 diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.c b/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.c index 09e1cb3c..29443a2f 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.c +++ b/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.c @@ -30,6 +30,7 @@ #if defined(CONFIG_MICROPY_USE_CURL) || defined(CONFIG_MICROPY_USE_SSH) #include +#include #include "freertos/FreeRTOS.h" #include "libs/espcurl.h" #include "libs/libGSM.h" @@ -46,28 +47,11 @@ #include "esp_wifi_types.h" #include "tcpip_adapter.h" +#include "modnetwork.h" #include "modmachine.h" #include "py/mpthread.h" #include "py/nlr.h" - -//-------------------- -void checkConnection() -{ - tcpip_adapter_ip_info_t info; - tcpip_adapter_get_ip_info(WIFI_IF_STA, &info); - if (info.ip.addr == 0) { - #ifdef CONFIG_MICROPY_USE_GSM - if (ppposStatus() != GSM_STATE_CONNECTED) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "No Internet connection")); - } - #else - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "No Internet connection")); - #endif - } -} - - #ifdef CONFIG_MICROPY_USE_CURL const char *CURL_TAG = "[Curl]"; @@ -130,7 +114,7 @@ static size_t curlWrite(void *buffer, size_t size, size_t nmemb, void *userdata) if ((s->status == 0) && ((size*nmemb) > 0)) { for (int i=0; i<(size*nmemb); i++) { if (s->len < (s->maxlen-2)) { - if (((buf[i] == 0x0a) || (buf[i] == 0x0d)) || ((buf[i] >= 0x20) && (buf[i] >= 0x20))) s->ptr[s->len] = buf[i]; + if ((buf[i] == 0x0a) || (buf[i] == 0x0d) || (buf[i] == 0x09) || (buf[i] >= 0x20)) s->ptr[s->len] = buf[i]; else s->ptr[s->len] = '.'; s->len++; s->ptr[s->len] = '\0'; @@ -382,6 +366,161 @@ int Curl_GET(char *url, char *fname, char *hdr, char *body, int hdrlen, int body return err; } +// Converts an integer value to its hex character +//----------------------------- +static char to_hex(char code) { + static char hex[] = "0123456789abcdef"; + return hex[code & 15]; +} + +//------------------------------------------------------------ +/* Returns a url encoded version of str + * IMPORTANT: be sure to free() the returned string after use + */ +//================================= +char *url_encode(const char *str) { + const char *pstr = str; + char *buf = malloc(strlen(str) * 3 + 1); + char *pbuf = buf; + while (*pstr) { + if (*pstr == ' ') { + *pbuf++ = '%'; + *pbuf++ = to_hex(*pstr >> 4); + *pbuf++ = to_hex(*pstr & 15); + } + else { + *pbuf++ = *pstr; + } + pstr++; + } + *pbuf = '\0'; + return buf; +} + +//========================================================================================================================================================================================= +int Curl_IMAP_GET(const char *opts, char *fname, char *hdr, char *body, int hdrlen, int bodylen, const char* imapserver, unsigned int imapport, const char* username, const char* password) +{ + CURL *curl = NULL; + CURLcode res = 0; + FILE* file = NULL; + int err = 0; + + if ((hdr) && (hdrlen < MIN_HDR_BUF_LEN)) { + err = -1; + goto exit; + } + if ((body) && (bodylen < MIN_BODY_BUF_LEN)) { + err = -2; + goto exit; + } + + struct curl_Transfer get_data; + struct curl_Transfer get_header; + + if (!curl_initialized) { + res = curl_global_init(CURL_GLOBAL_DEFAULT); + if (res) { + err = -3; + goto exit; + } + curl_initialized = 1; + } + + // Create a curl curl + curl = curl_easy_init(); + if (curl == NULL) { + err = -4; + goto exit; + } + + init_curl_Transfer(curl, &get_data, body, bodylen, NULL); + init_curl_Transfer(curl, &get_header, hdr, hdrlen, NULL); + + if (fname) { + if (strcmp(fname, "simulate") == 0) { + get_data.tofile = 1; + curl_sim_fs = 1; + } + else { + file = fopen(fname, "wb"); + if (file == NULL) { + err = -5; + goto exit; + } + get_data.file = file; + get_data.tofile = 1; + curl_sim_fs = 0; + } + } + + //set destination URL + char* url; + char *opts_out = url_encode(opts); + int opts_len = strlen(opts_out); + size_t len = strlen(imapserver) + opts_len + 16; + if ((url = (char*)malloc(len)) == NULL) { + free(opts_out); + ESP_LOGE(CURL_TAG, "Error allocating memory"); + err = -6; + goto exit; + } + + sprintf(url, "imaps://%s:%u/%s", imapserver, imapport, opts_out); + free(opts_out); + + curl_easy_setopt(curl, CURLOPT_URL, url); + printf("=== URL=[%s]\n", url); + free(url); + + _set_default_options(curl); + + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curlWrite); + curl_easy_setopt(curl, CURLOPT_HEADERDATA, &get_header); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWrite); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &get_data); + + // Try using Transport Layer Security (TLS), but continue anyway if it fails + curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY); + + //set authentication credentials if provided + if (username && *username) curl_easy_setopt(curl, CURLOPT_USERNAME, username); + if (password) curl_easy_setopt(curl, CURLOPT_PASSWORD, password); + + // Only allow IMAPS, we do not want this to work when unencrypted. + curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_IMAPS); + + // Perform the request, res will get the return code + res = curl_easy_perform(curl); + + if (res != CURLE_OK) { + if (curl_verbose) { + ESP_LOGE(CURL_TAG, "curl_easy_perform failed: %s", curl_easy_strerror(res)); + } + if (body) snprintf(body, bodylen, "%s", curl_easy_strerror(res)); + err = -7; + goto exit; + } + + if (get_data.tofile) { + if (curl_progress) { + double curtime = 0; + curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &curtime); + ESP_LOGI(CURL_TAG, "* Download: received %d B; time=%0.1f s; speed=%0.1f KB/sec", get_data.len, curtime, (float)(((get_data.len*10)/curtime) / 10240.0)); + } + if (body) { + if (strcmp(fname, "simulate") == 0) snprintf(body, bodylen, "SIMULATED save to file; size=%d", get_data.len); + else snprintf(body, bodylen, "Saved to file %s, size=%d", fname, get_data.len); + } + } + +exit: + // Cleanup + if (file) fclose(file); + if (curl) curl_easy_cleanup(curl); + + return err; +} //======================================================================= int Curl_POST(char *url , char *hdr, char *body, int hdrlen, int bodylen) @@ -467,6 +606,7 @@ int Curl_POST(char *url , char *hdr, char *body, int hdrlen, int bodylen) return err; } +//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- #ifdef CONFIG_MICROPY_USE_CURLFTP //=================================================================================================================== diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.h b/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.h index 9de8f4b3..7b001339 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.h +++ b/MicroPython_BUILD/components/micropython/esp32/libs/espcurl.h @@ -47,6 +47,8 @@ #define GMAIL_SMTP "smtp.gmail.com" #define GMAIL_PORT 465 +#define GMAIL_IMAP "imap.gmail.com" +#define GMAIL_IMAP_PORT 993 struct curl_httppost *formpost; struct curl_httppost *lastptr; @@ -82,6 +84,10 @@ extern uint8_t curl_nodecode; int Curl_GET(char *url, char *fname, char *hdr, char *body, int hdrlen, int bodylen); +//========================================================================================================================================================================================== +int Curl_IMAP_GET(const char *opts, char *fname, char *hdr, char *body, int hdrlen, int bodylen, const char* imapserver, unsigned int imapport, const char* username, const char* password); + + /* * ----------------------------------------------------- * int res = Curl_POST(url, hdr, body, hdrlen, bodylen); @@ -160,8 +166,9 @@ int ssh_SCP(uint8_t type, char *server, char *port, char * scppath, char *user, #endif // CONFIG_MICROPY_USE_SSH -//===================== -void checkConnection(); + +//================================ +char *url_encode(const char *str); #endif // defined(CONFIG_MICROPY_USE_CURL) || defined(CONFIG_MICROPY_USE_SSH) diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/eve/FT8.h b/MicroPython_BUILD/components/micropython/esp32/libs/eve/FT8.h index 9bd977cb..d55e980c 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/eve/FT8.h +++ b/MicroPython_BUILD/components/micropython/esp32/libs/eve/FT8.h @@ -28,40 +28,16 @@ * THE SOFTWARE. */ -/* -@file FT8.h -@brief Contains FT80x/FT81x API definitions -@version 3.2 -@date 2017-04-08 -@author Rudolph Riedel - -@section History - -2.1 -- changes to this header -2.2 -- commented out "#define DISPLAY() ((0UL<<24))" as it collides with a define in the Arduino IDE - the whole section of "macros" needs a rework... - -3.0 -- renamed from FT800.h to FT8.h -- changed FT_ prefixes to FT8_ -- switched to standard-C compliant comment-style -- changed FT81x register definitions from decimal to hex -- verified all FT81x register definitions -- moved FT81x registers marked as "reserved" to an #if 0 block +#ifndef _FT8_H_ +#define _FT8_H_ -3.1 -- moved several undocumented commands to an #if 0 block +#include "sdkconfig.h" -3.2 -- moved CMD_CRC to the block of undocumented commands as well -*/ +#if CONFIG_MICROPY_USE_EVE #include "FT8_commands.h" -#ifndef _FT8_H_ -#define _FT8_H_ #define DL_CLEAR 0x26000000UL /* requires OR'd arguments */ @@ -763,4 +739,508 @@ #endif + +/* The following predifined configurations are available + ----------------------------------------------------- + #define FT8_VM800B35A + #define FT8_VM800B43A + #define FT8_VM800B50A + #define FT8_VM810C + #define FT8_ME812A + #define FT8_ME813A + #define FT8_FT810CB_HY50HD + #define FT8_FT811CB_HY50HD + #define FT8_ET07 + #define FT8_RVT70AQ + #define FT8_EVE2_29 + #define FT8_EVE2_35 + #define FT8_EVE2_35G + #define FT8_EVE2_38 + #define FT8_EVE2_38G + #define FT8_EVE2_43 + #define FT8_EVE2_43G + #define FT8_EVE2_50 + #define FT8_EVE2_50G + #define FT8_EVE2_70 + #define FT8_EVE2_70G + #define FT8_NHD_35 + #define FT8_NHD_43 + #define FT8_NHD_50 + #define FT8_NHD_70 + #define FT8_ADAM101 +*/ + + +/* + * ================================= + * display timing parameters below + * ================================= +*/ + +/* VM800B35A: FT800 320x240 3.5" FTDI */ +#if defined (CONFIG_FT8_VM800B35A) +#define FT8_HSIZE (320L) /* Thd Length of visible part of line (in PCLKs) - display width */ +#define FT8_VSIZE (240L) /* Tvd Number of visible lines (in lines) - display height */ + +#define FT8_VSYNC0 (0L) /* Tvf Vertical Front Porch */ +#define FT8_VSYNC1 (2L) /* Tvf + Tvp Vertical Front Porch plus Vsync Pulse width */ +#define FT8_VOFFSET (13L) /* Tvf + Tvp + Tvb Number of non-visible lines (in lines) */ +#define FT8_VCYCLE (263L) /* Tv Total number of lines (visible and non-visible) (in lines) */ +#define FT8_HSYNC0 (0L) /* Thf Horizontal Front Porch */ +#define FT8_HSYNC1 (10L) /* Thf + Thp Horizontal Front Porch plus Hsync Pulse width */ +#define FT8_HOFFSET (70L) /* Thf + Thp + Thb Length of non-visible part of line (in PCLK cycles) */ +#define FT8_HCYCLE (408L) /* Th Total length of line (visible and non-visible) (in PCLKs) */ +#define FT8_PCLKPOL (0L) /* PCLK polarity (0 = rising edge, 1 = falling edge) */ +#define FT8_SWIZZLE (2L) /* Defines the arrangement of the RGB pins of the FT800 */ +#define FT8_PCLK (8L) /* 48MHz / REG_PCLK = PCLK frequency */ +#define FT8_CSPREAD (1L) /* helps with noise, when set to 1 fewer signals are changed simultaneously, reset-default: 1 */ +#define FT8_TOUCH_RZTHRESH (1200L) /* touch-sensitivity */ +#define FT8_HAS_CRYSTAL /* use external crystal or internal oscillator? */ +#endif + + +/* FTDI/BRT EVE modules VM800B43A and VM800B50A FT800 480x272 4.3" and 5.0" */ +#if defined (CONFIG_FT8_VM800B43A) || defined (FT8_VM800B50A) +#define FT8_HSIZE (480L) +#define FT8_VSIZE (272L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (10L) +#define FT8_VOFFSET (12L) +#define FT8_VCYCLE (292L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (41L) +#define FT8_HOFFSET (43L) +#define FT8_HCYCLE (548L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (5L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) +#define FT8_HAS_CRYSTAL +#endif + + +/* untested */ +/* FTDI/BRT EVE2 modules VM810C50A-D, ME812A-WH50R and ME813A-WH50C, 800x480 5.0" */ +#if defined (CONFIG_FT8_VM810C) || defined (FT8_ME812A) || defined (FT8_ME813A) +#define FT8_HSIZE (800L) +#define FT8_VSIZE (480L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (3L) +#define FT8_VOFFSET (32L) +#define FT8_VCYCLE (525L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (48L) +#define FT8_HOFFSET (88L) +#define FT8_HCYCLE (928L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (2L) +#define FT8_CSPREAD (0L) +#define FT8_TOUCH_RZTHRESH (1200L) +#define FT8_HAS_CRYSTAL +#endif + + +/* FT810CB-HY50HD: FT810 800x480 5.0" HAOYU */ +#if defined (CONFIG_FT8_FT810CB_HY50HD) +#define FT8_HSIZE (800L) +#define FT8_VSIZE (480L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (2L) +#define FT8_VOFFSET (13L) +#define FT8_VCYCLE (525L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (20L) +#define FT8_HOFFSET (64L) +#define FT8_HCYCLE (952L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (2L) +#define FT8_CSPREAD (0L) +#define FT8_TOUCH_RZTHRESH (2000L) /* touch-sensitivity */ +#define FT8_HAS_CRYSTAL +#endif + + +/* FT811CB-HY50HD: FT811 800x480 5.0" HAOYU */ +#if defined (CONFIG_FT8_FT811CB_HY50HD) +#define FT8_HSIZE (800L) +#define FT8_VSIZE (480L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (2L) +#define FT8_VOFFSET (13L) +#define FT8_VCYCLE (525L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (20L) +#define FT8_HOFFSET (64L) +#define FT8_HCYCLE (952L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (2L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) /* touch-sensitivity */ +#define FT8_HAS_CRYSTAL +#endif + + +/* untested */ +/* G-ET0700G0DM6 800x480 7.0" Glyn */ +#if defined (CONFIG_FT8_ET07) +#define FT8_HSIZE (800L) +#define FT8_VSIZE (480L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (2L) +#define FT8_VOFFSET (35L) +#define FT8_VCYCLE (525L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (128L) +#define FT8_HOFFSET (203L) +#define FT8_HCYCLE (1056L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (2L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) +#define FT8_HAS_CRYSTAL 0 /* no idea if these come with a crystal populated or not */ +#endif + + +/* RVT70AQxxxxxx 800x480 7.0" Riverdi, various options, FT812/FT813, tested with RVT70UQFNWC0x */ +#if defined (CONFIG_FT8_RVT70AQ) +#define FT8_HSIZE (800L) /* Thd Length of visible part of line (in PCLKs) - display width */ +#define FT8_VSIZE (480L) /* Tvd Number of visible lines (in lines) - display height */ + +#define FT8_VSYNC0 (0L) /* Tvf Vertical Front Porch */ +#define FT8_VSYNC1 (10L) /* Tvf + Tvp Vertical Front Porch plus Vsync Pulse width */ +#define FT8_VOFFSET (23L) /* Tvf + Tvp + Tvb Number of non-visible lines (in lines) */ +#define FT8_VCYCLE (525L) /* Tv Total number of lines (visible and non-visible) (in lines) */ +#define FT8_HSYNC0 (0L) /* Thf Horizontal Front Porch */ +#define FT8_HSYNC1 (10L) /* Thf + Thp Horizontal Front Porch plus Hsync Pulse width */ +#define FT8_HOFFSET (46L) /* Thf + Thp + Thb Length of non-visible part of line (in PCLK cycles) */ +#define FT8_HCYCLE (1056L) /* Th Total length of line (visible and non-visible) (in PCLKs) */ +#define FT8_PCLKPOL (1L) /* PCLK polarity (0 = rising edge, 1 = falling edge) */ +#define FT8_SWIZZLE (0L) /* Defines the arrangement of the RGB pins of the FT800 */ +#define FT8_PCLK (2L) /* 60MHz / REG_PCLK = PCLK frequency 30 MHz */ +#define FT8_CSPREAD (1L) /* helps with noise, when set to 1 fewer signals are changed simultaneously, reset-default: 1 */ +#define FT8_TOUCH_RZTHRESH (1800L) /* touch-sensitivity */ +#endif + + +/* untested */ +/* EVE2-29A 320x102 2.9" 1U Matrix Orbital, non-touch, FT812 */ +#if defined (CONFIG_FT8_EVE2_29) +#define FT8_HSIZE (320L) +#define FT8_VSIZE (102L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (2L) +#define FT8_VOFFSET (156L) +#define FT8_VCYCLE (262L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (10L) +#define FT8_HOFFSET (70L) +#define FT8_HCYCLE (408L) +#define FT8_PCLKPOL (0L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (8L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) +#endif + + +/* EVE2-35A 320x240 3.5" Matrix Orbital, resistive, or non-touch, FT812 */ +#if defined (CONFIG_FT8_EVE2_35) +#define FT8_HSIZE (320L) +#define FT8_VSIZE (240L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (2L) +#define FT8_VOFFSET (18L) +#define FT8_VCYCLE (262L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (10L) +#define FT8_HOFFSET (70L) +#define FT8_HCYCLE (408L) +#define FT8_PCLKPOL (0L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (8L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) +#endif + + +/* EVE2-35G 320x240 3.5" Matrix Orbital, capacitive touch, FT813 */ +#if defined (CONFIG_FT8_EVE2_35G) +#define FT8_HSIZE (320L) +#define FT8_VSIZE (240L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (2L) +#define FT8_VOFFSET (18L) +#define FT8_VCYCLE (262L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (10L) +#define FT8_HOFFSET (70L) +#define FT8_HCYCLE (408L) +#define FT8_PCLKPOL (0L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (8L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) +#define FT8_HAS_GT911 /* special treatment required for out-of-spec touch-controller */ +#endif + + +/* EVE2-38A 480x116 3.8" 1U Matrix Orbital, resistive touch, FT812 */ +#if defined (CONFIG_FT8_EVE2_38) +#define FT8_HSIZE (480L) +#define FT8_VSIZE (272L) + +#define FT8_VSYNC0 (152L) +#define FT8_VSYNC1 (10L) +#define FT8_VOFFSET (12L) +#define FT8_VCYCLE (292L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (41L) +#define FT8_HOFFSET (43L) +#define FT8_HCYCLE (548L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (5L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) +#endif + + +/* EVE2-38G 480x116 3.8" 1U Matrix Orbital, capacitive touch, FT813 */ +#if defined (CONFIG_FT8_EVE2_38G) +#define FT8_HSIZE (480L) +#define FT8_VSIZE (272L) + +#define FT8_VSYNC0 (152L) +#define FT8_VSYNC1 (10L) +#define FT8_VOFFSET (12L) +#define FT8_VCYCLE (292L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (41L) +#define FT8_HOFFSET (43L) +#define FT8_HCYCLE (548L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (5L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) +#define FT8_HAS_GT911 /* special treatment required for out-of-spec touch-controller */ +#endif + + +/* untested */ +/* EVE2-43A 480x272 4.3" Matrix Orbital, resistive or no touch, FT812 */ +#if defined (CONFIG_FT8_EVE2_43) +#define FT8_HSIZE (480L) +#define FT8_VSIZE (272L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (10L) +#define FT8_VOFFSET (12L) +#define FT8_VCYCLE (292L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (41L) +#define FT8_HOFFSET (43L) +#define FT8_HCYCLE (548L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (5L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) +#endif + + +/* EVE2-43G 480x272 4.3" Matrix Orbital, capacitive touch, FT813 */ +#if defined (CONFIG_FT8_EVE2_43G) +#define FT8_HSIZE (480L) +#define FT8_VSIZE (272L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (10L) +#define FT8_VOFFSET (12L) +#define FT8_VCYCLE (292L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (41L) +#define FT8_HOFFSET (43L) +#define FT8_HCYCLE (548L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (5L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) +#define FT8_HAS_GT911 /* special treatment required for out-of-spec touch-controller */ +#endif + + +/* untested */ +/* Matrix Orbital EVE2 modules EVE2-50A, EVE2-70A : 800x480 5.0" and 7.0" resistive, or no touch, FT812 */ +#if defined (CONFIG_FT8_EVE2_50) || defined (FT8_EVE2_70) +#define FT8_HSIZE (800L) +#define FT8_VSIZE (480L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (3L) +#define FT8_VOFFSET (32L) +#define FT8_VCYCLE (525L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (48L) +#define FT8_HOFFSET (88L) +#define FT8_HCYCLE (928L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (2L) +#define FT8_CSPREAD (0L) +#define FT8_TOUCH_RZTHRESH (1200L) +#endif + + +/* Matrix Orbital EVE2 modules EVE2-50G, EVE2-70G : 800x480 5.0" and 7.0" capacitive touch, FT813 */ +#if defined (CONFIG_FT8_EVE2_50G) || defined (FT8_EVE2_70G) +#define FT8_HSIZE (800L) +#define FT8_VSIZE (480L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (3L) +#define FT8_VOFFSET (32L) +#define FT8_VCYCLE (525L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (48L) +#define FT8_HOFFSET (88L) +#define FT8_HCYCLE (928L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (2L) +#define FT8_CSPREAD (0L) +#define FT8_TOUCH_RZTHRESH (1200L) +#define FT8_HAS_GT911 /* special treatment required for out-of-spec touch-controller */ +#endif + + +/* NHD-3.5-320240FT-CxXx-xxx 320x240 3.5" Newhaven, resistive or capacitive, FT81x */ +#if defined (CONFIG_FT8_NHD_35) +#define FT8_HSIZE (320L) +#define FT8_VSIZE (240L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (2L) +#define FT8_VOFFSET (13L) +#define FT8_VCYCLE (263L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (10L) +#define FT8_HOFFSET (70L) +#define FT8_HCYCLE (408L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (2L) +#define FT8_PCLK (6L) +#define FT8_CSPREAD (0L) +#define FT8_TOUCH_RZTHRESH (1200L) +#define FT8_HAS_CRYSTAL +#endif + + +/* untested */ +/* NHD-4.3-480272FT-CxXx-xxx 480x272 4.3" Newhaven, resistive or capacitive, FT81x */ +#if defined (CONFIG_FT8_NHD_43) +#define FT8_HSIZE (480L) +#define FT8_VSIZE (272L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (10L) +#define FT8_VOFFSET (12L) +#define FT8_VCYCLE (292L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (41L) +#define FT8_HOFFSET (43L) +#define FT8_HCYCLE (548L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (5L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) +#define FT8_HAS_CRYSTAL +#endif + + +/* untested */ +/* NHD-5.0-800480FT-CxXx-xxx 800x480 5.0" Newhaven, resistive or capacitive, FT81x */ +#if defined (CONFIG_FT8_NHD_50) +#define FT8_HSIZE (800L) +#define FT8_VSIZE (480L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (3L) +#define FT8_VOFFSET (32L) +#define FT8_VCYCLE (525L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (48L) +#define FT8_HOFFSET (88L) +#define FT8_HCYCLE (928L) +#define FT8_PCLKPOL (0L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (2L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) +#define FT8_HAS_CRYSTAL +#endif + + +/* untested */ +/* NHD-7.0-800480FT-CxXx-xxx 800x480 7.0" Newhaven, resistive or capacitive, FT81x */ +#if defined (CONFIG_FT8_NHD_70) +#define FT8_HSIZE (800L) +#define FT8_VSIZE (480L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (3L) +#define FT8_VOFFSET (32L) +#define FT8_VCYCLE (525L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (48L) +#define FT8_HOFFSET (88L) +#define FT8_HCYCLE (928L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (2L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) +#define FT8_HAS_CRYSTAL +#endif + + +/* ADAM101-LCP-SWVGA-NEW 1024x600 10.1" Glyn, capacitive, FT813 */ +#if defined (CONFIG_FT8_ADAM101) +#define FT8_HSIZE (1024L) +#define FT8_VSIZE (600L) + +#define FT8_VSYNC0 (0L) +#define FT8_VSYNC1 (1L) +#define FT8_VOFFSET (1L) +#define FT8_VCYCLE (720L) +#define FT8_HSYNC0 (0L) +#define FT8_HSYNC1 (1L) +#define FT8_HOFFSET (1L) +#define FT8_HCYCLE (1100L) +#define FT8_PCLKPOL (1L) +#define FT8_SWIZZLE (0L) +#define FT8_PCLK (2L) +#define FT8_CSPREAD (1L) +#define FT8_TOUCH_RZTHRESH (1200L) +#define FT8_HAS_CRYSTAL +#endif + + +#endif //CONFIG_MICROPY_USE_EVE + #endif /* _FT8_H_ */ diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/eve/FT8_commands.c b/MicroPython_BUILD/components/micropython/esp32/libs/eve/FT8_commands.c index 76f0d5c2..c568df03 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/eve/FT8_commands.c +++ b/MicroPython_BUILD/components/micropython/esp32/libs/eve/FT8_commands.c @@ -31,62 +31,367 @@ #include "sdkconfig.h" -#if CONFIG_MICROPY_USE_EVE_NOT_USE +#if CONFIG_MICROPY_USE_EVE #include +#include +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "esp_log.h" #include "FT8.h" -#include "tft/spi_master_lobo.h" +#include "driver/spi_master_utils.h" +#include "mphalport.h" + +uint16_t eve_chip_id = 0; + +static const char TAG[] = "[EveDrv]"; // FT8xx Memory Commands - use with FT8_memWritexx and FT8_memReadxx -#define MEM_WRITE 0x80 // FT8xx Host Memory Write -#define MEM_READ 0x00 // FT8xx Host Memory Read +#define MEM_WRITE 0x80 // FT8xx Host Memory Write +#define MEM_READ 0x00 // FT8xx Host Memory Read + +#define MIN_FIFO_FREE 256 uint16_t eve_cmdOffset = 0x0000; // used to navigate command ring buffer static uint8_t cmd_burst = 0; // flag to indicate cmd-burst is active -spi_lobo_device_handle_t eve_spi = NULL; +uint8_t eve_spibus_is_init = 0; +uint8_t spi_is_init = 0; +uint8_t ft8_full_cs = 1; +exspi_device_handle_t *eve_spi = NULL; +uint32_t ft8_ramg_ptr = FT8_RAM_G; +FT8_Fifo_t ft8_stFifo = {0}; +//FT8_Fifo_t *ft8_pFifo = &ft8_stFifo; + + +// FT811 / FT813 binary-blob from FTDIs AN_336 to patch the touch-engine for Goodix GT911 / GT9271 touch controllers +const uint16_t FT8_GT911_len = 1184; +const uint8_t FT8_GT911_data[1184] = +{ + 26,255,255,255,32,32,48,0,4,0,0,0,2,0,0,0, + 34,255,255,255,0,176,48,0,120,218,237,84,221,111,84,69,20,63,51,179,93,160,148,101,111,76,5,44,141,123,111,161,11,219,154,16,9,16,17,229,156,75,26,11,13,21,227,3,16,252,184,179, + 45,219,143,45,41,125,144,72,67,100,150,71,189,113,18,36,17,165,100,165,198,16,32,17,149,196,240,128,161,16,164,38,54,240,0,209,72,130,15,38,125,48,66,82,30,76,19,31,172,103,46, + 139,24,255,4,227,157,204,156,51,115,102,206,231,239,220,5,170,94,129,137,75,194,216,98,94,103,117,115,121,76,131,177,125,89,125,82,123,60,243,58,142,242,204,185,243,188,118,156, + 227,155,203,238,238,195,251,205,229,71,92,28,169,190,184,84,143,113,137,53,244,103,181,237,87,253,113,137,233,48,12,198,165,181,104,139,25,84,253,155,114,74,191,0,54,138,163, + 12,62,131,207,129,23,217,34,91,31,128,65,246,163,175,213,8,147,213,107,35,203,94,108,3,111,40,171,83,24,15,165,177,222,116,97,23,188,140,206,150,42,102,181,87,78,86,182,170,134, + 215,241,121,26,243,252,2,76,115,217,139,222,206,173,136,132,81,61,35,185,39,113,23,46,199,76,178,54,151,183,224,0,40,189,28,149,182,58,131,79,152,30,76,34,98,234,162,216,133,141, + 102,39,170,40,192,101,53,201,146,191,37,77,44,177,209,74,211,5,206,187,5,6,216,47,53,96,123,22,50,103,251,192,84,17,74,227,185,56,106,51,91,161,96,182,163,48,171,141,139,65,152, + 66,66,11,102,43,158,75,36,80,147,184,147,139,112,17,235,216,103,111,239,245,92,10,175,194,40,44,58,125,5,59,112,50,103,245,4,78,192,5,156,194,51,60,191,134,75,110,173,237,46,192, + 121,156,192,115,184,218,120,67,63,115,46,11,102,10,97,232,50,235,114,182,148,118,178,41,188,12,135,77,202,124,12,96,238,35,161,234,189,129,23,249,212,139,230,25,53,48,205,52,93, + 163,117,53,154,170,81,85,163,178,70,69,66,167,241,14,46,241,1,226,136,152,179,197,59,184,148,254,49,132,48,15,176,137,192,76,131,196,105,104,162,86,81,160,165,255,26,173,162,137, + 86,145,210,183,192,55,175,194,211,60,91,120,230,184,174,27,41,131,155,40,224,29,87,179,232,16,55,55,7,165,147,81,23,165,49,101,54,224,75,180,81,108,18,29,226,69,225,110,175,224, + 42,212,25,47,130,193,110,234,192,215,252,56,74,162,24,46,251,174,54,106,68,245,14,9,155,160,22,120,207,104,240,29,90,178,140,28,24,220,47,166,112,61,251,208,192,111,56,239,238, + 93,255,251,62,99,32,193,75,61,190,235,123,229,110,218,194,85,79,225,59,98,20,238,227,235,220,11,221,149,25,180,116,194,159,111,96,192,24,213,59,139,179,156,215,69,230,19,24,35, + 135,117,206,171,206,162,67,129,234,61,235,11,104,103,84,64,223,167,254,40,163,101,92,84,43,150,46,249,219,205,7,116,11,91,104,61,57,75,223,8,48,25,28,119,252,222,113,49,86,249, + 74,180,211,156,181,61,215,168,157,7,251,199,150,242,250,91,58,132,94,121,7,53,151,139,98,6,165,153,69,214,32,110,211,100,101,31,89,45,81,98,23,205,205,197,209,109,186,198,35, + 141,191,249,25,60,132,223,153,251,98,20,239,146,139,20,217,250,41,250,137,58,177,90,57,79,51,108,233,20,253,194,187,49,222,205,114,141,96,48,175,219,107,54,111,138,22,154,103, + 108,79,58,252,179,178,79,164,195,2,153,36,39,170,199,201,167,197,85,106,8,59,177,81,46,56,2,230,75,114,17,55,112,188,65,208,137,77,114,10,115,55,58,208,197,173,122,87,6,140, + 110,42,208,124,163,70,108,241,104,18,245,98,214,187,134,53,42,221,22,182,133,211,116,148,177,194,209,192,85,90,199,58,55,203,2,229,19,137,187,161,228,154,112,203,145,125,244, + 188,220,118,228,41,201,181,41,195,144,215,183,51,80,250,21,217,16,217,200,235,109,227,188,122,218,142,60,170,224,112,240,184,130,229,224,113,5,223,148,163,80,165,183,130,187, + 132,116,64,238,161,85,220,115,139,205,98,227,244,29,102,125,7,37,243,123,223,11,26,92,63,243,116,61,191,138,123,244,160,84,186,74,31,5,174,247,119,135,199,248,253,135,242,97, + 102,145,190,144,14,85,238,221,231,193,158,48,205,25,120,248,15,220,29,158,9,70,185,30,103,229,33,254,23,237,160,172,62,193,90,222,224,232,14,200,56,90,104,142,227,120,110,6, + 21,211,203,65,150,99,151,220,247,87,164,50,159,49,239,234,58,142,0,109,108,123,18,79,227,36,100,248,222,205,96,127,120,26,171,228,69,63,36,17,252,200,17,116,242,187,227,88,143, + 247,2,75,191,6,130,59,188,11,55,240,31,243,122,152,226,183,207,154,73,188,39,219,43,105,222,87,41,143,141,140,175,73,112,184,252,61,184,16,90,250,35,168,82,119,176,57,116,94, + 200,150,22,190,179,44,104,12,235,84,149,102,252,89,154,193,99,228,106,242,125,248,64,194,255,223,127,242,83,11,255,2,70,214,226,128,0,0 +}; -//----------------------------------------------------------------------------------------- -static void _spi_transfer_start(spi_lobo_device_handle_t spi_dev, int wrbits, int rdbits) { - // Load send buffer - spi_dev->host->hw->user.usr_mosi_highpart = 0; - spi_dev->host->hw->mosi_dlen.usr_mosi_dbitlen = wrbits-1; - spi_dev->host->hw->user.usr_mosi = 1; - if (rdbits) { - spi_dev->host->hw->miso_dlen.usr_miso_dbitlen = rdbits; - spi_dev->host->hw->user.usr_miso = 1; + +//--------------------------- +static esp_err_t eve_select() +{ + if (ft8_full_cs) return spi_device_select(eve_spi, 0); + else { + gpio_set_level(eve_spi->cs, 0); + return ESP_OK; } +} + +//----------------------------- +static esp_err_t eve_deselect() +{ + if (ft8_full_cs) return spi_device_deselect(eve_spi); else { - spi_dev->host->hw->miso_dlen.usr_miso_dbitlen = 0; - spi_dev->host->hw->user.usr_miso = 0; + gpio_set_level(eve_spi->cs, 1); + return ESP_OK; } - // Start transfer - spi_dev->host->hw->cmd.usr = 1; - // Wait for SPI bus ready - while (spi_dev->host->hw->cmd.usr); } +//----------------------------------------------- +static int FT8_Fifo_write_file_block(int blksize) +{ + int bytesread, write_parc, write_remain, size, total=0; + //uint32_t old_wp = ft8_stFifo.fifo_wp; + + // repeat sending in maximum file buffer sizes + while (blksize > 0) { + size = (blksize > ft8_stFifo.fbuff_size) ? ft8_stFifo.fbuff_size : blksize; + // read block from file + bytesread = fread(ft8_stFifo.g_scratch, 1, size, ft8_stFifo.pFile); + if (bytesread <= 0) { + ft8_stFifo.file_remain = 0; + break; + } + total += bytesread; + + if ((ft8_stFifo.fifo_wp+bytesread) <= ft8_stFifo.fifo_len) { + // the whole block fits into mediafifo buffer + FT8_memWrite_flash_buffer(ft8_stFifo.fifo_buff + ft8_stFifo.fifo_wp, ft8_stFifo.g_scratch, bytesread, true); + // adjust the write pointer + ft8_stFifo.fifo_wp += bytesread; + if (ft8_stFifo.fifo_wp >= ft8_stFifo.fifo_len) ft8_stFifo.fifo_wp = 0; // wrap to the buffer start + } + else { + // wp will wrap the mediafifo buffer, write in two parts + write_parc = ft8_stFifo.fifo_len - ft8_stFifo.fifo_wp; // until the end of buffer + FT8_memWrite_flash_buffer(ft8_stFifo.fifo_buff + ft8_stFifo.fifo_wp, ft8_stFifo.g_scratch, write_parc, true); + ft8_stFifo.fifo_wp = 0; + write_remain = bytesread-write_parc; // from buffer start write remaining + FT8_memWrite_flash_buffer(ft8_stFifo.fifo_buff + ft8_stFifo.fifo_wp, ft8_stFifo.g_scratch+write_parc, write_remain, true); + // adjust the write pointer + ft8_stFifo.fifo_wp += write_remain; + } + + // adjust remaining file size + if (bytesread < size) { + ft8_stFifo.file_remain = 0; // the whole file written + blksize = 0; + } + else { + ft8_stFifo.file_remain -= bytesread; + blksize -= size; + } + } + //ESP_LOGD(TAG, "Write block (%d) at wp=%d (new wp=%d), remaining_in_file=%d", total, old_wp, ft8_stFifo.fifo_wp, ft8_stFifo.file_remain); + return total; +} + +//-------------------- +void FT8_Fifo_deinit() +{ + if (ft8_stFifo.g_scratch) free(ft8_stFifo.g_scratch); + memset((void *)&ft8_stFifo, 0, sizeof(FT8_Fifo_t)); +} + +//---------------------------- +int FT8_Fifo_init(FILE *fhndl) +{ + int err = 0; + ESP_LOGD(TAG, "=== MEDIAFIFO Init"); + // check if there is enough space in EVE RAM_G + // minimum of 16KB is required + ft8_stFifo.fifo_len = FT8_RAM_G_SIZE - ft8_ramg_ptr; + if (ft8_stFifo.fifo_len < 16348) { err=-1; goto errexit; } + + ft8_stFifo.fifo_len = (ft8_stFifo.fifo_len / 16384) * 16384; + if (ft8_stFifo.fifo_len > 65536) ft8_stFifo.fifo_len = 65536; + + // set the buffer start address + ft8_stFifo.fifo_buff = FT8_RAM_G_SIZE-ft8_stFifo.fifo_len; + + ft8_stFifo.fifo_rp = 0; + ft8_stFifo.fifo_wp = 0; + ft8_stFifo.max_free = 0; + ft8_stFifo.min_free = ft8_stFifo.fifo_len; + + // get file size + ft8_stFifo.pFile = fhndl; + if (fseek(ft8_stFifo.pFile,0,SEEK_END)) { err=-2; goto errexit; } + ft8_stFifo.file_size = ftell(ft8_stFifo.pFile); + if (ft8_stFifo.file_size < 0) return -2; + if (fseek(ft8_stFifo.pFile,0,SEEK_SET)) { err=-2; goto errexit; } + if (ft8_stFifo.file_size == 0) { err=-2; goto errexit; } + ft8_stFifo.file_remain = ft8_stFifo.file_size; + + // Allocate file read buffer of minimum 512 bytes + ft8_stFifo.fbuff_size = 8192; + ft8_stFifo.g_scratch = NULL; + while (ft8_stFifo.g_scratch == NULL){ + ft8_stFifo.fbuff_size /= 2; + if (ft8_stFifo.fbuff_size < 512) break; + ft8_stFifo.g_scratch = malloc(ft8_stFifo.fbuff_size); + } + if (ft8_stFifo.g_scratch == NULL) { err=-3; goto errexit; } + ESP_LOGD(TAG, " mediafifo buffer at %d, size=%d, file_buff_size=%d", ft8_stFifo.fifo_buff, ft8_stFifo.fifo_len, ft8_stFifo.fbuff_size); + + // === Fill mediafifo buffer from the file === + FT8_Fifo_write_file_block(ft8_stFifo.fifo_len - ft8_stFifo.fbuff_size); + ESP_LOGD(TAG, " buffer_filled=%d, remaining_in_file: %d", ft8_stFifo.fifo_wp, ft8_stFifo.file_remain); + + // Execute CMD_MEDIAFIFO, set mediafifo parameters + FT8_start_cmd(CMD_MEDIAFIFO); + FT8_send_long(ft8_stFifo.fifo_buff, ft8_stFifo.fifo_len, 0, 2); + + if (!FT8_cmd_execute(250)) err = -8; + else return 0; + +errexit: + ESP_LOGE(TAG, " Fifo init: error %d", err); + FT8_Fifo_deinit(); + return err; +} + +//-------------------- +int FT8_Fifo_service() +{ + if (ft8_stFifo.file_remain <= 0) { + // === Complete file was sent to mediafifo, wait until processed === + ESP_LOGD(TAG, "Service: file completed"); + ft8_stFifo.fifo_rp = FT8_memRead32(REG_MEDIAFIFO_READ); // get the read pointer + + uint64_t tmo = mp_hal_ticks_ms(); + uint8_t res = FT8_busy(); + while (res == 1) { + mp_hal_reset_wdt(); + res = FT8_busy(); + if ((res == 1) && ((mp_hal_ticks_ms()-tmo) > 250)) res = 2; + } + + // wait until all data are precessed + while (ft8_stFifo.fifo_rp < ft8_stFifo.fifo_wp) { + ft8_stFifo.fifo_rp = FT8_memRead32(REG_MEDIAFIFO_READ); + res++; + if ((mp_hal_ticks_ms()-tmo) > 100) { + ESP_LOGW(TAG, "Mediafifo processing timeout (ft8_stFifo.fifo_rp=%d < wp=%d)", ft8_stFifo.fifo_rp, ft8_stFifo.fifo_wp); + if (cmd_burst) eve_select(); + return -1; + } + } + ESP_LOGD(TAG, "Service: finished"); + if (cmd_burst) eve_select(); + return 0; + } + + // === Still some data to send === + uint32_t fifo_free, written=0; + + // Get the read pointer + ft8_stFifo.fifo_rp = FT8_memRead32(REG_MEDIAFIFO_READ); + // and calculate the free fifo space + if (ft8_stFifo.fifo_rp < ft8_stFifo.fifo_wp) fifo_free = (ft8_stFifo.fifo_len - ft8_stFifo.fifo_wp) + ft8_stFifo.fifo_rp; + else fifo_free = ft8_stFifo.fifo_rp - ft8_stFifo.fifo_wp; + // keep minimum of 256 free buffer + if (fifo_free >= MIN_FIFO_FREE) fifo_free -= MIN_FIFO_FREE; + if (fifo_free > ft8_stFifo.max_free) ft8_stFifo.max_free = fifo_free; + if (fifo_free < ft8_stFifo.min_free) ft8_stFifo.min_free = fifo_free; + + if (fifo_free >= MIN_FIFO_FREE) { + // send file block + written = FT8_Fifo_write_file_block(fifo_free); + if (written > 0) FT8_memWrite32(REG_MEDIAFIFO_WRITE, ft8_stFifo.fifo_wp); + } + + //if (written > 0) { + // ESP_LOGD(TAG, "Service: free=%d, written: %d, rd=%d, wp=%d", fifo_free, written, ft8_stFifo.fifo_rp, ft8_stFifo.fifo_wp); + //} + //if (cmd_burst) eve_select(); + return 1; +} + +//------------------------------------------------------------------------------------- +int FT8_sendDataViaMediafifo(FILE *pFile, uint32_t ptr, uint32_t options, uint8_t type) +{ + if (type == 0) { + ESP_LOGD(TAG, "=== Load image"); + FT8_start_cmd(CMD_LOADIMAGE); + FT8_send_long(ptr, options, 0, 2); + eve_deselect(); + FT8_cmd_start(); + } + else if (type == 1) { + ESP_LOGD(TAG, "==== Play video"); + FT8_start_cmd(CMD_PLAYVIDEO); + FT8_send_long(options, 0, 0, 1); + eve_deselect(); + FT8_cmd_start(); + } + else if (type == 2) { + ESP_LOGD(TAG, "=== Start video"); + + FT8_cmd_dl(CMD_VIDEOSTART); + //FT8_send_long(options, 0, 0, 1); + FT8_cmd_execute(250); + ESP_LOGD(TAG, " VIDEOSTART executed"); + } + else { + ESP_LOGE(TAG, "=== Unknown type"); + return -9; + } + + // update the read and write pointers of mediafifo + FT8_memWrite32(REG_MEDIAFIFO_READ, 0); + FT8_memWrite32(REG_MEDIAFIFO_WRITE, ft8_stFifo.fifo_wp); + + if (type < 2) { + int res, rdptr=0; + uint64_t tmo = mp_hal_ticks_ms(); + mp_hal_set_wdt_tmo(); + // Execute the service to send the whole file + do { + res = FT8_Fifo_service(); + if (res < 0) return -9; + mp_hal_reset_wdt(); + if (rdptr == ft8_stFifo.fifo_rp) { + if ((mp_hal_ticks_ms()-tmo) > 250) { + // read pointer does not advance + ESP_LOGE(TAG, "Mediafifo processing timeout (rdptr=%d < wp=%d)", rdptr, ft8_stFifo.fifo_wp); + FT8_CP_reset(); + return -10; + } + } + else tmo = mp_hal_ticks_ms(); + rdptr = ft8_stFifo.fifo_rp; + } while (res); + + tmo = mp_hal_ticks_ms(); + res = FT8_busy(); + while (res == 1) { + if ((mp_hal_ticks_ms()-tmo) > 250) { + res = 2; + break; + } + mp_hal_reset_wdt(); + res = FT8_busy(); + } + if (res != 0) { + ESP_LOGE(TAG, "Error executing"); + FT8_CP_reset(); + } + + ESP_LOGD(TAG, "Finished"); + return ft8_stFifo.file_remain; + } + + return 0; +} + + +// ==== Basic SPI commands ==== + +// Send command to FT8xx, only used in Init function //----------------------------- void FT8_cmdWrite(uint8_t data) { - if (spi_lobo_device_select(eve_spi, 0)) return; - eve_spi->host->hw->data_buf[0] = (uint32_t)data; - _spi_transfer_start(eve_spi, 8, 0); - spi_lobo_device_deselect(eve_spi); + if (eve_select()) return; + eve_spi->handle->host->hw->data_buf[0] = (uint32_t)data; + _spi_transfer_start(eve_spi, 24, 0); + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready + eve_deselect(); } +// ==== Memory read/write ======================================================================== + +// Prepare 32-bit address to be sent to FT8xx //---------------------------------------------------- uint32_t FT8_address(uint32_t ftAddress, uint8_t mask) { - uint32_t wd = (ftAddress >> 16) & 0x3F; // Memory Write plus high address byte - wd |= ftAddress & 0x0000FF00; // middle address byte - wd |= (ftAddress << 16) & 0x00FF0000; // low address byte & dummy byte + uint32_t wd = ((ftAddress&0x00FF0000) >> 16) | mask; // Memory Write plus high address byte + wd |= (ftAddress & 0x0000FF00); // middle address byte + wd |= ((ftAddress & 0xFF) << 16); // low address byte & dummy byte return wd; } @@ -95,13 +400,14 @@ uint8_t FT8_memRead8(uint32_t ftAddress) { uint8_t ftData8 = 0; - if (spi_lobo_device_select(eve_spi, 0)) return 0; - eve_spi->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_READ); - eve_spi->host->hw->data_buf[1] = 0; + if (eve_select()) return 0; + eve_spi->handle->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_READ); + eve_spi->handle->host->hw->data_buf[1] = 0; _spi_transfer_start(eve_spi, 40, 40); + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready - ftData8 = (uint8_t)eve_spi->host->hw->data_buf[1]; - spi_lobo_device_deselect(eve_spi); + ftData8 = (uint8_t)eve_spi->handle->host->hw->data_buf[1]; + eve_deselect(); return ftData8; // return byte read } @@ -111,15 +417,16 @@ uint16_t FT8_memRead16(uint32_t ftAddress) { uint16_t ftData16 = 0; - if (spi_lobo_device_select(eve_spi, 0)) return 0; - eve_spi->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_READ); - eve_spi->host->hw->data_buf[1] = 0; + if (eve_select()) return 0; + eve_spi->handle->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_READ); + eve_spi->handle->host->hw->data_buf[1] = 0; _spi_transfer_start(eve_spi, 48, 48); + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready - ftData16 = (uint16_t)eve_spi->host->hw->data_buf[1]; - spi_lobo_device_deselect(eve_spi); + ftData16 = (uint16_t)eve_spi->handle->host->hw->data_buf[1]; + eve_deselect(); - return ftData16; // return integer read + return ftData16; // return 16-bit integer read } //---------------------------------------- @@ -127,87 +434,167 @@ uint32_t FT8_memRead32(uint32_t ftAddress) { uint32_t ftData32= 0; - if (spi_lobo_device_select(eve_spi, 0)) return 0; - eve_spi->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_READ); - eve_spi->host->hw->data_buf[1] = 0; - _spi_transfer_start(eve_spi, 56, 56); + if (eve_select()) return 0; + eve_spi->handle->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_READ); + eve_spi->handle->host->hw->data_buf[1] = 0; + _spi_transfer_start(eve_spi, 64, 64); + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready + + ftData32 = eve_spi->handle->host->hw->data_buf[1]; + eve_deselect(); + + return ftData32; // return 32-bit long read +} + +//---------------------------------------------------------------------- +void FT8_memRead_buffer(uint32_t ftAddress, uint8_t *data, uint16_t len) +{ + spi_transaction_t t; + memset(&t, 0, sizeof(t)); //Zero out the transaction + memset(data, 0, len); - ftData32 = eve_spi->host->hw->data_buf[1]; - spi_lobo_device_deselect(eve_spi); + if (eve_select()) return; + eve_spi->handle->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_READ); + _spi_transfer_start(eve_spi, 32, 32); + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready + + t.length = len * 8; + t.tx_buffer = data; + t.rxlength = len * 8; + t.rx_buffer = data; - return ftData32; // return long read + spi_transfer_data_nodma(eve_spi, &t); // Send using direct mode + eve_deselect(); } //----------------------------------------------------- void FT8_memWrite8(uint32_t ftAddress, uint8_t ftData8) { - if (spi_lobo_device_select(eve_spi, 0)) return; - eve_spi->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE) | (uint32_t)(ftData8 << 24); + if (eve_select()) return; + eve_spi->handle->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE) | (uint32_t)((uint32_t)ftData8 << 24); _spi_transfer_start(eve_spi, 32, 32); - spi_lobo_device_deselect(eve_spi); + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready + eve_deselect(); } //-------------------------------------------------------- void FT8_memWrite16(uint32_t ftAddress, uint16_t ftData16) { - if (spi_lobo_device_select(eve_spi, 0)) return; - eve_spi->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE) | (uint32_t)(ftData16 << 24); - eve_spi->host->hw->data_buf[1] = (uint32_t)(ftData16 >> 8); + if (eve_select()) return; + eve_spi->handle->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE) | (uint32_t)((uint32_t)ftData16 << 24); + eve_spi->handle->host->hw->data_buf[1] = (uint32_t)(ftData16 >> 8); // high byte _spi_transfer_start(eve_spi, 40, 40); - spi_lobo_device_deselect(eve_spi); + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready + eve_deselect(); } //-------------------------------------------------------- void FT8_memWrite32(uint32_t ftAddress, uint32_t ftData32) { - if (spi_lobo_device_select(eve_spi, 0)) return; - eve_spi->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE) | ftData32 << 24; - uint32_t wd = ((ftData32 >> 8) & 0xFF) | ((ftData32 >> 16) & 0xFF) | ((ftData32 >> 24) & 0xFF); - eve_spi->host->hw->data_buf[1] = wd; + if (eve_select()) return; + eve_spi->handle->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE) | (ftData32 << 24); + eve_spi->handle->host->hw->data_buf[1] = (ftData32 >> 8); _spi_transfer_start(eve_spi, 56, 56); - spi_lobo_device_deselect(eve_spi); + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready + eve_deselect(); } -//---------------------------------------------------- -static void FT8_send_data(uint8_t *data, uint32_t len) +//----------------------------------------------------------------------- +static int FT8_send_data(uint8_t *data, int data_len, bool check_padding) { - spi_lobo_transaction_t t; - memset(&t, 0, sizeof(t)); //Zero out the transaction - - t.length = len * 8; - t.tx_buffer = data; - t.rxlength = 0; - t.rx_buffer = NULL; + uint8_t padding = 0; + if (check_padding) { + // ensure 4-byte alignment + padding = data_len % 4; + if (padding) padding = 4 - padding; + } - spi_lobo_transfer_data(eve_spi, &t); // Send using direct mode + if ((data_len + padding) <= 64) { + // === Send length <= 64, send directly === + memset((uint8_t *)eve_spi->handle->host->hw->data_buf, 0, 64); + int bits = 0; + int idx = 0; + uint32_t wd = 0; + for (int i=0; ihandle->host->hw->data_buf[idx] = wd; + bits = 0; + idx++; + wd = 0; + } + } + if (bits) eve_spi->handle->host->hw->data_buf[idx] = wd; + _spi_transfer_start(eve_spi, (data_len + padding) * 8, 0); + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready + } + else { + // === Send length > 64, send using block transfer function === + spi_transaction_t t; + memset(&t, 0, sizeof(t)); //Zero out the transaction + + t.length = data_len * 8; + t.tx_buffer = data; + t.rxlength = 0; + t.rx_buffer = NULL; + + spi_transfer_data_nodma(eve_spi, &t); // Send using direct mode + + if (padding) { + // send padding bytes + eve_spi->handle->host->hw->data_buf[0] = 0; + _spi_transfer_start(eve_spi, padding * 8, 0); + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready + } + } + return (data_len + padding); } -//----------------------------------------------------------------------------------- -void FT8_memWrite_flash_buffer(uint32_t ftAddress, const uint8_t *data, uint16_t len) +//------------------------------------------------------------------------------------------------------ +int FT8_memWrite_flash_buffer(uint32_t ftAddress, const uint8_t *data, uint16_t len, bool check_padding) { - if (spi_lobo_device_select(eve_spi, 0)) return; - eve_spi->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE); + if (eve_select()) return 0; + eve_spi->handle->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE); _spi_transfer_start(eve_spi, 24, 24); + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready - len = (len + 3)&(~3); + int res = FT8_send_data((uint8_t *)data, len, check_padding); - FT8_send_data((uint8_t *)data, len); - - spi_lobo_device_deselect(eve_spi); + eve_deselect(); + return res; } +//----------------- +void FT8_CP_reset() +{ + FT8_memWrite8(REG_CPURESET, 1); // hold co-processor engine in the reset condition + FT8_memWrite16(REG_CMD_READ, 0); // set REG_CMD_READ to 0 + FT8_memWrite16(REG_CMD_WRITE, 0); // set REG_CMD_WRITE to 0 + eve_cmdOffset = 0; // reset eve_cmdOffset + FT8_memWrite8(REG_CPURESET, 0); // set REG_CMD_WRITE to 0 to restart the co-processor engine +} // Check if the graphics processor completed executing the current command list. -// This is the case when REG_CMD_READ matches eve_cmdOffset, indicating that all commands have been executed. +// This is the case when REG_CMD_READ matches REG_CMD_WRITE (eve_cmdOffset), +// indicating that all commands have been executed. //-------------------- uint8_t FT8_busy(void) { - uint16_t cmdBufferRead; + uint16_t cmdBufferRead, cmdBufferWrite; cmdBufferRead = FT8_memRead16(REG_CMD_READ); // read the graphics processor read pointer + cmdBufferWrite = FT8_memRead16(REG_CMD_WRITE); // read the graphics processor write pointer - if (eve_cmdOffset != cmdBufferRead) return 1; - else return 0; + if (cmdBufferRead == 0xFFF) { + // EVE co-processor engine fault + FT8_CP_reset(); + ESP_LOGE(TAG, "EVE co-processor fault"); + return 2; + } + + if (cmdBufferWrite != cmdBufferRead) return 1; + else return 0; } //------------------------------ @@ -216,11 +603,12 @@ uint32_t FT8_get_touch_tag(void) uint32_t value; value = FT8_memRead32(REG_TOUCH_TAG); - return value; + return (value & 0xFF); } -// Order the command coprocessor to start processing its FIFO queue and do not wait for completion +// Order the command coprocessor to start processing its FIFO queue +// do not wait for completion ! //---------------------- void FT8_cmd_start(void) { @@ -229,12 +617,23 @@ void FT8_cmd_start(void) } -/// Order the command coprocessor to start processing its FIFO queue and wait for completion -//------------------------ -void FT8_cmd_execute(void) +// Order the command coprocessor to start processing its FIFO queue +// Wait for completion ! +//------------------------------ +bool FT8_cmd_execute(int tmo_ms) { FT8_cmd_start(); - while (FT8_busy()); + uint64_t tmo = mp_hal_ticks_ms(); + uint8_t res = FT8_busy(); + while (res == 1) { + mp_hal_reset_wdt(); + res = FT8_busy(); + if ((res == 1) && ((mp_hal_ticks_ms()-tmo) > tmo_ms)) { + FT8_CP_reset(); + res = 2; + } + } + return (res == 0); } //-------------------------- @@ -243,6 +642,14 @@ void FT8_get_cmdoffset(void) eve_cmdOffset = FT8_memRead16(REG_CMD_WRITE); } +// make current value of cmdOffset available while limiting access to that var to the FT8_commands module +//--------------------------------- +uint16_t FT8_report_cmdoffset(void) +{ + return (eve_cmdOffset); +} + + //---------------------------------------- void FT8_inc_cmdoffset(uint16_t increment) { @@ -251,10 +658,12 @@ void FT8_inc_cmdoffset(uint16_t increment) } +// ==== Write to EVE command FIFO ============================================================================ /* -These eliminate the overhead of transmitting the command fifo address with every single command, just wrap a sequence of commands -with these and the address is only transmitted once at the start of the block. -Be careful to not use any functions in the sequence that do not address the command-fifo as for example any FT8_mem...() function. +These eliminate the overhead of transmitting the command fifo address with every single command, +just wrap a sequence of commands with these and the address is only transmitted once at the start of the block. +Be careful to not use any functions in the sequence that do not address the command-fifo, +as for example any FT8_mem...() function. */ //---------------------------- void FT8_start_cmd_burst(void) @@ -263,16 +672,30 @@ void FT8_start_cmd_burst(void) cmd_burst = 42; ftAddress = FT8_RAM_CMD + eve_cmdOffset; - if (spi_lobo_device_select(eve_spi, 0)) return; - eve_spi->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE); + if (eve_select()) return; + + eve_spi->handle->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE); _spi_transfer_start(eve_spi, 24, 24); + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready } //-------------------------- void FT8_end_cmd_burst(void) { cmd_burst = 0; - spi_lobo_device_deselect(eve_spi); + eve_deselect(); +} + +// Write a string to coprocessor memory in context of a command +// no chip-select, just plain spi-transfers +//------------------------------------- +void FT8_write_string(const char *text) +{ + size_t textlen = strlen(text); + // sent string must be terminated with null character (ASCII 0) + int res = FT8_send_data((uint8_t *)text, textlen+1, true); + + FT8_inc_cmdoffset(res); } // Begin a coprocessor command @@ -281,20 +704,18 @@ void FT8_start_cmd(uint32_t command) { uint32_t ftAddress; - uint32_t wd = command & 0xff; - wd |= (uint32_t)((command >> 8) & 0xff); - wd |= (uint32_t)((command >> 16) & 0xff); - wd |= (uint32_t)((command >> 24) & 0xff); + if (eve_select()) return; - if (cmd_burst == 0) { + if (cmd_burst == 0) { ftAddress = FT8_RAM_CMD + eve_cmdOffset; - if (spi_lobo_device_select(eve_spi, 0)) return; - eve_spi->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE); - _spi_transfer_start(eve_spi, 24, 24); // send address + eve_spi->handle->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE); + _spi_transfer_start(eve_spi, 24, 24); // send address + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready } - eve_spi->host->hw->data_buf[0] = wd; + eve_spi->handle->host->hw->data_buf[0] = command; _spi_transfer_start(eve_spi, 32, 32); + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready FT8_inc_cmdoffset(4); // update the command-ram pointer } @@ -314,104 +735,51 @@ void FT8_start_cmd(uint32_t command) void FT8_cmd_dl(uint32_t command) { FT8_start_cmd(command); - if (cmd_burst == 0) { - spi_lobo_device_deselect(eve_spi); - } -} - - -// Write a string to coprocessor memory in context of a command -// no chip-select, just plain spi-transfers -//------------------------------------- -void FT8_write_string(const char *text) -{ - uint8_t textlen = strlen(text); - uint8_t padding = 0; - - spi_lobo_transaction_t t; - memset(&t, 0, sizeof(t)); //Zero out the transaction - - t.length = textlen * 8; - t.tx_buffer = text; - t.rxlength = 0; - t.rx_buffer = NULL; - - spi_lobo_transfer_data(eve_spi, &t); // Send using direct mode - - padding = strlen(text) % 4; /* 0, 1, 2 or 3 */ - padding = 4-padding; /* 4, 3, 2, 1 */ - - eve_spi->host->hw->data_buf[0] = 0; - _spi_transfer_start(eve_spi, padding * 8, 0); - - FT8_inc_cmdoffset(textlen + padding); + if (cmd_burst == 0) eve_deselect(); } // ============================================ // ==== Commands to draw graphics objects: ==== // ============================================ +// Send number of 16-bit parameters +// 'len' can have the value 2, 4, 6 or 8 //------------------------------------------------------------------------------------------------------------------------------------------- static void FT8_send_params(int16_t p1, int16_t p2, int16_t p3, uint16_t p4, uint16_t p5, uint16_t p6, uint16_t p7, uint16_t p8, uint8_t len) { - uint32_t wd = (uint32_t)(p1 & 0xFF); - wd |= (uint32_t)(p1 & 0xFF00); - wd |= (uint32_t)((p2 & 0xFF) << 16); - wd |= (uint32_t)((p2 & 0xFF00) << 16); - eve_spi->host->hw->data_buf[0] = wd; + eve_spi->handle->host->hw->data_buf[0] = ((uint32_t)p1 | (uint32_t)p2 << 16); if (len < 4) goto send; - wd = (uint32_t)(p3 & 0xFF); - wd |= (uint32_t)(p3 & 0xFF00); - wd |= (uint32_t)((p4 & 0xFF) << 16); - wd |= (uint32_t)((p4 & 0xFF00) << 16); - eve_spi->host->hw->data_buf[1] = wd; + eve_spi->handle->host->hw->data_buf[1] = ((uint32_t)p3 | (uint32_t)p4 << 16); if (len < 6) goto send; - wd = (uint32_t)(p5 & 0xFF); - wd |= (uint32_t)(p5 & 0xFF00); - wd |= (uint32_t)((p6 & 0xFF) << 16); - wd |= (uint32_t)((p6 & 0xFF00) << 16); - eve_spi->host->hw->data_buf[2] = wd; + eve_spi->handle->host->hw->data_buf[2] = ((uint32_t)p5 | (uint32_t)p6 << 16); if (len < 8) goto send; - wd = (uint32_t)(p7 & 0xFF); - wd |= (uint32_t)(p7 & 0xFF00); - wd |= (uint32_t)((p8 & 0xFF) << 16); - wd |= (uint32_t)((p8 & 0xFF00) << 16); - eve_spi->host->hw->data_buf[2] = wd; + eve_spi->handle->host->hw->data_buf[3] = ((uint32_t)p7 | (uint32_t)p8 << 16); send: _spi_transfer_start(eve_spi, len*16, len*16); // send + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready FT8_inc_cmdoffset(len * 2); } -//--------------------------------------------------------------------------------- -static void FT8_send_long(uint32_t val1, uint32_t val2, uint32_t val3, uint8_t len) +// Send number of 32-bit longs +//-------------------------------------------------------------------------- +void FT8_send_long(uint32_t val1, uint32_t val2, uint32_t val3, uint8_t len) { - uint32_t wd = (uint32_t)(val1 & 0xFF); - wd |= (uint32_t)((val1 >> 8) & 0xFF); - wd |= (uint32_t)((val1 >> 16) & 0xFF); - wd |= (uint32_t)((val1 >> 24) & 0xFF); - eve_spi->host->hw->data_buf[0] = wd; + eve_spi->handle->host->hw->data_buf[0] = val1; if (len < 2) goto send; - wd = (uint32_t)(val2 & 0xFF); - wd |= (uint32_t)((val2 >> 8) & 0xFF); - wd |= (uint32_t)((val2 >> 16) & 0xFF); - wd |= (uint32_t)((val2 >> 24) & 0xFF); - eve_spi->host->hw->data_buf[1] = wd; + eve_spi->handle->host->hw->data_buf[1] = val2; if (len < 3) goto send; - wd = (uint32_t)(val3 & 0xFF); - wd |= (uint32_t)((val3 >> 8) & 0xFF); - wd |= (uint32_t)((val3 >> 16) & 0xFF); - wd |= (uint32_t)((val3 >> 24) & 0xFF); - eve_spi->host->hw->data_buf[2] = wd; + eve_spi->handle->host->hw->data_buf[2] = val3; send: _spi_transfer_start(eve_spi, len*32, len*32); // send + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready FT8_inc_cmdoffset(len * 4); } @@ -424,7 +792,7 @@ void FT8_cmd_text(int16_t x0, int16_t y0, int16_t font, uint16_t options, const FT8_send_params(x0, y0, font, options, 0, 0, 0, 0, 4); FT8_write_string(text); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } // Draw a button with text @@ -435,7 +803,7 @@ void FT8_cmd_button(int16_t x0, int16_t y0, int16_t w0, int16_t h0, int16_t font FT8_send_params(x0, y0, w0, h0, font, options, 0, 0, 6); FT8_write_string(text); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } // Draw a clock @@ -445,7 +813,7 @@ void FT8_cmd_clock(int16_t x0, int16_t y0, int16_t r0, uint16_t options, uint16_ FT8_start_cmd(CMD_CLOCK); FT8_send_params(x0, y0, r0, options, hours, minutes, seconds, millisecs, 8); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //---------------------------------- @@ -454,7 +822,7 @@ void FT8_cmd_bgcolor(uint32_t color) FT8_start_cmd(CMD_BGCOLOR); FT8_send_long(color, 0, 0, 1); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //---------------------------------- @@ -463,7 +831,7 @@ void FT8_cmd_fgcolor(uint32_t color) FT8_start_cmd(CMD_FGCOLOR); FT8_send_long(color, 0, 0, 1); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //------------------------------------ @@ -472,7 +840,7 @@ void FT8_cmd_gradcolor(uint32_t color) FT8_start_cmd(CMD_GRADCOLOR); FT8_send_long(color, 0, 0, 1); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //------------------------------------------------------------------------------------------------------------------------------------ @@ -481,16 +849,19 @@ void FT8_cmd_gauge(int16_t x0, int16_t y0, int16_t r0, uint16_t options, uint16_ FT8_start_cmd(CMD_GAUGE); FT8_send_params(x0, y0, r0, options, major, minor, val, range, 8); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //------------------------------------------------------------------------------------------------- void FT8_cmd_gradient(int16_t x0, int16_t y0, uint32_t rgb0, int16_t x1, int16_t y1, uint32_t rgb1) { FT8_start_cmd(CMD_GRADIENT); - FT8_send_params(x0, y0, (uint16_t)rgb0, (uint16_t)(rgb0 >> 16), x1, y1, (uint16_t)rgb1, (uint16_t)(rgb1 >> 16), 8); + FT8_send_params(x0, y0, 0, 0, 0, 0, 0, 0, 2); + FT8_send_long(rgb0, 0, 0, 1); + FT8_send_params(x1, y1, 0, 0, 0, 0, 0, 0, 2); + FT8_send_long(rgb1, 0, 0, 1); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //----------------------------------------------------------------------------------------------------------------- @@ -501,7 +872,7 @@ void FT8_cmd_keys(int16_t x0, int16_t y0, int16_t w0, int16_t h0, int16_t font, FT8_send_params(x0, y0, w0, h0, font, options, 0, 0, 6); FT8_write_string(text); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //------------------------------------------------------------------------------------------------------------------- @@ -510,7 +881,7 @@ void FT8_cmd_progress(int16_t x0, int16_t y0, int16_t w0, int16_t h0, uint16_t o FT8_start_cmd(CMD_PROGRESS); FT8_send_params(x0, y0, w0, h0, options, val, range, 0, 8); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //----------------------------------------------------------------------------------------------------------------------------------- @@ -519,16 +890,16 @@ void FT8_cmd_scrollbar(int16_t x0, int16_t y0, int16_t w0, int16_t h0, uint16_t FT8_start_cmd(CMD_SCROLLBAR); FT8_send_params(x0, y0, w0, h0, options, val, size, range, 8); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } - +//----------------------------------------------------------------------------------------------------------------- void FT8_cmd_slider(int16_t x1, int16_t y1, int16_t w1, int16_t h1, uint16_t options, uint16_t val, uint16_t range) { FT8_start_cmd(CMD_SLIDER); FT8_send_params(x1, y1, w1, h1, options, val, range, 0, 8); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //----------------------------------------------------------------------------------- @@ -537,7 +908,7 @@ void FT8_cmd_dial(int16_t x0, int16_t y0, int16_t r0, uint16_t options, uint16_t FT8_start_cmd(CMD_DIAL); FT8_send_params(x0, y0, r0, options, val, 0, 0, 0, 6); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //----------------------------------------------------------------------------------------------------------------------- @@ -547,91 +918,84 @@ void FT8_cmd_toggle(int16_t x0, int16_t y0, int16_t w0, int16_t font, uint16_t o FT8_send_params(x0, y0, w0, font, options, state, 0, 0, 6); FT8_write_string(text); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } - -#ifdef FT8_81X_ENABLE //--------------------------------- void FT8_cmd_setbase(uint32_t base) { + if (eve_chip_id < 0x810) return; FT8_start_cmd(CMD_SETBASE); - FT8_send_params((uint16_t)base, (uint16_t)(base >> 16), 0, 0, 0, 0, 0, 0, 2); + FT8_send_long(base, 0, 0, 1); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //---------------------------------------------------------------------------------- void FT8_cmd_setbitmap(uint32_t addr, uint16_t fmt, uint16_t width, uint16_t height) { + if (eve_chip_id < 0x810) return; FT8_start_cmd(CMD_SETBITMAP); - FT8_send_params((uint16_t)addr, (uint16_t)(addr >> 16), fmt, width, height, 0, 0, 0, 6); + FT8_send_long(addr, 0, 0, 1); + FT8_send_params(fmt, width, height, 0, 0, 0, 0, 0, 4); + + if (cmd_burst == 0) eve_deselect(); +} - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); +//------------------------------------------- +void FT8_cmd_bitmapXY(uint16_t x, uint16_t y) +{ + FT8_cmd_dl(DL_BEGIN | FT8_BITMAPS); + FT8_cmd_dl(VERTEX2F(x*16, y*16)); + FT8_cmd_dl(DL_END); } -#endif //----------------------------------------------------------------------------------------- void FT8_cmd_number(int16_t x0, int16_t y0, int16_t font, uint16_t options, int32_t number) { FT8_start_cmd(CMD_NUMBER); - FT8_send_params(x0, y0, font, options, (uint16_t)number, (uint16_t)(number >> 16), 0, 0, 6); + FT8_send_params(x0, y0, font, options, 0, 0, 0, 0, 4); + FT8_send_long(number, 0, 0, 1); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } // ======================================== // ==== Commands to operate on memory: ==== // ======================================== +//---------------------------------------------- void FT8_cmd_memzero(uint32_t ptr, uint32_t num) { FT8_start_cmd(CMD_MEMZERO); FT8_send_long(ptr, num, 0, 2); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } - +//------------------------------------------------------------ void FT8_cmd_memset(uint32_t ptr, uint8_t value, uint32_t num) { FT8_start_cmd(CMD_MEMSET); FT8_send_long(ptr, (uint32_t)value, num, 3); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } - -/* -void FT8_cmd_memwrite(uint32_t dest, uint32_t num, const uint8_t *data) +// Write bytes into memory +// If the number of bytes is not a multiple of 4, then 1, 2 or 3 bytes should be +// appended to ensure 4-byte alignment of the next command +//--------------------------------------------------------------------- +void FT8_cmd_memwrite(uint32_t dest, const uint8_t *data, uint32_t num) { FT8_start_cmd(CMD_MEMWRITE); - spi_transmit((uint8_t)(dest)); - spi_transmit((uint8_t)(dest >> 8)); - spi_transmit((uint8_t)(dest >> 16)); - spi_transmit((uint8_t)(dest >> 24)); + FT8_send_long(dest, num, 0, 2); + int res = FT8_send_data((uint8_t *)data, num, true); + FT8_inc_cmdoffset(res); - spi_transmit((uint8_t)(num)); - spi_transmit((uint8_t)(num >> 8)); - spi_transmit((uint8_t)(num >> 16)); - spi_transmit((uint8_t)(num >> 24)); - - num = (num + 3)&(~3); - - for(count=0;count 0) - { - block_len = bytes_left>4000 ? 4000:bytes_left; - - ftAddress = FT8_RAM_CMD + eve_cmdOffset; - spi_lobo_device_select(eve_spi, 0); + uint8_t * buff = NULL; - eve_spi->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE); - _spi_transfer_start(eve_spi, 24, 24); // send address - - spi_flash_write(data, block_len); - spi_lobo_device_deselect(eve_spi); - - data += block_len; - bytes_left -= block_len; - FT8_cmd_execute(); - } + if (type == 1) { + FT8_start_cmd(CMD_LOADIMAGE); + FT8_send_long(ptr, options, 0, 2); + eve_deselect(); } + else if (type == 2) { + FT8_start_cmd(CMD_INFLATE); + FT8_send_long(ptr, 0, 0, 1); + eve_deselect(); + } + + if (fhndl == NULL) return -2; + buff = malloc(1024); + if (buff == NULL) return -3; + + bytes_sent = 0; + bytes_left = len; + + while (bytes_left > 0) { + // read block from file + block_len = (bytes_left > 1024) ? 1024 : bytes_left; + block_len = fread(buff, 1, block_len, fhndl); + if (block_len <= 0) { + ESP_LOGE(TAG, "File read error [%d]: sent=%d, remaining=%d", block_len, bytes_sent, bytes_left); + break; + } + + if (type < 3) { + // sending via command buffer + ftAddress = FT8_RAM_CMD + eve_cmdOffset; + eve_select(); + + eve_spi->handle->host->hw->data_buf[0] = FT8_address(ftAddress, MEM_WRITE); + _spi_transfer_start(eve_spi, 24, 24); // send address + while (eve_spi->handle->host->hw->cmd.usr); // Wait for SPI bus ready + + // Send data block (alligned to 4 bytes) + res = FT8_send_data(buff, block_len, true); + FT8_inc_cmdoffset(res); + eve_deselect(); + + bytes_left -= block_len; + bytes_sent += res; + if (!FT8_cmd_execute(250)) { + free(buff); + ESP_LOGE(TAG, "Execute error: sent=%d, remaining=%d", bytes_sent, bytes_left); + return (bytes_sent * -1); + } + } + else { + // send directly to RAM_G + res = FT8_memWrite_flash_buffer(ptr + bytes_sent, buff, block_len, true); + + bytes_left -= block_len; + bytes_sent += res; + } + } + free(buff); + return bytes_sent; } -#ifdef FT8_81X_ENABLE + // this is meant to be called outside display-list building, // does not support cmd-burst //------------------------------------------------- void FT8_cmd_mediafifo(uint32_t ptr, uint32_t size) { + if (eve_chip_id < 0x810) return; FT8_start_cmd(CMD_MEDIAFIFO); FT8_send_long(ptr, size, 0, 2); - spi_lobo_device_deselect(eve_spi); + eve_deselect(); +} + +//------------------------------------ +void FT8_cmd_videoframe(uint32_t addr) +{ + FT8_start_cmd(CMD_VIDEOFRAME); + FT8_send_long(addr, ft8_stFifo.fifo_buff-4, 0, 2); + + if (cmd_burst == 0) eve_deselect(); } -#endif + // =========================================================== @@ -737,7 +1141,7 @@ void FT8_cmd_translate(int32_t tx, int32_t ty) FT8_start_cmd(CMD_TRANSLATE); FT8_send_long(tx, ty, 0, 2); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //---------------------------------------- @@ -746,7 +1150,7 @@ void FT8_cmd_scale(int32_t sx, int32_t sy) FT8_start_cmd(CMD_SCALE); FT8_send_long(sx, sy, 0, 2); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //------------------------------ @@ -755,9 +1159,16 @@ void FT8_cmd_rotate(int32_t ang) FT8_start_cmd(CMD_ROTATE); FT8_send_long(ang, 0, 0, 1); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } +//---------------------- +void FT8_cmd_setmatrix() +{ + FT8_start_cmd(CMD_SETMATRIX); + + if (cmd_burst == 0) eve_deselect(); +} /* * the description in the programmers guide is strange for this function @@ -774,7 +1185,7 @@ void FT8_cmd_getmatrix(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, in FT8_send_long(a, b, c, 3); FT8_send_long(d, e, f, 3); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } @@ -788,7 +1199,7 @@ void FT8_cmd_calibrate(void) FT8_start_cmd(CMD_CALIBRATE); FT8_send_long(0, 0, 0, 1); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //--------------------------------- @@ -797,20 +1208,19 @@ void FT8_cmd_interrupt(uint32_t ms) FT8_start_cmd(CMD_INTERRUPT); FT8_send_long(ms, 0, 0, 1); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } -#ifdef FT8_81X_ENABLE //--------------------------------------------------- void FT8_cmd_romfont(uint32_t font, uint32_t romslot) { + if (eve_chip_id < 0x810) return; FT8_start_cmd(CMD_ROMFONT); FT8_send_long(font, romslot & 0xFFFF, 0, 2); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } -#endif //----------------------------------------------- void FT8_cmd_setfont(uint32_t font, uint32_t ptr) @@ -818,46 +1228,47 @@ void FT8_cmd_setfont(uint32_t font, uint32_t ptr) FT8_start_cmd(CMD_SETFONT); FT8_send_long(font, ptr, 0, 2); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } - -#ifdef FT8_81X_ENABLE //-------------------------------------------------------------------- void FT8_cmd_setfont2(uint32_t font, uint32_t ptr, uint32_t firstchar) { + if (eve_chip_id < 0x810) return; FT8_start_cmd(CMD_SETFONT2); FT8_send_long(font, ptr, firstchar, 3); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //-------------------------------- void FT8_cmd_setrotate(uint32_t r) { + if (eve_chip_id < 0x810) return; FT8_start_cmd(CMD_SETROTATE); FT8_send_long(r, 0, 0, 1); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //-------------------------------------- void FT8_cmd_setscratch(uint32_t handle) { + if (eve_chip_id < 0x810) return; FT8_start_cmd(CMD_SETSCRATCH); FT8_send_long(handle, 0, 0, 1); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } -#endif //-------------------------------------------------------------------------------------------------- void FT8_cmd_sketch(int16_t x0, int16_t y0, uint16_t w0, uint16_t h0, uint32_t ptr, uint16_t format) { FT8_start_cmd(CMD_SKETCH); - FT8_send_params(x0, y0, w0, h0, (uint16_t)ptr, (uint16_t)(ptr >> 16), 0, 0, 8); + FT8_send_params(x0, y0, w0, h0, 0, 0, 0, 0, 4); + FT8_send_long(ptr, (uint32_t)format, 0, 2); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //--------------------------------- @@ -866,20 +1277,19 @@ void FT8_cmd_snapshot(uint32_t ptr) FT8_start_cmd(CMD_SNAPSHOT); FT8_send_long(ptr, 0, 0, 1); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } - -#ifdef FT8_81X_ENABLE //------------------------------------------------------------------------------------------------ void FT8_cmd_snapshot2(uint32_t fmt, uint32_t ptr, int16_t x0, int16_t y0, int16_t w0, int16_t h0) { + if (eve_chip_id < 0x810) return; FT8_start_cmd(CMD_SNAPSHOT2); - FT8_send_params((uint16_t)fmt, (uint16_t)(fmt >> 16), (uint16_t)ptr, (uint16_t)(ptr >> 16), x0, y0, w0, h0, 8); + FT8_send_long(fmt, ptr, 0, 2); + FT8_send_params(x0, y0, w0, h0, 0, 0, 0, 0, 4); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } -#endif //-------------------------------------------------------------------------- void FT8_cmd_spinner(int16_t x0, int16_t y0, uint16_t style, uint16_t scale) @@ -887,7 +1297,7 @@ void FT8_cmd_spinner(int16_t x0, int16_t y0, uint16_t style, uint16_t scale) FT8_start_cmd(CMD_SPINNER); FT8_send_params(x0, y0, style, scale, 0, 0, 0, 0, 4); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //----------------------------------------------------------------------------- @@ -896,7 +1306,7 @@ void FT8_cmd_track(int16_t x0, int16_t y0, int16_t w0, int16_t h0, int16_t tag) FT8_start_cmd(CMD_TRACK); FT8_send_params(x0, y0, w0, h0, tag, 0, 0, 0, 6); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } @@ -904,25 +1314,25 @@ void FT8_cmd_track(int16_t x0, int16_t y0, int16_t w0, int16_t h0, int16_t tag) // ==== Commands that return values by writing to the command-fifo ==== // ==================================================================== - /* * This is handled by having this functions return the offset address on the command-fifo from * which the results can be fetched after execution: FT8_memRead32(FT8_RAM_CMD + offset) * - * Note: yes, these are different than the functions in the Programmers Guide from FTDI, + * Note: these are different than the functions in the Programmers Guide from FTDI, this is because I have no idea why anyone would want to pass "result" as an actual argument to these functions - when this only marks the offset the command-processor is writing to, - it may even be okay to not transfer anything at all, - just advance the offset by 4 bytes + when this only marks the offset the command-processor is writing to. + It may even be okay to not transfer anything at all, just advance the offset by 4 bytes * Example of using FT8_cmd_memcrc: offset = FT8_cmd_memcrc(my_ptr_to_some_memory_region, some_amount_of_bytes); - FT8_cmd_execute(); + FT8_cmd_execute(250); crc32 = FT8_memRead32(FT8_RAM_CMD + offset); */ +// Compute a CRC-32 for memory segment +// returns offset pointing to the CRC value //------------------------------------------------- uint16_t FT8_cmd_memcrc(uint32_t ptr, uint32_t num) { @@ -932,11 +1342,12 @@ uint16_t FT8_cmd_memcrc(uint32_t ptr, uint32_t num) FT8_send_long(ptr, num, 0, 3); offset = eve_cmdOffset - 4; - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); return offset; } +// Get the end memory address of data inflated by CMD_INFLATE //--------------------------- uint16_t FT8_cmd_getptr(void) { @@ -946,11 +1357,12 @@ uint16_t FT8_cmd_getptr(void) FT8_send_long(0, 0, 0, 1); offset = eve_cmdOffset - 4; - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); return offset; } +// Read a register value, returns offset pointing to the register value //------------------------------------ uint16_t FT8_cmd_regread(uint32_t ptr) { @@ -960,43 +1372,42 @@ uint16_t FT8_cmd_regread(uint32_t ptr) FT8_send_long(ptr, 0, 0, 2); offset = eve_cmdOffset - 4; - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); return offset; } - /* + * Get the image properties decompressed by CMD_LOADIMAGE + * * Be aware that this returns the first offset pointing to "width", - * in order to also read "height" you need to: + * in order to also read "height" you need to execute: offset = FT8_cmd_getprops(my_last_picture_pointer); - FT8_cmd_execute(); + FT8_cmd_execute(250); width = FT8_memRead32(FT8_RAM_CMD + offset); offset += 4; offset &= 0x0fff; height = FT8_memRead32(FT8_RAM_CMD + offset); */ - //------------------------------------- uint16_t FT8_cmd_getprops(uint32_t ptr) { uint16_t offset; - FT8_start_cmd(CMD_REGREAD); + FT8_start_cmd(CMD_GETPROPS); FT8_send_long(ptr, 0, 0, 3); offset = eve_cmdOffset - 8; - eve_cmdOffset -= 4; - eve_cmdOffset &= 0x0fff; - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); return offset; } -// ======================================================================================================================================== -// ==== meta-commands, sequences of several display-list entries condensed into simpler to use functions at the price of some overhead ==== -// ======================================================================================================================================== +// =============================================================================== +// ==== meta-commands, sequences of several display-list entries ==== +// ==== condensed into simpler to use functions at the price of some overhead ==== +// =============================================================================== //------------------------------------------------------- void FT8_cmd_point(int16_t x0, int16_t y0, uint16_t size) @@ -1009,7 +1420,7 @@ void FT8_cmd_point(int16_t x0, int16_t y0, uint16_t size) calc2 = VERTEX2F(x0 * 16, y0 * 16); FT8_send_long(calc1, calc2, DL_END, 3); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); } //------------------------------------------------------------------------------- @@ -1025,7 +1436,27 @@ void FT8_cmd_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t width FT8_send_long(calc1, calc2, calc3, 3); FT8_send_long(DL_END, 0, 0, 1); - if (cmd_burst == 0) spi_lobo_device_deselect(eve_spi); + if (cmd_burst == 0) eve_deselect(); +} + +//------------------------------------------------------------------------------- +void FT8_cmd_strip(uint16_t *data, uint16_t length, uint8_t type, uint16_t width) +{ + if ((type < FT8_LINE_STRIP) || (type > FT8_EDGE_STRIP_B)) return; + + uint32_t calc, lwidth; + + FT8_start_cmd((DL_BEGIN | type)); + + lwidth = LINE_WIDTH(width * 16); + FT8_send_long(lwidth, 0, 0, 1); + for (int i=0; imiso); + gpio_pad_select_gpio(dconfig->mosi); + gpio_pad_select_gpio(dconfig->sck); + + gpio_set_direction(dconfig->miso, GPIO_MODE_INPUT); + gpio_set_pull_mode(dconfig->miso, GPIO_PULLUP_ONLY); + gpio_set_direction(dconfig->mosi, GPIO_MODE_OUTPUT); + gpio_set_direction(dconfig->sck, GPIO_MODE_OUTPUT); + } + + gpio_pad_select_gpio(dconfig->cs); + gpio_set_direction(dconfig->cs, GPIO_MODE_OUTPUT); + gpio_set_level(dconfig->cs, 1); + + if (dconfig->pd >= 0) { + gpio_pad_select_gpio(dconfig->pd); + gpio_set_direction(dconfig->pd, GPIO_MODE_OUTPUT); + gpio_set_level(dconfig->pd, 0); + } + eve_spibus_is_init = 1; +} + +//------------------------------------------------- +static esp_err_t EVE_spiInit(eve_config_t *dconfig) { - uint8_t gpio; - uint8_t chipid; + esp_err_t ret; + + /*int used_spi = spi_host_used_by_sdspi(); + if ((used_spi != 0) && (used_spi == dconfig->host)) { + // change spi host + if (used_spi == VSPI_HOST) eve_spi->spihost = HSPI_HOST; + else eve_spi->spihost = VSPI_HOST; + ESP_LOGW(TAG, "spi bus changed (%d -> %d)", used_spi, eve_spi->spihost); + } + else eve_spi->spihost = dconfig->host;*/ + + eve_spi->spihost = dconfig->host; + ESP_LOGD(TAG, "Using spi bus %d", eve_spi->spihost); + eve_spi->buscfg = SPIbus_configs[eve_spi->spihost]; + if (eve_spi->buscfg == NULL) { + ESP_LOGE(TAG, "spi bus %d not available ", eve_spi->spihost); + return ESP_ERR_INVALID_ARG; + } + + eve_spi->dma_channel = 1; + eve_spi->curr_clock = 8000000; // for initialization set the clock to 8MHz + eve_spi->handle = NULL; + eve_spi->cs = dconfig->cs; + eve_spi->dc = 0; + eve_spi->selected = 0; + + eve_spi->buscfg->miso_io_num = dconfig->miso; // set SPI MISO pin + eve_spi->buscfg->mosi_io_num = dconfig->mosi; // set SPI MOSI pin + eve_spi->buscfg->sclk_io_num = dconfig->sck; // set SPI CLK pin + eve_spi->buscfg->quadwp_io_num = -1; + eve_spi->buscfg->quadhd_io_num = -1; + eve_spi->buscfg->max_transfer_sz = 6*1024; + + eve_spi->devcfg.clock_speed_hz = eve_spi->curr_clock; // Initial clock + eve_spi->devcfg.duty_cycle_pos = 128; // 50% duty cycle + eve_spi->devcfg.mode = 0; // SPI mode 0 + eve_spi->devcfg.spics_io_num = -1; // we will use external CS pin + eve_spi->devcfg.queue_size = 1; // we need only one transaction + eve_spi->devcfg.flags = 0; // ALWAYS SET to FULL DUPLEX MODE for EVE display spi + + // ================================================================== + // ==== Initialize the SPI bus and attach the LCD to the SPI bus ==== + ret = add_extspi_device(eve_spi); + if (ret != ESP_OK) { + return ret; + } + + ESP_LOGD(TAG, "SPI bus configured (%d)", eve_spi->spihost); + spi_is_init = 1; + + // ==== Test select/deselect ==== + ret = spi_device_select(eve_spi, 1); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error selecting display device"); + } + vTaskDelay(10 / portTICK_RATE_MS); + ret = spi_device_deselect(eve_spi); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error deselecting display device"); + } + + ESP_LOGI(TAG, "Attached display device, speed=%u", spi_get_speed(eve_spi)); + ESP_LOGI(TAG, "Bus uses native pins: %s", spi_uses_native_pins(eve_spi->handle) ? "true" : "false"); + + return ESP_OK; +} + +//============================================================================ +esp_err_t FT8_init(eve_config_t *dconfig, exspi_device_handle_t *disp_spi_dev) +{ + uint8_t chipid = 0; + uint32_t chip_type = 0; uint8_t timeout = 0; + esp_err_t ret; + + eve_spi = disp_spi_dev; + if (spi_is_init == 0) { + EVE_PinsInit(dconfig); + ret = EVE_spiInit(dconfig); + if (ret != ESP_OK) { + eve_spi->handle = NULL; + eve_spi = NULL; + return ret; + } + } - //FT8_pdn_set(); - vTaskDelay(10 / portTICK_RATE_MS); // minimum time for power-down is 5ms - //FT8_pdn_clear(); - vTaskDelay(21 / portTICK_RATE_MS); // minimum time to allow from rising PD_N to first access is 20ms - - // FT8_cmdWrite(FT8_CORERST); // reset, only required for warmstart if PowerDown line is not used + vTaskDelay(6 / portTICK_RATE_MS); + if (dconfig->pd >= 0) { + gpio_set_level(dconfig->pd, 0); + vTaskDelay(7 / portTICK_RATE_MS); // minimum time for power-down is 5ms + gpio_set_level(dconfig->pd, 1); + vTaskDelay(25 / portTICK_RATE_MS); // minimum time to allow from rising PD_N to first access is 20ms + } + else { + FT8_cmdWrite(FT8_CORERST); // reset, only required for warm start if PowerDown line is not used + vTaskDelay(25 / portTICK_RATE_MS); // minimum time to allow from rising PD_N to first access is 20ms + } + + #if defined (FT8_ADAM101) + FT8_memWrite8(REG_PWM_DUTY, 0x80); // turn off backlight for Glyn ADAM101 module, it uses inverted values + #else + FT8_memWrite8(REG_PWM_DUTY, 0); // turn off backlight for any other module + #endif - if (FT8_HAS_CRYSTAL != 0) FT8_cmdWrite(FT8_CLKEXT); // setup FT8xx for external clock - else FT8_cmdWrite(FT8_CLKINT); // setup FT8xx for internal clock + // Setup FT8xx for external or internal clock + if (dconfig->disp_config.has_crystal != 0) FT8_cmdWrite(FT8_CLKEXT); + else FT8_cmdWrite(FT8_CLKINT); - FT8_cmdWrite(FT8_ACTIVE); // start FT8xx + // Start FT8xx + FT8_cmdWrite(FT8_ACTIVE); - chipid = FT8_memRead8(REG_ID); // Read ID register // if chip id is not 0x7c, continue to read it until it is, // FT81x may need a moment for it's power on self test - while(chipid != 0x7C) { + while (chipid != 0x7C) { chipid = FT8_memRead8(REG_ID); - vTaskDelay(2 / portTICK_RATE_MS); + vTaskDelay(1 / portTICK_RATE_MS); timeout++; - if (timeout > 100) return 0; + if (timeout > 200) { + ESP_LOGE(TAG, "EVE chip not detected (timeout)"); + eve_chip_id = 0; + return ESP_FAIL; + } } - FT8_memWrite8(REG_PCLK, 0x00); // set PCLK to zero - don't clock the LCD until later - FT8_memWrite8(REG_PWM_DUTY, 10); // turn off backlight - - // *** Initialize Display - FT8_memWrite16(REG_HSIZE, FT8_HSIZE); // active display width - FT8_memWrite16(REG_HCYCLE, FT8_HCYCLE); // total number of clocks per line, including front/back porch - FT8_memWrite16(REG_HOFFSET, FT8_HOFFSET); // start of active line - FT8_memWrite16(REG_HSYNC0, FT8_HSYNC0); // start of horizontal sync pulse - FT8_memWrite16(REG_HSYNC1, FT8_HSYNC1); // end of horizontal sync pulse - FT8_memWrite16(REG_VSIZE, FT8_VSIZE); // active display height - FT8_memWrite16(REG_VCYCLE, FT8_VCYCLE); // total number of lines per screen, incl pre/post - FT8_memWrite16(REG_VOFFSET, FT8_VOFFSET); // start of active screen - FT8_memWrite16(REG_VSYNC0, FT8_VSYNC0); // start of vertical sync pulse - FT8_memWrite16(REG_VSYNC1, FT8_VSYNC1); // end of vertical sync pulse - FT8_memWrite8(REG_SWIZZLE, FT8_SWIZZLE); // FT8xx output to LCD - pin order - FT8_memWrite8(REG_PCLK_POL, FT8_PCLKPOL); /// LCD data is clocked in on this PCLK edge - // Don't set PCLK yet - wait for just after the first display list + // Get chip model + chip_type = FT8_memRead32(FT8_ROM_CHIPID); + eve_chip_id = ((chip_type & 0xFF) << 8) | ((chip_type & 0xFF00) >> 8); + if (((eve_chip_id >= 0x800) && (eve_chip_id <= 0x801)) || ((eve_chip_id >= 0x810) && (eve_chip_id <= 0x813))) { + ESP_LOGD(TAG, "EVE chip detected: FT%4x", eve_chip_id); + } + else { + ESP_LOGE(TAG, "EVE chip not detected (wrong ID)"); + eve_chip_id = 0; + return ESP_FAIL; + } - // ** Configure Touch - FT8_memWrite8(REG_TOUCH_MODE, FT8_TMODE_CONTINUOUS); // enable touch - FT8_memWrite16(REG_TOUCH_RZTHRESH, FT8_TOUCH_RZTHRESH); // eliminate any false touches + // If we have a display with a Goodix GT911 / GT9271 touch-controller on it, we need to patch our FT811 or FT813 according to AN_336 + if (dconfig->disp_config.has_GT911) { + uint32_t ftAddress; - // ** Configure Audio - not used, so disable it - FT8_memWrite8(REG_VOL_PB, 0x00); // turn recorded audio volume down - // FT8_memWrite8(REG_VOL_SOUND, 0xff); // turn synthesizer volume on - FT8_memWrite8(REG_VOL_SOUND, 0x00); // turn synthesizer volume off - FT8_memWrite16(REG_SOUND, 0x6000); // set synthesizer to mute + FT8_get_cmdoffset(); + ftAddress = FT8_RAM_CMD + eve_cmdOffset; - FT8_memWrite32(FT8_RAM_DL, DL_CLEAR_RGB); - FT8_memWrite32(FT8_RAM_DL + 4, (DL_CLEAR | CLR_COL | CLR_STN | CLR_TAG)); - FT8_memWrite32(FT8_RAM_DL + 8, DL_DISPLAY); // end of display list - FT8_memWrite32(REG_DLSWAP, FT8_DLSWAP_FRAME); + FT8_memWrite_flash_buffer(ftAddress, FT8_GT911_data, FT8_GT911_len, true); - // nothing is being displayed yet... the pixel clock is still 0x00 + FT8_cmd_execute(250); - gpio = FT8_memRead8(REG_GPIO_DIR); - // set DISP to Output although it always is output, set GPIO1 to Output - Audio Enable on VM800B - gpio |= 0x82; - FT8_memWrite8(REG_GPIO_DIR, gpio); + FT8_memWrite8(REG_TOUCH_OVERSAMPLE, 0x0f); // setup oversample to 0x0f as "hidden" in binary-blob for AN_336 + FT8_memWrite16(REG_TOUCH_CONFIG, 0x05D0); // write magic cookie as requested by AN_336 - gpio = FT8_memRead8(REG_GPIO); // read the FT8xx GPIO register for a read/modify/write operation - // gpio |= 0x82; // set bit 7 of FT8xx GPIO register (DISP), set GPIO1 to High to enable Audio - others are inputs - gpio |= 0x80; // set bit 7 of FT8xx GPIO register (DISP), others are inputs - FT8_memWrite8(REG_GPIO, gpio); // enable the DISP signal to the LCD panel - FT8_memWrite8(REG_PCLK, FT8_PCLK); // now start clocking data to the LCD panel + // specific to the EVE2 modules from Matrix-Orbital we have to use GPIO3 to reset GT911 + FT8_memWrite16(REG_GPIOX_DIR,0x8008); // Reset-Value is 0x8000, adding 0x08 sets GPIO3 to output, default-value for REG_GPIOX is 0x8000 -> Low output on GPIO3 + vTaskDelay(2 / portTICK_RATE_MS); // wait more than 100µs + FT8_memWrite8(REG_CPURESET, 0x00); // clear all resets + vTaskDelay(57 / portTICK_RATE_MS); // wait more than 55ms + FT8_memWrite16(REG_GPIOX_DIR,0x8000); // setting GPIO3 back to input + } - FT8_memWrite8(REG_PWM_DUTY, 70); // turn on backlight + //FT8_memWrite8(REG_PCLK, 0x00); // set PCLK to zero - don't clock the LCD until later + + // === Initialize the display timings === + FT8_memWrite16(REG_HSIZE, dconfig->disp_config.hsize); // active display width + FT8_memWrite16(REG_HCYCLE, dconfig->disp_config.hcycle); // total number of clocks per line, including front/back porch + FT8_memWrite16(REG_HOFFSET, dconfig->disp_config.hoffset); // start of active line + FT8_memWrite16(REG_HSYNC0, dconfig->disp_config.hsync0); // start of horizontal sync pulse + FT8_memWrite16(REG_HSYNC1, dconfig->disp_config.hsync1); // end of horizontal sync pulse + FT8_memWrite16(REG_VSIZE, dconfig->disp_config.vsize); // active display height + FT8_memWrite16(REG_VCYCLE, dconfig->disp_config.vcycle); // total number of lines per screen, incl pre/post + FT8_memWrite16(REG_VOFFSET, dconfig->disp_config.voffset); // start of active screen + FT8_memWrite16(REG_VSYNC0, dconfig->disp_config.vsync0); // start of vertical sync pulse + FT8_memWrite16(REG_VSYNC1, dconfig->disp_config.vsync1); // end of vertical sync pulse + FT8_memWrite8(REG_SWIZZLE, dconfig->disp_config.swizzle); // FT8xx output to LCD - pin order + FT8_memWrite8(REG_PCLK_POL, dconfig->disp_config.pclkpol); // LCD data is clocked in on this PCLK edge + FT8_memWrite8(REG_CSPREAD, dconfig->disp_config.cspread); // helps with noise, when set to 1 fewer signals are changed simultaneously, reset-default: 1 + + // Don't set PCLK yet - wait for just after the first display list - vTaskDelay(2 / portTICK_RATE_MS); // just to be safe - - while (FT8_busy() == 1) ; + // ** Configure Touch + FT8_memWrite8(REG_TOUCH_MODE, FT8_TMODE_CONTINUOUS); // enable touch + FT8_memWrite16(REG_TOUCH_RZTHRESH, dconfig->disp_config.touch_thresh); // eliminate any false touches + + // disable Audio for now + FT8_memWrite8(REG_VOL_PB, 0x00); // turn recorded audio volume down + FT8_memWrite8(REG_VOL_SOUND, 0x00); // turn synthesizer volume off + FT8_memWrite16(REG_SOUND, 0x6000); // set synthesizer to mute + + // write a basic display-list to get things started + FT8_memWrite32(FT8_RAM_DL, DL_CLEAR_RGB); + FT8_memWrite32(FT8_RAM_DL + 4, (DL_CLEAR | CLR_COL | CLR_STN | CLR_TAG)); + FT8_memWrite32(FT8_RAM_DL + 8, DL_DISPLAY); // end of display list + FT8_memWrite32(REG_DLSWAP, FT8_DLSWAP_FRAME); + + // nothing is being displayed yet... the pixel clock is still 0x00 + FT8_memWrite8(REG_GPIO, 0x80); // enable the DISP signal to the LCD panel + FT8_memWrite8(REG_PCLK, dconfig->disp_config.pclk); // now start clocking data to the LCD panel + + do { + vTaskDelay(2 / portTICK_RATE_MS); // just to be safe + } while (FT8_busy()); + + FT8_memWrite8(REG_PWM_DUTY, 64); // turn on backlight + FT8_get_cmdoffset(); - FT8_get_cmdoffset(); - return 1; + return ESP_OK; } #endif // CONFIG_MICROPY_USE_EVE diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/eve/FT8_commands.h b/MicroPython_BUILD/components/micropython/esp32/libs/eve/FT8_commands.h index c68955af..166d199f 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/eve/FT8_commands.h +++ b/MicroPython_BUILD/components/micropython/esp32/libs/eve/FT8_commands.h @@ -32,213 +32,150 @@ #ifndef FT8_COMMANDS_H_ #define FT8_COMMANDS_H_ -#include - -/* switch over to FT81x */ -#define FT8_81X_ENABLE +#include "sdkconfig.h" +#if CONFIG_MICROPY_USE_EVE -/* select the settings for the TFT attached */ -#if 0 - #define FT8_VM800B35A - #define FT8_VM800B43A - #define FT8_VM800B50A - #define FT8_FT810CB_HY50HD - #define FT8_FT811CB_HY50HD - #define FT8_ET07 - #define FT8_RVT70AQ -#endif - -#define FT8_FT810CB_HY50HD - - -/* some pre-definded colors */ -#define RED 0xff0000UL -#define ORANGE 0xffa500UL -#define GREEN 0x00ff00UL -#define BLUE 0x0000ffUL -#define YELLOW 0xffff00UL -/*#define PINK 0xff00ffUL*/ -#define PURPLE 0x800080UL -#define WHITE 0xffffffUL -#define BLACK 0x000000UL - - -/* VM800B35A: FT800 320x240 3.5" FTDI */ -#ifdef FT8_VM800B35A -#define FT8_VSYNC0 (0L) /* Tvf Vertical Front Porch */ -#define FT8_VSYNC1 (2L) /* Tvf + Tvp Vertical Front Porch plus Vsync Pulse width */ -#define FT8_VOFFSET (13L) /* Tvf + Tvp + Tvb Number of non-visible lines (in lines) */ -#define FT8_VCYCLE (263L) /* Tv Total number of lines (visible and non-visible) (in lines) */ -#define FT8_VSIZE (240L) /* Tvd Number of visible lines (in lines) - display height */ -#define FT8_HSYNC0 (0L) /* Thf Horizontal Front Porch */ -#define FT8_HSYNC1 (10L) /* Thf + Thp Horizontal Front Porch plus Hsync Pulse width */ -#define FT8_HOFFSET (70L) /* Thf + Thp + Thb Length of non-visible part of line (in PCLK cycles) */ -#define FT8_HCYCLE (408L) /* Th Total length of line (visible and non-visible) (in PCLKs) */ -#define FT8_HSIZE (320L) /* Thd Length of visible part of line (in PCLKs) - display width */ -#define FT8_PCLKPOL (0L) /* PCLK polarity (0 = rising edge, 1 = falling edge) */ -#define FT8_SWIZZLE (2L) /* Defines the arrangement of the RGB pins of the FT800 */ -#define FT8_PCLK (8L) /* 48MHz / REG_PCLK = PCLK frequency */ -#define FT8_TOUCH_RZTHRESH (1200L) /* touch-sensitivity */ -#define FT8_HAS_CRYSTAL 1 /* use external crystal or internal oscillator? */ -#endif - -/* VM800B43A: FT800 480x272 4.3" FTDI */ -#ifdef FT8_VM800B43A -#define FT8_VSYNC0 (0L) -#define FT8_VSYNC1 (10L) -#define FT8_VOFFSET (12L) -#define FT8_VCYCLE (292L) -#define FT8_VSIZE (272L) -#define FT8_HSYNC0 (0L) -#define FT8_HSYNC1 (41L) -#define FT8_HOFFSET (43L) -#define FT8_HCYCLE (548L) -#define FT8_HSIZE (480L) -#define FT8_PCLKPOL (1L) -#define FT8_SWIZZLE (0L) -#define FT8_PCLK (5L) -#define FT8_TOUCH_RZTHRESH (1200L) -#define FT8_HAS_CRYSTAL 1 -#endif +#include +#include "esp_err.h" +//#include "tft/tftspi.h" +#include "driver/spi_master_utils.h" -/* VM800B50A: FT800 480x272 5.0" FTDI */ -#ifdef FT8_VM800B50A -#define FT8_VSYNC0 (0L) -#define FT8_VSYNC1 (10L) -#define FT8_VOFFSET (12L) -#define FT8_VCYCLE (292L) -#define FT8_VSIZE (272L) -#define FT8_HSYNC0 (0L) -#define FT8_HSYNC1 (41L) -#define FT8_HOFFSET (43L) -#define FT8_HCYCLE (548L) -#define FT8_HSIZE (480L) -#define FT8_PCLKPOL (1L) -#define FT8_SWIZZLE (0L) -#define FT8_PCLK (5L) -#define FT8_TOUCH_RZTHRESH (1200L) -#define FT8_HAS_CRYSTAL 1 -#endif -/* FT810CB-HY50HD: FT810 800x480 5" HAOYU */ -#ifdef FT8_FT810CB_HY50HD -#define FT8_VSYNC0 (0L) -#define FT8_VSYNC1 (2L) -#define FT8_VOFFSET (13L) -#define FT8_VCYCLE (525L) -#define FT8_VSIZE (480L) -#define FT8_HSYNC0 (0L) -#define FT8_HSYNC1 (20L) -#define FT8_HOFFSET (64L) -#define FT8_HCYCLE (952L) -#define FT8_HSIZE (800L) -#define FT8_PCLKPOL (1L) -#define FT8_SWIZZLE (0L) -#define FT8_PCLK (2L) -#define FT8_TOUCH_RZTHRESH (2000L) /* touch-sensitivity */ -#define FT8_HAS_CRYSTAL 1 -#endif +#define MAX_USER_FONTS 15 +//#define EVE_STATIC_LIST 0 +//#define EVE_STATIC_LIST_SIZE 8192 +//#define EVE_FONT_IMG_START 8192 +#define EVE_FONT_METRICS_SIZE 148 +#define EVE_FONT_WIDTHS_SIZE 128 -/* FT811CB-HY50HD: FT811 800x480 5" HAOYU */ -#ifdef FT8_FT811CB_HY50HD -#define FT8_VSYNC0 (0L) -#define FT8_VSYNC1 (2L) -#define FT8_VOFFSET (13L) -#define FT8_VCYCLE (525L) -#define FT8_VSIZE (480L) -#define FT8_HSYNC0 (0L) -#define FT8_HSYNC1 (20L) -#define FT8_HOFFSET (64L) -#define FT8_HCYCLE (952L) -#define FT8_HSIZE (800L) -#define FT8_PCLKPOL (1L) -#define FT8_SWIZZLE (0L) -#define FT8_PCLK (2L) -#define FT8_TOUCH_RZTHRESH (1200L) /* touch-sensitivity */ -#define FT8_HAS_CRYSTAL 1 +#ifdef CONFIG_MICROPY_EVE_FT81X +#define FT8_81X_ENABLE #endif -/* some test setup */ -#ifdef FT8_800x480x -#define FT8_VSYNC0 (0L) /* Tvf Vertical Front Porch */ -#define FT8_VSYNC1 (10L) /* Tvf + Tvp Vertical Front Porch plus Vsync Pulse width */ -#define FT8_VOFFSET (35L) /* Tvf + Tvp + Tvb Number of non-visible lines (in lines) */ -#define FT8_VCYCLE (516L) /* Tv Total number of lines (visible and non-visible) (in lines) */ -#define FT8_VSIZE (480L) /* Tvd Number of visible lines (in lines) - display height */ -#define FT8_HSYNC0 (0L) /* (40L) // Thf Horizontal Front Porch */ -#define FT8_HSYNC1 (88L) /* Thf + Thp Horizontal Front Porch plus Hsync Pulse width */ -#define FT8_HOFFSET (169L) /* Thf + Thp + Thb Length of non-visible part of line (in PCLK cycles) */ -#define FT8_HCYCLE (969L) /* Th Total length of line (visible and non-visible) (in PCLKs) */ -#define FT8_HSIZE (800L) /* Thd Length of visible part of line (in PCLKs) - display width */ -#define FT8_PCLKPOL (1L) /* PCLK polarity (0 = rising edge, 1 = falling edge) */ -#define FT8_SWIZZLE (0L) /* Defines the arrangement of the RGB pins of the FT800 */ -#define FT8_PCLK (2L) /* 60MHz / REG_PCLK = PCLK frequency 30 MHz */ -#define FT8_TOUCH_RZTHRESH (1200L) /* touch-sensitivity */ -#define FT8_HAS_CRYSTAL 1 -#endif +#define EVE_TYPE_NONE 0 +#define EVE_TYPE_FT800 1 +#define EVE_TYPE_FT801 2 +#define EVE_TYPE_FT810 3 +#define EVE_TYPE_FT811 4 +#define EVE_TYPE_FT812 5 +#define EVE_TYPE_FT813 6 +#define EVE_TYPE_MAX 7 -/* G-ET0700G0DM6 800x480 7" Glyn, untested */ -#ifdef FT8_ET07 -#define FT8_VSYNC0 (0L) -#define FT8_VSYNC1 (2L) -#define FT8_VOFFSET (35L) -#define FT8_VCYCLE (525L) -#define FT8_VSIZE (480L) -#define FT8_HSYNC0 (0L) -#define FT8_HSYNC1 (128L) -#define FT8_HOFFSET (203L) -#define FT8_HCYCLE (1056L) -#define FT8_HSIZE (800L) -#define FT8_PCLKPOL (1L) -#define FT8_SWIZZLE (0L) -#define FT8_PCLK (2L) -#define FT8_TOUCH_RZTHRESH (1200L) -#define FT8_HAS_CRYSTAL 0 /* no idea if these come with a crystal populated or not */ -#endif +/* some pre-definded colors */ +#define EVE_BLACK 0 +#define EVE_NAVY 128 +#define EVE_DARKGREEN 32768 +#define EVE_DARKCYAN 32896 +#define EVE_MAROON 8388608 +#define EVE_PURPLE 8388736 +#define EVE_OLIVE 8421376 +#define EVE_LIGHTGREY 12632256 +#define EVE_DARKGREY 8421504 +#define EVE_BLUE 255 +#define EVE_GREEN 65280 +#define EVE_CYAN 65535 +#define EVE_RED 16515072 +#define EVE_MAGENTA 16515327 +#define EVE_YELLOW 16579584 +#define EVE_WHITE 16579836 +#define EVE_ORANGE 16557056 +#define EVE_GREENYELLOW 11336748 +#define EVE_PINK 16564426 + + +typedef struct { + uint16_t vsync0; // Tvf Vertical Front Porch + uint16_t vsync1; // Tvf + Tvp Vertical Front Porch plus Vsync Pulse width + uint16_t voffset; // Tvf + Tvp + Tvb Number of non-visible lines (in lines) + uint16_t vcycle; // Tv Total number of lines (visible and non-visible) (in lines) + uint16_t vsize; // Tvd Number of visible lines (in lines) - display height + uint16_t hsync0; // Thf Horizontal Front Porch + uint16_t hsync1; // Thf + Thp Horizontal Front Porch plus Hsync Pulse width + uint16_t hoffset; // Thf + Thp + Thb Length of non-visible part of line (in PCLK cycles) + uint16_t hcycle; // Th Total length of line (visible and non-visible) (in PCLKs) + uint16_t hsize; // Thd Length of visible part of line (in PCLKs) - display width + uint8_t pclkpol; // PCLK polarity (0 = rising edge, 1 = falling edge) + uint8_t swizzle; // Defines the arrangement of the RGB pins of the FT800 + uint8_t pclk; // 48MHz or 60 MHz / REG_PCLK = PCLK frequency + uint8_t has_crystal; // use external crystal or internal oscillator? + uint16_t touch_thresh; // touch-sensitivity + uint8_t cspread; // helps with noise, when set to 1 fewer signals are changed simultaneously, reset-default: 1 + uint8_t has_GT911; // special treatment required for out-of-spec touch-controller +} ft8_config_t; + +// EVE Display structure +typedef struct { + uint16_t width; // Display width (smaller dimension) + uint16_t height; // Display height (larger dimension) + uint32_t speed; // SPI clock in Hz + uint8_t host; // SPI host (HSPI_HOST or VSPI_HOST) + uint8_t miso; // SPI MISO pin + uint8_t mosi; // SPI MOSI pin + uint8_t sck; // SPI CLOCK pin + uint8_t cs; // Display CS pin + int8_t pd; // GPIO used as PD pin + uint8_t touch; // Touch panel type + ft8_config_t disp_config; // Pointer to display configuration structure +} eve_config_t; + +typedef struct { + uint32_t fifo_buff; //fifo buffer address + int32_t fifo_len; //fifo length + int32_t fifo_wp; //fifo write pointer - maintained by host + int32_t fifo_rp; //fifo read point - maintained by device + FILE *pFile; + int32_t file_remain; + int32_t file_size; + uint8_t *g_scratch; + uint16_t fbuff_size; + uint32_t max_free; + uint32_t min_free; +} FT8_Fifo_t; -/* RVT70AQxxxxxx 800x480 7" Riverdi, various options, FT812/FT813, tested with RVT70UQFNWC0x */ -#ifdef FT8_RVT70AQ -#define FT8_VSYNC0 (0L) /* Tvf Vertical Front Porch */ -#define FT8_VSYNC1 (10L) /* Tvf + Tvp Vertical Front Porch plus Vsync Pulse width */ -#define FT8_VOFFSET (23L) /* Tvf + Tvp + Tvb Number of non-visible lines (in lines) */ -#define FT8_VCYCLE (525L) /* Tv Total number of lines (visible and non-visible) (in lines) */ -#define FT8_VSIZE (480L) /* Tvd Number of visible lines (in lines) - display height */ -#define FT8_HSYNC0 (0L) /* Thf Horizontal Front Porch */ -#define FT8_HSYNC1 (10L) /* Thf + Thp Horizontal Front Porch plus Hsync Pulse width */ -#define FT8_HOFFSET (46L) /* Thf + Thp + Thb Length of non-visible part of line (in PCLK cycles) */ -#define FT8_HCYCLE (1056L) /* Th Total length of line (visible and non-visible) (in PCLKs) */ -#define FT8_HSIZE (800L) /* Thd Length of visible part of line (in PCLKs) - display width */ -#define FT8_PCLKPOL (1L) /* PCLK polarity (0 = rising edge, 1 = falling edge) */ -#define FT8_SWIZZLE (0L) /* Defines the arrangement of the RGB pins of the FT800 */ -#define FT8_PCLK (2L) /* 60MHz / REG_PCLK = PCLK frequency 30 MHz */ -#define FT8_TOUCH_RZTHRESH (1800L) /* touch-sensitivity */ -#define FT8_HAS_CRYSTAL 0 -#endif // ---------------------------------------------------------------------------------- +extern uint16_t eve_chip_id; +extern exspi_device_handle_t *eve_spi; extern uint16_t eve_cmdOffset; +extern uint32_t ft8_ramg_ptr; +extern FT8_Fifo_t ft8_stFifo; +extern uint8_t ft8_full_cs; +extern uint8_t eve_spibus_is_init; +extern uint8_t spi_is_init; + + +int FT8_Fifo_init(FILE *fhndl); +void FT8_Fifo_deinit(); void FT8_cmdWrite(uint8_t data); uint8_t FT8_memRead8(uint32_t ftAddress); uint16_t FT8_memRead16(uint32_t ftAddress); uint32_t FT8_memRead32(uint32_t ftAddress); +void FT8_memRead_buffer(uint32_t ftAddress, uint8_t *data, uint16_t len); + void FT8_memWrite8(uint32_t ftAddress, uint8_t ftData8); void FT8_memWrite16(uint32_t ftAddress, uint16_t ftData16); void FT8_memWrite32(uint32_t ftAddress, uint32_t ftData32); -void FT8_memWrite_flash_buffer(uint32_t ftAddress, const uint8_t *data, uint16_t len); +int FT8_memWrite_flash_buffer(uint32_t ftAddress, const uint8_t *data, uint16_t len, bool check_padding); + +void FT8_send_long(uint32_t val1, uint32_t val2, uint32_t val3, uint8_t len); + uint8_t FT8_busy(void); void FT8_cmd_dl(uint32_t command); +void FT8_inc_cmdoffset(uint16_t increment); void FT8_get_cmdoffset(void); uint32_t FT8_get_touch_tag(void); void FT8_cmd_start(void); -void FT8_cmd_execute(void); +bool FT8_cmd_execute(int tmo_ms); void FT8_start_cmd_burst(void); void FT8_end_cmd_burst(void); +void FT8_start_cmd(uint32_t command); + /* commands to draw graphics objects: */ void FT8_cmd_text(int16_t x0, int16_t y0, int16_t font, uint16_t options, const char* text); @@ -257,51 +194,52 @@ void FT8_cmd_dial(int16_t x0, int16_t y0, int16_t r0, uint16_t options, uint16_t void FT8_cmd_toggle(int16_t x0, int16_t y0, int16_t w0, int16_t font, uint16_t options, uint16_t state, const char* text); void FT8_cmd_number(int16_t x0, int16_t y0, int16_t font, uint16_t options, int32_t number); -#ifdef FT8_81X_ENABLE void FT8_cmd_setbase(uint32_t base); void FT8_cmd_setbitmap(uint32_t addr, uint16_t fmt, uint16_t width, uint16_t height); -#endif +void FT8_cmd_bitmapXY(uint16_t x, uint16_t y); /* commands to operate on memory: */ void FT8_cmd_memzero(uint32_t ptr, uint32_t num); void FT8_cmd_memset(uint32_t ptr, uint8_t value, uint32_t num); -/*(void FT8_cmd_memwrite(uint32_t dest, uint32_t num, const uint8_t *data); */ +void FT8_cmd_memwrite(uint32_t dest, const uint8_t *data, uint32_t num); void FT8_cmd_memcpy(uint32_t dest, uint32_t src, uint32_t num); void FT8_cmd_append(uint32_t ptr, uint32_t num); /* commands for loading image data into FT8xx memory: */ void FT8_cmd_inflate(uint32_t ptr, const uint8_t *data, uint16_t len); -void FT8_cmd_loadimage(uint32_t ptr, uint32_t options, const uint8_t *data, uint16_t len); -#ifdef FT8_81X_ENABLE +int FT8_cmd_loadimage(uint32_t ptr, uint32_t options, FILE *fhndl, uint32_t len, uint8_t type); void FT8_cmd_mediafifo(uint32_t ptr, uint32_t size); -#endif + +int FT8_sendDataViaMediafifo(FILE *pFile, uint32_t ptr, uint32_t options, uint8_t type); +int FT8_Fifo_service(); +void FT8_cmd_videoframe(uint32_t addr); /* commands for setting the bitmap transform matrix: */ void FT8_cmd_translate(int32_t tx, int32_t ty); void FT8_cmd_scale(int32_t sx, int32_t sy); void FT8_cmd_rotate(int32_t ang); void FT8_cmd_getmatrix(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f); +void FT8_cmd_setmatrix(); /* other commands: */ void FT8_cmd_calibrate(void); void FT8_cmd_interrupt(uint32_t ms); void FT8_cmd_setfont(uint32_t font, uint32_t ptr); -#ifdef FT8_81X_ENABLE + void FT8_cmd_romfont(uint32_t font, uint32_t romslot); void FT8_cmd_setfont2(uint32_t font, uint32_t ptr, uint32_t firstchar); void FT8_cmd_setrotate(uint32_t r); void FT8_cmd_setscratch(uint32_t handle); -#endif + void FT8_cmd_sketch(int16_t x0, int16_t y0, uint16_t w0, uint16_t h0, uint32_t ptr, uint16_t format); void FT8_cmd_snapshot(uint32_t ptr); -#ifdef FT8_81X_ENABLE void FT8_cmd_snapshot2(uint32_t fmt, uint32_t ptr, int16_t x0, int16_t y0, int16_t w0, int16_t h0); -#endif void FT8_cmd_spinner(int16_t x0, int16_t y0, uint16_t style, uint16_t scale); void FT8_cmd_track(int16_t x0, int16_t y0, int16_t w0, int16_t h0, int16_t tag); +void FT8_CP_reset(); /* commands that return values by writing to the command-fifo */ uint16_t FT8_cmd_memcrc(uint32_t ptr, uint32_t num); @@ -314,9 +252,12 @@ uint16_t FT8_cmd_getprops(uint32_t ptr); void FT8_cmd_point(int16_t x0, int16_t y0, uint16_t size); void FT8_cmd_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t w0); void FT8_cmd_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t corner); +void FT8_cmd_strip(uint16_t *data, uint16_t length, uint8_t type, uint16_t width); /* startup FT8xx: */ -uint8_t FT8_init(void); +esp_err_t FT8_init(eve_config_t *dconfig, exspi_device_handle_t *disp_spi_dev); + +#endif //CONFIG_MICROPY_USE_EVE #endif // FT8_COMMANDS_H_ diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/ftp.c b/MicroPython_BUILD/components/micropython/esp32/libs/ftp.c index e5050fc1..2fa3654f 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/ftp.c +++ b/MicroPython_BUILD/components/micropython/esp32/libs/ftp.c @@ -68,6 +68,8 @@ #include "freertos/task.h" #include "freertos/semphr.h" +#include "modnetwork.h" + TaskHandle_t FtpTaskHandle = NULL; QueueHandle_t ftp_mutex = NULL; uint32_t ftp_stack_size; @@ -482,26 +484,20 @@ static ftp_result_t ftp_wait_for_connection (int32_t l_sd, int32_t *n_sd, uint32 } if (ip_addr) { - tcpip_adapter_ip_info_t ip_info; - wifi_mode_t wifi_mode; - esp_wifi_get_mode(&wifi_mode); - if (wifi_mode != WIFI_MODE_APSTA) { - // easy way - tcpip_adapter_if_t if_type; - if (wifi_mode == WIFI_MODE_AP) { - if_type = TCPIP_ADAPTER_IF_AP; - } else { - if_type = TCPIP_ADAPTER_IF_STA; - } - tcpip_adapter_get_ip_info(if_type, &ip_info); - } else { - // see on which subnet is the client ip address - tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip_info); - if ((ip_info.ip.addr & ip_info.netmask.addr) != (ip_info.netmask.addr & sClientAddress.sin_addr.s_addr)) { - tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info); + // check on which network interface the client was connected + tcpip_adapter_ip_info_t ip_info = {0}; + int n_if = network_get_active_interfaces(); + + if (n_if > 0) { + for (int i=0; i 0 +static char telnet_login_msg[TELNET_LOGIN_MSG_LEN_MAX+1]; +#else +const char* telnet_login_msg = "\r\nLogin succeeded!\r\nType \"help()\" for more information.\r\n"; +#endif +char *telnet_login_success = telnet_login_msg; + static const uint8_t telnet_options_user[] = { IAC, WONT, ECHO, IAC, WONT, SUPPRESS_GO_AHEAD, IAC, WILL, LINEMODE }; static const uint8_t telnet_options_pass[] = { IAC, WILL, ECHO, IAC, WONT, SUPPRESS_GO_AHEAD, IAC, WILL, LINEMODE }; static const uint8_t telnet_options_repl[] = { IAC, WILL, ECHO, IAC, WILL, SUPPRESS_GO_AHEAD, IAC, WONT, LINEMODE }; diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/telnet.h b/MicroPython_BUILD/components/micropython/esp32/libs/telnet.h index d4f64b98..e684e217 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/telnet.h +++ b/MicroPython_BUILD/components/micropython/esp32/libs/telnet.h @@ -41,6 +41,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" +#define TELNET_LOGIN_MSG_LEN_MAX 128 // set this to 0 to use static login msg #define TELNET_USER_PASS_LEN_MAX 32 #define TELNET_DEF_USER "micro" #define TELNET_DEF_PASS "python" @@ -58,6 +59,7 @@ typedef enum { extern char telnet_user[TELNET_USER_PASS_LEN_MAX + 1]; extern char telnet_pass[TELNET_USER_PASS_LEN_MAX + 1]; +char *telnet_login_success; extern uint32_t telnet_stack_size; extern QueueHandle_t telnet_mutex; extern int telnet_timeout; diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/tft/DefaultFont.c b/MicroPython_BUILD/components/micropython/esp32/libs/tft/DefaultFont.c index 3e3c2a07..5ec86aee 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/tft/DefaultFont.c +++ b/MicroPython_BUILD/components/micropython/esp32/libs/tft/DefaultFont.c @@ -38,6 +38,10 @@ // Memory usage : 1158 bytes // # characters : 95 +#include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT + const unsigned char tft_DefaultFont[] = { 0x00, 0x0B, 0x86, 0x04, @@ -331,3 +335,5 @@ const unsigned char tft_DefaultFont[] = // Terminator 0xFF }; + +#endif diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/tft/DejaVuSans18.c b/MicroPython_BUILD/components/micropython/esp32/libs/tft/DejaVuSans18.c index b9e6ba94..922c3ff6 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/tft/DejaVuSans18.c +++ b/MicroPython_BUILD/components/micropython/esp32/libs/tft/DejaVuSans18.c @@ -27,6 +27,10 @@ // Memory usage : 1828 bytes // # characters : 95 +#include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT + const unsigned char tft_Dejavu18[] = { 0x00, 0x12, 0x00, 0x00, @@ -320,3 +324,5 @@ const unsigned char tft_Dejavu18[] = // Terminator 0xFF }; + +#endif diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/tft/DejaVuSans24.c b/MicroPython_BUILD/components/micropython/esp32/libs/tft/DejaVuSans24.c index aa7e2f1a..69893491 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/tft/DejaVuSans24.c +++ b/MicroPython_BUILD/components/micropython/esp32/libs/tft/DejaVuSans24.c @@ -36,6 +36,10 @@ // Memory usage : 2724 bytes // # characters : 95 +#include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT + const unsigned char tft_Dejavu24[] = { 0x00, 0x17, 0x00, 0x00, @@ -329,3 +333,5 @@ const unsigned char tft_Dejavu24[] = // Terminator 0xFF }; + +#endif diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/tft/SmallFont.c b/MicroPython_BUILD/components/micropython/esp32/libs/tft/SmallFont.c index b7c8943b..d0ac220d 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/tft/SmallFont.c +++ b/MicroPython_BUILD/components/micropython/esp32/libs/tft/SmallFont.c @@ -3,6 +3,9 @@ // Font size : 8x12 pixels // Memory usage : 1144 bytes +#include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT const unsigned char tft_SmallFont[1144] = { @@ -108,3 +111,5 @@ const unsigned char tft_SmallFont[1144] = 0x00,0x60,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0x60,0x00, // } 0x40,0xA4,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~ }; + +#endif diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/tft/comic24.c b/MicroPython_BUILD/components/micropython/esp32/libs/tft/comic24.c index f897e31f..fe9d312c 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/tft/comic24.c +++ b/MicroPython_BUILD/components/micropython/esp32/libs/tft/comic24.c @@ -21,6 +21,10 @@ // First Character (Reserved. 0x00) // Number Of Characters (Reserved. 0x00) +#include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT + const unsigned char tft_Comic24[] = { 0x00, 0x19, 0x00, 0x00, @@ -329,3 +333,5 @@ const unsigned char tft_Comic24[] = // Terminator 0xFF }; + +#endif diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/tft/def_small.c b/MicroPython_BUILD/components/micropython/esp32/libs/tft/def_small.c index 725a20a5..b5e879d9 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/tft/def_small.c +++ b/MicroPython_BUILD/components/micropython/esp32/libs/tft/def_small.c @@ -22,6 +22,10 @@ // Number Of Characters (Reserved. 0x00) +#include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT + const unsigned char tft_def_small[] = { 0x00, 0x08, 0x00, 0x00, @@ -330,3 +334,5 @@ const unsigned char tft_def_small[] = // Terminator 0xFF }; + +#endif diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/tft/minya24.c b/MicroPython_BUILD/components/micropython/esp32/libs/tft/minya24.c index 223bd668..c3080ab5 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/tft/minya24.c +++ b/MicroPython_BUILD/components/micropython/esp32/libs/tft/minya24.c @@ -21,6 +21,10 @@ // First Character (Reserved. 0x00) // Number Of Characters (Reserved. 0x00) +#include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT + const unsigned char tft_minya24[] = { 0x00, 0x15, 0x00, 0x00, @@ -329,3 +333,5 @@ const unsigned char tft_minya24[] = // Terminator 0xFF }; + +#endif diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/tft/stmpe610.h b/MicroPython_BUILD/components/micropython/esp32/libs/tft/stmpe610.h index 50f3e19c..d4cae2db 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/tft/stmpe610.h +++ b/MicroPython_BUILD/components/micropython/esp32/libs/tft/stmpe610.h @@ -30,6 +30,10 @@ #ifndef _STMPE610_H #define _STMPE610_H +#include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT + #include #define STMPE610_SPI_MODE 0 @@ -145,4 +149,6 @@ #define STMPE610_REG_INT_CTRL_ENABLE 0x01 #define STMPE610_REG_INT_CTRL_DISABLE 0x00 -#endif /* _STMPE610_H */ +#endif // CONFIG_MICROPY_USE_TFT + +#endif // _STMPE610_H diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/tft/tft.c b/MicroPython_BUILD/components/micropython/esp32/libs/tft/tft.c index 1f7eb91c..7b811ddd 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/tft/tft.c +++ b/MicroPython_BUILD/components/micropython/esp32/libs/tft/tft.c @@ -32,6 +32,10 @@ * Library supporting SPI TFT displays based on ILI9341, ILI9488 & ST7789V controllers */ +#include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT + #include #include #include @@ -46,6 +50,10 @@ #include "esp_heap_caps.h" #include "tftspi.h" +#if CONFIG_MICROPY_USE_EVE +#include "eve/FT8.h" +#endif + #include "py/mpprint.h" #include "extmod/vfs_native.h" @@ -96,6 +104,8 @@ const color_t TFT_PINK = { 252, 192, 202 }; // ============================================================== // ==== Set default values of global variables ================== + +uint8_t tft_active_mode = TFT_MODE_TFT; uint8_t orientation = LANDSCAPE;// screen orientation uint16_t font_rotate = 0; // font rotation uint8_t font_transparent = 0; @@ -131,6 +141,15 @@ Font cfont = { uint8_t font_buffered_char = 1; uint8_t font_line_space = 0; + +// ------------------------ +// ePaper display variables +// ------------------------ +uint8_t *drawBuff = NULL; +uint8_t *gs_drawBuff = NULL; +uint8_t _gs = 0; +uint16_t gs_used_shades = 0; + // ============================================================== @@ -172,18 +191,248 @@ int TFT_compare_colors(color_t c1, color_t c2) return 0; } +// ==== EPD low level functions ==================================================== + +//-------------------------------------------------- +static void EPD_drawPixel(int x, int y, uint8_t val) +{ + if (orientation == LANDSCAPE_FLIP) { + x = _width - x - 1; + y = _height - y - 1; + } + if (_gs) { + val &= 0x0F; + //if (gs_drawBuff[(y * _width) + x] != val) { + gs_drawBuff[(y * _width) + x] = val; + gs_used_shades |= (1<> 3)) + (y>>3)]; + uint8_t new_val = buf_val; + if (val) new_val &= (0x80 >> (y % 8)) ^ 0xFF; + else new_val |= (0x80 >> (y % 8)); + //if (new_val != buf_val) drawBuff[(x * (_height>>3)) + (y>>3)] = new_val; + drawBuff[(x * (_height>>3)) + (y>>3)] = new_val; + } +} + +//------------------------------------------------------------------------- +static void EPD_pushColorRep(int x1, int y1, int x2, int y2, uint8_t color) +{ + if (_gs == 0) color &= 0x01; + else color &= 0x0F; + for (int y=y1; y<=y2; y++) { + for (int x = x1; x<=x2; x++){ + EPD_drawPixel(x, y, color); + } + } +} + +// ^^^^ EPD low level functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +#if CONFIG_MICROPY_USE_EVE +// ==== EVE low level functions ==================================================== + +tft_eve_obj_t *eve_tft_obj = NULL; + + +//-------------------------------------- +static uint16_t eve_color(color_t color) +{ + uint16_t _color; + if (eve_tft_obj->type == FT8_RGB565) { + _color = (uint16_t)(color.r & 0xF8) << 8; + _color |= (uint16_t)(color.g & 0xFC) << 3; + _color |= (uint16_t)(color.b & 0xF8) >> 3; + } + else { + _color = (uint16_t)(color.r & 0xE0); + _color |= (uint16_t)(color.g & 0xE0) >> 3; + _color |= (uint16_t)(color.b & 0xC0) >> 6; + } + return _color; +} + +//---------------------------------------------------- +static void EVE_drawPixel(int x, int y, color_t color) +{ + if (eve_tft_obj == NULL) return; + + uint16_t _color = eve_color(color); + // calculate pixel address + uint32_t addr = eve_tft_obj->addr + (y * eve_tft_obj->rowsize) + (x * eve_tft_obj->byte_per_pixel); + if (eve_tft_obj->type == FT8_RGB565) FT8_memWrite16(addr, _color); + else FT8_memWrite8(addr, (uint8_t)_color); +} + +//------------------------------------------------------------------------- +static void EVE_pushColorRep(int x1, int y1, int x2, int y2, color_t color) +{ + if (eve_tft_obj == NULL) return; + + uint16_t _color = eve_color(color); + + int y = y1; + uint16_t xlen = x2 - x1 + 1; + uint8_t buff[xlen * eve_tft_obj->byte_per_pixel]; + uint32_t addr; + + if (xlen > 2) { + // fill buffer with color + if (eve_tft_obj->type == FT8_RGB565) { + for (int i=0; i> 8; // high byte first + buff[i+1] = _color & 0x00FF; + } + } + else { + for (int i=0; iaddr + ((y * eve_tft_obj->width) * eve_tft_obj->byte_per_pixel) + (x1 * eve_tft_obj->byte_per_pixel); + if (eve_tft_obj->type == FT8_RGB565) { + if (xlen == 1) FT8_memWrite16(addr, _color); + else if (xlen == 2) FT8_memWrite32(addr, (uint32_t)((_color << 16) | _color)); + else FT8_memWrite_flash_buffer(addr, (uint8_t *)buff, xlen*2, false); + } + else { + if (xlen == 1) FT8_memWrite8(addr, (uint8_t)_color); + else if (xlen == 2) FT8_memWrite16(addr, (uint16_t)((_color << 16) | _color)); + else FT8_memWrite_flash_buffer(addr, (uint8_t *)buff, xlen, false); + } + y++; + if (y >= _height) break; + } + + spi_device_deselect(eve_spi); + ft8_full_cs = 1; +} + +//------------------------------------------------------------------------------------ +static void EVE_send_data(int x1, int y1, int x2, int y2, uint32_t len, color_t *cbuf) +{ + if (eve_tft_obj == NULL) return; + + int y = y1; + int buf_pos = 0; + uint16_t xlen = x2 - x1 + 1; + uint8_t buff[xlen * eve_tft_obj->byte_per_pixel]; + uint32_t addr; + + spi_device_select(eve_spi, 0); + ft8_full_cs = 0; + while (y <= y2) { + // fill the row buffer + if (eve_tft_obj->type == FT8_RGB565) { + for (int i=0; i> 8; + buff[i+1] = eve_color(cbuf[buf_pos]) & 0x00FF; + buf_pos++; + } + } + else { + for (int i=0; iaddr + ((y * eve_tft_obj->width) * eve_tft_obj->byte_per_pixel) + (x1 * eve_tft_obj->byte_per_pixel); + FT8_memWrite_flash_buffer(addr, (uint8_t *)buff, xlen*eve_tft_obj->byte_per_pixel, false); + y++; + if (y >= _height) break; + } + spi_device_deselect(eve_spi); + ft8_full_cs = 1; +} + +// ^^^^ EVE low level functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#endif + +//=========================================================================================== + +//------------------------------------ +static esp_err_t TFT_EPD_disp_select() +{ + #if CONFIG_MICROPY_USE_EVE + if (tft_active_mode == TFT_MODE_EVE) { + spi_device_select(eve_spi, 0); + ft8_full_cs = 0; + return ESP_OK; + } + #endif + return disp_select(); +} + +//-------------------------------------- +static esp_err_t TFT_EPD_disp_deselect() +{ + #if CONFIG_MICROPY_USE_EVE + if (tft_active_mode == TFT_MODE_EVE) { + spi_device_deselect(eve_spi); + ft8_full_cs = 1; + return ESP_OK; + } + #endif + return disp_deselect(); +} + +//----------------------------------------------------------------------------------------------------- +static void TFT_EPD_send_data(int x1, int y1, int x2, int y2, uint32_t len, color_t *buf, uint8_t wait) +{ + #if CONFIG_MICROPY_USE_EVE + if (tft_active_mode == TFT_MODE_EVE) { + EVE_send_data(x1, y1, x2, y2, len, buf); + } + else send_data(x1, y1, x2, y2, len, buf, wait); + #else + send_data(x1, y1, x2, y2, len, buf, wait); + #endif +} + // draw color pixel on screen -//------------------------------------------------------------------------ -static void _drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel) { +//---------------------------------------------------------------------- +static void TFT_EPD_drawPixe(int16_t x, int16_t y, color_t color, uint8_t sel) +{ + if ((x < dispWin.x1) || (y < dispWin.y1) || (x > dispWin.x2) || (y > dispWin.y2)) return; + + if (tft_active_mode == TFT_MODE_EPD) EPD_drawPixel(x, y, color.b); + #if CONFIG_MICROPY_USE_EVE + else if (tft_active_mode == TFT_MODE_EVE) EVE_drawPixel(x, y, color); + #endif + else if (tft_active_mode == TFT_MODE_TFT) drawPixel(x, y, color, sel); +} - if ((x < dispWin.x1) || (y < dispWin.y1) || (x > dispWin.x2) || (y > dispWin.y2)) return; - drawPixel(x, y, color, sel); +//------------------------------------------------------------------------------------------- +static void TFT_EPD_pushColorRep(int x1, int y1, int x2, int y2, color_t color, uint32_t len) +{ + if (len == 0) return; + + if (tft_active_mode == TFT_MODE_EPD) EPD_pushColorRep(x1, y1, x2, y2, color.b); + #if CONFIG_MICROPY_USE_EVE + else if (tft_active_mode == TFT_MODE_EVE) EVE_pushColorRep(x1, y1, x2, y2, color); + #endif + else if (tft_active_mode == TFT_MODE_TFT) TFT_pushColorRep(x1, y1, x2, y2, color, len); } +//=========================================================================================== + + //==================================================================== void TFT_drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel) { - _drawPixel(x+dispWin.x1, y+dispWin.y1, color, sel); + TFT_EPD_drawPixe(x+dispWin.x1, y+dispWin.y1, color, sel); } //=========================================== @@ -205,7 +454,7 @@ static void _drawFastVLine(int16_t x, int16_t y, int16_t h, color_t color) { if (h < 0) h = 0; if ((y + h) > (dispWin.y2+1)) h = dispWin.y2 - y + 1; if (h == 0) h = 1; - TFT_pushColorRep(x, y, x, y+h-1, color, (uint32_t)h); + TFT_EPD_pushColorRep(x, y, x, y+h-1, color, (uint32_t)h); } //-------------------------------------------------------------------------- @@ -220,7 +469,7 @@ static void _drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color) { if ((x + w) > (dispWin.x2+1)) w = dispWin.x2 - x + 1; if (w == 0) w = 1; - TFT_pushColorRep(x, y, x+w-1, y, color, (uint32_t)w); + TFT_EPD_pushColorRep(x, y, x+w-1, y, color, (uint32_t)w); } //====================================================================== @@ -233,8 +482,8 @@ void TFT_drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color) { _drawFastHLine(x+dispWin.x1, y+dispWin.y1, w, color); } -// Bresenham's algorithm - thx wikipedia - speed enhanced by Bodmer this uses -// the eficient FastH/V Line draw routine for segments of 2 pixels or more +// Bresenham's algorithm, speed enhanced by Bodmer this uses +// the efficient FastH/V Line draw routine for segments of 2 pixels or more //---------------------------------------------------------------------------------- static void _drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t color) { @@ -272,7 +521,7 @@ static void _drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t co err -= dy; if (err < 0) { err += dx; - if (dlen == 1) _drawPixel(y0, xs, color, 1); + if (dlen == 1) TFT_EPD_drawPixe(y0, xs, color, 1); else _drawFastVLine(y0, xs, dlen, color); dlen = 0; y0 += ystep; xs = x0 + 1; } @@ -286,7 +535,7 @@ static void _drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t co err -= dy; if (err < 0) { err += dx; - if (dlen == 1) _drawPixel(xs, y0, color, 1); + if (dlen == 1) TFT_EPD_drawPixe(xs, y0, color, 1); else _drawFastHLine(xs, y0, dlen, color); dlen = 0; y0 += ystep; xs = x0 + 1; } @@ -322,7 +571,7 @@ static void _fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color) if ((y + h) > (dispWin.y2+1)) h = dispWin.y2 - y + 1; if (w == 0) w = 1; if (h == 0) h = 1; - TFT_pushColorRep(x, y, x+w-1, y+h-1, color, (uint32_t)(h*w)); + TFT_EPD_pushColorRep(x, y, x+w-1, y+h-1, color, (uint32_t)(h*w)); } //============================================================================ @@ -332,12 +581,12 @@ void TFT_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color) { //================================== void TFT_fillScreen(color_t color) { - TFT_pushColorRep(0, 0, _width-1, _height-1, color, (uint32_t)(_height*_width)); + TFT_EPD_pushColorRep(0, 0, _width-1, _height-1, color, (uint32_t)(_height*_width)); } //================================== void TFT_fillWindow(color_t color) { - TFT_pushColorRep(dispWin.x1, dispWin.y1, dispWin.x2, dispWin.y2, + TFT_EPD_pushColorRep(dispWin.x1, dispWin.y1, dispWin.x2, dispWin.y2, color, (uint32_t)((dispWin.x2-dispWin.x1+1) * (dispWin.y2-dispWin.y1+1))); } @@ -368,7 +617,7 @@ static void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornerna int16_t x = 0; int16_t y = r; - disp_select(); + TFT_EPD_disp_select(); while (x < y) { if (f >= 0) { y--; @@ -379,23 +628,23 @@ static void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornerna ddF_x += 2; f += ddF_x; if (cornername & 0x4) { - _drawPixel(x0 + x, y0 + y, color, 0); - _drawPixel(x0 + y, y0 + x, color, 0); + TFT_EPD_drawPixe(x0 + x, y0 + y, color, 0); + TFT_EPD_drawPixe(x0 + y, y0 + x, color, 0); } if (cornername & 0x2) { - _drawPixel(x0 + x, y0 - y, color, 0); - _drawPixel(x0 + y, y0 - x, color, 0); + TFT_EPD_drawPixe(x0 + x, y0 - y, color, 0); + TFT_EPD_drawPixe(x0 + y, y0 - x, color, 0); } if (cornername & 0x8) { - _drawPixel(x0 - y, y0 + x, color, 0); - _drawPixel(x0 - x, y0 + y, color, 0); + TFT_EPD_drawPixe(x0 - y, y0 + x, color, 0); + TFT_EPD_drawPixe(x0 - x, y0 + y, color, 0); } if (cornername & 0x1) { - _drawPixel(x0 - y, y0 - x, color, 0); - _drawPixel(x0 - x, y0 - y, color, 0); + TFT_EPD_drawPixe(x0 - y, y0 - x, color, 0); + TFT_EPD_drawPixe(x0 - x, y0 - y, color, 0); } } - disp_deselect(); + TFT_EPD_disp_deselect(); } // Used to do circles and roundrects @@ -620,11 +869,11 @@ void TFT_drawCircle(int16_t x, int16_t y, int radius, color_t color) { int x1 = 0; int y1 = radius; - disp_select(); - _drawPixel(x, y + radius, color, 0); - _drawPixel(x, y - radius, color, 0); - _drawPixel(x + radius, y, color, 0); - _drawPixel(x - radius, y, color, 0); + TFT_EPD_disp_select(); + TFT_EPD_drawPixe(x, y + radius, color, 0); + TFT_EPD_drawPixe(x, y - radius, color, 0); + TFT_EPD_drawPixe(x + radius, y, color, 0); + TFT_EPD_drawPixe(x - radius, y, color, 0); while(x1 < y1) { if (f >= 0) { y1--; @@ -634,16 +883,16 @@ void TFT_drawCircle(int16_t x, int16_t y, int radius, color_t color) { x1++; ddF_x += 2; f += ddF_x; - _drawPixel(x + x1, y + y1, color, 0); - _drawPixel(x - x1, y + y1, color, 0); - _drawPixel(x + x1, y - y1, color, 0); - _drawPixel(x - x1, y - y1, color, 0); - _drawPixel(x + y1, y + x1, color, 0); - _drawPixel(x - y1, y + x1, color, 0); - _drawPixel(x + y1, y - x1, color, 0); - _drawPixel(x - y1, y - x1, color, 0); + TFT_EPD_drawPixe(x + x1, y + y1, color, 0); + TFT_EPD_drawPixe(x - x1, y + y1, color, 0); + TFT_EPD_drawPixe(x + x1, y - y1, color, 0); + TFT_EPD_drawPixe(x - x1, y - y1, color, 0); + TFT_EPD_drawPixe(x + y1, y + x1, color, 0); + TFT_EPD_drawPixe(x - y1, y + x1, color, 0); + TFT_EPD_drawPixe(x + y1, y - x1, color, 0); + TFT_EPD_drawPixe(x - y1, y - x1, color, 0); } - disp_deselect(); + TFT_EPD_disp_deselect(); } //==================================================================== @@ -658,16 +907,16 @@ void TFT_fillCircle(int16_t x, int16_t y, int radius, color_t color) { //---------------------------------------------------------------------------------------------------------------- static void _draw_ellipse_section(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, color_t color, uint8_t option) { - disp_select(); + TFT_EPD_disp_select(); // upper right - if ( option & TFT_ELLIPSE_UPPER_RIGHT ) _drawPixel(x0 + x, y0 - y, color, 0); + if ( option & TFT_ELLIPSE_UPPER_RIGHT ) TFT_EPD_drawPixe(x0 + x, y0 - y, color, 0); // upper left - if ( option & TFT_ELLIPSE_UPPER_LEFT ) _drawPixel(x0 - x, y0 - y, color, 0); + if ( option & TFT_ELLIPSE_UPPER_LEFT ) TFT_EPD_drawPixe(x0 - x, y0 - y, color, 0); // lower right - if ( option & TFT_ELLIPSE_LOWER_RIGHT ) _drawPixel(x0 + x, y0 + y, color, 0); + if ( option & TFT_ELLIPSE_LOWER_RIGHT ) TFT_EPD_drawPixe(x0 + x, y0 + y, color, 0); // lower left - if ( option & TFT_ELLIPSE_LOWER_LEFT ) _drawPixel(x0 - x, y0 + y, color, 0); - disp_deselect(); + if ( option & TFT_ELLIPSE_LOWER_LEFT ) TFT_EPD_drawPixe(x0 - x, y0 + y, color, 0); + TFT_EPD_disp_deselect(); } //===================================================================================================== @@ -873,7 +1122,7 @@ static void _fillArcOffsetted(uint16_t cx, uint16_t cy, uint16_t radius, uint16_ int ir2 = (radius - thickness) * (radius - thickness); int or2 = radius * radius; - disp_select(); + TFT_EPD_disp_select(); for (int x = -radius; x <= radius; x++) { for (int y = -radius; y <= radius; y++) { int x2 = x * x; @@ -896,10 +1145,10 @@ static void _fillArcOffsetted(uint16_t cx, uint16_t cy, uint16_t radius, uint16_ (y == 0 && start == 0 && x > 0) ) ) - _drawPixel(cx+x, cy+y, color, 0); + TFT_EPD_drawPixe(cx+x, cy+y, color, 0); } } - disp_deselect(); + TFT_EPD_disp_deselect(); } @@ -1625,11 +1874,11 @@ static int printProportionalChar(int x, int y) { } } // send to display in one transaction - wait_trans_finish(1); - disp_select(); - send_data(x, y, x+char_width, y+cfont.y_size-1, len, color_line, 1); - disp_deselect(); - free(color_line); + if (tft_active_mode != TFT_MODE_EVE) wait_trans_finish(1); + TFT_EPD_disp_select(); + TFT_EPD_send_data(x, y, x+char_width, y+cfont.y_size-1, len, color_line, 1); + TFT_EPD_disp_deselect(); + if (tft_active_mode != TFT_MODE_EVE) free(color_line); return char_width; } @@ -1641,7 +1890,7 @@ static int printProportionalChar(int x, int y) { // draw Glyph uint8_t mask = 0x80; - disp_select(); + TFT_EPD_disp_select(); for (j=0; j < fontChar.height; j++) { for (i=0; i < fontChar.width; i++) { if (((i + (j*fontChar.width)) % 8) == 0) { @@ -1652,12 +1901,12 @@ static int printProportionalChar(int x, int y) { if ((ch & mask) !=0) { cx = (uint16_t)(x+fontChar.xOffset+i); cy = (uint16_t)(y+j+fontChar.adjYOffset); - _drawPixel(cx, cy, _fg, 0); + TFT_EPD_drawPixe(cx, cy, _fg, 0); } mask >>= 1; } } - disp_deselect(); + TFT_EPD_disp_deselect(); return char_width; } @@ -1697,11 +1946,11 @@ static void printChar(uint8_t c, int x, int y) { temp += (fz); } // send to display in one transaction - wait_trans_finish(1); - disp_select(); - send_data(x, y, x+cfont.x_size-1, y+cfont.y_size-1, len, color_line, 1); - disp_deselect(); - free(color_line); + if (tft_active_mode != TFT_MODE_EVE) wait_trans_finish(1); + TFT_EPD_disp_select(); + TFT_EPD_send_data(x, y, x+cfont.x_size-1, y+cfont.y_size-1, len, color_line, 1); + TFT_EPD_disp_deselect(); + if (tft_active_mode != TFT_MODE_EVE) free(color_line); return; } @@ -1709,7 +1958,7 @@ static void printChar(uint8_t c, int x, int y) { if (!font_transparent) _fillRect(x, y, cfont.x_size, cfont.y_size, _bg); - disp_select(); + TFT_EPD_disp_select(); for (j=0; j>= 1; } } temp += (fz); } - disp_deselect(); + TFT_EPD_disp_deselect(); } // print rotated proportional character @@ -1738,7 +1987,7 @@ static int rotatePropChar(int x, int y, int offset) { float sin_radian = sin(radian); uint8_t mask = 0x80; - disp_select(); + TFT_EPD_disp_select(); for (int j=0; j < fontChar.height; j++) { for (int i=0; i < fontChar.width; i++) { if (((i + (j*fontChar.width)) % 8) == 0) { @@ -1749,13 +1998,13 @@ static int rotatePropChar(int x, int y, int offset) { int newX = (int)(x + (((offset + i) * cos_radian) - ((j+fontChar.adjYOffset)*sin_radian))); int newY = (int)(y + (((j+fontChar.adjYOffset) * cos_radian) + ((offset + i) * sin_radian))); - if ((ch & mask) != 0) _drawPixel(newX,newY,_fg, 0); - else if (!font_transparent) _drawPixel(newX,newY,_bg, 0); + if ((ch & mask) != 0) TFT_EPD_drawPixe(newX,newY,_fg, 0); + else if (!font_transparent) TFT_EPD_drawPixe(newX,newY,_bg, 0); mask >>= 1; } } - disp_deselect(); + TFT_EPD_disp_deselect(); return fontChar.xDelta+1; } @@ -1775,7 +2024,7 @@ static void rotateChar(uint8_t c, int x, int y, int pos) { else fz = cfont.x_size/8; temp=((c-cfont.offset)*((fz)*cfont.y_size))+4; - disp_select(); + TFT_EPD_disp_select(); for (j=0; j>= 1; } } temp+=(fz); } - disp_deselect(); + TFT_EPD_disp_deselect(); // calculate x,y for the next char TFT_X = (int)(x + ((pos+1) * cfont.x_size * cos_radian)); TFT_Y = (int)(y + ((pos+1) * cfont.x_size * sin_radian)); @@ -1854,7 +2103,7 @@ void TFT_clearStringRect(int x, int y, char *str) static const uint16_t font_bcd[] = { 0x200, // 0010 0000 0000 // - 0x080, // 0000 1000 0000 // . - 0x06C, // 0100 0110 1100 // /, degree + 0x06C, // 0100 0110 1100 // / (degree sign) 0x05f, // 0000 0101 1111, // 0 0x005, // 0000 0000 0101, // 1 0x076, // 0000 0111 0110, // 2 @@ -1865,7 +2114,8 @@ static const uint16_t font_bcd[] = { 0x045, // 0000 0100 0101, // 7 0x07f, // 0000 0111 1111, // 8 0x07d, // 0000 0111 1101 // 9 - 0x900 // 1001 0000 0000 // : + 0x900, // 1001 0000 0000 // : + 0x000 // 0000 0000 0000 // ; (space) }; //----------------------------------------------------------------------------------------------- @@ -1895,9 +2145,11 @@ static void barHor(int16_t x, int16_t y, int16_t w, int16_t l, color_t color, co //-------------------------------------------------------------------------------------------- static void _draw7seg(int16_t x, int16_t y, int8_t num, int16_t w, int16_t l, color_t color) { /* TODO: clipping */ - if (num < 0x2D || num > 0x3A) return; + uint8_t nnum = num; + if (num == 0x20) nnum = 0x3B; // to clear the space character + if ((nnum < 0x2D) || (nnum > 0x3B)) return; - int16_t c = font_bcd[num-0x2D]; + int16_t c = font_bcd[nnum - 0x2D]; int16_t d = 2*w+l+1; // === Clear unused segments === @@ -1930,6 +2182,7 @@ static void _draw7seg(int16_t x, int16_t y, int8_t num, int16_t w, int16_t l, co if (cfont.offset) _drawRect(x+2*w+1, y+d, l, 2*w+1, _bg); } + if (c == 0) return; // === Draw used segments === if (c & 0x001) barVert(x+d, y+d, w, l, color, cfont.color); // down right if (c & 0x002) barVert(x, y+d, w, l, color, cfont.color); // down left @@ -2089,9 +2342,9 @@ void TFT_print(char *st, int x, int y) { void TFT_setRotation(uint8_t rot) { if (rot > 3) { uint8_t madctl = (rot & 0xF8); // for testing, manually set MADCTL register - if (disp_select() == ESP_OK) { + if (TFT_EPD_disp_select() == ESP_OK) { disp_spi_transfer_cmd_data(TFT_MADCTL, &madctl, 1); - disp_deselect(); + TFT_EPD_disp_deselect(); } } else { @@ -2381,30 +2634,51 @@ static UINT tjd_output ( if ((len > 0) && (len <= JPG_IMAGE_LINE_BUF_SIZE)) { - uint8_t *dest = (uint8_t *)(dev->linbuf[dev->linbuf_idx]); - - for (y = top; y <= bottom; y++) { - for (x = left; x <= right; x++) { - // Clip to display area - if ((x >= dleft) && (y >= dtop) && (x <= dright) && (y <= dbottom)) { - *dest++ = (*src++) & 0xFC; - *dest++ = (*src++) & 0xFC; - *dest++ = (*src++) & 0xFC; - } - else src += 3; // skip - } - } - if (image_trans) { - wait_trans_finish(1); - send_data(dleft, dtop, dright, dbottom, len, dev->linbuf[dev->linbuf_idx], 0); - } - else { - disp_select(); - send_data(dleft, dtop, dright, dbottom, len, dev->linbuf[dev->linbuf_idx], 0); - wait_trans_finish(1); - disp_deselect(); - } - dev->linbuf_idx = ((dev->linbuf_idx + 1) & 1); + if (tft_active_mode == TFT_MODE_EPD) { + uint8_t pix; + for (y = top; y <= bottom; y++) { + for (x = left; x <= right; x++) { + // Clip to display area + if ((x >= dleft) && (y >= dtop) && (x <= dright) && (y <= dbottom)) { + // Directly convert color to 4-bit gray scale + pix = 0; + pix |= ((*src++) >> 4) & 0x08; + pix |= ((*src++) >> 5) & 0x06; + pix |= ((*src++) >> 7); + pix ^= 0x0F; + gs_drawBuff[(y * _width) + x] = pix; + gs_used_shades |= (1 << pix); + } + else src += 3; // skip + } + } + } + else { + uint8_t *dest = (uint8_t *)(dev->linbuf[dev->linbuf_idx]); + + for (y = top; y <= bottom; y++) { + for (x = left; x <= right; x++) { + // Clip to display area + if ((x >= dleft) && (y >= dtop) && (x <= dright) && (y <= dbottom)) { + *dest++ = (*src++) & 0xFC; + *dest++ = (*src++) & 0xFC; + *dest++ = (*src++) & 0xFC; + } + else src += 3; // skip + } + } + if (image_trans) { + wait_trans_finish(1); + send_data(dleft, dtop, dright, dbottom, len, dev->linbuf[dev->linbuf_idx], 0); + } + else { + disp_select(); + send_data(dleft, dtop, dright, dbottom, len, dev->linbuf[dev->linbuf_idx], 0); + wait_trans_finish(1); + disp_deselect(); + } + dev->linbuf_idx = ((dev->linbuf_idx + 1) & 1); + } } else { if (image_trans) wait_trans_finish(1); @@ -2457,7 +2731,7 @@ void TFT_jpg_image(int x, int y, uint8_t scale, char *fname, uint8_t *buf, int s } // Check if the image file is on sdcard - image_trans = file_noton_spi_sdcard(fname); + image_trans = file_noton_spi_sdcard(fname) & (tft_active_mode != TFT_MODE_EPD); if (scale > 3) scale = 3; @@ -2480,19 +2754,21 @@ void TFT_jpg_image(int x, int y, uint8_t scale, char *fname, uint8_t *buf, int s dev.x = x; dev.y = y; - dev.linbuf[0] = malloc(JPG_IMAGE_LINE_BUF_SIZE*3); - if (dev.linbuf[0] == NULL) { - if (image_debug) mp_printf(&mp_plat_print, "Error allocating line buffer #0\r\n"); - goto exit; - } - dev.linbuf[1] = malloc(JPG_IMAGE_LINE_BUF_SIZE*3); - if (dev.linbuf[1] == NULL) { - if (image_debug) mp_printf(&mp_plat_print, "Error allocating line buffer #1\r\n"); - goto exit; + if (tft_active_mode != TFT_MODE_EPD) { + dev.linbuf[0] = malloc(JPG_IMAGE_LINE_BUF_SIZE*3); + if (dev.linbuf[0] == NULL) { + if (image_debug) mp_printf(&mp_plat_print, "Error allocating line buffer #0\r\n"); + goto exit; + } + dev.linbuf[1] = malloc(JPG_IMAGE_LINE_BUF_SIZE*3); + if (dev.linbuf[1] == NULL) { + if (image_debug) mp_printf(&mp_plat_print, "Error allocating line buffer #1\r\n"); + goto exit; + } } // Start to decode the JPEG file - if (image_trans) disp_select(); + if (image_trans) TFT_EPD_disp_select(); rc = jd_decomp(&jd, tjd_output, scale); if (image_trans) { wait_trans_finish(1); @@ -3013,3 +3289,4 @@ int TFT_read_touch(int *x, int* y, uint8_t raw) return 1; } +#endif // CONFIG_MICROPY_USE_TFT diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/tft/tft.h b/MicroPython_BUILD/components/micropython/esp32/libs/tft/tft.h index cb394dfb..45b2aa61 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/tft/tft.h +++ b/MicroPython_BUILD/components/micropython/esp32/libs/tft/tft.h @@ -32,8 +32,18 @@ #ifndef _TFT_H_ #define _TFT_H_ +#include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT + #include #include "tftspi.h" +#include "py/obj.h" + +#define TFT_MODE_TFT 0 +#define TFT_MODE_EPD 1 +#define TFT_MODE_EVE 2 + typedef struct { uint16_t x1; @@ -54,10 +64,24 @@ typedef struct { color_t color; } Font; +typedef struct _tft_eve_obj_t { + mp_obj_base_t base; + uint32_t addr; + uint32_t size; + uint16_t width; + uint16_t height; + uint16_t rowsize; + uint8_t type; + uint8_t byte_per_pixel; + uint8_t prev_tft_mode; + uint8_t loaded; +} tft_eve_obj_t; + //========================================================================================== // ==== Global variables =================================================================== //========================================================================================== + extern uint8_t orientation; // current screen orientation extern uint16_t font_rotate; // current font font_rotate angle (0~395) extern uint8_t font_transparent; // if not 0 draw fonts transparent @@ -78,6 +102,13 @@ extern int TFT_Y; // Y position of the next character after TFT_print() func extern uint32_t tp_calx; // touch screen X calibration constant extern uint32_t tp_caly; // touch screen Y calibration constant + +extern uint8_t tft_active_mode; // used tft driver mode (TFT, EPD or EVE) + +#if CONFIG_MICROPY_USE_EVE +extern tft_eve_obj_t *eve_tft_obj; +#endif + // ========================================================================================= @@ -725,4 +756,6 @@ int compile_font_file(char *fontfile, uint8_t dbg); */ void getFontCharacters(uint8_t *buf); +#endif // CONFIG_MICROPY_USE_TFT + #endif diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/tft/tftspi.c b/MicroPython_BUILD/components/micropython/esp32/libs/tft/tftspi.c index 657d2b93..d0c5157f 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/tft/tftspi.c +++ b/MicroPython_BUILD/components/micropython/esp32/libs/tft/tftspi.c @@ -33,6 +33,10 @@ * */ +#include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT + #include #include "tftspi.h" #include "esp_system.h" @@ -81,7 +85,45 @@ uint8_t spibus_is_init = 0; #define GS_FACT_G 0.4870 #define GS_FACT_B 0.2140 +#ifdef CONFIG_MICROPY_USE_EPD + +static uint16_t xDot = 128; +static uint16_t yDot = 296; + +//static uint8_t GDOControl[] = {0x01, (_width-1)%256, (_width-1)/256, 0x00}; +static uint8_t softstart[4] = {0x0c, 0xd7, 0xd6, 0x9d}; +static uint8_t VCOMVol[2] = {0x2c, 0xa8}; // VCOM 7c +static uint8_t DummyLine[2] = {0x3a, 0x1a}; // 4 dummy line per gate +static uint8_t Gatetime[2] = {0x3b, 0x08}; // 2us per line +static uint8_t RamDataEntryMode[2] = {0x11, 0x01}; // Ram data entry mode +static uint8_t Border[2] = {0x3c, 0x61}; // Border control ( 0x61: white border; 0x51: black border + +/* +There are totally 20 phases for programmable Source waveform of different phase length. +The phase period defined as TP [n] * T FRAME , where TP [n] range from 0 to 15. +TP [n] = 0 indicates phase skipped +Source Voltage Level: VS [n-XY] is constant in each phase +VS [n-XY] indicates the voltage in phase n for transition from GS X to GS Y + 00 – VSS + 01 – VSH + 10 – VSL + 11 – NA +VS [n-XY] and TP[n] are stored in waveform lookup table register [LUT]. + +VS coding: VS[0-11] VS[0-10] VS[0-01] VS[0-00] + +*/ +// --- VS ---- ---- TP ---- +//uint8_t LUTDefault_full[31] = {0x32, 0x02,0x02,0x01,0x11,0x12,0x12,0x22,0x22,0x66,0x69,0x69,0x59,0x58,0x99,0x99,0x88,0x00,0x00,0x00,0x00, 0xF8,0xB4,0x13,0x51,0x35,0x51,0x51,0x19,0x01,0x00}; +uint8_t LUTDefault_full[31] = {0x32, 0x11,0x11,0x10,0x02,0x02,0x22,0x22,0x22,0x22,0x22,0x51,0x51,0x55,0x88,0x08,0x08,0x88,0x88,0x00,0x00, 0x34,0x23,0x12,0x21,0x24,0x28,0x22,0x21,0xA1,0x01}; +uint8_t LUTDefault_part[31] = {0x32, 0x10,0x18,0x18,0x08,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x13,0x14,0x44,0x12,0x00,0x00,0x00,0x00,0x00,0x00}; +uint8_t LUT_gs[31] = {0x32, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; +uint8_t LUTFastest[31] = {0x32, 0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + +uint8_t lvl_buf[16] = {32,70,110,150,185,210,220,225,230,235,240,243,248,251,253,255}; +uint8_t lvl_buf_jpg[16] = {4,8,12,16,22,30,40,60,80,110,140,180,220,240,250,255}; +#endif // ==== Functions ===================== @@ -1243,4 +1285,5 @@ esp_err_t TFT_display_init(display_config_t *dconfig) return ESP_OK; } +#endif // CONFIG_MICROPY_USE_TFT diff --git a/MicroPython_BUILD/components/micropython/esp32/libs/tft/tftspi.h b/MicroPython_BUILD/components/micropython/esp32/libs/tft/tftspi.h index a841999b..960d4df4 100644 --- a/MicroPython_BUILD/components/micropython/esp32/libs/tft/tftspi.h +++ b/MicroPython_BUILD/components/micropython/esp32/libs/tft/tftspi.h @@ -32,11 +32,12 @@ #ifndef _TFTSPI_H_ #define _TFTSPI_H_ -#include "tftspi.h" -//#include "driver/spi_master.h" -//#include "driver/spi_master_internal.h" -#include "driver/spi_master_utils.h" #include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT + + +#include "driver/spi_master_utils.h" #include "stmpe610.h" typedef struct { @@ -104,7 +105,7 @@ typedef struct __attribute__((__packed__)) { #define DEFAULT_TFT_DISPLAY_HEIGHT 320 #define DEFAULT_DISP_TYPE DISP_TYPE_ILI9341 - +/* #define WROVER_V3_CONFIG() {\ .type = DISP_TYPE_ST7789V, \ .host = HSPI_HOST, \ @@ -170,7 +171,7 @@ typedef struct __attribute__((__packed__)) { .bgr = 8, \ .touch = TOUCH_TYPE_NONE \ } - +*/ // ############################################################## // #### Global variables #### @@ -622,4 +623,6 @@ uint32_t stmpe610_getID(); // =============================================================================== +#endif // CONFIG_MICROPY_USE_TFT + #endif diff --git a/MicroPython_BUILD/components/micropython/esp32/machine_dac.c b/MicroPython_BUILD/components/micropython/esp32/machine_dac.c index a5ed8c51..608bd19d 100644 --- a/MicroPython_BUILD/components/micropython/esp32/machine_dac.c +++ b/MicroPython_BUILD/components/micropython/esp32/machine_dac.c @@ -572,7 +572,8 @@ STATIC mp_obj_t mdac_waveform(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map dac_offset_set(self->dac_id, (int8_t)args[ARG_offset].u_int); dac_invert_set(self->dac_id, args[ARG_invert].u_int & 3); dac_cosine_enable(self->dac_id); - return mp_const_none; + + goto exit; } if (type == 4) { @@ -589,7 +590,7 @@ STATIC mp_obj_t mdac_waveform(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map if (err) { ESP_LOGE("DAC", "Error starting DAC timer (%d)", err); } - return mp_const_none; + goto exit; } // --- For other waveforms we use I2S peripheral to generate the waveform --- @@ -634,6 +635,7 @@ STATIC mp_obj_t mdac_waveform(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map mp_raise_ValueError("Error allocating wave buffer"); } +exit: if (args[ARG_duration].u_int > 0) { mp_hal_delay_ms(args[ARG_duration].u_int); dac_func_stop(self); diff --git a/MicroPython_BUILD/components/micropython/esp32/machine_pin.c b/MicroPython_BUILD/components/micropython/esp32/machine_pin.c index 8c55f885..a713b677 100644 --- a/MicroPython_BUILD/components/micropython/esp32/machine_pin.c +++ b/MicroPython_BUILD/components/micropython/esp32/machine_pin.c @@ -353,7 +353,7 @@ mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, if ((args[ARG_trigger].u_int < GPIO_PIN_INTR_DISABLE) || (args[ARG_trigger].u_int >= GPIO_INTR_MAX)) { mp_raise_ValueError("invalid trigger type"); } - if ((args[ARG_debounce].u_int < 100) || (args[ARG_debounce].u_int > 500000)) { + if ((args[ARG_debounce].u_int != 0) && ((args[ARG_debounce].u_int < 100) || (args[ARG_debounce].u_int > 500000))) { mp_raise_ValueError("out of debounce range (100 - 500000 us)"); } if ((args[ARG_acttime].u_int < 0) || (args[ARG_acttime].u_int > 500000)) { diff --git a/MicroPython_BUILD/components/micropython/esp32/main.c b/MicroPython_BUILD/components/micropython/esp32/main.c index 821ae799..83facd75 100644 --- a/MicroPython_BUILD/components/micropython/esp32/main.c +++ b/MicroPython_BUILD/components/micropython/esp32/main.c @@ -426,9 +426,17 @@ void micropython_entry(void) esp_log_level_set("phy_init", ESP_LOG_WARN); esp_log_level_set("wl_flash", ESP_LOG_WARN); esp_log_level_set("RTC_MODULE", ESP_LOG_WARN); + #ifdef CONFIG_MICROPY_USE_ETHERNET + esp_log_level_set("phy_common", ESP_LOG_WARN); + #endif #ifdef CONFIG_MICROPY_USE_RFCOMM esp_log_level_set("BTDM_INIT", ESP_LOG_WARN); #endif + #ifdef CONFIG_MICROPY_USE_REQUESTS + //esp_log_level_set("HTTP_CLIENT", ESP_LOG_WARN); + //esp_log_level_set("TRANS_TCP", ESP_LOG_WARN); + //esp_log_level_set("TRANS_SSL", ESP_LOG_WARN); + #endif } #ifdef CONFIG_MICROPY_USE_OTA if (CONFIG_LOG_DEFAULT_LEVEL >= ESP_LOG_DEBUG) esp_log_level_set("OTA_UPDATE", ESP_LOG_DEBUG); diff --git a/MicroPython_BUILD/components/micropython/esp32/modcurl.c b/MicroPython_BUILD/components/micropython/esp32/modcurl.c index 7fe8ccae..4b957a19 100644 --- a/MicroPython_BUILD/components/micropython/esp32/modcurl.c +++ b/MicroPython_BUILD/components/micropython/esp32/modcurl.c @@ -42,6 +42,7 @@ #include "py/obj.h" #include "py/runtime.h" #include "modmachine.h" +#include "modnetwork.h" #include "libs/espcurl.h" #include "libs/curl_mail.h" #include "extmod/vfs_native.h" @@ -143,7 +144,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(curl_Options_obj, 0, curl_Options); //---------------------------------------------------------------------------------- STATIC mp_obj_t curl_GET(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - checkConnection(); + network_checkConnection(); enum { ARG_url, ARG_file }; const mp_arg_t allowed_args[] = { { MP_QSTR_url, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, @@ -197,10 +198,76 @@ STATIC mp_obj_t curl_GET(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(curl_GET_obj, 1, curl_GET); +//--------------------------------------------------------------------------------------- +STATIC mp_obj_t curl_GET_MAIL(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + network_checkConnection(); + enum { ARG_opts, ARG_user, ARG_pass, ARG_server, ARG_port, ARG_file }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_opts, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_user, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_password, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_server, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_port, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = GMAIL_IMAP_PORT } }, + { MP_QSTR_file, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + char *opts = (char *)mp_obj_str_get_str(args[ARG_opts].u_obj); + char *user = (char *)mp_obj_str_get_str(args[ARG_user].u_obj); + char *pass = (char *)mp_obj_str_get_str(args[ARG_pass].u_obj); + char mail_server[128] = {'\0'}; + int res; + int hdr_len = hdr_maxlen; + int body_len = body_maxlen; + vstr_t header; + vstr_t body; + char *fname = NULL; + char fullname[128] = {'\0'}; + + uint32_t mail_port = args[ARG_port].u_int; + if (MP_OBJ_IS_STR(args[ARG_server].u_obj)) sprintf(mail_server, "%s", (char *)mp_obj_str_get_str(args[ARG_server].u_obj)); + else sprintf(mail_server, GMAIL_IMAP); + + if (MP_OBJ_IS_STR(args[ARG_file].u_obj)) { + // GET to file + fname = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); + if (strcmp(fname, "simulate") != 0) { + res = physicalPath(fname, fullname); + if ((res != 0) || (strlen(fullname) == 0)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error resolving file name")); + } + fname = fullname; + } + body_len = MIN_BODY_BUF_LEN; + } + + vstr_init_len(&header, hdr_len); + vstr_init_len(&body, body_len); + header.buf[0] = '\0'; + body.buf[0] = '\0'; + + MP_THREAD_GIL_EXIT(); + res = Curl_IMAP_GET(opts, fname, header.buf, body.buf, header.len, body.len, mail_server, mail_port, user, pass); + MP_THREAD_GIL_ENTER(); + + mp_obj_t tuple[3]; + tuple[0] = mp_obj_new_int(res); + header.len = strlen(header.buf); + body.len = strlen(body.buf); + tuple[1] = mp_obj_new_str_from_vstr(&mp_type_str, &header); + tuple[2] = mp_obj_new_str_from_vstr(&mp_type_str, &body); + + return mp_obj_new_tuple(3, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(curl_GET_MAIL_obj, 1, curl_GET_MAIL); + //----------------------------------------------------------------------------------- STATIC mp_obj_t curl_POST(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - checkConnection(); + network_checkConnection(); enum { ARG_url, ARG_params }; const mp_arg_t allowed_args[] = { { MP_QSTR_url, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, @@ -279,50 +346,6 @@ STATIC mp_obj_t curl_POST(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ nparam++; } } - /* - mp_obj_dict_t *params = MP_OBJ_TO_PTR(args[ARG_params].u_obj); - mp_map_t *map = ¶ms->map; - mp_map_elem_t *table = map->table; - int nparam = map->used; - if (nparam > 0) { - nparam = 0; - for (int i=0; iused; i++) { - const char *key = mp_obj_str_get_str(table[i].key); - if (MP_OBJ_IS_STR(table[i].value)) { - const char *value = mp_obj_str_get_str(table[i].value); - uint8_t fadded = 0; - if (strlen(value) < 128) { - res = physicalPath(value, fullname); - if ((res == 0) && (strlen(fullname) > 0)) { - if (check_file(fullname)) { - curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, key, CURLFORM_FILE, fullname, CURLFORM_END); - nparam++; - fadded = 1; - } - } - } - if (fadded == 0) { - curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, key, CURLFORM_COPYCONTENTS, value, CURLFORM_END); - nparam++; - } - } - else if (MP_OBJ_IS_INT(table[i].value)) { - int ival = mp_obj_get_int(table[i].value); - char sval[64]; - sprintf(sval,"%d", ival); - curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, key, CURLFORM_COPYCONTENTS, sval, CURLFORM_END); - nparam++; - } - else if (MP_OBJ_IS_TYPE(table[i].value, &mp_type_float)) { - double fval = mp_obj_get_float(table[i].value); - char sval[64]; - sprintf(sval,"%f", fval); - curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, key, CURLFORM_COPYCONTENTS, sval, CURLFORM_END); - nparam++; - } - } - } - */ if (nparam == 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Expected at least one POST parameter")); } @@ -356,7 +379,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(curl_POST_obj, 1, curl_POST); //--------------------------------------------------------------------------------------- STATIC mp_obj_t curl_sendmail(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - checkConnection(); + network_checkConnection(); enum { ARG_user, ARG_pass, ARG_to, ARG_subject, ARG_msg, ARG_cc, ARG_bcc, ARG_attach, ARG_server, ARG_port, ARG_prot }; const mp_arg_t allowed_args[] = { { MP_QSTR_user, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, @@ -512,7 +535,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(curl_sendmail_obj, 1, curl_sendmail); //------------------------------------------------------------------------------------------------------- STATIC mp_obj_t curl_FTP_helper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t type) { - checkConnection(); + network_checkConnection(); enum { ARG_url, ARG_user, ARG_pass, ARG_file }; const mp_arg_t allowed_args[] = { { MP_QSTR_url, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, @@ -612,6 +635,7 @@ STATIC const mp_rom_map_elem_t curl_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&curl_GET_obj) }, { MP_ROM_QSTR(MP_QSTR_post), MP_ROM_PTR(&curl_POST_obj) }, { MP_ROM_QSTR(MP_QSTR_sendmail), MP_ROM_PTR(&curl_sendmail_obj) }, + { MP_ROM_QSTR(MP_QSTR_getmail), MP_ROM_PTR(&curl_GET_MAIL_obj) }, #ifdef CONFIG_MICROPY_USE_CURLFTP { MP_ROM_QSTR(MP_QSTR_ftp_get), MP_ROM_PTR(&curl_FTP_GET_obj) }, diff --git a/MicroPython_BUILD/components/micropython/esp32/moddisplay.c b/MicroPython_BUILD/components/micropython/esp32/moddisplay.c index 7da3189f..1707642a 100644 --- a/MicroPython_BUILD/components/micropython/esp32/moddisplay.c +++ b/MicroPython_BUILD/components/micropython/esp32/moddisplay.c @@ -24,1692 +24,35 @@ * THE SOFTWARE. */ -#include -#include -#include -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "rom/ets_sys.h" -#include "esp_system.h" -#include "esp_task_wdt.h" -#include - -#include "py/obj.h" -#include "py/objint.h" -#include "py/runtime.h" - -#include "driver/gpio.h" -#include "tft/tftspi.h" -#include "tft/tft.h" -#include "extmod/vfs_native.h" -#include "machine_hw_spi.h" -#include "modmachine.h" +#include "sdkconfig.h" +#ifdef CONFIG_MICROPY_USE_DISPLAY -typedef struct _display_tft_obj_t { - mp_obj_base_t base; - machine_hw_spi_obj_t *spi; - display_config_t dconfig; - exspi_device_handle_t disp_spi_dev; - exspi_device_handle_t ts_spi_dev; - exspi_device_handle_t *disp_spi; - exspi_device_handle_t *ts_spi; - uint32_t tp_calx; - uint32_t tp_caly; -} display_tft_obj_t; +#include -const mp_obj_type_t display_tft_type; +#include "py/obj.h" uint8_t disp_used_spi_host = 0; -static const char* const display_types[] = { - "ILI9341", - "ILI9488", - "ST7789V", - "ST7735", - "ST7735R", - "ST7735B", - "M5STACK", - "Unknown", -}; - -static const char* const touch_types[] = { - "None", - "xpt2046", - "stmpe610", - "Unknown", -}; - -// constructor(id, ...) -//----------------------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - - display_tft_obj_t *self = m_new_obj(display_tft_obj_t); //(display_tft_obj_t*)&display_tft_obj; - self->base.type = &display_tft_type; - self->spi = NULL; - self->disp_spi_dev.handle = NULL; - self->disp_spi_dev.cs = -1; - self->disp_spi_dev.dc = -1; - self->disp_spi_dev.selected = 0; - self->ts_spi_dev.handle = NULL; - self->ts_spi_dev.cs = -1; - self->ts_spi_dev.dc = -1; - self->ts_spi_dev.selected = 0; - self->disp_spi = &self->disp_spi_dev; - self->ts_spi = &self->ts_spi_dev; - - //return (mp_obj_t)&display_tft_obj; - return MP_OBJ_FROM_PTR(self); -} - -//----------------------------------------------------------------------------------------------- -STATIC void display_tft_printinfo(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) -{ - display_tft_obj_t *self = self_in; - if (self->disp_spi->handle) { - mp_printf(print, "TFT (%dx%d, Type=%s, Ready: %s, Color mode: %d-bit, Clk=%u Hz, RdClk=%u Hz, Touch: %s)\n", - self->dconfig.width, self->dconfig.height, display_types[self->dconfig.type], ((self->disp_spi->handle) ? "yes" : "no"), self->dconfig.color_bits, self->dconfig.speed, self->dconfig.rdspeed, ((self->ts_spi->handle) ? "yes" : "no")); - mp_printf(print, "Pins (miso=%d, mosi=%d, clk=%d, cs=%d, dc=%d, reset=%d, backlight=%d)", self->dconfig.miso, self->dconfig.mosi, self->dconfig.sck, self->dconfig.cs, self->dconfig.dc, self->dconfig.rst, self->dconfig.bckl); - if (self->ts_spi->handle) { - mp_printf(print, "\nTouch (Enabled, type: %s, cs=%d)", touch_types[self->dconfig.touch], self->dconfig.tcs); - } - } - else { - mp_printf(print, "TFT (Not initialized)"); - } -} - -/* - * tftspi.c low level driver uses some global variables - * Here we set those variables so that multiple displays can be used - */ -//------------------------------------------------- -static int setupDevice(display_tft_obj_t *disp_dev) -{ - if (disp_dev->disp_spi->handle == NULL) return 1; - - if (disp_spi != disp_dev->disp_spi) { - disp_spi = disp_dev->disp_spi; - ts_spi = disp_dev->ts_spi; - TFT_display_setvars(&disp_dev->dconfig); - - tp_calx = disp_dev->tp_calx; - tp_caly = disp_dev->tp_caly; - spi_device_select(disp_spi, 1); - spi_device_deselect(disp_spi); - } - - return 0; -} - -//-------------------------------------- -STATIC color_t intToColor(uint32_t cint) -{ - color_t cl = {0,0,0}; - cl.r = (cint >> 16) & 0xFF; - cl.g = (cint >> 8) & 0xFF; - cl.b = cint & 0xFF; - return cl; -} - -//------------------------------------------------------ -STATIC void spi_deinit_internal(display_tft_obj_t *self) -{ - if (self->disp_spi->handle) { - esp_err_t ret; - // Deinitialize display spi device(s) - if (self->ts_spi->handle) { - ret = remove_extspi_device(self->ts_spi); - if (ret != ESP_OK) { - mp_raise_msg(&mp_type_OSError, "Error removing touch device"); - } - } - ret = remove_extspi_device(self->disp_spi); - if (ret != ESP_OK) { - mp_raise_msg(&mp_type_OSError, "Error removing display device"); - } - - gpio_pad_select_gpio(self->dconfig.miso); - gpio_pad_select_gpio(self->dconfig.mosi); - gpio_pad_select_gpio(self->dconfig.sck); - } -} - - -//----------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_type, ARG_host, ARG_width, ARG_height, ARG_speed, ARG_miso, ARG_mosi, ARG_clk, ARG_cs, - ARG_dc, ARG_tcs, ARG_rst, ARG_bckl, ARG_bcklon, ARG_hastouch, ARG_invrot, ARG_bgr, ARG_cbits, ARG_rot, ARG_splash }; - const mp_arg_t allowed_args[] = { - { MP_QSTR_type, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = DISP_TYPE_ST7789V } }, - { MP_QSTR_spihost, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = HSPI_HOST } }, - { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = DEFAULT_TFT_DISPLAY_WIDTH } }, - { MP_QSTR_height, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = DEFAULT_TFT_DISPLAY_HEIGHT } }, - { MP_QSTR_speed, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 10000000 } }, - { MP_QSTR_miso, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_mosi, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_clk, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_cs, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_dc, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_tcs, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_rst_pin, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_backl_pin, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_backl_on, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_hastouch, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = TOUCH_TYPE_NONE } }, - { MP_QSTR_invrot, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_bgr, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = false } }, - { MP_QSTR_color_bits, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 24 } }, - { MP_QSTR_rot, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_splash, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = true } }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - display_tft_obj_t *self = pos_args[0]; - esp_err_t ret; - - // === deinitialize display spi device if it was initialized === - if (self->disp_spi->handle) spi_deinit_internal(self); - - // === Get arguments === - if ((args[ARG_host].u_int != HSPI_HOST) && (args[ARG_host].u_int != VSPI_HOST)) { - mp_raise_ValueError("SPI host must be either HSPI(1) or VSPI(2)"); - } - if ((SPIbus_configs[VSPI_HOST] == NULL) && (args[ARG_host].u_int == VSPI_HOST)) { - mp_raise_ValueError("SPI host must be HSPI(1), VSPI(2) used by SPIRAM"); - } - - if ((args[ARG_type].u_int < 0) || (args[ARG_type].u_int >= DISP_TYPE_MAX)) { - mp_raise_ValueError("Unsupported display type"); - } - - if ((args[ARG_cbits].u_int != 16) && (args[ARG_cbits].u_int != 24)) { - mp_raise_ValueError("Unsupported color bits"); - } - - self->dconfig.color_bits = args[ARG_cbits].u_int; - - self->dconfig.type = args[ARG_type].u_int; - - if ((args[ARG_hastouch].u_int == TOUCH_TYPE_XPT2046) || (args[ARG_hastouch].u_int == TOUCH_TYPE_STMPE610)) { - if (args[ARG_tcs].u_int < 0) { - mp_raise_ValueError("Touch selected but no touch cs given"); - } - self->dconfig.touch = args[ARG_hastouch].u_int; - if (args[ARG_hastouch].u_int == TOUCH_TYPE_XPT2046) { - self->tp_calx = TP_CALX_XPT2046; - self->tp_caly = TP_CALY_XPT2046; - } - else { - self->tp_calx = TP_CALX_STMPE610; - self->tp_caly = TP_CALY_STMPE610; - } - self->dconfig.tcs = args[ARG_tcs].u_int; - } - else self->dconfig.touch = TOUCH_TYPE_NONE; - - self->dconfig.host = args[ARG_host].u_int; - self->dconfig.gamma = 0; - self->dconfig.width = args[ARG_width].u_int; // smaller dimension - self->dconfig.height = args[ARG_height].u_int; // larger dimension - self->dconfig.rdspeed = 8000000; - if (args[ARG_invrot].u_int >= 0) self->dconfig.invrot = args[ARG_invrot].u_int; - else { - if ((self->dconfig.type == DISP_TYPE_ST7789V) || - (self->dconfig.type == DISP_TYPE_ST7735) || - (self->dconfig.type == DISP_TYPE_ST7735R) || - (self->dconfig.type == DISP_TYPE_ST7735B)) self->dconfig.invrot = 1; - else if (self->dconfig.type == DISP_TYPE_M5STACK) self->dconfig.invrot = 3; - else self->dconfig.invrot = 0; - } - - if (args[ARG_bgr].u_bool) self->dconfig.bgr = 8; - else self->dconfig.bgr = 0; - - self->dconfig.rst = args[ARG_rst].u_int; - self->dconfig.bckl = args[ARG_bckl].u_int; - self->dconfig.bckl_on = args[ARG_bcklon].u_int & 1; - - self->dconfig.miso = args[ARG_miso].u_int; - self->dconfig.mosi = args[ARG_mosi].u_int; - self->dconfig.sck = args[ARG_clk].u_int; - - self->dconfig.cs = args[ARG_cs].u_int; - self->dconfig.dc = args[ARG_dc].u_int; - - disp_spi = self->disp_spi; - ts_spi = self->ts_spi; - - int orient = args[ARG_rot].u_int; - if (orient < 0) { - if (self->dconfig.type == DISP_TYPE_M5STACK) orient = LANDSCAPE; - else orient = PORTRAIT; - } - else orient &= 3; - - // ================================ - // ==== Initialize the Display ==== - ret = TFT_display_init(&self->dconfig); - if (ret != ESP_OK) { - mp_raise_msg(&mp_type_OSError, "Error initializing display"); - } - - disp_used_spi_host = args[ARG_host].u_int; - - if (self->dconfig.type == DISP_TYPE_GENERIC) return mp_const_none; - - // ==== Set SPI clock used for display operations ==== - self->dconfig.speed = spi_set_speed(self->disp_spi, args[ARG_speed].u_int); - - max_rdclock = find_rd_speed(); - self->dconfig.rdspeed = max_rdclock; - - font_rotate = 0; - text_wrap = 0; - font_transparent = 0; - font_forceFixed = 0; - gray_scale = 0; - TFT_setRotation(orient); - self->dconfig.width = _width; - self->dconfig.height = _height; - TFT_setGammaCurve(0); - TFT_setFont(DEFAULT_FONT, NULL); - TFT_resetclipwin(); - if (args[ARG_splash].u_bool) { - int fhight = TFT_getfontheight(); - _fg = intToColor(iTFT_RED); - TFT_print("MicroPython", CENTER, (_height/2) - fhight - (fhight/2)); - _fg = intToColor(iTFT_GREEN); - TFT_print("MicroPython", CENTER, (_height/2) - (fhight/2)); - _fg = intToColor(iTFT_BLUE); - TFT_print("MicroPython", CENTER, (_height/2) + (fhight/2)); - _fg = intToColor(iTFT_GREEN); - } - - bcklOn(&self->dconfig); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_init_obj, 0, display_tft_init); - -//-------------------------------------------------- -STATIC mp_obj_t display_tft_deinit(mp_obj_t self_in) -{ - display_tft_obj_t *self = self_in; - if (setupDevice(self) == 0) { - spi_deinit_internal(self); - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_deinit_obj, display_tft_deinit); - -//------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_drawPixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t color = _fg; - mp_int_t x = args[0].u_int; - mp_int_t y = args[1].u_int; - if (args[2].u_int >= 0) { - color = intToColor(args[2].u_int); - } - TFT_drawPixel(x, y, color, 1); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawPixel_obj, 2, display_tft_drawPixel); - -//------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_readPixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_int_t x = args[0].u_int; - mp_int_t y = args[1].u_int; - - color_t color = TFT_readPixel(x, y); - mp_int_t icolor = (int)((color.r << 16) | (color.g << 8) | color.b); - - return mp_obj_new_int(icolor); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_readPixel_obj, 2, display_tft_readPixel); - -//------------------------------------------------------------------------------------------------ -STATIC mp_obj_t display_tft_drawLine(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t color = _fg; - mp_int_t x0 = args[0].u_int; - mp_int_t y0 = args[1].u_int; - mp_int_t x1 = args[2].u_int; - mp_int_t y1 = args[3].u_int; - if (args[4].u_int >= 0) { - color = intToColor(args[4].u_int); - } - TFT_drawLine(x0, y0, x1, y1, color); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawLine_obj, 4, display_tft_drawLine); - -//------------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_drawLineByAngle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_start, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_length, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_angle, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t color = _fg; - mp_int_t x = args[0].u_int; - mp_int_t y = args[1].u_int; - mp_int_t start = args[2].u_int; - mp_int_t len = args[3].u_int; - mp_int_t angle = args[4].u_int; - if (args[5].u_int >= 0) { - color = intToColor(args[5].u_int); - } - TFT_drawLineByAngle(x, y, start, len, angle, color); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawLineByAngle_obj, 5, display_tft_drawLineByAngle); - -//---------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_drawTriangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t color = _fg; - mp_int_t x0 = args[0].u_int; - mp_int_t y0 = args[1].u_int; - mp_int_t x1 = args[2].u_int; - mp_int_t y1 = args[3].u_int; - mp_int_t x2 = args[4].u_int; - mp_int_t y2 = args[5].u_int; - if (args[6].u_int >= 0) { - color = intToColor(args[6].u_int); - } - if (args[7].u_int >= 0) { - TFT_fillTriangle(x0, y0, x1, y1, x2, y2, intToColor(args[7].u_int)); - } - TFT_drawTriangle(x0, y0, x1, y1, x2, y2, color); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawTriangle_obj, 6, display_tft_drawTriangle); - -//-------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_drawCircle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t color = _fg; - mp_int_t x = args[0].u_int; - mp_int_t y = args[1].u_int; - mp_int_t radius = args[2].u_int; - if (args[3].u_int >= 0) { - color = intToColor(args[3].u_int); - } - if (args[4].u_int >= 0) { - TFT_fillCircle(x, y, radius, intToColor(args[4].u_int)); - if (args[3].u_int != args[4].u_int) TFT_drawCircle(x, y, radius, color); - } - else TFT_drawCircle(x, y, radius, color); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawCircle_obj, 3, display_tft_drawCircle); - -//--------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_drawEllipse(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_rx, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_ry, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_opt, MP_ARG_INT, { .u_int = 15 } }, - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t color = _fg; - mp_int_t x = args[0].u_int; - mp_int_t y = args[1].u_int; - mp_int_t rx = args[2].u_int; - mp_int_t ry = args[3].u_int; - mp_int_t opt = args[4].u_int & 0x0F; - if (args[5].u_int >= 0) { - color = intToColor(args[5].u_int); - } - if (args[6].u_int >= 0) { - TFT_fillEllipse(x, y, rx, ry, intToColor(args[6].u_int), opt); - } - TFT_drawEllipse(x, y, rx, ry, color, opt); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawEllipse_obj, 4, display_tft_drawEllipse); - -//----------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_drawArc(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_thick, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_start, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_end, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 15 } }, - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t color = _fg; - color_t fill_color = _fg; - mp_int_t x = args[0].u_int; - mp_int_t y = args[1].u_int; - mp_int_t r = args[2].u_int; - mp_int_t th = args[3].u_int; - mp_int_t start = args[4].u_int; - mp_int_t end = args[5].u_int; - if (args[6].u_int >= 0) { - color = intToColor(args[6].u_int); - } - if (args[7].u_int >= 0) { - fill_color = intToColor(args[7].u_int); - } - TFT_drawArc(x, y, r, th, start, end, color, fill_color); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawArc_obj, 6, display_tft_drawArc); - -//------------------------------------------------------------------------------------------------ -STATIC mp_obj_t display_tft_drawPoly(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_sides, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_thick, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 1 } }, - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_rotate, MP_ARG_INT, { .u_int = 0 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t color = _fg; - color_t fill_color = _fg; - mp_int_t x = args[0].u_int; - mp_int_t y = args[1].u_int; - mp_int_t r = args[2].u_int; - mp_int_t sides = args[3].u_int; - mp_int_t th = args[4].u_int; - if (args[5].u_int >= 0) { - color = intToColor(args[5].u_int); - } - if (args[6].u_int >= 0) { - fill_color = intToColor(args[6].u_int); - } - TFT_drawPolygon(x, y, sides, r, color, fill_color, args[7].u_int, th); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawPoly_obj, 5, display_tft_drawPoly); - -//------------------------------------------------------------------------------------------------ -STATIC mp_obj_t display_tft_drawRect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t color = _fg; - mp_int_t x = args[0].u_int; - mp_int_t y = args[1].u_int; - mp_int_t w = args[2].u_int; - mp_int_t h = args[3].u_int; - if (args[4].u_int >= 0) { - color = intToColor(args[4].u_int); - } - if (args[5].u_int >= 0) { - TFT_fillRect(x, y, w, h, intToColor(args[5].u_int)); - } - TFT_drawRect(x, y, w, h, color); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawRect_obj, 4, display_tft_drawRect); - -//-------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_readScreen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_buffer, MP_ARG_OBJ, { .u_obj = mp_const_none } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t color = _fg; - mp_int_t x = args[0].u_int; - mp_int_t y = args[1].u_int; - mp_int_t w = args[2].u_int; - mp_int_t h = args[3].u_int; - - // clipping - if ((x >= _width) || (y > _height)) { - mp_raise_ValueError("Point (x,y) outside the display area"); - } - - if (x < 0) { - w -= (0 - x); - x = 0; - } - if (y < 0) { - h -= (0 - y); - y = 0; - } - if (w < 0) w = 0; - if (h < 0) h = 0; - - if ((x + w) > (_width+1)) w = _width - x + 1; - if ((y + h) > (_height+1)) h = _height - y + 1; - if (w == 0) w = 1; - if (h == 0) h = 1; - - int clr_len = h*w; - int buf_len = (clr_len*3) + 1; - uint8_t *buf = NULL; - vstr_t vstr; - - if (args[4].u_obj == mp_const_none) { - vstr_init_len(&vstr, buf_len); - buf = (uint8_t *)vstr.buf; - } - else { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[4].u_obj, &bufinfo, MP_BUFFER_WRITE); - if (bufinfo.len != buf_len) { - mp_raise_ValueError("Wrong buffer length"); - } - buf = (uint8_t *)bufinfo.buf; - } - memset(buf, 0, buf_len); - - esp_err_t ret = read_data(x, y, x+w+1, y+h+1, (uint32_t)clr_len, buf, 1); - - if (ret == ESP_OK) { - if (args[4].u_obj == mp_const_none) return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); - else return mp_const_true; - } - return mp_const_false; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_readScreen_obj, 4, display_tft_readScreen); - -//----------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_drawRoundRect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t color = _fg; - mp_int_t x = args[0].u_int; - mp_int_t y = args[1].u_int; - mp_int_t w = args[2].u_int; - mp_int_t h = args[3].u_int; - mp_int_t r = args[4].u_int; - if (args[5].u_int >= 0) { - color = intToColor(args[5].u_int); - } - if (args[6].u_int >= 0) { - TFT_fillRoundRect(x, y, w, h, r, intToColor(args[6].u_int)); - } - TFT_drawRoundRect(x, y, w, h, r, color); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawRoundRect_obj, 5, display_tft_drawRoundRect); - -//-------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_fillScreen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t color = _bg; - if (args[0].u_int >= 0) { - color = intToColor(args[0].u_int); - } - TFT_fillScreen(color); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_fillScreen_obj, 0, display_tft_fillScreen); - -//----------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_fillWin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t color = _bg; - if (args[0].u_int >= 0) { - color = intToColor(args[0].u_int); - } - TFT_fillWindow(color); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_fillWin_obj, 0, display_tft_fillWin); - -//-------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_7segAttrib(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_dist, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_outline, MP_ARG_REQUIRED | MP_ARG_BOOL, { .u_bool = false } }, - { MP_QSTR_color, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - set_7seg_font_atrib(args[0].u_int, args[1].u_int, (int)args[2].u_bool, intToColor(args[3].u_int)); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_7segAttrib_obj, 4, display_tft_7segAttrib); - -//----------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_setFont(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_font, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_rotate, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_transparent, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_fixedwidth, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_dist, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 8 } }, - { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 2 } }, - { MP_QSTR_outline, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = false } }, - { MP_QSTR_color, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - const char *font_file = NULL; - char fullname[128] = {'\0'}; - mp_int_t font = DEFAULT_FONT; - - if (MP_OBJ_IS_STR(args[0].u_obj)) { - font_file = mp_obj_str_get_str(args[0].u_obj); - - if (physicalPath(font_file, fullname) == 0) { - font = USER_FONT; - font_file = fullname; - } - } - else { - font = mp_obj_get_int(args[0].u_obj); - } - TFT_setFont(font, font_file); - - if (args[1].u_int >= 0) font_rotate = args[1].u_int; - if (args[2].u_int >= 0) font_transparent = args[2].u_int & 1; - if (args[3].u_int >= 0) font_forceFixed = args[3].u_int & 1; - - if (font == FONT_7SEG) { - set_7seg_font_atrib(args[4].u_int, args[5].u_int, (int)args[6].u_bool, intToColor(args[7].u_int)); - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_setFont_obj, 1, display_tft_setFont); - -//------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_getFontSize(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) -{ - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - int width, height; - TFT_getfontsize(&width, &height); - - mp_obj_t tuple[2]; - - tuple[0] = mp_obj_new_int(width); - tuple[1] = mp_obj_new_int(height); - - return mp_obj_new_tuple(2, tuple); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_getFontSize_obj, 0, display_tft_getFontSize); - -//----------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_setRot(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_rot, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = PORTRAIT } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_int_t rot = args[0].u_int; - if ((rot < 0) || (rot > 3)) rot = 0; - - TFT_setRotation(rot); - self->dconfig.width = _width; - self->dconfig.height = _height; - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_setRot_obj, 1, display_tft_setRot); - -//--------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_print(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_rotate, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_transparent, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_fixedwidth, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_wrap, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_bgcolor, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t old_fg = _fg; - color_t old_bg = _bg; - int old_rot = font_rotate; - int old_transp = font_transparent; - int old_fixed = font_forceFixed; - int old_wrap = text_wrap; - - mp_int_t x = args[0].u_int; - mp_int_t y = args[1].u_int; - char *st = (char *)mp_obj_str_get_str(args[2].u_obj); - - if (args[3].u_int >= 0) _fg = intToColor(args[3].u_int); - if (args[4].u_int >= 0) font_rotate = args[4].u_int; - if (args[5].u_int >= 0) font_transparent = args[5].u_int & 1; - if (args[6].u_int >= 0) font_forceFixed = args[6].u_int & 1; - if (args[7].u_int >= 0) text_wrap = args[7].u_int & 1; - if (args[8].u_int >= 0) _bg = intToColor(args[8].u_int); - - TFT_print(st, x, y); - - _fg = old_fg; - _bg = old_bg; - font_rotate = old_rot; - font_transparent = old_transp; - font_forceFixed = old_fixed; - text_wrap = old_wrap; - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_print_obj, 3, display_tft_print); - -//--------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_stringWidth(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - char *st = (char *)mp_obj_str_get_str(args[0].u_obj); - - mp_int_t w = TFT_getStringWidth(st); - - return mp_obj_new_int(w); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_stringWidth_obj, 1, display_tft_stringWidth); - -//------------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_clearStringRect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - color_t old_bg = _bg; - mp_int_t x = args[0].u_int; - mp_int_t y = args[1].u_int; - char *st = (char *)mp_obj_str_get_str(args[2].u_obj); - - if (args[3].u_int >= 0) _bg = intToColor(args[3].u_int); - - TFT_clearStringRect(x, y, st); - - _bg = old_bg; - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_clearStringRect_obj, 3, display_tft_clearStringRect); - -//----------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_Image(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_scale, MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_type, MP_ARG_INT, { .u_int = -1 } }, - { MP_QSTR_debug, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - char *fname = NULL; - char fullname[128] = {'\0'}; - int img_type = args[4].u_int; - - fname = (char *)mp_obj_str_get_str(args[2].u_obj); - - int res = physicalPath(fname, fullname); - if ((res != 0) || (strlen(fullname) == 0)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error resolving file name")); - } - - if (img_type < 0) { - // try to determine image type - char upr_fname[128]; - strcpy(upr_fname, fname); - for (int i=0; i < strlen(upr_fname); i++) { - upr_fname[i] = toupper((unsigned char) upr_fname[i]); - } - if (strstr(upr_fname, ".JPG") != NULL) img_type = IMAGE_TYPE_JPG; - else if (strstr(upr_fname, ".BMP") != NULL) img_type = IMAGE_TYPE_BMP; - else { - FILE *fhndl = fopen(fullname, "r"); - if (fhndl != NULL) { - uint8_t buf[16]; - if (fread(buf, 1, 11, fhndl) == 11) { - buf[10] = 0; - if (strstr((char *)(buf+6), "JFIF") != NULL) img_type = IMAGE_TYPE_JPG; - else if ((buf[0] = 0x42) && (buf[1] = 0x4d)) img_type = IMAGE_TYPE_BMP; - } - fclose(fhndl); - } - } - if (img_type < 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Cannot determine image type")); - } - } - - image_debug = (uint8_t)args[5].u_bool; - if (img_type == IMAGE_TYPE_BMP) { - TFT_bmp_image(args[0].u_int, args[1].u_int, args[3].u_int, fullname, NULL, 0); - } - else if (img_type == IMAGE_TYPE_JPG) { - TFT_jpg_image(args[0].u_int, args[1].u_int, args[3].u_int, fullname, NULL, 0); - } - else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Unsupported image type")); - } - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_Image_obj, 3, display_tft_Image); - -//------------------------------------------------------------------------------------------------ -STATIC mp_obj_t display_tft_getTouch(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_raw, MP_ARG_BOOL, { .u_bool = false } }, - { MP_QSTR_wait, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - - if (setupDevice(self)) return mp_const_none; - if (self->ts_spi->handle == NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Touch not configured")); - } - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - int x = 0; - int y = 0; - uint8_t raw = 0; - if (args[0].u_bool) raw = 1; - int wait = args[1].u_int; - if ((wait < 5) || (wait > 60000)) wait = 0; - - int res = TFT_read_touch(&x, &y, raw); - if (wait) { - #ifdef CONFIG_MICROPY_USE_TASK_WDT - esp_task_wdt_reset(); - #endif - struct timeval tv; - gettimeofday(&tv, NULL); - uint32_t tstart = ((uint32_t)tv.tv_sec * 1000) + ((uint32_t)tv.tv_usec / 1000); - uint32_t tend = tstart; - uint32_t nres = tstart; - - // wait until not touched - while ((tend-tstart) < wait) { - res = TFT_read_touch(&x, &y, raw); - if (res == 0) break; - vTaskDelay(2); - gettimeofday(&tv, NULL); - tend = ((uint32_t)tv.tv_sec * 1000) + ((uint32_t)tv.tv_usec / 1000); - #ifdef CONFIG_MICROPY_USE_TASK_WDT - if ((tend-nres) > (CONFIG_TASK_WDT_TIMEOUT_S*500)) { - esp_task_wdt_reset(); - nres = tend; - } - #endif - } - // wait until touched - while ((tend-tstart) < wait) { - res = TFT_read_touch(&x, &y, raw); - if (res) break; - vTaskDelay(2); - gettimeofday(&tv, NULL); - tend = ((uint32_t)tv.tv_sec * 1000) + ((uint32_t)tv.tv_usec / 1000); - #ifdef CONFIG_MICROPY_USE_TASK_WDT - if ((tend-nres) > (CONFIG_TASK_WDT_TIMEOUT_S*500)) { - esp_task_wdt_reset(); - nres = tend; - } - #endif - } - } - - mp_obj_t tuple[3]; - tuple[0] = mp_obj_new_bool(res); - tuple[1] = mp_obj_new_int(x); - tuple[2] = mp_obj_new_int(y); - - return mp_obj_new_tuple(3, tuple); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_getTouch_obj, 0, display_tft_getTouch); - -//----------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_compileFont(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_debug, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = false } }, - }; - //display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - //if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - char *fname = NULL; - char fullname[128] = {'\0'}; - uint8_t debug = (uint8_t)args[1].u_bool; - - fname = (char *)mp_obj_str_get_str(args[0].u_obj); - - int res = physicalPath(fname, fullname); - if ((res != 0) || (strlen(fullname) == 0)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error resolving file name")); - } - - res = compile_font_file(fullname, debug); - if (res) return mp_const_false; - return mp_const_true; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_compileFont_obj, 1, display_tft_compileFont); - -//----------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_HSBtoRGB(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_hue, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_saturation, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_brightness, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_float_t hue = mp_obj_get_float(args[0].u_obj); - mp_float_t sat = mp_obj_get_float(args[1].u_obj); - mp_float_t bri = mp_obj_get_float(args[2].u_obj); - - color_t color = HSBtoRGB(hue, sat, bri); - mp_int_t icolor = (int)((color.r << 16) | (color.g << 8) | color.b); - - return mp_obj_new_int(icolor); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_HSBtoRGB_obj, 3, display_tft_HSBtoRGB); - -//-------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_setclipwin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_int_t x0 = args[0].u_int; - mp_int_t y0 = args[1].u_int; - mp_int_t x1 = args[2].u_int; - mp_int_t y1 = args[3].u_int; - - TFT_setclipwin(x0, y0, x1, y1); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_setclipwin_obj, 4, display_tft_setclipwin); - -//---------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_resetclipwin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - TFT_resetclipwin(); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_resetclipwin_obj, 0, display_tft_resetclipwin); - -//--------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_saveclipwin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - TFT_saveClipWin(); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_saveclipwin_obj, 0, display_tft_saveclipwin); - -//------------------------------------------------------------------------------------------------------ -STATIC mp_obj_t display_tft_restoreclipwin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - TFT_restoreClipWin(); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_restoreclipwin_obj, 0, display_tft_restoreclipwin); - -//------------------------------------------------------------------------------------------------ -STATIC mp_obj_t display_tft_getSize(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_obj_t tuple[2]; - tuple[0] = mp_obj_new_int(_width); - tuple[1] = mp_obj_new_int(_height); - - return mp_obj_new_tuple(2, tuple); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_getSize_obj, 0, display_tft_getSize); - -//-------------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_getWinSize(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - - mp_obj_t tuple[2]; - tuple[0] = mp_obj_new_int(dispWin.x2 - dispWin.x1 + 1); - tuple[1] = mp_obj_new_int(dispWin.y2 - dispWin.y1 + 1); - - return mp_obj_new_tuple(2, tuple); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_getWinSize_obj, 0, display_tft_getWinSize); - -//------------------------------------------------------------------------------------------------ -STATIC mp_obj_t display_tft_setCalib(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - const mp_arg_t allowed_args[] = { - { MP_QSTR_calx, MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_caly, MP_ARG_INT, { .u_int = 0 } }, - { MP_QSTR_from_nvs, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = false } }, - }; - display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if (setupDevice(self)) return mp_const_none; - if (self->ts_spi->handle == NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Touch not configured")); - } - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - if (self->dconfig.touch == TOUCH_TYPE_NONE) { - return mp_const_none; - } - - if (args[2].u_bool) { - if (mpy_nvs_handle == 0) { - mp_raise_msg(&mp_type_OSError, "NVS not available!"); - } - int calx = 0, caly = 0; - bool f = true; - if (ESP_ERR_NVS_NOT_FOUND == nvs_get_i32(mpy_nvs_handle, "tpcalibX", &calx)) f = false; - if (f) { - if (ESP_ERR_NVS_NOT_FOUND == nvs_get_i32(mpy_nvs_handle, "tpcalibY", &caly)) f = false; - } - if (!f) { - mp_raise_msg(&mp_type_OSError, "Calibration values not found in NVS"); - } - self->tp_calx = calx; - self->tp_caly = caly; - return mp_const_none; - } - - if (args[0].u_int == 0) { - if (self->dconfig.touch == TOUCH_TYPE_XPT2046) self->tp_calx = TP_CALX_XPT2046; - else self->tp_calx = TP_CALX_STMPE610; - } - else self->tp_calx = args[0].u_int; - - if (args[1].u_int == 0) { - if (self->dconfig.touch == TOUCH_TYPE_XPT2046) self->tp_caly = TP_CALY_XPT2046; - else self->tp_caly = TP_CALY_STMPE610; - } - else self->tp_caly = args[1].u_int; - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_setCalib_obj, 0, display_tft_setCalib); - -//---------------------------------------------------- -STATIC mp_obj_t display_tft_getCalib(mp_obj_t self_in) -{ - display_tft_obj_t *self = self_in; - if (setupDevice(self)) return mp_const_none; - if (self->ts_spi->handle == NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Touch not configured")); - } - mp_obj_t tuple[2]; - - tuple[0] = mp_obj_new_int(self->tp_calx); - tuple[1] = mp_obj_new_int(self->tp_caly); - - return mp_obj_new_tuple(2, tuple); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_getCalib_obj, display_tft_getCalib); - - -//------------------------------------------------------------------------ -STATIC mp_obj_t display_tft_backlight(mp_obj_t self_in, mp_obj_t onoff_in) -{ - display_tft_obj_t *self = self_in; - if (setupDevice(self)) return mp_const_none; - - int onoff = mp_obj_get_int(onoff_in); - if (onoff) bcklOn(&self->dconfig); - else bcklOff(&self->dconfig); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(display_tft_backlight_obj, display_tft_backlight); - -//------------------------------------------------------ -STATIC mp_obj_t display_tft_touch_type(mp_obj_t self_in) -{ - display_tft_obj_t *self = self_in; - if (setupDevice(self)) return mp_const_none; - - return mp_obj_new_int(self->dconfig.touch); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_touch_type_obj, display_tft_touch_type); - - -// ==== Low level functions ====================================== - -//------------------------------------------------------------------------ -STATIC mp_obj_t display_tft_set_speed(mp_obj_t self_in, mp_obj_t speed_in) -{ - display_tft_obj_t *self = self_in; - if (setupDevice(self)) return mp_const_none; - - int speed = mp_obj_get_int(speed_in); - - // Set SPI clock used for display operations - self->dconfig.speed = spi_set_speed(self->disp_spi, speed); - - max_rdclock = find_rd_speed(); - self->dconfig.rdspeed = max_rdclock; - - mp_obj_t tuple[2]; - - tuple[0] = mp_obj_new_int(self->dconfig.speed); - tuple[1] = mp_obj_new_int(self->dconfig.rdspeed); - - return mp_obj_new_tuple(2, tuple); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(display_tft_set_speed_obj, display_tft_set_speed); - -//-------------------------------------------------- -STATIC mp_obj_t display_tft_select(mp_obj_t self_in) -{ - display_tft_obj_t *self = self_in; - if (setupDevice(self)) return mp_const_none; - - disp_select(); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_select_obj, display_tft_select); - -//---------------------------------------------------- -STATIC mp_obj_t display_tft_deselect(mp_obj_t self_in) -{ - display_tft_obj_t *self = self_in; - if (setupDevice(self)) return mp_const_none; - - disp_deselect(); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_deselect_obj, display_tft_deselect); - -//-------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_cmd_read(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t len_in) -{ - display_tft_obj_t *self = self_in; - if (setupDevice(self)) return mp_const_none; - - uint8_t cmd = (uint8_t)mp_obj_get_int(cmd_in); - uint8_t len = (uint8_t)mp_obj_get_int(len_in); - if ((len < 1) || (len > 4)) len = 1; - - uint32_t res = read_cmd(cmd, len); - - return mp_obj_new_int_from_uint(res); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_3(display_tft_cmd_read_obj, display_tft_cmd_read); - -//------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_send_command(mp_obj_t self_in, mp_obj_t cmd_in) -{ - display_tft_obj_t *self = self_in; - if (setupDevice(self)) return mp_const_none; - - uint8_t cmd = (uint8_t)mp_obj_get_int(cmd_in); - - disp_select(); - disp_spi_transfer_cmd(cmd); - wait_trans_finish(0); - disp_deselect(); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(display_tft_send_command_obj, display_tft_send_command); - -//-------------------------------------------------------------------------------------------- -STATIC mp_obj_t display_tft_send_cmd_data(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t data_in) -{ - display_tft_obj_t *self = self_in; - if (setupDevice(self)) return mp_const_none; - - uint8_t cmd = (uint8_t)mp_obj_get_int(cmd_in); - mp_buffer_info_t data; - mp_get_buffer_raise(data_in, &data, MP_BUFFER_READ); - - disp_select(); - disp_spi_transfer_cmd_data(cmd, data.buf, data.len); - wait_trans_finish(0); - disp_deselect(); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_3(display_tft_send_cmd_data_obj, display_tft_send_cmd_data); - -//-------------------------------------------------- -STATIC mp_obj_t display_tft_get_bg(mp_obj_t self_in) -{ - int icolor = (int)((_bg.r << 16) | (_bg.g << 8) | _bg.b); - return mp_obj_new_int(icolor); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_get_bg_obj, display_tft_get_bg); - -//-------------------------------------------------- -STATIC mp_obj_t display_tft_get_fg(mp_obj_t self_in) -{ - int icolor = (int)((_fg.r << 16) | (_fg.g << 8) | _fg.b); - return mp_obj_new_int(icolor); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_get_fg_obj, display_tft_get_fg); - -//--------------------------------------------------------------------- -STATIC mp_obj_t display_tft_set_bg(mp_obj_t self_in, mp_obj_t color_in) -{ - color_t color = intToColor(mp_obj_get_int(color_in)); - _bg = color; - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(display_tft_set_bg_obj, display_tft_set_bg); - -//--------------------------------------------------------------------- -STATIC mp_obj_t display_tft_set_fg(mp_obj_t self_in, mp_obj_t color_in) -{ - color_t color = intToColor(mp_obj_get_int(color_in)); - _fg = color; - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(display_tft_set_fg_obj, display_tft_set_fg); - -//------------------------------------------------- -STATIC mp_obj_t display_tft_get_X(mp_obj_t self_in) -{ - int x = TFT_X; - return mp_obj_new_int(x); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_get_X_obj, display_tft_get_X); - -//------------------------------------------------- -STATIC mp_obj_t display_tft_get_Y(mp_obj_t self_in) -{ - int y = TFT_Y; - return mp_obj_new_int(y); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_get_Y_obj, display_tft_get_Y); - - -//================================================================ -STATIC const mp_rom_map_elem_t display_tft_locals_dict_table[] = { - // instance methods - { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&display_tft_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&display_tft_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&display_tft_drawPixel_obj) }, - { MP_ROM_QSTR(MP_QSTR_readPixel), MP_ROM_PTR(&display_tft_readPixel_obj) }, - { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&display_tft_drawLine_obj) }, - { MP_ROM_QSTR(MP_QSTR_lineByAngle), MP_ROM_PTR(&display_tft_drawLineByAngle_obj) }, - { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&display_tft_drawTriangle_obj) }, - { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&display_tft_drawCircle_obj) }, - { MP_ROM_QSTR(MP_QSTR_ellipse), MP_ROM_PTR(&display_tft_drawEllipse_obj) }, - { MP_ROM_QSTR(MP_QSTR_arc), MP_ROM_PTR(&display_tft_drawArc_obj) }, - { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&display_tft_drawPoly_obj) }, - { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&display_tft_drawRect_obj) }, - { MP_ROM_QSTR(MP_QSTR_readScreen), MP_ROM_PTR(&display_tft_readScreen_obj) }, - { MP_ROM_QSTR(MP_QSTR_roundrect), MP_ROM_PTR(&display_tft_drawRoundRect_obj) }, - { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&display_tft_fillScreen_obj) }, - { MP_ROM_QSTR(MP_QSTR_clearwin), MP_ROM_PTR(&display_tft_fillWin_obj) }, - { MP_ROM_QSTR(MP_QSTR_font), MP_ROM_PTR(&display_tft_setFont_obj) }, - { MP_ROM_QSTR(MP_QSTR_fontSize), MP_ROM_PTR(&display_tft_getFontSize_obj) }, - { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&display_tft_print_obj) }, - { MP_ROM_QSTR(MP_QSTR_orient), MP_ROM_PTR(&display_tft_setRot_obj) }, - { MP_ROM_QSTR(MP_QSTR_textWidth), MP_ROM_PTR(&display_tft_stringWidth_obj) }, - { MP_ROM_QSTR(MP_QSTR_textClear), MP_ROM_PTR(&display_tft_clearStringRect_obj) }, - { MP_ROM_QSTR(MP_QSTR_attrib7seg), MP_ROM_PTR(&display_tft_7segAttrib_obj) }, - { MP_ROM_QSTR(MP_QSTR_image), MP_ROM_PTR(&display_tft_Image_obj) }, - { MP_ROM_QSTR(MP_QSTR_gettouch), MP_ROM_PTR(&display_tft_getTouch_obj) }, - { MP_ROM_QSTR(MP_QSTR_compileFont), MP_ROM_PTR(&display_tft_compileFont_obj) }, - { MP_ROM_QSTR(MP_QSTR_hsb2rgb), MP_ROM_PTR(&display_tft_HSBtoRGB_obj) }, - { MP_ROM_QSTR(MP_QSTR_setwin), MP_ROM_PTR(&display_tft_setclipwin_obj) }, - { MP_ROM_QSTR(MP_QSTR_resetwin), MP_ROM_PTR(&display_tft_resetclipwin_obj) }, - { MP_ROM_QSTR(MP_QSTR_savewin), MP_ROM_PTR(&display_tft_saveclipwin_obj) }, - { MP_ROM_QSTR(MP_QSTR_restorewin), MP_ROM_PTR(&display_tft_restoreclipwin_obj) }, - { MP_ROM_QSTR(MP_QSTR_screensize), MP_ROM_PTR(&display_tft_getSize_obj) }, - { MP_ROM_QSTR(MP_QSTR_winsize), MP_ROM_PTR(&display_tft_getWinSize_obj) }, - { MP_ROM_QSTR(MP_QSTR_setCalib), MP_ROM_PTR(&display_tft_setCalib_obj) }, - { MP_ROM_QSTR(MP_QSTR_getCalib), MP_ROM_PTR(&display_tft_getCalib_obj) }, - { MP_ROM_QSTR(MP_QSTR_backlight), MP_ROM_PTR(&display_tft_backlight_obj) }, - { MP_ROM_QSTR(MP_QSTR_getTouchType), MP_ROM_PTR(&display_tft_touch_type_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_fg), MP_ROM_PTR(&display_tft_get_fg_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_bg), MP_ROM_PTR(&display_tft_get_bg_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_fg), MP_ROM_PTR(&display_tft_set_fg_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_bg), MP_ROM_PTR(&display_tft_set_bg_obj) }, - { MP_ROM_QSTR(MP_QSTR_text_x), MP_ROM_PTR(&display_tft_get_X_obj) }, - { MP_ROM_QSTR(MP_QSTR_text_y), MP_ROM_PTR(&display_tft_get_Y_obj) }, - - { MP_ROM_QSTR(MP_QSTR_tft_setspeed), MP_ROM_PTR(&display_tft_set_speed_obj) }, - { MP_ROM_QSTR(MP_QSTR_tft_select), MP_ROM_PTR(&display_tft_select_obj) }, - { MP_ROM_QSTR(MP_QSTR_tft_deselect), MP_ROM_PTR(&display_tft_deselect_obj) }, - { MP_ROM_QSTR(MP_QSTR_tft_writecmd), MP_ROM_PTR(&display_tft_send_command_obj) }, - { MP_ROM_QSTR(MP_QSTR_tft_writecmddata), MP_ROM_PTR(&display_tft_send_cmd_data_obj) }, - { MP_ROM_QSTR(MP_QSTR_tft_readcmd), MP_ROM_PTR(&display_tft_cmd_read_obj) }, - - // class constants - { MP_ROM_QSTR(MP_QSTR_ST7789), MP_ROM_INT(DISP_TYPE_ST7789V) }, - { MP_ROM_QSTR(MP_QSTR_ILI9341), MP_ROM_INT(DISP_TYPE_ILI9341) }, - { MP_ROM_QSTR(MP_QSTR_ILI9488), MP_ROM_INT(DISP_TYPE_ILI9488) }, - { MP_ROM_QSTR(MP_QSTR_ST7735), MP_ROM_INT(DISP_TYPE_ST7735) }, - { MP_ROM_QSTR(MP_QSTR_ST7735R), MP_ROM_INT(DISP_TYPE_ST7735R) }, - { MP_ROM_QSTR(MP_QSTR_ST7735B), MP_ROM_INT(DISP_TYPE_ST7735B) }, - { MP_ROM_QSTR(MP_QSTR_M5STACK), MP_ROM_INT(DISP_TYPE_M5STACK) }, - { MP_ROM_QSTR(MP_QSTR_GENERIC), MP_ROM_INT(DISP_TYPE_GENERIC) }, - - { MP_ROM_QSTR(MP_QSTR_CENTER), MP_ROM_INT(CENTER) }, - { MP_ROM_QSTR(MP_QSTR_RIGHT), MP_ROM_INT(RIGHT) }, - { MP_ROM_QSTR(MP_QSTR_BOTTOM), MP_ROM_INT(BOTTOM) }, - { MP_ROM_QSTR(MP_QSTR_LASTX), MP_ROM_INT(LASTX) }, - { MP_ROM_QSTR(MP_QSTR_LASTY), MP_ROM_INT(LASTY) }, - - { MP_ROM_QSTR(MP_QSTR_PORTRAIT), MP_ROM_INT(PORTRAIT) }, - { MP_ROM_QSTR(MP_QSTR_LANDSCAPE), MP_ROM_INT(LANDSCAPE) }, - { MP_ROM_QSTR(MP_QSTR_PORTRAIT_FLIP), MP_ROM_INT(PORTRAIT_FLIP) }, - { MP_ROM_QSTR(MP_QSTR_LANDSCAPE_FLIP), MP_ROM_INT(LANDSCAPE_FLIP) }, - - { MP_ROM_QSTR(MP_QSTR_FONT_Default), MP_ROM_INT(DEFAULT_FONT) }, - { MP_ROM_QSTR(MP_QSTR_FONT_DejaVu18), MP_ROM_INT(DEJAVU18_FONT) }, - { MP_ROM_QSTR(MP_QSTR_FONT_DejaVu24), MP_ROM_INT(DEJAVU24_FONT) }, - { MP_ROM_QSTR(MP_QSTR_FONT_Ubuntu), MP_ROM_INT(UBUNTU16_FONT) }, - { MP_ROM_QSTR(MP_QSTR_FONT_Comic), MP_ROM_INT(COMIC24_FONT) }, - { MP_ROM_QSTR(MP_QSTR_FONT_Minya), MP_ROM_INT(MINYA24_FONT) }, - { MP_ROM_QSTR(MP_QSTR_FONT_Tooney), MP_ROM_INT(TOONEY32_FONT) }, - { MP_ROM_QSTR(MP_QSTR_FONT_Small), MP_ROM_INT(SMALL_FONT) }, - { MP_ROM_QSTR(MP_QSTR_FONT_DefaultSmall), MP_ROM_INT(DEF_SMALL_FONT) }, - { MP_ROM_QSTR(MP_QSTR_FONT_7seg), MP_ROM_INT(FONT_7SEG) }, - - { MP_ROM_QSTR(MP_QSTR_BLACK), MP_ROM_INT(iTFT_BLACK) }, - { MP_ROM_QSTR(MP_QSTR_NAVY), MP_ROM_INT(iTFT_NAVY) }, - { MP_ROM_QSTR(MP_QSTR_DARKGREEN), MP_ROM_INT(iTFT_DARKGREEN) }, - { MP_ROM_QSTR(MP_QSTR_DARKCYAN), MP_ROM_INT(iTFT_DARKCYAN) }, - { MP_ROM_QSTR(MP_QSTR_MAROON), MP_ROM_INT(iTFT_MAROON) }, - { MP_ROM_QSTR(MP_QSTR_PURPLE), MP_ROM_INT(iTFT_PURPLE) }, - { MP_ROM_QSTR(MP_QSTR_OLIVE), MP_ROM_INT(iTFT_OLIVE) }, - { MP_ROM_QSTR(MP_QSTR_LIGHTGREY), MP_ROM_INT(iTFT_LIGHTGREY) }, - { MP_ROM_QSTR(MP_QSTR_DARKGREY), MP_ROM_INT(iTFT_DARKGREY) }, - { MP_ROM_QSTR(MP_QSTR_BLUE), MP_ROM_INT(iTFT_BLUE) }, - { MP_ROM_QSTR(MP_QSTR_GREEN), MP_ROM_INT(iTFT_GREEN) }, - { MP_ROM_QSTR(MP_QSTR_CYAN), MP_ROM_INT(iTFT_CYAN) }, - { MP_ROM_QSTR(MP_QSTR_RED), MP_ROM_INT(iTFT_RED) }, - { MP_ROM_QSTR(MP_QSTR_MAGENTA), MP_ROM_INT(iTFT_MAGENTA) }, - { MP_ROM_QSTR(MP_QSTR_YELLOW), MP_ROM_INT(iTFT_YELLOW) }, - { MP_ROM_QSTR(MP_QSTR_WHITE), MP_ROM_INT(iTFT_WHITE) }, - { MP_ROM_QSTR(MP_QSTR_ORANGE), MP_ROM_INT(iTFT_ORANGE) }, - { MP_ROM_QSTR(MP_QSTR_GREENYELLOW), MP_ROM_INT(iTFT_GREENYELLOW) }, - { MP_ROM_QSTR(MP_QSTR_PINK), MP_ROM_INT(iTFT_PINK) }, - - { MP_ROM_QSTR(MP_QSTR_COLOR_BITS16), MP_ROM_INT(16) }, - { MP_ROM_QSTR(MP_QSTR_COLOR_BITS24), MP_ROM_INT(24) }, - - { MP_ROM_QSTR(MP_QSTR_JPG), MP_ROM_INT(IMAGE_TYPE_JPG) }, - { MP_ROM_QSTR(MP_QSTR_BMP), MP_ROM_INT(IMAGE_TYPE_BMP) }, - - { MP_ROM_QSTR(MP_QSTR_HSPI), MP_ROM_INT(HSPI_HOST) }, - { MP_ROM_QSTR(MP_QSTR_VSPI), MP_ROM_INT(VSPI_HOST) }, - - { MP_ROM_QSTR(MP_QSTR_TOUCH_NONE), MP_ROM_INT(TOUCH_TYPE_NONE) }, - { MP_ROM_QSTR(MP_QSTR_TOUCH_XPT), MP_ROM_INT(TOUCH_TYPE_XPT2046) }, - { MP_ROM_QSTR(MP_QSTR_TOUCH_STMPE), MP_ROM_INT(TOUCH_TYPE_STMPE610) }, -}; -STATIC MP_DEFINE_CONST_DICT(display_tft_locals_dict, display_tft_locals_dict_table); - -//====================================== -const mp_obj_type_t display_tft_type = { - { &mp_type_type }, - .name = MP_QSTR_TFT, - .print = display_tft_printinfo, - .make_new = display_tft_make_new, - .locals_dict = (mp_obj_t)&display_tft_locals_dict, -}; +#ifdef CONFIG_MICROPY_USE_TFT +extern const mp_obj_type_t display_tft_type; +#endif +#ifdef CONFIG_MICROPY_USE_EVE +extern const mp_obj_type_t display_eve_type; +#endif //=============================================================== STATIC const mp_rom_map_elem_t display_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_display) }, + #ifdef CONFIG_MICROPY_USE_TFT { MP_OBJ_NEW_QSTR(MP_QSTR_TFT), MP_ROM_PTR(&display_tft_type) }, + #endif + #ifdef CONFIG_MICROPY_USE_EVE + { MP_OBJ_NEW_QSTR(MP_QSTR_EVE), MP_ROM_PTR(&display_eve_type) }, + #endif }; //=============================================================================== @@ -1720,3 +63,4 @@ const mp_obj_module_t mp_module_display = { .globals = (mp_obj_dict_t*)&display_module_globals, }; +#endif diff --git a/MicroPython_BUILD/components/micropython/esp32/moddisplay_eve.c b/MicroPython_BUILD/components/micropython/esp32/moddisplay_eve.c new file mode 100644 index 00000000..c01041c4 --- /dev/null +++ b/MicroPython_BUILD/components/micropython/esp32/moddisplay_eve.c @@ -0,0 +1,4401 @@ +/* + * This file is part of the MicroPython ESP32 project, https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo + * + * The MIT License (MIT) + * + * Copyright (c) 2018 LoBo (https://github.com/loboris) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sdkconfig.h" + +#if CONFIG_MICROPY_USE_EVE + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "rom/ets_sys.h" +#include "esp_system.h" +#include "esp_task_wdt.h" +#include "esp_log.h" + +#include "py/obj.h" +#include "py/objarray.h" + +#include "driver/gpio.h" +#include "extmod/vfs_native.h" +#include "machine_hw_spi.h" +#include "modmachine.h" +#include "mphalport.h" +#include "tft/tft.h" +#include "moddisplay_tft.h" +#include "eve/FT8.h" + + +#define FT8_ENABLE_PNG_LOADING 1 +#define IMAGE_TYPE_PNG 0 +#define IMAGE_TYPE_JPG 1 +#define IMAGE_TYPE_RAW 2 +#define IMAGE_TYPE_BIN 3 +#define IMAGE_TYPE_NONE 4 + +typedef struct _display_eve_obj_t { + mp_obj_base_t base; + machine_hw_spi_obj_t *spi; + eve_config_t dconfig; + exspi_device_handle_t disp_spi_dev; + exspi_device_handle_t *disp_spi; + uint16_t width; + uint16_t height; + uint8_t in_list; +} display_eve_obj_t; + +typedef struct _eve_font_metrics_t { + uint8_t widths[EVE_FONT_WIDTHS_SIZE]; + uint32_t format; + uint32_t stride; + uint32_t width; + uint32_t height; + int32_t ptr; +} eve_font_metrics_t; + +typedef struct _font_eve_obj_t { + mp_obj_base_t base; + uint32_t addr; + uint32_t size; + eve_font_metrics_t metrics; + uint8_t handle; + uint8_t format; + uint8_t maxwidth; + uint8_t minwidth; + uint8_t nchars; + uint8_t firstc; + uint8_t loaded; +} font_eve_obj_t; + +typedef struct _image_eve_obj_t { + mp_obj_base_t base; + uint32_t addr; + uint32_t size; + uint16_t width; + uint16_t height; + uint8_t format; + uint8_t orig_fmt; + uint8_t loaded; +} image_eve_obj_t; + +typedef struct _console_eve_obj_t { + mp_obj_base_t base; + uint32_t addr; + uint32_t size; + uint32_t curr_addr; + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; + uint16_t rowbytes; + mp_float_t scale; + uint32_t fgcolor; + uint32_t bgcolor; + uint8_t vgacolor; + uint8_t rowspace; + uint8_t type; + uint8_t show_cursor; + uint8_t wrap; + uint8_t loaded; +} console_eve_obj_t; + +typedef struct _list_eve_obj_t { + mp_obj_base_t base; + uint32_t addr; + uint32_t size; + uint8_t loaded; +} list_eve_obj_t; + +typedef struct _ramg_objects_t { + uint16_t count; + uint16_t size; + void **objects; +} ramg_objects_t; + +const mp_obj_type_t display_eve_type; +const mp_obj_type_t font_eve_type; +const mp_obj_type_t image_eve_type; +const mp_obj_type_t list_eve_type; +const mp_obj_type_t console_eve_type; +const mp_obj_type_t tft_eve_type; + +static display_eve_obj_t *eve_obj = NULL; +static font_eve_obj_t *user_fonts[MAX_USER_FONTS] = {NULL}; +static ramg_objects_t ramg_objects = {0, 0, NULL}; +static uint16_t eve_cmd_start_addr = 0; +static int16_t loaded_lists = 0; +static int16_t loaded_images = 0; +static int16_t loaded_fonts = 0; + +extern uint8_t disp_used_spi_host; + +static const char* const ft8_prim[] = { + "BITMAPS", + "POINTS", + "LINES", + "LINE_STRIP", + "EDGE_STRIP_R", + "EDGE_STRIP_L", + "EDGE_STRIP_A", + "EDGE_STRIP_B", + "RECTS", + "?", +}; + +static const char* const ft8_imgtypes[] = { + "PNG", + "JPEG", + "RAW_COMPRESSED", + "RAW", +}; + +static const char* const ft8_bmp_formats[] = { + "ARGB1555", + "L1", + "L4", + "L8", + "RGB332", + "ARGB2", + "ARGB4", + "RGB565", + "PALETTED", + "TEXT8X8", + "TEXTVGA", + "BARGRAPH", +}; + +static const char TAG[] = "[ModEve]"; +static const uint8_t stride_factor[18] = {0, 4, 2, 1, 1, 1, 0, 0, 16, 1, 0, 1, 16, 16, 1, 1, 1, 3 }; + +//------------------------------------------------------------ +static int _check_jpeg(uint8_t *data, int *width, int *height) +{ + int tmp; + int idx = 0; + tmp = (data[idx]<<8) | data[idx+1]; + if (tmp != 0xFFD8) return -1; + idx += 2; + tmp = (data[idx]<<8) | data[idx+1]; + if (tmp != 0xFFE0) return -2; + idx += 2; + tmp = (data[idx]<<8) | data[idx+1]; // size + idx += 2; + if (memcmp(data+idx, "JFIF", 4)) return -3; + idx += (tmp-2); + + // segment + do { + if (data[idx] != 0xFF) return -4; + tmp = (data[idx]<<8) | data[idx+1]; + if (tmp == 0xFFC0) break; + idx += 2; + tmp = (data[idx]<<8) | data[idx+1]; // size + idx += tmp; + } while (idx < (254)); + + if (tmp != 0xFFC0) return -5; + if ((idx+8) > 256) return -6; + // get width and height + idx += 4; + if (data[idx] != 8) return -7; + idx++; + *height = (data[idx]<<8) | data[idx+1]; + idx += 2; + *width = (data[idx]<<8) | data[idx+1]; + return 0; +} + +#if FT8_ENABLE_PNG_LOADING +//------------------------------------------------------------ +static int _check_png(uint8_t *data, int *width, int *height) +{ + int idx = 0; + if (memcmp(data, "\x89PNG\x0d\x0a\x1a\x0a", 8)) return -1; + idx += 12; + if (memcmp(data+idx, "IHDR", 4)) return -2; + idx += 6; + *width = (data[idx] << 8) | data[idx+1]; + idx += 4; + *height = (data[idx] << 8) | data[idx+1]; + idx += 2; + if (data[idx] != 8) return -3; // only bit depth 8 is supported + idx++; + if (data[idx] == 4) return -4; // Grayscale and alpha not supported + return data[idx]; +} +#endif + +//--------------------------------------------------------------------------------------- +static int _check_avi(uint8_t *data, int *width, int *height, int* playtime, int *frames) +{ + int idx = 0; + if (memcmp(data, "RIFF", 4)) return -1; + idx = 8; + if (memcmp(data+idx, "AVI ", 4)) return -2; + if ((memcmp(data+108, "vidsMJPG", 8)) && (memcmp(data+108, "vidsmjpg", 8))) return -3; + memcpy(width, data+64, 4); + memcpy(height, data+68, 4); + uint32_t sec_between_frames, total_frames; + memcpy(&sec_between_frames, data+32, 4); + memcpy(&total_frames, data+48, 4); + uint64_t time = total_frames * sec_between_frames; + *playtime = time / 1000000; + *frames = total_frames; + + return 0; +} + +//------------------------------------------------------ +STATIC void spi_deinit_internal(display_eve_obj_t *self) +{ + if (self->disp_spi->handle) { + esp_err_t ret; + // Deinitialize display spi device(s) + ret = remove_extspi_device(self->disp_spi); + if (ret != ESP_OK) { + mp_raise_msg(&mp_type_OSError, "Error removing display device"); + } + + gpio_pad_select_gpio(self->dconfig.miso); + gpio_pad_select_gpio(self->dconfig.mosi); + gpio_pad_select_gpio(self->dconfig.sck); + + eve_spibus_is_init = 0; + spi_is_init = 0; + eve_obj = NULL; + } +} + +//----------------------------------- +static bool check_ramg(uint32_t size) +{ + if ((ft8_ramg_ptr+size) > (FT8_RAM_G_SIZE)) return false; + return true; +} + +//------------------------------------ +static bool add_ramg_object(void *obj) +{ + if (ramg_objects.count == ramg_objects.size) return false; + + void **obj_pos = ramg_objects.objects + (ramg_objects.count*sizeof(void*)); + *obj_pos = obj; + ramg_objects.count++; + obj_pos += sizeof(void*); + if (ramg_objects.count == ramg_objects.size) { + // add space for 16 new objects + void **tmp_ptr = realloc(ramg_objects.objects, (ramg_objects.size+16)*sizeof(void*)); + if (tmp_ptr) { + ramg_objects.objects = tmp_ptr; + ramg_objects.size += 16; + memset(obj_pos, 0, 16*sizeof(void*)); + } + } + return true; +} + +//--------------------------------------------------------------------------- +static void adjust_ramg_objects(void *this_obj, uint32_t addr, uint32_t size) +{ + void **obj_pos; + // delete this object + for (int i=0; i 0)memcpy(obj_pos, obj_pos+sizeof(void*), sizeof(ramg_objects_t) * obj_after_count); + // delete the last object + memset(ramg_objects.objects + (sizeof(void*) * (ramg_objects.count-1)), 0, sizeof(ramg_objects_t)); + ramg_objects.count--; + break; + } + } + // adjust the RAM_G addresses of the remaining objects + for (int i=0; itype == &font_eve_type) { + font_eve_obj_t *obj = (font_eve_obj_t *)ptr; + if (obj->addr > addr) { + obj->addr -= size; + obj->metrics.ptr -= size; + } + } + else if (base->type == &image_eve_type) { + image_eve_obj_t *obj = (image_eve_obj_t *)ptr; + if (obj->addr > addr) { + obj->addr -= size; + } + } + else if (base->type == &list_eve_type) { + list_eve_obj_t *obj = (list_eve_obj_t *)ptr; + if (obj->addr > addr) { + obj->addr -= size; + } + } + else if (base->type == &console_eve_type) { + console_eve_obj_t *obj = (console_eve_obj_t *)ptr; + if (obj->addr > addr) { + obj->addr -= size; + } + } + else if (base->type == &tft_eve_type) { + tft_eve_obj_t *obj = (tft_eve_obj_t *)ptr; + if (obj->addr > addr) { + obj->addr -= size; + } + } + } + } +} + +//------------------------------------------------ +static void print_objects(const mp_print_t *print) +{ + if (ramg_objects.count == 0) return; + void **obj_pos; + for (int i=0; itype == &font_eve_type) { + font_eve_obj_t *obj = (font_eve_obj_t *)ptr; + mp_printf(print, " %2d: Font, addr=%u, size=%u\n", i, obj->addr,obj->size); + } + else if (base->type == &image_eve_type) { + image_eve_obj_t *obj = (image_eve_obj_t *)ptr; + mp_printf(print, " %2d: Image, addr=%u, size=%u\n", i, obj->addr,obj->size); + } + else if (base->type == &list_eve_type) { + list_eve_obj_t *obj = (list_eve_obj_t *)ptr; + mp_printf(print, " %2d: List, addr=%u, size=%u\n", i, obj->addr,obj->size); + } + else if (base->type == &console_eve_type) { + console_eve_obj_t *obj = (console_eve_obj_t *)ptr; + mp_printf(print, " %2d: Console, addr=%u, size=%u\n", i, obj->addr,obj->size); + } + else if (base->type == &tft_eve_type) { + tft_eve_obj_t *obj = (tft_eve_obj_t *)ptr; + mp_printf(print, " %2d: Tft, addr=%u, size=%u\n", i, obj->addr,obj->size); + } + else { + mp_printf(print, " %2d: Unknown object type\n", i); + } + } + } +} + +//----------------------------------------------------------------------------------------------- +STATIC void display_eve_printinfo(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + display_eve_obj_t *self = self_in; + if (self->disp_spi->handle) { + if (eve_chip_id > 0) { + mp_printf(print, "EVE ( %dx%d, Type=FT%X, Ready: %s, Clk=%u Hz\n", + self->width, self->height, eve_chip_id, ((self->disp_spi->handle) ? "yes" : "no"), self->dconfig.speed); + mp_printf(print, " Pins: miso=%d, mosi=%d, clk=%d, cs=%d, pd=%d\n", self->dconfig.miso, self->dconfig.mosi, self->dconfig.sck, self->dconfig.cs, self->dconfig.pd); + mp_printf(print, " Free Objects RAM: %u (%u used)\n", FT8_RAM_G+FT8_RAM_G_SIZE-ft8_ramg_ptr, ft8_ramg_ptr); + mp_printf(print, " Loaded objects: fonts=%d, images=%d, lists=%d\n", loaded_fonts, loaded_images, loaded_lists); + print_objects(print); + mp_printf(print, " )"); + } + else { + mp_printf(print, "EVE ( FT8xx not detected )"); + } + } + else { + mp_printf(print, "EVE ( Not initialized )"); + } +} + +//--------------------------------------------------------------------------------------------- +STATIC void font_eve_printinfo(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + font_eve_obj_t *self = self_in; + if (self->loaded) { + mp_printf(print, "EVE_FONT ( handle=%d )\n", self->handle); + mp_printf(print, " Format: L%d\n", self->format); + mp_printf(print, " Stride: %d\n", self->metrics.stride); + mp_printf(print, " Font width: %d\n", self->metrics.width); + mp_printf(print, " Font height: %d\n", self->metrics.height); + mp_printf(print, " Max char width: %d\n", self->maxwidth); + mp_printf(print, " Min char width: %d\n", self->minwidth); + mp_printf(print, " RAM_G address: %u\n", self->addr); + mp_printf(print, " RAM_G size: %u\n", self->size); + mp_printf(print, " Data addr: %d\n", self->metrics.ptr); + mp_printf(print, " Number of chars: %d\n", self->nchars); + mp_printf(print, " First char: %d\n", self->firstc); + } + else { + mp_printf(print, "EVE_FONT ( Unloaded )"); + } +} + +//---------------------------------------------------------------------------------------------- +STATIC void image_eve_printinfo(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + image_eve_obj_t *self = self_in; + if (self->loaded) { + mp_printf(print, "EVE_IMAGE ( format=%s (from %s), addr=%u, size=%u, w=%d, h=%d )", + ft8_bmp_formats[self->format], ft8_imgtypes[self->orig_fmt], self->addr, self->size, self->width, self->height); + } + else { + mp_printf(print, "EVE_IMAGE ( Unloaded )"); + } +} + +//--------------------------------------------------------------------------------------------- +STATIC void list_eve_printinfo(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + list_eve_obj_t *self = self_in; + if (self->loaded) { + mp_printf(print, "EVE_LIST ( addr=%u, size=%u )", self->addr, self->size); + } + else { + mp_printf(print, "EVE_LIST ( Unloaded )"); + } +} + +//------------------------------------------------------------------------------------------------ +STATIC void console_eve_printinfo(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + console_eve_obj_t *self = self_in; + if (self->loaded) { + mp_printf(print, "EVE_CONSOLE_%s [%d * %d] ( addr=%u, size=%u, cursor: (%d,%d), row space=%d, scale=%1.2f )", + (self->type == FT8_TEXT8X8) ? "8x8" : "VGA", self->width, self->height, self->addr, self->size, self->x, self->y, self->rowspace, self->scale); + } + else { + mp_printf(print, "EVE_CONSOLE ( Unloaded )"); + } +} + +//-------------------------------------------------------------------------------------------- +STATIC void tft_eve_printinfo(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + tft_eve_obj_t *self = self_in; + if (self->loaded) { + mp_printf(print, "EVE_TFT_%s [%d * %d] ( addr=%u, size=%u )", + (self->type == FT8_RGB565) ? "RGB565" : "RGB332", self->width, self->height, self->addr, self->size); + } + else { + mp_printf(print, "EVE_TFT ( Unloaded )"); + } +} + +//-------------------------------------------- +static esp_err_t _EVE_calibrate(bool nvs_read) +{ + uint32_t cal_const = 0; + char calibs[16]; + esp_err_t err; + + if (nvs_read) { + // Get calibration values from NVS + if (mpy_nvs_handle == 0) err = ESP_FAIL; + for (int i=0; i<6; i++) { + sprintf(calibs, "eve_calib_%c", (char)(i+0x61)); + err = nvs_get_u32(mpy_nvs_handle, calibs, &cal_const); + if (err != ESP_OK) break; + FT8_memWrite32(REG_TOUCH_TRANSFORM_A + (i*4), cal_const); + } + return err; + } + + // Perform calibration + FT8_start_cmd_burst(); + FT8_cmd_dl(CMD_DLSTART); + FT8_cmd_dl(DL_CLEAR_RGB | 0x00e0e0e0); + FT8_cmd_dl(DL_CLEAR | CLR_COL | CLR_STN | CLR_TAG); + FT8_cmd_dl(DL_COLOR_RGB | 0x00000040); + FT8_cmd_text(400, 240, 28, FT8_OPT_CENTERX, "Please tap on the dot"); + FT8_cmd_calibrate(); + + FT8_cmd_dl(DL_DISPLAY); + FT8_cmd_dl(CMD_SWAP); + + FT8_end_cmd_burst(); + + bool res = FT8_cmd_execute(30000); + + FT8_start_cmd_burst(); + FT8_cmd_dl(CMD_DLSTART); + FT8_cmd_dl(DL_CLEAR_RGB); + FT8_cmd_dl(DL_CLEAR | CLR_COL | CLR_STN | CLR_TAG); + if (res) { + FT8_cmd_dl(DL_COLOR_RGB | 0x0000FF00); + FT8_cmd_text(400, 240, 28, FT8_OPT_CENTERX, "Calibration OK"); + } + else { + FT8_cmd_dl(DL_COLOR_RGB | 0x0000FF00); + FT8_cmd_text(400, 240, 28, FT8_OPT_CENTERX, "Calibration failed"); + } + FT8_cmd_dl(DL_DISPLAY); + FT8_cmd_dl(CMD_SWAP); + FT8_end_cmd_burst(); + FT8_cmd_execute(250); + + err = ESP_OK; + if (res) { + // Save calibration constants to NVS + for (int i=0; i<6; i++) { + cal_const = FT8_memRead32(REG_TOUCH_TRANSFORM_A + (i*4)); + sprintf(calibs, "eve_calib_%c", (char)(i+0x61)); + err = nvs_set_u32(mpy_nvs_handle, calibs, cal_const); + if (err != ESP_OK) break; + nvs_commit(mpy_nvs_handle); + } + } + + return err; +} + +//------------------------------------------------------- +static void _eve_rotate(display_eve_obj_t *self, int rot) +{ + FT8_start_cmd_burst(); + FT8_cmd_dl(CMD_DLSTART); + FT8_cmd_setrotate(rot); + FT8_cmd_dl(DL_DISPLAY); + FT8_end_cmd_burst(); + FT8_cmd_execute(250); + + if ((rot & 2)) { + // portrait, invert width/heigth + self->width = self->dconfig.height; + self->height = self->dconfig.width; + } + else { + // landscape + self->width = self->dconfig.width; + self->height = self->dconfig.height; + } +} + +// === EVE object constructor === +//--------------------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_eve_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) +{ + if (eve_obj) { + mp_raise_msg(&mp_type_OSError, "EVE object instance already exists!"); + } + display_eve_obj_t *self = m_new_obj(display_eve_obj_t); + memset(self, 0, sizeof(display_eve_obj_t)); + self->base.type = &display_eve_type; + self->spi = NULL; + self->disp_spi_dev.handle = NULL; + self->disp_spi_dev.cs = -1; + self->disp_spi_dev.dc = -1; + self->disp_spi_dev.selected = 0; + self->disp_spi = &self->disp_spi_dev; + eve_spi = NULL; + memset(user_fonts, 0, sizeof(user_fonts)); + ft8_ramg_ptr = FT8_RAM_G; + //list_ptr = EVE_STATIC_LIST; + ramg_objects.count = 0; + ramg_objects.size = 0; + if (ramg_objects.objects == NULL) { + ramg_objects.objects = malloc(16 * sizeof(uint32_t)); + if (ramg_objects.objects == NULL) { + mp_raise_msg(&mp_type_OSError, "Error creating EVE instance"); + } + } + ramg_objects.size = 16; + loaded_lists = 0; + loaded_images = 0; + eve_chip_id = 1; + eve_obj = self; + + return MP_OBJ_FROM_PTR(self); +} + +// ToDo: Change this +// -------------------- +static void _eve_logo() +{ + FT8_start_cmd_burst(); // start writing to the cmd-fifo as one stream of bytes, only sending the address once + FT8_cmd_dl(CMD_DLSTART); // start the display list + FT8_cmd_dl(CMD_LOGO); + FT8_cmd_dl(DL_DISPLAY); // End the display list. FT81X will ignore all the commands following this command. + FT8_cmd_dl(CMD_SWAP); // make this list active + FT8_end_cmd_burst(); // stop writing to the cmd-fifo + FT8_cmd_start(); + vTaskDelay(2500 / portTICK_RATE_MS); + + // Wait till both read & write pointer register are equal to zero + uint16_t wr, rd; + do { + wr = FT8_memRead16(REG_CMD_WRITE); + rd = FT8_memRead16(REG_CMD_READ); + } while ((wr != 0) && (wr != rd)); + FT8_get_cmdoffset(); +} + +//------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_eve_config(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_hsize, ARG_vsize, ARG_vsync0, ARG_vsync1, ARG_voffset, ARG_vcycle, ARG_hsync0, ARG_hsync1, ARG_hoffset, ARG_hcycle, ARG_pclkpol, ARG_swizzle, ARG_pclk, ARG_cspread, ARG_rzthresh, ARG_hascrystal,ARG_hasgt911 }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_hsize, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 800 } }, + { MP_QSTR_vsize, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 480 } }, + { MP_QSTR_vsync0, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_vsync1, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 2 } }, + { MP_QSTR_voffset, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 13 } }, + { MP_QSTR_vcycle, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 525 } }, + { MP_QSTR_hsync0, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_hsync1, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 20 } }, + { MP_QSTR_hoffset, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 64 } }, + { MP_QSTR_hcycle, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 952 } }, + + { MP_QSTR_pclkpol, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 1 } }, + { MP_QSTR_swizzle, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_pclk, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 2 } }, + { MP_QSTR_cspread, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_rzthresh, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 2000 } }, + { MP_QSTR_hascrystal, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = true } }, + { MP_QSTR_hasgt911, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = false } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + + self->dconfig.disp_config.hsize = args[ARG_hsize].u_int; + self->dconfig.disp_config.vsize = args[ARG_vsize].u_int; + self->dconfig.disp_config.vsync0 = args[ARG_vsync0].u_int; + self->dconfig.disp_config.vsync1 = args[ARG_vsync1].u_int; + self->dconfig.disp_config.voffset = args[ARG_voffset].u_int; + self->dconfig.disp_config.vcycle = args[ARG_vcycle].u_int; + self->dconfig.disp_config.hsync0 = args[ARG_hsync0].u_int; + self->dconfig.disp_config.hsync1 = args[ARG_hsync1].u_int; + self->dconfig.disp_config.hoffset = args[ARG_hoffset].u_int; + self->dconfig.disp_config.hcycle = args[ARG_hcycle].u_int; + self->dconfig.disp_config.pclkpol = args[ARG_pclkpol].u_int; + self->dconfig.disp_config.swizzle = args[ARG_swizzle].u_int; + self->dconfig.disp_config.pclk = args[ARG_pclk].u_int; + self->dconfig.disp_config.cspread = args[ARG_cspread].u_int; + self->dconfig.disp_config.touch_thresh = args[ARG_rzthresh].u_int; + self->dconfig.disp_config.has_crystal = args[ARG_hascrystal].u_bool; + self->dconfig.disp_config.has_GT911 = args[ARG_hasgt911].u_bool; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_eve_config_obj, 0, display_eve_config); + +//----------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_eve_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_host, ARG_width, ARG_height, ARG_speed, ARG_miso, ARG_mosi, ARG_clk, ARG_cs, ARG_pd, ARG_rot, ARG_splash }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_spihost, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = HSPI_HOST } }, + { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 800 } }, + { MP_QSTR_height, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 480 } }, + { MP_QSTR_speed, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 10000000 } }, + { MP_QSTR_miso, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_mosi, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_clk, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_cs, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_pd, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_rot, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_splash, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = false } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + esp_err_t ret; + + #ifdef CONFIG_FT8_USER_TYPE + + if ((self->dconfig.disp_config.hsize == 0) || (self->dconfig.disp_config.vsize == 0)) { + mp_raise_ValueError("EVE display not configured"); + } + + #else + + #if defined (FT8_HAS_CRYSTAL) + self->dconfig.disp_config.has_crystal = 1; + #else + self->dconfig.disp_config.has_crystal = 0; + #endif + #if defined (FT8_HAS_GT911) + self->dconfig.disp_config.has_GT911 = 1; + #else + self->dconfig.disp_config.has_GT911 = 0; + #endif + self->dconfig.disp_config.cspread = FT8_CSPREAD; + self->dconfig.disp_config.hcycle = FT8_HCYCLE; + self->dconfig.disp_config.hoffset = FT8_HOFFSET; + self->dconfig.disp_config.hsize = FT8_HSIZE; + self->dconfig.disp_config.hsync0 = FT8_HSYNC0; + self->dconfig.disp_config.hsync1 = FT8_HSYNC1; + self->dconfig.disp_config.pclk = FT8_PCLK; + self->dconfig.disp_config.pclkpol = FT8_PCLKPOL; + self->dconfig.disp_config.swizzle = FT8_SWIZZLE; + self->dconfig.disp_config.touch_thresh = FT8_TOUCH_RZTHRESH; + self->dconfig.disp_config.vcycle = FT8_VCYCLE; + self->dconfig.disp_config.voffset = FT8_VOFFSET; + self->dconfig.disp_config.vsize = FT8_VSIZE; + self->dconfig.disp_config.vsync0 = FT8_VSYNC0; + self->dconfig.disp_config.vsync1 = FT8_VSYNC1; + + self->dconfig.height = FT8_HSIZE; + self->dconfig.width = FT8_VSIZE; + #endif + + // === deinitialize display spi device if it was initialized === + if (self->disp_spi->handle) spi_deinit_internal(self); + + // === Get arguments === + if ((args[ARG_host].u_int != HSPI_HOST) && (args[ARG_host].u_int != VSPI_HOST)) { + mp_raise_ValueError("SPI host must be either HSPI(1) or VSPI(2)"); + } + if ((SPIbus_configs[VSPI_HOST] == NULL) && (args[ARG_host].u_int == VSPI_HOST)) { + mp_raise_ValueError("SPI host must be HSPI(1), VSPI(2) used by SPIRAM"); + } + + self->dconfig.host = args[ARG_host].u_int; + self->dconfig.width = args[ARG_width].u_int; // native display width + self->dconfig.height = args[ARG_height].u_int; // native display height + self->width = self->dconfig.width; + self->height = self->dconfig.height; + + self->dconfig.pd = args[ARG_pd].u_int; + + self->dconfig.miso = args[ARG_miso].u_int; + self->dconfig.mosi = args[ARG_mosi].u_int; + self->dconfig.sck = args[ARG_clk].u_int; + + self->dconfig.cs = args[ARG_cs].u_int; + + // ================================ + // ==== Initialize the Display ==== + ret = FT8_init(&self->dconfig, self->disp_spi); + if (ret != ESP_OK) { + mp_raise_msg(&mp_type_OSError, "Error initializing display"); + } + + disp_used_spi_host = args[ARG_host].u_int; + + // ==== Set SPI clock used for display operations ==== + self->dconfig.speed = spi_set_speed(self->disp_spi, args[ARG_speed].u_int); + + if (args[ARG_splash].u_bool) { + _eve_logo(); + } + + ret = _EVE_calibrate(true); + if (ret != ESP_OK) ret = _EVE_calibrate(false); + + if (ret == ESP_OK) { + if (args[ARG_rot].u_int >= 0) { + _eve_rotate(self, args[ARG_rot].u_int & 7); + } + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_eve_init_obj, 0, display_eve_init); + + +// Check if EVE object is initialized +// and if the functions can be executed in current context +//---------------------------------------------------------- +static void _check_inlist(display_eve_obj_t *self, uint8_t f) +{ + if ((eve_obj == NULL) || (eve_chip_id == 0) || (self->disp_spi->handle == NULL)) { + mp_raise_msg(&mp_type_OSError, "EVE object not initialized!"); + } + if ((f == 0) && (self->in_list)) { + mp_raise_ValueError("Can only be used outside display list"); + } + else if ((f == 1) && (self->in_list == 0)) { + mp_raise_ValueError("Display list not started"); + } +} + +// --------------------------------------------------------------- +STATIC mp_obj_t EVE_calibrate(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 0); + + esp_err_t err; + + if ((n_args > 1) && (mp_obj_is_true(args[1]))) { + err = _EVE_calibrate(true); + if (err == ESP_OK) return mp_const_true; + return mp_const_false; + } + + err = _EVE_calibrate(false); + + if (err == ESP_OK) return mp_const_true; + return mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_calibrate_obj, 1, 2, EVE_calibrate); + + +// ---------------------------------------------------------- +STATIC mp_obj_t EVE_rotate(mp_obj_t self_in, mp_obj_t rot_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 0); + + int rot = mp_obj_get_int(rot_in); + if ((rot < 0) || (rot > 7)) { + mp_raise_ValueError("Invalid rotation value"); + } + _eve_rotate(self, rot); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_rotate_obj, EVE_rotate); + +// Start creating display list +// -------------------------------------------- +STATIC mp_obj_t EVE_startlist(mp_obj_t self_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 0); + FT8_CP_reset(); + FT8_memWrite32(REG_CMD_DL, 0); + + eve_cmd_start_addr = eve_cmdOffset; + FT8_start_cmd_burst(); // start writing to the cmd-fifo as one stream of bytes, only sending the address once + FT8_cmd_dl(CMD_DLSTART); // start the display list + //FT8_cmd_dl(CMD_COLDSTART); + self->in_list = 1; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(EVE_startlist_obj, EVE_startlist); + +// End display list, make it active and show on display +// ----------------------------------------- +STATIC mp_obj_t EVE_endlist(mp_obj_t self_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 1); + FT8_cmd_dl(DL_DISPLAY); // End the display list. FT81X will ignore all the commands following this command. + FT8_cmd_dl(CMD_SWAP); // make this list active + + FT8_end_cmd_burst(); // stop writing to the cmd-fifo + bool res = FT8_cmd_execute(250); + self->in_list = 0; + + if (res) return mp_const_true; + return mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(EVE_endlist_obj, EVE_endlist); + +// End the current list and save it to static DL RAM +// Returns List object +// ------------------------------------------- +STATIC mp_obj_t EVE_savelist(mp_obj_t self_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 1); + // Execute current list + FT8_end_cmd_burst(); // stop writing to the cmd-fifo + bool res = FT8_cmd_execute(250); + self->in_list = 0; + if (!res) return mp_const_false; + + // Copy to static list + uint32_t list_size = FT8_memRead32(REG_CMD_DL) & 0x1FFF; + if (!check_ramg(list_size)) { + mp_raise_ValueError("No place to append list"); + } + FT8_cmd_memcpy(ft8_ramg_ptr, FT8_RAM_DL, list_size); + res = FT8_cmd_execute(250); + if (!res) return mp_const_false; + + // Create LIST instance object + list_eve_obj_t *list_obj = m_new_obj(list_eve_obj_t); + memset(list_obj, 0, sizeof(list_eve_obj_t)); + list_obj->base.type = &list_eve_type; + + list_obj->addr = ft8_ramg_ptr; + list_obj->size = list_size; + list_obj->loaded = 1; + + if (!add_ramg_object((void *)list_obj)) { + mp_raise_ValueError("Error adding ramg object"); + } + ft8_ramg_ptr += list_size; + loaded_lists++; + + return MP_OBJ_FROM_PTR(list_obj); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(EVE_savelist_obj, EVE_savelist); + + +// --------------------------------------------------------------- +STATIC mp_obj_t EVE_appendlist(mp_obj_t self_in, mp_obj_t list_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 1); + if (mp_obj_get_type(list_in) != &list_eve_type) { + mp_raise_ValueError("List object expected"); + } + + list_eve_obj_t *list = (list_eve_obj_t *)(list_in); + if (list->loaded == 0) { + mp_raise_ValueError("List unloaded"); + } + + FT8_cmd_append(list->addr, list->size); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_appendlist_obj, EVE_appendlist); + +// ----------------------------------------------------------- +STATIC mp_obj_t EVE_clear(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + uint32_t color = 0; + uint8_t alpha = 0; + if (n_args > 1) color = mp_obj_get_int(args[1]) & 0x00ffffff; + if (n_args > 2) alpha = mp_obj_get_int(args[2]) & 0xff; + FT8_cmd_dl(DL_CLEAR_RGB | color); + FT8_cmd_dl(CLEAR_COLOR_A(alpha)); + // clear the screen - this and the previous prevent artifacts between lists. + // Attributes are the color, stencil and tag buffers + FT8_cmd_dl(CLEAR(1,1,1)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_clear_obj, 1, 3, EVE_clear); + +// ----------------------------------------------------------- +STATIC mp_obj_t EVE_color(mp_obj_t self_in, mp_obj_t color_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 1); + mp_int_t color = mp_obj_get_int(color_in); + FT8_cmd_dl(DL_COLOR_RGB | ((uint32_t)color & 0x00ffffff)); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_color_obj, EVE_color); + +// ------------------------------------------------------------- +STATIC mp_obj_t EVE_fgcolor(mp_obj_t self_in, mp_obj_t color_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 1); + mp_int_t color = mp_obj_get_int(color_in); + FT8_cmd_fgcolor((uint32_t)color & 0x00ffffff); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_fgcolor_obj, EVE_fgcolor); + +// ------------------------------------------------------------- +STATIC mp_obj_t EVE_bgcolor(mp_obj_t self_in, mp_obj_t color_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 1); + mp_int_t color = mp_obj_get_int(color_in); + FT8_cmd_bgcolor((uint32_t)color & 0x00ffffff); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_bgcolor_obj, EVE_bgcolor); + +// ----------------------------------------------------------- +STATIC mp_obj_t EVE_alpha(mp_obj_t self_in, mp_obj_t alpha_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 1); + int alpha = mp_obj_get_int(alpha_in) & 0xFF; + FT8_cmd_dl(COLOR_A((uint8_t)alpha)); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_alpha_obj, EVE_alpha); + +// --------------------------------------------------------------- +STATIC mp_obj_t EVE_alphafunc(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + + uint8_t func = mp_obj_get_int(args[1]) & 7; + uint8_t ref = 0; + if (n_args > 2) ref = mp_obj_get_int(args[2]) & 255; + + FT8_cmd_dl(ALPHA_FUNC(func, ref)); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_alphafunc_obj, 2, 3, EVE_alphafunc); + +// ----------------------------------------------------------------- +STATIC mp_obj_t EVE_stencilfunc(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + + uint8_t func = mp_obj_get_int(args[1]) & 7; + uint8_t mask = mp_obj_get_int(args[2]) & 255; + uint8_t ref = 0; + if (n_args > 3) ref = mp_obj_get_int(args[3]) & 255; + + FT8_cmd_dl(STENCIL_FUNC(func, ref, mask)); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_stencilfunc_obj, 3, 4, EVE_stencilfunc); + +// ---------------------------------------------------------------- +STATIC mp_obj_t EVE_stencilmask(mp_obj_t self_in, mp_obj_t mask_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 1); + + uint8_t mask = mp_obj_get_int(mask_in) & 255; + + FT8_cmd_dl(STENCIL_MASK(mask)); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_stencilmask_obj, EVE_stencilmask); + +// ---------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_stencilop(mp_obj_t self_in, mp_obj_t sfail_in, mp_obj_t spass_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 1); + + uint8_t sfail = mp_obj_get_int(sfail_in) & 7; + uint8_t spass = mp_obj_get_int(sfail_in) & 7; + + FT8_cmd_dl(STENCIL_OP(sfail, spass)); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(EVE_stencilop_obj, EVE_stencilop); + +// --------------------------------------------------------------- +STATIC mp_obj_t EVE_colormask(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + + FT8_cmd_dl(COLOR_MASK(mp_obj_get_int(args[1]), mp_obj_get_int(args[2]), mp_obj_get_int(args[3]), mp_obj_get_int(args[4]))); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_colormask_obj, 5, 5, EVE_colormask); + +// ----------------------------------------------------------- +STATIC mp_obj_t EVE_blend(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + + FT8_cmd_dl(BLEND_FUNC(mp_obj_get_int(args[1]), mp_obj_get_int(args[2]))); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_blend_obj, 3, 3, EVE_blend); + +// ------------------------------------------------------------- +STATIC mp_obj_t EVE_backlight(mp_obj_t self_in, mp_obj_t bkl_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 0); + int bkl = mp_obj_get_int(bkl_in) & 0x7F; + FT8_memWrite8(REG_PWM_DUTY, bkl); // set the backlight + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_backlight_obj, EVE_backlight); + +// ---------------------------------------------------------------------- +STATIC mp_obj_t EVE_scale(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 1); + + float x = mp_obj_get_float(x_in); + float y = mp_obj_get_float(y_in); + int32_t ix = (uint32_t)(x * 65536); + int32_t iy = (uint32_t)(y * 65536); + + FT8_cmd_scale(ix, iy); + FT8_cmd_setmatrix(); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(EVE_scale_obj, EVE_scale); + +// ----------------------------------------------------------- +STATIC mp_obj_t EVE_point(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + + uint16_t x = mp_obj_get_int(args[1]); + uint16_t y = mp_obj_get_int(args[2]); + uint16_t r = mp_obj_get_int(args[3]); + + FT8_cmd_point(x, y, r); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_point_obj, 4, 4, EVE_point); + +// ------------------------------------------------------------ +STATIC mp_obj_t EVE_circle(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + + uint16_t x = mp_obj_get_int(args[1]); + uint16_t y = mp_obj_get_int(args[2]); + uint16_t r = mp_obj_get_int(args[3]); + uint32_t color = mp_obj_get_int(args[4]) & 0x00ffffff; + uint16_t lsize = 1; + if (n_args > 5) lsize = mp_obj_get_int(args[5]); + + // draw to alpha buffer + FT8_cmd_dl(COLOR_MASK(0, 0, 0, 1)); + FT8_cmd_dl(BLEND_FUNC(FT8_ONE, FT8_ONE_MINUS_SRC_ALPHA)); + FT8_cmd_point(x, y, r); // outer circle + FT8_cmd_dl(BLEND_FUNC(FT8_ZERO, FT8_ONE_MINUS_SRC_ALPHA)); + FT8_cmd_point(x, y, r-lsize); // inner circle + + // Draw outher circle from alpha buffer + FT8_cmd_dl(COLOR_MASK(1, 1, 1, 0)); + FT8_cmd_dl(BLEND_FUNC(FT8_DST_ALPHA, FT8_ONE)); + FT8_cmd_dl(DL_COLOR_RGB | color); + //FT8_cmd_rect(x-r, y-r, x+r, y+r, 1); + FT8_cmd_point(x, y, r); // outer circle + + //FT8_cmd_dl(COLOR_MASK(1, 1, 1, 1)); + FT8_cmd_dl(BLEND_FUNC(FT8_SRC_ALPHA, FT8_ONE_MINUS_SRC_ALPHA)); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_circle_obj, 5, 6, EVE_circle); + +// ---------------------------------------------------------- +STATIC mp_obj_t EVE_line(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + + uint16_t x0 = mp_obj_get_int(args[1]); + uint16_t y0 = mp_obj_get_int(args[2]); + uint16_t x1 = mp_obj_get_int(args[3]); + uint16_t y1 = mp_obj_get_int(args[4]); + uint16_t width = mp_obj_get_int(args[5]) & 255; + + FT8_cmd_line(x0, y0, x1, y1, width); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_line_obj, 6, 6, EVE_line); + +// ---------------------------------------------------------- +STATIC mp_obj_t EVE_rect(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + + uint16_t x0 = mp_obj_get_int(args[1]); + uint16_t y0 = mp_obj_get_int(args[2]); + uint16_t x1 = mp_obj_get_int(args[3]); + uint16_t y1 = mp_obj_get_int(args[4]); + uint16_t corner = 1; + if (n_args > 5) corner = mp_obj_get_int(args[5]) & 255; + + FT8_cmd_rect(x0, y0, x1, y1, corner); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_rect_obj, 5, 6, EVE_rect); + +// --------------------------------------------------------------- +STATIC mp_obj_t EVE_rectangle(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + + uint16_t lwidth = 1; + if (n_args > 5) lwidth = mp_obj_get_int(args[5]); + uint16_t data[10]; + uint16_t x0 = mp_obj_get_int(args[1]); + uint16_t y0 = mp_obj_get_int(args[2]); + uint16_t x1 = mp_obj_get_int(args[3]); + uint16_t y1 = mp_obj_get_int(args[4]); + data[0] = x0; + data[1] = y0; + data[2] = x1; + data[3] = y0; + data[4] = x1; + data[5] = y1; + data[6] = x0; + data[7] = y1; + data[8] = x0; + data[9] = y0; + + FT8_cmd_strip(data, 10, FT8_LINE_STRIP, lwidth); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_rectangle_obj, 5, 6, EVE_rectangle); + +// -------------------------------------------------------------- +STATIC mp_obj_t EVE_triangle(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + + uint16_t lwidth = 1; + if (n_args > 7) lwidth = mp_obj_get_int(args[7]); + uint16_t data[8]; + data[0] = mp_obj_get_int(args[1]); + data[1] = mp_obj_get_int(args[2]); + data[2] = mp_obj_get_int(args[3]); + data[3] = mp_obj_get_int(args[4]); + data[4] = mp_obj_get_int(args[5]); + data[5] = mp_obj_get_int(args[6]); + data[6] = mp_obj_get_int(args[1]); + data[7] = mp_obj_get_int(args[2]); + + FT8_cmd_strip(data, 8, FT8_LINE_STRIP, lwidth); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_triangle_obj, 7, 8, EVE_triangle); + +// ------------------------------------------------------------ +STATIC mp_obj_t EVE_strips(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + + uint16_t lwidth = 1; + if (n_args > 3) lwidth = mp_obj_get_int(args[3]); + + uint16_t type = mp_obj_get_int(args[1]); + + if (!MP_OBJ_IS_TYPE(args[2], &mp_type_array)) { + mp_raise_ValueError("array argument expected"); + } + mp_obj_array_t * arr = (mp_obj_array_t *)MP_OBJ_TO_PTR(args[2]); + if ((arr->typecode != 'h') && (arr->typecode == 'H')) { + mp_raise_ValueError("array argument of type 'h', 'H' or 'B' expected"); + } + if ((arr->len < 2) || ((arr->len % 2) != 0)) { + mp_raise_ValueError("array argument length must be even and >= 2"); + } + uint16_t *buff = (uint16_t *)arr->items; + + FT8_cmd_strip(buff, arr->len*2, type, lwidth); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_strips_obj, 3, 4, EVE_strips); + +// ----------------------------------------------------------------- +STATIC mp_obj_t EVE_scissorSize(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + + int16_t x = -1; + int16_t y = -1; + + uint16_t w = mp_obj_get_int(args[1]); + uint16_t h = mp_obj_get_int(args[2]); + if (n_args == 5) { + x = mp_obj_get_int(args[3]); + y = mp_obj_get_int(args[4]); + } + + FT8_cmd_dl(SCISSOR_SIZE(w, h)); + if ((x >= 0) && (y >= 0)) FT8_cmd_dl(SCISSOR_XY(x, y)); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_scissorSize_obj, 3, 5, EVE_scissorSize); + +// --------------------------------------------------------------- +STATIC mp_obj_t EVE_scissorXY(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 1); + + uint16_t x = mp_obj_get_int(args[3]); + uint16_t y = mp_obj_get_int(args[4]); + + FT8_cmd_dl(SCISSOR_XY(x, y)); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_scissorXY_obj, 3, 3, EVE_scissorXY); + +// -------------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_text(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_x, ARG_y, ARG_text, ARG_font, ARG_align }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_font, MP_ARG_INT, { .u_int = 20 } }, + { MP_QSTR_align, MP_ARG_INT, { .u_int = 0 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + _check_inlist(self, 1); + + int max_font = 31; + if (eve_chip_id >= 0x810) max_font = 43; + mp_int_t x = args[ARG_x].u_int; + mp_int_t y = args[ARG_y].u_int; + mp_int_t font = args[ARG_font].u_int; + uint32_t align = (uint32_t)args[ARG_align].u_int; + if ((font < 0) || (font > max_font)) { + mp_raise_ValueError("Unsupported font size"); + } + uint32_t allowed_opts = FT8_OPT_CENTERX | FT8_OPT_CENTERY | FT8_OPT_CENTER | FT8_OPT_RIGHTX; + if ((align & allowed_opts) != align) { + mp_raise_ValueError("Unsupported text align"); + } + const char *st = mp_obj_str_get_str(args[ARG_text].u_obj); + + if (font > 31) { + FT8_cmd_romfont(1, font); + font = 1; + } + FT8_cmd_text(x, y, font, align, st); + FT8_cmd_dl(NOP()); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_text_obj, 0, EVE_text); + +// -------------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_number(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_x, ARG_y, ARG_num, ARG_font, ARG_align, ARG_base }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_num, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_font, MP_ARG_INT, { .u_int = 20 } }, + { MP_QSTR_align, MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_base, MP_ARG_INT, { .u_int = -1 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + _check_inlist(self, 1); + + int max_font = 31; + if (eve_chip_id >= 0x810) max_font = 43; + mp_int_t x = args[ARG_x].u_int; + mp_int_t y = args[ARG_y].u_int; + mp_int_t font = args[ARG_font].u_int; + uint32_t align = (uint32_t)args[ARG_align].u_int; + if ((font < 0) || (font > max_font)) { + mp_raise_ValueError("Unsupported font size"); + } + uint32_t allowed_opts = FT8_OPT_CENTERX | FT8_OPT_CENTERY | FT8_OPT_CENTER | FT8_OPT_RIGHTX | FT8_OPT_SIGNED; + if ((align & allowed_opts) != align) { + mp_raise_ValueError("Unsupported number align"); + } + int32_t num = mp_obj_get_int(args[ARG_num].u_obj); + if (num < 0) align |= FT8_OPT_SIGNED; + if (font > 31) { + FT8_cmd_romfont(1, font); + font = 1; + } + + int base = 10; + if ((args[ARG_base].u_int > 1) && (args[ARG_base].u_int < 37) && (eve_chip_id >= 0x810)) { + base = args[ARG_base].u_int; + FT8_cmd_setbase(base); + } + FT8_cmd_number(x, y, font, align, num); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_number_obj, 0, EVE_number); + +// ---------------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_button(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_x, ARG_y, ARG_width, ARG_height, ARG_text, ARG_font, ARG_opt }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_font, MP_ARG_INT, { .u_int = 20 } }, + { MP_QSTR_opt, MP_ARG_INT, { .u_int = 0 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + _check_inlist(self, 1); + + mp_int_t x = args[ARG_x].u_int; + mp_int_t y = args[ARG_y].u_int; + mp_int_t width = args[ARG_width].u_int; + mp_int_t height = args[ARG_height].u_int; + mp_int_t font = args[ARG_font].u_int; + mp_int_t opt = args[ARG_opt].u_int; + if ((font < 0) || (font > 31)) { + mp_raise_ValueError("Unsupported font size"); + } + if ((opt != 0) && (opt != FT8_OPT_FLAT)) { + mp_raise_ValueError("Unsupported option"); + } + const char *st = mp_obj_str_get_str(args[ARG_text].u_obj); + + FT8_cmd_button(x, y, width, height, font, opt, st); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_button_obj, 0, EVE_button); + +//--------------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_toggle(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { ARG_x, ARG_y, ARG_width, ARG_state, ARG_text, ARG_font, ARG_opt }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_state, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_font, MP_ARG_INT, { .u_int = 20 } }, + { MP_QSTR_opt, MP_ARG_INT, { .u_int = 0 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + _check_inlist(self, 1); + + mp_int_t x = args[ARG_x].u_int; + mp_int_t y = args[ARG_y].u_int; + mp_int_t width = args[ARG_width].u_int; + mp_int_t state = args[ARG_state].u_int; + if (state) state = 65535; + mp_int_t font = args[ARG_font].u_int; + mp_int_t opt = args[ARG_opt].u_int; + if ((font < 0) || (font > 31)) { + mp_raise_ValueError("Unsupported font size"); + } + if ((opt != 0) && (opt != FT8_OPT_FLAT)) { + mp_raise_ValueError("Unsupported option"); + } + const char *st = mp_obj_str_get_str(args[ARG_text].u_obj); + + FT8_cmd_toggle(x, y, width, font, opt, state, st); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_toggle_obj, 0, EVE_toggle); + +//------------------------------------------------------------------------------------------ +STATIC mp_obj_t EVE_scrollbar(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { ARG_x, ARG_y, ARG_width, ARG_height, ARG_value, ARG_size, ARG_range, ARG_opt }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_size, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_range, MP_ARG_INT, { .u_int = 100 } }, + { MP_QSTR_opt, MP_ARG_INT, { .u_int = 0 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + _check_inlist(self, 1); + + mp_int_t x = args[ARG_x].u_int; + mp_int_t y = args[ARG_y].u_int; + mp_int_t width = args[ARG_width].u_int; + mp_int_t height = args[ARG_height].u_int; + mp_int_t value = args[ARG_value].u_int; + mp_int_t size = args[ARG_size].u_int; + if (size < 0) size = width / 5; + mp_int_t range = args[ARG_range].u_int; + mp_int_t opt = args[ARG_opt].u_int; + if ((opt != 0) && (opt != FT8_OPT_FLAT)) { + mp_raise_ValueError("Unsupported option"); + } + + FT8_cmd_scrollbar(x, y, width, height, opt, value, size, range); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_scrollbar_obj, 0, EVE_scrollbar); + +//---------------------------------------------------------------------------------------------------------- +STATIC void EVE_slider_progress(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t type) +{ + enum { ARG_x, ARG_y, ARG_width, ARG_height, ARG_value, ARG_range, ARG_opt }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_range, MP_ARG_INT, { .u_int = 100 } }, + { MP_QSTR_opt, MP_ARG_INT, { .u_int = 0 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + _check_inlist(self, 1); + + mp_int_t x = args[ARG_x].u_int; + mp_int_t y = args[ARG_y].u_int; + mp_int_t width = args[ARG_width].u_int; + mp_int_t height = args[ARG_height].u_int; + mp_int_t value = args[ARG_value].u_int; + mp_int_t range = args[ARG_range].u_int; + mp_int_t opt = args[ARG_opt].u_int; + if ((opt != 0) && (opt != FT8_OPT_FLAT)) { + mp_raise_ValueError("Unsupported option"); + } + + if (type) FT8_cmd_progress(x, y, width, height, opt, value, range); + else FT8_cmd_slider(x, y, width, height, opt, value, range); +} + +//--------------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_slider(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + EVE_slider_progress(n_args, pos_args, kw_args, 0); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_slider_obj, 0, EVE_slider); + +//----------------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_progress(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + EVE_slider_progress(n_args, pos_args, kw_args, 1); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_progress_obj, 0, EVE_progress); + +//------------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_keys(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { ARG_x, ARG_y, ARG_width, ARG_height, ARG_labels, ARG_font, ARG_opt }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_labels, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_font, MP_ARG_INT, { .u_int = 20 } }, + { MP_QSTR_opt, MP_ARG_INT, { .u_int = 0 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + _check_inlist(self, 1); + + mp_int_t x = args[ARG_x].u_int; + mp_int_t y = args[ARG_y].u_int; + mp_int_t width = args[ARG_width].u_int; + mp_int_t height = args[ARG_height].u_int; + mp_int_t font = args[ARG_font].u_int; + mp_int_t opt = args[ARG_opt].u_int; + const char *labels = mp_obj_str_get_str(args[ARG_labels].u_obj); + if ((font < 0) || (font > 31)) { + mp_raise_ValueError("Unsupported font size"); + } + if ((opt >= 32) && (opt < 128)) { + if (strchr(labels, opt) == NULL) { + mp_raise_ValueError("Unsupported option"); + } + } + else { + uint32_t allowed_opts = FT8_OPT_CENTERX | FT8_OPT_CENTERY | FT8_OPT_CENTER | FT8_OPT_RIGHTX | FT8_OPT_FLAT; + if ((opt & allowed_opts) != opt) { + mp_raise_ValueError("Unsupported option"); + } + } + + FT8_cmd_keys(x, y, width, height, font, opt, labels); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_keys_obj, 0, EVE_keys); + +// --------------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_clock(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_x, ARG_y, ARG_r, ARG_time, ARG_opt }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_time, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_opt, MP_ARG_INT, { .u_int = 0 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + _check_inlist(self, 1); + + mp_int_t x = args[ARG_x].u_int; + mp_int_t y = args[ARG_y].u_int; + mp_int_t r = args[ARG_r].u_int; + uint32_t opt = (uint32_t)args[ARG_opt].u_int; + uint32_t allowed_opts = FT8_OPT_FLAT | FT8_OPT_NOBACK | FT8_OPT_NOTICKS | FT8_OPT_NOPOINTER | FT8_OPT_NOSECS | FT8_OPT_NOHANDS; + if ((opt & allowed_opts) != opt) { + mp_raise_ValueError("Unsupported option"); + } + struct tm *tm_info; + struct tm tm_inf; + + if (args[ARG_time].u_obj != mp_const_none) { + mp_obj_t *time_items; + + mp_obj_get_array_fixed_n(args[1].u_obj, 8, &time_items); + + tm_inf.tm_year = mp_obj_get_int(time_items[0]) - 1900; + tm_inf.tm_mon = mp_obj_get_int(time_items[1]) - 1; + tm_inf.tm_mday = mp_obj_get_int(time_items[2]); + tm_inf.tm_hour = mp_obj_get_int(time_items[3]); + tm_inf.tm_min = mp_obj_get_int(time_items[4]); + tm_inf.tm_sec = mp_obj_get_int(time_items[5]); + tm_inf.tm_wday = mp_obj_get_int(time_items[6]) - 1; + tm_inf.tm_yday = mp_obj_get_int(time_items[7]) - 1; + tm_info = &tm_inf; + } + else { + time_t seconds; + time(&seconds); // get the time from the RTC + tm_info = localtime(&seconds); + } + + FT8_cmd_clock(x, y, r, opt, tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec, 0); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_clock_obj, 0, EVE_clock); + +// --------------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_gauge(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_x, ARG_y, ARG_r, ARG_major, ARG_minor, ARG_range, ARG_val, ARG_opt }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_major, MP_ARG_INT, { .u_int = 10 } }, + { MP_QSTR_minor, MP_ARG_INT, { .u_int = 2 } }, + { MP_QSTR_range, MP_ARG_INT, { .u_int = 100 } }, + { MP_QSTR_val, MP_ARG_INT, { .u_int = 50 } }, + { MP_QSTR_opt, MP_ARG_INT, { .u_int = 0 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + _check_inlist(self, 1); + + mp_int_t x = args[ARG_x].u_int; + mp_int_t y = args[ARG_y].u_int; + mp_int_t r = args[ARG_r].u_int; + mp_int_t major = args[ARG_major].u_int; + mp_int_t minor = args[ARG_minor].u_int; + mp_int_t val = args[ARG_val].u_int; + mp_int_t range = args[ARG_range].u_int; + uint32_t opt = (uint32_t)args[ARG_opt].u_int; + uint32_t allowed_opts = FT8_OPT_FLAT | FT8_OPT_NOBACK | FT8_OPT_NOTICKS | FT8_OPT_NOPOINTER ; + if ((opt & allowed_opts) != opt) { + mp_raise_ValueError("Unsupported option"); + } + + FT8_cmd_gauge(x, y, r, opt, major, minor, val, range); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_gauge_obj, 0, EVE_gauge); + +// ------------------------------------------------------------------------------------------ +STATIC mp_obj_t EVE_gradient(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_x0, ARG_y0, ARG_rgb0, ARG_x1, ARG_y1, ARG_rgb1 }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x0, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y0, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_rgb0, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_rgb1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + _check_inlist(self, 1); + + int16_t x0 = args[ARG_x0].u_int; + int16_t y0 = args[ARG_y0].u_int; + uint32_t rgb0 = args[ARG_rgb0].u_int; + int16_t x1 = args[ARG_x1].u_int; + int16_t y1 = args[ARG_y1].u_int; + uint32_t rgb1 = args[ARG_rgb1].u_int; + + FT8_cmd_gradient(x0, y0, rgb0, x1, y1, rgb1); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_gradient_obj, 0, EVE_gradient); + +// --------------------------------------------- +STATIC mp_obj_t EVE_getprops(mp_obj_t self_in) { + display_eve_obj_t *self = self_in; + _check_inlist(self, 0); + + uint32_t w, h, ptr; + uint16_t offset = FT8_cmd_getprops(0); + FT8_cmd_execute(250); + w = FT8_memRead32(FT8_RAM_CMD + offset); + offset += 4; + offset &= 0x0fff; + h = FT8_memRead32(FT8_RAM_CMD + offset); + offset += 4; + offset &= 0x0fff; + ptr = FT8_memRead32(FT8_RAM_CMD + offset); + + mp_obj_t tuple[3]; + tuple[0] = mp_obj_new_int(w); + tuple[1] = mp_obj_new_int(h); + tuple[2] = mp_obj_new_int(ptr); + + return mp_obj_new_tuple(3, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(EVE_getprops_obj, EVE_getprops); + +// ------------------------------------------------------------- +STATIC mp_obj_t EVE_fontinfo(mp_obj_t self_in, mp_obj_t font_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 0); + + if (mp_obj_get_type(font_in) == &font_eve_type) { + font_eve_printinfo(&mp_plat_print, font_in, PRINT_STR); + return mp_const_none; + } + + int fhandle = mp_obj_get_int(font_in); + if ((fhandle < MAX_USER_FONTS) && user_fonts[fhandle] != NULL) { + font_eve_printinfo(&mp_plat_print, user_fonts[fhandle], PRINT_STR); + return mp_const_none; + } + + // === ROM font, get metrics and print the font properties + if ((fhandle < 16) || (fhandle > ((eve_chip_id < 0x810) ? 31:34))) { + mp_raise_ValueError("Invalid font handle"); + } + + font_eve_obj_t font; + font.base.type = &font_eve_type; + // get the ROM fonts start address, fonts table starts at font 16 + uint32_t fp = FT8_memRead32(FT8_ROM_FONT_ADDR); + // calculate the address of the requested font + font.addr = fp + (EVE_FONT_METRICS_SIZE * (fhandle - 16)); + + // read the font metrics + FT8_memRead_buffer(font.addr, (uint8_t *)(&font.metrics.widths[0]), EVE_FONT_METRICS_SIZE); + + uint32_t fformat = font.metrics.format; + if (fformat == 17) fformat = 2; + else if (fformat == 2) fformat = 4; + else if (fformat == 3) fformat = 8; + font.minwidth = 99; + font.maxwidth = 0; + font.nchars = 0; + for (int i=0; i 0) { + font.nchars++; + if (font.firstc == 0) font.firstc = i; + if (font.metrics.widths[i] < font.minwidth) font.minwidth = font.metrics.widths[i]; + if (font.metrics.widths[i] > font.maxwidth) font.maxwidth = font.metrics.widths[i]; + } + } + font.handle = fhandle; + font.format = (uint8_t)fformat; + + font_eve_printinfo(&mp_plat_print, (mp_obj_t)&font, PRINT_STR); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_fontinfo_obj, EVE_fontinfo); + +// ------------------------------------------------------------- +STATIC mp_obj_t EVE_userfont(mp_obj_t self_in, mp_obj_t font_in) +{ + display_eve_obj_t *self = self_in; + _check_inlist(self, 1); + if (mp_obj_get_type(font_in) != &font_eve_type) { + mp_raise_ValueError("Font object expected"); + } + + font_eve_obj_t *font = (font_eve_obj_t *)(font_in); + if (font->loaded == 0) { + mp_raise_ValueError("Font unloaded"); + } + + if (eve_chip_id < 0x810) { + // For FT80x use CMD_SETFONT + FT8_cmd_dl(BEGIN(FT8_BITMAPS)); + FT8_cmd_dl(BITMAP_HANDLE(font->handle)); + FT8_cmd_dl(BITMAP_SOURCE(font->metrics.ptr)); + FT8_cmd_dl(BITMAP_LAYOUT(font->metrics.format, font->metrics.stride, font->metrics.height)); + FT8_cmd_dl(BITMAP_SIZE(FT8_NEAREST, FT8_BORDER, FT8_BORDER, font->metrics.width, font->metrics.height)); + FT8_cmd_setfont(font->handle, font->addr); + } + else { + // For FT81x use CMD_SETFONT2 + FT8_cmd_setbitmap(font->metrics.ptr, font->metrics.format, font->metrics.width, font->metrics.height); + FT8_cmd_setfont2(font->handle, font->addr, font->firstc); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_userfont_obj, EVE_userfont); + +// ------------------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_setbitmap(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_addr, ARG_x, ARG_y, ARG_width, ARG_height, ARG_format, ARG_wrapx, ARG_wrapy, ARG_filter, ARG_scalex, ARG_scaley }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_format, MP_ARG_INT, { .u_int = FT8_RGB565 } }, + { MP_QSTR_wrapx, MP_ARG_INT, { .u_int = FT8_BORDER } }, + { MP_QSTR_wrapy, MP_ARG_INT, { .u_int = FT8_BORDER } }, + { MP_QSTR_filter, MP_ARG_INT, { .u_int = FT8_NEAREST } }, + { MP_QSTR_scalex, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_scaley, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + _check_inlist(self, 1); + + uint32_t addr = args[ARG_addr].u_int; + int format = args[ARG_format].u_int; + if ((format < 0) || (format > 17) || (format == 8) || (format == 12) || (format == 13)) { + mp_raise_ValueError("Unsupported format"); + } + uint16_t width = args[ARG_width].u_int; + uint16_t height = args[ARG_height].u_int; + uint16_t x = args[ARG_x].u_int; + uint16_t y = args[ARG_y].u_int; + uint8_t wrapx = args[ARG_wrapx].u_int & 1; + uint8_t wrapy = args[ARG_wrapy].u_int & 1; + uint8_t filter = args[ARG_filter].u_int & 1; + mp_float_t fx=1.0, fy=1.0; + int32_t sx=0, sy=0; + uint16_t stride = (width*2) >> stride_factor[format]; + uint16_t sheight = height; + + if (args[ARG_scalex].u_obj != mp_const_none) { + fx = mp_obj_get_float(args[ARG_scalex].u_obj); + fy = fx; + if (args[ARG_scaley].u_obj != mp_const_none) { + fy = mp_obj_get_float(args[ARG_scaley].u_obj); + } + sx = (int32_t)round((fx * 65536)); + sy = (int32_t)round((fy * 65536)); + width = (int16_t)round((fx * width)); + sheight = (int16_t)round((fy * height)); + } + + FT8_cmd_dl(BITMAP_SOURCE(addr)); + if ((eve_chip_id >= 0x810)) FT8_cmd_dl(BITMAP_LAYOUT_H(stride>>10, height>>9)); + FT8_cmd_dl(BITMAP_LAYOUT(format, stride , height)); + if ((eve_chip_id >= 0x810)) FT8_cmd_dl(BITMAP_SIZE_H(width>>9, sheight>>9)); + FT8_cmd_dl(BITMAP_SIZE(filter, wrapx, wrapy, width, sheight)); + + FT8_cmd_dl(DL_BEGIN | FT8_BITMAPS); + if (sx != 0) { + FT8_cmd_dl(CMD_LOADIDENTITY); + FT8_cmd_scale(sx, sy); + FT8_cmd_setmatrix(); + } + FT8_cmd_dl(VERTEX2F(x*16, y*16)); + FT8_cmd_dl(DL_END); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_setbitmap_obj, 0, EVE_setbitmap); + +// ------------------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_showimage(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_x, ARG_y, ARG_img, ARG_wrapx, ARG_wrapy, ARG_filter, ARG_scalex, ARG_scaley }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_image, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_wrapx, MP_ARG_INT, { .u_int = FT8_BORDER } }, + { MP_QSTR_wrapy, MP_ARG_INT, { .u_int = FT8_BORDER } }, + { MP_QSTR_filter, MP_ARG_INT, { .u_int = FT8_NEAREST } }, + { MP_QSTR_scalex, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_scaley, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_eve_obj_t *self = pos_args[0]; + _check_inlist(self, 1); + + if (mp_obj_get_type(args[ARG_img].u_obj) != &image_eve_type) { + mp_raise_ValueError("Image object expected"); + } + + image_eve_obj_t *image = (image_eve_obj_t *)(args[ARG_img].u_obj); + if (image->loaded == 0) { + mp_raise_ValueError("Image unloaded"); + } + + uint16_t width = image->width; + uint16_t height = image->height; + uint16_t x = args[ARG_x].u_int; + uint16_t y = args[ARG_y].u_int; + uint8_t wrapx = args[ARG_wrapx].u_int & 1; + uint8_t wrapy = args[ARG_wrapy].u_int & 1; + uint8_t filter = args[ARG_filter].u_int & 1; + mp_float_t fx=1.0, fy=1.0; + int32_t sx=0, sy=0; + uint16_t stride = (width*2) >> stride_factor[image->format]; + uint16_t sheight = height; + + if (args[ARG_scalex].u_obj != mp_const_none) { + fx = mp_obj_get_float(args[ARG_scalex].u_obj); + fy = fx; + if (args[ARG_scaley].u_obj != mp_const_none) { + fy = mp_obj_get_float(args[ARG_scaley].u_obj); + } + sx = (int32_t)round((fx * 65536)); + sy = (int32_t)round((fy * 65536)); + width = (int16_t)round((fx * width)); + sheight = (int16_t)round((fy * height)); + } + + FT8_cmd_dl(BITMAP_SOURCE(image->addr)); + if ((eve_chip_id >= 0x810)) FT8_cmd_dl(BITMAP_LAYOUT_H(stride>>10, height>>9)); + FT8_cmd_dl(BITMAP_LAYOUT(image->format, stride , height)); + if ((eve_chip_id >= 0x810)) FT8_cmd_dl(BITMAP_SIZE_H(width>>9, sheight>>9)); + FT8_cmd_dl(BITMAP_SIZE(filter, wrapx, wrapy, width, sheight)); + + FT8_cmd_dl(DL_BEGIN | FT8_BITMAPS); + if (sx != 0) { + FT8_cmd_dl(CMD_LOADIDENTITY); + FT8_cmd_scale(sx, sy); + FT8_cmd_setmatrix(); + } + FT8_cmd_dl(VERTEX2F(x*16, y*16)); + FT8_cmd_dl(DL_END); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_showimage_obj, 0, EVE_showimage); + +//------------------------------------------------------------------------------------------ +STATIC mp_obj_t EVE_playvideo(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { ARG_file, ARG_opt, ARG_mode, ARG_vol }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_opt, MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_mode, MP_ARG_INT, { .u_int = 1 } }, + { MP_QSTR_vol, MP_ARG_INT, { .u_int = -1 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + //display_eve_obj_t *self = pos_args[0]; + + if (eve_chip_id < 0x810) { + mp_raise_ValueError("Not supported on FT80x"); + } + + _check_inlist(eve_obj, 0); + + uint32_t addr = ft8_ramg_ptr; + int size=0, frames=0; + char *fname = NULL; + char fullname[128] = {'\0'}; + struct stat sb; + fname = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); + uint32_t allowed_opts = FT8_OPT_MONO | FT8_OPT_MEDIAFIFO | FT8_OPT_NOTEAR | FT8_OPT_SOUND | FT8_OPT_FULLSCREEN; + uint32_t opt = args[ARG_opt].u_int & allowed_opts; + opt |= FT8_OPT_MEDIAFIFO; + uint32_t mode = args[ARG_mode].u_int; + + int res = physicalPath(fname, fullname); + if ((res != 0) || (strlen(fullname) == 0)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error resolving file name")); + } + + if (stat(fullname, &sb) != 0) { + mp_raise_ValueError("Error getting file info"); + } + int file_len = sb.st_size; + + // try to determine image type + FILE *fhndl = fopen(fullname, "rb"); + if (fhndl == NULL) { + mp_raise_ValueError("Error opening file"); + } + + int width=0, height=0, time=0; + uint8_t buf[256]; + if (fread(buf, 1, 256, fhndl) == 256) { + buf[255] = 0; + res = _check_avi(buf, &width, &height, &time, &frames); + if (res != 0) { + fclose(fhndl); + mp_raise_ValueError("Wriong file format, only MJPEG AVI files are supported"); + } + size = width*height * 2; + if (size > (FT8_RAM_G_SIZE-addr-65536-4)) { + fclose(fhndl); + mp_raise_ValueError("No space left in Eve RAM"); + } + } + else { + fclose(fhndl); + mp_raise_ValueError("Error reading file info"); + } + fseek(fhndl, 0, SEEK_SET); + + if (args[ARG_vol].u_int > 0) FT8_memWrite8(REG_VOL_PB, args[ARG_vol].u_int & 0xFF); // set audio volume + + res = FT8_Fifo_init(fhndl); + if (res != 0) { + fclose(fhndl); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error initializing mediafifo")); + } + + res = FT8_sendDataViaMediafifo(fhndl, addr, opt, (uint8_t)mode); + if (res < 0) return mp_const_false; + + if (mode == 2) { + mp_obj_t tuple[5]; + tuple[0] = mp_obj_new_int(width); + tuple[1] = mp_obj_new_int(height); + tuple[2] = mp_obj_new_int(time); + tuple[3] = mp_obj_new_int(addr); + tuple[4] = mp_obj_new_int(frames); + + return mp_obj_new_tuple(5, tuple); + } + + FT8_Fifo_deinit(); + ESP_LOGD(TAG, "PlayVideo: file length=%d, played=%d\n", file_len, file_len - ft8_stFifo.file_remain); + + fclose(fhndl); + + return mp_const_true; + +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_playvideo_obj, 0, EVE_playvideo); + +// --------------------------------------------------------------- +STATIC mp_obj_t EVE_videoframe(mp_obj_t self_in, mp_obj_t addr_in) +{ + //display_eve_obj_t *self = self_in; + _check_inlist(eve_obj, 1); + + uint32_t addr = mp_obj_get_int(addr_in); + FT8_cmd_videoframe(addr); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_videoframe_obj, EVE_videoframe); + +// --------------------------------------------- +STATIC mp_obj_t EVE_lastframe(mp_obj_t self_in) +{ + //display_eve_obj_t *self = self_in; + _check_inlist(eve_obj, 0); + + if (FT8_memRead32(ft8_stFifo.fifo_buff-4)) return mp_const_false; + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(EVE_lastframe_obj, EVE_lastframe); + +// ---------------------------------------------- +STATIC mp_obj_t EVE_videobuffer(mp_obj_t self_in) +{ + //display_eve_obj_t *self = self_in; + _check_inlist(eve_obj, 0); + + int res = FT8_Fifo_service(); + if (res < 0) { + ESP_LOGE(TAG, "Error in Fifo service"); + FT8_CP_reset(); + return mp_obj_new_int(res); + } + + return mp_obj_new_int(ft8_stFifo.file_remain); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(EVE_videobuffer_obj, EVE_videobuffer); + +// --------------------------------------------- +STATIC mp_obj_t EVE_closevideo(mp_obj_t self_in) +{ + //display_eve_obj_t *self = self_in; + _check_inlist(eve_obj, 0); + + if (ft8_stFifo.pFile) fclose(ft8_stFifo.pFile); + FT8_Fifo_deinit(); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(EVE_closevideo_obj, EVE_closevideo); + + +// ---------------------------------------------------------- +STATIC mp_obj_t EVE_vol_pb(mp_obj_t self_in, mp_obj_t vol_in) +{ + _check_inlist(eve_obj, 0); + + uint8_t volume = mp_obj_get_int(vol_in) & 0xFF; + FT8_memWrite8(REG_VOL_PB, volume); // set audio volume + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_vol_pb_obj, EVE_vol_pb); + +// ------------------------------------------------------------- +STATIC mp_obj_t EVE_vol_sound(mp_obj_t self_in, mp_obj_t vol_in) +{ + _check_inlist(eve_obj, 0); + + uint8_t volume = mp_obj_get_int(vol_in) & 0xFF; + FT8_memWrite8(REG_VOL_SOUND, volume); // set sound volume + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_vol_sound_obj, EVE_vol_sound); + +// ------------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_sound(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { ARG_effect, ARG_note, ARG_vol, ARG_wait }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_effect, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 255 } }, + { MP_QSTR_note, MP_ARG_INT, { .u_int = 84 } }, + { MP_QSTR_vol, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_wait, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + _check_inlist(eve_obj, 0); + + + int effect = args[ARG_effect].u_int; + int note = args[ARG_note].u_int; + if ((note < 21) || (note > 108)) { + mp_raise_ValueError("Invalid MIDI note"); + } + + int effect_type = -1; + if (effect == 0) effect_type = 2; // silence + else if (effect < 0x09) effect_type = 3; // waves and effects + else if ((effect >= 0x10) && (effect <= 0x1F)) effect_type = 1; // pips + else if ((effect == 0x23) || (effect == 0x2C) || ((effect >= 0x30) && (effect <= 0x39))) effect_type = 2; // DTMF tones + else if ((effect >= 0x40) && (effect <= 0x49)) effect_type = 1; // instruments + else if ((effect >= 0x50) && (effect <= 0x58)) effect_type = 0; // sound effects + else if ((effect == 0x60) || (effect == 0x61)) effect_type = 0; // mute/unmute + if (effect_type < 0) { + mp_raise_ValueError("Invalid sound effect"); + } + + uint16_t sound = effect; + if (effect_type & 1) sound |= (note << 8); // has pitch/note + + // stop the previous sound + //FT8_memWrite16(REG_SOUND, 0); + //FT8_memWrite8(REG_PLAY, 1); + + if (args[ARG_vol].u_int >= 0) { + // set the sound volume + FT8_memWrite8(REG_VOL_SOUND, args[ARG_vol].u_int & 0xFF); + } + + // start the sound effect + FT8_memWrite16(REG_SOUND, sound); + FT8_memWrite8(REG_PLAY, 1); + + if (args[ARG_wait].u_int > 0) { + if (effect_type & 2) { + // coutinuous sound, wait for given time + mp_hal_delay_ms(args[ARG_wait].u_int); + FT8_memWrite16(REG_SOUND, 0x60); // mute + FT8_memWrite8(REG_PLAY, 1); + } + else { + // non continuous sound, wait untill finished + while (FT8_memRead8(REG_PLAY)) { + mp_hal_delay_ms(3); + } + } + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(EVE_sound_obj, 0, EVE_sound); + +// ---------------------------------------------------------------------------- +// ---- List dump methods ----------------------------------------------------- +// ---------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +static uint16_t process_eve_command(uint32_t cmd, uint32_t base, uint16_t *idx) +{ + uint16_t proc_bytes = 4; + uint32_t ccmd = cmd & 0xFF000000; + *idx += 4; + *idx &= 0xfff; + if (cmd == DL_DISPLAY) mp_printf(&mp_plat_print, "DISPLAY (End Display List)\n"); + else if (ccmd == DL_CLEAR_RGB) mp_printf(&mp_plat_print, "CLEAR_COLOR_RGB (0x%06x)\n", cmd & 0xFFFFFF); + else if (ccmd == DL_CLEAR) mp_printf(&mp_plat_print, "CLEAR (%d, %d, %d)\n", (cmd>>2)&1, (cmd>>1)&1, cmd&1); + else if (ccmd == DL_CLEAR) mp_printf(&mp_plat_print, "CLEAR (%d, %d, %d)\n", (cmd>>2)&1, (cmd>>1)&1, cmd&1); + else if (ccmd == 0x0F000000) mp_printf(&mp_plat_print, "CLEAR_COLOR_A (%d)\n", cmd & 0xFF); + else if (ccmd == 0x11000000) mp_printf(&mp_plat_print, "CLEAR_STENCIL (%d)\n", cmd & 0xFF); + else if (ccmd == 0x12000000) mp_printf(&mp_plat_print, "CLEAR_TAG (%d)\n", cmd & 0xFF); + else if (ccmd == 0x03000000) mp_printf(&mp_plat_print, "TAG (%d)\n", cmd & 0xFF); + else if (ccmd == 0x01400000) mp_printf(&mp_plat_print, "TAG_MASK (%d)\n", cmd & 1); + else if (ccmd == DL_POINT_SIZE) mp_printf(&mp_plat_print, "POINT_SIZE (%d)\n", cmd & 8192); + else if (ccmd == 0x0E000000) mp_printf(&mp_plat_print, "LINE_WIDTH (%d)\n", cmd & 4095); + else if (ccmd == DL_END) mp_printf(&mp_plat_print, "END\n"); + else if (ccmd == DL_BEGIN) { + if (((cmd & 0x0F)-1) < 9) mp_printf(&mp_plat_print, "BEGIN %s\n", ft8_prim[(cmd & 0x0F)-1]); + else mp_printf(&mp_plat_print, "BEGIN ? (%d)\n", cmd & 0x0F); + } + else if (ccmd == 0x01000000) mp_printf(&mp_plat_print, "BITMAP_SOURCE (%d)\n", cmd & 0xFFFFFF); + else if (ccmd == 0x07000000) mp_printf(&mp_plat_print, "BITMAP_LAYOUT (%d, %d, %d)\n", (cmd>>19)&31, (cmd>>9)&1023, cmd&511); + else if (ccmd == 0x28000000) mp_printf(&mp_plat_print, "BITMAP_LAYOUT_H (%d, %d)\n", (cmd>>2)&3, cmd&3); + else if (ccmd == 0x29000000) mp_printf(&mp_plat_print, "BITMAP_SIZE_H (%d, %d)\n", (cmd>>2)&3, cmd&3); + else if (ccmd == 0x08000000) mp_printf(&mp_plat_print, "BITMAP_SIZE (%d, %d, %d, %d, %d)\n", (cmd>>20)&1, (cmd>>19)&1, (cmd>>18)&1, (cmd>>9)&512, cmd&511); + else if (ccmd == 0x05000000) mp_printf(&mp_plat_print, "BITMAP_HANDLE (%0d)\n", cmd & 31); + else if (ccmd == 0x2A000000) mp_printf(&mp_plat_print, "PALETTE_SOURCE (%d)\n", cmd & 0x3FFFFF); + else if (ccmd == 0x2B000000) mp_printf(&mp_plat_print, "VERTEX_TRANSLATE_X (%d)\n", cmd & 131071); + else if (ccmd == 0x2C000000) mp_printf(&mp_plat_print, "VERTEX_TRANSLATE_Y (%d)\n", cmd & 131071); + else if (ccmd == 0x0b000000) mp_printf(&mp_plat_print, "BLEND_FUNC (%d, %d)\n", (cmd>>3)&7, cmd&7); + else if (ccmd == 0x09000000) mp_printf(&mp_plat_print, "ALPHA_FUNC (%d, %d)\n", (cmd>>8)&7, cmd&255); + else if (ccmd == 0x10000000) mp_printf(&mp_plat_print, "COLOR_A (%d)\n", cmd&255); + else if (ccmd == 0x20000000) mp_printf(&mp_plat_print, "COLOR_MASK (%d, %d, %d, %d)\n", (cmd>>3)&1, (cmd>>2)&1, (cmd>>1)&1, cmd&1); + else if (ccmd == 0x04000000) mp_printf(&mp_plat_print, "COLOR_RGB (%d, %d, %d)\n", (cmd>>16)&255, (cmd>>8)&255, cmd&255); + else if (ccmd == 0x22000000) mp_printf(&mp_plat_print, "SAVE_CONTEXT\n"); + else if (ccmd == 0x23000000) mp_printf(&mp_plat_print, "RESTORE_CONTEXT\n"); + else if ((ccmd >= 0x15000000) && (ccmd <= 0x1A000000)) mp_printf(&mp_plat_print, "BITMAP_TRANSFORM_%c (%d)\n", 65+((ccmd>>24)-0x15), cmd&131071); + else if (ccmd == NOP()) mp_printf(&mp_plat_print, "NOP\n"); + else if ((cmd & 0xC0000000) == 0x40000000) mp_printf(&mp_plat_print, "VERTEX2F (%d, %d)\n", (cmd >> 15)&32767, cmd&32767); + else if ((cmd & 0xC0000000) == 0x80000000) mp_printf(&mp_plat_print, "VERTEXII (%d, %d, %d, %d)\n", (cmd >> 21)&0x1FF, (cmd >> 12)&0x1FF, (cmd >> 7)&31, cmd&127); + else { + uint16_t j = *idx; + switch (cmd) { + case (CMD_DLSTART): + mp_printf(&mp_plat_print, "CMD_DLSTART\n"); + break; + case (CMD_SWAP): + mp_printf(&mp_plat_print, "CMD_SWAP\n"); + break; + case (CMD_LOADIDENTITY): + mp_printf(&mp_plat_print, "CMD_LOADIDENTITY\n"); + break; + case (CMD_SETMATRIX): + mp_printf(&mp_plat_print, "CMD_SETMATRIX\n"); + break; + case (CMD_SCALE): { + mp_printf(&mp_plat_print, "CMD_SCALE\n"); + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "(%1.3f,", (float)(cmd / 65536.0)); + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "%1.3f)\n", (float)(cmd / 65536.0)); + j += 4; + j &= 0xfff; + proc_bytes += 4; + } + break; + case (CMD_COLDSTART): + mp_printf(&mp_plat_print, "CMD_COLDSTART\n"); + break; + case (CMD_FGCOLOR): { + mp_printf(&mp_plat_print, "CMD_FGCOLOR "); + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "(0x%06x)\n", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + } + break; + case (CMD_BGCOLOR): { + mp_printf(&mp_plat_print, "CMD_BGCOLOR "); + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "(0x%06x)\n", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + } + break; + case (CMD_INFLATE): { + mp_printf(&mp_plat_print, "CMD_INFLATE "); + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "(%d)\n", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + } + break; + case (CMD_GETPTR): { + mp_printf(&mp_plat_print, "CMD_GETPTR "); + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "(%d)\n", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + } + break; + case (CMD_LOADIMAGE): { + mp_printf(&mp_plat_print, "CMD_LOADIMAGE "); + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "(%d,", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "%d)\n", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + } + break; + case (CMD_MEDIAFIFO): { + mp_printf(&mp_plat_print, "CMD_MEDIAFIFO "); + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "(%d,", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "%d)\n", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + } + break; + case (CMD_GETPROPS): { + mp_printf(&mp_plat_print, "CMD_GETPROPS "); + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "(addr=%d, ", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "w=%d, ", cmd & 0xfff); + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "h=%d)\n", cmd & 0xfff); + j += 4; + j &= 0xfff; + proc_bytes += 4; + } + break; + case (CMD_APPEND): { + mp_printf(&mp_plat_print, "CMD_APPEND "); + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "(%d,", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "%d)\n", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + } + break; + case (CMD_SETBITMAP): { + mp_printf(&mp_plat_print, "CMD_SETBITMAP "); + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "(addr=%d, ", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "fmt=%d, w=%d, ", cmd & 0xffff, cmd >> 16); + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "h=%d)\n", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + } + break; + case (CMD_TEXT): { + mp_printf(&mp_plat_print, "CMD_TEXT "); + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "(%d,%d), ", cmd & 0xFFFF, cmd >> 16); + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "f=%d, opt=%d\n", cmd & 0xFFFF, cmd >> 16); + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, " '"); + while (cmd != NOP()) { + char *txt = (char *)&cmd; + for (int k=0; k<4; k++) { + char ch = *txt++; + if ((ch > 0) && (ch < 32)) ch = '.'; + if (ch > 0) { + if (ch >= 32) mp_printf(&mp_plat_print, "%c", ch); + else mp_printf(&mp_plat_print, "\\x%2x", ch); + } + } + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + } + mp_printf(&mp_plat_print, "'\n"); + } + break; + case (CMD_SETFONT): { + mp_printf(&mp_plat_print, "CMD_SETFONT: "); + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "(font=%d, ", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "addr=%d)\n", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + } + break; + case (CMD_SETFONT2): { + mp_printf(&mp_plat_print, "CMD_SETFONT2: "); + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "(font=%d, ", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "addr=%d, ", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + cmd = FT8_memRead32(base + j); + mp_printf(&mp_plat_print, "1st char=%d)\n", cmd); + j += 4; + j &= 0xfff; + proc_bytes += 4; + } + break; + default: + mp_printf(&mp_plat_print, "[%08x]\n", cmd); + } + *idx = j; + } + return proc_bytes; +} + +// ------------------------------------------------------------- +STATIC mp_obj_t EVE_dumpcmd(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 0); + + bool verbose = true; + if (n_args > 1) verbose = mp_obj_is_true(args[1]); + int list_size; + if (eve_cmdOffset < eve_cmd_start_addr) list_size = FT8_CMDFIFO_SIZE-eve_cmd_start_addr + eve_cmdOffset; + else list_size = eve_cmdOffset-eve_cmd_start_addr; + uint32_t cmd; + uint16_t idx = eve_cmd_start_addr; + + mp_printf(&mp_plat_print, "Command buffer content, size = %d\n", list_size); + while (list_size > 0) { + cmd = FT8_memRead32(FT8_RAM_CMD + idx); + if (verbose) { + mp_printf(&mp_plat_print, "%04d: ", idx); + list_size -= process_eve_command(cmd, FT8_RAM_CMD, &idx); + } + else { + mp_printf(&mp_plat_print, "%04d: %08x\n", idx, cmd); + idx += 4; + list_size -= 4; + if (cmd == DL_DISPLAY) break; + } + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_dumpcmd_obj, 1, 2, EVE_dumpcmd); + +// -------------------------------------------------------------- +STATIC mp_obj_t EVE_dumplist(size_t n_args, const mp_obj_t *args) +{ + display_eve_obj_t *self = args[0]; + _check_inlist(self, 0); + + bool verbose = true; + if (n_args > 1) verbose = mp_obj_is_true(args[1]); + uint16_t list_size = FT8_memRead32(REG_CMD_DL) & 0x1FFF; + uint32_t cmd; + uint16_t idx = 0; + mp_printf(&mp_plat_print, "Display list content, size = %d\n", list_size); + while (idx < list_size) { + cmd = FT8_memRead32(FT8_RAM_DL + idx); + if (verbose) { + mp_printf(&mp_plat_print, "%04d: ", idx); + process_eve_command(cmd, FT8_RAM_DL, &idx); + } + else { + mp_printf(&mp_plat_print, "%04d: %08x\n", idx, cmd); + idx += 4; + } + if (cmd == DL_DISPLAY) break; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_dumplist_obj, 1, 2, EVE_dumplist); + +// ------------------------------------------------ +STATIC mp_obj_t EVE_freeobjects(mp_obj_t self_in) { + display_eve_obj_t *self = self_in; + _check_inlist(self, 0); + + memset(user_fonts, 0, sizeof(user_fonts)); + memset(ramg_objects.objects, 0, sizeof(void*) * ramg_objects.size); + ramg_objects.count = 0; + + ft8_ramg_ptr = FT8_RAM_G; + loaded_images = 0; + loaded_fonts = 0; + loaded_lists = 0; + + FT8_cmd_memzero(FT8_RAM_G, FT8_RAM_G_SIZE); + FT8_cmd_execute(250); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(EVE_freeobjects_obj, EVE_freeobjects); + +// --------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_memWrite(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t buff_in) { + display_eve_obj_t *self = self_in; + _check_inlist(self, 0); + + int addr = mp_obj_get_int(addr_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buff_in, &bufinfo, MP_BUFFER_READ); + + FT8_memWrite_flash_buffer(addr, bufinfo.buf, bufinfo.len, false); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(EVE_memWrite_obj, EVE_memWrite); + +// ------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_memRead(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t len_in) { + display_eve_obj_t *self = self_in; + _check_inlist(self, 0); + + int addr = mp_obj_get_int(addr_in); + int len = mp_obj_get_int(len_in); + vstr_t vstr; + vstr_init_len(&vstr, len); + + FT8_memRead_buffer(addr, (uint8_t *)vstr.buf, len); + + // Return read data as string + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(EVE_memRead_obj, EVE_memRead); + +// ------------------------------------------------------------------------------- +STATIC mp_obj_t EVE_memZero(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t len_in) { + display_eve_obj_t *self = self_in; + _check_inlist(self, 0); + + int addr = mp_obj_get_int(addr_in); + int len = mp_obj_get_int(len_in); + + FT8_cmd_memzero(addr, len); + FT8_cmd_execute(250); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(EVE_memZero_obj, EVE_memZero); + +// -------------------------------------------------------------- +STATIC mp_obj_t EVE_memSet(size_t n_args, const mp_obj_t *args) { + display_eve_obj_t *self = args[0]; + _check_inlist(self, 0); + + int addr = mp_obj_get_int(args[1]); + int len = mp_obj_get_int(args[2]); + uint8_t val = mp_obj_get_int(args[3]) & 0xff; + + FT8_cmd_memset(addr, val, len); + FT8_cmd_execute(250); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(EVE_memSet_obj, 4, 4, EVE_memSet); + +// --------------------------------------------------------- +STATIC mp_obj_t EVE_tag(mp_obj_t self_in, mp_obj_t tag_in) { + display_eve_obj_t *self = self_in; + _check_inlist(self, 1); + + uint8_t tag = mp_obj_get_int(tag_in) & 0xff; + if (tag) FT8_cmd_dl(TAG(tag)); + else FT8_cmd_dl(TAG_MASK(0)); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_tag_obj, EVE_tag); + +// -------------------------------------------------------------- +STATIC mp_obj_t EVE_tagmask(mp_obj_t self_in, mp_obj_t mask_in) { + display_eve_obj_t *self = self_in; + _check_inlist(self, 1); + + bool mask = mp_obj_is_true(mask_in); + + FT8_cmd_dl(TAG_MASK(mask)); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(EVE_tagmask_obj, EVE_tagmask); + +// ------------------------------------------- +STATIC mp_obj_t EVE_gettag(mp_obj_t self_in) { + display_eve_obj_t *self = self_in; + _check_inlist(self, 0); + + int tag = FT8_get_touch_tag(); + + return mp_obj_new_int(tag); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(EVE_gettag_obj, EVE_gettag); + +// --------------------------------------------- +STATIC mp_obj_t EVE_gettagXY(mp_obj_t self_in) { + display_eve_obj_t *self = self_in; + _check_inlist(self, 0); + + uint32_t tagxy = FT8_memRead32(REG_TOUCH_TAG_XY); + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_int(tagxy & 0xFFFF); + tuple[1] = mp_obj_new_int(tagxy >> 16); + + return mp_obj_new_tuple(2, tuple); + +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(EVE_gettagXY_obj, EVE_gettagXY); + +// -------------------------------------------- +STATIC mp_obj_t EVE_touchXY(mp_obj_t self_in) { + display_eve_obj_t *self = self_in; + _check_inlist(self, 0); + + uint32_t touchxy = FT8_memRead32(REG_TOUCH_SCREEN_XY); + if ((touchxy & 0x80008000)) return mp_const_false; + + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_int(touchxy >> 16); // X + tuple[1] = mp_obj_new_int(touchxy & 0xFFFF); // Y + + return mp_obj_new_tuple(2, tuple); + +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(EVE_touchXY_obj, EVE_touchXY); + +// ----------------------------------------------- +STATIC mp_obj_t EVE_screensize(mp_obj_t self_in) { + display_eve_obj_t *self = self_in; + + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_int(self->width); + tuple[1] = mp_obj_new_int(self->height); + + return mp_obj_new_tuple(2, tuple); + +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(EVE_screensize_obj, EVE_screensize); + + + +// --------------------------------------------------------------------------------------- +// --------------------------------------------------------------------------------------- + +// ==== FONT object ============================================ + +// constructor +//---------------------------------------------------------------------------------------------------------------- +STATIC mp_obj_t font_eve_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) +{ + enum { ARG_file }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + _check_inlist(eve_obj, 0); + uint32_t addr = ft8_ramg_ptr; // object address in Eve RAM_G + + char *fname = NULL; + char fullname[128] = {'\0'}; + int len; + struct stat sb; + uint8_t fhandle = MAX_USER_FONTS; + + fname = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); + + int res = physicalPath(fname, fullname); + if ((res != 0) || (strlen(fullname) == 0)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error resolving file name")); + } + + if (stat(fullname, &sb) != 0) { + mp_raise_ValueError("Error getting file info"); + } + len = sb.st_size; + if (!check_ramg(len)) { + mp_raise_ValueError("No space left in Eve RAM"); + } + // Find free font structure + for (int i=0; i < MAX_USER_FONTS; i++) { + if (user_fonts[i] == NULL) { + fhandle = i; + break; + } + } + if (fhandle >= MAX_USER_FONTS) { + mp_raise_ValueError("No free font handles left"); + } + + eve_font_metrics_t metrics; + uint8_t *pmetrics = (uint8_t *)(&metrics.widths[0]); + uint32_t size = 0; + + // Read the font into Eve RAM_G + FILE *fhndl = fopen(fullname, "rb"); + if (fhndl != NULL) { + // get the font metrics block + if (fread(pmetrics, 1, EVE_FONT_METRICS_SIZE, fhndl) == EVE_FONT_METRICS_SIZE) { + uint8_t *buff = malloc(1024); + if (buff == NULL) { + fclose(fhndl); + mp_raise_ValueError("Error allocating read buffer"); + } + uint32_t fptr = addr + EVE_FONT_METRICS_SIZE; + size += EVE_FONT_METRICS_SIZE; + // Set the font's raw data address + if (eve_chip_id < 0x810) metrics.ptr = addr - (metrics.stride * metrics.height) + EVE_FONT_METRICS_SIZE; + else metrics.ptr = addr + EVE_FONT_METRICS_SIZE; + // transfer the font metrics block + FT8_memWrite_flash_buffer(FT8_RAM_G+addr, pmetrics, EVE_FONT_METRICS_SIZE, true); + // transfer the raw font data + do { + len = fread(buff, 1, 1024, fhndl); + if (len <= 0) break; + if (len < 1024) memset(buff+len, 0, 1024-len); + if ((len % 4) != 0) len += (4 - (len % 4)); + FT8_memWrite_flash_buffer(FT8_RAM_G+fptr, buff, len, true); + fptr += len; + size += len; + } while (len > 0); + + free(buff); + } + else { + fclose(fhndl); + mp_raise_ValueError("Error reading font file"); + } + fclose(fhndl); + } + else { + mp_raise_ValueError("Error opening font file"); + } + + uint8_t nchars = 0; + uint8_t firstc = 0; + uint32_t fformat = metrics.format; + if (fformat == 17) fformat = 2; + else if (fformat == 2) fformat = 4; + else if (fformat == 3) fformat = 8; + uint8_t minwidth = 99, maxwidth = 0; + for (int i=0; i<128; i++) { + if (metrics.widths[i] > 0) { + nchars++; + if (firstc == 0) firstc = i; + if (metrics.widths[i] < minwidth) minwidth = metrics.widths[i]; + if (metrics.widths[i] > maxwidth) maxwidth = metrics.widths[i]; + } + } + + // Create FONT instance object + font_eve_obj_t *self = m_new_obj(font_eve_obj_t); + memset(self, 0, sizeof(font_eve_obj_t)); + self->base.type = &font_eve_type; + + memcpy((uint8_t *)(&self->metrics.widths[0]), pmetrics, sizeof(eve_font_metrics_t)); + self->addr = addr; + self->size = size; + self->handle = fhandle; + self->firstc = firstc; + self->maxwidth = maxwidth; + self->minwidth = minwidth; + self->nchars = nchars; + self->format = (uint8_t)fformat; + self->loaded = 1; + + if (!add_ramg_object((void *)self)) { + mp_raise_ValueError("Error adding ramg object"); + } + user_fonts[fhandle] = self; + + ft8_ramg_ptr += size; + loaded_fonts++; + + return MP_OBJ_FROM_PTR(self); +} + +// -------------------------------------------- +STATIC mp_obj_t FONT_EVE_free(mp_obj_t self_in) +{ + _check_inlist(eve_obj, 0); + font_eve_obj_t *self = (font_eve_obj_t *)self_in; + if (self->loaded == 0) return mp_const_true; + + bool res = true; + if ((self->addr+self->size) < ft8_ramg_ptr) { + // move other objects in RAM_G above this one + FT8_cmd_memcpy(self->addr, self->addr + self->size, ft8_ramg_ptr - (self->addr+self->size)); + res = FT8_cmd_execute(250); + } + adjust_ramg_objects((void *)self, self->addr, self->size); + ft8_ramg_ptr -= self->size; + user_fonts[self->handle] = NULL; + loaded_fonts--; + self->loaded = 0; + + if (res) return mp_const_true; + return mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(FONT_EVE_free_obj, FONT_EVE_free); + +// -------------------------------------------- +STATIC mp_obj_t FONT_EVE_info(mp_obj_t self_in) +{ + font_eve_obj_t *self = (font_eve_obj_t *)self_in; + + font_eve_printinfo(&mp_plat_print, self, PRINT_STR); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(FONT_EVE_info_obj, FONT_EVE_info); + +// --------------------------------------------- +STATIC mp_obj_t FONT_EVE_props(mp_obj_t self_in) +{ + font_eve_obj_t *self = (font_eve_obj_t *)self_in; + if (self->loaded == 0) return mp_const_false; + + mp_obj_t tuple[7]; + tuple[0] = mp_obj_new_int(self->handle); + tuple[1] = mp_obj_new_int(self->metrics.width); + tuple[2] = mp_obj_new_int(self->metrics.height); + tuple[3] = mp_obj_new_int(self->minwidth); + tuple[4] = mp_obj_new_int(self->maxwidth); + tuple[5] = mp_obj_new_int(self->nchars); + tuple[6] = mp_obj_new_int(self->firstc); + + return mp_obj_new_tuple(7, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(FONT_EVE_props_obj, FONT_EVE_props); + +//------------------------------------------------------------- +STATIC const mp_rom_map_elem_t font_eve_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&FONT_EVE_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_free), MP_ROM_PTR(&FONT_EVE_free_obj) }, + { MP_ROM_QSTR(MP_QSTR_props), MP_ROM_PTR(&FONT_EVE_props_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(font_eve_locals_dict, font_eve_locals_dict_table); + +//----------------------------------- +const mp_obj_type_t font_eve_type = { + { &mp_type_type }, + .name = MP_QSTR_FONT, + .print = font_eve_printinfo, + .make_new = font_eve_make_new, + .locals_dict = (mp_obj_t)&font_eve_locals_dict, +}; + +// ^^^^ FONT object end ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +// ==== IMAGE object =========================================== + +// constructor +//---------------------------------------------------------------------------------------------------------------- +STATIC mp_obj_t image_eve_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) +{ + enum { ARG_file, ARG_opt, ARG_type, ARG_format, ARG_width, ARG_height }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_opt, MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_type, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_format, MP_ARG_INT, { .u_int = FT8_RGB565 } }, + { MP_QSTR_width, MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_height, MP_ARG_INT, { .u_int = 0 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + _check_inlist(eve_obj, 0); + + char *fname = NULL; + char fullname[128] = {'\0'}; + int len=0, size=0; + fname = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); + uint32_t allowed_opts = FT8_OPT_MONO | FT8_OPT_FULLSCREEN; + if (eve_chip_id >= 0x810) allowed_opts |= FT8_OPT_MEDIAFIFO; + uint32_t opt = args[ARG_opt].u_int & allowed_opts; + opt |= FT8_OPT_NODL; + uint32_t addr = ft8_ramg_ptr; // address in Eve RAM_G + int format = args[ARG_format].u_int; + int width = args[ARG_width].u_int; + int height = args[ARG_height].u_int; + + int img_type = args[ARG_type].u_int; + if (img_type < 0) { + img_type = IMAGE_TYPE_NONE; + // try to determine image type + char upr_fname[128] = {'\0'}; + int fname_len = strlen(upr_fname); + strcpy(upr_fname, fname); + for (int i=0; i < strlen(upr_fname); i++) { + upr_fname[i] = toupper((unsigned char) upr_fname[i]); + } + if (strstr(upr_fname, ".JPG") == (upr_fname+fname_len-4)) img_type = IMAGE_TYPE_JPG; + else if (strstr(upr_fname, ".JPEG") == (upr_fname+fname_len-5)) img_type = IMAGE_TYPE_JPG; + else if (strstr(upr_fname, ".PNG") == (upr_fname+fname_len-4)) img_type = IMAGE_TYPE_PNG; + else if (strstr(upr_fname, ".RAW") == (upr_fname+fname_len-4)) img_type = IMAGE_TYPE_RAW; + else if (strstr(upr_fname, ".BIN") == (upr_fname+fname_len-4)) img_type = IMAGE_TYPE_BIN; + else { + mp_raise_ValueError("Unsupported image file extension"); + } + } + else if ((img_type != IMAGE_TYPE_JPG) && (img_type != IMAGE_TYPE_PNG) && (img_type != IMAGE_TYPE_RAW) && (img_type != IMAGE_TYPE_BIN)) { + mp_raise_ValueError("Unsupported image file type"); + } + + int res = physicalPath(fname, fullname); + if ((res != 0) || (strlen(fullname) == 0)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error resolving file name")); + } + + // try to determine image type + FILE *fhndl = fopen(fullname, "rb"); + if (fhndl != NULL) { + // get file size + if (fseek(fhndl,0,SEEK_END) == 0) { + len = ftell(fhndl); + } + if (fseek(fhndl,0,SEEK_SET)) len = 0; + if (len == 0) { + fclose(fhndl); + mp_raise_ValueError("Error getting file size"); + } + uint8_t buf[256]; + if (fread(buf, 1, 256, fhndl) == 256) { + if ((img_type == IMAGE_TYPE_JPG) || (img_type == IMAGE_TYPE_PNG)) { + // Check if it is a JPG or PNG file + res = _check_jpeg(buf, &width, &height); + if (res != 0) { + #if FT8_ENABLE_PNG_LOADING + if (eve_chip_id < 0x810) { + fclose(fhndl); + mp_raise_ValueError("Only JPEG images are supported"); + } + // Not a jpeg image, check if PNG + res = _check_png(buf, &width, &height); + if (res < 0) { + // Not a PNG image + fclose(fhndl); + ESP_LOGD(TAG, "Not PNG (%d)", res); + mp_raise_ValueError("Only JPEG and PNG images are supported"); + } + opt &= 0xFFFFFFFE; + if (res == 0) { + format = FT8_L8; // Greyscale + opt |= FT8_OPT_MONO; + } + else if (res == 2) format = FT8_RGB565; // Truecolor + else if (res == 6) format = FT8_ARGB4; // Truecolor with alpha + else { + fclose(fhndl); + mp_raise_ValueError("PNG color type not supported"); + } + #else + fclose(fhndl); + mp_raise_ValueError("Only JPEG images are supported"); + #endif + } + size = width*height; + if ((opt & FT8_OPT_MONO) != 0) format = FT8_L8; + else size *= 2; + if (size > (FT8_RAM_G_SIZE-addr)) { + fclose(fhndl); + mp_raise_ValueError("No space left in Eve RAM"); + } + } + else if ((img_type == IMAGE_TYPE_RAW) || (img_type == IMAGE_TYPE_BIN)) { + // Image parameters must be given + if ((width <= 0) || (height <= 0)) { + mp_raise_ValueError("Wrong image dimensions"); + } + if ((format < 0) || (format > 7)) { + mp_raise_ValueError("Unsupported image format"); + } + size = width*height; + if (format == FT8_L1) size /= 8; + else if (format == FT8_L4) size /= 2; + else if ((format == FT8_ARGB1555) || (format == FT8_ARGB4) || (format == FT8_RGB565)) size *= 2; + if ((img_type == IMAGE_TYPE_RAW) && (size != len)) { + // We know the image size, check it + mp_raise_ValueError("Wrong image size"); + } + } + } + else { + fclose(fhndl); + mp_raise_ValueError("Error reading file image file"); + } + fseek(fhndl, 0, SEEK_SET); + } + else { + mp_raise_ValueError("Error opening file"); + } + + // set RAM_G area to zero + FT8_cmd_memzero(addr, size); + FT8_cmd_execute(250); + // Write some values to check the RAM after image decoding + FT8_memWrite32(addr+size-4, 0x1234abcd); // This should be overwritten + FT8_memWrite32(addr+size, size); // This must be the preserved + + FT8_CP_reset(); + + uint32_t tmp1, tmp2; + if ((img_type == IMAGE_TYPE_JPG) || (img_type == IMAGE_TYPE_PNG)) { + // === Decode JPG or PNG image === + if ((eve_chip_id >= 0x810) && ((opt & FT8_OPT_MEDIAFIFO) != 0)) { + res = FT8_Fifo_init(fhndl); + if (res != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error initializing mediafifo")); + } + res = FT8_sendDataViaMediafifo(fhndl, addr, opt, 0); + fclose(fhndl); + FT8_Fifo_deinit(); + } + else { + res = FT8_cmd_loadimage(addr, opt, fhndl, len, 1); + + fclose(fhndl); + } + if (res < 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error loading image file into EVE RAM")); + } + // == Check if the image was decoded as expected == + // Compare width and height returned by EVE Command processor with expected values + uint32_t offset = FT8_cmd_getprops(addr); + FT8_cmd_execute(250); + tmp1 = FT8_memRead32(FT8_RAM_CMD + offset); + offset += 4; + offset &= 0x0fff; + tmp2 = FT8_memRead32(FT8_RAM_CMD + offset); + if ((tmp1 != width) || (tmp2 != height)) { + ESP_LOGW(TAG, "Image dimension check failed (%d,%d) <> (%d,%d)\n", tmp1, tmp2, width, height); + } + } + else if (img_type == IMAGE_TYPE_BIN) { + // === Deflate compressed image === + res = FT8_cmd_loadimage(addr, opt, fhndl, len, 2); + ESP_LOGD(TAG, "Written bytes: %d (%d)\n", res, len); + + fclose(fhndl); + if (res < 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error loading image file into EVE RAM")); + } + // == Check if the image was decoded as expected == + uint32_t offset = FT8_cmd_getptr(); + FT8_cmd_execute(250); + tmp1 = FT8_memRead32(FT8_RAM_CMD + offset); + if (tmp1 != (ft8_ramg_ptr + size)) { + ESP_LOGW(TAG, "End RAM ptr check failed (%d <> %d)\n", tmp1, ft8_ramg_ptr + size); + } + } + else if (img_type == IMAGE_TYPE_RAW) { + // === Send RAW image to RAM_G === + res = FT8_cmd_loadimage(addr, opt, fhndl, len, 3); + ESP_LOGD(TAG, "Written bytes: %d (%d)\n", res, len); + + fclose(fhndl); + if (res < 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error loading image file into EVE RAM")); + } + } + + // Compare the values written to RAM before decoding + tmp1 = FT8_memRead32(FT8_RAM_G+addr+size); + tmp2 = FT8_memRead32(FT8_RAM_G+addr+size-4); + if ((tmp1 != size) || (tmp2 == 0x1234abcd)) { + ESP_LOGW(TAG, "RAM check failed: %s %s\n", (tmp1 != size) ? "Too big" : "", (tmp2 == 0x1234abcd) ? "Too small" : ""); + } + + ft8_ramg_ptr += size; + loaded_images++; + + // Create IMAGE instance object + image_eve_obj_t *self = m_new_obj(image_eve_obj_t); + memset(self, 0, sizeof(image_eve_obj_t)); + self->base.type = &image_eve_type; + + self->addr = addr; + self->width = width; + self->height = height; + self->size = size; + self->format = format; + self->orig_fmt = img_type; + self->loaded = 1; + + if (!add_ramg_object((void *)self)) { + mp_raise_ValueError("Error adding ramg object"); + } + + return MP_OBJ_FROM_PTR(self); +} + +// --------------------------------------------- +STATIC mp_obj_t IMAGE_EVE_free(mp_obj_t self_in) +{ + _check_inlist(eve_obj, 0); + image_eve_obj_t *self = (image_eve_obj_t *)self_in; + if (self->loaded == 0) return mp_const_true; + + FT8_cmd_memcpy(self->addr, self->addr + self->size, ft8_ramg_ptr - (self->addr+self->size)); + bool res = FT8_cmd_execute(250); + ft8_ramg_ptr -= self->size; + loaded_images--; + self->loaded = 0; + + adjust_ramg_objects((void *)self, self->addr, self->size); + + if (res) return mp_const_true; + return mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(IMAGE_EVE_free_obj, IMAGE_EVE_free); + +// --------------------------------------------- +STATIC mp_obj_t IMAGE_EVE_info(mp_obj_t self_in) +{ + image_eve_obj_t *self = (image_eve_obj_t *)self_in; + + image_eve_printinfo(&mp_plat_print, self, PRINT_STR); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(IMAGE_EVE_info_obj, IMAGE_EVE_info); + +// --------------------------------------------- +STATIC mp_obj_t IMAGE_EVE_props(mp_obj_t self_in) +{ + image_eve_obj_t *self = (image_eve_obj_t *)self_in; + if (self->loaded == 0) return mp_const_false; + + mp_obj_t tuple[5]; + tuple[0] = mp_obj_new_int(self->addr); + tuple[1] = mp_obj_new_int(self->size); + tuple[2] = mp_obj_new_int(self->width); + tuple[3] = mp_obj_new_int(self->height); + tuple[4] = mp_obj_new_int(self->format); + + return mp_obj_new_tuple(5, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(IMAGE_EVE_props_obj, IMAGE_EVE_props); + +//-------------------------------------------------------------- +STATIC const mp_rom_map_elem_t image_eve_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&IMAGE_EVE_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_free), MP_ROM_PTR(&IMAGE_EVE_free_obj) }, + { MP_ROM_QSTR(MP_QSTR_props), MP_ROM_PTR(&IMAGE_EVE_props_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(image_eve_locals_dict, image_eve_locals_dict_table); + +//------------------------------------ +const mp_obj_type_t image_eve_type = { + { &mp_type_type }, + .name = MP_QSTR_IMAGE, + .print = image_eve_printinfo, + .make_new = image_eve_make_new, + .locals_dict = (mp_obj_t)&image_eve_locals_dict, +}; + +// ^^^^ IMAGE object end ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +// ==== LIST object ============================================ + +// constructor +//---------------------------------------------------------------------------------------------------------------- +STATIC mp_obj_t LIST_eve_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) +{ + mp_raise_ValueError("Can only be created by 'savelist' method"); + return mp_const_none; +} + +// --------------------------------------------- +STATIC mp_obj_t LIST_EVE_free(mp_obj_t self_in) +{ + _check_inlist(eve_obj, 0); + image_eve_obj_t *self = (image_eve_obj_t *)self_in; + if (self->loaded == 0) return mp_const_true; + + FT8_cmd_memcpy(self->addr, self->addr + self->size, ft8_ramg_ptr - (self->addr+self->size)); + bool res = FT8_cmd_execute(250); + ft8_ramg_ptr -= self->size; + loaded_lists--; + self->loaded = 0; + + adjust_ramg_objects((void *)self, self->addr, self->size); + + if (res) return mp_const_true; + return mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(LIST_EVE_free_obj, LIST_EVE_free); + +// --------------------------------------------- +STATIC mp_obj_t LIST_EVE_info(mp_obj_t self_in) +{ + list_eve_obj_t *self = (list_eve_obj_t *)self_in; + + list_eve_printinfo(&mp_plat_print, self, PRINT_STR); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(LIST_EVE_info_obj, LIST_EVE_info); + +// --------------------------------------------- +STATIC mp_obj_t LIST_EVE_props(mp_obj_t self_in) +{ + list_eve_obj_t *self = (list_eve_obj_t *)self_in; + if (self->loaded == 0) return mp_const_false; + + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_int(self->addr); + tuple[1] = mp_obj_new_int(self->size); + + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(LIST_EVE_props_obj, LIST_EVE_props); + +//------------------------------------------------------------- +STATIC const mp_rom_map_elem_t list_eve_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&LIST_EVE_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_free), MP_ROM_PTR(&LIST_EVE_free_obj) }, + { MP_ROM_QSTR(MP_QSTR_props), MP_ROM_PTR(&LIST_EVE_props_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(list_eve_locals_dict, list_eve_locals_dict_table); + +//----------------------------------- +const mp_obj_type_t list_eve_type = { + { &mp_type_type }, + .name = MP_QSTR_LIST, + .print = list_eve_printinfo, + .make_new = LIST_eve_make_new, + .locals_dict = (mp_obj_t)&list_eve_locals_dict, +}; + +// ^^^^ IMAGE object end ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +// ==== CONSOLE object =========================================== + + +//-------------------------------------------------------- +static uint8_t console_rgb_to_vga(console_eve_obj_t *self) +{ + uint8_t c8 = 0; + c8 |= (self->fgcolor & 0x0000C0) ? 0x01 : 0; + c8 |= (self->fgcolor & 0x00C000) ? 0x02 : 0; + c8 |= (self->fgcolor & 0xC00000) ? 0x04 : 0; + c8 |= (self->fgcolor & 0x808080) ? 0x08 : 0; + + c8 |= (self->bgcolor & 0x0000C0) ? 0x10 : 0; + c8 |= (self->bgcolor & 0x00C000) ? 0x20 : 0; + c8 |= (self->bgcolor & 0xC00000) ? 0x40 : 0; + c8 |= (self->bgcolor & 0x808080) ? 0x80 : 0; + + return c8; +} + +/* +//-------------------------------------------------------------------- +static void console_vga_to_rgb(console_eve_obj_t *self, uint8_t color) +{ + uint8_t c32 = 0; + uint32_t ci = (color & 0x08) ? 0x80 : 0; + c32 |= ((color & 0x01) ? 0x7f : 0) | ci; + c32 |= ((color & 0x02) ? 0x7f00 : 0) | (ci<<8); + c32 |= ((color & 0x04) ? 0x7f0000 : 0) | (ci<<16); + self->fgcolor = c32; + + c32 = 0; + ci = (color & 0x80) ? 0x80 : 0; + c32 |= ((color & 0x01) ? 0x7f : 0) | ci; + c32 |= ((color & 0x02) ? 0x7f00 : 0) | (ci<<8); + c32 |= ((color & 0x04) ? 0x7f0000 : 0) | (ci<<16); + self->bgcolor = c32; +} +*/ + +//---------------------------------------------------------------------- +static void console_memclear(console_eve_obj_t *self, int addr, int len) +{ + if (self->type == FT8_TEXTVGA) { + len *= 2; + uint8_t row[len]; + for (int i=0; ivgacolor; + } + FT8_cmd_memwrite(addr , row, len); + } + else FT8_cmd_memset(addr, 0x20, len); + FT8_cmd_execute(250); +} + +//------------------------------------------------- +static void console_cursor(console_eve_obj_t *self) +{ + if (!self->show_cursor) return; + + uint8_t crs[2]; + crs [0] = 220; + crs[1] = 0x0E; + if (self->type == FT8_TEXTVGA) FT8_cmd_memwrite(self->curr_addr, crs, 2); + else FT8_cmd_memwrite(self->curr_addr, crs, 1); + FT8_cmd_execute(250); +} + +//------------------------------------------------ +static void console_clear(console_eve_obj_t *self) +{ + if (self->type == FT8_TEXTVGA) { + for (int i=0; iheight; i++) { + console_memclear(self, self->addr + (self->rowbytes * i), self->width); + } + } + else { + FT8_cmd_memset(self->addr, 0x20, self->size); + FT8_cmd_execute(250); + } +} + +//------------------------------------------------- +static void console_scroll(console_eve_obj_t *self) +{ + // scroll + FT8_cmd_memcpy(self->addr, self->addr + self->rowbytes, self->size - self->rowbytes); + FT8_cmd_execute(250); + // clear the last row + self->y = self->height - 1; + self->x = 0; + self->curr_addr = self->addr + (self->size - self->rowbytes); + console_memclear(self, self->addr + (self->rowbytes * self->y), self->width); + console_cursor(self); + return; +} + +//----------------------------------------------------------------------------------------- +static void console_row_add(console_eve_obj_t *self, uint8_t * row, uint8_t c, int *rowpos) +{ + uint8_t n = 1; + if (self->type == FT8_TEXTVGA) { + row[*rowpos] = c; + row[*rowpos+1] = self->vgacolor; + n = 2; + } + else row[*rowpos] = c; + *rowpos += n; +} + +//---------------------------------------------------------------------------- +static void _console_write_row(console_eve_obj_t *self, uint8_t *row, int len) +{ + if (len == 0) return; + FT8_cmd_memwrite(self->curr_addr, row, len); + FT8_cmd_execute(250); +} + +//------------------------------------------------------------ +static void _console_addrinc(console_eve_obj_t *self, int len) +{ + if (len == 0) return; + // set cursor and current address + self->curr_addr += len; + self->y = (self->curr_addr-self->addr) / self->rowbytes; + self->x = (self->curr_addr-self->addr) % self->rowbytes; + if (self->type == FT8_TEXTVGA) self->x /= 2; + if (self->y >= self->height) console_scroll(self); +} + +//--------------------------------------------------------------------------- +static void console_write_row(console_eve_obj_t *self, uint8_t *row, int len) +{ + _console_write_row(self, row, len); + _console_addrinc(self, len); +} + +//--------------------------------------------------------------------------- +static void console_write_blank_eol(console_eve_obj_t *self, uint8_t addrinc) +{ + int len = 0; + if (self->type == FT8_TEXTVGA) { + len = self->rowbytes - (self->x*2); + uint8_t buff16[len]; + for (int i=0; ivgacolor; + } + _console_write_row(self, buff16, len); + } + else { + len = self->rowbytes - self->x; + uint8_t buff8[len]; + for (int i=0; ix = 0; + self->y++; + if (self->y >= self->height) console_scroll(self); + else { + if (self->type == FT8_TEXTVGA) self->curr_addr = self->addr + (self->rowbytes * self->y) + (self->x * 2); + else self->curr_addr = self->addr + (self->rowbytes * self->y) + self->x; + } +} + + +// constructor +//------------------------------------------------------------------------------------------------------------------ +STATIC mp_obj_t console_eve_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) +{ + enum { ARG_x, ARG_y, ARG_type, ARG_scale }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_type, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = FT8_TEXT8X8 } }, + { MP_QSTR_scale, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + _check_inlist(eve_obj, 0); + + int format = args[ARG_type].u_int; + if ((format != FT8_TEXT8X8) && (format != FT8_TEXTVGA)) { + mp_raise_ValueError("Unsupported console type"); + } + uint16_t x = args[ARG_x].u_int; + uint16_t y = args[ARG_y].u_int; + uint16_t rowbytes = x; + uint32_t size = x * y; + if (format == FT8_TEXTVGA) { + size *= 2; + rowbytes *= 2; + } + + uint32_t addr = ft8_ramg_ptr; // address in Eve RAM_G + if (size > (FT8_RAM_G_SIZE-addr)) { + mp_raise_ValueError("No space left in Eve RAM"); + } + + mp_float_t fscale=1.0; + if (args[ARG_scale].u_obj != mp_const_none) { + fscale = mp_obj_get_float(args[ARG_scale].u_obj); + if (fscale < 1.2) fscale = 1.0; + } + + // Create console instance object + console_eve_obj_t *self = m_new_obj(console_eve_obj_t); + memset(self, 0, sizeof(console_eve_obj_t)); + self->base.type = &console_eve_type; + + self->addr = addr; + self->size = size; + self->curr_addr = addr; + self->x = 0; + self->y = 0; + self->width = x; + self->height = y; + self->rowbytes = rowbytes; + self->scale = fscale; + self->rowspace = 0; + self->fgcolor = 0x0000FF00; + self->bgcolor = 0; + self->type = format; + self->show_cursor = 0; + self->wrap = 0; + self->loaded = 1; + self->vgacolor = console_rgb_to_vga(self); + + if (!add_ramg_object((void *)self)) { + mp_raise_ValueError("Error adding ramg object"); + } + + ft8_ramg_ptr += size; + + console_clear(self); + console_cursor(self); + + return MP_OBJ_FROM_PTR(self); +} + +//------------------------------------------------ +STATIC mp_obj_t CONSOLE_EVE_free(mp_obj_t self_in) +{ + _check_inlist(eve_obj, 0); + console_eve_obj_t *self = (console_eve_obj_t *)self_in; + if (self->loaded == 0) return mp_const_true; + + FT8_cmd_memcpy(self->addr, self->addr + self->size, ft8_ramg_ptr - (self->addr+self->size)); + bool res = FT8_cmd_execute(250); + ft8_ramg_ptr -= self->size; + self->loaded = 0; + + adjust_ramg_objects((void *)self, self->addr, self->size); + + if (res) return mp_const_true; + return mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(CONSOLE_EVE_free_obj, CONSOLE_EVE_free); + +//-------------------------------------------------------------------- +STATIC mp_obj_t CONSOLE_EVE_clear(size_t n_args, const mp_obj_t *args) +{ + _check_inlist(eve_obj, 0); + console_eve_obj_t *self = (console_eve_obj_t *)args[0]; + if (self->loaded == 0) return mp_const_true; + + if (n_args > 1) { + int y = mp_obj_get_int(args[1]); + if (y < 0) y = 0; + if (y >= self->height) y = self->height - 1; + console_memclear(self, self->addr + (self->rowbytes * y), self->width); + } + else { + self->x = 0; + self->y = 0; + self->fgcolor = 0x0000FF00; + self->bgcolor = 0; + self->vgacolor = console_rgb_to_vga(self); + console_clear(self); + } + self->curr_addr = self->addr; + console_cursor(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(CONSOLE_EVE_clear_obj, 1, 2, CONSOLE_EVE_clear); + +//--------------------------------------------------------------------------------------------- +STATIC mp_obj_t CONSOLE_EVE_show(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { ARG_x, ARG_y, ARG_rowspace, ARG_filter, ARG_cursor, ARG_color, ARG_bgcolor, ARG_wrap }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_rowspace, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_filter, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = FT8_NEAREST } }, + { MP_QSTR_cursor, MP_ARG_KW_ONLY | MP_ARG_BOOL,{ .u_bool = false } }, + { MP_QSTR_fgcolor, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_bgcolor, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_wrap, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + }; + _check_inlist(eve_obj, 1); + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + console_eve_obj_t *self = pos_args[0]; + + if (self->loaded == 0) { + mp_raise_ValueError("Unloaded"); + } + + if (args[ARG_color].u_int >= 0) { + self->fgcolor = args[ARG_color].u_int; + self->vgacolor = console_rgb_to_vga(self); + } + if (args[ARG_bgcolor].u_int >= 0) { + self->bgcolor = args[ARG_bgcolor].u_int; + self->vgacolor = console_rgb_to_vga(self); + } + if (args[ARG_wrap].u_int >= 0) self->wrap = args[ARG_wrap].u_int & 1; + self->show_cursor = args[ARG_cursor].u_bool; + int rowspace = self->rowspace; + if (args[ARG_rowspace].u_int >= 0) { + rowspace = args[ARG_rowspace].u_int; + if (rowspace < 0) rowspace = 0; + if (rowspace > 8) rowspace = 8; + } + if (self->rowspace != rowspace) self->rowspace = rowspace; + int x = args[ARG_x].u_int; + int y = args[ARG_y].u_int; + uint16_t width = self->width * 8 ; + uint16_t swidth = width; + uint16_t height = 8; + uint16_t sheight = height; + uint16_t stride = (width*2) >> stride_factor[self->type]; + uint8_t filter = args[ARG_filter].u_int & 1; + int32_t scale=0; + if (self->scale > 1.19) { + //filter = FT8_BILINEAR; + swidth = (int16_t)(self->scale * width); + sheight = (int16_t)(self->scale * height); + scale = (int32_t)(self->scale * 65536); + } + + if (self->type == FT8_TEXTVGA) { + height *= 2; + sheight *= 2; + // draw backgroung rectangle + FT8_cmd_dl(DL_COLOR_RGB | (self->bgcolor & 0x00ffffff)); + FT8_cmd_rect(x, y, x+swidth, y+((sheight+self->rowspace)*self->height), 1); + // to draw characters non transparent + FT8_cmd_dl(DL_COLOR_RGB | 0x00ffffff); + FT8_cmd_dl(BLEND_FUNC(FT8_ONE, FT8_ZERO)); + } + else { + // draw backgroung rectangle + FT8_cmd_dl(DL_COLOR_RGB | (self->bgcolor & 0x00ffffff)); + FT8_cmd_rect(x, y, x+swidth, y+((sheight+self->rowspace)*self->height), 1); + } + + if ((eve_chip_id >= 0x810)) FT8_cmd_dl(BITMAP_LAYOUT_H(stride>>10, height>>9)); + FT8_cmd_dl(BITMAP_LAYOUT(self->type, stride , height)); + if ((eve_chip_id >= 0x810)) FT8_cmd_dl(BITMAP_SIZE_H(swidth>>9, sheight>>9)); + FT8_cmd_dl(BITMAP_SIZE(filter, FT8_BORDER, FT8_BORDER, swidth, sheight)); + if (scale) { + FT8_cmd_dl(CMD_LOADIDENTITY); + FT8_cmd_scale(scale, scale); + FT8_cmd_setmatrix(); + } + FT8_cmd_dl(DL_BEGIN | FT8_BITMAPS); + if (self->type == FT8_TEXT8X8) FT8_cmd_dl(DL_COLOR_RGB | (self->fgcolor & 0x00ffffff)); + + for (int i=0; iheight; i++) { + FT8_cmd_dl(BITMAP_SOURCE(self->addr + (self->rowbytes * i))); + FT8_cmd_dl(VERTEX2F(x*16, (y + (i*(sheight+self->rowspace)))*16)); + } + FT8_cmd_dl(DL_END); + if (self->type == FT8_TEXTVGA) { + FT8_cmd_dl(BLEND_FUNC(FT8_SRC_ALPHA, FT8_ONE_MINUS_SRC_ALPHA)); + } + if (scale) { + FT8_cmd_dl(CMD_LOADIDENTITY); + FT8_cmd_scale(65536, 65536); + FT8_cmd_setmatrix(); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(CONSOLE_EVE_show_obj, 0, CONSOLE_EVE_show); + +//--------------------------------------------------------------------------------------------- +STATIC mp_obj_t CONSOLE_EVE_text(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { ARG_text, ARG_x, ARG_y, ARG_color, ARG_bgcolor }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_x, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_y, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_fgcolor, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_bgcolor, MP_ARG_INT, { .u_int = -1 } }, + }; + _check_inlist(eve_obj, 0); + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + console_eve_obj_t *self = pos_args[0]; + if (self->loaded == 0) { + mp_raise_ValueError("Unloaded"); + } + + const char *st = mp_obj_str_get_str(args[ARG_text].u_obj); + if (strlen(st) == 0) return mp_const_none; + + // create the row buffer + uint8_t row[self->rowbytes]; + + int idx=0; + int len = strlen(st); + int rowstart, rowpos, lastblank; + uint8_t bpc = (self->type == FT8_TEXTVGA) ? 2 : 1; + uint16_t x = self->x; + uint16_t y = self->y; + if (args[ARG_color].u_int >= 0) { + self->fgcolor = args[ARG_color].u_int; + self->vgacolor = console_rgb_to_vga(self); + } + if (args[ARG_bgcolor].u_int >= 0) { + self->bgcolor = args[ARG_bgcolor].u_int; + self->vgacolor = console_rgb_to_vga(self); + } + + if ((args[ARG_x].u_int >= 0) || (args[ARG_y].u_int >= 0)) { + if (args[ARG_x].u_int >= 0) x = args[ARG_x].u_int; + if (args[ARG_y].u_int >= 0) y = args[ARG_y].u_int; + if ((x >= self->width) || (y >= self->height)) { + mp_raise_ValueError("Position outside console area"); + } + self->x = x; + self->y = y; + if (self->type == FT8_TEXTVGA) self->curr_addr = self->addr + (self->rowbytes * y) + (x * 2); + else self->curr_addr = self->addr + (self->rowbytes * y) + x; + console_cursor(self); + } + + rowstart = self->x; + rowpos = rowstart; + lastblank = -1; + + uint8_t vgacolor = self->vgacolor; // save original vga color + while (idx < len) { + if (st[idx] == 0x08) { + // *** ('\b'), set color if in TEXTVGA mode + idx++; + if (idx >= len) break; + if (self->type == FT8_TEXTVGA) { + // set color + if (st[idx] == 0xff) self->vgacolor = vgacolor; + else self->vgacolor = st[idx]; + } + idx++; + } + else if (st[idx] == 0x0A) { + // *** new line ('\n') + console_write_row(self, row+rowstart, rowpos-rowstart); + console_new_line(self); + rowstart = self->x; + rowpos = rowstart; + lastblank = -1; + idx++; + } + else if (st[idx] == 0x0D) { + // *** clear to the end of line ('\r'), preserve position + console_write_row(self, row+rowstart, rowpos-rowstart); + if (self->x > 0) console_write_blank_eol(self, 0); + rowstart = self->x; + rowpos = rowstart; + lastblank = -1; + idx++; + } + /* + else if (st[idx] == '\t') { + // *** tab, write 4 spaces + if ((self->rowbytes - rowpos) >= 4) { + for (int n=0; n<4; n++) { + console_row_add(self, row, 0x20, &rowpos); + } + } + idx++; + } + */ + else if (st[idx] < 32) idx++; // ignore non-printable characters + else { + // printable character, add it to row buffer + if (st[idx] == 0x20) lastblank = rowpos; + console_row_add(self, row, st[idx], &rowpos); + + if (rowpos >= self->rowbytes) { + // === row buffer filled, write it === + if ((self->wrap) && (lastblank >= 0)) { + // word wrapping is used, write up to the last blank character + // and advance row position + console_write_row(self, row+rowstart, lastblank-rowstart); + if (self->x > 0) console_write_blank_eol(self, 1); + // write remaining characters + rowstart = lastblank + bpc; + } + console_write_row(self, row+rowstart, rowpos-rowstart); + rowstart = self->x; + rowpos = rowstart; + lastblank = -1; + } + idx++; + } + } + if (rowpos > 0) console_write_row(self, row+rowstart, rowpos-rowstart); + + self->vgacolor = vgacolor; // restore original vga color + console_cursor(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(CONSOLE_EVE_text_obj, 0, CONSOLE_EVE_text); + + +//---------------------------------------------------------------- +STATIC const mp_rom_map_elem_t console_eve_locals_dict_table[] = { + // instance methods + //{ MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&CONSOLE_EVE_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_free), MP_ROM_PTR(&CONSOLE_EVE_free_obj) }, + { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&CONSOLE_EVE_show_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&CONSOLE_EVE_text_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&CONSOLE_EVE_clear_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(console_eve_locals_dict, console_eve_locals_dict_table); + + +//----------------------------------- +const mp_obj_type_t console_eve_type = { + { &mp_type_type }, + .name = MP_QSTR_CONSOLE, + .print = console_eve_printinfo, + .make_new = console_eve_make_new, + .locals_dict = (mp_obj_t)&console_eve_locals_dict, +}; + +// ^^^^ CONSOLE object end ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + + +// ==== TFT object =============================================== + + + + +// constructor +//--------------------------------------------------------------------------------------------------------------- +STATIC mp_obj_t tft_eve_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) +{ + enum { ARG_x, ARG_y, ARG_type }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_type, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = FT8_RGB332 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + _check_inlist(eve_obj, 0); + + int format = args[ARG_type].u_int; + if ((format != FT8_RGB332) && (format != FT8_RGB565)) { + mp_raise_ValueError("Unsupported console type"); + } + uint16_t x = args[ARG_x].u_int; + uint16_t y = args[ARG_y].u_int; + uint32_t size = x * y; + uint16_t rowsize = x; + uint8_t bpp = 1; + if (format == FT8_RGB565) { + size *= 2; + rowsize *= 2; + bpp = 2; + } + + uint32_t addr = ft8_ramg_ptr; // address in Eve RAM_G + if (size > (FT8_RAM_G_SIZE-addr)) { + mp_raise_ValueError("No space left in Eve RAM"); + } + + // Create tft instance object + tft_eve_obj_t *self = m_new_obj(tft_eve_obj_t); + memset(self, 0, sizeof(tft_eve_obj_t)); + self->base.type = &tft_eve_type; + + self->addr = addr; + self->size = size; + self->width = x; + self->height = y; + self->rowsize = rowsize; + self->byte_per_pixel = bpp; + self->type = format; + self->loaded = 1; + self->prev_tft_mode = tft_active_mode; + + if (!add_ramg_object((void *)self)) { + mp_raise_ValueError("Error adding ramg object"); + } + + ft8_ramg_ptr += size; + eve_tft_obj = NULL; + + FT8_cmd_memzero(self->addr, self->size); + FT8_cmd_execute(250); + + return MP_OBJ_FROM_PTR(self); +} + +//-------------------------------------------- +STATIC mp_obj_t TFT_EVE_free(mp_obj_t self_in) +{ + _check_inlist(eve_obj, 0); + tft_eve_obj_t *self = (tft_eve_obj_t *)self_in; + if (self->loaded == 0) return mp_const_true; + + FT8_cmd_memcpy(self->addr, self->addr + self->size, ft8_ramg_ptr - (self->addr+self->size)); + bool res = FT8_cmd_execute(250); + ft8_ramg_ptr -= self->size; + self->loaded = 0; + + adjust_ramg_objects((void *)self, self->addr, self->size); + + if (res) return mp_const_true; + return mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(TFT_EVE_free_obj, TFT_EVE_free); + +//------------------------------------------------ +static void _tft_eve_activate(tft_eve_obj_t *self) +{ + self->prev_tft_mode = tft_active_mode; + tft_active_mode = TFT_MODE_EVE; + disp_spi = NULL; + // === SET TFT GLOBAL VARIABLES + TFT_saveClipWin(); + _width = self->width; + _height = self->height; + dispWin.x1 = 0; + dispWin.y1 = 0; + dispWin.x2 = _width; + dispWin.y2 = _height; +} + +//------------------------------------------------ +STATIC mp_obj_t TFT_EVE_activate(mp_obj_t self_in) +{ + tft_eve_obj_t *self = (tft_eve_obj_t *)self_in; + eve_tft_obj = self; + if (tft_active_mode != TFT_MODE_EVE) _tft_eve_activate(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(TFT_EVE_activate_obj, TFT_EVE_activate); + +//-------------------------------------------------- +STATIC mp_obj_t TFT_EVE_deactivate(mp_obj_t self_in) +{ + tft_eve_obj_t *self = (tft_eve_obj_t *)self_in; + if (tft_active_mode == TFT_MODE_EVE) { + tft_active_mode = self->prev_tft_mode; + eve_tft_obj = NULL; + TFT_restoreClipWin(); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(TFT_EVE_deactivate_obj, TFT_EVE_deactivate); + +//-------------------------------------------------------------------- +STATIC mp_obj_t TFT_EVE_clear(size_t n_args, const mp_obj_t *args) +{ + _check_inlist(eve_obj, 0); + tft_eve_obj_t *self = (tft_eve_obj_t *)args[0]; + if (self->loaded == 0) return mp_const_true; + + FT8_cmd_memzero(self->addr, self->size); + FT8_cmd_execute(250); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(TFT_EVE_clear_obj, 1, 2, TFT_EVE_clear); + +//----------------------------------------------------------------------------------------- +STATIC mp_obj_t TFT_EVE_show(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { ARG_x, ARG_y }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + }; + _check_inlist(eve_obj, 1); + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + tft_eve_obj_t *self = pos_args[0]; + + if (self->loaded == 0) { + mp_raise_ValueError("Unloaded"); + } + + int x = args[ARG_x].u_int; + int y = args[ARG_y].u_int; + + if ((eve_chip_id >= 0x810)) FT8_cmd_dl(BITMAP_LAYOUT_H(self->rowsize>>10, self->height>>9)); + FT8_cmd_dl(BITMAP_LAYOUT(self->type, self->rowsize , self->height)); + if ((eve_chip_id >= 0x810)) FT8_cmd_dl(BITMAP_SIZE_H(self->width>>9, self->height>>9)); + FT8_cmd_dl(BITMAP_SIZE(FT8_NEAREST, FT8_BORDER, FT8_BORDER, self->width, self->height)); + FT8_cmd_dl(DL_BEGIN | FT8_BITMAPS); + FT8_cmd_dl(BITMAP_SOURCE(self->addr)); + FT8_cmd_dl(VERTEX2F(x*16, y*16)); + FT8_cmd_dl(DL_END); + + eve_tft_obj = self; + if (tft_active_mode != TFT_MODE_EVE) _tft_eve_activate(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(TFT_EVE_show_obj, 0, TFT_EVE_show); + +//------------------------------------------------------------ +STATIC const mp_rom_map_elem_t tft_eve_locals_dict_table[] = { + // instance methods + //{ MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&TFT_EVE_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_free), MP_ROM_PTR(&TFT_EVE_free_obj) }, + { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&TFT_EVE_activate_obj) }, + { MP_ROM_QSTR(MP_QSTR_deselect), MP_ROM_PTR(&TFT_EVE_deactivate_obj) }, + { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&TFT_EVE_show_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&TFT_EVE_clear_obj) }, + + { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&display_tft_drawPixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&display_tft_drawLine_obj) }, + { MP_ROM_QSTR(MP_QSTR_lineByAngle), MP_ROM_PTR(&display_tft_drawLineByAngle_obj) }, + { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&display_tft_drawTriangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&display_tft_drawCircle_obj) }, + { MP_ROM_QSTR(MP_QSTR_ellipse), MP_ROM_PTR(&display_tft_drawEllipse_obj) }, + { MP_ROM_QSTR(MP_QSTR_arc), MP_ROM_PTR(&display_tft_drawArc_obj) }, + { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&display_tft_drawPoly_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&display_tft_drawRect_obj) }, + { MP_ROM_QSTR(MP_QSTR_roundrect), MP_ROM_PTR(&display_tft_drawRoundRect_obj) }, + { MP_ROM_QSTR(MP_QSTR_font), MP_ROM_PTR(&display_tft_setFont_obj) }, + { MP_ROM_QSTR(MP_QSTR_fontSize), MP_ROM_PTR(&display_tft_getFontSize_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&display_tft_print_obj) }, + { MP_ROM_QSTR(MP_QSTR_screensize), MP_ROM_PTR(&display_tft_getSize_obj) }, + { MP_ROM_QSTR(MP_QSTR_setwin), MP_ROM_PTR(&display_tft_setclipwin_obj) }, + { MP_ROM_QSTR(MP_QSTR_resetwin), MP_ROM_PTR(&display_tft_resetclipwin_obj) }, + + // Constants + { MP_ROM_QSTR(MP_QSTR_CENTER), MP_ROM_INT(CENTER) }, + { MP_ROM_QSTR(MP_QSTR_RIGHT), MP_ROM_INT(RIGHT) }, + { MP_ROM_QSTR(MP_QSTR_BOTTOM), MP_ROM_INT(BOTTOM) }, + { MP_ROM_QSTR(MP_QSTR_LASTX), MP_ROM_INT(LASTX) }, + { MP_ROM_QSTR(MP_QSTR_LASTY), MP_ROM_INT(LASTY) }, + + { MP_ROM_QSTR(MP_QSTR_FONT_Default), MP_ROM_INT(DEFAULT_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_DejaVu18), MP_ROM_INT(DEJAVU18_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_DejaVu24), MP_ROM_INT(DEJAVU24_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_Ubuntu), MP_ROM_INT(UBUNTU16_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_Comic), MP_ROM_INT(COMIC24_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_Minya), MP_ROM_INT(MINYA24_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_Tooney), MP_ROM_INT(TOONEY32_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_Small), MP_ROM_INT(SMALL_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_DefaultSmall), MP_ROM_INT(DEF_SMALL_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_7seg), MP_ROM_INT(FONT_7SEG) }, + + { MP_ROM_QSTR(MP_QSTR_BLACK), MP_ROM_INT(iTFT_BLACK) }, + { MP_ROM_QSTR(MP_QSTR_NAVY), MP_ROM_INT(iTFT_NAVY) }, + { MP_ROM_QSTR(MP_QSTR_DARKGREEN), MP_ROM_INT(iTFT_DARKGREEN) }, + { MP_ROM_QSTR(MP_QSTR_DARKCYAN), MP_ROM_INT(iTFT_DARKCYAN) }, + { MP_ROM_QSTR(MP_QSTR_MAROON), MP_ROM_INT(iTFT_MAROON) }, + { MP_ROM_QSTR(MP_QSTR_PURPLE), MP_ROM_INT(iTFT_PURPLE) }, + { MP_ROM_QSTR(MP_QSTR_OLIVE), MP_ROM_INT(iTFT_OLIVE) }, + { MP_ROM_QSTR(MP_QSTR_LIGHTGREY), MP_ROM_INT(iTFT_LIGHTGREY) }, + { MP_ROM_QSTR(MP_QSTR_DARKGREY), MP_ROM_INT(iTFT_DARKGREY) }, + { MP_ROM_QSTR(MP_QSTR_BLUE), MP_ROM_INT(iTFT_BLUE) }, + { MP_ROM_QSTR(MP_QSTR_GREEN), MP_ROM_INT(iTFT_GREEN) }, + { MP_ROM_QSTR(MP_QSTR_CYAN), MP_ROM_INT(iTFT_CYAN) }, + { MP_ROM_QSTR(MP_QSTR_RED), MP_ROM_INT(iTFT_RED) }, + { MP_ROM_QSTR(MP_QSTR_MAGENTA), MP_ROM_INT(iTFT_MAGENTA) }, + { MP_ROM_QSTR(MP_QSTR_YELLOW), MP_ROM_INT(iTFT_YELLOW) }, + { MP_ROM_QSTR(MP_QSTR_WHITE), MP_ROM_INT(iTFT_WHITE) }, + { MP_ROM_QSTR(MP_QSTR_ORANGE), MP_ROM_INT(iTFT_ORANGE) }, + { MP_ROM_QSTR(MP_QSTR_GREENYELLOW), MP_ROM_INT(iTFT_GREENYELLOW) }, + { MP_ROM_QSTR(MP_QSTR_PINK), MP_ROM_INT(iTFT_PINK) }, +}; +STATIC MP_DEFINE_CONST_DICT(tft_eve_locals_dict, tft_eve_locals_dict_table); + + +//----------------------------------- +const mp_obj_type_t tft_eve_type = { + { &mp_type_type }, + .name = MP_QSTR_TFT, + .print = tft_eve_printinfo, + .make_new = tft_eve_make_new, + .locals_dict = (mp_obj_t)&tft_eve_locals_dict, +}; + +// ^^^^ TFT object ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +//================================================================ +STATIC const mp_rom_map_elem_t display_eve_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&display_eve_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&display_eve_config_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&display_tft_deinit_obj) }, + + { MP_ROM_QSTR(MP_QSTR_calibrate), MP_ROM_PTR(&EVE_calibrate_obj) }, + { MP_ROM_QSTR(MP_QSTR_startlist), MP_ROM_PTR(&EVE_startlist_obj) }, + { MP_ROM_QSTR(MP_QSTR_endlist), MP_ROM_PTR(&EVE_endlist_obj) }, + { MP_ROM_QSTR(MP_QSTR_savelist), MP_ROM_PTR(&EVE_savelist_obj) }, + { MP_ROM_QSTR(MP_QSTR_appendlist), MP_ROM_PTR(&EVE_appendlist_obj) }, + { MP_ROM_QSTR(MP_QSTR_dumplist), MP_ROM_PTR(&EVE_dumplist_obj) }, + { MP_ROM_QSTR(MP_QSTR_dumpcmd), MP_ROM_PTR(&EVE_dumpcmd_obj) }, + { MP_ROM_QSTR(MP_QSTR_point), MP_ROM_PTR(&EVE_point_obj) }, + { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&EVE_circle_obj) }, + { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&EVE_line_obj) }, + { MP_ROM_QSTR(MP_QSTR_strips), MP_ROM_PTR(&EVE_strips_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&EVE_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&EVE_rectangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&EVE_triangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_scissorSize), MP_ROM_PTR(&EVE_scissorSize_obj) }, + { MP_ROM_QSTR(MP_QSTR_scissorXY), MP_ROM_PTR(&EVE_scissorXY_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&EVE_text_obj) }, + { MP_ROM_QSTR(MP_QSTR_number), MP_ROM_PTR(&EVE_number_obj) }, + { MP_ROM_QSTR(MP_QSTR_button), MP_ROM_PTR(&EVE_button_obj) }, + { MP_ROM_QSTR(MP_QSTR_keys), MP_ROM_PTR(&EVE_keys_obj) }, + { MP_ROM_QSTR(MP_QSTR_clock), MP_ROM_PTR(&EVE_clock_obj) }, + { MP_ROM_QSTR(MP_QSTR_gauge), MP_ROM_PTR(&EVE_gauge_obj) }, + { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&EVE_toggle_obj) }, + { MP_ROM_QSTR(MP_QSTR_scrollbar), MP_ROM_PTR(&EVE_scrollbar_obj) }, + { MP_ROM_QSTR(MP_QSTR_slider), MP_ROM_PTR(&EVE_slider_obj) }, + { MP_ROM_QSTR(MP_QSTR_progress), MP_ROM_PTR(&EVE_progress_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&EVE_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_backlight), MP_ROM_PTR(&EVE_backlight_obj) }, + { MP_ROM_QSTR(MP_QSTR_color), MP_ROM_PTR(&EVE_color_obj) }, + { MP_ROM_QSTR(MP_QSTR_fgcolor), MP_ROM_PTR(&EVE_fgcolor_obj) }, + { MP_ROM_QSTR(MP_QSTR_bgcolor), MP_ROM_PTR(&EVE_bgcolor_obj) }, + { MP_ROM_QSTR(MP_QSTR_alpha), MP_ROM_PTR(&EVE_alpha_obj) }, + { MP_ROM_QSTR(MP_QSTR_alphafunc), MP_ROM_PTR(&EVE_alphafunc_obj) }, + { MP_ROM_QSTR(MP_QSTR_colormask), MP_ROM_PTR(&EVE_colormask_obj) }, + { MP_ROM_QSTR(MP_QSTR_blend), MP_ROM_PTR(&EVE_blend_obj) }, + { MP_ROM_QSTR(MP_QSTR_stencilfunc), MP_ROM_PTR(&EVE_stencilfunc_obj) }, + { MP_ROM_QSTR(MP_QSTR_stencilmask), MP_ROM_PTR(&EVE_stencilmask_obj) }, + { MP_ROM_QSTR(MP_QSTR_stencilop), MP_ROM_PTR(&EVE_stencilop_obj) }, + { MP_ROM_QSTR(MP_QSTR_gradient), MP_ROM_PTR(&EVE_gradient_obj) }, + { MP_ROM_QSTR(MP_QSTR_image), MP_ROM_PTR(&EVE_showimage_obj) }, + { MP_ROM_QSTR(MP_QSTR_setbitmap), MP_ROM_PTR(&EVE_setbitmap_obj) }, + { MP_ROM_QSTR(MP_QSTR_video), MP_ROM_PTR(&EVE_playvideo_obj) }, + { MP_ROM_QSTR(MP_QSTR_closevideo), MP_ROM_PTR(&EVE_closevideo_obj) }, + { MP_ROM_QSTR(MP_QSTR_videoframe), MP_ROM_PTR(&EVE_videoframe_obj) }, + { MP_ROM_QSTR(MP_QSTR_lastframe), MP_ROM_PTR(&EVE_lastframe_obj) }, + { MP_ROM_QSTR(MP_QSTR_videobuffer), MP_ROM_PTR(&EVE_videobuffer_obj) }, + { MP_ROM_QSTR(MP_QSTR_getprops), MP_ROM_PTR(&EVE_getprops_obj) }, + { MP_ROM_QSTR(MP_QSTR_userfont), MP_ROM_PTR(&EVE_userfont_obj) }, + { MP_ROM_QSTR(MP_QSTR_fontinfo), MP_ROM_PTR(&EVE_fontinfo_obj) }, + { MP_ROM_QSTR(MP_QSTR_freeobjects), MP_ROM_PTR(&EVE_freeobjects_obj) }, + { MP_ROM_QSTR(MP_QSTR_memWrite), MP_ROM_PTR(&EVE_memWrite_obj) }, + { MP_ROM_QSTR(MP_QSTR_memRead), MP_ROM_PTR(&EVE_memRead_obj) }, + { MP_ROM_QSTR(MP_QSTR_memZero), MP_ROM_PTR(&EVE_memZero_obj) }, + { MP_ROM_QSTR(MP_QSTR_memSet), MP_ROM_PTR(&EVE_memSet_obj) }, + { MP_ROM_QSTR(MP_QSTR_tag), MP_ROM_PTR(&EVE_tag_obj) }, + { MP_ROM_QSTR(MP_QSTR_tagmask), MP_ROM_PTR(&EVE_tagmask_obj) }, + { MP_ROM_QSTR(MP_QSTR_gettag), MP_ROM_PTR(&EVE_gettag_obj) }, + { MP_ROM_QSTR(MP_QSTR_gettagXY), MP_ROM_PTR(&EVE_gettagXY_obj) }, + { MP_ROM_QSTR(MP_QSTR_touchXY), MP_ROM_PTR(&EVE_touchXY_obj) }, + { MP_ROM_QSTR(MP_QSTR_vol_play), MP_ROM_PTR(&EVE_vol_pb_obj) }, + { MP_ROM_QSTR(MP_QSTR_vol_sound), MP_ROM_PTR(&EVE_vol_sound_obj) }, + { MP_ROM_QSTR(MP_QSTR_sound), MP_ROM_PTR(&EVE_sound_obj) }, + { MP_ROM_QSTR(MP_QSTR_rotate), MP_ROM_PTR(&EVE_rotate_obj) }, + { MP_ROM_QSTR(MP_QSTR_screensize), MP_ROM_PTR(&EVE_screensize_obj) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_Font), MP_ROM_PTR(&font_eve_type) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_Image), MP_ROM_PTR(&image_eve_type) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_Console), MP_ROM_PTR(&console_eve_type) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_Tft), MP_ROM_PTR(&tft_eve_type) }, + + // SPI bus constants + { MP_ROM_QSTR(MP_QSTR_HSPI), MP_ROM_INT(HSPI_HOST) }, + { MP_ROM_QSTR(MP_QSTR_VSPI), MP_ROM_INT(VSPI_HOST) }, + + // Options constants + { MP_ROM_QSTR(MP_QSTR_OPT_CENTERX), MP_ROM_INT(FT8_OPT_CENTERX) }, + { MP_ROM_QSTR(MP_QSTR_OPT_CENTERY), MP_ROM_INT(FT8_OPT_CENTERY) }, + { MP_ROM_QSTR(MP_QSTR_OPT_CENTER), MP_ROM_INT(FT8_OPT_CENTER) }, + { MP_ROM_QSTR(MP_QSTR_OPT_RIGHTX), MP_ROM_INT(FT8_OPT_RIGHTX) }, + { MP_ROM_QSTR(MP_QSTR_OPT_LEFTX), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_OPT_FLAT), MP_ROM_INT(FT8_OPT_FLAT) }, + { MP_ROM_QSTR(MP_QSTR_OPT_3D), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_OPT_MONO), MP_ROM_INT(FT8_OPT_MONO) }, + { MP_ROM_QSTR(MP_QSTR_OPT_NODL), MP_ROM_INT(FT8_OPT_NODL) }, + { MP_ROM_QSTR(MP_QSTR_OPT_SIGNED), MP_ROM_INT(FT8_OPT_SIGNED) }, + { MP_ROM_QSTR(MP_QSTR_OPT_NOBACK), MP_ROM_INT(FT8_OPT_NOBACK) }, + { MP_ROM_QSTR(MP_QSTR_OPT_NOTICKS), MP_ROM_INT(FT8_OPT_NOTICKS) }, + { MP_ROM_QSTR(MP_QSTR_OPT_NOPOINTER), MP_ROM_INT(FT8_OPT_NOPOINTER) }, + { MP_ROM_QSTR(MP_QSTR_OPT_NOHANDS), MP_ROM_INT(FT8_OPT_NOHANDS) }, + { MP_ROM_QSTR(MP_QSTR_OPT_NOSECS), MP_ROM_INT(FT8_OPT_NOSECS) }, + { MP_ROM_QSTR(MP_QSTR_OPT_NOTEAR), MP_ROM_INT(FT8_OPT_NOTEAR) }, + { MP_ROM_QSTR(MP_QSTR_OPT_FULLSCREEN), MP_ROM_INT(FT8_OPT_FULLSCREEN) }, + { MP_ROM_QSTR(MP_QSTR_OPT_MEDIAFIFO), MP_ROM_INT(FT8_OPT_MEDIAFIFO) }, + { MP_ROM_QSTR(MP_QSTR_OPT_SOUND), MP_ROM_INT(FT8_OPT_SOUND) }, + { MP_ROM_QSTR(MP_QSTR_OPT_RGB565), MP_ROM_INT(0) }, + + // Blend constants + { MP_ROM_QSTR(MP_QSTR_ZERO), MP_ROM_INT(FT8_ZERO) }, + { MP_ROM_QSTR(MP_QSTR_ONE), MP_ROM_INT(FT8_ONE) }, + { MP_ROM_QSTR(MP_QSTR_SRC_ALPHA), MP_ROM_INT(FT8_SRC_ALPHA) }, + { MP_ROM_QSTR(MP_QSTR_DST_ALPHA), MP_ROM_INT(FT8_DST_ALPHA) }, + { MP_ROM_QSTR(MP_QSTR_ONE_MINUS_SRC_ALPHA), MP_ROM_INT(FT8_ONE_MINUS_SRC_ALPHA) }, + { MP_ROM_QSTR(MP_QSTR_ONE_MINUS_DST_ALPHA), MP_ROM_INT(FT8_ONE_MINUS_DST_ALPHA) }, + + // Bitmap Wrap & Filter constants + { MP_ROM_QSTR(MP_QSTR_NEAREST), MP_ROM_INT(FT8_NEAREST) }, + { MP_ROM_QSTR(MP_QSTR_BILINEAR), MP_ROM_INT(FT8_BILINEAR) }, + { MP_ROM_QSTR(MP_QSTR_BORDER), MP_ROM_INT(FT8_BORDER) }, + { MP_ROM_QSTR(MP_QSTR_REPEAT), MP_ROM_INT(FT8_REPEAT) }, + + // Bitmap format constants + { MP_ROM_QSTR(MP_QSTR_IMG_ARGB1555), MP_ROM_INT(FT8_ARGB1555) }, + { MP_ROM_QSTR(MP_QSTR_IMG_L1), MP_ROM_INT(FT8_L1) }, + { MP_ROM_QSTR(MP_QSTR_IMG_L2), MP_ROM_INT(FT8_L2) }, + { MP_ROM_QSTR(MP_QSTR_IMG_L4), MP_ROM_INT(FT8_L4) }, + { MP_ROM_QSTR(MP_QSTR_IMG_L8), MP_ROM_INT(FT8_L8) }, + { MP_ROM_QSTR(MP_QSTR_IMG_RGB332), MP_ROM_INT(FT8_RGB332) }, + { MP_ROM_QSTR(MP_QSTR_IMG_ARGB2), MP_ROM_INT(FT8_ARGB2) }, + { MP_ROM_QSTR(MP_QSTR_IMG_ARGB4), MP_ROM_INT(FT8_ARGB4) }, + { MP_ROM_QSTR(MP_QSTR_IMG_RGB565), MP_ROM_INT(FT8_RGB565) }, + { MP_ROM_QSTR(MP_QSTR_BMP_TEXT8X8), MP_ROM_INT(FT8_TEXT8X8) }, + { MP_ROM_QSTR(MP_QSTR_BMP_TEXTVGA), MP_ROM_INT(FT8_TEXTVGA) }, + { MP_ROM_QSTR(MP_QSTR_BMP_PALETTED), MP_ROM_INT(FT8_PALETTED) }, + { MP_ROM_QSTR(MP_QSTR_BMP_BARGRAPH), MP_ROM_INT(FT8_BARGRAPH) }, + + // Image type constants + { MP_ROM_QSTR(MP_QSTR_IMG_PNG), MP_ROM_INT(IMAGE_TYPE_PNG) }, + { MP_ROM_QSTR(MP_QSTR_IMG_JPG), MP_ROM_INT(IMAGE_TYPE_JPG) }, + { MP_ROM_QSTR(MP_QSTR_IMG_RAW), MP_ROM_INT(IMAGE_TYPE_RAW) }, + { MP_ROM_QSTR(MP_QSTR_IMG_COMPRESSED), MP_ROM_INT(IMAGE_TYPE_BIN) }, + { MP_ROM_QSTR(MP_QSTR_IMG_AUTO), MP_ROM_INT(IMAGE_TYPE_NONE) }, + + // Color constants + { MP_ROM_QSTR(MP_QSTR_BLACK), MP_ROM_INT(EVE_BLACK) }, + { MP_ROM_QSTR(MP_QSTR_NAVY), MP_ROM_INT(EVE_NAVY) }, + { MP_ROM_QSTR(MP_QSTR_DARKGREEN), MP_ROM_INT(EVE_DARKGREEN) }, + { MP_ROM_QSTR(MP_QSTR_DARKCYAN), MP_ROM_INT(EVE_DARKCYAN) }, + { MP_ROM_QSTR(MP_QSTR_MAROON), MP_ROM_INT(EVE_MAROON) }, + { MP_ROM_QSTR(MP_QSTR_PURPLE), MP_ROM_INT(EVE_PURPLE) }, + { MP_ROM_QSTR(MP_QSTR_OLIVE), MP_ROM_INT(EVE_OLIVE) }, + { MP_ROM_QSTR(MP_QSTR_LIGHTGREY), MP_ROM_INT(EVE_LIGHTGREY) }, + { MP_ROM_QSTR(MP_QSTR_DARKGREY), MP_ROM_INT(EVE_DARKGREY) }, + { MP_ROM_QSTR(MP_QSTR_BLUE), MP_ROM_INT(EVE_BLUE) }, + { MP_ROM_QSTR(MP_QSTR_GREEN), MP_ROM_INT(EVE_GREEN) }, + { MP_ROM_QSTR(MP_QSTR_CYAN), MP_ROM_INT(EVE_CYAN) }, + { MP_ROM_QSTR(MP_QSTR_RED), MP_ROM_INT(EVE_RED) }, + { MP_ROM_QSTR(MP_QSTR_MAGENTA), MP_ROM_INT(EVE_MAGENTA) }, + { MP_ROM_QSTR(MP_QSTR_YELLOW), MP_ROM_INT(EVE_YELLOW) }, + { MP_ROM_QSTR(MP_QSTR_WHITE), MP_ROM_INT(EVE_WHITE) }, + { MP_ROM_QSTR(MP_QSTR_ORANGE), MP_ROM_INT(EVE_ORANGE) }, + { MP_ROM_QSTR(MP_QSTR_GREENYELLOW), MP_ROM_INT(EVE_GREENYELLOW) }, + { MP_ROM_QSTR(MP_QSTR_PINK), MP_ROM_INT(EVE_PINK) }, + + // Rotation constants + { MP_ROM_QSTR(MP_QSTR_LANDSCAPE), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_LANDSCAPE_FLIP), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_PORTRAIT), MP_ROM_INT(2) }, + { MP_ROM_QSTR(MP_QSTR_PORTRAIT_FLIP), MP_ROM_INT(3) }, + { MP_ROM_QSTR(MP_QSTR_MIRRORED), MP_ROM_INT(4) }, +}; +STATIC MP_DEFINE_CONST_DICT(display_eve_locals_dict, display_eve_locals_dict_table); + + +//====================================== +const mp_obj_type_t display_eve_type = { + { &mp_type_type }, + .name = MP_QSTR_EVE, + .print = display_eve_printinfo, + .make_new = display_eve_make_new, + .locals_dict = (mp_obj_t)&display_eve_locals_dict, +}; + +#endif // CONFIG_MICROPY_USE_EVE diff --git a/MicroPython_BUILD/components/micropython/esp32/moddisplay_tft.c b/MicroPython_BUILD/components/micropython/esp32/moddisplay_tft.c new file mode 100644 index 00000000..b2606a50 --- /dev/null +++ b/MicroPython_BUILD/components/micropython/esp32/moddisplay_tft.c @@ -0,0 +1,1706 @@ +/* + * This file is part of the MicroPython ESP32 project, https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo + * + * The MIT License (MIT) + * + * Copyright (c) 2018 LoBo (https://github.com/loboris) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT + +#include +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "rom/ets_sys.h" +#include "esp_system.h" +#include "esp_task_wdt.h" + +#include "driver/gpio.h" + +#include "tft/tftspi.h" +#include "tft/tft.h" +#include "extmod/vfs_native.h" +#include "machine_hw_spi.h" +#include "modmachine.h" + +extern uint8_t disp_used_spi_host; + +typedef struct _display_tft_obj_t { + mp_obj_base_t base; + machine_hw_spi_obj_t *spi; + display_config_t dconfig; + exspi_device_handle_t disp_spi_dev; + exspi_device_handle_t ts_spi_dev; + exspi_device_handle_t *disp_spi; + exspi_device_handle_t *ts_spi; + uint32_t tp_calx; + uint32_t tp_caly; +} display_tft_obj_t; + +const mp_obj_type_t display_tft_type; + +static const char* const display_types[] = { + "ILI9341", + "ILI9488", + "ST7789V", + "ST7735", + "ST7735R", + "ST7735B", + "M5STACK", + "Unknown", +}; + +static const char* const touch_types[] = { + "None", + "xpt2046", + "stmpe610", + "Unknown", +}; + +// constructor(id, ...) +//----------------------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + + display_tft_obj_t *self = m_new_obj(display_tft_obj_t); + self->base.type = &display_tft_type; + self->spi = NULL; + self->disp_spi_dev.handle = NULL; + self->disp_spi_dev.cs = -1; + self->disp_spi_dev.dc = -1; + self->disp_spi_dev.selected = 0; + self->ts_spi_dev.handle = NULL; + self->ts_spi_dev.cs = -1; + self->ts_spi_dev.dc = -1; + self->ts_spi_dev.selected = 0; + self->disp_spi = &self->disp_spi_dev; + self->ts_spi = &self->ts_spi_dev; + + return MP_OBJ_FROM_PTR(self); +} + +//----------------------------------------------------------------------------------------------- +STATIC void display_tft_printinfo(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + display_tft_obj_t *self = self_in; + if (self->disp_spi->handle) { + mp_printf(print, "TFT (%dx%d, Type=%s, Ready: %s, Color mode: %d-bit, Clk=%u Hz, RdClk=%u Hz, Touch: %s)\n", + self->dconfig.width, self->dconfig.height, display_types[self->dconfig.type], ((self->disp_spi->handle) ? "yes" : "no"), self->dconfig.color_bits, self->dconfig.speed, self->dconfig.rdspeed, ((self->ts_spi->handle) ? "yes" : "no")); + mp_printf(print, "Pins (miso=%d, mosi=%d, clk=%d, cs=%d, dc=%d, reset=%d, backlight=%d)", self->dconfig.miso, self->dconfig.mosi, self->dconfig.sck, self->dconfig.cs, self->dconfig.dc, self->dconfig.rst, self->dconfig.bckl); + if (self->ts_spi->handle) { + mp_printf(print, "\nTouch (Enabled, type: %s, cs=%d)", touch_types[self->dconfig.touch], self->dconfig.tcs); + } + } + else { + mp_printf(print, "TFT (Not initialized)"); + } +} + +/* + * tftspi.c low level driver uses some global variables + * Here we set those variables so that multiple displays can be used + */ +//------------------------------------------------- +static int setupDevice(display_tft_obj_t *disp_dev) +{ + if (tft_active_mode == TFT_MODE_EVE) return 0; + + if (disp_dev->disp_spi->handle == NULL) return 1; + + if (disp_spi != disp_dev->disp_spi) { + disp_spi = disp_dev->disp_spi; + ts_spi = disp_dev->ts_spi; + TFT_display_setvars(&disp_dev->dconfig); + + tp_calx = disp_dev->tp_calx; + tp_caly = disp_dev->tp_caly; + spi_device_select(disp_spi, 1); + spi_device_deselect(disp_spi); + } + + return 0; +} + +//-------------------------------------- +STATIC color_t intToColor(uint32_t cint) +{ + color_t cl = {0,0,0}; + cl.r = (cint >> 16) & 0xFF; + cl.g = (cint >> 8) & 0xFF; + cl.b = cint & 0xFF; + return cl; +} + +//------------------------------------------------------ +STATIC void spi_deinit_internal(display_tft_obj_t *self) +{ + if (self->disp_spi->handle) { + esp_err_t ret; + // Deinitialize display spi device(s) + if (self->ts_spi->handle) { + ret = remove_extspi_device(self->ts_spi); + if (ret != ESP_OK) { + mp_raise_msg(&mp_type_OSError, "Error removing touch device"); + } + } + ret = remove_extspi_device(self->disp_spi); + if (ret != ESP_OK) { + mp_raise_msg(&mp_type_OSError, "Error removing display device"); + } + + gpio_pad_select_gpio(self->dconfig.miso); + gpio_pad_select_gpio(self->dconfig.mosi); + gpio_pad_select_gpio(self->dconfig.sck); + } +} + + +//----------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_type, ARG_host, ARG_width, ARG_height, ARG_speed, ARG_miso, ARG_mosi, ARG_clk, ARG_cs, + ARG_dc, ARG_tcs, ARG_rst, ARG_bckl, ARG_bcklon, ARG_hastouch, ARG_invrot, ARG_bgr, ARG_cbits, ARG_rot, ARG_splash }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_type, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = DISP_TYPE_ST7789V } }, + { MP_QSTR_spihost, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = HSPI_HOST } }, + { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = DEFAULT_TFT_DISPLAY_WIDTH } }, + { MP_QSTR_height, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = DEFAULT_TFT_DISPLAY_HEIGHT } }, + { MP_QSTR_speed, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 10000000 } }, + { MP_QSTR_miso, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_mosi, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_clk, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_cs, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_dc, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_tcs, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_rst_pin, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_backl_pin, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_backl_on, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_hastouch, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = TOUCH_TYPE_NONE } }, + { MP_QSTR_invrot, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_bgr, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = false } }, + { MP_QSTR_color_bits, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 24 } }, + { MP_QSTR_rot, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_splash, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = true } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + display_tft_obj_t *self = pos_args[0]; + esp_err_t ret; + + // === deinitialize display spi device if it was initialized === + if (self->disp_spi->handle) spi_deinit_internal(self); + + // === Get arguments === + if ((args[ARG_host].u_int != HSPI_HOST) && (args[ARG_host].u_int != VSPI_HOST)) { + mp_raise_ValueError("SPI host must be either HSPI(1) or VSPI(2)"); + } + if ((SPIbus_configs[VSPI_HOST] == NULL) && (args[ARG_host].u_int == VSPI_HOST)) { + mp_raise_ValueError("SPI host must be HSPI(1), VSPI(2) used by SPIRAM"); + } + + if ((args[ARG_type].u_int < 0) || (args[ARG_type].u_int >= DISP_TYPE_MAX)) { + mp_raise_ValueError("Unsupported display type"); + } + + if ((args[ARG_cbits].u_int != 16) && (args[ARG_cbits].u_int != 24)) { + mp_raise_ValueError("Unsupported color bits"); + } + + self->dconfig.color_bits = args[ARG_cbits].u_int; + + self->dconfig.type = args[ARG_type].u_int; + + if ((args[ARG_hastouch].u_int == TOUCH_TYPE_XPT2046) || (args[ARG_hastouch].u_int == TOUCH_TYPE_STMPE610)) { + if (args[ARG_tcs].u_int < 0) { + mp_raise_ValueError("Touch selected but no touch cs given"); + } + self->dconfig.touch = args[ARG_hastouch].u_int; + if (args[ARG_hastouch].u_int == TOUCH_TYPE_XPT2046) { + self->tp_calx = TP_CALX_XPT2046; + self->tp_caly = TP_CALY_XPT2046; + } + else { + self->tp_calx = TP_CALX_STMPE610; + self->tp_caly = TP_CALY_STMPE610; + } + self->dconfig.tcs = args[ARG_tcs].u_int; + } + else self->dconfig.touch = TOUCH_TYPE_NONE; + + self->dconfig.host = args[ARG_host].u_int; + self->dconfig.gamma = 0; + self->dconfig.width = args[ARG_width].u_int; // smaller dimension + self->dconfig.height = args[ARG_height].u_int; // larger dimension + self->dconfig.rdspeed = 8000000; + if (args[ARG_invrot].u_int >= 0) self->dconfig.invrot = args[ARG_invrot].u_int; + else { + if ((self->dconfig.type == DISP_TYPE_ST7789V) || + (self->dconfig.type == DISP_TYPE_ST7735) || + (self->dconfig.type == DISP_TYPE_ST7735R) || + (self->dconfig.type == DISP_TYPE_ST7735B)) self->dconfig.invrot = 1; + else if (self->dconfig.type == DISP_TYPE_M5STACK) self->dconfig.invrot = 3; + else self->dconfig.invrot = 0; + } + + if (args[ARG_bgr].u_bool) self->dconfig.bgr = 8; + else self->dconfig.bgr = 0; + + self->dconfig.rst = args[ARG_rst].u_int; + self->dconfig.bckl = args[ARG_bckl].u_int; + self->dconfig.bckl_on = args[ARG_bcklon].u_int & 1; + + self->dconfig.miso = args[ARG_miso].u_int; + self->dconfig.mosi = args[ARG_mosi].u_int; + self->dconfig.sck = args[ARG_clk].u_int; + + self->dconfig.cs = args[ARG_cs].u_int; + self->dconfig.dc = args[ARG_dc].u_int; + + disp_spi = self->disp_spi; + ts_spi = self->ts_spi; + + int orient = args[ARG_rot].u_int; + if (orient < 0) { + if (self->dconfig.type == DISP_TYPE_M5STACK) orient = LANDSCAPE; + else orient = PORTRAIT; + } + else orient &= 3; + + // ================================ + // ==== Initialize the Display ==== + ret = TFT_display_init(&self->dconfig); + if (ret != ESP_OK) { + mp_raise_msg(&mp_type_OSError, "Error initializing display"); + } + + disp_used_spi_host = args[ARG_host].u_int; + + if (self->dconfig.type == DISP_TYPE_GENERIC) return mp_const_none; + + // ==== Set SPI clock used for display operations ==== + self->dconfig.speed = spi_set_speed(self->disp_spi, args[ARG_speed].u_int); + + max_rdclock = find_rd_speed(); + self->dconfig.rdspeed = max_rdclock; + + font_rotate = 0; + text_wrap = 0; + font_transparent = 0; + font_forceFixed = 0; + gray_scale = 0; + TFT_setRotation(orient); + self->dconfig.width = _width; + self->dconfig.height = _height; + TFT_setGammaCurve(0); + TFT_setFont(DEFAULT_FONT, NULL); + TFT_resetclipwin(); + if (args[ARG_splash].u_bool) { + int fhight = TFT_getfontheight(); + _fg = intToColor(iTFT_RED); + TFT_print("MicroPython", CENTER, (_height/2) - fhight - (fhight/2)); + _fg = intToColor(iTFT_GREEN); + TFT_print("MicroPython", CENTER, (_height/2) - (fhight/2)); + _fg = intToColor(iTFT_BLUE); + TFT_print("MicroPython", CENTER, (_height/2) + (fhight/2)); + _fg = intToColor(iTFT_GREEN); + } + + bcklOn(&self->dconfig); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_init_obj, 0, display_tft_init); + +//-------------------------------------------------- +STATIC mp_obj_t display_tft_deinit(mp_obj_t self_in) +{ + display_tft_obj_t *self = self_in; + if (setupDevice(self) == 0) { + spi_deinit_internal(self); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_deinit_obj, display_tft_deinit); + +//------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_drawPixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t color = _fg; + mp_int_t x = args[0].u_int; + mp_int_t y = args[1].u_int; + if (args[2].u_int >= 0) { + color = intToColor(args[2].u_int); + } + TFT_drawPixel(x, y, color, 1); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawPixel_obj, 2, display_tft_drawPixel); + +//------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_readPixel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t x = args[0].u_int; + mp_int_t y = args[1].u_int; + + color_t color = TFT_readPixel(x, y); + mp_int_t icolor = (int)((color.r << 16) | (color.g << 8) | color.b); + + return mp_obj_new_int(icolor); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_readPixel_obj, 2, display_tft_readPixel); + +//------------------------------------------------------------------------------------------------ +STATIC mp_obj_t display_tft_drawLine(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t color = _fg; + mp_int_t x0 = args[0].u_int; + mp_int_t y0 = args[1].u_int; + mp_int_t x1 = args[2].u_int; + mp_int_t y1 = args[3].u_int; + if (args[4].u_int >= 0) { + color = intToColor(args[4].u_int); + } + TFT_drawLine(x0, y0, x1, y1, color); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawLine_obj, 4, display_tft_drawLine); + +//------------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_drawLineByAngle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_start, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_length, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_angle, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t color = _fg; + mp_int_t x = args[0].u_int; + mp_int_t y = args[1].u_int; + mp_int_t start = args[2].u_int; + mp_int_t len = args[3].u_int; + mp_int_t angle = args[4].u_int; + if (args[5].u_int >= 0) { + color = intToColor(args[5].u_int); + } + TFT_drawLineByAngle(x, y, start, len, angle, color); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawLineByAngle_obj, 5, display_tft_drawLineByAngle); + +//---------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_drawTriangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t color = _fg; + mp_int_t x0 = args[0].u_int; + mp_int_t y0 = args[1].u_int; + mp_int_t x1 = args[2].u_int; + mp_int_t y1 = args[3].u_int; + mp_int_t x2 = args[4].u_int; + mp_int_t y2 = args[5].u_int; + if (args[6].u_int >= 0) { + color = intToColor(args[6].u_int); + } + if (args[7].u_int >= 0) { + TFT_fillTriangle(x0, y0, x1, y1, x2, y2, intToColor(args[7].u_int)); + } + TFT_drawTriangle(x0, y0, x1, y1, x2, y2, color); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawTriangle_obj, 6, display_tft_drawTriangle); + +//-------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_drawCircle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t color = _fg; + mp_int_t x = args[0].u_int; + mp_int_t y = args[1].u_int; + mp_int_t radius = args[2].u_int; + if (args[3].u_int >= 0) { + color = intToColor(args[3].u_int); + } + if (args[4].u_int >= 0) { + TFT_fillCircle(x, y, radius, intToColor(args[4].u_int)); + if (args[3].u_int != args[4].u_int) TFT_drawCircle(x, y, radius, color); + } + else TFT_drawCircle(x, y, radius, color); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawCircle_obj, 3, display_tft_drawCircle); + +//--------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_drawEllipse(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_rx, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_ry, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_opt, MP_ARG_INT, { .u_int = 15 } }, + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t color = _fg; + mp_int_t x = args[0].u_int; + mp_int_t y = args[1].u_int; + mp_int_t rx = args[2].u_int; + mp_int_t ry = args[3].u_int; + mp_int_t opt = args[4].u_int & 0x0F; + if (args[5].u_int >= 0) { + color = intToColor(args[5].u_int); + } + if (args[6].u_int >= 0) { + TFT_fillEllipse(x, y, rx, ry, intToColor(args[6].u_int), opt); + } + TFT_drawEllipse(x, y, rx, ry, color, opt); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawEllipse_obj, 4, display_tft_drawEllipse); + +//----------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_drawArc(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_thick, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_start, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_end, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 15 } }, + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t color = _fg; + color_t fill_color = _fg; + mp_int_t x = args[0].u_int; + mp_int_t y = args[1].u_int; + mp_int_t r = args[2].u_int; + mp_int_t th = args[3].u_int; + mp_int_t start = args[4].u_int; + mp_int_t end = args[5].u_int; + if (args[6].u_int >= 0) { + color = intToColor(args[6].u_int); + } + if (args[7].u_int >= 0) { + fill_color = intToColor(args[7].u_int); + } + TFT_drawArc(x, y, r, th, start, end, color, fill_color); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawArc_obj, 6, display_tft_drawArc); + +//------------------------------------------------------------------------------------------------ +STATIC mp_obj_t display_tft_drawPoly(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_sides, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_thick, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 1 } }, + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_rotate, MP_ARG_INT, { .u_int = 0 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t color = _fg; + color_t fill_color = _fg; + mp_int_t x = args[0].u_int; + mp_int_t y = args[1].u_int; + mp_int_t r = args[2].u_int; + mp_int_t sides = args[3].u_int; + mp_int_t th = args[4].u_int; + if (args[5].u_int >= 0) { + color = intToColor(args[5].u_int); + } + if (args[6].u_int >= 0) { + fill_color = intToColor(args[6].u_int); + } + TFT_drawPolygon(x, y, sides, r, color, fill_color, args[7].u_int, th); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawPoly_obj, 5, display_tft_drawPoly); + +//------------------------------------------------------------------------------------------------ +STATIC mp_obj_t display_tft_drawRect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t color = _fg; + mp_int_t x = args[0].u_int; + mp_int_t y = args[1].u_int; + mp_int_t w = args[2].u_int; + mp_int_t h = args[3].u_int; + if (args[4].u_int >= 0) { + color = intToColor(args[4].u_int); + } + if (args[5].u_int >= 0) { + TFT_fillRect(x, y, w, h, intToColor(args[5].u_int)); + } + TFT_drawRect(x, y, w, h, color); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawRect_obj, 4, display_tft_drawRect); + +//-------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_readScreen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_buffer, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t x = args[0].u_int; + mp_int_t y = args[1].u_int; + mp_int_t w = args[2].u_int; + mp_int_t h = args[3].u_int; + + // clipping + if ((x >= _width) || (y > _height)) { + mp_raise_ValueError("Point (x,y) outside the display area"); + } + + if (x < 0) { + w -= (0 - x); + x = 0; + } + if (y < 0) { + h -= (0 - y); + y = 0; + } + if (w < 0) w = 0; + if (h < 0) h = 0; + + if ((x + w) > (_width+1)) w = _width - x + 1; + if ((y + h) > (_height+1)) h = _height - y + 1; + if (w == 0) w = 1; + if (h == 0) h = 1; + + int clr_len = h*w; + int buf_len = (clr_len*3) + 1; + uint8_t *buf = NULL; + vstr_t vstr; + + if (args[4].u_obj == mp_const_none) { + vstr_init_len(&vstr, buf_len); + buf = (uint8_t *)vstr.buf; + } + else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[4].u_obj, &bufinfo, MP_BUFFER_WRITE); + if (bufinfo.len != buf_len) { + mp_raise_ValueError("Wrong buffer length"); + } + buf = (uint8_t *)bufinfo.buf; + } + memset(buf, 0, buf_len); + + esp_err_t ret = read_data(x, y, x+w+1, y+h+1, (uint32_t)clr_len, buf, 1); + + if (ret == ESP_OK) { + if (args[4].u_obj == mp_const_none) return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + else return mp_const_true; + } + return mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_readScreen_obj, 4, display_tft_readScreen); + +//----------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_drawRoundRect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t color = _fg; + mp_int_t x = args[0].u_int; + mp_int_t y = args[1].u_int; + mp_int_t w = args[2].u_int; + mp_int_t h = args[3].u_int; + mp_int_t r = args[4].u_int; + if (args[5].u_int >= 0) { + color = intToColor(args[5].u_int); + } + if (args[6].u_int >= 0) { + TFT_fillRoundRect(x, y, w, h, r, intToColor(args[6].u_int)); + } + TFT_drawRoundRect(x, y, w, h, r, color); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_drawRoundRect_obj, 5, display_tft_drawRoundRect); + +//-------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_fillScreen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t color = _bg; + if (args[0].u_int >= 0) { + color = intToColor(args[0].u_int); + } + TFT_fillScreen(color); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_fillScreen_obj, 0, display_tft_fillScreen); + +//----------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_fillWin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t color = _bg; + if (args[0].u_int >= 0) { + color = intToColor(args[0].u_int); + } + TFT_fillWindow(color); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_fillWin_obj, 0, display_tft_fillWin); + +//-------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_7segAttrib(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_dist, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_outline, MP_ARG_REQUIRED | MP_ARG_BOOL, { .u_bool = false } }, + { MP_QSTR_color, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + set_7seg_font_atrib(args[0].u_int, args[1].u_int, (int)args[2].u_bool, intToColor(args[3].u_int)); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_7segAttrib_obj, 4, display_tft_7segAttrib); + +//----------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_setFont(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_font, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_rotate, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_transparent, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_fixedwidth, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_dist, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 8 } }, + { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 2 } }, + { MP_QSTR_outline, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = false } }, + { MP_QSTR_color, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const char *font_file = NULL; + char fullname[128] = {'\0'}; + mp_int_t font = DEFAULT_FONT; + + if (MP_OBJ_IS_STR(args[0].u_obj)) { + font_file = mp_obj_str_get_str(args[0].u_obj); + + if (physicalPath(font_file, fullname) == 0) { + font = USER_FONT; + font_file = fullname; + } + } + else { + font = mp_obj_get_int(args[0].u_obj); + } + TFT_setFont(font, font_file); + + if (args[1].u_int >= 0) font_rotate = args[1].u_int; + if (args[2].u_int >= 0) font_transparent = args[2].u_int & 1; + if (args[3].u_int >= 0) font_forceFixed = args[3].u_int & 1; + + if (font == FONT_7SEG) { + set_7seg_font_atrib(args[4].u_int, args[5].u_int, (int)args[6].u_bool, intToColor(args[7].u_int)); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_setFont_obj, 1, display_tft_setFont); + +//------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_getFontSize(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + int width, height; + TFT_getfontsize(&width, &height); + + mp_obj_t tuple[2]; + + tuple[0] = mp_obj_new_int(width); + tuple[1] = mp_obj_new_int(height); + + return mp_obj_new_tuple(2, tuple); +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_getFontSize_obj, 0, display_tft_getFontSize); + +//----------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_setRot(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_rot, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = PORTRAIT } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t rot = args[0].u_int; + if ((rot < 0) || (rot > 3)) rot = 0; + + TFT_setRotation(rot); + self->dconfig.width = _width; + self->dconfig.height = _height; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_setRot_obj, 1, display_tft_setRot); + +//--------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_print(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_rotate, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_transparent, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_fixedwidth, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_wrap, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_bgcolor, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t old_fg = _fg; + color_t old_bg = _bg; + int old_rot = font_rotate; + int old_transp = font_transparent; + int old_fixed = font_forceFixed; + int old_wrap = text_wrap; + + mp_int_t x = args[0].u_int; + mp_int_t y = args[1].u_int; + char *st = (char *)mp_obj_str_get_str(args[2].u_obj); + + if (args[3].u_int >= 0) _fg = intToColor(args[3].u_int); + if (args[4].u_int >= 0) font_rotate = args[4].u_int; + if (args[5].u_int >= 0) font_transparent = args[5].u_int & 1; + if (args[6].u_int >= 0) font_forceFixed = args[6].u_int & 1; + if (args[7].u_int >= 0) text_wrap = args[7].u_int & 1; + if (args[8].u_int >= 0) _bg = intToColor(args[8].u_int); + + TFT_print(st, x, y); + + _fg = old_fg; + _bg = old_bg; + font_rotate = old_rot; + font_transparent = old_transp; + font_forceFixed = old_fixed; + text_wrap = old_wrap; + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_print_obj, 3, display_tft_print); + +//--------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_stringWidth(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + char *st = (char *)mp_obj_str_get_str(args[0].u_obj); + + mp_int_t w = TFT_getStringWidth(st); + + return mp_obj_new_int(w); +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_stringWidth_obj, 1, display_tft_stringWidth); + +//------------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_clearStringRect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_color, MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + color_t old_bg = _bg; + mp_int_t x = args[0].u_int; + mp_int_t y = args[1].u_int; + char *st = (char *)mp_obj_str_get_str(args[2].u_obj); + + if (args[3].u_int >= 0) _bg = intToColor(args[3].u_int); + + TFT_clearStringRect(x, y, st); + + _bg = old_bg; + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_clearStringRect_obj, 3, display_tft_clearStringRect); + +//----------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_Image(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_scale, MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_type, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_debug, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + char *fname = NULL; + char fullname[128] = {'\0'}; + int img_type = args[4].u_int; + + fname = (char *)mp_obj_str_get_str(args[2].u_obj); + + int res = physicalPath(fname, fullname); + if ((res != 0) || (strlen(fullname) == 0)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error resolving file name")); + } + + if (img_type < 0) { + // try to determine image type + char upr_fname[128]; + strcpy(upr_fname, fname); + for (int i=0; i < strlen(upr_fname); i++) { + upr_fname[i] = toupper((unsigned char) upr_fname[i]); + } + if (strstr(upr_fname, ".JPG") != NULL) img_type = IMAGE_TYPE_JPG; + else if (strstr(upr_fname, ".BMP") != NULL) img_type = IMAGE_TYPE_BMP; + else { + FILE *fhndl = fopen(fullname, "r"); + if (fhndl != NULL) { + uint8_t buf[16]; + if (fread(buf, 1, 11, fhndl) == 11) { + buf[10] = 0; + if (strstr((char *)(buf+6), "JFIF") != NULL) img_type = IMAGE_TYPE_JPG; + else if ((buf[0] = 0x42) && (buf[1] = 0x4d)) img_type = IMAGE_TYPE_BMP; + } + fclose(fhndl); + } + } + if (img_type < 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Cannot determine image type")); + } + } + + image_debug = (uint8_t)args[5].u_bool; + if (img_type == IMAGE_TYPE_BMP) { + TFT_bmp_image(args[0].u_int, args[1].u_int, args[3].u_int, fullname, NULL, 0); + } + else if (img_type == IMAGE_TYPE_JPG) { + TFT_jpg_image(args[0].u_int, args[1].u_int, args[3].u_int, fullname, NULL, 0); + } + else { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Unsupported image type")); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_Image_obj, 3, display_tft_Image); + +//------------------------------------------------------------------------------------------------ +STATIC mp_obj_t display_tft_getTouch(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_raw, MP_ARG_BOOL, { .u_bool = false } }, + { MP_QSTR_wait, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + if (setupDevice(self)) return mp_const_none; + if (self->ts_spi->handle == NULL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Touch not configured")); + } + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int x = 0; + int y = 0; + uint8_t raw = 0; + if (args[0].u_bool) raw = 1; + int wait = args[1].u_int; + if ((wait < 5) || (wait > 60000)) wait = 0; + + int res = TFT_read_touch(&x, &y, raw); + if (wait) { + #ifdef CONFIG_MICROPY_USE_TASK_WDT + esp_task_wdt_reset(); + #endif + struct timeval tv; + gettimeofday(&tv, NULL); + uint32_t tstart = ((uint32_t)tv.tv_sec * 1000) + ((uint32_t)tv.tv_usec / 1000); + uint32_t tend = tstart; + uint32_t nres = tstart; + + // wait until not touched + while ((tend-tstart) < wait) { + res = TFT_read_touch(&x, &y, raw); + if (res == 0) break; + vTaskDelay(2); + gettimeofday(&tv, NULL); + tend = ((uint32_t)tv.tv_sec * 1000) + ((uint32_t)tv.tv_usec / 1000); + #ifdef CONFIG_MICROPY_USE_TASK_WDT + if ((tend-nres) > (CONFIG_TASK_WDT_TIMEOUT_S*500)) { + esp_task_wdt_reset(); + nres = tend; + } + #endif + } + // wait until touched + while ((tend-tstart) < wait) { + res = TFT_read_touch(&x, &y, raw); + if (res) break; + vTaskDelay(2); + gettimeofday(&tv, NULL); + tend = ((uint32_t)tv.tv_sec * 1000) + ((uint32_t)tv.tv_usec / 1000); + #ifdef CONFIG_MICROPY_USE_TASK_WDT + if ((tend-nres) > (CONFIG_TASK_WDT_TIMEOUT_S*500)) { + esp_task_wdt_reset(); + nres = tend; + } + #endif + } + } + + mp_obj_t tuple[3]; + tuple[0] = mp_obj_new_bool(res); + tuple[1] = mp_obj_new_int(x); + tuple[2] = mp_obj_new_int(y); + + return mp_obj_new_tuple(3, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_getTouch_obj, 0, display_tft_getTouch); + +//----------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_compileFont(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_debug, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = false } }, + }; + //display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + //if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + char *fname = NULL; + char fullname[128] = {'\0'}; + uint8_t debug = (uint8_t)args[1].u_bool; + + fname = (char *)mp_obj_str_get_str(args[0].u_obj); + + int res = physicalPath(fname, fullname); + if ((res != 0) || (strlen(fullname) == 0)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error resolving file name")); + } + + res = compile_font_file(fullname, debug); + if (res) return mp_const_false; + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_compileFont_obj, 1, display_tft_compileFont); + +//----------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_HSBtoRGB(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_hue, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_saturation, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_brightness, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_float_t hue = mp_obj_get_float(args[0].u_obj); + mp_float_t sat = mp_obj_get_float(args[1].u_obj); + mp_float_t bri = mp_obj_get_float(args[2].u_obj); + + color_t color = HSBtoRGB(hue, sat, bri); + mp_int_t icolor = (int)((color.r << 16) | (color.g << 8) | color.b); + + return mp_obj_new_int(icolor); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_HSBtoRGB_obj, 3, display_tft_HSBtoRGB); + +//-------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_setclipwin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_fillcolor, MP_ARG_INT, { .u_int = -1 } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t x0 = args[0].u_int; + mp_int_t y0 = args[1].u_int; + mp_int_t x1 = args[2].u_int; + mp_int_t y1 = args[3].u_int; + + TFT_setclipwin(x0, y0, x1, y1); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_setclipwin_obj, 4, display_tft_setclipwin); + +//---------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_resetclipwin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + TFT_resetclipwin(); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_resetclipwin_obj, 0, display_tft_resetclipwin); + +//--------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_saveclipwin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + TFT_saveClipWin(); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_saveclipwin_obj, 0, display_tft_saveclipwin); + +//------------------------------------------------------------------------------------------------------ +STATIC mp_obj_t display_tft_restoreclipwin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + TFT_restoreClipWin(); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_restoreclipwin_obj, 0, display_tft_restoreclipwin); + +//------------------------------------------------------------------------------------------------ +STATIC mp_obj_t display_tft_getSize(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_int(_width); + tuple[1] = mp_obj_new_int(_height); + + return mp_obj_new_tuple(2, tuple); +} +MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_getSize_obj, 0, display_tft_getSize); + +//-------------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_getWinSize(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_int(dispWin.x2 - dispWin.x1 + 1); + tuple[1] = mp_obj_new_int(dispWin.y2 - dispWin.y1 + 1); + + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_getWinSize_obj, 0, display_tft_getWinSize); + +//------------------------------------------------------------------------------------------------ +STATIC mp_obj_t display_tft_setCalib(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + const mp_arg_t allowed_args[] = { + { MP_QSTR_calx, MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_caly, MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_from_nvs, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = false } }, + }; + display_tft_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if (setupDevice(self)) return mp_const_none; + if (self->ts_spi->handle == NULL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Touch not configured")); + } + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (self->dconfig.touch == TOUCH_TYPE_NONE) { + return mp_const_none; + } + + if (args[2].u_bool) { + if (mpy_nvs_handle == 0) { + mp_raise_msg(&mp_type_OSError, "NVS not available!"); + } + int calx = 0, caly = 0; + bool f = true; + if (ESP_ERR_NVS_NOT_FOUND == nvs_get_i32(mpy_nvs_handle, "tpcalibX", &calx)) f = false; + if (f) { + if (ESP_ERR_NVS_NOT_FOUND == nvs_get_i32(mpy_nvs_handle, "tpcalibY", &caly)) f = false; + } + if (!f) { + mp_raise_msg(&mp_type_OSError, "Calibration values not found in NVS"); + } + self->tp_calx = calx; + self->tp_caly = caly; + return mp_const_none; + } + + if (args[0].u_int == 0) { + if (self->dconfig.touch == TOUCH_TYPE_XPT2046) self->tp_calx = TP_CALX_XPT2046; + else self->tp_calx = TP_CALX_STMPE610; + } + else self->tp_calx = args[0].u_int; + + if (args[1].u_int == 0) { + if (self->dconfig.touch == TOUCH_TYPE_XPT2046) self->tp_caly = TP_CALY_XPT2046; + else self->tp_caly = TP_CALY_STMPE610; + } + else self->tp_caly = args[1].u_int; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(display_tft_setCalib_obj, 0, display_tft_setCalib); + +//---------------------------------------------------- +STATIC mp_obj_t display_tft_getCalib(mp_obj_t self_in) +{ + display_tft_obj_t *self = self_in; + if (setupDevice(self)) return mp_const_none; + if (self->ts_spi->handle == NULL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Touch not configured")); + } + mp_obj_t tuple[2]; + + tuple[0] = mp_obj_new_int(self->tp_calx); + tuple[1] = mp_obj_new_int(self->tp_caly); + + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_getCalib_obj, display_tft_getCalib); + + +//------------------------------------------------------------------------ +STATIC mp_obj_t display_tft_backlight(mp_obj_t self_in, mp_obj_t onoff_in) +{ + display_tft_obj_t *self = self_in; + if (setupDevice(self)) return mp_const_none; + + int onoff = mp_obj_get_int(onoff_in); + if (onoff) bcklOn(&self->dconfig); + else bcklOff(&self->dconfig); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(display_tft_backlight_obj, display_tft_backlight); + +//------------------------------------------------------ +STATIC mp_obj_t display_tft_touch_type(mp_obj_t self_in) +{ + display_tft_obj_t *self = self_in; + if (setupDevice(self)) return mp_const_none; + + return mp_obj_new_int(self->dconfig.touch); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_touch_type_obj, display_tft_touch_type); + + +// ==== Low level functions ====================================== + +//------------------------------------------------------------------------ +STATIC mp_obj_t display_tft_set_speed(mp_obj_t self_in, mp_obj_t speed_in) +{ + display_tft_obj_t *self = self_in; + if (setupDevice(self)) return mp_const_none; + + int speed = mp_obj_get_int(speed_in); + + // Set SPI clock used for display operations + self->dconfig.speed = spi_set_speed(self->disp_spi, speed); + + max_rdclock = find_rd_speed(); + self->dconfig.rdspeed = max_rdclock; + + mp_obj_t tuple[2]; + + tuple[0] = mp_obj_new_int(self->dconfig.speed); + tuple[1] = mp_obj_new_int(self->dconfig.rdspeed); + + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(display_tft_set_speed_obj, display_tft_set_speed); + +//-------------------------------------------------- +STATIC mp_obj_t display_tft_select(mp_obj_t self_in) +{ + display_tft_obj_t *self = self_in; + if (setupDevice(self)) return mp_const_none; + + disp_select(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_select_obj, display_tft_select); + +//---------------------------------------------------- +STATIC mp_obj_t display_tft_deselect(mp_obj_t self_in) +{ + display_tft_obj_t *self = self_in; + if (setupDevice(self)) return mp_const_none; + + disp_deselect(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_deselect_obj, display_tft_deselect); + +//-------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_cmd_read(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t len_in) +{ + display_tft_obj_t *self = self_in; + if (setupDevice(self)) return mp_const_none; + + uint8_t cmd = (uint8_t)mp_obj_get_int(cmd_in); + uint8_t len = (uint8_t)mp_obj_get_int(len_in); + if ((len < 1) || (len > 4)) len = 1; + + uint32_t res = read_cmd(cmd, len); + + return mp_obj_new_int_from_uint(res); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(display_tft_cmd_read_obj, display_tft_cmd_read); + +//------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_send_command(mp_obj_t self_in, mp_obj_t cmd_in) +{ + display_tft_obj_t *self = self_in; + if (setupDevice(self)) return mp_const_none; + + uint8_t cmd = (uint8_t)mp_obj_get_int(cmd_in); + + disp_select(); + disp_spi_transfer_cmd(cmd); + wait_trans_finish(0); + disp_deselect(); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(display_tft_send_command_obj, display_tft_send_command); + +//-------------------------------------------------------------------------------------------- +STATIC mp_obj_t display_tft_send_cmd_data(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t data_in) +{ + display_tft_obj_t *self = self_in; + if (setupDevice(self)) return mp_const_none; + + uint8_t cmd = (uint8_t)mp_obj_get_int(cmd_in); + mp_buffer_info_t data; + mp_get_buffer_raise(data_in, &data, MP_BUFFER_READ); + + disp_select(); + disp_spi_transfer_cmd_data(cmd, data.buf, data.len); + wait_trans_finish(0); + disp_deselect(); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(display_tft_send_cmd_data_obj, display_tft_send_cmd_data); + +//-------------------------------------------------- +STATIC mp_obj_t display_tft_get_bg(mp_obj_t self_in) +{ + int icolor = (int)((_bg.r << 16) | (_bg.g << 8) | _bg.b); + return mp_obj_new_int(icolor); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_get_bg_obj, display_tft_get_bg); + +//-------------------------------------------------- +STATIC mp_obj_t display_tft_get_fg(mp_obj_t self_in) +{ + int icolor = (int)((_fg.r << 16) | (_fg.g << 8) | _fg.b); + return mp_obj_new_int(icolor); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_get_fg_obj, display_tft_get_fg); + +//--------------------------------------------------------------------- +STATIC mp_obj_t display_tft_set_bg(mp_obj_t self_in, mp_obj_t color_in) +{ + color_t color = intToColor(mp_obj_get_int(color_in)); + _bg = color; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(display_tft_set_bg_obj, display_tft_set_bg); + +//--------------------------------------------------------------------- +STATIC mp_obj_t display_tft_set_fg(mp_obj_t self_in, mp_obj_t color_in) +{ + color_t color = intToColor(mp_obj_get_int(color_in)); + _fg = color; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(display_tft_set_fg_obj, display_tft_set_fg); + +//------------------------------------------------- +STATIC mp_obj_t display_tft_get_X(mp_obj_t self_in) +{ + int x = TFT_X; + return mp_obj_new_int(x); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_get_X_obj, display_tft_get_X); + +//------------------------------------------------- +STATIC mp_obj_t display_tft_get_Y(mp_obj_t self_in) +{ + int y = TFT_Y; + return mp_obj_new_int(y); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_tft_get_Y_obj, display_tft_get_Y); + + +//================================================================ +STATIC const mp_rom_map_elem_t display_tft_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&display_tft_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&display_tft_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&display_tft_drawPixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_readPixel), MP_ROM_PTR(&display_tft_readPixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&display_tft_drawLine_obj) }, + { MP_ROM_QSTR(MP_QSTR_lineByAngle), MP_ROM_PTR(&display_tft_drawLineByAngle_obj) }, + { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&display_tft_drawTriangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&display_tft_drawCircle_obj) }, + { MP_ROM_QSTR(MP_QSTR_ellipse), MP_ROM_PTR(&display_tft_drawEllipse_obj) }, + { MP_ROM_QSTR(MP_QSTR_arc), MP_ROM_PTR(&display_tft_drawArc_obj) }, + { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&display_tft_drawPoly_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&display_tft_drawRect_obj) }, + { MP_ROM_QSTR(MP_QSTR_readScreen), MP_ROM_PTR(&display_tft_readScreen_obj) }, + { MP_ROM_QSTR(MP_QSTR_roundrect), MP_ROM_PTR(&display_tft_drawRoundRect_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&display_tft_fillScreen_obj) }, + { MP_ROM_QSTR(MP_QSTR_clearwin), MP_ROM_PTR(&display_tft_fillWin_obj) }, + { MP_ROM_QSTR(MP_QSTR_font), MP_ROM_PTR(&display_tft_setFont_obj) }, + { MP_ROM_QSTR(MP_QSTR_fontSize), MP_ROM_PTR(&display_tft_getFontSize_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&display_tft_print_obj) }, + { MP_ROM_QSTR(MP_QSTR_orient), MP_ROM_PTR(&display_tft_setRot_obj) }, + { MP_ROM_QSTR(MP_QSTR_textWidth), MP_ROM_PTR(&display_tft_stringWidth_obj) }, + { MP_ROM_QSTR(MP_QSTR_textClear), MP_ROM_PTR(&display_tft_clearStringRect_obj) }, + { MP_ROM_QSTR(MP_QSTR_attrib7seg), MP_ROM_PTR(&display_tft_7segAttrib_obj) }, + { MP_ROM_QSTR(MP_QSTR_image), MP_ROM_PTR(&display_tft_Image_obj) }, + { MP_ROM_QSTR(MP_QSTR_gettouch), MP_ROM_PTR(&display_tft_getTouch_obj) }, + { MP_ROM_QSTR(MP_QSTR_compileFont), MP_ROM_PTR(&display_tft_compileFont_obj) }, + { MP_ROM_QSTR(MP_QSTR_hsb2rgb), MP_ROM_PTR(&display_tft_HSBtoRGB_obj) }, + { MP_ROM_QSTR(MP_QSTR_setwin), MP_ROM_PTR(&display_tft_setclipwin_obj) }, + { MP_ROM_QSTR(MP_QSTR_resetwin), MP_ROM_PTR(&display_tft_resetclipwin_obj) }, + { MP_ROM_QSTR(MP_QSTR_savewin), MP_ROM_PTR(&display_tft_saveclipwin_obj) }, + { MP_ROM_QSTR(MP_QSTR_restorewin), MP_ROM_PTR(&display_tft_restoreclipwin_obj) }, + { MP_ROM_QSTR(MP_QSTR_screensize), MP_ROM_PTR(&display_tft_getSize_obj) }, + { MP_ROM_QSTR(MP_QSTR_winsize), MP_ROM_PTR(&display_tft_getWinSize_obj) }, + { MP_ROM_QSTR(MP_QSTR_setCalib), MP_ROM_PTR(&display_tft_setCalib_obj) }, + { MP_ROM_QSTR(MP_QSTR_getCalib), MP_ROM_PTR(&display_tft_getCalib_obj) }, + { MP_ROM_QSTR(MP_QSTR_backlight), MP_ROM_PTR(&display_tft_backlight_obj) }, + { MP_ROM_QSTR(MP_QSTR_getTouchType), MP_ROM_PTR(&display_tft_touch_type_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_fg), MP_ROM_PTR(&display_tft_get_fg_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_bg), MP_ROM_PTR(&display_tft_get_bg_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_fg), MP_ROM_PTR(&display_tft_set_fg_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_bg), MP_ROM_PTR(&display_tft_set_bg_obj) }, + { MP_ROM_QSTR(MP_QSTR_text_x), MP_ROM_PTR(&display_tft_get_X_obj) }, + { MP_ROM_QSTR(MP_QSTR_text_y), MP_ROM_PTR(&display_tft_get_Y_obj) }, + + { MP_ROM_QSTR(MP_QSTR_tft_setspeed), MP_ROM_PTR(&display_tft_set_speed_obj) }, + { MP_ROM_QSTR(MP_QSTR_tft_select), MP_ROM_PTR(&display_tft_select_obj) }, + { MP_ROM_QSTR(MP_QSTR_tft_deselect), MP_ROM_PTR(&display_tft_deselect_obj) }, + { MP_ROM_QSTR(MP_QSTR_tft_writecmd), MP_ROM_PTR(&display_tft_send_command_obj) }, + { MP_ROM_QSTR(MP_QSTR_tft_writecmddata), MP_ROM_PTR(&display_tft_send_cmd_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_tft_readcmd), MP_ROM_PTR(&display_tft_cmd_read_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_ST7789), MP_ROM_INT(DISP_TYPE_ST7789V) }, + { MP_ROM_QSTR(MP_QSTR_ILI9341), MP_ROM_INT(DISP_TYPE_ILI9341) }, + { MP_ROM_QSTR(MP_QSTR_ILI9488), MP_ROM_INT(DISP_TYPE_ILI9488) }, + { MP_ROM_QSTR(MP_QSTR_ST7735), MP_ROM_INT(DISP_TYPE_ST7735) }, + { MP_ROM_QSTR(MP_QSTR_ST7735R), MP_ROM_INT(DISP_TYPE_ST7735R) }, + { MP_ROM_QSTR(MP_QSTR_ST7735B), MP_ROM_INT(DISP_TYPE_ST7735B) }, + { MP_ROM_QSTR(MP_QSTR_M5STACK), MP_ROM_INT(DISP_TYPE_M5STACK) }, + { MP_ROM_QSTR(MP_QSTR_GENERIC), MP_ROM_INT(DISP_TYPE_GENERIC) }, + + { MP_ROM_QSTR(MP_QSTR_CENTER), MP_ROM_INT(CENTER) }, + { MP_ROM_QSTR(MP_QSTR_RIGHT), MP_ROM_INT(RIGHT) }, + { MP_ROM_QSTR(MP_QSTR_BOTTOM), MP_ROM_INT(BOTTOM) }, + { MP_ROM_QSTR(MP_QSTR_LASTX), MP_ROM_INT(LASTX) }, + { MP_ROM_QSTR(MP_QSTR_LASTY), MP_ROM_INT(LASTY) }, + + { MP_ROM_QSTR(MP_QSTR_PORTRAIT), MP_ROM_INT(PORTRAIT) }, + { MP_ROM_QSTR(MP_QSTR_LANDSCAPE), MP_ROM_INT(LANDSCAPE) }, + { MP_ROM_QSTR(MP_QSTR_PORTRAIT_FLIP), MP_ROM_INT(PORTRAIT_FLIP) }, + { MP_ROM_QSTR(MP_QSTR_LANDSCAPE_FLIP), MP_ROM_INT(LANDSCAPE_FLIP) }, + + { MP_ROM_QSTR(MP_QSTR_FONT_Default), MP_ROM_INT(DEFAULT_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_DejaVu18), MP_ROM_INT(DEJAVU18_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_DejaVu24), MP_ROM_INT(DEJAVU24_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_Ubuntu), MP_ROM_INT(UBUNTU16_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_Comic), MP_ROM_INT(COMIC24_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_Minya), MP_ROM_INT(MINYA24_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_Tooney), MP_ROM_INT(TOONEY32_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_Small), MP_ROM_INT(SMALL_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_DefaultSmall), MP_ROM_INT(DEF_SMALL_FONT) }, + { MP_ROM_QSTR(MP_QSTR_FONT_7seg), MP_ROM_INT(FONT_7SEG) }, + + { MP_ROM_QSTR(MP_QSTR_BLACK), MP_ROM_INT(iTFT_BLACK) }, + { MP_ROM_QSTR(MP_QSTR_NAVY), MP_ROM_INT(iTFT_NAVY) }, + { MP_ROM_QSTR(MP_QSTR_DARKGREEN), MP_ROM_INT(iTFT_DARKGREEN) }, + { MP_ROM_QSTR(MP_QSTR_DARKCYAN), MP_ROM_INT(iTFT_DARKCYAN) }, + { MP_ROM_QSTR(MP_QSTR_MAROON), MP_ROM_INT(iTFT_MAROON) }, + { MP_ROM_QSTR(MP_QSTR_PURPLE), MP_ROM_INT(iTFT_PURPLE) }, + { MP_ROM_QSTR(MP_QSTR_OLIVE), MP_ROM_INT(iTFT_OLIVE) }, + { MP_ROM_QSTR(MP_QSTR_LIGHTGREY), MP_ROM_INT(iTFT_LIGHTGREY) }, + { MP_ROM_QSTR(MP_QSTR_DARKGREY), MP_ROM_INT(iTFT_DARKGREY) }, + { MP_ROM_QSTR(MP_QSTR_BLUE), MP_ROM_INT(iTFT_BLUE) }, + { MP_ROM_QSTR(MP_QSTR_GREEN), MP_ROM_INT(iTFT_GREEN) }, + { MP_ROM_QSTR(MP_QSTR_CYAN), MP_ROM_INT(iTFT_CYAN) }, + { MP_ROM_QSTR(MP_QSTR_RED), MP_ROM_INT(iTFT_RED) }, + { MP_ROM_QSTR(MP_QSTR_MAGENTA), MP_ROM_INT(iTFT_MAGENTA) }, + { MP_ROM_QSTR(MP_QSTR_YELLOW), MP_ROM_INT(iTFT_YELLOW) }, + { MP_ROM_QSTR(MP_QSTR_WHITE), MP_ROM_INT(iTFT_WHITE) }, + { MP_ROM_QSTR(MP_QSTR_ORANGE), MP_ROM_INT(iTFT_ORANGE) }, + { MP_ROM_QSTR(MP_QSTR_GREENYELLOW), MP_ROM_INT(iTFT_GREENYELLOW) }, + { MP_ROM_QSTR(MP_QSTR_PINK), MP_ROM_INT(iTFT_PINK) }, + + { MP_ROM_QSTR(MP_QSTR_COLOR_BITS16), MP_ROM_INT(16) }, + { MP_ROM_QSTR(MP_QSTR_COLOR_BITS24), MP_ROM_INT(24) }, + + { MP_ROM_QSTR(MP_QSTR_JPG), MP_ROM_INT(IMAGE_TYPE_JPG) }, + { MP_ROM_QSTR(MP_QSTR_BMP), MP_ROM_INT(IMAGE_TYPE_BMP) }, + + { MP_ROM_QSTR(MP_QSTR_HSPI), MP_ROM_INT(HSPI_HOST) }, + { MP_ROM_QSTR(MP_QSTR_VSPI), MP_ROM_INT(VSPI_HOST) }, + + { MP_ROM_QSTR(MP_QSTR_TOUCH_NONE), MP_ROM_INT(TOUCH_TYPE_NONE) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH_XPT), MP_ROM_INT(TOUCH_TYPE_XPT2046) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH_STMPE), MP_ROM_INT(TOUCH_TYPE_STMPE610) }, +}; +STATIC MP_DEFINE_CONST_DICT(display_tft_locals_dict, display_tft_locals_dict_table); + +//====================================== +const mp_obj_type_t display_tft_type = { + { &mp_type_type }, + .name = MP_QSTR_TFT, + .print = display_tft_printinfo, + .make_new = display_tft_make_new, + .locals_dict = (mp_obj_t)&display_tft_locals_dict, +}; + +#endif // CONFIG_MICROPY_USE_TFT + diff --git a/MicroPython_BUILD/components/micropython/esp32/moddisplay_tft.h b/MicroPython_BUILD/components/micropython/esp32/moddisplay_tft.h new file mode 100644 index 00000000..3d9f1b83 --- /dev/null +++ b/MicroPython_BUILD/components/micropython/esp32/moddisplay_tft.h @@ -0,0 +1,55 @@ +/* + * This file is part of the MicroPython ESP32 project, https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo + * + * The MIT License (MIT) + * + * Copyright (c) 2018 LoBo (https://github.com/loboris) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _MODDISPLAY_TFT_H_ +#define _MODDISPLAY_TFT_H_ + +#include "sdkconfig.h" + +#ifdef CONFIG_MICROPY_USE_TFT + +#include "py/obj.h" + +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_drawPixel_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_drawCircle_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_drawLine_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_drawLineByAngle_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_drawTriangle_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_drawEllipse_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_drawArc_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_drawPoly_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_drawRect_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_drawRoundRect_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_setFont_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_getFontSize_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_print_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_getSize_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_setclipwin_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(display_tft_resetclipwin_obj); + +#endif + +#endif diff --git a/MicroPython_BUILD/components/micropython/esp32/modmachine.c b/MicroPython_BUILD/components/micropython/esp32/modmachine.c index 440c61c5..1aeed635 100644 --- a/MicroPython_BUILD/components/micropython/esp32/modmachine.c +++ b/MicroPython_BUILD/components/micropython/esp32/modmachine.c @@ -454,8 +454,8 @@ STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_ma uint32_t s_rtc_clk_cal = (uint64_t)REG_READ(RTC_SLOW_CLK_CAL_REG); stub_timeout = (uint64_t)(2000000) * (1 << RTC_CLK_CAL_FRACT) / s_rtc_clk_cal; - mp_int_t stub_sleep = 0; - mp_int_t sleep_time = args[ARG_sleep_ms].u_int; + int64_t stub_sleep = 0; + int64_t sleep_time = args[ARG_sleep_ms].u_int; if (sleep_time < 0) sleep_time = 0; if (sleep_time > 0) { stub_sleep = args[ARG_stub_ms].u_int; @@ -472,7 +472,7 @@ STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_ma if (stub_sleep > 0) { wait_in_stub = (int64_t)args[ARG_stub_wait].u_int; if (wait_in_stub < 0) wait_in_stub = 0; - if (wait_in_stub > (stub_sleep*1000)) wait_in_stub = (int64_t)stub_sleep*1000; + if (wait_in_stub > (stub_sleep*1000)) wait_in_stub = stub_sleep*1000; machine_rtc_config.stub_wait = wait_in_stub; stub_timer_inc = 1; if (wait_in_stub > 100000) stub_timer_inc = 100; @@ -480,8 +480,8 @@ STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_ma } if (sleep_time > 0) { - if (stub_sleep) esp_sleep_enable_timer_wakeup((uint64_t)(stub_sleep * 1000)); - else esp_sleep_enable_timer_wakeup((uint64_t)(sleep_time * 1000)); + if (stub_sleep) esp_sleep_enable_timer_wakeup(stub_sleep * 1000); + else esp_sleep_enable_timer_wakeup(sleep_time * 1000); machine_rtc_config.deepsleep_time = sleep_time; } else { @@ -516,7 +516,7 @@ STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_ma esp_sleep_enable_touchpad_wakeup(); } - ESP_LOGD("DEEP SLEEP", "Sleep time: time=%d, interval=%d, pin=%d, level=%d, wait=%llu\n", + ESP_LOGD("DEEP SLEEP", "Sleep time: time=%llu, interval=%llu, pin=%d, level=%d, wait=%llu\n", sleep_time, stub_sleep, led_pin, args[ARG_stub_ledlevel].u_bool, wait_in_stub); prepareSleepReset(0, NULL); @@ -533,8 +533,8 @@ STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_ma if (stub_sleep) { // Get number of microseconds per RTC clock tick (scaled by 2^19) // Calculate RTC clock value for wakeup - machine_rtc_config.wakeup_delay_ticks = (uint64_t)(stub_sleep * 1000) * (1 << RTC_CLK_CAL_FRACT) / s_rtc_clk_cal; - machine_rtc_config.wakeup_delay_ticks_last = (uint64_t)((sleep_time % stub_sleep) * 1000) * (1 << RTC_CLK_CAL_FRACT) / s_rtc_clk_cal;; + machine_rtc_config.wakeup_delay_ticks = (stub_sleep * 1000) * (1 << RTC_CLK_CAL_FRACT) / s_rtc_clk_cal; + machine_rtc_config.wakeup_delay_ticks_last = ((sleep_time % stub_sleep) * 1000) * (1 << RTC_CLK_CAL_FRACT) / s_rtc_clk_cal;; // Set the wake stub function machine_rtc_config.deepsleep_interval = stub_sleep; diff --git a/MicroPython_BUILD/components/micropython/esp32/modnetwork.c b/MicroPython_BUILD/components/micropython/esp32/modnetwork.c index 797532fd..ecef95d0 100644 --- a/MicroPython_BUILD/components/micropython/esp32/modnetwork.c +++ b/MicroPython_BUILD/components/micropython/esp32/modnetwork.c @@ -40,6 +40,7 @@ #include "freertos/task.h" #include "sdkconfig.h" +#include "libs/libGSM.h" #include "py/nlr.h" #include "py/objlist.h" #include "py/runtime.h" @@ -51,7 +52,6 @@ #include "esp_event_loop.h" #include "esp_log.h" #include "lwip/dns.h" -#include "tcpip_adapter.h" #ifdef CONFIG_MICROPY_USE_MDNS #include "mdns.h" #endif @@ -184,6 +184,7 @@ bool wifi_sta_has_ipaddress = false; bool wifi_sta_changed_ipaddress = false; bool wifi_ap_isconnected = false; bool wifi_ap_sta_isconnected = false; +tcpip_adapter_if_t tcpip_if[MAX_ACTIVE_INTERFACES] = {TCPIP_ADAPTER_IF_MAX}; const mp_obj_type_t wlan_if_type; const wlan_if_obj_t wlan_sta_obj = {{&wlan_if_type}, WIFI_IF_STA, WIFI_MODE_STA}; @@ -1214,6 +1215,93 @@ STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode); +//--------------------------------- +int network_get_active_interfaces() +{ + int n_if = 0; + + for (int i=0; i 0) { + return ip_info.ip.addr; + } + } + } + return 0; +} + +//-------------------------- +uint32_t network_has_staip() +{ + tcpip_adapter_ip_info_t ip_info = {0}; + int n_if = network_get_active_interfaces(); + if (n_if) { + for (int i=0; i 0)) { + return ip_info.ip.addr; + } + } + } + return 0; +} + +//---------------------------- +void network_checkConnection() +{ + uint32_t ip = network_has_staip(); + if (ip == 0) { + #ifdef CONFIG_MICROPY_USE_GSM + if (ppposStatus() != GSM_STATE_CONNECTED) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "No Internet connection")); + } + #else + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "No Internet connection")); + #endif + } +} + + + #ifdef CONFIG_MICROPY_USE_MQTT extern const mp_obj_type_t mqtt_type; #endif @@ -1228,37 +1316,16 @@ extern const mp_obj_type_t mqtt_type; //----------------------------- static mp_obj_t get_listen_ip() { - if ((wifi_network_state == WIFI_STATE_STARTED) && (wifi_is_started())) { - wifi_mode_t mode; - tcpip_adapter_if_t tcpip_if = TCPIP_ADAPTER_IF_MAX; - int n_if = 0; - esp_err_t ret = esp_wifi_get_mode(&mode); - if (ret == ESP_OK) { - if (mode == WIFI_MODE_STA) { - n_if = 1; - tcpip_if = TCPIP_ADAPTER_IF_STA; - } - else if (mode == WIFI_MODE_AP) { - n_if = 1; - tcpip_if = TCPIP_ADAPTER_IF_AP; - } - else if (mode == WIFI_MODE_APSTA) n_if = 2; - } - if (n_if > 0) { - tcpip_adapter_ip_info_t info; - mp_obj_t ip_tuple[n_if]; - if (n_if == 1) { - tcpip_adapter_get_ip_info(tcpip_if, &info); - ip_tuple[0] = netutils_format_ipv4_addr((uint8_t*)&info.ip, NETUTILS_BIG); - } - else { - tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &info); - ip_tuple[0] = netutils_format_ipv4_addr((uint8_t*)&info.ip, NETUTILS_BIG); - tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &info); - ip_tuple[1] = netutils_format_ipv4_addr((uint8_t*)&info.ip, NETUTILS_BIG); - } - return mp_obj_new_tuple(n_if, ip_tuple); - } + tcpip_adapter_ip_info_t info; + int n_if = network_get_active_interfaces(); + + if (n_if > 0) { + mp_obj_t ip_tuple[n_if]; + for (int i=0; i 0 + { MP_QSTR_login_msg, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + #endif }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); if ((wifi_network_state < WIFI_STATE_STARTED) || (!wifi_is_started())) { - ESP_LOGE("[Telnet_start]", "WiFi not started or not connected"); - return mp_const_false; + #ifdef CONFIG_MICROPY_USE_ETHERNET + if (!lan_eth_active) { + ESP_LOGE("[Telnet_start]", "Network interface not started or not connected"); + return mp_const_false; + } + #else + return mp_const_false; + #endif } if (MP_OBJ_IS_STR(args[0].u_obj)) { @@ -1296,6 +1372,12 @@ STATIC mp_obj_t mod_network_startTelnet(mp_uint_t n_args, const mp_obj_t *pos_ar } else strcpy(telnet_pass, TELNET_DEF_PASS); + #if TELNET_LOGIN_MSG_LEN_MAX > 0 + if (MP_OBJ_IS_STR(args[3].u_obj)) { + snprintf(telnet_login_success, TELNET_LOGIN_MSG_LEN_MAX, mp_obj_str_get_str(args[3].u_obj)); + } + else snprintf(telnet_login_success, TELNET_LOGIN_MSG_LEN_MAX, "\r\nLogin succeeded!\r\nType \"help()\" for more information.\r\n"); + #endif telnet_timeout = args[2].u_int * 1000; if ((telnet_timeout < 120000) || (telnet_timeout > 86400000)) telnet_timeout = TELNET_DEF_TIMEOUT_MS; @@ -1401,8 +1483,14 @@ STATIC mp_obj_t mod_network_startFtp(mp_uint_t n_args, const mp_obj_t *pos_args, mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); if ((wifi_network_state < WIFI_STATE_STARTED) || (!wifi_is_started())) { - ESP_LOGE("[Ftp_start]", "WiFi not started or not connected"); - return mp_const_false; + #ifdef CONFIG_MICROPY_USE_ETHERNET + if (!lan_eth_active) { + ESP_LOGE("[Ftp_start]", "Network interface not started or not connected"); + return mp_const_false; + } + #else + return mp_const_false; + #endif } if (MP_OBJ_IS_STR(args[0].u_obj)) { diff --git a/MicroPython_BUILD/components/micropython/esp32/modnetwork.h b/MicroPython_BUILD/components/micropython/esp32/modnetwork.h index a2b5af81..b1108bb3 100644 --- a/MicroPython_BUILD/components/micropython/esp32/modnetwork.h +++ b/MicroPython_BUILD/components/micropython/esp32/modnetwork.h @@ -29,11 +29,14 @@ #define MICROPY_INCLUDED_ESP32_MODNETWORK_H #include "esp_wifi_types.h" +#include "esp_eth.h" +#include "tcpip_adapter.h" -#define WIFI_STATE_NOTINIT -1 -#define WIFI_STATE_INIT 0 -#define WIFI_STATE_STOPPED 1 -#define WIFI_STATE_STARTED 2 +#define WIFI_STATE_NOTINIT -1 +#define WIFI_STATE_INIT 0 +#define WIFI_STATE_STOPPED 1 +#define WIFI_STATE_STARTED 2 +#define MAX_ACTIVE_INTERFACES 3 enum { PHY_LAN8720, PHY_TLK110 }; @@ -47,6 +50,12 @@ typedef void (*wifi_sta_rx_probe_req_t)(const uint8_t *frame, int len, int rssi) extern esp_err_t esp_wifi_set_sta_rx_probe_req(wifi_sta_rx_probe_req_t cb); extern const mp_obj_type_t wlan_if_type; +tcpip_adapter_if_t tcpip_if[3]; + +#ifdef CONFIG_MICROPY_USE_ETHERNET +extern bool lan_eth_active; +//extern eth_phy_check_link_func lan_eth_link_func; +#endif extern int wifi_network_state; extern bool wifi_sta_isconnected; @@ -55,6 +64,12 @@ extern bool wifi_sta_changed_ipaddress; extern bool wifi_ap_isconnected; extern bool wifi_ap_sta_isconnected; +int network_get_active_interfaces(); +uint32_t network_hasip(); +uint32_t network_has_staip(); +void network_checkConnection(); + + #ifdef CONFIG_MICROPY_USE_ETHERNET MP_DECLARE_CONST_FUN_OBJ_KW(get_lan_obj); #endif diff --git a/MicroPython_BUILD/components/micropython/esp32/modrequests.c b/MicroPython_BUILD/components/micropython/esp32/modrequests.c index c99fe99a..f0d51077 100644 --- a/MicroPython_BUILD/components/micropython/esp32/modrequests.c +++ b/MicroPython_BUILD/components/micropython/esp32/modrequests.c @@ -36,8 +36,10 @@ #include "esp_log.h" #include "esp_system.h" #include "nvs_flash.h" +#include "mbedtls/base64.h" #include "esp_http_client.h" +#include "transport.h" #include "esp_wifi_types.h" #include "tcpip_adapter.h" @@ -45,6 +47,7 @@ #include "py/runtime.h" #include "modmachine.h" #include "extmod/vfs_native.h" +#include "modnetwork.h" #define MAX_HTTP_RECV_BUFFER 512 static const char *TAG = "[REQUESTS]"; @@ -57,7 +60,9 @@ static int rqheader_ptr = 0; static int rqbody_len = 0; static int rqbody_ptr = 0; static bool rqbody_ok = true; -static bool rq_debug = false; +static bool rq_debug = true; +static bool rq_base64 = false; + /* Root cert for howsmyssl.com, taken from howsmyssl_com_root_cert.pem @@ -83,7 +88,11 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) if (rq_debug) ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED"); break; case HTTP_EVENT_HEADER_SENT: - if (rq_debug) ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT"); + if (rq_debug) { + ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT"); + ESP_LOGD(TAG, " KEY: [%s]", evt->header_key); + ESP_LOGD(TAG, "VALUE: [%s]", evt->header_value); + } break; case HTTP_EVENT_ON_HEADER: if (rq_debug) ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value); @@ -165,6 +174,7 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) return ESP_OK; } +/* //--------------------- static void http_rest() { @@ -432,70 +442,282 @@ static void http_perform_as_stream_reader() esp_http_client_cleanup(client); free(buffer); } +*/ - -//-------------------- -static void checkConnection() +//----------------------------------------------- +static char *url_post_fields(mp_obj_dict_t *dict) { - tcpip_adapter_ip_info_t info; - tcpip_adapter_get_ip_info(WIFI_IF_STA, &info); - if (info.ip.addr == 0) { - #ifdef CONFIG_MICROPY_USE_GSM - if (ppposStatus() != GSM_STATE_CONNECTED) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "No Internet connection")); + char *params = calloc(256, sizeof(char)); + if (params == NULL) return 0; + + int nparam = 0; + const char *key; + const char *value; + char sval[64]; + size_t max = dict->map.alloc; + mp_map_t *map = &dict->map; + mp_map_elem_t *next; + size_t cur = 0; + while (1) { + next = NULL; + for (size_t i = cur; i < max; i++) { + if (MP_MAP_SLOT_IS_FILLED(map, i)) { + cur = i + 1; + next = &(map->table[i]); + break; + } + } + if (next == NULL) break; + + value = NULL; + key = mp_obj_str_get_str(next->key); + if (MP_OBJ_IS_STR(next->value)) { + value = mp_obj_str_get_str(next->value); + for (int i=0; i 0x7F)) { + value = NULL; + break; + } + } + } + else if (MP_OBJ_IS_INT(next->value)) { + int ival = mp_obj_get_int(next->value); + sprintf(sval,"%d", ival); + value = sval; + } + else if (MP_OBJ_IS_TYPE(next->value, &mp_type_float)) { + double fval = mp_obj_get_float(next->value); + sprintf(sval,"%f", fval); + value = sval; + } + if ((value) && ((strlen(params) + strlen(key) + strlen(value) + 2) < 256)) { + if (strlen(params) > 0) strcat(params, "&"); + strcat(params, key); + strcat(params, "="); + strcat(params, value); + nparam++; } - #else - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "No Internet connection")); - #endif } + if (nparam == 0) { + free(params); + params = NULL; + } + return params; } -//----------------------------------- -STATIC mp_obj_t mod_requests_test() { - ESP_LOGI(TAG, "Connected to AP, begin http example"); - http_rest(); - http_auth_basic(); - http_auth_basic_redirect(); - http_auth_digest(); - http_relative_redirect(); - http_absolute_redirect(); - https(); - http_redirect_to_https(); - http_download_chunk(); - http_perform_as_stream_reader(); - ESP_LOGI(TAG, "Finish http example"); - return mp_const_none; +//------------------------------------------------------------------------------------------------------------------------------- +static int post_field(esp_http_client_handle_t client, char *bndry, char *key, char *cont_type, char *value, int vlen, bool send) +{ + int len = vlen; + int res; + char buff[256]; + sprintf(buff, "--%s\r\nContent-Disposition: form-data; name=%s\r\n%s\r\n\r\n", bndry, key, cont_type); + len += strlen(buff); + if (send) { + res = esp_http_client_write(client, buff, strlen(buff)); + if (rq_debug) printf("%s", buff); + if (res <= 0) return res; + res = esp_http_client_write(client, value, vlen); + if (rq_debug) printf("%s", value); + if (res <= 0) return res; + } + + sprintf(buff, "\r\n--%s\r\n\r\n", bndry); + len += strlen(buff); + if (send) { + res = esp_http_client_write(client, buff, strlen(buff)); + if (rq_debug) printf("%s", buff); + if (res <= 0) return res; + } + return len; } -STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_requests_test_obj, mod_requests_test); -//-------------------------------------------------------------------------------------- -STATIC mp_obj_t requests_GET(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +//----------------------------------------------------------------------------------------------------- +static int handle_file(esp_http_client_handle_t client, char *bndry, char *key, char *fname, bool send) { - checkConnection(); - enum { ARG_url, ARG_file }; - const mp_arg_t allowed_args[] = { - { MP_QSTR_url, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_file, MP_ARG_OBJ, { .u_obj = mp_const_none } }, - }; + int flen = 0; + if (strlen(fname) < 128) { + FILE* file = NULL; + char fullname[128] = {'\0'}; + int res = physicalPath(fname, fullname); + if ((res == 0) && (strlen(fullname) > 0)) { + file = fopen(fullname, "rb"); + if (file == NULL) return flen; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + char *buff = malloc(1024); + if (buff == NULL) return flen; + + if (key) { + sprintf(buff, "--%s\r\nContent-Disposition: form-data; name=\"file_%s\"; filename=\"%s\"\r\nContent-Type: application/octet-stream\r\n\r\n", bndry, key, fname); + flen += strlen(buff); + if (send) { + res = esp_http_client_write(client, buff, strlen(buff)); + if (rq_debug) printf("%s", buff); + if (res <= 0) { + free(buff); + return -1; + } + } + } + res = 1; + while (res > 0) { + res = fread(buff, 1, 1023, file); + if (send) { + if (res > 0) buff[res] = 0; + if ((rq_debug) && (res > 0)) printf("%s", buff); + res = esp_http_client_write(client, buff, res); + } + flen += res; + } + fclose(file); + if (key) { + sprintf(buff, "\r\n--%s\r\n\r\n", bndry); + flen += strlen(buff); + if (send) { + res = esp_http_client_write(client, buff, strlen(buff)); + if (rq_debug) printf("%s", buff); + if (res <= 0) { + free(buff); + return -1; + } + } + } + free(buff); + } + } + return flen; +} + +// Parse MicroPython dictionary, calculate the content length +// or send the body to the server +//------------------------------------------------------------------------------------------------------------ +static int multipart_post_fields(mp_obj_dict_t *dict, char *bndry, esp_http_client_handle_t client, bool send) +{ + int data_len = 0; + int res; + int nparam = 0; + char *key; + char *value; + int vlen; + bool value_free; + char sval[64]; + char cont_type[64]; + + sprintf(cont_type, "%s", "Content-Type: text/plain"); + + // Parse dictionary + size_t max = dict->map.alloc; + mp_map_t *map = &dict->map; + mp_map_elem_t *next; + size_t cur = 0; + if ((rq_debug) && (send)) printf(">>> SEND FIELDS [\n"); + while (1) { + next = NULL; + for (size_t i = cur; i < max; i++) { + if (MP_MAP_SLOT_IS_FILLED(map, i)) { + cur = i + 1; + next = &(map->table[i]); + break; + } + } + if (next == NULL) break; + + value = NULL; + value_free = false; + key = (char *)mp_obj_str_get_str(next->key); + + if (MP_OBJ_IS_STR(next->value)) { + // String, it can be string to send or file name + value = (char *)mp_obj_str_get_str(next->value); + vlen = strlen(value); + res = handle_file(client, bndry, key, value, send); + if (res == 0) { + for (int i=0; i 0x7F)) { + value = NULL; + break; + } + } + } + else { + data_len += res; + nparam++; + value = NULL; + } + } + else if (MP_OBJ_IS_INT(next->value)) { + int ival = mp_obj_get_int(next->value); + sprintf(sval,"%d", ival); + value = sval; + vlen = strlen(sval); + } + else if (MP_OBJ_IS_TYPE(next->value, &mp_type_float)) { + double fval = mp_obj_get_float(next->value); + sprintf(sval,"%f", fval); + value = sval; + vlen = strlen(sval); + } + else { + mp_obj_type_t *type = mp_obj_get_type(next->value); + mp_buffer_info_t value_buff; + if (type->buffer_p.get_buffer != NULL) { + int ret = type->buffer_p.get_buffer(next->value, &value_buff, MP_BUFFER_READ); + if ((ret == 0) && (value_buff.len > 0)) { + if (rq_base64) { + // Send base64 encoded + value = malloc(value_buff.len * 4 / 3 + 64); + if (value) { + ret = mbedtls_base64_encode((unsigned char *)value, value_buff.len * 4 / 3 + 64, (size_t *)&vlen, (const unsigned char *)value_buff.buf, value_buff.len); + if (ret == 0) { + value[vlen] = '\0'; + sprintf(cont_type, "%s", "Content-Type: binary\r\nContent-Encoding: base64"); + value_free = true; + } + else { + free((void *)value); + value = NULL; + } + } + } + else { + value = value_buff.buf; + vlen = value_buff.len; + } + } + } + } + if (value) { + res = post_field(client, bndry, key, cont_type, value, vlen, send); + if (value_free) free((void *)value); + if (res <= 0) return res; + data_len += res; + nparam++; + } + } + if (rq_debug) { + if (send) { + printf("] LENGTH=%d\n", data_len); + } + else printf(">>> CONTENT LENGTH = %d\n", data_len); + } + return data_len; +} - esp_log_level_set("HTTP_CLIENT", ESP_LOG_WARN); - esp_log_level_set("TRANS_TCP", ESP_LOG_WARN); - esp_log_level_set("TRANS_SSL", ESP_LOG_WARN); +//-------------------------------------------------------------------------------------------------- +static mp_obj_t request(int method, bool multipart, mp_obj_t post_data_in, char * url, char *tofile) +{ int status; - char *url = NULL; - char *fname = NULL; char fullname[128] = {'\0'}; + char err_msg[128] = {'\0'}; + esp_err_t err; + bool perform_handled = false; + bool free_post_data = false; - url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); - + // Check if the response is redirected to file rqbody_file = NULL; - if (MP_OBJ_IS_STR(args[ARG_file].u_obj)) { + if (tofile) { // GET to file - fname = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); - int res = physicalPath(fname, fullname); + int res = physicalPath(tofile, fullname); if ((res != 0) || (strlen(fullname) == 0)) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error resolving file name")); } @@ -505,11 +727,21 @@ STATIC mp_obj_t requests_GET(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } } - esp_http_client_config_t config = { - .url = url, - .event_handler = _http_event_handler, - }; + char* post_data = NULL; + char bndry[32]; + + esp_http_client_config_t config = {0}; + config.url = url; + config.event_handler = _http_event_handler; + config.buffer_size = 1024; + + // Initialize the http_client and set the method esp_http_client_handle_t client = esp_http_client_init(&config); + if (client == NULL) { + if (rqbody_file) fclose(rqbody_file); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error initializing http client")); + } + esp_http_client_set_method(client, method); if (rqheader) free(rqheader); if (rqbody) free(rqbody); @@ -519,11 +751,130 @@ STATIC mp_obj_t requests_GET(size_t n_args, const mp_obj_t *pos_args, mp_map_t * rqbody_len = 0; rqbody_ptr = 0; rqbody_ok = true; - // GET - MP_THREAD_GIL_EXIT(); - esp_err_t err = esp_http_client_perform(client); - esp_http_client_cleanup(client); - MP_THREAD_GIL_ENTER(); + + if (method == HTTP_METHOD_POST) { + mp_obj_dict_t *dict; + if (!multipart) { + if (MP_OBJ_IS_TYPE(post_data_in, &mp_type_dict)) { + dict = MP_OBJ_TO_PTR(post_data_in); + post_data = url_post_fields(dict); + err = esp_http_client_set_post_field(client, post_data, strlen(post_data)); + if (err != ESP_OK) { + if (rqbody_file) fclose(rqbody_file); + free(post_data); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error setting post fields")); + } + free_post_data = true; + } + else if (MP_OBJ_IS_STR(post_data_in)) { + post_data = (char *)mp_obj_str_get_str(post_data_in); + err = esp_http_client_set_post_field(client, post_data, strlen(post_data)); + if (err != ESP_OK) { + if (rqbody_file) fclose(rqbody_file); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error setting post fields")); + } + } + else { + if (rqbody_file) fclose(rqbody_file); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Expected Dict or String type argument")); + } + } + else { + // === multipart POST === + if (MP_OBJ_IS_TYPE(post_data_in, &mp_type_dict)) { + dict = MP_OBJ_TO_PTR(post_data_in); + } + else { + if (rqbody_file) fclose(rqbody_file); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Expected Dict type argument")); + } + + // Prepare multipart boundary + memset(bndry,0x00,20); + int randn = rand(); + sprintf(bndry, "_____%d_____", randn); + // Get body length + int cont_len = multipart_post_fields(dict, bndry, client, false); + if (cont_len <= 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Nothing to send")); + } + char temp_buf[128]; + sprintf(temp_buf, "multipart/form-data; boundary=%s", bndry); + esp_http_client_set_header(client, "Content-Type", temp_buf); + + // Perform actions + MP_THREAD_GIL_EXIT(); + err = ESP_OK; + do { + if ((err = esp_http_client_open(client, cont_len)) != ESP_OK) { + sprintf(err_msg, "Http client error: open"); + break; + } + + // Send content + cont_len = multipart_post_fields(dict, bndry, client, true); + + // Check response + if ((esp_http_client_perform_response(client)) != ESP_OK) { + sprintf(err_msg, "Http client error: response"); + break; + } + } while (esp_http_client_process_again(client)); + esp_http_client_cleanup(client); + MP_THREAD_GIL_ENTER(); + perform_handled = true; + } + } + else if ((method == HTTP_METHOD_PUT) || (method == HTTP_METHOD_PATCH)) { + // String, it can be string to send or file name + if (MP_OBJ_IS_STR(post_data_in)) { + post_data = (char *)mp_obj_str_get_str(post_data_in); + int cont_len = handle_file(client, NULL, NULL, post_data, false); + if (cont_len > 0) { + // Perform actions + MP_THREAD_GIL_EXIT(); + err = ESP_OK; + do { + if ((err = esp_http_client_open(client, cont_len)) != ESP_OK) { + sprintf(err_msg, "Http client error: open"); + break; + } + + // Send content + cont_len = handle_file(client, NULL, NULL, post_data, true); + + // Check response + if ((esp_http_client_perform_response(client)) != ESP_OK) { + sprintf(err_msg, "Http client error: response"); + break; + } + } while (esp_http_client_process_again(client)); + esp_http_client_cleanup(client); + MP_THREAD_GIL_ENTER(); + perform_handled = true; + } + else { + err = esp_http_client_set_post_field(client, post_data, strlen(post_data)); + if (err != ESP_OK) { + if (rqbody_file) fclose(rqbody_file); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error setting post fields")); + } + } + } + else { + if (rqbody_file) fclose(rqbody_file); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Expected String type argument")); + } + } + + if (!perform_handled) { + MP_THREAD_GIL_EXIT(); + err = esp_http_client_perform(client); + esp_http_client_cleanup(client); + if ((free_post_data) && (post_data)) free(post_data); + MP_THREAD_GIL_ENTER(); + } + if (err != ESP_OK) { if (rqbody_file) fclose(rqbody_file); if (rqheader) free(rqheader); @@ -531,8 +882,8 @@ STATIC mp_obj_t requests_GET(size_t n_args, const mp_obj_t *pos_args, mp_map_t * rqbody_file = NULL; rqheader = NULL; rqbody = NULL; - ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err)); - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "HTTP GET request failed")); + ESP_LOGE(TAG, "HTTP Request failed: %s [%s]", esp_err_to_name(err), err_msg); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "HTTP Request failed")); } status = esp_http_client_get_status_code(client); @@ -543,7 +894,7 @@ STATIC mp_obj_t requests_GET(size_t n_args, const mp_obj_t *pos_args, mp_map_t * if ((rqheader) && (rqheader_ptr)) tuple[1] = mp_obj_new_str(rqheader, rqheader_ptr); else tuple[1] = mp_const_none; - if (rqbody_file) tuple[2] = mp_obj_new_str(fname, strlen(fname)); + if (rqbody_file) tuple[2] = mp_obj_new_str(tofile, strlen(tofile)); else if ((rqbody) && (rqbody_ptr)) tuple[2] = mp_obj_new_str(rqbody, rqbody_ptr); else tuple[2] = mp_const_none; @@ -556,15 +907,143 @@ STATIC mp_obj_t requests_GET(size_t n_args, const mp_obj_t *pos_args, mp_map_t * return mp_obj_new_tuple(3, tuple); } + +//-------------------------------------------------------------------------------------- +STATIC mp_obj_t requests_GET(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + network_checkConnection(); + enum { ARG_url, ARG_file }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_url, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_file, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + char *url = NULL; + char *fname = NULL; + + url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); + + if (MP_OBJ_IS_STR(args[ARG_file].u_obj)) { + // GET to file + fname = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); + } + mp_obj_t res = request(HTTP_METHOD_GET, false, NULL, url, fname); + + return res; +} STATIC MP_DEFINE_CONST_FUN_OBJ_KW(requests_GET_obj, 1, requests_GET); +//-------------------------------------------------------------------------------------- +STATIC mp_obj_t requests_HEAD(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + network_checkConnection(); + enum { ARG_url, ARG_file }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_url, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + char *url = NULL; + + url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); + + mp_obj_t res = request(HTTP_METHOD_HEAD, false, NULL, url, NULL); + + return res; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(requests_HEAD_obj, 1, requests_HEAD); + +//--------------------------------------------------------------------------------------- +STATIC mp_obj_t requests_POST(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + network_checkConnection(); + enum { ARG_url, ARG_params, ARG_file, ARG_multipart }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_url, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_params, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_file, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_multipart, MP_ARG_BOOL, { .u_bool = false } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + char *url = NULL; + char *fname = NULL; + + url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); + + if (MP_OBJ_IS_STR(args[ARG_file].u_obj)) { + // GET to file + fname = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); + } + mp_obj_t res = request(HTTP_METHOD_POST, args[ARG_multipart].u_bool, args[ARG_params].u_obj, url, fname); + + return res; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(requests_POST_obj, 1, requests_POST); + +//-------------------------------------------------------------------------------------- +STATIC mp_obj_t requests_PUT(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + network_checkConnection(); + enum { ARG_url, ARG_data }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_url, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + char *url = NULL; + + url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); + + mp_obj_t res = request(HTTP_METHOD_PUT, false, args[ARG_data].u_obj, url, NULL); + + return res; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(requests_PUT_obj, 1, requests_PUT); + +//---------------------------------------------------------------------------------------- +STATIC mp_obj_t requests_PATCH(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + network_checkConnection(); + enum { ARG_url, ARG_data }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_url, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + char *url = NULL; + + url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); + + mp_obj_t res = request(HTTP_METHOD_PATCH, false, args[ARG_data].u_obj, url, NULL); + + return res; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(requests_PATCH_obj, 1, requests_PATCH); + //================================================================ STATIC const mp_rom_map_elem_t requests_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_requests) }, - { MP_ROM_QSTR(MP_QSTR_test), MP_ROM_PTR(&mod_requests_test_obj) }, { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&requests_GET_obj) }, + { MP_ROM_QSTR(MP_QSTR_head), MP_ROM_PTR(&requests_HEAD_obj) }, + { MP_ROM_QSTR(MP_QSTR_post), MP_ROM_PTR(&requests_POST_obj) }, + { MP_ROM_QSTR(MP_QSTR_put), MP_ROM_PTR(&requests_PUT_obj) }, + { MP_ROM_QSTR(MP_QSTR_patch), MP_ROM_PTR(&requests_PATCH_obj) }, }; STATIC MP_DEFINE_CONST_DICT(requests_module_globals, requests_module_globals_table); diff --git a/MicroPython_BUILD/components/micropython/esp32/modssh.c b/MicroPython_BUILD/components/micropython/esp32/modssh.c index 4b66b548..ffac9c04 100644 --- a/MicroPython_BUILD/components/micropython/esp32/modssh.c +++ b/MicroPython_BUILD/components/micropython/esp32/modssh.c @@ -45,12 +45,13 @@ #include "libs/espcurl.h" #include "extmod/vfs_native.h" #include "libssh2.h" +#include "modnetwork.h" //------------------------------------------------------------------------------------------------------- STATIC mp_obj_t curl_SSH_helper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t type) { - checkConnection(); + network_checkConnection(); enum { ARG_url, ARG_user, ARG_pass, ARG_key, ARG_file, ARG_port }; const mp_arg_t allowed_args[] = { { MP_QSTR_url, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, diff --git a/MicroPython_BUILD/components/micropython/esp32/moduos.c b/MicroPython_BUILD/components/micropython/esp32/moduos.c index aa373378..f6078f4b 100644 --- a/MicroPython_BUILD/components/micropython/esp32/moduos.c +++ b/MicroPython_BUILD/components/micropython/esp32/moduos.c @@ -34,6 +34,7 @@ #include "esp_system.h" #include "esp_log.h" +#include "driver/spi_common.h" #include "py/mpconfig.h" #include "py/obj.h" @@ -145,7 +146,8 @@ STATIC mp_obj_t os_sdcard_config(size_t n_args, const mp_obj_t *pos_args, mp_map { MP_QSTR_mosi, MP_ARG_OBJ, { .u_obj = mp_const_none } }, { MP_QSTR_miso, MP_ARG_OBJ, { .u_obj = mp_const_none } }, { MP_QSTR_cs, MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_hispeed, MP_ARG_BOOL, { .u_bool = true } }, + { MP_QSTR_maxspeed, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_spihost, MP_ARG_INT, { .u_int = VSPI_HOST } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -153,7 +155,7 @@ STATIC mp_obj_t os_sdcard_config(size_t n_args, const mp_obj_t *pos_args, mp_map int mode = args[0].u_int; if ((mode < 1) || (mode > 3)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Unsupported sdcard mode")); + mp_raise_ValueError("Unsupported sdcard mode"); } if (mode == 1) { int clk = machine_pin_get_gpio(args[1].u_obj); @@ -167,12 +169,25 @@ STATIC mp_obj_t os_sdcard_config(size_t n_args, const mp_obj_t *pos_args, mp_map sdcard_config.miso = miso; sdcard_config.cs = cs; sdcard_config.mode = mode; + if ((args[6].u_int != HSPI_HOST) && (args[6].u_int != VSPI_HOST)) { + mp_raise_ValueError("Unsupported SPI hots (1 (HSPI) or 2 (VSPI) allowed)"); + } + sdcard_config.host = args[6].u_int; } else { if (native_vfs_mounted[VFS_NATIVE_TYPE_SDCARD]) os_umount_sdcard(); sdcard_config.mode = mode; + sdcard_config.host = 1; + } + if (args[5].u_int >= 0) { + if ((args[5].u_int == 400) || ((args[5].u_int >= 8) && (args[5].u_int <= 40))) { + if (args[5].u_int == 400) sdcard_config.max_speed = 400; + else sdcard_config.max_speed = args[5].u_int * 1000; + } + else { + mp_raise_ValueError("Unsupported max speed (8 - 40 MHz allowed)"); + } } - sdcard_config.hispeed = args[5].u_bool; return mp_const_none; } diff --git a/MicroPython_BUILD/components/micropython/esp32/mpthreadport.c b/MicroPython_BUILD/components/micropython/esp32/mpthreadport.c index d9df20a7..f080d4e2 100644 --- a/MicroPython_BUILD/components/micropython/esp32/mpthreadport.c +++ b/MicroPython_BUILD/components/micropython/esp32/mpthreadport.c @@ -41,10 +41,11 @@ #include "py/mpthread.h" #include "py/mphal.h" #include "mpthreadport.h" -#include "modnetwork.h" #include "modmachine.h" #if defined(CONFIG_MICROPY_USE_TELNET) || defined(CONFIG_MICROPY_USE_FTPSERVER) +#include "libs/libGSM.h" +#include "modnetwork.h" #include "tcpip_adapter.h" #include "esp_wifi_types.h" #include "esp_wifi.h" @@ -165,7 +166,6 @@ void mp_thread_gc_others(int flag) { } if (th->type == THREAD_TYPE_SERVICE) continue; - int n_marked; if (th->arg) { #if MICROPY_PY_GC_COLLECT_RETVAL n_marked = MP_STATE_MEM(gc_marked); @@ -485,7 +485,7 @@ int mp_thread_get_sp(void) { mp_thread_mutex_lock(&thread_mutex, 1); for (thread_t *th = thread; th != NULL; th = th->next) { if (th->id == xTaskGetCurrentTaskHandle()) { - res = th->curr_sp; + res = (uintptr_t)th->curr_sp; break; } } @@ -829,21 +829,23 @@ int mp_thread_mainAcceptMsg(int8_t accept) { // ===== SERVICE THREADS ============================================== #if defined(CONFIG_MICROPY_USE_TELNET) || defined(CONFIG_MICROPY_USE_FTPSERVER) -// Check if WiFi connection is available + +// Check if any network connection is available (WiFi STA and/or AP, ethernet) //----------------------- -static bool _check_wifi() +static bool _check_network() { - if (wifi_network_state < 2) return false; - - bool res = 0; - wifi_mode_t wifi_mode; - - esp_err_t ret = esp_wifi_get_mode(&wifi_mode); - if (ret == ESP_OK) { - if ((wifi_mode & WIFI_MODE_STA) && ((wifi_sta_isconnected) && (wifi_sta_has_ipaddress))) res = true; - if ((wifi_mode & WIFI_MODE_AP) && wifi_ap_isconnected) res = true; + uint32_t ip = network_hasip(); + if (ip == 0) { + #ifdef CONFIG_MICROPY_USE_GSM + //ToDo: should we enable telnet/ftp over GSM ? + //if (ppposStatus() != GSM_STATE_CONNECTED) { + return false; + //} + #else + return false; + #endif } - return res; + return true; } #endif @@ -854,13 +856,13 @@ void telnet_task (void *pvParameters) // Initialize telnet, create rx buffer and mutex telnet_init(); - // Check if WiFi connection is available - while (!_check_wifi()) { + // Check if network connection is available + while (!_check_network()) { vTaskDelay(1000 / portTICK_PERIOD_MS); if (telnet_stop_requested()) goto exit; } - // We have WiFi connection, enable telnet + // We have network connection, enable telnet telnet_enable(); while (1) { @@ -875,11 +877,11 @@ void telnet_task (void *pvParameters) vTaskDelay(1); - // ---- Check if WiFi is still available ---- - if (!_check_wifi()) { + // ---- Check if network is still available ---- + if (!_check_network()) { bool was_enabled = telnet_isenabled(); telnet_disable(); - while (!_check_wifi()) { + while (!_check_network()) { vTaskDelay(200 / portTICK_PERIOD_MS); if (telnet_stop_requested()) goto exit; } @@ -920,14 +922,17 @@ void ftp_task (void *pvParameters) { uint64_t elapsed, time_ms = mp_hal_ticks_ms(); // Initialize ftp, create rx buffer and mutex - ftp_init(); + if (!ftp_init()) { + ESP_LOGE("[Ftp]", "Init Error"); + goto exit; + } - while (!_check_wifi()) { + while (!_check_network()) { vTaskDelay(1000 / portTICK_PERIOD_MS); if (ftp_stop_requested()) goto exit; } - // We have WiFi connection, enable ftp + // We have network connection, enable ftp ftp_enable(); time_ms = mp_hal_ticks_ms(); @@ -946,11 +951,11 @@ void ftp_task (void *pvParameters) vTaskDelay(1); - // ---- Check if WiFi is still available ---- - if (!_check_wifi()) { + // ---- Check if network is still available ---- + if (!_check_network()) { bool was_enabled = ftp_isenabled(); ftp_disable(); - while (!_check_wifi()) { + while (!_check_network()) { vTaskDelay(200 / portTICK_PERIOD_MS); if (ftp_stop_requested()) goto exit; } diff --git a/MicroPython_BUILD/components/micropython/esp32/mpversion.h b/MicroPython_BUILD/components/micropython/esp32/mpversion.h index 845705a8..4557088c 100644 --- a/MicroPython_BUILD/components/micropython/esp32/mpversion.h +++ b/MicroPython_BUILD/components/micropython/esp32/mpversion.h @@ -24,14 +24,14 @@ * THE SOFTWARE. */ -#define MICROPY_GIT_TAG "ESP32_LoBo_v3.2.20" -#define MICROPY_ESPIDF_HASH "698d3bafa51a06a89605c6a15f89df514efa21f8" -#define MICROPY_ESPIDF_VERSION "v3.1-beta1-14-g698d3baf" -#define MICROPY_ESPIDF_DATE "2018-06-27" -#define MICROPY_BUILD_DATE "2018-06-28" +#define MICROPY_GIT_TAG "ESP32_LoBo_v3.2.21" +#define MICROPY_ESPIDF_HASH "53509c7bfde505b6d0aa5ce0cd1ac48bc3743039" +#define MICROPY_ESPIDF_VERSION "v3.1-rc1-53509c7b" +#define MICROPY_ESPIDF_DATE "2018-08-15" +#define MICROPY_BUILD_DATE "2018-08-27" #define MICROPY_VERSION_MAJOR (3) #define MICROPY_VERSION_MINOR (2) -#define MICROPY_VERSION_MICRO (20) -#define MICROPY_VERSION_STRING "3.2.20" +#define MICROPY_VERSION_MICRO (21) +#define MICROPY_VERSION_STRING "3.2.21" #define MICROPY_CORE_VERSION "1b7487e" #define MICROPY_CORE_DATE "2018-05-16" diff --git a/MicroPython_BUILD/components/micropython/esp32/network_lan.c b/MicroPython_BUILD/components/micropython/esp32/network_lan.c index 137bab5b..8693e9f0 100644 --- a/MicroPython_BUILD/components/micropython/esp32/network_lan.c +++ b/MicroPython_BUILD/components/micropython/esp32/network_lan.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2017 "Eric Poulsen" + * Copyright (c) 2018 LoBo (https://github.com/loboris) * * Based on the ESP IDF example code which is Public Domain / CC0 * @@ -28,8 +29,6 @@ #include "sdkconfig.h" -#ifdef CONFIG_MICROPY_USE_ETHERNET - #include "py/runtime.h" #include "py/mphal.h" @@ -38,9 +37,16 @@ #include "eth_phy/phy_lan8720.h" #include "tcpip_adapter.h" +#include "netutils.h" #include "modmachine.h" #include "modnetwork.h" +bool lan_eth_active = false; + +#ifdef CONFIG_MICROPY_USE_ETHERNET + +static eth_phy_check_link_func lan_eth_link_func = NULL; + typedef struct _lan_if_obj_t { mp_obj_base_t base; int if_id; // MUST BE FIRST to match wlan_if_obj_t @@ -56,8 +62,9 @@ typedef struct _lan_if_obj_t { } lan_if_obj_t; const mp_obj_type_t lan_if_type; -STATIC lan_if_obj_t lan_obj = {{&lan_if_type}, ESP_IF_ETH, false, false}; +STATIC lan_if_obj_t lan_obj = {{&lan_if_type}, ESP_IF_ETH, false, false, 23, 18, -1, 1, 0, NULL, NULL}; +//----------------------------------------- STATIC void phy_power_enable(bool enable) { lan_if_obj_t* self = &lan_obj; @@ -86,12 +93,14 @@ STATIC void phy_power_enable(bool enable) { } } +//--------------------------- STATIC void init_lan_rmii() { lan_if_obj_t* self = &lan_obj; phy_rmii_configure_data_interface_pins(); phy_rmii_smi_configure_pins(self->mdc_pin, self->mdio_pin); } +//----------------------------------------------------------------------------------- STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { lan_if_obj_t* self = &lan_obj; @@ -99,14 +108,15 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar return MP_OBJ_FROM_PTR(&lan_obj); } - enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type }; + enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type, ARG_clk_type }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_power, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_id, MP_ARG_OBJ, { .u_obj = mp_const_none} }, + { MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_power, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 1 } }, + { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = PHY_LAN8720 } }, + { MP_QSTR_clk_type, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = ETH_CLOCK_GPIO0_IN } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -122,14 +132,21 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar self->mdio_pin = machine_pin_get_gpio(args[ARG_mdio].u_obj); self->phy_power_pin = args[ARG_power].u_obj == mp_const_none ? -1 : machine_pin_get_gpio(args[ARG_power].u_obj); - if (args[ARG_phy_addr].u_int < 0x00 || args[ARG_phy_addr].u_int > 0x1f) { + if ((args[ARG_phy_addr].u_int < 0x00) || (args[ARG_phy_addr].u_int > 0x1f)) { mp_raise_ValueError("invalid phy address"); } - if (args[ARG_phy_type].u_int != PHY_LAN8720 && args[ARG_phy_type].u_int != PHY_TLK110) { + if ((args[ARG_phy_type].u_int != PHY_LAN8720) && (args[ARG_phy_type].u_int != PHY_TLK110)) { mp_raise_ValueError("invalid phy type"); } + if ((args[ARG_clk_type].u_int < 0) || (args[ARG_clk_type].u_int > 3)) { + mp_raise_ValueError("invalid clock type"); + } + if ((mpy_use_spiram) && (args[ARG_clk_type].u_int > 1)) { + mp_raise_ValueError("clock on gpio 16 & 17 not allowed when SPIRAM is used"); + } + eth_config_t config; switch (args[ARG_phy_type].u_int) { @@ -142,11 +159,13 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar } self->link_func = config.phy_check_link; + lan_eth_link_func = config.phy_check_link; // Replace default power func with our own self->power_func = config.phy_power_enable; config.phy_power_enable = phy_power_enable; + config.clock_mode = args[ARG_clk_type].u_int; config.phy_addr = args[ARG_phy_addr].u_int; config.gpio_config = init_lan_rmii; config.tcpip_input = tcpip_adapter_eth_input; @@ -161,6 +180,7 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar } MP_DEFINE_CONST_FUN_OBJ_KW(get_lan_obj, 0, get_lan); +//--------------------------------------------------------------- STATIC mp_obj_t lan_active(size_t n_args, const mp_obj_t *args) { lan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); @@ -177,30 +197,53 @@ STATIC mp_obj_t lan_active(size_t n_args, const mp_obj_t *args) { } } } + lan_eth_active = self->active; return mp_obj_new_bool(self->active); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lan_active_obj, 1, 2, lan_active); +//-------------------------------------------- STATIC mp_obj_t lan_status(mp_obj_t self_in) { return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_status_obj, lan_status); +//------------------------------------------------- STATIC mp_obj_t lan_isconnected(mp_obj_t self_in) { lan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); return self->active ? mp_obj_new_bool(self->link_func()) : mp_const_false; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_isconnected_obj, lan_isconnected); + +tcpip_adapter_ip_info_t info; +tcpip_adapter_dns_info_t dns_info; + +//----------------------------------------- +STATIC mp_obj_t lan_hasip(mp_obj_t self_in) +{ + lan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); + + tcpip_adapter_ip_info_t info; + tcpip_adapter_get_ip_info(self->if_id, &info); + if (info.ip.addr == 0) return mp_const_false; + + return netutils_format_ipv4_addr((uint8_t*)&info.ip, NETUTILS_BIG); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_hasip_obj, lan_hasip); + +//=========================================================== STATIC const mp_rom_map_elem_t lan_if_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&lan_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&lan_active_obj) }, { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&lan_isconnected_obj) }, - { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&lan_status_obj) }, - { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&lan_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) }, + { MP_ROM_QSTR(MP_QSTR_hasip), MP_ROM_PTR(&lan_hasip_obj) }, }; STATIC MP_DEFINE_CONST_DICT(lan_if_locals_dict, lan_if_locals_dict_table); +//================================= const mp_obj_type_t lan_if_type = { { &mp_type_type }, .name = MP_QSTR_LAN, diff --git a/MicroPython_BUILD/components/micropython/extmod/vfs_native.c b/MicroPython_BUILD/components/micropython/extmod/vfs_native.c index 427831d0..64029e23 100644 --- a/MicroPython_BUILD/components/micropython/extmod/vfs_native.c +++ b/MicroPython_BUILD/components/micropython/extmod/vfs_native.c @@ -107,6 +107,11 @@ STATIC const byte fresult_to_errno_table[20] = { STATIC const char *TAG = "vfs_native"; sdcard_config_t sdcard_config = { +#if CONFIG_SDCARD_MODE == 1 + SDMMC_FREQ_DEFAULT, +#else + SDMMC_FREQ_HIGHSPEED, +#endif CONFIG_SDCARD_MODE, #if CONFIG_SDCARD_MODE == 1 CONFIG_SDCARD_CLK, @@ -119,7 +124,7 @@ sdcard_config_t sdcard_config = { -1, -1, #endif - 1 + VSPI_HOST }; bool native_vfs_mounted[2] = {false, false}; @@ -703,39 +708,56 @@ STATIC void sdcard_print_info(const sdmmc_card_t* card, int mode) else if (mode == 3) { printf(" Mode: Unknown\n"); } - printf(" Name: %s\n", card->cid.name); - printf(" Type: %s\n", (card->ocr & SD_OCR_SDHC_CAP)?"SDHC/SDXC":"SDSC"); - printf("Speed: %s (%d MHz)\n", (card->csd.tr_speed > 25000000)?"high speed":"default speed", card->csd.tr_speed/1000000); - printf(" Size: %u MB\n", (uint32_t)(((uint64_t) card->csd.capacity) * card->csd.sector_size / (1024 * 1024))); - printf(" CSD: ver=%d, sector_size=%d, capacity=%d read_bl_len=%d\n", + printf(" Name: %s\n", card->cid.name); + printf(" Type: %s\n", (card->ocr & SD_OCR_SDHC_CAP)?"SDHC/SDXC":"SDSC"); + printf(" Speed: %s (%d MHz)\n", (card->csd.tr_speed > 25000000)?"high speed":"default speed", card->csd.tr_speed/1000000); + if (mode == 1) printf("SPI speed: %d MHz\n", card->host.max_freq_khz / 1000); + printf(" Size: %u MB\n", (uint32_t)(((uint64_t) card->csd.capacity) * card->csd.sector_size / (1024 * 1024))); + printf(" CSD: ver=%d, sector_size=%d, capacity=%d read_bl_len=%d\n", card->csd.csd_ver, card->csd.sector_size, card->csd.capacity, card->csd.read_block_len); - printf(" SCR: sd_spec=%d, bus_width=%d\n\n", card->scr.sd_spec, card->scr.bus_width); + printf(" SCR: sd_spec=%d, bus_width=%d\n\n", card->scr.sd_spec, card->scr.bus_width); #endif } -//-------------------------------------------------------------- -static void _setPins(int8_t p1, int8_t p2, int8_t p3, int8_t p4) +//-------------------------------------------------------------------------------------------- +static void _setPins(int8_t miso, int8_t mosi, int8_t clk, int8_t cs, int8_t dat1, int8_t dat2) { - if (p1 >= 0) { - gpio_pad_select_gpio(p1); - gpio_set_direction(p1, GPIO_MODE_INPUT); - gpio_set_pull_mode(p1, GPIO_PULLUP_ONLY); + if (miso >= 0) { // miso/dat0/dO + gpio_pad_select_gpio(miso); + gpio_set_direction(miso, GPIO_MODE_INPUT_OUTPUT_OD); + gpio_set_pull_mode(miso, GPIO_PULLUP_ONLY); + gpio_set_level(miso, 1); + } + if (mosi >= 0) { // mosi/cmd/dI + gpio_pad_select_gpio(mosi); + gpio_set_direction(mosi, GPIO_MODE_INPUT_OUTPUT_OD); + gpio_set_pull_mode(mosi, GPIO_PULLUP_ONLY); + gpio_set_level(mosi, 1); + } + if (clk >= 0) { // clk/sck + gpio_pad_select_gpio(clk); + gpio_set_direction(clk, GPIO_MODE_INPUT_OUTPUT_OD); + gpio_set_pull_mode(clk, GPIO_PULLUP_ONLY); + gpio_set_level(clk, 1); } - if (p2 >= 0) { - gpio_pad_select_gpio(p2); - gpio_set_direction(p2, GPIO_MODE_INPUT); - gpio_set_pull_mode(p2, GPIO_PULLUP_ONLY); + if (cs >= 0) { // cs/dat3 + gpio_pad_select_gpio(cs); + gpio_set_direction(cs, GPIO_MODE_INPUT_OUTPUT); + gpio_set_pull_mode(cs, GPIO_PULLUP_ONLY); + gpio_set_level(cs, 1); } - if (p3 >= 0) { - gpio_pad_select_gpio(p3); - gpio_set_direction(p3, GPIO_MODE_INPUT); - gpio_set_pull_mode(p3, GPIO_PULLUP_ONLY); + if (dat1 >= 0) { // dat1 + gpio_pad_select_gpio(dat1); + gpio_set_direction(dat1, GPIO_MODE_INPUT_OUTPUT_OD); + gpio_set_pull_mode(dat1, GPIO_PULLUP_ONLY); + gpio_set_level(dat1, 1); } - if (p4 >= 0) { - gpio_pad_select_gpio(p4); - gpio_set_direction(p4, GPIO_MODE_INPUT); - gpio_set_pull_mode(p4, GPIO_PULLUP_ONLY); + if (dat2 >= 0) { // dat2 + gpio_pad_select_gpio(dat2); + gpio_set_direction(dat2, GPIO_MODE_INPUT_OUTPUT_OD); + gpio_set_pull_mode(dat2, GPIO_PULLUP_ONLY); + gpio_set_level(dat2, 1); } } @@ -755,10 +777,10 @@ static void _sdcard_mount() // Use SPI mode sdmmc_host_t host = SDSPI_HOST_DEFAULT(); sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT(); - host.slot = VSPI_HOST; - host.max_freq_khz = (sdcard_config.hispeed > 0) ? SDMMC_FREQ_HIGHSPEED : SDMMC_FREQ_DEFAULT; + host.slot = sdcard_config.host; + host.max_freq_khz = sdcard_config.max_speed; slot_config.dma_channel = 2; - _setPins(sdcard_config.miso, sdcard_config.mosi, sdcard_config.clk, sdcard_config.cs); + _setPins(sdcard_config.miso, sdcard_config.mosi, sdcard_config.clk, sdcard_config.cs, -1, -1); slot_config.gpio_miso = sdcard_config.miso; slot_config.gpio_mosi = sdcard_config.mosi; @@ -769,16 +791,18 @@ static void _sdcard_mount() else { sdmmc_host_t host = SDMMC_HOST_DEFAULT(); sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); - host.max_freq_khz = (sdcard_config.hispeed > 0) ? SDMMC_FREQ_HIGHSPEED : SDMMC_FREQ_DEFAULT; + host.max_freq_khz = sdcard_config.max_speed; //(sdcard_config.max_speed > SDMMC_FREQ_DEFAULT) ? SDMMC_FREQ_HIGHSPEED : SDMMC_FREQ_DEFAULT; if (sdcard_config.mode == 2) { // Use 1-line SD mode - _setPins(4, 12, 15, 13); + // miso,mosi,clk,cs,dat1,dat2 + _setPins(2, 15, 14, 13, -1, -1); host.flags = SDMMC_HOST_FLAG_1BIT; slot_config.width = 1; } else { // Use 4-line SD mode - _setPins(4, 12, -1, -1); + // miso,mosi,clk,cs,dat1,dat2 + _setPins(2, 15, 14, 13, 4, 12); host.flags = SDMMC_HOST_FLAG_4BIT; slot_config.width = 4; } diff --git a/MicroPython_BUILD/components/micropython/extmod/vfs_native.h b/MicroPython_BUILD/components/micropython/extmod/vfs_native.h index 2b10b356..f9c41578 100644 --- a/MicroPython_BUILD/components/micropython/extmod/vfs_native.h +++ b/MicroPython_BUILD/components/micropython/extmod/vfs_native.h @@ -58,12 +58,13 @@ typedef struct _fs_user_mount_t { } fs_user_mount_t; typedef struct _sdcard_config_t { + int32_t max_speed; uint8_t mode; int8_t clk; int8_t mosi; int8_t miso; int8_t cs; - int8_t hispeed; + uint8_t host; } sdcard_config_t; extern const mp_obj_type_t mp_native_vfs_type; diff --git a/MicroPython_BUILD/components/micropython/lib/utils/pyexec.c b/MicroPython_BUILD/components/micropython/lib/utils/pyexec.c index 3a983cd7..1793a4f1 100644 --- a/MicroPython_BUILD/components/micropython/lib/utils/pyexec.c +++ b/MicroPython_BUILD/components/micropython/lib/utils/pyexec.c @@ -349,8 +349,10 @@ int pyexec_raw_repl(void) { } else if (c == CHAR_CTRL_D) { // input finished if (line.len == 0) { + // In raw_repl we only SIMULATE the reboot + // This is used by some applications like RSHELL mp_hal_stdout_tx_str("soft reboot\r\n"); - vTaskDelay(1000); + vTaskDelay(500); goto raw_repl_reset; } break; diff --git a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32.zip b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32.zip index d33d08ec..7fcdc2bd 100644 Binary files a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32.zip and b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32.zip differ diff --git a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_all.zip b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_all.zip index eeb798ca..3404bf83 100644 Binary files a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_all.zip and b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_all.zip differ diff --git a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_ota.zip b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_ota.zip index 95ba9f3a..2b555f5a 100644 Binary files a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_ota.zip and b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_ota.zip differ diff --git a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram.zip b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram.zip index 86b7565e..dd8b1233 100644 Binary files a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram.zip and b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram.zip differ diff --git a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_all.zip b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_all.zip index a1df4601..eea2a47e 100644 Binary files a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_all.zip and b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_all.zip differ diff --git a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_all_bt.zip b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_all_bt.zip index bbc589e8..ea747a5e 100644 Binary files a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_all_bt.zip and b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_all_bt.zip differ diff --git a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_ota.zip b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_ota.zip index a8483aa8..0ccb96f6 100644 Binary files a/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_ota.zip and b/MicroPython_BUILD/firmware/MicroPython_LoBo_esp32_psram_ota.zip differ diff --git a/MicroPython_BUILD/firmware/esp32/MicroPython.bin b/MicroPython_BUILD/firmware/esp32/MicroPython.bin index 075b65d6..dc598b1b 100644 Binary files a/MicroPython_BUILD/firmware/esp32/MicroPython.bin and b/MicroPython_BUILD/firmware/esp32/MicroPython.bin differ diff --git a/MicroPython_BUILD/firmware/esp32/bootloader/bootloader.bin b/MicroPython_BUILD/firmware/esp32/bootloader/bootloader.bin index de05ff6b..bff3225c 100644 Binary files a/MicroPython_BUILD/firmware/esp32/bootloader/bootloader.bin and b/MicroPython_BUILD/firmware/esp32/bootloader/bootloader.bin differ diff --git a/MicroPython_BUILD/firmware/esp32/partitions_mpy.bin b/MicroPython_BUILD/firmware/esp32/partitions_mpy.bin index 4d9423a1..bd8d0f13 100644 Binary files a/MicroPython_BUILD/firmware/esp32/partitions_mpy.bin and b/MicroPython_BUILD/firmware/esp32/partitions_mpy.bin differ diff --git a/MicroPython_BUILD/firmware/esp32/partitions_mpy.csv b/MicroPython_BUILD/firmware/esp32/partitions_mpy.csv index 7dfb66a2..adfaffd7 100644 --- a/MicroPython_BUILD/firmware/esp32/partitions_mpy.csv +++ b/MicroPython_BUILD/firmware/esp32/partitions_mpy.csv @@ -5,5 +5,5 @@ # ------------------------------------------------------- nvs, data, nvs, 0x9000, 24K, phy_init, data, phy, 0xf000, 4K, -MicroPython, app, factory, 0x10000, 1472K, +MicroPython, app, factory, 0x10000, 1536K, internalfs, data, spiffs, , 1024K, diff --git a/MicroPython_BUILD/firmware/esp32/sdkconfig b/MicroPython_BUILD/firmware/esp32/sdkconfig index 14b4157a..f886b154 100644 --- a/MicroPython_BUILD/firmware/esp32/sdkconfig +++ b/MicroPython_BUILD/firmware/esp32/sdkconfig @@ -134,12 +134,15 @@ CONFIG_MICROPY_PY_FRAMEBUF=y CONFIG_MICROPY_PY_USE_BTREE= CONFIG_MICROPY_USE_WEBSOCKETS= CONFIG_MICROPY_USE_DISPLAY=y +CONFIG_MICROPY_USE_TFT=y +CONFIG_MICROPY_USE_EPD= CONFIG_MICROPY_USE_EVE= CONFIG_MICROPY_USE_GSM= CONFIG_MICROPY_USE_GPS=y CONFIG_MICROPY_GPS_SERVICE_STACK=3072 CONFIG_MICROPY_USE_ETHERNET= CONFIG_MICROPY_USE_MDNS=y +CONFIG_MICROPY_USE_REQUESTS=y CONFIG_MICROPY_USE_CURL= CONFIG_MICROPY_USE_SSH= CONFIG_MICROPY_USE_MQTT=y diff --git a/MicroPython_BUILD/firmware/esp32_all/MicroPython.bin b/MicroPython_BUILD/firmware/esp32_all/MicroPython.bin index b01d60a9..c113b335 100644 Binary files a/MicroPython_BUILD/firmware/esp32_all/MicroPython.bin and b/MicroPython_BUILD/firmware/esp32_all/MicroPython.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_all/bootloader/bootloader.bin b/MicroPython_BUILD/firmware/esp32_all/bootloader/bootloader.bin index 55f5e591..1e6d8624 100644 Binary files a/MicroPython_BUILD/firmware/esp32_all/bootloader/bootloader.bin and b/MicroPython_BUILD/firmware/esp32_all/bootloader/bootloader.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_all/partitions_mpy.bin b/MicroPython_BUILD/firmware/esp32_all/partitions_mpy.bin index 7c7197a9..869be0be 100644 Binary files a/MicroPython_BUILD/firmware/esp32_all/partitions_mpy.bin and b/MicroPython_BUILD/firmware/esp32_all/partitions_mpy.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_all/partitions_mpy.csv b/MicroPython_BUILD/firmware/esp32_all/partitions_mpy.csv index 00ab0e14..dbeb22e8 100644 --- a/MicroPython_BUILD/firmware/esp32_all/partitions_mpy.csv +++ b/MicroPython_BUILD/firmware/esp32_all/partitions_mpy.csv @@ -5,5 +5,5 @@ # ------------------------------------------------------- nvs, data, nvs, 0x9000, 24K, phy_init, data, phy, 0xf000, 4K, -MicroPython, app, factory, 0x10000, 1920K, +MicroPython, app, factory, 0x10000, 1984K, internalfs, data, spiffs, , 1024K, diff --git a/MicroPython_BUILD/firmware/esp32_all/sdkconfig b/MicroPython_BUILD/firmware/esp32_all/sdkconfig index bdee26f6..dc3b2ef5 100644 --- a/MicroPython_BUILD/firmware/esp32_all/sdkconfig +++ b/MicroPython_BUILD/firmware/esp32_all/sdkconfig @@ -134,13 +134,17 @@ CONFIG_MICROPY_PY_FRAMEBUF=y CONFIG_MICROPY_PY_USE_BTREE=y CONFIG_MICROPY_USE_WEBSOCKETS=y CONFIG_MICROPY_USE_DISPLAY=y +CONFIG_MICROPY_USE_TFT=y +CONFIG_MICROPY_USE_EPD= CONFIG_MICROPY_USE_EVE= CONFIG_MICROPY_USE_GSM=y CONFIG_MICROPY_USE_GPS=y CONFIG_MICROPY_GPS_SERVICE_STACK=3072 CONFIG_MICROPY_USE_ETHERNET= CONFIG_MICROPY_USE_MDNS=y +CONFIG_MICROPY_USE_REQUESTS=y CONFIG_MICROPY_USE_CURL=y +CONFIG_MICROPY_CURL_MAX_WRITE_SIZE=8192 CONFIG_MICROPY_USE_CURL_TLS=y CONFIG_MICROPY_USE_CURLFTP=y CONFIG_MICROPY_USE_SSH=y diff --git a/MicroPython_BUILD/firmware/esp32_ota/MicroPython.bin b/MicroPython_BUILD/firmware/esp32_ota/MicroPython.bin index 0b9cae0a..fa3eb71b 100644 Binary files a/MicroPython_BUILD/firmware/esp32_ota/MicroPython.bin and b/MicroPython_BUILD/firmware/esp32_ota/MicroPython.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_ota/bootloader/bootloader.bin b/MicroPython_BUILD/firmware/esp32_ota/bootloader/bootloader.bin index 2406fbcf..6d37c7fd 100644 Binary files a/MicroPython_BUILD/firmware/esp32_ota/bootloader/bootloader.bin and b/MicroPython_BUILD/firmware/esp32_ota/bootloader/bootloader.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_ota/sdkconfig b/MicroPython_BUILD/firmware/esp32_ota/sdkconfig index b642e5c3..a6066aef 100644 --- a/MicroPython_BUILD/firmware/esp32_ota/sdkconfig +++ b/MicroPython_BUILD/firmware/esp32_ota/sdkconfig @@ -135,12 +135,15 @@ CONFIG_MICROPY_PY_FRAMEBUF=y CONFIG_MICROPY_PY_USE_BTREE= CONFIG_MICROPY_USE_WEBSOCKETS= CONFIG_MICROPY_USE_DISPLAY=y +CONFIG_MICROPY_USE_TFT=y +CONFIG_MICROPY_USE_EPD= CONFIG_MICROPY_USE_EVE= CONFIG_MICROPY_USE_GSM= CONFIG_MICROPY_USE_GPS=y CONFIG_MICROPY_GPS_SERVICE_STACK=3072 CONFIG_MICROPY_USE_ETHERNET= CONFIG_MICROPY_USE_MDNS=y +CONFIG_MICROPY_USE_REQUESTS=y CONFIG_MICROPY_USE_CURL= CONFIG_MICROPY_USE_SSH= CONFIG_MICROPY_USE_MQTT=y diff --git a/MicroPython_BUILD/firmware/esp32_psram/MicroPython.bin b/MicroPython_BUILD/firmware/esp32_psram/MicroPython.bin index d6c1fde3..e03d2b22 100644 Binary files a/MicroPython_BUILD/firmware/esp32_psram/MicroPython.bin and b/MicroPython_BUILD/firmware/esp32_psram/MicroPython.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_psram/bootloader/bootloader.bin b/MicroPython_BUILD/firmware/esp32_psram/bootloader/bootloader.bin index fab11a51..8a81154c 100644 Binary files a/MicroPython_BUILD/firmware/esp32_psram/bootloader/bootloader.bin and b/MicroPython_BUILD/firmware/esp32_psram/bootloader/bootloader.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_psram/sdkconfig b/MicroPython_BUILD/firmware/esp32_psram/sdkconfig index ad230c45..267c650e 100644 --- a/MicroPython_BUILD/firmware/esp32_psram/sdkconfig +++ b/MicroPython_BUILD/firmware/esp32_psram/sdkconfig @@ -134,12 +134,15 @@ CONFIG_MICROPY_PY_FRAMEBUF=y CONFIG_MICROPY_PY_USE_BTREE= CONFIG_MICROPY_USE_WEBSOCKETS= CONFIG_MICROPY_USE_DISPLAY=y +CONFIG_MICROPY_USE_TFT=y +CONFIG_MICROPY_USE_EPD= CONFIG_MICROPY_USE_EVE= CONFIG_MICROPY_USE_GSM= CONFIG_MICROPY_USE_GPS=y CONFIG_MICROPY_GPS_SERVICE_STACK=3072 CONFIG_MICROPY_USE_ETHERNET= CONFIG_MICROPY_USE_MDNS=y +CONFIG_MICROPY_USE_REQUESTS=y CONFIG_MICROPY_USE_CURL= CONFIG_MICROPY_USE_SSH= CONFIG_MICROPY_USE_MQTT=y diff --git a/MicroPython_BUILD/firmware/esp32_psram_all/MicroPython.bin b/MicroPython_BUILD/firmware/esp32_psram_all/MicroPython.bin index a58698bc..d4d66176 100644 Binary files a/MicroPython_BUILD/firmware/esp32_psram_all/MicroPython.bin and b/MicroPython_BUILD/firmware/esp32_psram_all/MicroPython.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_psram_all/bootloader/bootloader.bin b/MicroPython_BUILD/firmware/esp32_psram_all/bootloader/bootloader.bin index f2e53d28..b1e5270d 100644 Binary files a/MicroPython_BUILD/firmware/esp32_psram_all/bootloader/bootloader.bin and b/MicroPython_BUILD/firmware/esp32_psram_all/bootloader/bootloader.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.bin b/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.bin index 08662b12..ad8e58c6 100644 Binary files a/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.bin and b/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.csv b/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.csv index a3555ab3..0cc861d7 100644 --- a/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.csv +++ b/MicroPython_BUILD/firmware/esp32_psram_all/partitions_mpy.csv @@ -5,5 +5,5 @@ # ------------------------------------------------------- nvs, data, nvs, 0x9000, 24K, phy_init, data, phy, 0xf000, 4K, -MicroPython, app, factory, 0x10000, 2112K, +MicroPython, app, factory, 0x10000, 2176K, internalfs, data, spiffs, , 1024K, diff --git a/MicroPython_BUILD/firmware/esp32_psram_all/sdkconfig b/MicroPython_BUILD/firmware/esp32_psram_all/sdkconfig index e724e1ad..9d8aff34 100644 --- a/MicroPython_BUILD/firmware/esp32_psram_all/sdkconfig +++ b/MicroPython_BUILD/firmware/esp32_psram_all/sdkconfig @@ -134,13 +134,17 @@ CONFIG_MICROPY_PY_FRAMEBUF=y CONFIG_MICROPY_PY_USE_BTREE=y CONFIG_MICROPY_USE_WEBSOCKETS=y CONFIG_MICROPY_USE_DISPLAY=y +CONFIG_MICROPY_USE_TFT=y +CONFIG_MICROPY_USE_EPD= CONFIG_MICROPY_USE_EVE= CONFIG_MICROPY_USE_GSM=y CONFIG_MICROPY_USE_GPS=y CONFIG_MICROPY_GPS_SERVICE_STACK=3072 CONFIG_MICROPY_USE_ETHERNET= CONFIG_MICROPY_USE_MDNS=y +CONFIG_MICROPY_USE_REQUESTS=y CONFIG_MICROPY_USE_CURL=y +CONFIG_MICROPY_CURL_MAX_WRITE_SIZE=8192 CONFIG_MICROPY_USE_CURL_TLS=y CONFIG_MICROPY_USE_CURLFTP=y CONFIG_MICROPY_USE_SSH=y diff --git a/MicroPython_BUILD/firmware/esp32_psram_all_bt/MicroPython.bin b/MicroPython_BUILD/firmware/esp32_psram_all_bt/MicroPython.bin index f56ebab2..e1d37e2d 100644 Binary files a/MicroPython_BUILD/firmware/esp32_psram_all_bt/MicroPython.bin and b/MicroPython_BUILD/firmware/esp32_psram_all_bt/MicroPython.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_psram_all_bt/bootloader/bootloader.bin b/MicroPython_BUILD/firmware/esp32_psram_all_bt/bootloader/bootloader.bin index 134f06de..0f2d4a5b 100644 Binary files a/MicroPython_BUILD/firmware/esp32_psram_all_bt/bootloader/bootloader.bin and b/MicroPython_BUILD/firmware/esp32_psram_all_bt/bootloader/bootloader.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_psram_all_bt/partitions_mpy.bin b/MicroPython_BUILD/firmware/esp32_psram_all_bt/partitions_mpy.bin index ab21c87f..5498387c 100644 Binary files a/MicroPython_BUILD/firmware/esp32_psram_all_bt/partitions_mpy.bin and b/MicroPython_BUILD/firmware/esp32_psram_all_bt/partitions_mpy.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_psram_all_bt/partitions_mpy.csv b/MicroPython_BUILD/firmware/esp32_psram_all_bt/partitions_mpy.csv index 34a06484..6ec8e5c2 100644 --- a/MicroPython_BUILD/firmware/esp32_psram_all_bt/partitions_mpy.csv +++ b/MicroPython_BUILD/firmware/esp32_psram_all_bt/partitions_mpy.csv @@ -5,5 +5,5 @@ # ------------------------------------------------------- nvs, data, nvs, 0x9000, 24K, phy_init, data, phy, 0xf000, 4K, -MicroPython, app, factory, 0x10000, 2240K, +MicroPython, app, factory, 0x10000, 2304K, internalfs, data, spiffs, , 1024K, diff --git a/MicroPython_BUILD/firmware/esp32_psram_all_bt/sdkconfig b/MicroPython_BUILD/firmware/esp32_psram_all_bt/sdkconfig index bdf29f2a..6fc2ca7b 100644 --- a/MicroPython_BUILD/firmware/esp32_psram_all_bt/sdkconfig +++ b/MicroPython_BUILD/firmware/esp32_psram_all_bt/sdkconfig @@ -134,6 +134,8 @@ CONFIG_MICROPY_PY_FRAMEBUF=y CONFIG_MICROPY_PY_USE_BTREE=y CONFIG_MICROPY_USE_WEBSOCKETS=y CONFIG_MICROPY_USE_DISPLAY=y +CONFIG_MICROPY_USE_TFT=y +CONFIG_MICROPY_USE_EPD= CONFIG_MICROPY_USE_EVE= CONFIG_MICROPY_USE_GSM=y CONFIG_MICROPY_USE_GPS=y @@ -142,7 +144,9 @@ CONFIG_MICROPY_USE_ETHERNET= CONFIG_MICROPY_USE_BLUETOOTH= CONFIG_MICROPY_USE_RFCOMM=y CONFIG_MICROPY_USE_MDNS=y +CONFIG_MICROPY_USE_REQUESTS=y CONFIG_MICROPY_USE_CURL=y +CONFIG_MICROPY_CURL_MAX_WRITE_SIZE=8192 CONFIG_MICROPY_USE_CURL_TLS=y CONFIG_MICROPY_USE_CURLFTP=y CONFIG_MICROPY_USE_SSH=y @@ -254,6 +258,7 @@ CONFIG_BT_STACK_NO_LOG=y CONFIG_BT_ACL_CONNECTIONS=4 CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y +CONFIG_BLE_HOST_QUEUE_CONGESTION_CHECK= CONFIG_BLE_SCAN_DUPLICATE=y CONFIG_DUPLICATE_SCAN_CACHE_SIZE=20 CONFIG_BLE_MESH_SCAN_DUPLICATE_EN= diff --git a/MicroPython_BUILD/firmware/esp32_psram_ota/MicroPython.bin b/MicroPython_BUILD/firmware/esp32_psram_ota/MicroPython.bin index 425662c5..5eb19bb1 100644 Binary files a/MicroPython_BUILD/firmware/esp32_psram_ota/MicroPython.bin and b/MicroPython_BUILD/firmware/esp32_psram_ota/MicroPython.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_psram_ota/bootloader/bootloader.bin b/MicroPython_BUILD/firmware/esp32_psram_ota/bootloader/bootloader.bin index 4bb0ae72..c51c25b3 100644 Binary files a/MicroPython_BUILD/firmware/esp32_psram_ota/bootloader/bootloader.bin and b/MicroPython_BUILD/firmware/esp32_psram_ota/bootloader/bootloader.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.bin b/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.bin index fdc84317..3a5f8d2b 100644 Binary files a/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.bin and b/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.bin differ diff --git a/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.csv b/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.csv index 3d11e362..3e066a66 100644 --- a/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.csv +++ b/MicroPython_BUILD/firmware/esp32_psram_ota/partitions_mpy.csv @@ -6,6 +6,6 @@ nvs, data, nvs, 0x9000, 16K, otadata, data, ota, 0xd000, 8K, phy_init, data, phy, 0xf000, 4K, -MicroPython_1, app, ota_0, 0x10000, 1664K, -MicroPython_2, app, ota_1, , 1664K, -internalfs, data, spiffs, , 704K, +MicroPython_1, app, ota_0, 0x10000, 1728K, +MicroPython_2, app, ota_1, , 1728K, +internalfs, data, spiffs, , 576K, diff --git a/MicroPython_BUILD/firmware/esp32_psram_ota/sdkconfig b/MicroPython_BUILD/firmware/esp32_psram_ota/sdkconfig index a3d4259e..6c05f63e 100644 --- a/MicroPython_BUILD/firmware/esp32_psram_ota/sdkconfig +++ b/MicroPython_BUILD/firmware/esp32_psram_ota/sdkconfig @@ -135,12 +135,15 @@ CONFIG_MICROPY_PY_FRAMEBUF=y CONFIG_MICROPY_PY_USE_BTREE= CONFIG_MICROPY_USE_WEBSOCKETS= CONFIG_MICROPY_USE_DISPLAY=y +CONFIG_MICROPY_USE_TFT=y +CONFIG_MICROPY_USE_EPD= CONFIG_MICROPY_USE_EVE= CONFIG_MICROPY_USE_GSM= CONFIG_MICROPY_USE_GPS=y CONFIG_MICROPY_GPS_SERVICE_STACK=3072 CONFIG_MICROPY_USE_ETHERNET= CONFIG_MICROPY_USE_MDNS=y +CONFIG_MICROPY_USE_REQUESTS=y CONFIG_MICROPY_USE_CURL= CONFIG_MICROPY_USE_SSH= CONFIG_MICROPY_USE_MQTT=y diff --git a/MicroPython_BUILD/sdkconfig.fw_psram_all_bt b/MicroPython_BUILD/sdkconfig.fw_psram_all_bt index bdf29f2a..6fc2ca7b 100644 --- a/MicroPython_BUILD/sdkconfig.fw_psram_all_bt +++ b/MicroPython_BUILD/sdkconfig.fw_psram_all_bt @@ -134,6 +134,8 @@ CONFIG_MICROPY_PY_FRAMEBUF=y CONFIG_MICROPY_PY_USE_BTREE=y CONFIG_MICROPY_USE_WEBSOCKETS=y CONFIG_MICROPY_USE_DISPLAY=y +CONFIG_MICROPY_USE_TFT=y +CONFIG_MICROPY_USE_EPD= CONFIG_MICROPY_USE_EVE= CONFIG_MICROPY_USE_GSM=y CONFIG_MICROPY_USE_GPS=y @@ -142,7 +144,9 @@ CONFIG_MICROPY_USE_ETHERNET= CONFIG_MICROPY_USE_BLUETOOTH= CONFIG_MICROPY_USE_RFCOMM=y CONFIG_MICROPY_USE_MDNS=y +CONFIG_MICROPY_USE_REQUESTS=y CONFIG_MICROPY_USE_CURL=y +CONFIG_MICROPY_CURL_MAX_WRITE_SIZE=8192 CONFIG_MICROPY_USE_CURL_TLS=y CONFIG_MICROPY_USE_CURLFTP=y CONFIG_MICROPY_USE_SSH=y @@ -254,6 +258,7 @@ CONFIG_BT_STACK_NO_LOG=y CONFIG_BT_ACL_CONNECTIONS=4 CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y +CONFIG_BLE_HOST_QUEUE_CONGESTION_CHECK= CONFIG_BLE_SCAN_DUPLICATE=y CONFIG_DUPLICATE_SCAN_CACHE_SIZE=20 CONFIG_BLE_MESH_SCAN_DUPLICATE_EN= diff --git a/MicroPython_BUILD/updates.txt b/MicroPython_BUILD/updates.txt index b6f9a105..a006eaa6 100644 --- a/MicroPython_BUILD/updates.txt +++ b/MicroPython_BUILD/updates.txt @@ -1,3 +1,38 @@ +=== 2018-06-26 === + +Updated 'ethernet' module + updated all modules using network to work on any network interface, including ethernet + ftpserver and telnet server now also works over ethernet + +Updated 'uos.sdconfig()' + SPI host can be selected if SDCard mode is SPI + +Updated 'Curl' module + added 'getmail' method + added option to set maximum write buffer size, lower size can make it more usable on boards without psRAM + tab character (0x09) is now accepted in response body + +Updated 'machine' module + fixed bug in 'deepsleep' method, deepslep for all timeout values now works as expected + +Updated 'DAC' module + fixed bug in 'waveform' method, the 'duration' argument now works for waveform types + +Updated 'machine.Pin' module + fixed bug in handling the 'debounce' argument + +Added 'requests' module implemented in C, based on 'esp_http_client' componnent + get, post, head, put, patch methods + +Refactored 'display' module + added full support for FTDI EVE chips (FT8xx) + prepared for implementation of e-paper displays support + +Updated sdcard support + +Updated esp-idf to version v3.1-rc1-53509c7b + + === 2018-06-27 === Removed option to run REPL in separate thread diff --git a/MicroPython_BUILD/ver20180628.id b/MicroPython_BUILD/ver20180827.id similarity index 100% rename from MicroPython_BUILD/ver20180628.id rename to MicroPython_BUILD/ver20180827.id diff --git a/Tools/esp-idf.tar.xz b/Tools/esp-idf.tar.xz index 9f28507f..0b610024 100644 Binary files a/Tools/esp-idf.tar.xz and b/Tools/esp-idf.tar.xz differ diff --git a/Tools/esp-idf_github.sha b/Tools/esp-idf_github.sha index 8f57e2cf..6e851ff9 100644 --- a/Tools/esp-idf_github.sha +++ b/Tools/esp-idf_github.sha @@ -1 +1 @@ -139d49894c473bd34ab6e9515e85d3f6871a30c7 +53509c7bfde505b6d0aa5ce0cd1ac48bc3743039