diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c25c928d..d38142c79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,6 +417,16 @@ set(header_eez_modules_bp3c list (APPEND header_files ${header_eez_modules_bp3c}) source_group("eez\\modules\\bp3c" FILES ${src_eez_modules_bp3c} ${header_eez_modules_bp3c}) +set(src_eez_modules_fpga + src/eez/modules/fpga/prog.cpp +) +list (APPEND src_files ${src_eez_modules_fpga}) +set(header_eez_modules_fpga + src/eez/modules/fpga/prog.h +) +list (APPEND header_files ${header_eez_modules_fpga}) +source_group("eez\\modules\\fpga" FILES ${src_eez_modules_fpga} ${header_eez_modules_fpga}) + set(src_eez_modules_mcu src/eez/modules/mcu/battery.cpp src/eez/modules/mcu/display.cpp diff --git a/src/eez/gui/app_context.cpp b/src/eez/gui/app_context.cpp index e359ab70c..b4ba793c1 100644 --- a/src/eez/gui/app_context.cpp +++ b/src/eez/gui/app_context.cpp @@ -104,10 +104,10 @@ void AppContext::onPageChanged(int previousPageId, int activePageId) { } void AppContext::doShowPage(int pageId, Page *page, int previousPageId) { -#if CONF_OPTION_FPGA - pageId = PAGE_ID_WELCOME_800X480; - page = nullptr; -#endif +//#if CONF_OPTION_FPGA +// pageId = PAGE_ID_WELCOME_800X480; +// page = nullptr; +//#endif page = page ? page : getPageFromIdHook(pageId); diff --git a/src/eez/modules/fpga/prog.cpp b/src/eez/modules/fpga/prog.cpp new file mode 100644 index 000000000..f765b27ce --- /dev/null +++ b/src/eez/modules/fpga/prog.cpp @@ -0,0 +1,467 @@ +/* + * EEZ Modular Firmware + * Copyright (C) 2020-present, Envox d.o.o. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#if EEZ_PLATFORM_STM32 +#include +#include +#endif + +#include +#include +#include + +#include + +#include + +namespace eez { +namespace fpga { + +#if defined(EEZ_PLATFORM_SIMULATOR) + +#define DOUT2_GPIO_Port 0 +#define DOUT2_Pin 0 +#define GPIOB 0 +#define GPIO_PIN_14 0 +#define GPIOI 0 +#define GPIO_PIN_3 0 +#define GPIO_PIN_1 0 + +typedef uint32_t GPIO_TypeDef; + +enum GPIO_PinState { + GPIO_PIN_RESET = 0, + GPIO_PIN_SET +}; + +void HAL_GPIO_WritePin(GPIO_TypeDef *port, uint32_t pin, GPIO_PinState state) { +} + +GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *port, uint32_t pin) { + return GPIO_PIN_SET; +} + +#endif + +struct Pin { + Pin(GPIO_TypeDef *port, uint32_t pin) : m_port(port), m_pin(pin) { + } + + void on() { + HAL_GPIO_WritePin(m_port, m_pin, GPIO_PIN_SET); + } + + void off() { + HAL_GPIO_WritePin(m_port, m_pin, GPIO_PIN_RESET); + } + + GPIO_PinState value() { + return HAL_GPIO_ReadPin(m_port, m_pin); + } + + GPIO_TypeDef *m_port; + uint32_t m_pin; +}; + +Pin tms(DOUT2_GPIO_Port, DOUT2_Pin); +Pin tdi(GPIOB, GPIO_PIN_14); +Pin tdo(GPIOI, GPIO_PIN_3); +Pin tck(GPIOI, GPIO_PIN_1); + +void bitbang_jtag_on() { + // led=Pin(gpio_led,Pin.OUT) + // tms=Pin(gpio_tms,Pin.OUT) + // tck=Pin(gpio_tck,Pin.OUT) + // tdi=Pin(gpio_tdi,Pin.OUT) + // tdo=Pin(gpio_tdo,Pin.IN) +} + +void bitbang_jtag_off() { + // led=Pin(gpio_led,Pin.IN) + // tms=Pin(gpio_tms,Pin.IN) + // tck=Pin(gpio_tck,Pin.IN) + // tdi=Pin(gpio_tdi,Pin.IN) + // tdo=Pin(gpio_tdo,Pin.IN) + // a = led.value() + // a = tms.value() + // a = tck.value() + // a = tdo.value() + // a = tdi.value() + // del led + // del tms + // del tck + // del tdi + // del tdo +} + +void spi_jtag_on() { + // global hwspi,swspi + // hwspi=SPI(spi_channel, baudrate=spi_freq, polarity=1, phase=1, bits=8, firstbit=SPI.MSB, sck=Pin(gpio_tck), mosi=Pin(gpio_tdi), miso=Pin(gpio_tdo)) + // swspi=SPI(-1, baudrate=spi_freq, polarity=1, phase=1, bits=8, firstbit=SPI.MSB, sck=Pin(gpio_tck), mosi=Pin(gpio_tdi), miso=Pin(gpio_tdo)) +} + +void spi_jtag_off() { + // hwspi.deinit() + // del hwspi + + // swspi.deinit() + // del swspi +} + +void send_tms(int val) { + if (val) { + tms.on(); + } else { + tms.off(); + } + tck.off(); + tck.on(); +} + +void send_tms0111() { + send_tms(0); // # -> pause DR + send_tms(1); // # -> exit 2 DR + send_tms(1); // # -> update DR + send_tms(1); // # -> select DR scan +} + +void send_read_buf_lsb1st(const uint8_t *buf, int bufLen, int last, uint8_t *w) { + const uint8_t *p = buf; + int l = bufLen; + + int val = 0; + tms.off(); + + for (int i = 0; i < l - 1; i++) { + uint8_t byte = 0; + uint8_t val = p[i]; + + for (int nf = 0; nf < 8; nf++) { + if ((val >> nf) & 1) { + tdi.on(); + } else { + tdi.off(); + } + tck.off(); + tck.on(); + if (tdo.value()) { + byte |= 1 << nf; + } + } + + if (w) { + w[i] = byte; // # write byte + } + } + + uint8_t byte = 0; + val = p[l - 1]; // # read last byte + for (int nf = 0; nf < 7; nf++) { // # first 7 bits + if ((val >> nf) & 1) { + tdi.on(); + } else { + tdi.off(); + } + tck.off(); + tck.on(); + if (tdo.value()) { + byte |= 1 << nf; + } + } + + // # last bit + if (last) { + tms.on(); + } + if ((val >> 7) & 1) { + tdi.on(); + } else { + tdi.off(); + } + tck.off(); + tck.on(); + if (tdo.value()) { + byte |= 1 << 7; + } + if (w) { + w[l - 1] = byte; //# write last byte + } +} + +void reset_tap() { + for (int n = 0; n < 6; n++) { + send_tms(1); // # -> Test Logic Reset + } +} + +void runtest_idle(int count, uint32_t duration_ms) { + uint32_t leave = millis() + duration_ms; + + for (int n = 0; n < count; n++) { + send_tms(0); // # -> idle + } + + while (leave >= millis()) { + send_tms(0); // # -> idle + } + + send_tms(1); // # -> select DR scan +} + +void sir(const uint8_t *buf, int bufLen) { + send_tms(1); // # -> select IR scan + send_tms(0); // # -> capture IR + send_tms(0); // # -> shift IR + send_read_buf_lsb1st(buf, bufLen, 1, 0); //# -> exit 1 IR + send_tms0111(); // # -> select DR scan +} + +void sir(uint8_t byte) { + sir(&byte, 1); +} + +void sir_idle(const uint8_t *buf, int bufLen, int n, uint32_t ms) { + send_tms(1); // # -> select IR scan + send_tms(0); // # -> capture IR + send_tms(0); // # -> shift IR + send_read_buf_lsb1st(buf, bufLen, 1, 0); // # -> exit 1 IR + send_tms(0); // # -> pause IR + send_tms(1); // # -> exit 2 IR + send_tms(1); // # -> update IR + runtest_idle(n + 1, ms); // # -> select DR scan +} + +void sir_idle(uint8_t byte, int n, uint32_t ms) { + sir_idle(&byte, 1, n, ms); +} + +void sdr(const uint8_t *buf, int bufLen) { + send_tms(0); // # ->capture DR + send_tms(0); // # ->shift DR + send_read_buf_lsb1st(buf, bufLen, 1, 0); + send_tms0111(); // # -> select DR scan +} + +void sdr(uint8_t byte) { + sdr(&byte, 1); +} + +void sdr_idle(const uint8_t *buf, int bufLen, int n, uint32_t ms) { + send_tms(0); // # -> capture DR + send_tms(0); // # -> shift DR + send_read_buf_lsb1st(buf, bufLen, 1, 0); + send_tms(0); // # -> pause DR + send_tms(1); // # -> exit 2 DR + send_tms(1); // # -> update DR + runtest_idle(n + 1, ms); // # -> select DR scan +} + +void sdr_idle(uint8_t byte, int n, uint32_t ms) { + sdr_idle(&byte, 1, n, ms); +} + +void sdr_response(uint8_t *buf, int bufLen) { + send_tms(0); // # -> capture DR + send_tms(0); // # -> shift DR + send_read_buf_lsb1st(buf, bufLen, 1, buf); + send_tms0111(); // # -> select DR scan +} + +void check_response(uint32_t response, uint32_t expected, uint32_t mask = 0xFFFFFFFF, const char *message = "") { + if ((response & mask) != expected) { + DebugTrace("0x%08X & 0x%08X != 0x%08X %s\n", response, mask, expected, message); + } +} + +void common_open() { + spi_jtag_on(); + + // hwspi.init(sck=Pin(gpio_tcknc)) # avoid TCK-glitch + + bitbang_jtag_on(); + + reset_tap(); + runtest_idle(1, 0); + + //#sir(b"\xE0") # read IDCODE + //#sdr(pack("capture DR + send_tms(0); // # ->shift DR + // # switch from bitbanging to SPI mode + + // hwspi.init(sck = Pin(gpio_tck)) // # 1 TCK - glitch ? TDI = 0 + + // # we are lucky that format of the bitstream tolerates + // # any leading and trailing junk bits. If it weren't so, + // # HW SPI JTAG acceleration wouldn't work. + // # to upload the bitstream: + // # FAST SPI mode + // #hwspi.write(block) + // # SLOW bitbanging mode + // #for byte in block: + // # send_int_msb1st(byte,0) + +} + +void prog_stream_done() { + // # switch from hardware SPI to bitbanging done after prog_stream() + // hwspi.init(sck=Pin(gpio_tcknc)) # avoid TCK-glitch + spi_jtag_off(); +} + +// # call this after uploading all of the bitstream blocks, +// # this will exit FPGA programming mode and start the bitstream +// # returns status True - OK False - Fail +bool prog_close() { + bitbang_jtag_on(); + + send_tms(1); // # ->exit 1 DR + send_tms(0); // # ->pause DR + send_tms(1); // # ->exit 2 DR + send_tms(1); // # ->update DR + // #send_tms(0) # ->idle, disabled here as runtest_idle does the same + runtest_idle(100, 10); + // # ---------- bitstream end ----------- + sir_idle(0xC0, 2, 1); //# read usercode + + uint32_t usercode; + sdr_response((uint8_t *)&usercode, 4); + check_response(usercode, 0, 0xFFFFFFFF, "FAIL usercode"); + + sir_idle(0x26, 2, 200); // # ISC DISABLE + sir_idle(0xFF, 2, 1); // # BYPASS + + sir(0x3C); // # LSC_READ_STATUS + + uint32_t status; + sdr_response((uint8_t *)&status, 4); + check_response(status, 0x100, 0x2100, "FAIL status"); + + bool done = true; + if ((status & 0x2100) != 0x100) { + done = false; + } + + reset_tap(); + + bitbang_jtag_off(); + + return done; +} + +void write_block(uint8_t *block, uint32_t blockLen) { +#if defined(EEZ_PLATFORM_STM32) + spi::select(0, spi::CHIP_FPGA); + spi::transmit(0, block, blockLen); + spi::deselect(0); +#endif +} + +scpi_result_t prog(const char *filePath) { +#if OPTION_DISPLAY + size_t total; + size_t transfered; +#endif + + File file; + + if (!file.open(filePath, FILE_OPEN_EXISTING | FILE_READ)) { + goto Exit; + } + +#if OPTION_DISPLAY + psu::gui::showProgressPageWithoutAbort("Programming FPGA..."); + psu::gui::updateProgressPage(0, 0); + total = file.size(); + transfered = 0; +#endif + + prog_open(); + + while (true) { + uint8_t block[1024]; + size_t bytes = file.read(block, sizeof(block)); + if (bytes == 0) { + break; + } + + write_block(block, bytes); + +#if OPTION_DISPLAY + transfered += bytes; + psu::gui::updateProgressPage(transfered, total); +#endif + + if (bytes < sizeof(block)) { + break; + } + } + + prog_stream_done(); + + prog_close(); + + file.close(); + +#if OPTION_DISPLAY + psu::gui::hideProgressPage(); +#endif + +Exit: + + return SCPI_RES_OK; +} + +} // namespace fpga +} // namespace eez diff --git a/src/eez/modules/fpga/prog.h b/src/eez/modules/fpga/prog.h new file mode 100644 index 000000000..1af31a0c6 --- /dev/null +++ b/src/eez/modules/fpga/prog.h @@ -0,0 +1,27 @@ +/* + * EEZ Modular Firmware + * Copyright (C) 2020-present, Envox d.o.o. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +namespace eez { +namespace fpga { + +scpi_result_t prog(const char *filePath); + +} // namespace fpga +} // namespace eez diff --git a/src/eez/modules/psu/gui/file_manager.cpp b/src/eez/modules/psu/gui/file_manager.cpp index 9d4fb8533..026898e89 100644 --- a/src/eez/modules/psu/gui/file_manager.cpp +++ b/src/eez/modules/psu/gui/file_manager.cpp @@ -51,6 +51,7 @@ #include #include +#include using namespace eez::psu::gui; @@ -654,6 +655,12 @@ bool isOpenFileEnabled() { return mp::isIdle(); } + if (fileItem->type == FILE_TYPE_OTHER) { + if (endsWithNoCase(fileItem->name, ".bit")) { + return true; + } + } + return false; } @@ -690,6 +697,10 @@ void openFile() { sendMessageToLowPriorityThread(THREAD_MESSAGE_FILE_MANAGER_OPEN_IMAGE_FILE); } else if (fileItem->type == FILE_TYPE_MICROPYTHON) { mp::startScript(filePath); + } else if (fileItem->type == FILE_TYPE_OTHER) { + if (endsWithNoCase(filePath, ".bit")) { + sendMessageToLowPriorityThread(THREAD_MESSAGE_FILE_MANAGER_OPEN_BIT_FILE); + } } } @@ -712,6 +723,22 @@ void openImageFile() { } } +void openBitFile() { + auto fileItem = getFileItem(g_selectedFileIndex); + if (fileItem) { + if (strlen(g_currentDirectory) + 1 + strlen(fileItem->name) > MAX_PATH_LENGTH) { + return; + } + + char filePath[MAX_PATH_LENGTH + 1]; + strcpy(filePath, g_currentDirectory); + strcat(filePath, "/"); + strcat(filePath, fileItem->name); + + fpga::prog(filePath); + } +} + bool isUploadFileEnabled() { #if !defined(EEZ_PLATFORM_SIMULATOR) if (psu::serial::isConnected()) { diff --git a/src/eez/modules/psu/gui/file_manager.h b/src/eez/modules/psu/gui/file_manager.h index 5f1f3529a..a6ef962d3 100644 --- a/src/eez/modules/psu/gui/file_manager.h +++ b/src/eez/modules/psu/gui/file_manager.h @@ -72,6 +72,7 @@ bool isDeleteFileEnabled(); void deleteFile(); void openImageFile(); +void openBitFile(); void onEncoder(int couter); diff --git a/src/eez/modules/psu/gui/keypad.cpp b/src/eez/modules/psu/gui/keypad.cpp index a3dba3d33..3d78ebc9c 100644 --- a/src/eez/modules/psu/gui/keypad.cpp +++ b/src/eez/modules/psu/gui/keypad.cpp @@ -97,7 +97,7 @@ void onKeypadTextTouch(const WidgetCursor &widgetCursor, Event &touchEvent) { } Keypad *keypad = getActiveKeypad(); - if (keypad && keypad != getActiveNumericKeypad()) { + if (keypad) { keypad->setCursorPosition(DISPLAY_DATA_getCharIndexAtPosition(touchEvent.x, widgetCursor)); } } @@ -434,6 +434,7 @@ void NumericKeypad::init( if (value.getType() == VALUE_TYPE_IP_ADDRESS) { ipAddressToString(value.getUInt32(), m_keypadText); + m_cursorPosition = strlen(m_keypadText); m_state = BEFORE_DOT; } } @@ -725,6 +726,8 @@ int NumericKeypad::getCursorPostion() { double NumericKeypad::getValue() { const char *p = m_keypadText; + bool empty = true; + int a = 0; double b = 0; int sign = 1; @@ -739,6 +742,7 @@ double NumericKeypad::getValue() { while (*p && *p != getDotSign()) { a = a * 10 + (*p - '0'); ++p; + empty = false; } if (*p) { @@ -746,9 +750,14 @@ double NumericKeypad::getValue() { while (q != p) { b = (b + (*q - '0')) / 10; --q; + empty = false; } } + if (empty) { + return NAN; + } + double value = sign * (a + b); if (isPico()) { @@ -780,7 +789,13 @@ void NumericKeypad::digit(int d) { insertChar('+'); } } + } else { + if (m_keypadText[m_cursorPosition] == '-' || m_keypadText[m_cursorPosition] == '+') { + sound::playBeep(); + return; + } } + insertChar(d + '0'); if (!checkNumSignificantDecimalDigits()) { @@ -803,7 +818,7 @@ void NumericKeypad::dot() { return; } - if (m_state == EMPTY) { + if (m_state == START || m_state == EMPTY) { if (m_startValue.getType() == VALUE_TYPE_TIME_ZONE) { if (strlen(m_keypadText) == 0) { insertChar('+'); @@ -813,12 +828,7 @@ void NumericKeypad::dot() { m_state = BEFORE_DOT; } - if (m_state == START || m_state == EMPTY) { - insertChar('0'); - m_state = BEFORE_DOT; - } - - if (m_state == BEFORE_DOT) { + if (m_state == BEFORE_DOT && m_keypadText[m_cursorPosition] != '-' && m_keypadText[m_cursorPosition] != '+') { insertChar(getDotSign()); m_state = AFTER_DOT; } else { @@ -886,6 +896,8 @@ void NumericKeypad::sign() { if (m_keypadText[0] == 0) { m_keypadText[0] = '-'; m_keypadText[1] = 0; + m_cursorPosition = 1; + m_state = BEFORE_DOT; } else if (m_keypadText[0] == '-') { m_keypadText[0] = '+'; } else { @@ -894,11 +906,17 @@ void NumericKeypad::sign() { } else { if (m_keypadText[0] == '-') { strcpy(m_keypadText, m_keypadText + 1); + if (m_cursorPosition > 0) { + m_cursorPosition--; + } } else if (m_keypadText[0] == '+') { m_keypadText[0] = '-'; } else { - memmove(m_keypadText + 1, m_keypadText, strlen(m_keypadText)); + auto n = strlen(m_keypadText); + memmove(m_keypadText + 1, m_keypadText, n); + m_keypadText[n + 1] = 0; m_keypadText[0] = '-'; + m_cursorPosition++; } if (m_state == START || m_state == EMPTY) { @@ -981,6 +999,10 @@ void NumericKeypad::ok() { return; } else { double value = getValue(); + if (isNaN(value)) { + sound::playBeep(); + return; + } if (!isNaN(m_options.min) && value < m_options.min && !(value == 0 && m_options.allowZero)) { psuErrorMessage(0, MakeLessThenMinMessageValue(m_options.min, m_startValue)); diff --git a/src/eez/modules/psu/scpi/debug.cpp b/src/eez/modules/psu/scpi/debug.cpp index bd8cab8c5..458fc064f 100644 --- a/src/eez/modules/psu/scpi/debug.cpp +++ b/src/eez/modules/psu/scpi/debug.cpp @@ -48,6 +48,8 @@ #include +#include + namespace eez { namespace psu { @@ -117,7 +119,13 @@ scpi_result_t scpi_cmd_debug(scpi_t *context) { taskENTER_CRITICAL(); #endif while(1); - } { + } else if (cmd == 31) { + char filePath[MAX_PATH_LENGTH + 1]; + if (!getFilePath(context, filePath, true)) { + return SCPI_RES_ERR; + } + return fpga::prog(filePath); + } else { SCPI_ErrorPush(context, SCPI_ERROR_HARDWARE_MISSING); return SCPI_RES_ERR; } diff --git a/src/eez/platform/stm32/spi.cpp b/src/eez/platform/stm32/spi.cpp index 2eb8dc29a..3961d2e5a 100644 --- a/src/eez/platform/stm32/spi.cpp +++ b/src/eez/platform/stm32/spi.cpp @@ -57,6 +57,9 @@ void select(uint8_t slotIndex, int chip) { } else if (chip == CHIP_IOEXP || chip == CHIP_TEMP_SENSOR) { WRITE_REG(handle[slotIndex]->Instance->CR1, SPI_MODE_MASTER | SPI_DIRECTION_2LINES | SPI_POLARITY_LOW | SPI_PHASE_1EDGE | (SPI_NSS_SOFT & SPI_CR1_SSM) | SPI_BAUDRATEPRESCALER_16 | SPI_FIRSTBIT_MSB | SPI_CRCCALCULATION_DISABLE); handle[slotIndex]->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + } else if (chip == CHIP_FPGA) { + WRITE_REG(handle[slotIndex]->Instance->CR1, SPI_MODE_MASTER | SPI_DIRECTION_1LINE | SPI_POLARITY_HIGH | SPI_PHASE_1EDGE | (SPI_NSS_SOFT & SPI_CR1_SSM) | SPI_BAUDRATEPRESCALER_16 | SPI_FIRSTBIT_MSB | SPI_CRCCALCULATION_DISABLE); + handle[slotIndex]->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; } else { WRITE_REG(handle[slotIndex]->Instance->CR1, SPI_MODE_MASTER | SPI_DIRECTION_2LINES | SPI_POLARITY_LOW | SPI_PHASE_2EDGE | (SPI_NSS_SOFT & SPI_CR1_SSM) | SPI_BAUDRATEPRESCALER_16 | SPI_FIRSTBIT_MSB | SPI_CRCCALCULATION_DISABLE); handle[slotIndex]->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; diff --git a/src/eez/platform/stm32/spi.h b/src/eez/platform/stm32/spi.h index 758ad0001..dd290f002 100644 --- a/src/eez/platform/stm32/spi.h +++ b/src/eez/platform/stm32/spi.h @@ -35,6 +35,7 @@ static const int CHIP_IOEXP = 2; static const int CHIP_TEMP_SENSOR = 3; static const int CHIP_SLAVE_MCU = 4; static const int CHIP_SLAVE_MCU_NO_CRC = 5; +static const int CHIP_FPGA = 6; void init(uint8_t slotIndex, int chip); diff --git a/src/eez/tasks.cpp b/src/eez/tasks.cpp index 192d269a8..d486438c1 100644 --- a/src/eez/tasks.cpp +++ b/src/eez/tasks.cpp @@ -365,6 +365,8 @@ void lowPriorityThreadOneIter() { file_manager::uploadFile(); } else if (type == THREAD_MESSAGE_FILE_MANAGER_OPEN_IMAGE_FILE) { file_manager::openImageFile(); + } else if (type == THREAD_MESSAGE_FILE_MANAGER_OPEN_BIT_FILE) { + file_manager::openBitFile(); } else if (type == THREAD_MESSAGE_FILE_MANAGER_DELETE_FILE) { file_manager::deleteFile(); } else if (type == THREAD_MESSAGE_FILE_MANAGER_RENAME_FILE) { diff --git a/src/eez/tasks.h b/src/eez/tasks.h index c67096566..105b41dba 100644 --- a/src/eez/tasks.h +++ b/src/eez/tasks.h @@ -90,6 +90,7 @@ enum LowPriorityThreadMessage { THREAD_MESSAGE_FILE_MANAGER_LOAD_DIRECTORY, THREAD_MESSAGE_FILE_MANAGER_UPLOAD_FILE, THREAD_MESSAGE_FILE_MANAGER_OPEN_IMAGE_FILE, + THREAD_MESSAGE_FILE_MANAGER_OPEN_BIT_FILE, THREAD_MESSAGE_FILE_MANAGER_DELETE_FILE, THREAD_MESSAGE_FILE_MANAGER_RENAME_FILE, THREAD_MESSAGE_DLOG_UPLOAD_FILE, diff --git a/src/eez/util.cpp b/src/eez/util.cpp index 6f52f3c92..0612911a9 100644 --- a/src/eez/util.cpp +++ b/src/eez/util.cpp @@ -214,6 +214,10 @@ bool isNaN(float x) { return x != x; } +bool isNaN(double x) { + return x != x; +} + bool isDigit(char ch) { return ch >= '0' && ch <= '9'; } diff --git a/src/eez/util.h b/src/eez/util.h index b027e66eb..763911f6e 100644 --- a/src/eez/util.h +++ b/src/eez/util.h @@ -76,6 +76,7 @@ float floorPrec(float a, float prec); float ceilPrec(float a, float prec); bool isNaN(float x); +bool isNaN(double x); bool isDigit(char ch); bool isHexDigit(char ch);