38#include "esp_vfs_fat.h"
39#include "esp_task_wdt.h"
40#include "driver/sdspi_host.h"
42#include "esp_spiffs.h"
43#include "soc/efuse_reg.h"
46#include "soc/adc_channel.h"
55#pragma GCC optimize ("O2")
68 : m_start(esp_timer_get_time())
73bool TimeOut::expired(
int valueMS)
75 return valueMS > -1 && ((esp_timer_get_time() - m_start) / 1000) > valueMS;
88 int squaredbit = 0x40000000;
91 while (squaredbit > 0) {
92 if (remainder >= (squaredbit | root)) {
93 remainder -= (squaredbit | root);
108bool calcParity(uint8_t v)
112 return (0x6996 >> v) & 1;
121void * realloc32(
void * ptr,
size_t size)
123 uint32_t * newBuffer = (uint32_t*) heap_caps_malloc(size, MALLOC_CAP_32BIT);
125 moveItems(newBuffer, (uint32_t*)ptr, size /
sizeof(uint32_t));
132void free32(
void * ptr)
142uint32_t msToTicks(
int ms)
144 return ms < 0 ? portMAX_DELAY : pdMS_TO_TICKS(ms);
154 uint32_t ver_pkg = (REG_READ(EFUSE_BLK0_RDATA3_REG) >> 9) & 7;
157 return ChipPackage::ESP32D0WDQ6;
159 return ChipPackage::ESP32D0WDQ5;
161 return ChipPackage::ESP32D2WDQ5;
163 return ChipPackage::ESP32PICOD4;
165 return ChipPackage::Unknown;
171adc1_channel_t ADC1_GPIO2Channel(gpio_num_t gpio)
174 case ADC1_CHANNEL_0_GPIO_NUM:
175 return ADC1_CHANNEL_0;
176 case ADC1_CHANNEL_1_GPIO_NUM:
177 return ADC1_CHANNEL_1;
178 case ADC1_CHANNEL_2_GPIO_NUM:
179 return ADC1_CHANNEL_2;
180 case ADC1_CHANNEL_3_GPIO_NUM:
181 return ADC1_CHANNEL_3;
182 case ADC1_CHANNEL_4_GPIO_NUM:
183 return ADC1_CHANNEL_4;
184 case ADC1_CHANNEL_5_GPIO_NUM:
185 return ADC1_CHANNEL_5;
186 case ADC1_CHANNEL_6_GPIO_NUM:
187 return ADC1_CHANNEL_6;
188 case ADC1_CHANNEL_7_GPIO_NUM:
189 return ADC1_CHANNEL_7;
191 return ADC1_CHANNEL_0;
198void configureGPIO(gpio_num_t gpio, gpio_mode_t mode)
200 PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
201 gpio_set_direction(gpio, mode);
207uint32_t getApbFrequency()
209 rtc_cpu_freq_config_t conf;
210 rtc_clk_cpu_freq_get_config(&conf);
211 return conf.freq_mhz >= 80 ? 80000000 : (conf.source_freq_mhz * 80000000 / conf.div);
217uint32_t getCPUFrequencyMHz()
219 rtc_cpu_freq_config_t conf;
220 rtc_clk_cpu_freq_get_config(&conf);
221 return conf.freq_mhz;
228struct esp_intr_alloc_args {
231 intr_handler_t handler;
233 intr_handle_t * ret_handle;
234 TaskHandle_t waitingTask;
238void esp_intr_alloc_pinnedToCore_call(
void * arg)
240 auto args = (esp_intr_alloc_args*) arg;
241 esp_intr_alloc(args->source, args->flags, args->handler, args->arg, args->ret_handle);
245void esp_intr_alloc_pinnedToCore(
int source,
int flags, intr_handler_t handler,
void * arg, intr_handle_t * ret_handle,
int core)
247 esp_intr_alloc_args args = { source, flags, handler, arg, ret_handle, xTaskGetCurrentTaskHandle() };
248 esp_ipc_call_blocking(core, esp_intr_alloc_pinnedToCore_call, &args);
256void replacePathSep(
char * path,
char newSep)
258 for (; *path; ++path)
259 if (*path ==
'\\' || *path ==
'/')
268static int clipLine_code(
int x,
int y, Rect
const & clipRect)
273 else if (x > clipRect.X2)
277 else if (y > clipRect.Y2)
284bool clipLine(
int & x1,
int & y1,
int & x2,
int & y2, Rect
const & clipRect,
bool checkOnly)
290 int topLeftCode = clipLine_code(newX1, newY1, clipRect);
291 int bottomRightCode = clipLine_code(newX2, newY2, clipRect);
293 if ((topLeftCode == 0) && (bottomRightCode == 0)) {
301 }
else if (topLeftCode & bottomRightCode) {
305 int ncode = topLeftCode != 0 ? topLeftCode : bottomRightCode;
307 x = newX1 + (newX2 - newX1) * (clipRect.Y2 - newY1) / (newY2 - newY1);
309 }
else if (ncode & 4) {
310 x = newX1 + (newX2 - newX1) * (clipRect.Y1 - newY1) / (newY2 - newY1);
312 }
else if (ncode & 2) {
313 y = newY1 + (newY2 - newY1) * (clipRect.X2 - newX1) / (newX2 - newX1);
315 }
else if (ncode & 1) {
316 y = newY1 + (newY2 - newY1) * (clipRect.X1 - newX1) / (newX2 - newX1);
319 if (ncode == topLeftCode) {
322 topLeftCode = clipLine_code(newX1, newY1, clipRect);
326 bottomRightCode = clipLine_code(newX2, newY2, clipRect);
338void removeRectangle(Stack<Rect> & rects, Rect
const & mainRect, Rect
const & rectToRemove)
340 if (!mainRect.intersects(rectToRemove) || rectToRemove.contains(mainRect))
344 if (mainRect.Y1 < rectToRemove.Y1)
345 rects.push(Rect(mainRect.X1, mainRect.Y1, mainRect.X2, rectToRemove.Y1 - 1));
348 if (mainRect.Y2 > rectToRemove.Y2)
349 rects.push(Rect(mainRect.X1, rectToRemove.Y2 + 1, mainRect.X2, mainRect.Y2));
352 if (mainRect.X1 < rectToRemove.X1)
353 rects.push(Rect(mainRect.X1, tmax(rectToRemove.Y1, mainRect.Y1), rectToRemove.X1 - 1, tmin(rectToRemove.Y2, mainRect.Y2)));
356 if (mainRect.X2 > rectToRemove.X2)
357 rects.push(Rect(rectToRemove.X2 + 1, tmax(rectToRemove.Y1, mainRect.Y1), mainRect.X2, tmin(rectToRemove.Y2, mainRect.Y2)));
364Rect IRAM_ATTR Rect::merge(Rect
const & rect)
const
366 return Rect(imin(rect.X1,
X1), imin(rect.Y1,
Y1), imax(rect.X2,
X2), imax(rect.Y2,
Y2));
370Rect IRAM_ATTR Rect::intersection(Rect
const & rect)
const
372 return Rect(tmax(
X1, rect.X1), tmax(
Y1, rect.Y1), tmin(
X2, rect.X2), tmin(
Y2, rect.Y2));
379void rgb222_to_hsv(
int R,
int G,
int B,
double * h,
double * s,
double * v)
384 double cmax = tmax<double>(tmax<double>(r, g), b);
385 double cmin = tmin<double>(tmin<double>(r, g), b);
386 double diff = cmax - cmin;
390 *h = fmod((60.0 * ((g - b) / diff) + 360.0), 360.0);
392 *h = fmod((60.0 * ((b - r) / diff) + 120.0), 360.0);
394 *h = fmod((60.0 * ((r - g) / diff) + 240.0), 360.0);
395 *s = cmax == 0 ? 0 : (diff / cmax) * 100.0;
405StringList::StringList()
415StringList::~StringList()
421void StringList::clear()
424 for (
int i = 0; i < m_count; ++i)
425 free((
void*) m_items[i]);
431 m_count = m_allocated = 0;
435void StringList::copyFrom(StringList
const & src)
438 m_count = src.m_count;
439 checkAllocatedSpace(m_count);
440 for (
int i = 0; i < m_count; ++i) {
441 m_items[i] =
nullptr;
442 set(i, src.m_items[i]);
448void StringList::copySelectionMapFrom(StringList
const & src)
450 int maskLen = (31 + m_allocated) / 32;
451 for (
int i = 0; i < maskLen; ++i)
452 m_selMap[i] = src.m_selMap[i];
456void StringList::checkAllocatedSpace(
int requiredItems)
458 if (m_allocated < requiredItems) {
459 if (m_allocated == 0) {
461 m_allocated = requiredItems;
464 while (m_allocated < requiredItems)
467 m_items = (
char const**) realloc32(m_items, m_allocated *
sizeof(
char const *));
468 m_selMap = (uint32_t*) realloc32(m_selMap, (31 + m_allocated) / 32 *
sizeof(uint32_t));
473void StringList::insert(
int index,
char const * str)
476 checkAllocatedSpace(m_count);
477 moveItems(m_items + index + 1, m_items + index, m_count - index - 1);
478 m_items[index] =
nullptr;
484int StringList::append(
char const * str)
486 insert(m_count, str);
491int StringList::appendFmt(
const char *format, ...)
495 va_start(ap, format);
496 int size = vsnprintf(
nullptr, 0, format, ap) + 1;
499 va_start(ap, format);
501 vsnprintf(buf, size, format, ap);
502 insert(m_count, buf);
509void StringList::append(
char const * strlist[],
int count)
511 for (
int i = 0; i < count; ++i)
512 insert(m_count, strlist[i]);
517void StringList::appendSepList(
char const * strlist,
char separator)
521 char const * start = strlist;
523 auto end = strchr(start, separator);
525 end = strchr(start, 0);
526 int len = end - start;
528 memcpy(str, start, len);
530 insert(m_count, str);
531 start += len + (*end == 0 ? 0 : 1);
537void StringList::set(
int index,
char const * str)
540 free((
void*)m_items[index]);
541 m_items[index] = (
char const*) malloc(strlen(str) + 1);
542 strcpy((
char*)m_items[index], str);
544 m_items[index] = str;
549void StringList::remove(
int index)
552 free((
void*)m_items[index]);
553 moveItems(m_items + index, m_items + index + 1, m_count - index - 1);
559void StringList::takeStrings()
564 for (
int i = 0; i < m_count; ++i) {
565 char const * str = m_items[i];
566 m_items[i] =
nullptr;
573void StringList::deselectAll()
575 for (
int i = 0; i < (31 + m_count) / 32; ++i)
580bool StringList::selected(
int index)
582 return m_selMap[index / 32] & (1 << (index % 32));
587int StringList::getFirstSelected()
589 for (
int i = 0; i < m_count; ++i)
596void StringList::select(
int index,
bool value)
599 m_selMap[index / 32] |= 1 << (index % 32);
601 m_selMap[index / 32] &= ~(1 << (index % 32));
615char const * FileBrowser::s_SPIFFSMountPath;
616bool FileBrowser::s_SPIFFSMounted =
false;
617size_t FileBrowser::s_SPIFFSMaxFiles;
619char const * FileBrowser::s_SDCardMountPath;
620bool FileBrowser::s_SDCardMounted =
false;
621size_t FileBrowser::s_SDCardMaxFiles;
622int FileBrowser::s_SDCardAllocationUnitSize;
623int8_t FileBrowser::s_SDCardMISO;
624int8_t FileBrowser::s_SDCardMOSI;
625int8_t FileBrowser::s_SDCardCLK;
626int8_t FileBrowser::s_SDCardCS;
627sdmmc_card_t * FileBrowser::s_SDCard =
nullptr;
631FileBrowser::FileBrowser()
636 m_includeHiddenFiles(false),
637 m_namesStorage(nullptr)
642FileBrowser::FileBrowser(
char const * path)
649FileBrowser::~FileBrowser()
658void FileBrowser::clear()
663 free(m_namesStorage);
664 m_namesStorage =
nullptr;
671bool FileBrowser::setDirectory(
const char * path)
673 if (m_dir ==
nullptr || strcmp(path, m_dir) != 0) {
675 m_dir = strdup(path);
684void FileBrowser::changeDirectory(
const char * subdir)
686 if (!m_dir || strlen(subdir) == 0)
688 if (strcmp(subdir,
"..") == 0) {
690 auto lastSlash = strrchr(m_dir,
'/');
692 if (lastSlash != m_dir)
700 auto oldLen = strcmp(m_dir,
"/") == 0 ? 0 : strlen(m_dir);
701 char * newDir = (
char*) malloc(oldLen + 1 + strlen(subdir) + 1);
702 strcpy(newDir, m_dir);
703 newDir[oldLen] =
'/';
704 strcpy(newDir + oldLen + 1, subdir);
712int FileBrowser::countDirEntries(
int * namesLength)
715 if (strcmp(m_dir,
"/") == 0) {
727 auto dirp = opendir(m_dir);
729 auto dp = readdir(dirp);
732 if (strcmp(
".", dp->d_name) && strcmp(
"..", dp->d_name) && dp->d_type != DT_UNKNOWN) {
733 *namesLength += strlen(dp->d_name) + 1;
747bool FileBrowser::exists(
char const * name,
bool caseSensitive)
750 for (
int i = 0; i < m_count; ++i)
751 if (strcmp(name, m_items[i].name) == 0)
754 for (
int i = 0; i < m_count; ++i)
755 if (strcasecmp(name, m_items[i].name) == 0)
762bool FileBrowser::filePathExists(
char const * filepath)
764 auto f = openFile(filepath,
"rb");
771size_t FileBrowser::fileSize(
char const * name)
774 char fullpath[strlen(m_dir) + 1 + strlen(name) + 1];
775 sprintf(fullpath,
"%s/%s", m_dir, name);
776 auto fr = fopen(fullpath,
"rb");
778 fseek(fr, 0, SEEK_END);
786bool FileBrowser::fileCreationDate(
char const * name,
int * year,
int * month,
int * day,
int * hour,
int * minutes,
int * seconds)
788 char fullpath[strlen(m_dir) + 1 + strlen(name) + 1];
789 sprintf(fullpath,
"%s/%s", m_dir, name);
791 if (stat(fullpath, &s))
793 auto tm = *localtime((time_t*)&s.st_ctime);
794 *year = 1900 + tm.tm_year;
795 *month = 1 + tm.tm_mon;
798 *minutes = tm.tm_min;
799 *seconds = imin(tm.tm_sec, 59);
804bool FileBrowser::fileUpdateDate(
char const * name,
int * year,
int * month,
int * day,
int * hour,
int * minutes,
int * seconds)
806 char fullpath[strlen(m_dir) + 1 + strlen(name) + 1];
807 sprintf(fullpath,
"%s/%s", m_dir, name);
809 if (stat(fullpath, &s))
811 auto tm = *localtime((time_t*)&s.st_mtime);
812 *year = 1900 + tm.tm_year;
813 *month = 1 + tm.tm_mon;
816 *minutes = tm.tm_min;
817 *seconds = imin(tm.tm_sec, 59);
822bool FileBrowser::fileAccessDate(
char const * name,
int * year,
int * month,
int * day,
int * hour,
int * minutes,
int * seconds)
824 char fullpath[strlen(m_dir) + 1 + strlen(name) + 1];
825 sprintf(fullpath,
"%s/%s", m_dir, name);
827 if (stat(fullpath, &s))
829 auto tm = *localtime((time_t*)&s.st_atime);
830 *year = 1900 + tm.tm_year;
831 *month = 1 + tm.tm_mon;
834 *minutes = tm.tm_min;
835 *seconds = imin(tm.tm_sec, 59);
841int DirComp(
const void * i1,
const void * i2)
846 return d1->
isDir ? -1 : +1;
852bool FileBrowser::reload()
858 int c = countDirEntries(&namesAlloc);
860 m_namesStorage = (
char*) malloc(namesAlloc);
861 char * sname = m_namesStorage;
863 if (strcmp(m_dir,
"/") == 0) {
866 if (s_SPIFFSMounted) {
867 m_items[m_count].name = s_SPIFFSMountPath + 1;
868 m_items[m_count].isDir =
true;
871 if (s_SDCardMounted) {
872 m_items[m_count].name = s_SDCardMountPath + 1;
873 m_items[m_count].isDir =
true;
880 m_items[0].name =
"..";
881 m_items[0].isDir =
true;
884 int hiddenFilesCount = 0;
885 auto dirp = opendir(m_dir);
887 auto dp = readdir(dirp);
890 if (strcmp(
".", dp->d_name) && strcmp(
"..", dp->d_name) && dp->d_type != DT_UNKNOWN) {
891 DirItem * di = m_items + m_count;
893 auto slashPos = strchr(dp->d_name,
'/');
896 auto len = slashPos - dp->d_name;
897 strncpy(sname, dp->d_name, len);
899 if (!exists(sname)) {
906 bool isHidden = dp->d_name[0] ==
'.';
907 if (!isHidden || m_includeHiddenFiles) {
908 strcpy(sname, dp->d_name);
910 di->
isDir = (dp->d_type == DT_DIR);
911 sname += strlen(sname) + 1;
925 if (m_count == 1 && hiddenFilesCount == 0 && getDriveType(m_dir) == DriveType::SPIFFS)
931 qsort(m_items, m_count,
sizeof(
DirItem), DirComp);
939void FileBrowser::makeDirectory(
char const * dirname)
941 int dirnameLen = strlen(dirname);
942 if (dirnameLen > 0) {
943 if (getCurrentDriveType() == DriveType::SPIFFS) {
945 char fullpath[strlen(m_dir) + 3 + 2 * dirnameLen + 1];
948 auto next = name + 1;
949 while (*next && *next !=
'\\' && *next !=
'/')
951 strcpy(fullpath, m_dir);
952 if (dirname != name) {
953 strcat(fullpath,
"/");
954 strncat(fullpath, dirname, name - dirname - 1);
956 strcat(fullpath,
"/");
957 strncat(fullpath, name, next - name);
958 strcat(fullpath,
"/.");
959 strncat(fullpath, name, next - name);
960 replacePathSep(fullpath,
'/');
961 FILE * f = fopen(fullpath,
"wb");
969 char fullpath[strlen(m_dir) + 1 + dirnameLen + 1];
970 sprintf(fullpath,
"%s/%s", m_dir, dirname);
971 replacePathSep(fullpath,
'/');
972 mkdir(fullpath, ACCESSPERMS);
981void FileBrowser::remove(
char const * name)
983 char fullpath[strlen(m_dir) + 1 + strlen(name) + 1];
984 sprintf(fullpath,
"%s/%s", m_dir, name);
985 int r = unlink(fullpath);
994 if (getCurrentDriveType() == DriveType::SPIFFS) {
997 char hidpath[strlen(m_dir) + 3 + 2 * strlen(name) + 1];
998 sprintf(hidpath,
"%s/%s/.%s", m_dir, name, name);
1001 auto dirp = opendir(fullpath);
1003 auto dp = readdir(dirp);
1006 if (strcmp(
".", dp->d_name) && strcmp(
"..", dp->d_name) && dp->d_type != DT_UNKNOWN) {
1007 char sfullpath[strlen(fullpath) + 1 + strlen(dp->d_name) + 1];
1008 sprintf(sfullpath,
"%s/%s", fullpath, dp->d_name);
1019void FileBrowser::rename(
char const * oldName,
char const * newName)
1021 char oldfullpath[strlen(m_dir) + 1 + strlen(oldName) + 1];
1022 sprintf(oldfullpath,
"%s/%s", m_dir, oldName);
1024 char newfullpath[strlen(m_dir) + 1 + strlen(newName) + 1];
1025 sprintf(newfullpath,
"%s/%s", m_dir, newName);
1027 ::rename(oldfullpath, newfullpath);
1032char * FileBrowser::createTempFilename()
1034 constexpr int FLEN = 6;
1035 auto ret = (
char*) malloc(strlen(m_dir) + 1 + FLEN + 4 + 1);
1037 char name[FLEN + 1] = { 0 };
1038 for (
int i = 0; i < FLEN; ++i)
1039 name[i] = 65 + (rand() % 26);
1040 sprintf(ret,
"%s/%s.TMP", m_dir, name);
1041 if (!exists(name,
false))
1047bool FileBrowser::truncate(
char const * name,
size_t size)
1049 constexpr size_t BUFLEN = 512;
1051 char fullpath[strlen(m_dir) + 1 + strlen(name) + 1];
1052 sprintf(fullpath,
"%s/%s", m_dir, name);
1057 bool retval =
false;
1060 char * tempFilename = createTempFilename();
1061 if (::rename(fullpath, tempFilename) == 0) {
1062 void * buf = malloc(BUFLEN);
1064 auto fr = fopen(tempFilename,
"rb");
1066 auto fw = fopen(fullpath,
"wb");
1070 auto l = fread(buf, 1, tmin(size, BUFLEN), fr);
1073 fwrite(buf, 1, l, fw);
1078 for (; size > 0; --size)
1088 unlink(tempFilename);
1097int FileBrowser::getFullPath(
char const * name,
char * outPath,
int maxlen)
1099 return (outPath ? snprintf(outPath, maxlen,
"%s/%s", m_dir, name) : snprintf(
nullptr, 0,
"%s/%s", m_dir, name)) + 1;
1103FILE * FileBrowser::openFile(
char const * filename,
char const * mode)
1105 char fullpath[strlen(m_dir) + 1 + strlen(filename) + 1];
1106 strcpy(fullpath, m_dir);
1107 strcat(fullpath,
"/");
1108 strcat(fullpath, filename);
1110 replacePathSep(fullpath,
'/');
1112 return fopen(fullpath, mode);
1118 return getDriveType(m_dir);
1124 if (strncmp(path,
"/spiffs", 7) == 0 || (s_SPIFFSMounted && strncmp(path, s_SPIFFSMountPath, strlen(s_SPIFFSMountPath)) == 0)) {
1125 return DriveType::SPIFFS;
1126 }
else if (s_SDCardMounted && strncmp(path, s_SDCardMountPath, strlen(s_SDCardMountPath)) == 0) {
1127 return DriveType::SDCard;
1129 return DriveType::None;
1136 esp_task_wdt_init(45,
false);
1138 if (driveType == DriveType::SDCard && s_SDCardMounted) {
1141 char drv[3] = {(char)(
'0' + drive),
':', 0};
1144 void * buffer = malloc(FF_MAX_SS);
1149 DWORD plist[] = { 100, 0, 0, 0 };
1150 if (f_fdisk(drive, plist, buffer) != FR_OK) {
1156 if (f_mkfs(drv, FM_ANY, 16 * 1024, buffer, FF_MAX_SS) != FR_OK) {
1167 }
else if (driveType == DriveType::SPIFFS && s_SPIFFSMounted) {
1170 bool r = (esp_spiffs_format(
nullptr) == ESP_OK);
1181bool FileBrowser::mountSDCard(
bool formatOnFail,
char const * mountPath,
size_t maxFiles,
int allocationUnitSize,
int MISO,
int MOSI,
int CLK,
int CS)
1183 switch (getChipPackage()) {
1184 case ChipPackage::ESP32PICOD4:
1188 case ChipPackage::ESP32D0WDQ5:
1196 s_SDCardMountPath = mountPath;
1197 s_SDCardMaxFiles = maxFiles;
1198 s_SDCardAllocationUnitSize = allocationUnitSize;
1199 s_SDCardMISO = MISO;
1200 s_SDCardMOSI = MOSI;
1203 s_SDCardMounted =
false;
1205 sdmmc_host_t host = SDSPI_HOST_DEFAULT();
1206 host.slot = HSPI_HOST;
1208 #if FABGL_ESP_IDF_VERSION <= FABGL_ESP_IDF_VERSION_VAL(3, 3, 5)
1210 sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT();
1211 slot_config.gpio_miso = int2gpio(MISO);
1212 slot_config.gpio_mosi = int2gpio(MOSI);
1213 slot_config.gpio_sck = int2gpio(CLK);
1214 slot_config.gpio_cs = int2gpio(CS);
1216 esp_vfs_fat_sdmmc_mount_config_t mount_config;
1217 mount_config.format_if_mount_failed = formatOnFail;
1218 mount_config.max_files = maxFiles;
1219 mount_config.allocation_unit_size = allocationUnitSize;
1221 s_SDCardMounted = (esp_vfs_fat_sdmmc_mount(mountPath, &host, &slot_config, &mount_config, &s_SDCard) == ESP_OK);
1227 host.max_freq_khz = 19000;
1229 spi_bus_config_t bus_cfg = {
1230 .mosi_io_num = int2gpio(MOSI),
1231 .miso_io_num = int2gpio(MISO),
1232 .sclk_io_num = int2gpio(CLK),
1233 .quadwp_io_num = -1,
1234 .quadhd_io_num = -1,
1235 .max_transfer_sz = 4000,
1237 auto r = spi_bus_initialize((spi_host_device_t)host.slot, &bus_cfg, 2);
1239 if (r == ESP_OK || r == ESP_ERR_INVALID_STATE) {
1240 sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
1241 slot_config.gpio_cs = int2gpio(CS);
1242 slot_config.host_id = (spi_host_device_t) host.slot;
1244 esp_vfs_fat_sdmmc_mount_config_t mount_config;
1245 mount_config.format_if_mount_failed = formatOnFail;
1246 mount_config.max_files = maxFiles;
1247 mount_config.allocation_unit_size = allocationUnitSize;
1249 r = esp_vfs_fat_sdspi_mount(mountPath, &host, &slot_config, &mount_config, &s_SDCard);
1251 s_SDCardMounted = (r == ESP_OK);
1256 return s_SDCardMounted;
1260void FileBrowser::unmountSDCard()
1262 if (s_SDCardMounted) {
1263 #if FABGL_ESP_IDF_VERSION <= FABGL_ESP_IDF_VERSION_VAL(3, 3, 5)
1264 esp_vfs_fat_sdmmc_unmount();
1266 esp_vfs_fat_sdcard_unmount(s_SDCardMountPath, s_SDCard);
1268 s_SDCardMounted =
false;
1273bool FileBrowser::remountSDCard()
1276 return mountSDCard(
false, s_SDCardMountPath, s_SDCardMaxFiles, s_SDCardAllocationUnitSize, s_SDCardMISO, s_SDCardMOSI, s_SDCardCLK, s_SDCardCS);
1280bool FileBrowser::mountSPIFFS(
bool formatOnFail,
char const * mountPath,
size_t maxFiles)
1282 s_SPIFFSMountPath = mountPath;
1283 s_SPIFFSMaxFiles = maxFiles;
1284 esp_vfs_spiffs_conf_t conf = {
1285 .base_path = mountPath,
1286 .partition_label =
nullptr,
1287 .max_files = maxFiles,
1288 .format_if_mount_failed =
true
1290 s_SPIFFSMounted = (esp_vfs_spiffs_register(&conf) == ESP_OK);
1291 return s_SPIFFSMounted;
1295void FileBrowser::unmountSPIFFS()
1297 if (s_SPIFFSMounted) {
1298 esp_vfs_spiffs_unregister(
nullptr);
1299 s_SPIFFSMounted =
false;
1304bool FileBrowser::remountSPIFFS()
1307 return mountSPIFFS(
false, s_SPIFFSMountPath, s_SPIFFSMaxFiles);
1311bool FileBrowser::getFSInfo(
DriveType driveType,
int drive, int64_t * total, int64_t * used)
1315 if (driveType == DriveType::SDCard) {
1318 DWORD free_clusters;
1319 char drv[3] = {(char)(
'0' + drive),
':', 0};
1320 if (f_getfree(drv, &free_clusters, &fs) != FR_OK)
1322 int64_t total_sectors = (fs->n_fatent - 2) * fs->csize;
1323 int64_t free_sectors = free_clusters * fs->csize;
1324 *total = total_sectors * fs->ssize;
1325 *used = *total - free_sectors * fs->ssize;
1329 }
else if (driveType == DriveType::SPIFFS) {
1331 size_t stotal = 0, sused = 0;
1332 if (esp_spiffs_info(NULL, &stotal, &sused) != ESP_OK)
1353void LightMemoryPool::mark(
int pos, int16_t size,
bool allocated)
1355 m_mem[pos] = size & 0xff;
1356 m_mem[pos + 1] = ((size >> 8) & 0x7f) | (allocated ? 0x80 : 0);
1360int16_t LightMemoryPool::getSize(
int pos)
1362 return m_mem[pos] | ((m_mem[pos + 1] & 0x7f) << 8);
1366bool LightMemoryPool::isFree(
int pos)
1368 return (m_mem[pos + 1] & 0x80) == 0;
1372LightMemoryPool::LightMemoryPool(
int poolSize)
1374 m_poolSize = poolSize + 2;
1375 m_mem = (uint8_t*) heap_caps_malloc(m_poolSize, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
1376 mark(0, m_poolSize - 2,
false);
1380LightMemoryPool::~LightMemoryPool()
1382 heap_caps_free(m_mem);
1386void * LightMemoryPool::alloc(
int size)
1388 for (
int pos = 0; pos < m_poolSize; ) {
1389 int16_t blockSize = getSize(pos);
1391 if (blockSize == size) {
1393 mark(pos, size,
true);
1394 return m_mem + pos + 2;
1395 }
else if (blockSize > size) {
1397 int remainingSize = blockSize - size - 2;
1398 if (remainingSize > 0)
1399 mark(pos + 2 + size, remainingSize,
false);
1402 mark(pos, size,
true);
1403 return m_mem + pos + 2;
1407 int nextBlockPos = pos + 2 + blockSize;
1408 if (nextBlockPos < m_poolSize && isFree(nextBlockPos)) {
1410 mark(pos, blockSize + getSize(nextBlockPos) + 2,
false);
1413 pos += blockSize + 2;
1418 pos += blockSize + 2;
1425bool LightMemoryPool::memCheck()
1428 while (pos < m_poolSize) {
1429 int16_t blockSize = getSize(pos);
1430 pos += blockSize + 2;
1432 return pos == m_poolSize;
1436int LightMemoryPool::totFree()
1439 for (
int pos = 0; pos < m_poolSize; ) {
1440 int16_t blockSize = getSize(pos);
1443 pos += blockSize + 2;
1449int LightMemoryPool::totAllocated()
1452 for (
int pos = 0; pos < m_poolSize; ) {
1453 int16_t blockSize = getSize(pos);
1456 pos += blockSize + 2;
1462int LightMemoryPool::largestFree()
1465 for (
int pos = 0; pos < m_poolSize; ) {
1466 int16_t blockSize = getSize(pos);
1467 if (isFree(pos) && blockSize > r)
1469 pos += blockSize + 2;
1496VideoMode CurrentVideoMode::s_videoMode = VideoMode::None;
1511#if FABGLIB_USE_APLL_AB_COEF
1512void floatToFraction(
double value,
int maxDen,
int * num,
int * den)
1514 int64_t a, h[3] = { 0, 1, 0 }, k[3] = { 1, 0, 0 };
1515 int64_t x, d, n = 1;
1516 while (value != floor(value)) {
1521 for (
int i = 0; i < 64; ++i) {
1529 if (k[1] * a + k[0] >= maxDen) {
1530 x = (maxDen - k[0]) / k[1];
1531 if (x * 2 >= a || k[1] >= maxDen)
1536 h[2] = x * h[1] + h[0];
1539 k[2] = x * k[1] + k[0];
1657void APLLCalcParams(
double freq, APLLParams * params, uint8_t * a, uint8_t * b,
double * out_freq,
double * error)
1663 double apll_freq = freq * 2;
1665 for (
int o_div = 0; o_div <= 31; ++o_div) {
1667 int idivisor = (2 * o_div + 4);
1669 for (
int sdm2 = 4; sdm2 <= 8; ++sdm2) {
1672 int minSDM1 = (sdm2 == 4 ? 192 : 0);
1673 int maxSDM1 = (sdm2 == 8 ? 128 : 255);
1675 int startSDM1 = ((apll_freq * idivisor - FXTAL * 4.0 - FXTAL * sdm2) * 256.0 / FXTAL);
1676#if FABGLIB_USE_APLL_AB_COEF
1677 for (
int isdm1 = tmax(minSDM1, startSDM1); isdm1 <= maxSDM1; ++isdm1) {
1679 int isdm1 = startSDM1; {
1683 sdm1 = tmax(minSDM1, sdm1);
1684 sdm1 = tmin(maxSDM1, sdm1);
1687 int sdm0 = ((apll_freq * idivisor - FXTAL * 4.0 - FXTAL * sdm2 - FXTAL * sdm1 / 256.0) * 65536.0 / FXTAL);
1689 sdm0 = (sdm2 == 8 && sdm1 == 128 ? 0 : tmin(255, sdm0));
1690 sdm0 = tmax(0, sdm0);
1693 double dividend = FXTAL * (4.0 + sdm2 + sdm1 / 256.0 + sdm0 / 65536.0);
1694 if (dividend >= 350000000 && dividend <= 500000000) {
1696 double oapll_freq = dividend / idivisor;
1702 uint8_t oa = 1, ob = 0;
1703#if FABGLIB_USE_APLL_AB_COEF
1704 double abr = oapll_freq / freq - 2.0;
1705 if (abr > 0 && abr < 1) {
1707 floatToFraction(abr, 63, &num, &den);
1708 ob = tclamp(num, 0, 63);
1709 oa = tclamp(den, 0, 63);
1714 double ofreq = oapll_freq / (2.0 + (double)ob / oa);
1715 double err = freq - ofreq;
1716 if (abs(err) < abs(*error)) {
1717 *params = (APLLParams){(uint8_t)sdm0, (uint8_t)sdm1, (uint8_t)sdm2, (uint8_t)o_div};
1739int calcI2STimingParams(
int sampleRate,
int * outA,
int * outB,
int * outN,
int * outM)
1743 double N = (double)APB_CLK_FREQ / sampleRate;
1746 N = (double)APB_CLK_FREQ / sampleRate / *outM;
1749 double min_error = 1.0;
1754 for (
int a = 1; a < 64; ++a) {
1755 int b = (N - (double)(*outN)) * (
double)a;
1759 double divisor = (double)(*outN) + (double)b / (
double)a;
1760 double error = divisor > N ? divisor - N : N - divisor;
1761 if (error < min_error) {
1770 divisor = (double)(*outN) + (double)b / (
double)a;
1771 error = divisor > N ? divisor - N : N - divisor;
1772 if (error < min_error) {
1779 return APB_CLK_FREQ / ((double)(*outN) + (double)(*outB) / (*outA)) / *outM;
#define FABGLIB_VIDEO_CPUINTENSIVE_TASKS_CORE
This file contains some utility classes and functions.
VideoMode
Specifies a video mode.
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.