36#include "esp_vfs_fat.h"
37#include "esp_task_wdt.h"
38#include "driver/sdspi_host.h"
40#include "esp_spiffs.h"
41#include "soc/efuse_reg.h"
44#include "soc/adc_channel.h"
53#pragma GCC optimize ("O2")
66 : m_start(esp_timer_get_time())
71bool TimeOut::expired(
int valueMS)
73 return valueMS > -1 && ((esp_timer_get_time() - m_start) / 1000) > valueMS;
86 int squaredbit = 0x40000000;
89 while (squaredbit > 0) {
90 if (remainder >= (squaredbit | root)) {
91 remainder -= (squaredbit | root);
106bool calcParity(uint8_t v)
110 return (0x6996 >> v) & 1;
119void * realloc32(
void * ptr,
size_t size)
121 uint32_t * newBuffer = (uint32_t*) heap_caps_malloc(size, MALLOC_CAP_32BIT);
123 moveItems(newBuffer, (uint32_t*)ptr, size /
sizeof(uint32_t));
130void free32(
void * ptr)
140uint32_t msToTicks(
int ms)
142 return ms < 0 ? portMAX_DELAY : pdMS_TO_TICKS(ms);
152 uint32_t ver_pkg = (REG_READ(EFUSE_BLK0_RDATA3_REG) >> 9) & 7;
155 return ChipPackage::ESP32D0WDQ6;
157 return ChipPackage::ESP32D0WDQ5;
159 return ChipPackage::ESP32D2WDQ5;
161 return ChipPackage::ESP32PICOD4;
163 return ChipPackage::Unknown;
169adc1_channel_t ADC1_GPIO2Channel(gpio_num_t gpio)
172 case ADC1_CHANNEL_0_GPIO_NUM:
173 return ADC1_CHANNEL_0;
174 case ADC1_CHANNEL_1_GPIO_NUM:
175 return ADC1_CHANNEL_1;
176 case ADC1_CHANNEL_2_GPIO_NUM:
177 return ADC1_CHANNEL_2;
178 case ADC1_CHANNEL_3_GPIO_NUM:
179 return ADC1_CHANNEL_3;
180 case ADC1_CHANNEL_4_GPIO_NUM:
181 return ADC1_CHANNEL_4;
182 case ADC1_CHANNEL_5_GPIO_NUM:
183 return ADC1_CHANNEL_5;
184 case ADC1_CHANNEL_6_GPIO_NUM:
185 return ADC1_CHANNEL_6;
186 case ADC1_CHANNEL_7_GPIO_NUM:
187 return ADC1_CHANNEL_7;
189 return ADC1_CHANNEL_0;
196void configureGPIO(gpio_num_t gpio, gpio_mode_t mode)
198 PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
199 gpio_set_direction(gpio, mode);
205uint32_t getApbFrequency()
207 rtc_cpu_freq_config_t conf;
208 rtc_clk_cpu_freq_get_config(&conf);
209 return conf.freq_mhz >= 80 ? 80000000 : (conf.source_freq_mhz * 80000000 / conf.div);
215uint32_t getCPUFrequencyMHz()
217 rtc_cpu_freq_config_t conf;
218 rtc_clk_cpu_freq_get_config(&conf);
219 return conf.freq_mhz;
226struct esp_intr_alloc_args {
229 intr_handler_t handler;
231 intr_handle_t * ret_handle;
232 TaskHandle_t waitingTask;
236void esp_intr_alloc_pinnedToCore_call(
void * arg)
238 auto args = (esp_intr_alloc_args*) arg;
239 esp_intr_alloc(args->source, args->flags, args->handler, args->arg, args->ret_handle);
243void esp_intr_alloc_pinnedToCore(
int source,
int flags, intr_handler_t handler,
void * arg, intr_handle_t * ret_handle,
int core)
245 esp_intr_alloc_args args = { source, flags, handler, arg, ret_handle, xTaskGetCurrentTaskHandle() };
246 esp_ipc_call_blocking(core, esp_intr_alloc_pinnedToCore_call, &args);
254void replacePathSep(
char * path,
char newSep)
256 for (; *path; ++path)
257 if (*path ==
'\\' || *path ==
'/')
266static int clipLine_code(
int x,
int y, Rect
const & clipRect)
271 else if (x > clipRect.X2)
275 else if (y > clipRect.Y2)
282bool clipLine(
int & x1,
int & y1,
int & x2,
int & y2, Rect
const & clipRect,
bool checkOnly)
288 int topLeftCode = clipLine_code(newX1, newY1, clipRect);
289 int bottomRightCode = clipLine_code(newX2, newY2, clipRect);
291 if ((topLeftCode == 0) && (bottomRightCode == 0)) {
299 }
else if (topLeftCode & bottomRightCode) {
303 int ncode = topLeftCode != 0 ? topLeftCode : bottomRightCode;
305 x = newX1 + (newX2 - newX1) * (clipRect.Y2 - newY1) / (newY2 - newY1);
307 }
else if (ncode & 4) {
308 x = newX1 + (newX2 - newX1) * (clipRect.Y1 - newY1) / (newY2 - newY1);
310 }
else if (ncode & 2) {
311 y = newY1 + (newY2 - newY1) * (clipRect.X2 - newX1) / (newX2 - newX1);
313 }
else if (ncode & 1) {
314 y = newY1 + (newY2 - newY1) * (clipRect.X1 - newX1) / (newX2 - newX1);
317 if (ncode == topLeftCode) {
320 topLeftCode = clipLine_code(newX1, newY1, clipRect);
324 bottomRightCode = clipLine_code(newX2, newY2, clipRect);
336void removeRectangle(Stack<Rect> & rects, Rect
const & mainRect, Rect
const & rectToRemove)
338 if (!mainRect.intersects(rectToRemove) || rectToRemove.contains(mainRect))
342 if (mainRect.Y1 < rectToRemove.Y1)
343 rects.push(Rect(mainRect.X1, mainRect.Y1, mainRect.X2, rectToRemove.Y1 - 1));
346 if (mainRect.Y2 > rectToRemove.Y2)
347 rects.push(Rect(mainRect.X1, rectToRemove.Y2 + 1, mainRect.X2, mainRect.Y2));
350 if (mainRect.X1 < rectToRemove.X1)
351 rects.push(Rect(mainRect.X1, tmax(rectToRemove.Y1, mainRect.Y1), rectToRemove.X1 - 1, tmin(rectToRemove.Y2, mainRect.Y2)));
354 if (mainRect.X2 > rectToRemove.X2)
355 rects.push(Rect(rectToRemove.X2 + 1, tmax(rectToRemove.Y1, mainRect.Y1), mainRect.X2, tmin(rectToRemove.Y2, mainRect.Y2)));
362Rect IRAM_ATTR Rect::merge(Rect
const & rect)
const
364 return Rect(imin(rect.X1,
X1), imin(rect.Y1,
Y1), imax(rect.X2,
X2), imax(rect.Y2,
Y2));
368Rect IRAM_ATTR Rect::intersection(Rect
const & rect)
const
370 return Rect(tmax(
X1, rect.X1), tmax(
Y1, rect.Y1), tmin(
X2, rect.X2), tmin(
Y2, rect.Y2));
377void rgb222_to_hsv(
int R,
int G,
int B,
double * h,
double * s,
double * v)
382 double cmax = tmax<double>(tmax<double>(r, g), b);
383 double cmin = tmin<double>(tmin<double>(r, g), b);
384 double diff = cmax - cmin;
388 *h = fmod((60.0 * ((g - b) / diff) + 360.0), 360.0);
390 *h = fmod((60.0 * ((b - r) / diff) + 120.0), 360.0);
392 *h = fmod((60.0 * ((r - g) / diff) + 240.0), 360.0);
393 *s = cmax == 0 ? 0 : (diff / cmax) * 100.0;
403StringList::StringList()
413StringList::~StringList()
419void StringList::clear()
422 for (
int i = 0; i < m_count; ++i)
423 free((
void*) m_items[i]);
429 m_count = m_allocated = 0;
433void StringList::copyFrom(StringList
const & src)
436 m_count = src.m_count;
437 checkAllocatedSpace(m_count);
438 for (
int i = 0; i < m_count; ++i) {
439 m_items[i] =
nullptr;
440 set(i, src.m_items[i]);
446void StringList::copySelectionMapFrom(StringList
const & src)
448 int maskLen = (31 + m_allocated) / 32;
449 for (
int i = 0; i < maskLen; ++i)
450 m_selMap[i] = src.m_selMap[i];
454void StringList::checkAllocatedSpace(
int requiredItems)
456 if (m_allocated < requiredItems) {
457 if (m_allocated == 0) {
459 m_allocated = requiredItems;
462 while (m_allocated < requiredItems)
465 m_items = (
char const**) realloc32(m_items, m_allocated *
sizeof(
char const *));
466 m_selMap = (uint32_t*) realloc32(m_selMap, (31 + m_allocated) / 32 *
sizeof(uint32_t));
471void StringList::insert(
int index,
char const * str)
474 checkAllocatedSpace(m_count);
475 moveItems(m_items + index + 1, m_items + index, m_count - index - 1);
476 m_items[index] =
nullptr;
482int StringList::append(
char const * str)
484 insert(m_count, str);
489int StringList::appendFmt(
const char *format, ...)
493 va_start(ap, format);
494 int size = vsnprintf(
nullptr, 0, format, ap) + 1;
497 va_start(ap, format);
499 vsnprintf(buf, size, format, ap);
500 insert(m_count, buf);
507void StringList::append(
char const * strlist[],
int count)
509 for (
int i = 0; i < count; ++i)
510 insert(m_count, strlist[i]);
515void StringList::appendSepList(
char const * strlist,
char separator)
519 char const * start = strlist;
521 auto end = strchr(start, separator);
523 end = strchr(start, 0);
524 int len = end - start;
526 memcpy(str, start, len);
528 insert(m_count, str);
529 start += len + (*end == 0 ? 0 : 1);
535void StringList::set(
int index,
char const * str)
538 free((
void*)m_items[index]);
539 m_items[index] = (
char const*) malloc(strlen(str) + 1);
540 strcpy((
char*)m_items[index], str);
542 m_items[index] = str;
547void StringList::remove(
int index)
550 free((
void*)m_items[index]);
551 moveItems(m_items + index, m_items + index + 1, m_count - index - 1);
557void StringList::takeStrings()
562 for (
int i = 0; i < m_count; ++i) {
563 char const * str = m_items[i];
564 m_items[i] =
nullptr;
571void StringList::deselectAll()
573 for (
int i = 0; i < (31 + m_count) / 32; ++i)
578bool StringList::selected(
int index)
580 return m_selMap[index / 32] & (1 << (index % 32));
585int StringList::getFirstSelected()
587 for (
int i = 0; i < m_count; ++i)
594void StringList::select(
int index,
bool value)
597 m_selMap[index / 32] |= 1 << (index % 32);
599 m_selMap[index / 32] &= ~(1 << (index % 32));
613char const * FileBrowser::s_SPIFFSMountPath;
614bool FileBrowser::s_SPIFFSMounted =
false;
615size_t FileBrowser::s_SPIFFSMaxFiles;
617char const * FileBrowser::s_SDCardMountPath;
618bool FileBrowser::s_SDCardMounted =
false;
619size_t FileBrowser::s_SDCardMaxFiles;
620int FileBrowser::s_SDCardAllocationUnitSize;
621int8_t FileBrowser::s_SDCardMISO;
622int8_t FileBrowser::s_SDCardMOSI;
623int8_t FileBrowser::s_SDCardCLK;
624int8_t FileBrowser::s_SDCardCS;
625sdmmc_card_t * FileBrowser::s_SDCard =
nullptr;
629FileBrowser::FileBrowser()
634 m_includeHiddenFiles(false),
635 m_namesStorage(nullptr)
640FileBrowser::FileBrowser(
char const * path)
647FileBrowser::~FileBrowser()
656void FileBrowser::clear()
661 free(m_namesStorage);
662 m_namesStorage =
nullptr;
669bool FileBrowser::setDirectory(
const char * path)
671 if (m_dir ==
nullptr || strcmp(path, m_dir) != 0) {
673 m_dir = strdup(path);
682void FileBrowser::changeDirectory(
const char * subdir)
684 if (!m_dir || strlen(subdir) == 0)
686 if (strcmp(subdir,
"..") == 0) {
688 auto lastSlash = strrchr(m_dir,
'/');
690 if (lastSlash != m_dir)
698 auto oldLen = strcmp(m_dir,
"/") == 0 ? 0 : strlen(m_dir);
699 char * newDir = (
char*) malloc(oldLen + 1 + strlen(subdir) + 1);
700 strcpy(newDir, m_dir);
701 newDir[oldLen] =
'/';
702 strcpy(newDir + oldLen + 1, subdir);
710int FileBrowser::countDirEntries(
int * namesLength)
713 if (strcmp(m_dir,
"/") == 0) {
725 auto dirp = opendir(m_dir);
727 auto dp = readdir(dirp);
730 if (strcmp(
".", dp->d_name) && strcmp(
"..", dp->d_name) && dp->d_type != DT_UNKNOWN) {
731 *namesLength += strlen(dp->d_name) + 1;
745bool FileBrowser::exists(
char const * name,
bool caseSensitive)
748 for (
int i = 0; i < m_count; ++i)
749 if (strcmp(name, m_items[i].name) == 0)
752 for (
int i = 0; i < m_count; ++i)
753 if (strcasecmp(name, m_items[i].name) == 0)
760bool FileBrowser::filePathExists(
char const * filepath)
762 auto f = openFile(filepath,
"rb");
769size_t FileBrowser::fileSize(
char const * name)
772 char fullpath[strlen(m_dir) + 1 + strlen(name) + 1];
773 sprintf(fullpath,
"%s/%s", m_dir, name);
774 auto fr = fopen(fullpath,
"rb");
776 fseek(fr, 0, SEEK_END);
784bool FileBrowser::fileCreationDate(
char const * name,
int * year,
int * month,
int * day,
int * hour,
int * minutes,
int * seconds)
786 char fullpath[strlen(m_dir) + 1 + strlen(name) + 1];
787 sprintf(fullpath,
"%s/%s", m_dir, name);
789 if (stat(fullpath, &s))
791 auto tm = *localtime((time_t*)&s.st_ctime);
792 *year = 1900 + tm.tm_year;
793 *month = 1 + tm.tm_mon;
796 *minutes = tm.tm_min;
797 *seconds = imin(tm.tm_sec, 59);
802bool FileBrowser::fileUpdateDate(
char const * name,
int * year,
int * month,
int * day,
int * hour,
int * minutes,
int * seconds)
804 char fullpath[strlen(m_dir) + 1 + strlen(name) + 1];
805 sprintf(fullpath,
"%s/%s", m_dir, name);
807 if (stat(fullpath, &s))
809 auto tm = *localtime((time_t*)&s.st_mtime);
810 *year = 1900 + tm.tm_year;
811 *month = 1 + tm.tm_mon;
814 *minutes = tm.tm_min;
815 *seconds = imin(tm.tm_sec, 59);
820bool FileBrowser::fileAccessDate(
char const * name,
int * year,
int * month,
int * day,
int * hour,
int * minutes,
int * seconds)
822 char fullpath[strlen(m_dir) + 1 + strlen(name) + 1];
823 sprintf(fullpath,
"%s/%s", m_dir, name);
825 if (stat(fullpath, &s))
827 auto tm = *localtime((time_t*)&s.st_atime);
828 *year = 1900 + tm.tm_year;
829 *month = 1 + tm.tm_mon;
832 *minutes = tm.tm_min;
833 *seconds = imin(tm.tm_sec, 59);
839int DirComp(
const void * i1,
const void * i2)
844 return d1->
isDir ? -1 : +1;
850bool FileBrowser::reload()
856 int c = countDirEntries(&namesAlloc);
858 m_namesStorage = (
char*) malloc(namesAlloc);
859 char * sname = m_namesStorage;
861 if (strcmp(m_dir,
"/") == 0) {
864 if (s_SPIFFSMounted) {
865 m_items[m_count].name = s_SPIFFSMountPath + 1;
866 m_items[m_count].isDir =
true;
869 if (s_SDCardMounted) {
870 m_items[m_count].name = s_SDCardMountPath + 1;
871 m_items[m_count].isDir =
true;
878 m_items[0].name =
"..";
879 m_items[0].isDir =
true;
882 int hiddenFilesCount = 0;
883 auto dirp = opendir(m_dir);
885 auto dp = readdir(dirp);
888 if (strcmp(
".", dp->d_name) && strcmp(
"..", dp->d_name) && dp->d_type != DT_UNKNOWN) {
889 DirItem * di = m_items + m_count;
891 auto slashPos = strchr(dp->d_name,
'/');
894 auto len = slashPos - dp->d_name;
895 strncpy(sname, dp->d_name, len);
897 if (!exists(sname)) {
904 bool isHidden = dp->d_name[0] ==
'.';
905 if (!isHidden || m_includeHiddenFiles) {
906 strcpy(sname, dp->d_name);
908 di->
isDir = (dp->d_type == DT_DIR);
909 sname += strlen(sname) + 1;
923 if (m_count == 1 && hiddenFilesCount == 0 && getDriveType(m_dir) == DriveType::SPIFFS)
929 qsort(m_items, m_count,
sizeof(
DirItem), DirComp);
937void FileBrowser::makeDirectory(
char const * dirname)
939 int dirnameLen = strlen(dirname);
940 if (dirnameLen > 0) {
941 if (getCurrentDriveType() == DriveType::SPIFFS) {
943 char fullpath[strlen(m_dir) + 3 + 2 * dirnameLen + 1];
946 auto next = name + 1;
947 while (*next && *next !=
'\\' && *next !=
'/')
949 strcpy(fullpath, m_dir);
950 if (dirname != name) {
951 strcat(fullpath,
"/");
952 strncat(fullpath, dirname, name - dirname - 1);
954 strcat(fullpath,
"/");
955 strncat(fullpath, name, next - name);
956 strcat(fullpath,
"/.");
957 strncat(fullpath, name, next - name);
958 replacePathSep(fullpath,
'/');
959 FILE * f = fopen(fullpath,
"wb");
967 char fullpath[strlen(m_dir) + 1 + dirnameLen + 1];
968 sprintf(fullpath,
"%s/%s", m_dir, dirname);
969 replacePathSep(fullpath,
'/');
970 mkdir(fullpath, ACCESSPERMS);
979void FileBrowser::remove(
char const * name)
981 char fullpath[strlen(m_dir) + 1 + strlen(name) + 1];
982 sprintf(fullpath,
"%s/%s", m_dir, name);
983 int r = unlink(fullpath);
992 if (getCurrentDriveType() == DriveType::SPIFFS) {
995 char hidpath[strlen(m_dir) + 3 + 2 * strlen(name) + 1];
996 sprintf(hidpath,
"%s/%s/.%s", m_dir, name, name);
999 auto dirp = opendir(fullpath);
1001 auto dp = readdir(dirp);
1004 if (strcmp(
".", dp->d_name) && strcmp(
"..", dp->d_name) && dp->d_type != DT_UNKNOWN) {
1005 char sfullpath[strlen(fullpath) + 1 + strlen(dp->d_name) + 1];
1006 sprintf(sfullpath,
"%s/%s", fullpath, dp->d_name);
1017void FileBrowser::rename(
char const * oldName,
char const * newName)
1019 char oldfullpath[strlen(m_dir) + 1 + strlen(oldName) + 1];
1020 sprintf(oldfullpath,
"%s/%s", m_dir, oldName);
1022 char newfullpath[strlen(m_dir) + 1 + strlen(newName) + 1];
1023 sprintf(newfullpath,
"%s/%s", m_dir, newName);
1025 ::rename(oldfullpath, newfullpath);
1030char * FileBrowser::createTempFilename()
1032 constexpr int FLEN = 6;
1033 auto ret = (
char*) malloc(strlen(m_dir) + 1 + FLEN + 4 + 1);
1035 char name[FLEN + 1] = { 0 };
1036 for (
int i = 0; i < FLEN; ++i)
1037 name[i] = 65 + (rand() % 26);
1038 sprintf(ret,
"%s/%s.TMP", m_dir, name);
1039 if (!exists(name,
false))
1045bool FileBrowser::truncate(
char const * name,
size_t size)
1047 constexpr size_t BUFLEN = 512;
1049 char fullpath[strlen(m_dir) + 1 + strlen(name) + 1];
1050 sprintf(fullpath,
"%s/%s", m_dir, name);
1055 bool retval =
false;
1058 char * tempFilename = createTempFilename();
1059 if (::rename(fullpath, tempFilename) == 0) {
1060 void * buf = malloc(BUFLEN);
1062 auto fr = fopen(tempFilename,
"rb");
1064 auto fw = fopen(fullpath,
"wb");
1068 auto l = fread(buf, 1, tmin(size, BUFLEN), fr);
1071 fwrite(buf, 1, l, fw);
1076 for (; size > 0; --size)
1086 unlink(tempFilename);
1095int FileBrowser::getFullPath(
char const * name,
char * outPath,
int maxlen)
1097 return (outPath ? snprintf(outPath, maxlen,
"%s/%s", m_dir, name) : snprintf(
nullptr, 0,
"%s/%s", m_dir, name)) + 1;
1101FILE * FileBrowser::openFile(
char const * filename,
char const * mode)
1103 char fullpath[strlen(m_dir) + 1 + strlen(filename) + 1];
1104 strcpy(fullpath, m_dir);
1105 strcat(fullpath,
"/");
1106 strcat(fullpath, filename);
1108 replacePathSep(fullpath,
'/');
1110 return fopen(fullpath, mode);
1116 return getDriveType(m_dir);
1122 if (strncmp(path,
"/spiffs", 7) == 0 || (s_SPIFFSMounted && strncmp(path, s_SPIFFSMountPath, strlen(s_SPIFFSMountPath)) == 0)) {
1123 return DriveType::SPIFFS;
1124 }
else if (s_SDCardMounted && strncmp(path, s_SDCardMountPath, strlen(s_SDCardMountPath)) == 0) {
1125 return DriveType::SDCard;
1127 return DriveType::None;
1134 esp_task_wdt_init(45,
false);
1136 if (driveType == DriveType::SDCard && s_SDCardMounted) {
1139 char drv[3] = {(char)(
'0' + drive),
':', 0};
1142 void * buffer = malloc(FF_MAX_SS);
1147 DWORD plist[] = { 100, 0, 0, 0 };
1148 if (f_fdisk(drive, plist, buffer) != FR_OK) {
1154 if (f_mkfs(drv, FM_ANY, 16 * 1024, buffer, FF_MAX_SS) != FR_OK) {
1165 }
else if (driveType == DriveType::SPIFFS && s_SPIFFSMounted) {
1168 bool r = (esp_spiffs_format(
nullptr) == ESP_OK);
1179bool FileBrowser::mountSDCard(
bool formatOnFail,
char const * mountPath,
size_t maxFiles,
int allocationUnitSize,
int MISO,
int MOSI,
int CLK,
int CS)
1181 switch (getChipPackage()) {
1182 case ChipPackage::ESP32PICOD4:
1186 case ChipPackage::ESP32D0WDQ5:
1194 s_SDCardMountPath = mountPath;
1195 s_SDCardMaxFiles = maxFiles;
1196 s_SDCardAllocationUnitSize = allocationUnitSize;
1197 s_SDCardMISO = MISO;
1198 s_SDCardMOSI = MOSI;
1201 s_SDCardMounted =
false;
1203 sdmmc_host_t host = SDSPI_HOST_DEFAULT();
1204 host.slot = HSPI_HOST;
1206 #if FABGL_ESP_IDF_VERSION <= FABGL_ESP_IDF_VERSION_VAL(3, 3, 5)
1208 sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT();
1209 slot_config.gpio_miso = int2gpio(MISO);
1210 slot_config.gpio_mosi = int2gpio(MOSI);
1211 slot_config.gpio_sck = int2gpio(CLK);
1212 slot_config.gpio_cs = int2gpio(CS);
1214 esp_vfs_fat_sdmmc_mount_config_t mount_config;
1215 mount_config.format_if_mount_failed = formatOnFail;
1216 mount_config.max_files = maxFiles;
1217 mount_config.allocation_unit_size = allocationUnitSize;
1219 s_SDCardMounted = (esp_vfs_fat_sdmmc_mount(mountPath, &host, &slot_config, &mount_config, &s_SDCard) == ESP_OK);
1225 host.max_freq_khz = 19000;
1227 spi_bus_config_t bus_cfg = {
1228 .mosi_io_num = int2gpio(MOSI),
1229 .miso_io_num = int2gpio(MISO),
1230 .sclk_io_num = int2gpio(CLK),
1231 .quadwp_io_num = -1,
1232 .quadhd_io_num = -1,
1233 .max_transfer_sz = 4000,
1235 auto r = spi_bus_initialize((spi_host_device_t)host.slot, &bus_cfg, 2);
1237 if (r == ESP_OK || r == ESP_ERR_INVALID_STATE) {
1238 sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
1239 slot_config.gpio_cs = int2gpio(CS);
1240 slot_config.host_id = (spi_host_device_t) host.slot;
1242 esp_vfs_fat_sdmmc_mount_config_t mount_config;
1243 mount_config.format_if_mount_failed = formatOnFail;
1244 mount_config.max_files = maxFiles;
1245 mount_config.allocation_unit_size = allocationUnitSize;
1247 r = esp_vfs_fat_sdspi_mount(mountPath, &host, &slot_config, &mount_config, &s_SDCard);
1249 s_SDCardMounted = (r == ESP_OK);
1254 return s_SDCardMounted;
1258void FileBrowser::unmountSDCard()
1260 if (s_SDCardMounted) {
1261 #if FABGL_ESP_IDF_VERSION <= FABGL_ESP_IDF_VERSION_VAL(3, 3, 5)
1262 esp_vfs_fat_sdmmc_unmount();
1264 esp_vfs_fat_sdcard_unmount(s_SDCardMountPath, s_SDCard);
1266 s_SDCardMounted =
false;
1271bool FileBrowser::remountSDCard()
1274 return mountSDCard(
false, s_SDCardMountPath, s_SDCardMaxFiles, s_SDCardAllocationUnitSize, s_SDCardMISO, s_SDCardMOSI, s_SDCardCLK, s_SDCardCS);
1278bool FileBrowser::mountSPIFFS(
bool formatOnFail,
char const * mountPath,
size_t maxFiles)
1280 s_SPIFFSMountPath = mountPath;
1281 s_SPIFFSMaxFiles = maxFiles;
1282 esp_vfs_spiffs_conf_t conf = {
1283 .base_path = mountPath,
1284 .partition_label =
nullptr,
1285 .max_files = maxFiles,
1286 .format_if_mount_failed =
true
1288 s_SPIFFSMounted = (esp_vfs_spiffs_register(&conf) == ESP_OK);
1289 return s_SPIFFSMounted;
1293void FileBrowser::unmountSPIFFS()
1295 if (s_SPIFFSMounted) {
1296 esp_vfs_spiffs_unregister(
nullptr);
1297 s_SPIFFSMounted =
false;
1302bool FileBrowser::remountSPIFFS()
1305 return mountSPIFFS(
false, s_SPIFFSMountPath, s_SPIFFSMaxFiles);
1309bool FileBrowser::getFSInfo(
DriveType driveType,
int drive, int64_t * total, int64_t * used)
1313 if (driveType == DriveType::SDCard) {
1316 DWORD free_clusters;
1317 char drv[3] = {(char)(
'0' + drive),
':', 0};
1318 if (f_getfree(drv, &free_clusters, &fs) != FR_OK)
1320 int64_t total_sectors = (fs->n_fatent - 2) * fs->csize;
1321 int64_t free_sectors = free_clusters * fs->csize;
1322 *total = total_sectors * fs->ssize;
1323 *used = *total - free_sectors * fs->ssize;
1327 }
else if (driveType == DriveType::SPIFFS) {
1329 size_t stotal = 0, sused = 0;
1330 if (esp_spiffs_info(NULL, &stotal, &sused) != ESP_OK)
1351void LightMemoryPool::mark(
int pos, int16_t size,
bool allocated)
1353 m_mem[pos] = size & 0xff;
1354 m_mem[pos + 1] = ((size >> 8) & 0x7f) | (allocated ? 0x80 : 0);
1358int16_t LightMemoryPool::getSize(
int pos)
1360 return m_mem[pos] | ((m_mem[pos + 1] & 0x7f) << 8);
1364bool LightMemoryPool::isFree(
int pos)
1366 return (m_mem[pos + 1] & 0x80) == 0;
1370LightMemoryPool::LightMemoryPool(
int poolSize)
1372 m_poolSize = poolSize + 2;
1373 m_mem = (uint8_t*) heap_caps_malloc(m_poolSize, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
1374 mark(0, m_poolSize - 2,
false);
1378LightMemoryPool::~LightMemoryPool()
1380 heap_caps_free(m_mem);
1384void * LightMemoryPool::alloc(
int size)
1386 for (
int pos = 0; pos < m_poolSize; ) {
1387 int16_t blockSize = getSize(pos);
1389 if (blockSize == size) {
1391 mark(pos, size,
true);
1392 return m_mem + pos + 2;
1393 }
else if (blockSize > size) {
1395 int remainingSize = blockSize - size - 2;
1396 if (remainingSize > 0)
1397 mark(pos + 2 + size, remainingSize,
false);
1400 mark(pos, size,
true);
1401 return m_mem + pos + 2;
1405 int nextBlockPos = pos + 2 + blockSize;
1406 if (nextBlockPos < m_poolSize && isFree(nextBlockPos)) {
1408 mark(pos, blockSize + getSize(nextBlockPos) + 2,
false);
1411 pos += blockSize + 2;
1416 pos += blockSize + 2;
1423bool LightMemoryPool::memCheck()
1426 while (pos < m_poolSize) {
1427 int16_t blockSize = getSize(pos);
1428 pos += blockSize + 2;
1430 return pos == m_poolSize;
1434int LightMemoryPool::totFree()
1437 for (
int pos = 0; pos < m_poolSize; ) {
1438 int16_t blockSize = getSize(pos);
1441 pos += blockSize + 2;
1447int LightMemoryPool::totAllocated()
1450 for (
int pos = 0; pos < m_poolSize; ) {
1451 int16_t blockSize = getSize(pos);
1454 pos += blockSize + 2;
1460int LightMemoryPool::largestFree()
1463 for (
int pos = 0; pos < m_poolSize; ) {
1464 int16_t blockSize = getSize(pos);
1465 if (isFree(pos) && blockSize > r)
1467 pos += blockSize + 2;
1497#if FABGLIB_USE_APLL_AB_COEF
1498void floatToFraction(
double value,
int maxDen,
int * num,
int * den)
1500 int64_t a, h[3] = { 0, 1, 0 }, k[3] = { 1, 0, 0 };
1501 int64_t x, d, n = 1;
1502 while (value != floor(value)) {
1507 for (
int i = 0; i < 64; ++i) {
1515 if (k[1] * a + k[0] >= maxDen) {
1516 x = (maxDen - k[0]) / k[1];
1517 if (x * 2 >= a || k[1] >= maxDen)
1522 h[2] = x * h[1] + h[0];
1525 k[2] = x * k[1] + k[0];
1643void APLLCalcParams(
double freq, APLLParams * params, uint8_t * a, uint8_t * b,
double * out_freq,
double * error)
1649 double apll_freq = freq * 2;
1651 for (
int o_div = 0; o_div <= 31; ++o_div) {
1653 int idivisor = (2 * o_div + 4);
1655 for (
int sdm2 = 4; sdm2 <= 8; ++sdm2) {
1658 int minSDM1 = (sdm2 == 4 ? 192 : 0);
1659 int maxSDM1 = (sdm2 == 8 ? 128 : 255);
1661 int startSDM1 = ((apll_freq * idivisor - FXTAL * 4.0 - FXTAL * sdm2) * 256.0 / FXTAL);
1662#if FABGLIB_USE_APLL_AB_COEF
1663 for (
int isdm1 = tmax(minSDM1, startSDM1); isdm1 <= maxSDM1; ++isdm1) {
1665 int isdm1 = startSDM1; {
1669 sdm1 = tmax(minSDM1, sdm1);
1670 sdm1 = tmin(maxSDM1, sdm1);
1673 int sdm0 = ((apll_freq * idivisor - FXTAL * 4.0 - FXTAL * sdm2 - FXTAL * sdm1 / 256.0) * 65536.0 / FXTAL);
1675 sdm0 = (sdm2 == 8 && sdm1 == 128 ? 0 : tmin(255, sdm0));
1676 sdm0 = tmax(0, sdm0);
1679 double dividend = FXTAL * (4.0 + sdm2 + sdm1 / 256.0 + sdm0 / 65536.0);
1680 if (dividend >= 350000000 && dividend <= 500000000) {
1682 double oapll_freq = dividend / idivisor;
1688 uint8_t oa = 1, ob = 0;
1689#if FABGLIB_USE_APLL_AB_COEF
1690 double abr = oapll_freq / freq - 2.0;
1691 if (abr > 0 && abr < 1) {
1693 floatToFraction(abr, 63, &num, &den);
1694 ob = tclamp(num, 0, 63);
1695 oa = tclamp(den, 0, 63);
1700 double ofreq = oapll_freq / (2.0 + (double)ob / oa);
1701 double err = freq - ofreq;
1702 if (abs(err) < abs(*error)) {
1703 *params = (APLLParams){(uint8_t)sdm0, (uint8_t)sdm1, (uint8_t)sdm2, (uint8_t)o_div};
#define FABGLIB_VIDEO_CPUINTENSIVE_TASKS_CORE
This file contains some utility classes and functions.
ChipPackage
This enum defines ESP32 module types (packages)
DriveType
This enum defines drive types (SPIFFS or SD Card)
This file contains fabgl::PS2Controller definition.
FileBrowser item specificator.
This file contains fabgl::VGA16Controller definition.
This file contains fabgl::VGA2Controller definition.
This file contains fabgl::VGAController definition.