Goran Mahovlić
1 year ago
377 changed files with 4 additions and 114470 deletions
@ -0,0 +1,3 @@
|
||||
[submodule "Middlewares/eez-framework"] |
||||
path = Middlewares/eez-framework |
||||
url = https://github.com/eez-open/eez-framework.git |
@ -1,202 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <math.h> |
||||
#include <assert.h> |
||||
#include <memory.h> |
||||
#include <cstring> |
||||
|
||||
#include <eez/core/alloc.h> |
||||
#include <eez/core/os.h> |
||||
|
||||
namespace eez { |
||||
|
||||
static const size_t ALIGNMENT = 8; |
||||
static const size_t MIN_BLOCK_SIZE = 8; |
||||
|
||||
struct AllocBlock { |
||||
AllocBlock *next; |
||||
int free; |
||||
size_t size; |
||||
uint32_t id; |
||||
}; |
||||
|
||||
static uint8_t *g_heap; |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
#pragma GCC diagnostic push |
||||
#pragma GCC diagnostic ignored "-Wparentheses" |
||||
#endif |
||||
|
||||
EEZ_MUTEX_DECLARE(alloc); |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
#pragma GCC diagnostic pop |
||||
#endif |
||||
|
||||
void initAllocHeap(uint8_t *heap, size_t heapSize) { |
||||
g_heap = heap; |
||||
|
||||
AllocBlock *first = (AllocBlock *)g_heap; |
||||
first->next = 0; |
||||
first->free = 1; |
||||
first->size = heapSize - sizeof(AllocBlock); |
||||
|
||||
EEZ_MUTEX_CREATE(alloc); |
||||
} |
||||
|
||||
void *alloc(size_t size, uint32_t id) { |
||||
if (size == 0) { |
||||
return nullptr; |
||||
} |
||||
|
||||
if (EEZ_MUTEX_WAIT(alloc, 0)) { |
||||
AllocBlock *firstBlock = (AllocBlock *)g_heap; |
||||
|
||||
AllocBlock *block = firstBlock; |
||||
size = ((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; |
||||
|
||||
// find free block with enough size
|
||||
// TODO merge multiple free consecutive blocks into one that has enough size
|
||||
while (block) { |
||||
if (block->free && block->size >= size) { |
||||
break; |
||||
} |
||||
block = block->next; |
||||
} |
||||
|
||||
if (!block) { |
||||
EEZ_MUTEX_RELEASE(alloc); |
||||
return nullptr; |
||||
} |
||||
|
||||
int remainingSize = block->size - size - sizeof(AllocBlock); |
||||
if (remainingSize >= (int)MIN_BLOCK_SIZE) { |
||||
// remainingSize is enough to create a new block
|
||||
auto newBlock = (AllocBlock *)((uint8_t *)block + sizeof(AllocBlock) + size); |
||||
newBlock->next = block->next; |
||||
newBlock->free = 1; |
||||
newBlock->size = remainingSize; |
||||
|
||||
block->next = newBlock; |
||||
block->size = size; |
||||
} |
||||
|
||||
block->free = 0; |
||||
block->id = id; |
||||
|
||||
EEZ_MUTEX_RELEASE(alloc); |
||||
|
||||
return block + 1; |
||||
} |
||||
|
||||
return nullptr; |
||||
} |
||||
|
||||
void free(void *ptr) { |
||||
if (ptr == 0) { |
||||
return; |
||||
} |
||||
|
||||
if (EEZ_MUTEX_WAIT(alloc, 0)) { |
||||
AllocBlock *firstBlock = (AllocBlock *)g_heap; |
||||
|
||||
AllocBlock *prevBlock = nullptr; |
||||
AllocBlock *block = firstBlock; |
||||
|
||||
while (block && block + 1 < ptr) { |
||||
prevBlock = block; |
||||
block = block->next; |
||||
} |
||||
|
||||
if (!block || block + 1 != ptr || block->free) { |
||||
assert(false); |
||||
EEZ_MUTEX_RELEASE(alloc); |
||||
return; |
||||
} |
||||
|
||||
// reset memory to catch errors when memory is used after free is called
|
||||
memset(ptr, 0xCC, block->size); |
||||
|
||||
auto nextBlock = block->next; |
||||
if (nextBlock && nextBlock->free) { |
||||
if (prevBlock && prevBlock->free) { |
||||
// both next and prev blocks are free, merge 3 blocks into one
|
||||
prevBlock->next = nextBlock->next; |
||||
prevBlock->size += sizeof(AllocBlock) + block->size + sizeof(AllocBlock) + nextBlock->size; |
||||
} else { |
||||
// next block is free, merge 2 blocks into one
|
||||
block->next = nextBlock->next; |
||||
block->size += sizeof(AllocBlock) + nextBlock->size; |
||||
block->free = 1; |
||||
} |
||||
} else if (prevBlock && prevBlock->free) { |
||||
// prev block is free, merge 2 blocks into one
|
||||
prevBlock->next = nextBlock; |
||||
prevBlock->size += sizeof(AllocBlock) + block->size; |
||||
} else { |
||||
// just free
|
||||
block->free = 1; |
||||
} |
||||
|
||||
EEZ_MUTEX_RELEASE(alloc); |
||||
} |
||||
} |
||||
|
||||
template<typename T> void freeObject(T *ptr) { |
||||
ptr->~T(); |
||||
free(ptr); |
||||
} |
||||
|
||||
#if OPTION_SCPI |
||||
void dumpAlloc(scpi_t *context) { |
||||
AllocBlock *first = (AllocBlock *)g_heap; |
||||
AllocBlock *block = first; |
||||
while (block) { |
||||
char buffer[100]; |
||||
if (block->free) { |
||||
snprintf(buffer, sizeof(buffer), "FREE: %d", (int)block->size); |
||||
} else { |
||||
snprintf(buffer, sizeof(buffer), "ALOC (0x%08x): %d", (unsigned int)block->id, (int)block->size); |
||||
} |
||||
SCPI_ResultText(context, buffer); |
||||
block = block->next; |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
void getAllocInfo(uint32_t &free, uint32_t &alloc) { |
||||
free = 0; |
||||
alloc = 0; |
||||
if (EEZ_MUTEX_WAIT(alloc, 0)) { |
||||
AllocBlock *first = (AllocBlock *)g_heap; |
||||
AllocBlock *block = first; |
||||
while (block) { |
||||
if (block->free) { |
||||
free += block->size; |
||||
} else { |
||||
alloc += block->size; |
||||
} |
||||
block = block->next; |
||||
} |
||||
EEZ_MUTEX_RELEASE(alloc); |
||||
} |
||||
} |
||||
|
||||
} // eez
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
#include <math.h> |
||||
#include <new> |
||||
|
||||
#if OPTION_SCPI |
||||
#include <scpi/scpi.h> |
||||
#endif |
||||
|
||||
namespace eez { |
||||
|
||||
void initAllocHeap(uint8_t *heap, size_t heapSize); |
||||
|
||||
void *alloc(size_t size, uint32_t id); |
||||
void free(void *ptr); |
||||
|
||||
template<class T> struct ObjectAllocator { |
||||
static T *allocate(uint32_t id) { |
||||
auto ptr = alloc(sizeof(T), id); |
||||
return new (ptr) T; |
||||
} |
||||
static void deallocate(T* ptr) { |
||||
ptr->~T(); |
||||
free(ptr); |
||||
} |
||||
}; |
||||
|
||||
#if OPTION_SCPI |
||||
void dumpAlloc(scpi_t *context); |
||||
#endif |
||||
|
||||
void getAllocInfo(uint32_t &free, uint32_t &alloc); |
||||
|
||||
} // eez
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2018-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#ifdef DEBUG |
||||
|
||||
#include <cstdio> |
||||
#include <stdarg.h> |
||||
#include <string.h> |
||||
|
||||
#include <eez/core/debug.h> |
||||
|
||||
namespace eez { |
||||
namespace debug { |
||||
|
||||
void Trace(TraceType traceType, const char *format, ...) { |
||||
va_list args; |
||||
va_start(args, format); |
||||
|
||||
static const size_t BUFFER_SIZE = 256; |
||||
char buffer[BUFFER_SIZE + 1]; |
||||
|
||||
vsnprintf(buffer, BUFFER_SIZE, format, args); |
||||
buffer[BUFFER_SIZE] = 0; |
||||
|
||||
va_end(args); |
||||
|
||||
if (traceType == TRACE_TYPE_DEBUG) { |
||||
pushDebugTraceHook(buffer, strlen(buffer)); |
||||
} else if (traceType == TRACE_TYPE_INFO) { |
||||
pushInfoTraceHook(buffer, strlen(buffer)); |
||||
} else { |
||||
pushErrorTraceHook(buffer, strlen(buffer)); |
||||
} |
||||
} |
||||
|
||||
} // namespace debug
|
||||
} // namespace eez
|
||||
|
||||
extern "C" void debug_trace(const char *str, size_t len) { |
||||
eez::debug::pushDebugTraceHook(str, len); |
||||
} |
||||
|
||||
#endif // DEBUG
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2018-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#ifdef DEBUG |
||||
|
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
|
||||
namespace eez { |
||||
namespace debug { |
||||
|
||||
void pushDebugTraceHook(const char *message, size_t messageLength); |
||||
void pushInfoTraceHook(const char *message, size_t messageLength); |
||||
void pushErrorTraceHook(const char *message, size_t messageLength); |
||||
|
||||
enum TraceType { |
||||
TRACE_TYPE_DEBUG, |
||||
TRACE_TYPE_INFO, |
||||
TRACE_TYPE_ERROR |
||||
}; |
||||
|
||||
void Trace(TraceType traceType, const char *format, ...); |
||||
|
||||
} // namespace debug
|
||||
} // namespace eez
|
||||
|
||||
#define InfoTrace(...) ::eez::debug::Trace(::eez::debug::TRACE_TYPE_INFO, __VA_ARGS__) |
||||
#define ErrorTrace(...) ::eez::debug::Trace(::eez::debug::TRACE_TYPE_ERROR, __VA_ARGS__) |
||||
#define DebugTrace(...) ::eez::debug::Trace(::eez::debug::TRACE_TYPE_DEBUG, __VA_ARGS__) |
||||
|
||||
#else // NO DEBUG
|
||||
|
||||
#define InfoTrace(...) 0 |
||||
#define ErrorTrace(...) 0 |
||||
#define DebugTrace(...) 0 |
||||
|
||||
#endif |
@ -1,211 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <memory.h> |
||||
|
||||
#include <eez/core/eeprom.h> |
||||
#include <eez/core/os.h> |
||||
#include <eez/core/util.h> |
||||
|
||||
//#include <bb3/system.h>
|
||||
//#include <bb3/psu/psu.h>
|
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) && !CONF_SURVIVE_MODE |
||||
#define USE_EEPROM 1 |
||||
#else |
||||
#define USE_EEPROM 0 |
||||
#endif |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
#ifdef EEZ_PLATFORM_STM32F469I_DISCO |
||||
#else |
||||
#include <i2c.h> |
||||
#endif |
||||
#endif |
||||
|
||||
#if !USE_EEPROM |
||||
#include <eez/fs/fs.h> |
||||
#endif |
||||
|
||||
#if OPTION_SCPI |
||||
#include <scpi/scpi.h> |
||||
#endif |
||||
|
||||
namespace eez { |
||||
namespace eeprom { |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
// opcodes
|
||||
static const uint8_t WREN = 6; |
||||
static const uint8_t WRDI = 4; |
||||
static const uint8_t RDSR = 5; |
||||
static const uint8_t WRSR = 1; |
||||
static const uint8_t READ = 3; |
||||
static const uint8_t WRITE = 2; |
||||
|
||||
// EEPROM AT24C256C
|
||||
// I2C-Compatible (2-Wire) Serial EEPROM
|
||||
// 256-Kbit (32,768 x 8)
|
||||
// http://ww1.microchip.com/downloads/en/devicedoc/atmel-8568-seeprom-at24c256c-datasheet.pdf
|
||||
static const uint16_t EEPROM_ADDRESS = 0b10100000; |
||||
#endif |
||||
|
||||
TestResult g_testResult = TEST_FAILED; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
|
||||
const int MAX_READ_CHUNK_SIZE = 16; |
||||
const int MAX_WRITE_CHUNK_SIZE = 16; |
||||
|
||||
bool readFromEEPROM(uint8_t *buffer, uint16_t bufferSize, uint16_t address) { |
||||
#ifdef EEZ_PLATFORM_STM32F469I_DISCO |
||||
return false; |
||||
#else |
||||
for (uint16_t i = 0; i < bufferSize; i += MAX_READ_CHUNK_SIZE) { |
||||
uint16_t chunkAddress = address + i; |
||||
|
||||
uint16_t chunkSize = MIN(MAX_READ_CHUNK_SIZE, bufferSize - i); |
||||
|
||||
uint8_t data[2] = { |
||||
I2C_MEM_ADD_MSB(chunkAddress), |
||||
I2C_MEM_ADD_LSB(chunkAddress) |
||||
}; |
||||
|
||||
HAL_StatusTypeDef returnValue; |
||||
|
||||
taskENTER_CRITICAL(); |
||||
returnValue = HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDRESS, data, 2, HAL_MAX_DELAY); |
||||
if (returnValue != HAL_OK) { |
||||
taskEXIT_CRITICAL(); |
||||
return false; |
||||
} |
||||
returnValue = HAL_I2C_Master_Receive(&hi2c1, EEPROM_ADDRESS, buffer + i, chunkSize, HAL_MAX_DELAY); |
||||
taskEXIT_CRITICAL(); |
||||
if (returnValue != HAL_OK) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
#endif |
||||
} |
||||
|
||||
bool writeToEEPROM(const uint8_t *buffer, uint16_t bufferSize, uint16_t address) { |
||||
#ifdef EEZ_PLATFORM_STM32F469I_DISCO |
||||
return false; |
||||
#else |
||||
for (uint16_t i = 0; i < bufferSize; i += MAX_WRITE_CHUNK_SIZE) { |
||||
uint16_t chunkAddress = address + i; |
||||
|
||||
uint16_t chunkSize = MIN(MAX_WRITE_CHUNK_SIZE, bufferSize - i); |
||||
|
||||
HAL_StatusTypeDef returnValue; |
||||
|
||||
taskENTER_CRITICAL(); |
||||
returnValue = HAL_I2C_Mem_Write(&hi2c1, EEPROM_ADDRESS, chunkAddress, I2C_MEMADD_SIZE_16BIT, (uint8_t *)buffer + i, chunkSize, HAL_MAX_DELAY); |
||||
taskEXIT_CRITICAL(); |
||||
|
||||
if (returnValue != HAL_OK) { |
||||
return false; |
||||
} |
||||
|
||||
osDelay(5); |
||||
|
||||
// verify
|
||||
uint8_t verify[MAX_WRITE_CHUNK_SIZE]; |
||||
|
||||
uint8_t data[2] = { |
||||
I2C_MEM_ADD_MSB(chunkAddress), |
||||
I2C_MEM_ADD_LSB(chunkAddress) |
||||
}; |
||||
|
||||
taskENTER_CRITICAL(); |
||||
returnValue = HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDRESS, data, 2, HAL_MAX_DELAY); |
||||
if (returnValue != HAL_OK) { |
||||
taskEXIT_CRITICAL(); |
||||
return false; |
||||
} |
||||
returnValue = HAL_I2C_Master_Receive(&hi2c1, EEPROM_ADDRESS, verify, chunkSize, HAL_MAX_DELAY); |
||||
taskEXIT_CRITICAL(); |
||||
if (returnValue != HAL_OK) { |
||||
return false; |
||||
} |
||||
|
||||
for (int j = 0; j < chunkSize; ++j) { |
||||
if (buffer[i+j] != verify[j]) { |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
#endif |
||||
} |
||||
|
||||
#endif |
||||
|
||||
#if !USE_EEPROM |
||||
const char *EEPROM_FILE_PATH = "/EEPROM.state"; |
||||
#endif |
||||
|
||||
bool read(uint8_t *buffer, uint16_t bufferSize, uint16_t address) { |
||||
#if USE_EEPROM |
||||
return readFromEEPROM(buffer, bufferSize, address); |
||||
#else |
||||
File file; |
||||
if (!file.open(EEPROM_FILE_PATH, FILE_READ)) { |
||||
return false; |
||||
} |
||||
file.seek(address); |
||||
size_t readBytes = file.read(buffer, bufferSize); |
||||
if (readBytes < bufferSize) { |
||||
memset(buffer + readBytes, 0xFF, bufferSize - readBytes); |
||||
} |
||||
file.close(); |
||||
return true; |
||||
#endif |
||||
} |
||||
|
||||
bool write(const uint8_t *buffer, uint16_t bufferSize, uint16_t address) { |
||||
#if USE_EEPROM |
||||
return writeToEEPROM(buffer, bufferSize, address); |
||||
#else |
||||
File file; |
||||
if (!file.open(EEPROM_FILE_PATH, FILE_OPEN_ALWAYS | FILE_WRITE)) { |
||||
return false; |
||||
} |
||||
file.seek(address); |
||||
file.write(buffer, bufferSize); |
||||
file.close(); |
||||
return true; |
||||
#endif |
||||
} |
||||
|
||||
void init() { |
||||
g_testResult = TEST_OK; |
||||
} |
||||
|
||||
bool test() { |
||||
// TODO add test
|
||||
return g_testResult == TEST_OK; |
||||
} |
||||
|
||||
} // namespace eeprom
|
||||
} // namespace eez
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include <eez/core/os.h> |
||||
|
||||
namespace eez { |
||||
namespace eeprom { |
||||
|
||||
static const uint16_t EEPROM_SIZE = 32768; |
||||
|
||||
void init(); |
||||
bool test(); |
||||
|
||||
extern TestResult g_testResult; |
||||
|
||||
bool read(uint8_t *buffer, uint16_t buffer_size, uint16_t address); |
||||
bool write(const uint8_t *buffer, uint16_t buffer_size, uint16_t address); |
||||
|
||||
} // namespace eeprom
|
||||
} // namespace eez
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
namespace eez { |
||||
namespace mcu { |
||||
namespace encoder { |
||||
|
||||
#if defined(EEZ_PLATFORM_SIMULATOR) |
||||
void write(int counter, bool clicked); |
||||
void setButtonState(bool pressed); |
||||
#endif |
||||
|
||||
} // namespace encoder
|
||||
} // namespace mcu
|
||||
} // namespace eez
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* EEZ PSU Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/core/hmi.h> |
||||
#include <eez/core/os.h> |
||||
|
||||
namespace eez { |
||||
namespace hmi { |
||||
|
||||
#define MAX_GUI_OR_ENCODER_INACTIVITY_TIME_MS 60 * 1000 |
||||
|
||||
static uint32_t g_timeOfLastActivity; |
||||
static bool g_inactivityTimeMaxed = true; |
||||
|
||||
void tick() { |
||||
if (!g_inactivityTimeMaxed) { |
||||
uint32_t inactivityPeriod = getInactivityPeriodMs(); |
||||
if (inactivityPeriod >= MAX_GUI_OR_ENCODER_INACTIVITY_TIME_MS) { |
||||
g_inactivityTimeMaxed = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void noteActivity() { |
||||
g_timeOfLastActivity = millis(); |
||||
g_inactivityTimeMaxed = false; |
||||
} |
||||
|
||||
uint32_t getInactivityPeriodMs() { |
||||
if (g_inactivityTimeMaxed) { |
||||
return MAX_GUI_OR_ENCODER_INACTIVITY_TIME_MS; |
||||
} else { |
||||
return millis() - g_timeOfLastActivity; |
||||
} |
||||
} |
||||
|
||||
uint32_t getTimeOfLastActivity() { |
||||
if (g_inactivityTimeMaxed) { |
||||
return millis() - MAX_GUI_OR_ENCODER_INACTIVITY_TIME_MS; |
||||
} else { |
||||
return g_timeOfLastActivity; |
||||
} |
||||
} |
||||
|
||||
} // namespace hmi
|
||||
} // namespace eez
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* EEZ PSU Firmware |
||||
* Copyright (C) 2017-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
|
||||
namespace eez { |
||||
namespace hmi { |
||||
|
||||
void tick(); |
||||
|
||||
void noteActivity(); |
||||
uint32_t getInactivityPeriodMs(); |
||||
uint32_t getTimeOfLastActivity(); |
||||
|
||||
} |
||||
} // namespace eez::hmi
|
@ -1,285 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic 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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include <eez/conf.h> |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
#if OPTION_KEYBOARD |
||||
#include <usbh_hid.h> |
||||
#endif |
||||
#endif |
||||
|
||||
#if defined(EEZ_PLATFORM_SIMULATOR) && !defined(__EMSCRIPTEN__) |
||||
#include <SDL.h> |
||||
#endif |
||||
|
||||
namespace eez { |
||||
namespace keyboard { |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
#if OPTION_KEYBOARD |
||||
void onKeyboardEvent(USBH_HandleTypeDef *phost); |
||||
#endif |
||||
#endif |
||||
|
||||
#if defined(EEZ_PLATFORM_SIMULATOR) && !defined(__EMSCRIPTEN__) |
||||
void onKeyboardEvent(SDL_KeyboardEvent *key); |
||||
#endif |
||||
|
||||
bool isDisplayDirty(); |
||||
void updateDisplay(); |
||||
|
||||
void onPageChanged(); |
||||
|
||||
static const uint8_t KEY_MOD_LCTRL = 1 << 0; |
||||
static const uint8_t KEY_MOD_LSHIFT = 1 << 1; |
||||
static const uint8_t KEY_MOD_LALT = 1 << 2; |
||||
static const uint8_t KEY_MOD_LGUI = 1 << 3; |
||||
static const uint8_t KEY_MOD_RCTRL = 1 << 4; |
||||
static const uint8_t KEY_MOD_RSHIFT = 1 << 5; |
||||
static const uint8_t KEY_MOD_RALT = 1 << 6; |
||||
static const uint8_t KEY_MOD_RGUI = 1 << 7; |
||||
|
||||
#if defined(EEZ_PLATFORM_SIMULATOR) |
||||
#define KEY_NONE 0x00 |
||||
#define KEY_ERRORROLLOVER 0x01 |
||||
#define KEY_POSTFAIL 0x02 |
||||
#define KEY_ERRORUNDEFINED 0x03 |
||||
#define KEY_A 0x04 |
||||
#define KEY_B 0x05 |
||||
#define KEY_C 0x06 |
||||
#define KEY_D 0x07 |
||||
#define KEY_E 0x08 |
||||
#define KEY_F 0x09 |
||||
#define KEY_G 0x0A |
||||
#define KEY_H 0x0B |
||||
#define KEY_I 0x0C |
||||
#define KEY_J 0x0D |
||||
#define KEY_K 0x0E |
||||
#define KEY_L 0x0F |
||||
#define KEY_M 0x10 |
||||
#define KEY_N 0x11 |
||||
#define KEY_O 0x12 |
||||
#define KEY_P 0x13 |
||||
#define KEY_Q 0x14 |
||||
#define KEY_R 0x15 |
||||
#define KEY_S 0x16 |
||||
#define KEY_T 0x17 |
||||
#define KEY_U 0x18 |
||||
#define KEY_V 0x19 |
||||
#define KEY_W 0x1A |
||||
#define KEY_X 0x1B |
||||
#define KEY_Y 0x1C |
||||
#define KEY_Z 0x1D |
||||
#define KEY_1_EXCLAMATION_MARK 0x1E |
||||
#define KEY_2_AT 0x1F |
||||
#define KEY_3_NUMBER_SIGN 0x20 |
||||
#define KEY_4_DOLLAR 0x21 |
||||
#define KEY_5_PERCENT 0x22 |
||||
#define KEY_6_CARET 0x23 |
||||
#define KEY_7_AMPERSAND 0x24 |
||||
#define KEY_8_ASTERISK 0x25 |
||||
#define KEY_9_OPARENTHESIS 0x26 |
||||
#define KEY_0_CPARENTHESIS 0x27 |
||||
#define KEY_ENTER 0x28 |
||||
#define KEY_ESCAPE 0x29 |
||||
#define KEY_BACKSPACE 0x2A |
||||
#define KEY_TAB 0x2B |
||||
#define KEY_SPACEBAR 0x2C |
||||
#define KEY_MINUS_UNDERSCORE 0x2D |
||||
#define KEY_EQUAL_PLUS 0x2E |
||||
#define KEY_OBRACKET_AND_OBRACE 0x2F |
||||
#define KEY_CBRACKET_AND_CBRACE 0x30 |
||||
#define KEY_BACKSLASH_VERTICAL_BAR 0x31 |
||||
#define KEY_NONUS_NUMBER_SIGN_TILDE 0x32 |
||||
#define KEY_SEMICOLON_COLON 0x33 |
||||
#define KEY_SINGLE_AND_DOUBLE_QUOTE 0x34 |
||||
#define KEY_GRAVE ACCENT AND TILDE 0x35 |
||||
#define KEY_COMMA_AND_LESS 0x36 |
||||
#define KEY_DOT_GREATER 0x37 |
||||
#define KEY_SLASH_QUESTION 0x38 |
||||
#define KEY_CAPS LOCK 0x39 |
||||
#define KEY_F1 0x3A |
||||
#define KEY_F2 0x3B |
||||
#define KEY_F3 0x3C |
||||
#define KEY_F4 0x3D |
||||
#define KEY_F5 0x3E |
||||
#define KEY_F6 0x3F |
||||
#define KEY_F7 0x40 |
||||
#define KEY_F8 0x41 |
||||
#define KEY_F9 0x42 |
||||
#define KEY_F10 0x43 |
||||
#define KEY_F11 0x44 |
||||
#define KEY_F12 0x45 |
||||
#define KEY_PRINTSCREEN 0x46 |
||||
#define KEY_SCROLL LOCK 0x47 |
||||
#define KEY_PAUSE 0x48 |
||||
#define KEY_INSERT 0x49 |
||||
#define KEY_HOME 0x4A |
||||
#define KEY_PAGEUP 0x4B |
||||
#define KEY_DELETE 0x4C |
||||
#define KEY_END1 0x4D |
||||
#define KEY_PAGEDOWN 0x4E |
||||
#define KEY_RIGHTARROW 0x4F |
||||
#define KEY_LEFTARROW 0x50 |
||||
#define KEY_DOWNARROW 0x51 |
||||
#define KEY_UPARROW 0x52 |
||||
#define KEY_KEYPAD_NUM_LOCK_AND_CLEAR 0x53 |
||||
#define KEY_KEYPAD_SLASH 0x54 |
||||
#define KEY_KEYPAD_ASTERIKS 0x55 |
||||
#define KEY_KEYPAD_MINUS 0x56 |
||||
#define KEY_KEYPAD_PLUS 0x57 |
||||
#define KEY_KEYPAD_ENTER 0x58 |
||||
#define KEY_KEYPAD_1_END 0x59 |
||||
#define KEY_KEYPAD_2_DOWN_ARROW 0x5A |
||||
#define KEY_KEYPAD_3_PAGEDN 0x5B |
||||
#define KEY_KEYPAD_4_LEFT_ARROW 0x5C |
||||
#define KEY_KEYPAD_5 0x5D |
||||
#define KEY_KEYPAD_6_RIGHT_ARROW 0x5E |
||||
#define KEY_KEYPAD_7_HOME 0x5F |
||||
#define KEY_KEYPAD_8_UP_ARROW 0x60 |
||||
#define KEY_KEYPAD_9_PAGEUP 0x61 |
||||
#define KEY_KEYPAD_0_INSERT 0x62 |
||||
#define KEY_KEYPAD_DECIMAL_SEPARATOR_DELETE 0x63 |
||||
#define KEY_NONUS_BACK_SLASH_VERTICAL_BAR 0x64 |
||||
#define KEY_APPLICATION 0x65 |
||||
#define KEY_POWER 0x66 |
||||
#define KEY_KEYPAD_EQUAL 0x67 |
||||
#define KEY_F13 0x68 |
||||
#define KEY_F14 0x69 |
||||
#define KEY_F15 0x6A |
||||
#define KEY_F16 0x6B |
||||
#define KEY_F17 0x6C |
||||
#define KEY_F18 0x6D |
||||
#define KEY_F19 0x6E |
||||
#define KEY_F20 0x6F |
||||
#define KEY_F21 0x70 |
||||
#define KEY_F22 0x71 |
||||
#define KEY_F23 0x72 |
||||
#define KEY_F24 0x73 |
||||
// #define KEY_EXECUTE 0x74
|
||||
#define KEY_HELP 0x75 |
||||
#define KEY_MENU 0x76 |
||||
#define KEY_SELECT 0x77 |
||||
#define KEY_STOP 0x78 |
||||
#define KEY_AGAIN 0x79 |
||||
#define KEY_UNDO 0x7A |
||||
#define KEY_CUT 0x7B |
||||
#define KEY_COPY 0x7C |
||||
#define KEY_PASTE 0x7D |
||||
#define KEY_FIND 0x7E |
||||
#define KEY_MUTE 0x7F |
||||
#define KEY_VOLUME_UP 0x80 |
||||
#define KEY_VOLUME_DOWN 0x81 |
||||
#define KEY_LOCKING_CAPS_LOCK 0x82 |
||||
#define KEY_LOCKING_NUM_LOCK 0x83 |
||||
#define KEY_LOCKING_SCROLL_LOCK 0x84 |
||||
#define KEY_KEYPAD_COMMA 0x85 |
||||
#define KEY_KEYPAD_EQUAL_SIGN 0x86 |
||||
#define KEY_INTERNATIONAL1 0x87 |
||||
#define KEY_INTERNATIONAL2 0x88 |
||||
#define KEY_INTERNATIONAL3 0x89 |
||||
#define KEY_INTERNATIONAL4 0x8A |
||||
#define KEY_INTERNATIONAL5 0x8B |
||||
#define KEY_INTERNATIONAL6 0x8C |
||||
#define KEY_INTERNATIONAL7 0x8D |
||||
#define KEY_INTERNATIONAL8 0x8E |
||||
#define KEY_INTERNATIONAL9 0x8F |
||||
#define KEY_LANG1 0x90 |
||||
#define KEY_LANG2 0x91 |
||||
#define KEY_LANG3 0x92 |
||||
#define KEY_LANG4 0x93 |
||||
#define KEY_LANG5 0x94 |
||||
#define KEY_LANG6 0x95 |
||||
#define KEY_LANG7 0x96 |
||||
#define KEY_LANG8 0x97 |
||||
#define KEY_LANG9 0x98 |
||||
#define KEY_ALTERNATE_ERASE 0x99 |
||||
#define KEY_SYSREQ 0x9A |
||||
#define KEY_CANCEL 0x9B |
||||
#define KEY_CLEAR 0x9C |
||||
#define KEY_PRIOR 0x9D |
||||
#define KEY_RETURN 0x9E |
||||
#define KEY_SEPARATOR 0x9F |
||||
#define KEY_OUT 0xA0 |
||||
#define KEY_OPER 0xA1 |
||||
#define KEY_CLEAR_AGAIN 0xA2 |
||||
#define KEY_CRSEL 0xA3 |
||||
#define KEY_EXSEL 0xA4 |
||||
#define KEY_KEYPAD_00 0xB0 |
||||
#define KEY_KEYPAD_000 0xB1 |
||||
#define KEY_THOUSANDS_SEPARATOR 0xB2 |
||||
#define KEY_DECIMAL_SEPARATOR 0xB3 |
||||
#define KEY_CURRENCY_UNIT 0xB4 |
||||
#define KEY_CURRENCY_SUB_UNIT 0xB5 |
||||
#define KEY_KEYPAD_OPARENTHESIS 0xB6 |
||||
#define KEY_KEYPAD_CPARENTHESIS 0xB7 |
||||
#define KEY_KEYPAD_OBRACE 0xB8 |
||||
#define KEY_KEYPAD_CBRACE 0xB9 |
||||
#define KEY_KEYPAD_TAB 0xBA |
||||
#define KEY_KEYPAD_BACKSPACE 0xBB |
||||
#define KEY_KEYPAD_A 0xBC |
||||
#define KEY_KEYPAD_B 0xBD |
||||
#define KEY_KEYPAD_C 0xBE |
||||
#define KEY_KEYPAD_D 0xBF |
||||
#define KEY_KEYPAD_E 0xC0 |
||||
#define KEY_KEYPAD_F 0xC1 |
||||
#define KEY_KEYPAD_XOR 0xC2 |
||||
#define KEY_KEYPAD_CARET 0xC3 |
||||
#define KEY_KEYPAD_PERCENT 0xC4 |
||||
#define KEY_KEYPAD_LESS 0xC5 |
||||
#define KEY_KEYPAD_GREATER 0xC6 |
||||
#define KEY_KEYPAD_AMPERSAND 0xC7 |
||||
#define KEY_KEYPAD_LOGICAL_AND 0xC8 |
||||
#define KEY_KEYPAD_VERTICAL_BAR 0xC9 |
||||
#define KEY_KEYPAD_LOGIACL_OR 0xCA |
||||
#define KEY_KEYPAD_COLON 0xCB |
||||
#define KEY_KEYPAD_NUMBER_SIGN 0xCC |
||||
#define KEY_KEYPAD_SPACE 0xCD |
||||
#define KEY_KEYPAD_AT 0xCE |
||||
#define KEY_KEYPAD_EXCLAMATION_MARK 0xCF |
||||
#define KEY_KEYPAD_MEMORY_STORE 0xD0 |
||||
#define KEY_KEYPAD_MEMORY_RECALL 0xD1 |
||||
#define KEY_KEYPAD_MEMORY_CLEAR 0xD2 |
||||
#define KEY_KEYPAD_MEMORY_ADD 0xD3 |
||||
#define KEY_KEYPAD_MEMORY_SUBTRACT 0xD4 |
||||
#define KEY_KEYPAD_MEMORY_MULTIPLY 0xD5 |
||||
#define KEY_KEYPAD_MEMORY_DIVIDE 0xD6 |
||||
#define KEY_KEYPAD_PLUSMINUS 0xD7 |
||||
#define KEY_KEYPAD_CLEAR 0xD8 |
||||
#define KEY_KEYPAD_CLEAR_ENTRY 0xD9 |
||||
#define KEY_KEYPAD_BINARY 0xDA |
||||
#define KEY_KEYPAD_OCTAL 0xDB |
||||
#define KEY_KEYPAD_DECIMAL 0xDC |
||||
#define KEY_KEYPAD_HEXADECIMAL 0xDD |
||||
#define KEY_LEFTCONTROL 0xE0 |
||||
#define KEY_LEFTSHIFT 0xE1 |
||||
#define KEY_LEFTALT 0xE2 |
||||
#define KEY_LEFT_GUI 0xE3 |
||||
#define KEY_RIGHTCONTROL 0xE4 |
||||
#define KEY_RIGHTSHIFT 0xE5 |
||||
#define KEY_RIGHTALT 0xE6 |
||||
#define KEY_RIGHT_GUI 0xE7 |
||||
#endif // EEZ_PLATFORM_STM32
|
||||
|
||||
} // keyboard
|
||||
} // eez
|
@ -1,99 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <assert.h> |
||||
|
||||
#include <eez/core/memory.h> |
||||
|
||||
namespace eez { |
||||
|
||||
#if defined(EEZ_PLATFORM_SIMULATOR) |
||||
uint8_t g_memory[MEMORY_SIZE] = { 0 }; |
||||
#endif |
||||
|
||||
uint8_t *DECOMPRESSED_ASSETS_START_ADDRESS; |
||||
uint8_t *FLOW_TO_DEBUGGER_MESSAGE_BUFFER; |
||||
|
||||
uint8_t *VRAM_BUFFER1_START_ADDRESS; |
||||
uint8_t *VRAM_BUFFER2_START_ADDRESS; |
||||
|
||||
uint8_t *VRAM_ANIMATION_BUFFER1_START_ADDRESS; |
||||
uint8_t *VRAM_ANIMATION_BUFFER2_START_ADDRESS; |
||||
|
||||
uint8_t *VRAM_AUX_BUFFER1_START_ADDRESS; |
||||
uint8_t *VRAM_AUX_BUFFER2_START_ADDRESS; |
||||
uint8_t *VRAM_AUX_BUFFER3_START_ADDRESS; |
||||
uint8_t *VRAM_AUX_BUFFER4_START_ADDRESS; |
||||
uint8_t *VRAM_AUX_BUFFER5_START_ADDRESS; |
||||
uint8_t *VRAM_AUX_BUFFER6_START_ADDRESS; |
||||
|
||||
uint8_t *SCREENSHOOT_BUFFER_START_ADDRESS; |
||||
|
||||
uint8_t *GUI_STATE_BUFFER; |
||||
|
||||
uint8_t *ALLOC_BUFFER; |
||||
uint32_t ALLOC_BUFFER_SIZE; |
||||
|
||||
void initMemory() { |
||||
initAssetsMemory(); |
||||
initOtherMemory(); |
||||
} |
||||
|
||||
void initAssetsMemory() { |
||||
ALLOC_BUFFER = MEMORY_BEGIN; |
||||
ALLOC_BUFFER_SIZE = MEMORY_SIZE; |
||||
|
||||
DECOMPRESSED_ASSETS_START_ADDRESS = allocBuffer(MAX_DECOMPRESSED_ASSETS_SIZE); |
||||
} |
||||
|
||||
void initOtherMemory() { |
||||
FLOW_TO_DEBUGGER_MESSAGE_BUFFER = allocBuffer(FLOW_TO_DEBUGGER_MESSAGE_BUFFER_SIZE); |
||||
|
||||
uint32_t VRAM_BUFFER_SIZE = DISPLAY_WIDTH * DISPLAY_HEIGHT * DISPLAY_BPP / 8; |
||||
|
||||
VRAM_BUFFER1_START_ADDRESS = allocBuffer(VRAM_BUFFER_SIZE); |
||||
VRAM_BUFFER2_START_ADDRESS = allocBuffer(VRAM_BUFFER_SIZE); |
||||
|
||||
VRAM_ANIMATION_BUFFER1_START_ADDRESS = allocBuffer(VRAM_BUFFER_SIZE); |
||||
VRAM_ANIMATION_BUFFER2_START_ADDRESS = allocBuffer(VRAM_BUFFER_SIZE); |
||||
|
||||
VRAM_AUX_BUFFER1_START_ADDRESS = allocBuffer(VRAM_BUFFER_SIZE); |
||||
VRAM_AUX_BUFFER2_START_ADDRESS = allocBuffer(VRAM_BUFFER_SIZE); |
||||
VRAM_AUX_BUFFER3_START_ADDRESS = allocBuffer(VRAM_BUFFER_SIZE); |
||||
VRAM_AUX_BUFFER4_START_ADDRESS = allocBuffer(VRAM_BUFFER_SIZE); |
||||
VRAM_AUX_BUFFER5_START_ADDRESS = allocBuffer(VRAM_BUFFER_SIZE); |
||||
VRAM_AUX_BUFFER6_START_ADDRESS = allocBuffer(VRAM_BUFFER_SIZE); |
||||
|
||||
GUI_STATE_BUFFER = allocBuffer(GUI_STATE_BUFFER_SIZE); |
||||
|
||||
SCREENSHOOT_BUFFER_START_ADDRESS = VRAM_ANIMATION_BUFFER1_START_ADDRESS; |
||||
} |
||||
|
||||
uint8_t *allocBuffer(uint32_t size) { |
||||
size = ((size + 1023) / 1024) * 1024; |
||||
|
||||
auto buffer = ALLOC_BUFFER; |
||||
|
||||
assert(ALLOC_BUFFER_SIZE > size); |
||||
ALLOC_BUFFER += size; |
||||
ALLOC_BUFFER_SIZE -= size; |
||||
|
||||
return buffer; |
||||
} |
||||
|
||||
} // eez
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
#include <eez/conf.h> |
||||
|
||||
namespace eez { |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
static uint8_t * const MEMORY_BEGIN = (uint8_t *)0xc0000000u; |
||||
#if CONF_OPTION_FPGA |
||||
static const uint32_t MEMORY_SIZE = 32 * 1024 * 1024; |
||||
#elif defined(EEZ_PLATFORM_STM32F469I_DISCO) |
||||
static const uint32_t MEMORY_SIZE = 8 * 1024 * 1024; |
||||
#else |
||||
static const uint32_t MEMORY_SIZE = 8 * 1024 * 1024; |
||||
#endif |
||||
#endif |
||||
|
||||
#if defined(EEZ_PLATFORM_SIMULATOR) |
||||
extern uint8_t g_memory[]; |
||||
static uint8_t * const MEMORY_BEGIN = g_memory; |
||||
static const uint32_t MEMORY_SIZE = 64 * 1024 * 1024; |
||||
#endif |
||||
|
||||
extern uint8_t *ALLOC_BUFFER; |
||||
extern uint32_t ALLOC_BUFFER_SIZE; |
||||
|
||||
extern uint8_t *DECOMPRESSED_ASSETS_START_ADDRESS; |
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
static const uint32_t MAX_DECOMPRESSED_ASSETS_SIZE = 2 * 1024 * 1024; |
||||
#endif |
||||
#if defined(EEZ_PLATFORM_SIMULATOR) |
||||
static const uint32_t MAX_DECOMPRESSED_ASSETS_SIZE = 8 * 1024 * 1024; |
||||
#endif |
||||
|
||||
extern uint8_t *FLOW_TO_DEBUGGER_MESSAGE_BUFFER; |
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
static const uint32_t FLOW_TO_DEBUGGER_MESSAGE_BUFFER_SIZE = 32 * 1024; |
||||
#endif |
||||
#if defined(EEZ_PLATFORM_SIMULATOR) |
||||
static const uint32_t FLOW_TO_DEBUGGER_MESSAGE_BUFFER_SIZE = 1024 * 1024; |
||||
#endif |
||||
|
||||
extern uint8_t *VRAM_BUFFER1_START_ADDRESS; |
||||
extern uint8_t *VRAM_BUFFER2_START_ADDRESS; |
||||
|
||||
extern uint8_t *VRAM_ANIMATION_BUFFER1_START_ADDRESS; |
||||
extern uint8_t *VRAM_ANIMATION_BUFFER2_START_ADDRESS; |
||||
|
||||
extern uint8_t *VRAM_AUX_BUFFER1_START_ADDRESS; |
||||
extern uint8_t *VRAM_AUX_BUFFER2_START_ADDRESS; |
||||
extern uint8_t *VRAM_AUX_BUFFER3_START_ADDRESS; |
||||
extern uint8_t *VRAM_AUX_BUFFER4_START_ADDRESS; |
||||
extern uint8_t *VRAM_AUX_BUFFER5_START_ADDRESS; |
||||
extern uint8_t *VRAM_AUX_BUFFER6_START_ADDRESS; |
||||
|
||||
extern uint8_t* SCREENSHOOT_BUFFER_START_ADDRESS; |
||||
|
||||
extern uint8_t* GUI_STATE_BUFFER; |
||||
|
||||
void initMemory(); |
||||
void initAssetsMemory(); |
||||
void initOtherMemory(); |
||||
uint8_t *allocBuffer(uint32_t size); |
||||
|
||||
} // eez
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic 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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/gui/event.h> |
||||
|
||||
namespace eez { |
||||
namespace mouse { |
||||
|
||||
bool isMouseEnabled(); |
||||
|
||||
bool isDisplayDirty(); |
||||
void updateDisplay(); |
||||
|
||||
void onPageChanged(); |
||||
|
||||
#if defined(EEZ_PLATFORM_SIMULATOR) |
||||
void onMouseEvent(bool mouseButton1IsPressed, int mouseX, int mouseY); |
||||
#endif |
||||
|
||||
} // mouse
|
||||
} // eez
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2018-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
#include <main.h> |
||||
#endif |
||||
|
||||
#include <eez/core/os.h> |
||||
|
||||
namespace eez { |
||||
|
||||
uint32_t millis() { |
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
return HAL_GetTick(); |
||||
#endif |
||||
|
||||
#if defined(EEZ_PLATFORM_SIMULATOR) |
||||
return osKernelGetTickCount(); |
||||
#endif |
||||
} |
||||
|
||||
} // namespace eez
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include "cmsis_os2.h" |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
#include "FreeRTOS.h" |
||||
#include "task.h" |
||||
#endif |
||||
|
||||
#define EEZ_THREAD_DECLARE(NAME, PRIORITY, STACK_SIZE) \ |
||||
osThreadId_t g_##NAME##TaskHandle; \
|
||||
const osThreadAttr_t g_##NAME##TaskAttributes = { \
|
||||
#NAME, \ |
||||
0, \
|
||||
0, \
|
||||
0, \
|
||||
0, \
|
||||
STACK_SIZE, \
|
||||
osPriority##PRIORITY, \
|
||||
0, \
|
||||
0, \
|
||||
} |
||||
#define EEZ_THREAD_CREATE(NAME, THREAD_FUNC) g_##NAME##TaskHandle = osThreadNew(THREAD_FUNC, nullptr, &g_##NAME##TaskAttributes); |
||||
#define EEZ_THREAD_TERMINATE(NAME) osThreadTerminate(g_##NAME##TaskHandle) |
||||
|
||||
#define EEZ_MESSAGE_QUEUE_DECLARE(NAME, OBJECT_DEF) \ |
||||
struct NAME##MessageQueueObject OBJECT_DEF; \
|
||||
osMessageQueueId_t g_##NAME##MessageQueueId |
||||
#define EEZ_MESSAGE_QUEUE_CREATE(NAME, QUEUE_SIZE) g_##NAME##MessageQueueId = osMessageQueueNew(QUEUE_SIZE, sizeof(NAME##MessageQueueObject), nullptr) |
||||
#define EEZ_MESSAGE_QUEUE_GET(NAME, OBJ, TIMEOUT) (osMessageQueueGet(g_##NAME##MessageQueueId, &OBJ, nullptr, TIMEOUT) == osOK) |
||||
#define EEZ_MESSAGE_QUEUE_PUT(NAME, OBJ, TIMEOUT) osMessageQueuePut(g_##NAME##MessageQueueId, &OBJ, 0, TIMEOUT) |
||||
|
||||
#define EEZ_MUTEX_DECLARE(NAME) \ |
||||
osMutexId_t g_##NAME##mutexId;\
|
||||
const osMutexAttr_t g_##NAME##mutexAttr = { \
|
||||
#NAME, \ |
||||
osMutexRecursive | osMutexPrioInherit, \
|
||||
NULL, \
|
||||
0U \
|
||||
} |
||||
#define EEZ_MUTEX_CREATE(NAME) g_##NAME##mutexId = osMutexNew(&g_##NAME##mutexAttr) |
||||
#define EEZ_MUTEX_WAIT(NAME, TIMEOUT) osMutexAcquire(g_##NAME##mutexId, TIMEOUT) == osOK |
||||
#define EEZ_MUTEX_RELEASE(NAME) osMutexRelease(g_##NAME##mutexId) |
||||
|
||||
#if defined(__EMSCRIPTEN__) |
||||
#ifndef EM_PORT_API |
||||
# if defined(__EMSCRIPTEN__) |
||||
# include <emscripten.h> |
||||
# if defined(__cplusplus) |
||||
# define EM_PORT_API(rettype) extern "C" rettype EMSCRIPTEN_KEEPALIVE |
||||
# else |
||||
# define EM_PORT_API(rettype) rettype EMSCRIPTEN_KEEPALIVE |
||||
# endif |
||||
# else |
||||
# if defined(__cplusplus) |
||||
# define EM_PORT_API(rettype) extern "C" rettype |
||||
# else |
||||
# define EM_PORT_API(rettype) rettype |
||||
# endif |
||||
# endif |
||||
#endif |
||||
#else |
||||
# define EM_PORT_API(rettype) rettype |
||||
#endif |
||||
|
||||
namespace eez { |
||||
|
||||
enum TestResult { |
||||
TEST_NONE, |
||||
TEST_FAILED, |
||||
TEST_OK, |
||||
TEST_CONNECTING, |
||||
TEST_SKIPPED, |
||||
TEST_WARNING |
||||
}; |
||||
|
||||
uint32_t millis(); |
||||
|
||||
extern bool g_shutdown; |
||||
void shutdown(); |
||||
|
||||
} // namespace eez
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
|
||||
namespace eez { |
||||
namespace sound { |
||||
|
||||
void init(); |
||||
void tick(); |
||||
|
||||
/// Play power up tune.
|
||||
enum PlayPowerUpCondition { |
||||
PLAY_POWER_UP_CONDITION_NONE, |
||||
PLAY_POWER_UP_CONDITION_TEST_SUCCESSFUL, |
||||
PLAY_POWER_UP_CONDITION_WELCOME_PAGE_IS_ACTIVE |
||||
}; |
||||
|
||||
void playPowerUp(PlayPowerUpCondition condition); |
||||
|
||||
/// Play power down tune.
|
||||
void playPowerDown(); |
||||
|
||||
/// Play beep sound.
|
||||
void playBeep(bool force = false); |
||||
|
||||
/// Play click sound
|
||||
void playClick(); |
||||
|
||||
/// Play shutter sound
|
||||
void playShutter(); |
||||
|
||||
} // namespace sound
|
||||
} // namespace eez
|
@ -1,30 +0,0 @@
|
||||
#pragma once |
||||
|
||||
#include <eez/core/unit.h> |
||||
|
||||
namespace eez { |
||||
|
||||
enum EncoderMode { |
||||
ENCODER_MODE_MIN, |
||||
ENCODER_MODE_AUTO = ENCODER_MODE_MIN, |
||||
ENCODER_MODE_STEP1, |
||||
ENCODER_MODE_STEP2, |
||||
ENCODER_MODE_STEP3, |
||||
ENCODER_MODE_STEP4, |
||||
ENCODER_MODE_STEP5, |
||||
ENCODER_MODE_MAX = ENCODER_MODE_STEP5 |
||||
}; |
||||
|
||||
struct StepValues { |
||||
int count; |
||||
const float *values; |
||||
Unit unit; |
||||
struct { |
||||
bool accelerationEnabled; |
||||
float range; |
||||
float step; |
||||
EncoderMode mode; |
||||
} encoderSettings; |
||||
}; |
||||
|
||||
} // namespace eez
|
@ -1,309 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2018-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <eez/core/unit.h> |
||||
|
||||
#if OPTION_SCPI |
||||
#include <scpi/types.h> |
||||
#endif |
||||
|
||||
namespace eez { |
||||
|
||||
const char *g_unitNames[] = { |
||||
"", // UNIT_NONE
|
||||
"V", // UNIT_VOLT
|
||||
"mV", // UNIT_MILLI_VOLT
|
||||
"A", // UNIT_AMPER
|
||||
"mA", // UNIT_MILLI_AMPER
|
||||
"uA", // UNIT_MICRO_AMPER
|
||||
"W", // UNIT_WATT
|
||||
"mW", // UNIT_MILLI_WATT
|
||||
"s", // UNIT_SECOND
|
||||
"ms", // UNIT_MILLI_SECOND
|
||||
DEGREE_SYMBOL"C", // UNIT_CELSIUS
|
||||
"rpm", // UNIT_RPM
|
||||
"\xb4", // UNIT_OHM
|
||||
"K\xb4", // UNIT_KOHM
|
||||
"M\xb4", // UNIT_MOHM
|
||||
"%", // UNIT_PERCENT
|
||||
"Hz", // UNIT_HERTZ
|
||||
"mHz", // UNIT_MILLI_HERTZ
|
||||
"KHz", // UNIT_KHERTZ
|
||||
"MHz", // UNIT_MHERTZ
|
||||
"J", // UNIT_JOULE
|
||||
"F", // UNIT_FARAD
|
||||
"mF", // UNIT_MILLI_FARAD
|
||||
"uF", // UNIT_MICRO_FARAD
|
||||
"nF", // UNIT_NANO_FARAD
|
||||
"pF", // UNIT_PICO_FARAD
|
||||
"minutes", // UNIT_MINUTE
|
||||
"VA", // UNIT_VOLT_AMPERE
|
||||
"VAR", // UNIT_VOLT_AMPERE_REACTIVE
|
||||
DEGREE_SYMBOL, // UNIT_DEGREE
|
||||
"Vpp", // UNIT_VOLT_PP
|
||||
"mVpp", // UNIT_MILLI_VOLT_PP
|
||||
"App", // UNIT_AMPER_PP
|
||||
"mApp", // UNIT_MILLI_AMPER_PP
|
||||
"uApp", // UNIT_MICRO_AMPER_PP
|
||||
}; |
||||
|
||||
const Unit g_baseUnit[] = { |
||||
UNIT_NONE, // UNIT_NONE
|
||||
UNIT_VOLT, // UNIT_VOLT
|
||||
UNIT_VOLT, // UNIT_MILLI_VOLT
|
||||
UNIT_AMPER, // UNIT_AMPER
|
||||
UNIT_AMPER, // UNIT_MILLI_AMPER
|
||||
UNIT_AMPER, // UNIT_MICRO_AMPER
|
||||
UNIT_WATT, // UNIT_WATT
|
||||
UNIT_WATT, // UNIT_MILLI_WATT
|
||||
UNIT_SECOND, // UNIT_SECOND
|
||||
UNIT_SECOND, // UNIT_MILLI_SECOND
|
||||
UNIT_CELSIUS, // UNIT_CELSIUS
|
||||
UNIT_RPM, // UNIT_RPM
|
||||
UNIT_OHM, // UNIT_OHM
|
||||
UNIT_OHM, // UNIT_KOHM
|
||||
UNIT_OHM, // UNIT_MOHM
|
||||
UNIT_PERCENT, // UNIT_PERCENT
|
||||
UNIT_HERTZ, // UNIT_HERTZ
|
||||
UNIT_HERTZ, // UNIT_MILLI_HERTZ
|
||||
UNIT_HERTZ, // UNIT_KHERTZ
|
||||
UNIT_HERTZ, // UNIT_MHERTZ
|
||||
UNIT_JOULE, // UNIT_JOULE
|
||||
UNIT_FARAD, // UNIT_FARAD
|
||||
UNIT_FARAD, // UNIT_MILLI_FARAD
|
||||
UNIT_FARAD, // UNIT_MICRO_FARAD
|
||||
UNIT_FARAD, // UNIT_NANO_FARAD
|
||||
UNIT_FARAD, // UNIT_PICO_FARAD
|
||||
UNIT_SECOND, // UNIT_MINUTE
|
||||
UNIT_VOLT_AMPERE, // UNIT_VOLT_AMPERE
|
||||
UNIT_VOLT_AMPERE, //UNIT_VOLT_AMPERE_REACTIVE
|
||||
UNIT_DEGREE, // UNIT_DEGREE
|
||||
UNIT_VOLT_PP, // UNIT_VOLT_PP
|
||||
UNIT_VOLT_PP, // UNIT_MILLI_VOLT_PP
|
||||
UNIT_AMPER_PP, // UNIT_AMPER_PP
|
||||
UNIT_AMPER_PP, // UNIT_MILLI_AMPER_PP
|
||||
UNIT_AMPER_PP, // UNIT_MICRO_AMPER_PP
|
||||
}; |
||||
|
||||
const float g_unitFactor[] = { |
||||
1.0f, // UNIT_NONE
|
||||
1.0f, // UNIT_VOLT
|
||||
1E-3f, // UNIT_MILLI_VOLT
|
||||
1.0f, // UNIT_AMPER
|
||||
1E-3f, // UNIT_MILLI_AMPER
|
||||
1E-6f, // UNIT_MICRO_AMPER
|
||||
1.0f, // UNIT_WATT
|
||||
1E-3f, // UNIT_MILLI_WATT
|
||||
1.0f, // UNIT_SECOND
|
||||
1E-3f, // UNIT_MILLI_SECOND
|
||||
1.0f, // UNIT_CELSIUS
|
||||
1.0f, // UNIT_RPM
|
||||
1.0f, // UNIT_OHM
|
||||
1E3f, // UNIT_KOHM
|
||||
1E6f, // UNIT_MOHM
|
||||
1.0f, // UNIT_PERCENT
|
||||
1.0f, // UNIT_HERTZ
|
||||
1E-3f, // UNIT_MILLI_HERTZ
|
||||
1E3f, // UNIT_KHERTZ
|
||||
1E6f, // UNIT_MHERTZ
|
||||
1.0f, // UNIT_JOULE
|
||||
1.0f, // UNIT_FARAD
|
||||
1E-3f, // UNIT_MILLI_FARAD
|
||||
1E-6f, // UNIT_MICRO_FARAD
|
||||
1E-9f, // UNIT_NANO_FARAD
|
||||
1E-12f, // UNIT_PICO_FARAD
|
||||
60.0f, // UNIT_MINUTE
|
||||
1.0f, // UNIT_VOLT_AMPERE
|
||||
1.0f, //UNIT_VOLT_AMPERE_REACTIVE
|
||||
1.0f, // UNIT_DEGREE
|
||||
1.0f, // UNIT_VOLT_PP
|
||||
1E-3f, // UNIT_MILLI_VOLT_PP
|
||||
1.0f, // UNIT_AMPER_PP
|
||||
1E-3f, // UNIT_MILLI_AMPER_PP
|
||||
1E-6f, // UNIT_MICRO_AMPER_PP
|
||||
}; |
||||
|
||||
#if OPTION_SCPI |
||||
static const int g_scpiUnits[] = { |
||||
SCPI_UNIT_NONE, // UNIT_NONE
|
||||
SCPI_UNIT_VOLT, // UNIT_VOLT
|
||||
SCPI_UNIT_VOLT, // UNIT_MILLI_VOLT
|
||||
SCPI_UNIT_AMPER, // UNIT_AMPER
|
||||
SCPI_UNIT_AMPER, // UNIT_MILLI_AMPER
|
||||
SCPI_UNIT_AMPER, // UNIT_MICRO_AMPER
|
||||
SCPI_UNIT_WATT, // UNIT_WATT
|
||||
SCPI_UNIT_WATT, // UNIT_MILLI_WATT
|
||||
SCPI_UNIT_SECOND, // UNIT_SECOND
|
||||
SCPI_UNIT_SECOND, // UNIT_MILLI_SECOND
|
||||
SCPI_UNIT_CELSIUS, // UNIT_CELSIUS
|
||||
SCPI_UNIT_NONE, // UNIT_RPM
|
||||
SCPI_UNIT_OHM, // UNIT_OHM
|
||||
SCPI_UNIT_OHM, // UNIT_KOHM
|
||||
SCPI_UNIT_OHM, // UNIT_MOHM
|
||||
SCPI_UNIT_NONE, // UNIT_PERCENT
|
||||
SCPI_UNIT_HERTZ, // UNIT_HERTZ
|
||||
SCPI_UNIT_HERTZ, // UNIT_MILLI_HERTZ
|
||||
SCPI_UNIT_HERTZ, // UNIT_KHERTZ
|
||||
SCPI_UNIT_HERTZ, // UNIT_MHERTZ
|
||||
SCPI_UNIT_JOULE, // UNIT_JOULE
|
||||
SCPI_UNIT_FARAD, // UNIT_FARAD
|
||||
SCPI_UNIT_FARAD, // UNIT_MILLI_FARAD
|
||||
SCPI_UNIT_FARAD, // UNIT_MICRO_FARAD
|
||||
SCPI_UNIT_FARAD, // UNIT_NANO_FARAD
|
||||
SCPI_UNIT_FARAD, // UNIT_PICO_FARAD
|
||||
SCPI_UNIT_SECOND, // UNIT_MINUTE
|
||||
SCPI_UNIT_WATT, // UNIT_VOLT_AMPERE
|
||||
SCPI_UNIT_WATT, // UNIT_VOLT_AMPERE_REACTIVE
|
||||
SCPI_UNIT_DEGREE, // UNIT_DEGREE
|
||||
SCPI_UNIT_VOLT, // UNIT_VOLT_PP
|
||||
SCPI_UNIT_VOLT, // UNIT_MILLI_VOLT_PP
|
||||
SCPI_UNIT_AMPER, // UNIT_AMPER_PP
|
||||
SCPI_UNIT_AMPER, // UNIT_MILLI_AMPER_PP
|
||||
SCPI_UNIT_AMPER, // UNIT_MICRO_AMPER_PP
|
||||
}; |
||||
#endif |
||||
|
||||
Unit getUnitFromName(const char *unitName) { |
||||
if (unitName) { |
||||
for (unsigned i = 0; i < sizeof(g_unitNames) / sizeof(const char *); i++) { |
||||
if (strcmp(g_unitNames[i], unitName) == 0) { |
||||
return (Unit)i; |
||||
} |
||||
} |
||||
} |
||||
return UNIT_NONE; |
||||
} |
||||
|
||||
#if OPTION_SCPI |
||||
int getScpiUnit(Unit unit) { |
||||
if (unit == UNIT_UNKNOWN) { |
||||
return SCPI_UNIT_NONE; |
||||
} |
||||
return g_scpiUnits[unit]; |
||||
} |
||||
#endif |
||||
|
||||
Unit getBaseUnit(Unit unit) { |
||||
if (unit == UNIT_UNKNOWN) { |
||||
return UNIT_UNKNOWN; |
||||
} |
||||
return g_baseUnit[unit]; |
||||
} |
||||
|
||||
float getUnitFactor(Unit unit) { |
||||
if (unit == UNIT_UNKNOWN) { |
||||
return 1.0f; |
||||
} |
||||
return g_unitFactor[unit]; |
||||
} |
||||
|
||||
static Unit getDerivedUnit(Unit unit, float factor) { |
||||
if (unit == UNIT_UNKNOWN) { |
||||
return UNIT_UNKNOWN; |
||||
} |
||||
|
||||
for (size_t i = 0; i < sizeof(g_baseUnit); i++) { |
||||
if (g_baseUnit[i] == g_baseUnit[unit] && g_unitFactor[i] == factor) { |
||||
return (Unit)i; |
||||
} |
||||
} |
||||
|
||||
return UNIT_UNKNOWN; |
||||
} |
||||
|
||||
static const float FACTORS[] = { 1E-12F, 1E-9F, 1E-6F, 1E-3F, 1E0F, 1E3F, 1E6F, 1E9F, 1E12F }; |
||||
|
||||
Unit findDerivedUnit(float value, Unit unit) { |
||||
Unit result; |
||||
|
||||
for (int factorIndex = 1; ; factorIndex++) { |
||||
float factor = FACTORS[factorIndex]; |
||||
if (factor > 1.0F) { |
||||
break; |
||||
} |
||||
if (value < factor) { |
||||
result = getDerivedUnit(unit, FACTORS[factorIndex - 1]); |
||||
if (result != UNIT_UNKNOWN) { |
||||
return result; |
||||
} |
||||
} |
||||
} |
||||
|
||||
for (int factorIndex = sizeof(FACTORS) / sizeof(float) - 1; factorIndex >= 0; factorIndex--) { |
||||
float factor = FACTORS[factorIndex]; |
||||
if (factor == 1.0F) { |
||||
break; |
||||
} |
||||
if (value >= factor) { |
||||
result = getDerivedUnit(unit, factor); |
||||
if (result != UNIT_UNKNOWN) { |
||||
return result; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return unit; |
||||
} |
||||
|
||||
float getSmallerFactor(float factor) { |
||||
for (int factorIndex = sizeof(FACTORS) / sizeof(float) - 1; factorIndex > 0; factorIndex--) { |
||||
float itFactor = FACTORS[factorIndex]; |
||||
if (itFactor < factor) { |
||||
return itFactor; |
||||
} |
||||
} |
||||
return FACTORS[0]; |
||||
} |
||||
|
||||
Unit getSmallerUnit(Unit unit, float min, float precision) { |
||||
float factor = getUnitFactor(unit); |
||||
if (precision <= factor || min <= factor) { |
||||
return getDerivedUnit(unit, getSmallerFactor(factor)); |
||||
} |
||||
return UNIT_UNKNOWN; |
||||
} |
||||
|
||||
Unit getBiggestUnit(Unit unit, float max) { |
||||
for (int factorIndex = sizeof(FACTORS) / sizeof(float) - 1; factorIndex >= 0; factorIndex--) { |
||||
float factor = FACTORS[factorIndex]; |
||||
if (max >= factor) { |
||||
auto result = getDerivedUnit(unit, factor); |
||||
if (result != UNIT_UNKNOWN) { |
||||
return result; |
||||
} |
||||
} |
||||
} |
||||
return UNIT_UNKNOWN; |
||||
} |
||||
|
||||
Unit getSmallestUnit(Unit unit, float min, float precision) { |
||||
for (int factorIndex = 0; factorIndex < int(sizeof(FACTORS) / sizeof(float)); factorIndex++) { |
||||
float factor = FACTORS[factorIndex]; |
||||
if (precision <= factor || min <= factor) { |
||||
auto result = getDerivedUnit(unit, factor); |
||||
if (result != UNIT_UNKNOWN) { |
||||
return result; |
||||
} |
||||
} |
||||
} |
||||
return UNIT_UNKNOWN; |
||||
} |
||||
|
||||
} // namespace eez
|
@ -1,94 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2018-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#define INFINITY_SYMBOL "\x91" |
||||
#define DEGREE_SYMBOL "\x8a" |
||||
|
||||
namespace eez { |
||||
|
||||
// order of units should not be changed since it is used in DLOG files
|
||||
enum Unit { |
||||
UNIT_UNKNOWN = 255, |
||||
UNIT_NONE = 0, |
||||
UNIT_VOLT, |
||||
UNIT_MILLI_VOLT, |
||||
UNIT_AMPER, |
||||
UNIT_MILLI_AMPER, |
||||
UNIT_MICRO_AMPER, |
||||
UNIT_WATT, |
||||
UNIT_MILLI_WATT, |
||||
UNIT_SECOND, |
||||
UNIT_MILLI_SECOND, |
||||
UNIT_CELSIUS, |
||||
UNIT_RPM, |
||||
UNIT_OHM, |
||||
UNIT_KOHM, |
||||
UNIT_MOHM, |
||||
UNIT_PERCENT, |
||||
UNIT_HERTZ, |
||||
UNIT_MILLI_HERTZ, |
||||
UNIT_KHERTZ, |
||||
UNIT_MHERTZ, |
||||
UNIT_JOULE, |
||||
UNIT_FARAD, |
||||
UNIT_MILLI_FARAD, |
||||
UNIT_MICRO_FARAD, |
||||
UNIT_NANO_FARAD, |
||||
UNIT_PICO_FARAD, |
||||
UNIT_MINUTE, |
||||
UNIT_VOLT_AMPERE, |
||||
UNIT_VOLT_AMPERE_REACTIVE, |
||||
UNIT_DEGREE, |
||||
UNIT_VOLT_PP, |
||||
UNIT_MILLI_VOLT_PP, |
||||
UNIT_AMPER_PP, |
||||
UNIT_MILLI_AMPER_PP, |
||||
UNIT_MICRO_AMPER_PP, |
||||
}; |
||||
|
||||
extern const char *g_unitNames[]; |
||||
|
||||
inline const char *getUnitName(Unit unit) { |
||||
if (unit == UNIT_UNKNOWN) { |
||||
return ""; |
||||
} |
||||
return g_unitNames[unit]; |
||||
} |
||||
|
||||
Unit getUnitFromName(const char *unitName); |
||||
|
||||
#if OPTION_SCPI |
||||
int getScpiUnit(Unit unit); |
||||
#endif |
||||
|
||||
// for UNIT_MILLI_VOLT returns UNIT_VOLT, etc...
|
||||
Unit getBaseUnit(Unit unit); |
||||
|
||||
// returns 1.0 form UNIT_VOLT, returns 1E-3 for UNIT_MILLI_VOLT, 1E-6 for UNIT_MICRO_AMPER, 1E3 for UNIT_KOHM, etc
|
||||
float getUnitFactor(Unit unit); |
||||
|
||||
// if value is 0.01 and unit is UNIT_VOLT returns UNIT_MILLI_VOLT, etc
|
||||
Unit findDerivedUnit(float value, Unit unit); |
||||
|
||||
Unit getSmallerUnit(Unit unit, float min, float precision); |
||||
Unit getBiggestUnit(Unit unit, float max); |
||||
Unit getSmallestUnit(Unit unit, float min, float precision); |
||||
|
||||
} // namespace eez
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2018-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/conf.h> |
||||
|
||||
#ifndef UTF8_SUPPORT |
||||
#define UTF8_SUPPORT 1 |
||||
#endif |
||||
|
||||
#if UTF8_SUPPORT |
||||
|
||||
#include <eez/libs/utf8.h> |
||||
|
||||
#else |
||||
|
||||
typedef char utf8_int8_t; |
||||
typedef int32_t utf8_int32_t; |
||||
|
||||
inline const utf8_int8_t* utf8codepoint(const utf8_int8_t *str, utf8_int32_t *out_codepoint) { |
||||
*out_codepoint = *((uint8_t *)str); |
||||
return str + 1;
|
||||
} |
||||
|
||||
#define utf8len strlen |
||||
|
||||
#endif |
@ -1,921 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2018-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/core/util.h> |
||||
|
||||
#define _USE_MATH_DEFINES |
||||
#include <math.h> |
||||
#include <stdio.h> |
||||
#include <ctype.h> |
||||
#include <string.h> |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
#include <crc.h> |
||||
#endif |
||||
|
||||
namespace eez { |
||||
|
||||
float remap(float x, float x1, float y1, float x2, float y2) { |
||||
return y1 + (x - x1) * (y2 - y1) / (x2 - x1); |
||||
} |
||||
|
||||
float remapQuad(float x, float x1, float y1, float x2, float y2) { |
||||
float t = remap(x, x1, 0, x2, 1); |
||||
t = t * t; |
||||
x = remap(t, 0, x1, 1, x2); |
||||
return remap(x, x1, y1, x2, y2); |
||||
} |
||||
|
||||
float remapOutQuad(float x, float x1, float y1, float x2, float y2) { |
||||
float t = remap(x, x1, 0, x2, 1); |
||||
t = t * (2 - t); |
||||
x = remap(t, 0, x1, 1, x2); |
||||
return remap(x, x1, y1, x2, y2); |
||||
} |
||||
|
||||
float remapInOutQuad(float x, float x1, float y1, float x2, float y2) { |
||||
float t = remap(x, x1, 0, x2, 1); |
||||
t = t < .5 ? 2 * t*t : -1 + (4 - 2 * t)*t; |
||||
x = remap(t, 0, x1, 1, x2); |
||||
return remap(x, x1, y1, x2, y2); |
||||
} |
||||
|
||||
float remapCubic(float x, float x1, float y1, float x2, float y2) { |
||||
float t = remap(x, x1, 0, x2, 1); |
||||
t = t * t * t; |
||||
x = remap(t, 0, x1, 1, x2); |
||||
return remap(x, x1, y1, x2, y2); |
||||
} |
||||
|
||||
float remapOutCubic(float x, float x1, float y1, float x2, float y2) { |
||||
float t = remap(x, x1, 0, x2, 1); |
||||
t = t - 1; |
||||
t = 1 + t * t * t; |
||||
x = remap(t, 0, x1, 1, x2); |
||||
return remap(x, x1, y1, x2, y2); |
||||
} |
||||
|
||||
float remapExp(float x, float x1, float y1, float x2, float y2) { |
||||
float t = remap(x, x1, 0, x2, 1); |
||||
t = t == 0 ? 0 : float(pow(2, 10 * (t - 1))); |
||||
x = remap(t, 0, x1, 1, x2); |
||||
return remap(x, x1, y1, x2, y2); |
||||
} |
||||
|
||||
float remapOutExp(float x, float x1, float y1, float x2, float y2) { |
||||
float t = remap(x, x1, 0, x2, 1); |
||||
t = t == 1 ? 1 : float(1 - pow(2, -10 * t)); |
||||
x = remap(t, 0, x1, 1, x2); |
||||
return remap(x, x1, y1, x2, y2); |
||||
} |
||||
|
||||
float clamp(float x, float min, float max) { |
||||
if (x < min) { |
||||
return min; |
||||
} |
||||
if (x > max) { |
||||
return max; |
||||
} |
||||
return x; |
||||
} |
||||
|
||||
void stringCopy(char *dst, size_t maxStrLength, const char *src) { |
||||
strncpy(dst, src, maxStrLength); |
||||
dst[maxStrLength - 1] = 0; |
||||
} |
||||
|
||||
void stringCopyLength(char *dst, size_t maxStrLength, const char *src, size_t length) { |
||||
size_t n = MIN(length, maxStrLength); |
||||
strncpy(dst, src, n); |
||||
dst[n] = 0; |
||||
} |
||||
|
||||
void stringAppendString(char *str, size_t maxStrLength, const char *value) { |
||||
int n = maxStrLength - strlen(str) - 1; |
||||
if (n >= 0) { |
||||
strncat(str, value, n); |
||||
} |
||||
} |
||||
|
||||
void stringAppendStringLength(char *str, size_t maxStrLength, const char *value, size_t length) { |
||||
int n = MIN(maxStrLength - strlen(str) - 1, length); |
||||
if (n >= 0) { |
||||
strncat(str, value, n); |
||||
} |
||||
} |
||||
|
||||
void stringAppendInt(char *str, size_t maxStrLength, int value) { |
||||
auto n = strlen(str); |
||||
snprintf(str + n, maxStrLength - n, "%d", value); |
||||
} |
||||
|
||||
void stringAppendUInt32(char *str, size_t maxStrLength, uint32_t value) { |
||||
auto n = strlen(str); |
||||
snprintf(str + n, maxStrLength - n, "%lu", (unsigned long)value); |
||||
} |
||||
|
||||
void stringAppendInt64(char *str, size_t maxStrLength, int64_t value) { |
||||
auto n = strlen(str); |
||||
snprintf(str + n, maxStrLength - n, "%jd", value); |
||||
} |
||||
|
||||
void stringAppendUInt64(char *str, size_t maxStrLength, uint64_t value) { |
||||
auto n = strlen(str); |
||||
snprintf(str + n, maxStrLength - n, "%ju", value); |
||||
} |
||||
|
||||
void stringAppendFloat(char *str, size_t maxStrLength, float value) { |
||||
auto n = strlen(str); |
||||
snprintf(str + n, maxStrLength - n, "%g", value); |
||||
} |
||||
|
||||
void stringAppendFloat(char *str, size_t maxStrLength, float value, int numDecimalPlaces) { |
||||
auto n = strlen(str); |
||||
snprintf(str + n, maxStrLength - n, "%.*f", numDecimalPlaces, value); |
||||
} |
||||
|
||||
void stringAppendDouble(char *str, size_t maxStrLength, double value) { |
||||
auto n = strlen(str); |
||||
snprintf(str + n, maxStrLength - n, "%g", value); |
||||
} |
||||
|
||||
void stringAppendDouble(char *str, size_t maxStrLength, double value, int numDecimalPlaces) { |
||||
auto n = strlen(str); |
||||
snprintf(str + n, maxStrLength - n, "%.*f", numDecimalPlaces, value); |
||||
} |
||||
|
||||
void stringAppendVoltage(char *str, size_t maxStrLength, float value) { |
||||
auto n = strlen(str); |
||||
snprintf(str + n, maxStrLength - n, "%g V", value); |
||||
} |
||||
|
||||
void stringAppendCurrent(char *str, size_t maxStrLength, float value) { |
||||
auto n = strlen(str); |
||||
snprintf(str + n, maxStrLength - n, "%g A", value); |
||||
} |
||||
|
||||
void stringAppendPower(char *str, size_t maxStrLength, float value) { |
||||
auto n = strlen(str); |
||||
snprintf(str + n, maxStrLength - n, "%g W", value); |
||||
} |
||||
|
||||
void stringAppendDuration(char *str, size_t maxStrLength, float value) { |
||||
auto n = strlen(str); |
||||
if (value > 0.1) { |
||||
snprintf(str + n, maxStrLength - n, "%g s", value); |
||||
} else { |
||||
snprintf(str + n, maxStrLength - n, "%g ms", value * 1000); |
||||
} |
||||
} |
||||
|
||||
void stringAppendLoad(char *str, size_t maxStrLength, float value) { |
||||
auto n = strlen(str); |
||||
if (value < 1000) { |
||||
snprintf(str + n, maxStrLength - n, "%g ohm", value); |
||||
} else if (value < 1000000) { |
||||
snprintf(str + n, maxStrLength - n, "%g Kohm", value / 1000); |
||||
} else { |
||||
snprintf(str + n, maxStrLength - n, "%g Mohm", value / 1000000); |
||||
} |
||||
} |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
uint32_t crc32(const uint8_t *mem_block, size_t block_size) { |
||||
return HAL_CRC_Calculate(&hcrc, (uint32_t *)mem_block, block_size); |
||||
} |
||||
#else |
||||
/*
|
||||
From http://www.hackersdelight.org/hdcodetxt/crc.c.txt:
|
||||
|
||||
This is the basic CRC-32 calculation with some optimization but no |
||||
table lookup. The the byte reversal is avoided by shifting the crc reg |
||||
right instead of left and by using a reversed 32-bit word to represent |
||||
the polynomial. |
||||
When compiled to Cyclops with GCC, this function executes in 8 + 72n |
||||
instructions, where n is the number of bytes in the input message. It |
||||
should be doable in 4 + 61n instructions. |
||||
If the inner loop is strung out (approx. 5*8 = 40 instructions), |
||||
it would take about 6 + 46n instructions. |
||||
*/ |
||||
|
||||
uint32_t crc32(const uint8_t *mem_block, size_t block_size) { |
||||
uint32_t crc = 0xFFFFFFFF; |
||||
for (size_t i = 0; i < block_size; ++i) { |
||||
uint32_t byte = mem_block[i]; // Get next byte.
|
||||
crc = crc ^ byte; |
||||
for (int j = 0; j < 8; ++j) { // Do eight times.
|
||||
uint32_t mask = -((int32_t)crc & 1); |
||||
crc = (crc >> 1) ^ (0xEDB88320 & mask); |
||||
} |
||||
} |
||||
return ~crc; |
||||
} |
||||
#endif |
||||
|
||||
uint8_t toBCD(uint8_t bin) { |
||||
return ((bin / 10) << 4) | (bin % 10); |
||||
} |
||||
|
||||
uint8_t fromBCD(uint8_t bcd) { |
||||
return ((bcd >> 4) & 0xF) * 10 + (bcd & 0xF); |
||||
} |
||||
|
||||
float roundPrec(float a, float prec) { |
||||
float r = 1 / prec; |
||||
return roundf(a * r) / r; |
||||
} |
||||
|
||||
float floorPrec(float a, float prec) { |
||||
float r = 1 / prec; |
||||
return floorf(a * r) / r; |
||||
} |
||||
|
||||
float ceilPrec(float a, float prec) { |
||||
float r = 1 / prec; |
||||
return ceilf(a * r) / r; |
||||
} |
||||
|
||||
bool isNaN(float x) { |
||||
return x != x; |
||||
} |
||||
|
||||
bool isNaN(double x) { |
||||
return x != x; |
||||
} |
||||
|
||||
bool isDigit(char ch) { |
||||
return ch >= '0' && ch <= '9'; |
||||
} |
||||
|
||||
bool isHexDigit(char ch) { |
||||
return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); |
||||
} |
||||
|
||||
bool isUperCaseLetter(char ch) { |
||||
return ch >= 'A' && ch <= 'Z'; |
||||
} |
||||
|
||||
char toHexDigit(int num) { |
||||
if (num >= 0 && num <= 9) { |
||||
return '0' + num; |
||||
} else { |
||||
return 'A' + (num - 10); |
||||
} |
||||
} |
||||
|
||||
int fromHexDigit(char ch) { |
||||
if (ch >= '0' && ch <= '9') { |
||||
return ch - '0'; |
||||
} |
||||
|
||||
if (ch >= 'a' && ch <= 'f') { |
||||
return 10 + (ch - 'a'); |
||||
} |
||||
|
||||
return 10 + (ch - 'A'); |
||||
} |
||||
|
||||
bool pointInsideRect(int xPoint, int yPoint, int xRect, int yRect, int wRect, int hRect) { |
||||
return xPoint >= xRect && xPoint < xRect + wRect && yPoint >= yRect && yPoint < yRect + hRect; |
||||
} |
||||
|
||||
void getParentDir(const char *path, char *parentDirPath) { |
||||
int lastPathSeparatorIndex; |
||||
|
||||
for (lastPathSeparatorIndex = strlen(path) - 1; |
||||
lastPathSeparatorIndex >= 0 && path[lastPathSeparatorIndex] != PATH_SEPARATOR[0]; |
||||
--lastPathSeparatorIndex) |
||||
; |
||||
|
||||
int i; |
||||
for (i = 0; i < lastPathSeparatorIndex; ++i) { |
||||
parentDirPath[i] = path[i]; |
||||
} |
||||
parentDirPath[i] = 0; |
||||
} |
||||
|
||||
bool parseMacAddress(const char *macAddressStr, size_t macAddressStrLength, uint8_t *macAddress) { |
||||
int state = 0; |
||||
int a = 0; |
||||
int i = 0; |
||||
uint8_t resultMacAddress[6]; |
||||
|
||||
const char *end = macAddressStr + macAddressStrLength; |
||||
for (const char *p = macAddressStr; p < end; ++p) { |
||||
if (state == 0) { |
||||
if (*p == '-' || *p == ' ') { |
||||
continue; |
||||
} else if (isHexDigit(*p)) { |
||||
a = fromHexDigit(*p); |
||||
state = 1; |
||||
} else { |
||||
return false; |
||||
} |
||||
} else if (state == 1) { |
||||
if (isHexDigit(*p)) { |
||||
if (i < 6) { |
||||
resultMacAddress[i++] = (a << 4) | fromHexDigit(*p); |
||||
state = 0; |
||||
} else { |
||||
return false; |
||||
} |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (state != 0 || i != 6) { |
||||
return false; |
||||
} |
||||
|
||||
memcpy(macAddress, resultMacAddress, 6); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool parseIpAddress(const char *ipAddressStr, size_t ipAddressStrLength, uint32_t &ipAddress) { |
||||
const char *p = ipAddressStr; |
||||
const char *q = ipAddressStr + ipAddressStrLength; |
||||
|
||||
uint8_t ipAddressArray[4]; |
||||
|
||||
for (int i = 0; i < 4; ++i) { |
||||
if (p == q) { |
||||
return false; |
||||
} |
||||
|
||||
uint32_t part = 0; |
||||
for (int j = 0; j < 3; ++j) { |
||||
if (p == q) { |
||||
if (j > 0 && i == 3) { |
||||
break; |
||||
} else { |
||||
return false; |
||||
} |
||||
} else if (isDigit(*p)) { |
||||
part = part * 10 + (*p++ - '0'); |
||||
} else if (j > 0 && *p == '.') { |
||||
break; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
if (part > 255) { |
||||
return false; |
||||
} |
||||
|
||||
if ((i < 3 && *p++ != '.') || (i == 3 && p != q)) { |
||||
return false; |
||||
} |
||||
|
||||
ipAddressArray[i] = part; |
||||
} |
||||
|
||||
ipAddress = arrayToIpAddress(ipAddressArray); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
int getIpAddressPartA(uint32_t ipAddress) { |
||||
return ((uint8_t *)&ipAddress)[0]; |
||||
} |
||||
|
||||
void setIpAddressPartA(uint32_t *ipAddress, uint8_t value) { |
||||
((uint8_t *)ipAddress)[0] = value; |
||||
} |
||||
|
||||
int getIpAddressPartB(uint32_t ipAddress) { |
||||
return ((uint8_t *)&ipAddress)[1]; |
||||
} |
||||
|
||||
void setIpAddressPartB(uint32_t *ipAddress, uint8_t value) { |
||||
((uint8_t *)ipAddress)[1] = value; |
||||
} |
||||
|
||||
int getIpAddressPartC(uint32_t ipAddress) { |
||||
return ((uint8_t *)&ipAddress)[2]; |
||||
} |
||||
|
||||
void setIpAddressPartC(uint32_t *ipAddress, uint8_t value) { |
||||
((uint8_t *)ipAddress)[2] = value; |
||||
} |
||||
|
||||
int getIpAddressPartD(uint32_t ipAddress) { |
||||
return ((uint8_t *)&ipAddress)[3]; |
||||
} |
||||
|
||||
void setIpAddressPartD(uint32_t *ipAddress, uint8_t value) { |
||||
((uint8_t *)ipAddress)[3] = value; |
||||
} |
||||
|
||||
void ipAddressToArray(uint32_t ipAddress, uint8_t *ipAddressArray) { |
||||
ipAddressArray[0] = getIpAddressPartA(ipAddress); |
||||
ipAddressArray[1] = getIpAddressPartB(ipAddress); |
||||
ipAddressArray[2] = getIpAddressPartC(ipAddress); |
||||
ipAddressArray[3] = getIpAddressPartD(ipAddress); |
||||
} |
||||
|
||||
uint32_t arrayToIpAddress(uint8_t *ipAddressArray) { |
||||
return getIpAddress(ipAddressArray[0], ipAddressArray[1], ipAddressArray[2], ipAddressArray[3]); |
||||
} |
||||
|
||||
uint32_t getIpAddress(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { |
||||
uint32_t ipAddress; |
||||
|
||||
setIpAddressPartA(&ipAddress, a); |
||||
setIpAddressPartB(&ipAddress, b); |
||||
setIpAddressPartC(&ipAddress, c); |
||||
setIpAddressPartD(&ipAddress, d); |
||||
|
||||
return ipAddress; |
||||
} |
||||
|
||||
void ipAddressToString(uint32_t ipAddress, char *ipAddressStr, size_t maxIpAddressStrLength) { |
||||
snprintf(ipAddressStr, maxIpAddressStrLength, "%d.%d.%d.%d", |
||||
getIpAddressPartA(ipAddress), getIpAddressPartB(ipAddress), |
||||
getIpAddressPartC(ipAddress), getIpAddressPartD(ipAddress)); |
||||
} |
||||
|
||||
void macAddressToString(const uint8_t *macAddress, char *macAddressStr) { |
||||
for (int i = 0; i < 6; ++i) { |
||||
macAddressStr[3 * i] = toHexDigit((macAddress[i] & 0xF0) >> 4); |
||||
macAddressStr[3 * i + 1] = toHexDigit(macAddress[i] & 0xF); |
||||
macAddressStr[3 * i + 2] = i < 5 ? '-' : 0; |
||||
} |
||||
} |
||||
|
||||
void formatTimeZone(int16_t timeZone, char *text, int count) { |
||||
if (timeZone == 0) { |
||||
stringCopy(text, count, "GMT"); |
||||
} else { |
||||
char sign; |
||||
int16_t value; |
||||
if (timeZone > 0) { |
||||
sign = '+'; |
||||
value = timeZone; |
||||
} else { |
||||
sign = '-'; |
||||
value = -timeZone; |
||||
} |
||||
snprintf(text, count, "%c%02d:%02d GMT", sign, value / 100, value % 100); |
||||
} |
||||
} |
||||
|
||||
bool parseTimeZone(const char *timeZoneStr, size_t timeZoneLength, int16_t &timeZone) { |
||||
int state = 0; |
||||
|
||||
int sign = 1; |
||||
int integerPart = 0; |
||||
int fractionPart = 0; |
||||
|
||||
const char *end = timeZoneStr + timeZoneLength; |
||||
for (const char *p = timeZoneStr; p < end; ++p) { |
||||
if (*p == ' ') { |
||||
continue; |
||||
} |
||||
|
||||
if (state == 0) { |
||||
if (*p == '+') { |
||||
state = 1; |
||||
} else if (*p == '-') { |
||||
sign = -1; |
||||
state = 1; |
||||
} else if (isDigit(*p)) { |
||||
integerPart = *p - '0'; |
||||
state = 2; |
||||
} else { |
||||
return false; |
||||
} |
||||
} else if (state == 1) { |
||||
if (isDigit(*p)) { |
||||
integerPart = (*p - '0'); |
||||
state = 2; |
||||
} else { |
||||
return false; |
||||
} |
||||
} else if (state == 2) { |
||||
if (*p == ':') { |
||||
state = 4; |
||||
} else if (isDigit(*p)) { |
||||
integerPart = integerPart * 10 + (*p - '0'); |
||||
state = 3; |
||||
} else { |
||||
return false; |
||||
} |
||||
} else if (state == 3) { |
||||
if (*p == ':') { |
||||
state = 4; |
||||
} else { |
||||
return false; |
||||
} |
||||
} else if (state == 4) { |
||||
if (isDigit(*p)) { |
||||
fractionPart = (*p - '0'); |
||||
state = 5; |
||||
} else { |
||||
return false; |
||||
} |
||||
} else if (state == 5) { |
||||
if (isDigit(*p)) { |
||||
fractionPart = fractionPart * 10 + (*p - '0'); |
||||
state = 6; |
||||
} else { |
||||
return false; |
||||
} |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
if (state != 2 && state != 3 && state != 6) { |
||||
return false; |
||||
} |
||||
|
||||
int value = sign * (integerPart * 100 + fractionPart); |
||||
|
||||
if (value < -1200 || value > 1400) { |
||||
return false; |
||||
} |
||||
|
||||
timeZone = (int16_t)value; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void replaceCharacter(char *str, char ch, char repl) { |
||||
while (*str) { |
||||
if (*str == ch) { |
||||
*str = repl; |
||||
} |
||||
++str; |
||||
} |
||||
} |
||||
|
||||
int strcicmp(char const *a, char const *b) { |
||||
for (;; a++, b++) { |
||||
int d = tolower((unsigned char)*a) - tolower((unsigned char)*b); |
||||
if (d != 0 || !*a) |
||||
return d; |
||||
} |
||||
} |
||||
|
||||
int strncicmp(char const *a, char const *b, int n) { |
||||
for (; n--; a++, b++) { |
||||
int d = tolower((unsigned char)*a) - tolower((unsigned char)*b); |
||||
if (d != 0 || !*a) |
||||
return d; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
bool isStringEmpty(char const *s) { |
||||
for (; *s; s++) { |
||||
if (!isspace(*s)) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool startsWith(const char *str, const char *prefix) { |
||||
if (!str || !prefix) |
||||
return false; |
||||
size_t strLen = strlen(str); |
||||
size_t prefixLen = strlen(prefix); |
||||
if (prefixLen > strLen) |
||||
return false; |
||||
return strncmp(str, prefix, prefixLen) == 0; |
||||
} |
||||
|
||||
bool startsWithNoCase(const char *str, const char *prefix) { |
||||
if (!str || !prefix) |
||||
return false; |
||||
size_t strLen = strlen(str); |
||||
size_t prefixLen = strlen(prefix); |
||||
if (prefixLen > strLen) |
||||
return false; |
||||
return strncicmp(str, prefix, prefixLen) == 0; |
||||
} |
||||
|
||||
bool endsWith(const char *str, const char *suffix) { |
||||
if (!str || !suffix) |
||||
return false; |
||||
size_t strLen = strlen(str); |
||||
size_t suffixLen = strlen(suffix); |
||||
if (suffixLen > strLen) |
||||
return false; |
||||
return strncmp(str + strLen - suffixLen, suffix, suffixLen) == 0; |
||||
} |
||||
|
||||
bool endsWithNoCase(const char *str, const char *suffix) { |
||||
if (!str || !suffix) |
||||
return false; |
||||
size_t strLen = strlen(str); |
||||
size_t suffixLen = strlen(suffix); |
||||
if (suffixLen > strLen) |
||||
return false; |
||||
return strncicmp(str + strLen - suffixLen, suffix, suffixLen) == 0; |
||||
} |
||||
|
||||
void formatBytes(uint64_t bytes, char *text, int count) { |
||||
if (bytes == 0) { |
||||
stringCopy(text, count, "0 Bytes"); |
||||
} else { |
||||
double c = 1024.0; |
||||
const char *e[] = { "Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; |
||||
uint64_t f = (uint64_t)floor(log((double)bytes) / log(c)); |
||||
double g = round((bytes / pow(c, (double)f)) * 100) / 100; |
||||
snprintf(text, count, "%g %s", g, e[f]); |
||||
} |
||||
} |
||||
|
||||
void getFileName(const char *path, char *fileName, unsigned fileNameSize) { |
||||
const char *a = strrchr(path, '/'); |
||||
if (a) { |
||||
a++; |
||||
} else { |
||||
a = path; |
||||
} |
||||
|
||||
const char *b = path + strlen(path); |
||||
|
||||
unsigned n = b - a; |
||||
n = MIN(fileNameSize - 1, n); |
||||
if (n > 0) { |
||||
memcpy(fileName, a, n); |
||||
} |
||||
fileName[n] = 0; |
||||
} |
||||
|
||||
void getBaseFileName(const char *path, char *baseName, unsigned baseNameSize) { |
||||
const char *a = strrchr(path, '/'); |
||||
if (a) { |
||||
a++; |
||||
} else { |
||||
a = path; |
||||
} |
||||
|
||||
const char *b = strrchr(path, '.'); |
||||
if (!b || !(b >= a)) { |
||||
b = path + strlen(path); |
||||
} |
||||
|
||||
unsigned n = b - a; |
||||
n = MIN(baseNameSize - 1, n); |
||||
if (n > 0) { |
||||
memcpy(baseName, a, n); |
||||
} |
||||
baseName[n] = 0; |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const float PI = (float)M_PI; |
||||
static const float c1 = 1.70158f; |
||||
static const float c2 = c1 * 1.525f; |
||||
static const float c3 = c1 + 1.0f; |
||||
static const float c4 = (2 * PI) / 3; |
||||
static const float c5 = (2 * PI) / 4.5f; |
||||
|
||||
float linear(float x) { |
||||
return x; |
||||
} |
||||
|
||||
float easeInQuad(float x) { |
||||
return x * x; |
||||
} |
||||
|
||||
float easeOutQuad(float x) { |
||||
return 1 - (1 - x) * (1 - x); |
||||
} |
||||
|
||||
float easeInOutQuad(float x) { |
||||
return x < 0.5f ? 2 * x * x : 1 - powf(-2 * x + 2, 2) / 2; |
||||
} |
||||
|
||||
float easeInCubic(float x) { |
||||
return x * x * x; |
||||
} |
||||
|
||||
float easeOutCubic(float x) { |
||||
return 1 - pow(1 - x, 3); |
||||
} |
||||
|
||||
float easeInOutCubic(float x) { |
||||
return x < 0.5f ? 4 * x * x * x : 1 - powf(-2 * x + 2, 3) / 2; |
||||
} |
||||
|
||||
float easeInQuart(float x) { |
||||
return x * x * x * x; |
||||
} |
||||
|
||||
float easeOutQuart(float x) { |
||||
return 1 - powf(1 - x, 4); |
||||
} |
||||
|
||||
float easeInOutQuart(float x) { |
||||
return x < 0.5 ? 8 * x * x * x * x : 1 - powf(-2 * x + 2, 4) / 2; |
||||
} |
||||
|
||||
float easeInQuint(float x) { |
||||
return x * x * x * x * x; |
||||
} |
||||
|
||||
float easeOutQuint(float x) { |
||||
return 1 - powf(1 - x, 5); |
||||
} |
||||
|
||||
float easeInOutQuint(float x) { |
||||
return x < 0.5f ? 16 * x * x * x * x * x : 1 - powf(-2 * x + 2, 5) / 2; |
||||
} |
||||
|
||||
float easeInSine(float x) { |
||||
return 1 - cosf((x * PI) / 2); |
||||
} |
||||
|
||||
float easeOutSine(float x) { |
||||
return sinf((x * PI) / 2); |
||||
} |
||||
|
||||
float easeInOutSine(float x) { |
||||
return -(cosf(PI * x) - 1) / 2; |
||||
} |
||||
|
||||
float easeInExpo(float x) { |
||||
return x == 0 ? 0 : powf(2, 10 * x - 10); |
||||
} |
||||
|
||||
float easeOutExpo(float x) { |
||||
return x == 1 ? 1 : 1 - powf(2, -10 * x); |
||||
} |
||||
|
||||
float easeInOutExpo(float x) { |
||||
return x == 0 |
||||
? 0 |
||||
: x == 1 |
||||
? 1 |
||||
: x < 0.5 |
||||
? powf(2, 20 * x - 10) / 2 |
||||
: (2 - powf(2, -20 * x + 10)) / 2; |
||||
} |
||||
|
||||
float easeInCirc(float x) { |
||||
return 1 - sqrtf(1 - powf(x, 2)); |
||||
} |
||||
|
||||
float easeOutCirc(float x) { |
||||
return sqrtf(1 - powf(x - 1, 2)); |
||||
} |
||||
|
||||
float easeInOutCirc(float x) { |
||||
return x < 0.5 |
||||
? (1 - sqrtf(1 - pow(2 * x, 2))) / 2 |
||||
: (sqrtf(1 - powf(-2 * x + 2, 2)) + 1) / 2; |
||||
} |
||||
|
||||
float easeInBack(float x) { |
||||
return c3 * x * x * x - c1 * x * x; |
||||
} |
||||
|
||||
float easeOutBack(float x) { |
||||
return 1 + c3 * powf(x - 1, 3) + c1 * powf(x - 1, 2); |
||||
} |
||||
|
||||
float easeInOutBack(float x) { |
||||
return x < 0.5 |
||||
? (powf(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2 |
||||
: (powf(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2; |
||||
} |
||||
|
||||
float easeInElastic(float x) { |
||||
return x == 0 |
||||
? 0 |
||||
: x == 1 |
||||
? 1 |
||||
: -powf(2, 10 * x - 10) * sinf((x * 10 - 10.75f) * c4); |
||||
} |
||||
|
||||
float easeOutElastic(float x) { |
||||
return x == 0 |
||||
? 0 |
||||
: x == 1 |
||||
? 1 |
||||
: powf(2, -10 * x) * sinf((x * 10 - 0.75f) * c4) + 1; |
||||
} |
||||
|
||||
float easeInOutElastic(float x) { |
||||
return x == 0 |
||||
? 0 |
||||
: x == 1 |
||||
? 1 |
||||
: x < 0.5 |
||||
? -(powf(2, 20 * x - 10) * sinf((20 * x - 11.125f) * c5)) / 2 |
||||
: (powf(2, -20 * x + 10) * sinf((20 * x - 11.125f) * c5)) / 2 + 1; |
||||
} |
||||
|
||||
float easeOutBounce(float x); |
||||
|
||||
float easeInBounce(float x) { |
||||
return 1 -easeOutBounce(1 - x); |
||||
} |
||||
|
||||
float easeOutBounce(float x) { |
||||
static const float n1 = 7.5625f; |
||||
static const float d1 = 2.75f; |
||||
|
||||
if (x < 1 / d1) { |
||||
return n1 * x * x; |
||||
} else if (x < 2 / d1) { |
||||
x -= 1.5f / d1; |
||||
return n1 * x * x + 0.75f; |
||||
} else if (x < 2.5f / d1) { |
||||
x -= 2.25f / d1; |
||||
return n1 * x * x + 0.9375f; |
||||
} else { |
||||
x -= 2.625f / d1; |
||||
return n1 * x * x + 0.984375f; |
||||
} |
||||
}; |
||||
|
||||
float easeInOutBounce(float x) { |
||||
return x < 0.5 |
||||
? (1 - easeOutBounce(1 - 2 * x)) / 2 |
||||
: (1 + easeOutBounce(2 * x - 1)) / 2; |
||||
} |
||||
|
||||
EasingFuncType g_easingFuncs[] = { |
||||
linear, |
||||
easeInQuad, |
||||
easeOutQuad, |
||||
easeInOutQuad, |
||||
easeInCubic, |
||||
easeOutCubic, |
||||
easeInOutCubic, |
||||
easeInQuart, |
||||
easeOutQuart, |
||||
easeInOutQuart, |
||||
easeInQuint, |
||||
easeOutQuint, |
||||
easeInOutQuint, |
||||
easeInSine, |
||||
easeOutSine, |
||||
easeInOutSine, |
||||
easeInExpo, |
||||
easeOutExpo, |
||||
easeInOutExpo, |
||||
easeInCirc, |
||||
easeOutCirc, |
||||
easeInOutCirc, |
||||
easeInBack, |
||||
easeOutBack, |
||||
easeInOutBack, |
||||
easeInElastic, |
||||
easeOutElastic, |
||||
easeInOutElastic, |
||||
easeInBounce, |
||||
easeOutBounce, |
||||
easeInOutBounce, |
||||
}; |
||||
|
||||
} // namespace eez
|
||||
|
||||
#ifdef EEZ_PLATFORM_SIMULATOR_WIN32 |
||||
char *strnstr(const char *s1, const char *s2, size_t n) { |
||||
char c = *s2; |
||||
|
||||
if (c == '\0') |
||||
return (char *)s1; |
||||
|
||||
for (size_t len = strlen(s2); len <= n; n--, s1++) { |
||||
if (*s1 == c) { |
||||
for (size_t i = 1;; i++) { |
||||
if (i == len) { |
||||
return (char *)s1; |
||||
} |
||||
if (s1[i] != s2[i]) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
#endif |
@ -1,209 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2018-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include <eez/core/os.h> |
||||
#include <eez/core/unit.h> |
||||
|
||||
#define clear_bit(reg, bitmask) *reg &= ~bitmask |
||||
#define set_bit(reg, bitmask) *reg |= bitmask |
||||
#define util_swap(type, i, j) \ |
||||
{ \
|
||||
type t = i; \
|
||||
i = j; \
|
||||
j = t; \
|
||||
} |
||||
|
||||
#ifndef MIN |
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b)) |
||||
#endif |
||||
|
||||
#ifndef MAX |
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b)) |
||||
#endif |
||||
|
||||
#define PATH_SEPARATOR "/" |
||||
|
||||
namespace eez { |
||||
|
||||
float remap(float x, float x1, float y1, float x2, float y2); |
||||
float remapQuad(float x, float x1, float y1, float x2, float y2); |
||||
float remapOutQuad(float x, float x1, float y1, float x2, float y2); |
||||
float remapInOutQuad(float x, float x1, float y1, float x2, float y2); |
||||
float remapCubic(float x, float x1, float y1, float x2, float y2); |
||||
float remapOutCubic(float x, float x1, float y1, float x2, float y2); |
||||
float remapExp(float x, float x1, float y1, float x2, float y2); |
||||
float remapOutExp(float x, float x1, float y1, float x2, float y2); |
||||
float clamp(float x, float min, float max); |
||||
|
||||
void stringCopy(char *dst, size_t maxStrLength, const char *src); |
||||
void stringCopyLength(char *dst, size_t maxStrLength, const char *src, size_t length); |
||||
|
||||
void stringAppendString(char *str, size_t maxStrLength, const char *value); |
||||
void stringAppendStringLength(char *str, size_t maxStrLength, const char *value, size_t length); |
||||
|
||||
void stringAppendInt(char *str, size_t maxStrLength, int value); |
||||
void stringAppendUInt32(char *str, size_t maxStrLength, uint32_t value); |
||||
void stringAppendInt64(char *str, size_t maxStrLength, int64_t value); |
||||
void stringAppendUInt64(char *str, size_t maxStrLength, uint64_t value); |
||||
void stringAppendFloat(char *str, size_t maxStrLength, float value); |
||||
void stringAppendFloat(char *str, size_t maxStrLength, float value, int numDecimalPlaces); |
||||
void stringAppendDouble(char *str, size_t maxStrLength, double value); |
||||
void stringAppendDouble(char *str, size_t maxStrLength, double value, int numDecimalPlaces); |
||||
|
||||
void stringAppendVoltage(char *str, size_t maxStrLength, float value); |
||||
void stringAppendCurrent(char *str, size_t maxStrLength, float value); |
||||
void stringAppendPower(char *str, size_t maxStrLength, float value); |
||||
void stringAppendDuration(char *str, size_t maxStrLength, float value); |
||||
void stringAppendLoad(char *str, size_t maxStrLength, float value); |
||||
|
||||
uint32_t crc32(const uint8_t *message, size_t size); |
||||
|
||||
uint8_t toBCD(uint8_t bin); |
||||
uint8_t fromBCD(uint8_t bcd); |
||||
|
||||
float roundPrec(float a, float prec); |
||||
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); |
||||
bool isUperCaseLetter(char ch); |
||||
|
||||
char toHexDigit(int num); |
||||
int fromHexDigit(char ch); |
||||
|
||||
bool pointInsideRect(int xPoint, int yPoint, int xRect, int yRect, int wRect, int hRect); |
||||
|
||||
void getParentDir(const char *path, char *parentDirPath); |
||||
|
||||
bool parseMacAddress(const char *macAddressStr, size_t macAddressStrLength, uint8_t *macAddress); |
||||
|
||||
int getIpAddressPartA(uint32_t ipAddress); |
||||
void setIpAddressPartA(uint32_t *ipAddress, uint8_t value); |
||||
|
||||
int getIpAddressPartB(uint32_t ipAddress); |
||||
void setIpAddressPartB(uint32_t *ipAddress, uint8_t value); |
||||
|
||||
int getIpAddressPartC(uint32_t ipAddress); |
||||
void setIpAddressPartC(uint32_t *ipAddress, uint8_t value); |
||||
|
||||
int getIpAddressPartD(uint32_t ipAddress); |
||||
void setIpAddressPartD(uint32_t *ipAddress, uint8_t value); |
||||
|
||||
void ipAddressToArray(uint32_t ipAddress, uint8_t *ipAddressArray); |
||||
uint32_t arrayToIpAddress(uint8_t *ipAddressArray); |
||||
|
||||
uint32_t getIpAddress(uint8_t a, uint8_t b, uint8_t c, uint8_t d); |
||||
|
||||
bool parseIpAddress(const char *ipAddressStr, size_t ipAddressStrLength, uint32_t &ipAddress); |
||||
void ipAddressToString(uint32_t ipAddress, char *ipAddressStr, size_t maxIpAddressStrLength); |
||||
|
||||
void macAddressToString(const uint8_t *macAddress, char *macAddressStr); |
||||
|
||||
void formatTimeZone(int16_t timeZone, char *text, int count); |
||||
bool parseTimeZone(const char *timeZoneStr, size_t timeZoneLength, int16_t &timeZone); |
||||
|
||||
void replaceCharacter(char *str, char ch, char repl); |
||||
|
||||
int strcicmp(char const *a, char const *b); |
||||
int strncicmp(char const *a, char const *b, int n); |
||||
bool isStringEmpty(char const *a); |
||||
bool startsWith(const char *str, const char *prefix); |
||||
bool startsWithNoCase(const char *str, const char *prefix); |
||||
bool endsWith(const char *str, const char *suffix); |
||||
bool endsWithNoCase(const char *str, const char *suffix); |
||||
|
||||
void formatBytes(uint64_t bytes, char *text, int count); |
||||
|
||||
void getFileName(const char *path, char *fileName, unsigned fileNameSize); |
||||
void getBaseFileName(const char *path, char *baseName, unsigned baseNameSize); |
||||
|
||||
typedef float (*EasingFuncType)(float x); |
||||
extern EasingFuncType g_easingFuncs[]; |
||||
|
||||
class Interval { |
||||
public: |
||||
// Returns true when called for the first time,
|
||||
// and later returns true after interval, interval * 2, interval * 3, ...
|
||||
// Interval is in milliseconds.
|
||||
bool test(uint32_t interval) { |
||||
auto time = millis(); |
||||
|
||||
if (lastTime == 0) { |
||||
lastTime = time == 0 ? 1 : time; |
||||
return true; |
||||
} |
||||
|
||||
if (time >= lastTime + interval) { |
||||
lastTime += ((uint32_t)(time - lastTime) / interval) * interval; |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
private: |
||||
uint32_t lastTime = 0; |
||||
}; |
||||
|
||||
template <typename T, typename Total, uint64_t N> |
||||
class MovingAverage { |
||||
public: |
||||
void operator()(T sample) { |
||||
if (m_numSamples < N) { |
||||
m_samples[m_numSamples++] = sample; |
||||
m_total += sample; |
||||
} else { |
||||
T& oldest = m_samples[m_numSamples++ % N]; |
||||
m_total += sample - oldest; |
||||
oldest = sample; |
||||
} |
||||
} |
||||
|
||||
operator T() const { |
||||
if (m_numSamples < N) { |
||||
return m_total / m_numSamples; |
||||
} else { |
||||
return m_total / N; |
||||
} |
||||
} |
||||
|
||||
void reset() { |
||||
m_numSamples = 0; |
||||
m_total = 0; |
||||
} |
||||
|
||||
private: |
||||
T m_samples[N]; |
||||
uint64_t m_numSamples{0}; |
||||
Total m_total{0}; |
||||
}; |
||||
|
||||
} // namespace eez
|
||||
|
||||
#ifdef EEZ_PLATFORM_SIMULATOR_WIN32 |
||||
char *strnstr(const char *s1, const char *s2, size_t n); |
||||
#endif |
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/conf.h> |
||||
#include <eez/core/unit.h> |
||||
|
||||
#define VALUE_TYPES \ |
||||
VALUE_TYPE(UNDEFINED) /* 0 */ \
|
||||
VALUE_TYPE(NULL) /* 1 */ \
|
||||
VALUE_TYPE(BOOLEAN) /* 2 */ \
|
||||
VALUE_TYPE(INT8) /* 3 */ \
|
||||
VALUE_TYPE(UINT8) /* 4 */ \
|
||||
VALUE_TYPE(INT16) /* 5 */ \
|
||||
VALUE_TYPE(UINT16) /* 6 */ \
|
||||
VALUE_TYPE(INT32) /* 7 */ \
|
||||
VALUE_TYPE(UINT32) /* 8 */ \
|
||||
VALUE_TYPE(INT64) /* 9 */ \
|
||||
VALUE_TYPE(UINT64) /* 10 */ \
|
||||
VALUE_TYPE(FLOAT) /* 11 */ \
|
||||
VALUE_TYPE(DOUBLE) /* 12 */ \
|
||||
VALUE_TYPE(STRING) /* 13 */ \
|
||||
VALUE_TYPE(ARRAY) /* 14 */ \
|
||||
VALUE_TYPE(STRING_REF) /* 15 */ \
|
||||
VALUE_TYPE(ARRAY_REF) /* 16 */ \
|
||||
VALUE_TYPE(BLOB_REF) /* 17 */ \
|
||||
VALUE_TYPE(STREAM) /* 18 */ \
|
||||
VALUE_TYPE(DATE) /* 19 */ \
|
||||
VALUE_TYPE(VERSIONED_STRING) /* 20 */ \
|
||||
VALUE_TYPE(VALUE_PTR) /* 21 */ \
|
||||
VALUE_TYPE(ARRAY_ELEMENT_VALUE) /* 22 */ \
|
||||
VALUE_TYPE(FLOW_OUTPUT) /* 23 */ \
|
||||
VALUE_TYPE(NATIVE_VARIABLE) /* 24 */ \
|
||||
VALUE_TYPE(RANGE) /* 25 */ \
|
||||
VALUE_TYPE(POINTER) /* 26 */ \
|
||||
VALUE_TYPE(ENUM) /* 27 */ \
|
||||
VALUE_TYPE(IP_ADDRESS) /* 28 */ \
|
||||
VALUE_TYPE(TIME_ZONE) /* 29 */ \
|
||||
VALUE_TYPE(YT_DATA_GET_VALUE_FUNCTION_POINTER) /* 30 */ \
|
||||
CUSTOM_VALUE_TYPES |
||||
|
||||
namespace eez { |
||||
|
||||
#define VALUE_TYPE(NAME) VALUE_TYPE_##NAME, |
||||
enum ValueType { |
||||
VALUE_TYPES |
||||
}; |
||||
#undef VALUE_TYPE |
||||
|
||||
} |
@ -1,142 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <math.h> |
||||
|
||||
#include <eez/core/os.h> |
||||
|
||||
#include <eez/flow/flow.h> |
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/queue.h> |
||||
#include <eez/flow/hooks.h> |
||||
|
||||
#if defined(__EMSCRIPTEN__) |
||||
#include <eez/flow/dashboard_api.h> |
||||
#endif |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeStartComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeEndComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeInputComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeOutputComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeWatchVariableComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeEvalExprComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeSetVariableComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeSwitchComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeCompareComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeIsTrueComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeConstantComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeLogComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeCallActionComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeDelayComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeErrorComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeCatchErrorComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeCounterComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeLoopComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeShowPageComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeShowMessageBoxComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeShowKeyboardComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeShowKeypadComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeSelectLanguageComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeSetPageDirectionComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeAnimateComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeNoopComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeOnEventComponent(FlowState *flowState, unsigned componentIndex); |
||||
|
||||
void executeLayoutViewWidgetComponent(FlowState *flowState, unsigned componentIndex); |
||||
void executeRollerWidgetComponent(FlowState *flowState, unsigned componentIndex); |
||||
|
||||
typedef void (*ExecuteComponentFunctionType)(FlowState *flowState, unsigned componentIndex); |
||||
|
||||
static ExecuteComponentFunctionType g_executeComponentFunctions[] = { |
||||
executeStartComponent, |
||||
executeEndComponent, |
||||
executeInputComponent, |
||||
executeOutputComponent, |
||||
executeWatchVariableComponent, |
||||
executeEvalExprComponent, |
||||
executeSetVariableComponent, |
||||
executeSwitchComponent, |
||||
executeCompareComponent, |
||||
executeIsTrueComponent, |
||||
executeConstantComponent, |
||||
executeLogComponent, |
||||
executeCallActionComponent, |
||||
executeDelayComponent, |
||||
executeErrorComponent, |
||||
executeCatchErrorComponent, |
||||
executeCounterComponent, // COMPONENT_TYPE_COUNTER_ACTION
|
||||
executeLoopComponent, |
||||
executeShowPageComponent, |
||||
nullptr, // COMPONENT_TYPE_SCPIACTION
|
||||
executeShowMessageBoxComponent, |
||||
executeShowKeyboardComponent, |
||||
executeShowKeypadComponent, |
||||
executeNoopComponent, // COMPONENT_TYPE_NOOP_ACTION
|
||||
nullptr, // COMPONENT_TYPE_COMMENT_ACTION
|
||||
executeSelectLanguageComponent, // COMPONENT_TYPE_SELECT_LANGUAGE_ACTION
|
||||
executeSetPageDirectionComponent, // COMPONENT_TYPE_SET_PAGE_DIRECTION_ACTION
|
||||
executeAnimateComponent, // COMPONENT_TYPE_ANIMATE_ACTION
|
||||
executeOnEventComponent, // COMPONENT_TYPE_ON_EVENT_ACTION
|
||||
}; |
||||
|
||||
void registerComponent(ComponentTypes componentType, ExecuteComponentFunctionType executeComponentFunction) { |
||||
if (componentType >= defs_v3::COMPONENT_TYPE_START_ACTION) { |
||||
g_executeComponentFunctions[componentType - defs_v3::COMPONENT_TYPE_START_ACTION] = executeComponentFunction; |
||||
} |
||||
} |
||||
|
||||
void executeComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
|
||||
#if defined(__EMSCRIPTEN__) |
||||
if (component->type >= defs_v3::FIRST_DASHBOARD_COMPONENT_TYPE) { |
||||
if (executeDashboardComponentHook) { |
||||
executeDashboardComponentHook(component->type, getFlowStateIndex(flowState), componentIndex); |
||||
return; |
||||
} |
||||
} else |
||||
#endif // __EMSCRIPTEN__
|
||||
if (component->type >= defs_v3::COMPONENT_TYPE_START_ACTION) { |
||||
auto executeComponentFunction = g_executeComponentFunctions[component->type - defs_v3::COMPONENT_TYPE_START_ACTION]; |
||||
if (executeComponentFunction != nullptr) { |
||||
executeComponentFunction(flowState, componentIndex); |
||||
return; |
||||
} |
||||
} else if (component->type < 1000) { |
||||
if (component->type == defs_v3::COMPONENT_TYPE_LAYOUT_VIEW_WIDGET) { |
||||
executeLayoutViewWidgetComponent(flowState, componentIndex); |
||||
} else if (component->type == defs_v3::COMPONENT_TYPE_ROLLER_WIDGET) { |
||||
executeRollerWidgetComponent(flowState, componentIndex); |
||||
} |
||||
return; |
||||
} |
||||
|
||||
char errorMessage[100]; |
||||
snprintf(errorMessage, sizeof(errorMessage), "Unknown component at index = %d, type = %d\n", componentIndex, component->type); |
||||
throwError(flowState, componentIndex, errorMessage); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/flow/private.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
using defs_v3::ComponentTypes; |
||||
|
||||
typedef void (*ExecuteComponentFunctionType)(FlowState *flowState, unsigned componentIndex); |
||||
void registerComponent(ComponentTypes componentType, ExecuteComponentFunctionType executeComponentFunction); |
||||
|
||||
void executeComponent(FlowState *flowState, unsigned componentIndex); |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
#include <eez/flow/private.h> |
||||
#include <eez/flow/queue.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct AnimateComponenentExecutionState : public ComponenentExecutionState { |
||||
float startPosition; |
||||
float endPosition; |
||||
float speed; |
||||
uint32_t startTimestamp; |
||||
}; |
||||
|
||||
void executeAnimateComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto state = (AnimateComponenentExecutionState *)flowState->componenentExecutionStates[componentIndex]; |
||||
if (!state) { |
||||
Value fromValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::ANIMATE_ACTION_COMPONENT_PROPERTY_FROM, fromValue, "Failed to evaluate From in Animate")) { |
||||
return; |
||||
} |
||||
|
||||
Value toValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::ANIMATE_ACTION_COMPONENT_PROPERTY_TO, toValue, "Failed to evaluate To in Animate")) { |
||||
return; |
||||
} |
||||
|
||||
Value speedValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::ANIMATE_ACTION_COMPONENT_PROPERTY_SPEED, speedValue, "Failed to evaluate Speed in Animate")) { |
||||
return; |
||||
} |
||||
|
||||
float from = fromValue.toFloat(); |
||||
float to = toValue.toFloat(); |
||||
float speed = speedValue.toFloat(); |
||||
|
||||
if (speed == 0) { |
||||
flowState->timelinePosition = to; |
||||
onFlowStateTimelineChanged(flowState); |
||||
|
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} else { |
||||
state = allocateComponentExecutionState<AnimateComponenentExecutionState>(flowState, componentIndex); |
||||
|
||||
state->startPosition = from; |
||||
state->endPosition = to; |
||||
state->speed = speed; |
||||
state->startTimestamp = millis(); |
||||
|
||||
if (!addToQueue(flowState, componentIndex, -1, -1, -1, true)) { |
||||
throwError(flowState, componentIndex, "Execution queue is full\n"); |
||||
return; |
||||
} |
||||
} |
||||
} else { |
||||
float currentTime; |
||||
|
||||
if (state->startPosition < state->endPosition) { |
||||
currentTime = state->startPosition + state->speed * (millis() - state->startTimestamp) / 1000.0f; |
||||
if (currentTime >= state->endPosition) { |
||||
currentTime = state->endPosition; |
||||
} |
||||
} else { |
||||
currentTime = state->startPosition - state->speed * (millis() - state->startTimestamp) / 1000.0f; |
||||
if (currentTime <= state->endPosition) { |
||||
currentTime = state->endPosition; |
||||
} |
||||
} |
||||
|
||||
flowState->timelinePosition = currentTime; |
||||
onFlowStateTimelineChanged(flowState); |
||||
|
||||
if (currentTime == state->endPosition) { |
||||
deallocateComponentExecutionState(flowState, componentIndex); |
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} else { |
||||
if (!addToQueue(flowState, componentIndex, -1, -1, -1, true)) { |
||||
throwError(flowState, componentIndex, "Execution queue is full\n"); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/components/call_action.h> |
||||
#include <eez/flow/debugger.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
CallActionComponenentExecutionState::~CallActionComponenentExecutionState() { |
||||
freeFlowState(flowState); |
||||
} |
||||
|
||||
void executeCallAction(FlowState *flowState, unsigned componentIndex, int flowIndex) { |
||||
if (flowIndex >= (int)flowState->flowDefinition->flows.count) { |
||||
executeActionFunction(flowIndex - flowState->flowDefinition->flows.count); |
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
return; |
||||
} |
||||
|
||||
auto callActionComponenentExecutionState = (CallActionComponenentExecutionState *)flowState->componenentExecutionStates[componentIndex]; |
||||
if (callActionComponenentExecutionState) { |
||||
if (canFreeFlowState(callActionComponenentExecutionState->flowState)) { |
||||
freeFlowState(callActionComponenentExecutionState->flowState); |
||||
} else { |
||||
throwError(flowState, componentIndex, "CallAction is already running\n"); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
FlowState *actionFlowState = initActionFlowState(flowIndex, flowState, componentIndex); |
||||
|
||||
if (canFreeFlowState(actionFlowState)) { |
||||
freeFlowState(actionFlowState); |
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} else { |
||||
callActionComponenentExecutionState = allocateComponentExecutionState<CallActionComponenentExecutionState>(flowState, componentIndex); |
||||
callActionComponenentExecutionState->flowState = actionFlowState; |
||||
} |
||||
} |
||||
|
||||
void executeCallActionComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = (CallActionActionComponent *)flowState->flow->components[componentIndex]; |
||||
|
||||
auto flowIndex = component->flowIndex; |
||||
if (flowIndex < 0) { |
||||
throwError(flowState, componentIndex, "Invalid action flow index in CallAction\n"); |
||||
return; |
||||
} |
||||
|
||||
executeCallAction(flowState, componentIndex, flowIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/flow/private.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct CallActionActionComponent : public Component { |
||||
int16_t flowIndex; |
||||
uint8_t inputsStartIndex; |
||||
uint8_t outputsStartIndex; |
||||
}; |
||||
|
||||
typedef CallActionActionComponent LayoutViewWidgetComponent; |
||||
|
||||
struct CallActionComponenentExecutionState : public ComponenentExecutionState { |
||||
FlowState *flowState; |
||||
|
||||
~CallActionComponenentExecutionState(); |
||||
}; |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeCatchErrorComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto catchErrorComponentExecutionState = (CatchErrorComponenentExecutionState *)flowState->componenentExecutionStates[componentIndex]; |
||||
propagateValue(flowState, componentIndex, 1, catchErrorComponentExecutionState->message); |
||||
deallocateComponentExecutionState(flowState, componentIndex); |
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct CompareActionComponent : public Component { |
||||
uint8_t conditionInstructions[1]; |
||||
}; |
||||
|
||||
void executeCompareComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = (CompareActionComponent *)flowState->flow->components[componentIndex]; |
||||
|
||||
Value conditionValue; |
||||
if (!evalExpression(flowState, componentIndex, component->conditionInstructions, conditionValue, "Failed to evaluate Condition in Compare")) { |
||||
return; |
||||
} |
||||
|
||||
int err; |
||||
bool result = conditionValue.toBool(&err); |
||||
if (err == 0) { |
||||
if (result) { |
||||
propagateValue(flowState, componentIndex, 1, Value(true, VALUE_TYPE_BOOLEAN)); |
||||
} else { |
||||
propagateValue(flowState, componentIndex, 2, Value(false, VALUE_TYPE_BOOLEAN)); |
||||
} |
||||
} else { |
||||
throwError(flowState, componentIndex, "Failed to convert Value to boolean in IsTrue\n"); |
||||
return; |
||||
} |
||||
|
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct ConstantActionComponent : public Component { |
||||
uint16_t valueIndex; |
||||
}; |
||||
|
||||
void executeConstantComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = (ConstantActionComponent *)flowState->flow->components[componentIndex]; |
||||
|
||||
auto &sourceValue = *flowState->flowDefinition->constants[component->valueIndex]; |
||||
|
||||
propagateValue(flowState, componentIndex, 1, sourceValue); |
||||
|
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
#include <eez/flow/operations.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct CounterComponenentExecutionState : public ComponenentExecutionState { |
||||
int counter; |
||||
}; |
||||
|
||||
void executeCounterComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto counterComponenentExecutionState = (CounterComponenentExecutionState *)flowState->componenentExecutionStates[componentIndex]; |
||||
|
||||
if (!counterComponenentExecutionState) { |
||||
Value counterValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::COUNTER_ACTION_COMPONENT_PROPERTY_COUNT_VALUE, counterValue, "Failed to evaluate countValue in Counter")) { |
||||
return; |
||||
} |
||||
|
||||
counterComponenentExecutionState = allocateComponentExecutionState<CounterComponenentExecutionState>(flowState, componentIndex); |
||||
counterComponenentExecutionState->counter = counterValue.getInt(); |
||||
} |
||||
|
||||
if (counterComponenentExecutionState->counter > 0) { |
||||
counterComponenentExecutionState->counter--; |
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} else { |
||||
// done
|
||||
deallocateComponentExecutionState(flowState, componentIndex); |
||||
propagateValue(flowState, componentIndex, 1); |
||||
} |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/core/alloc.h> |
||||
#include <eez/core/os.h> |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
#include <eez/flow/queue.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct DelayComponenentExecutionState : public ComponenentExecutionState { |
||||
uint32_t waitUntil; |
||||
}; |
||||
|
||||
void executeDelayComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto delayComponentExecutionState = (DelayComponenentExecutionState *)flowState->componenentExecutionStates[componentIndex]; |
||||
|
||||
if (!delayComponentExecutionState) { |
||||
Value value; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::DELAY_ACTION_COMPONENT_PROPERTY_MILLISECONDS, value, "Failed to evaluate Milliseconds in Delay")) { |
||||
return; |
||||
} |
||||
|
||||
double milliseconds = value.toDouble(); |
||||
if (!isNaN(milliseconds)) { |
||||
delayComponentExecutionState = allocateComponentExecutionState<DelayComponenentExecutionState>(flowState, componentIndex); |
||||
delayComponentExecutionState->waitUntil = millis() + (uint32_t)floor(milliseconds); |
||||
} else { |
||||
throwError(flowState, componentIndex, "Invalid Milliseconds value in Delay\n"); |
||||
return; |
||||
} |
||||
|
||||
if (!addToQueue(flowState, componentIndex, -1, -1, -1, true)) { |
||||
throwError(flowState, componentIndex, "Execution queue is full\n"); |
||||
return; |
||||
} |
||||
} else { |
||||
if (millis() >= delayComponentExecutionState->waitUntil) { |
||||
deallocateComponentExecutionState(flowState, componentIndex); |
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} else { |
||||
if (!addToQueue(flowState, componentIndex, -1, -1, -1, true)) { |
||||
throwError(flowState, componentIndex, "Execution queue is full\n"); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/flow.h> |
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/hooks.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeEndComponent(FlowState *flowState, unsigned componentIndex) { |
||||
if (flowState->parentFlowState && flowState->isAction) { |
||||
propagateValueThroughSeqout(flowState->parentFlowState, flowState->parentComponentIndex); |
||||
} else { |
||||
stopScriptHook(); |
||||
} |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeErrorComponent(FlowState *flowState, unsigned componentIndex) { |
||||
Value expressionValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::EVAL_EXPR_ACTION_COMPONENT_PROPERTY_EXPRESSION, expressionValue, "Failed to evaluate Message in Error")) { |
||||
return; |
||||
} |
||||
|
||||
throwError(flowState, componentIndex, expressionValue.getString()); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeEvalExprComponent(FlowState *flowState, unsigned componentIndex) { |
||||
Value expressionValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::EVAL_EXPR_ACTION_COMPONENT_PROPERTY_EXPRESSION, expressionValue, "Failed to evaluate Expression in EvalExpr")) { |
||||
return; |
||||
} |
||||
|
||||
propagateValue(flowState, componentIndex, 1, expressionValue); |
||||
|
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include <eez/flow/components/input.h> |
||||
#include <eez/flow/components/call_action.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
bool getCallActionValue(FlowState *flowState, unsigned componentIndex, Value &value) { |
||||
auto component = (InputActionComponent *)flowState->flow->components[componentIndex]; |
||||
|
||||
if (!flowState->parentFlowState) { |
||||
throwError(flowState, componentIndex, "No parentFlowState in Input\n"); |
||||
return false; |
||||
} |
||||
|
||||
if (!flowState->parentComponent) { |
||||
throwError(flowState, componentIndex, "No parentComponent in Input\n"); |
||||
return false; |
||||
} |
||||
|
||||
auto callActionComponent = (CallActionActionComponent *)flowState->parentComponent; |
||||
|
||||
uint8_t parentComponentInputIndex = callActionComponent->inputsStartIndex + component->inputIndex; |
||||
if (component->type == defs_v3::COMPONENT_TYPE_INPUT_ACTION) { |
||||
parentComponentInputIndex = callActionComponent->inputsStartIndex + component->inputIndex; |
||||
} else { |
||||
parentComponentInputIndex = 0; |
||||
} |
||||
|
||||
if (parentComponentInputIndex >= flowState->parentComponent->inputs.count) { |
||||
throwError(flowState, componentIndex, "Invalid input index in Input\n"); |
||||
return false; |
||||
} |
||||
|
||||
auto parentComponentInputs = flowState->parentComponent->inputs; |
||||
auto flowInputIndex = parentComponentInputs[parentComponentInputIndex]; |
||||
|
||||
auto parentFlow = flowState->flowDefinition->flows[flowState->parentFlowState->flowIndex]; |
||||
if (flowInputIndex >= parentFlow->componentInputs.count) { |
||||
throwError(flowState, componentIndex, "Invalid input index of parent component in Input\n"); |
||||
return false; |
||||
} |
||||
|
||||
value = flowState->parentFlowState->values[flowInputIndex]; |
||||
return true; |
||||
} |
||||
|
||||
void executeInputComponent(FlowState *flowState, unsigned componentIndex) { |
||||
Value value; |
||||
if (getCallActionValue(flowState, componentIndex, value)) { |
||||
auto inputActionComponentExecutionState = (InputActionComponentExecutionState *)flowState->componenentExecutionStates[componentIndex]; |
||||
if (!inputActionComponentExecutionState) { |
||||
inputActionComponentExecutionState = allocateComponentExecutionState<InputActionComponentExecutionState>(flowState, componentIndex); |
||||
} |
||||
|
||||
propagateValue(flowState, componentIndex, 0, value); |
||||
inputActionComponentExecutionState->value = value; |
||||
} |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/flow/private.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct InputActionComponent : public Component { |
||||
uint8_t inputIndex; |
||||
}; |
||||
|
||||
struct InputActionComponentExecutionState : public ComponenentExecutionState { |
||||
Value value; |
||||
}; |
||||
|
||||
|
||||
bool getCallActionValue(FlowState *flowState, unsigned componentIndex, Value &value); |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeIsTrueComponent(FlowState *flowState, unsigned componentIndex) { |
||||
Value srcValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::IS_TRUE_ACTION_COMPONENT_PROPERTY_VALUE, srcValue, "Failed to evaluate Value in IsTrue")) { |
||||
return; |
||||
} |
||||
|
||||
int err; |
||||
bool result = srcValue.toBool(&err); |
||||
if (err == 0) { |
||||
if (result) { |
||||
propagateValue(flowState, componentIndex, 1, Value(true, VALUE_TYPE_BOOLEAN)); |
||||
} else { |
||||
propagateValue(flowState, componentIndex, 2, Value(false, VALUE_TYPE_BOOLEAN)); |
||||
} |
||||
} else { |
||||
throwError(flowState, componentIndex, "Failed to convert Value to boolean in IsTrue\n"); |
||||
return; |
||||
} |
||||
|
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/core/alloc.h> |
||||
#include <eez/core/os.h> |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/queue.h> |
||||
#include <eez/flow/components/call_action.h> |
||||
#include <eez/flow/components/input.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct LayoutViewWidgetExecutionState : public ComponenentExecutionState { |
||||
FlowState *flowState; |
||||
|
||||
~LayoutViewWidgetExecutionState() { |
||||
freeFlowState(flowState); |
||||
} |
||||
}; |
||||
|
||||
static LayoutViewWidgetExecutionState *createLayoutViewFlowState(FlowState *flowState, uint16_t layoutViewWidgetComponentIndex, int16_t pageId) { |
||||
auto layoutViewFlowState = initPageFlowState(flowState->assets, pageId, flowState, layoutViewWidgetComponentIndex); |
||||
auto layoutViewWidgetExecutionState = allocateComponentExecutionState<LayoutViewWidgetExecutionState>(flowState, layoutViewWidgetComponentIndex); |
||||
layoutViewWidgetExecutionState->flowState = layoutViewFlowState; |
||||
return layoutViewWidgetExecutionState; |
||||
} |
||||
|
||||
FlowState *getLayoutViewFlowState(FlowState *flowState, uint16_t layoutViewWidgetComponentIndex, int16_t pageId) { |
||||
auto layoutViewWidgetExecutionState = (LayoutViewWidgetExecutionState *)flowState->componenentExecutionStates[layoutViewWidgetComponentIndex]; |
||||
if (!layoutViewWidgetExecutionState) { |
||||
layoutViewWidgetExecutionState = createLayoutViewFlowState(flowState, layoutViewWidgetComponentIndex, pageId); |
||||
} |
||||
|
||||
return layoutViewWidgetExecutionState->flowState; |
||||
} |
||||
|
||||
void executeLayoutViewWidgetComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = (CallActionActionComponent *)flowState->flow->components[componentIndex]; |
||||
|
||||
auto layoutViewWidgetExecutionState = (LayoutViewWidgetExecutionState *)flowState->componenentExecutionStates[componentIndex]; |
||||
if (!layoutViewWidgetExecutionState) { |
||||
createLayoutViewFlowState(flowState, componentIndex, component->flowIndex); |
||||
} else { |
||||
auto layoutViewFlowState = layoutViewWidgetExecutionState->flowState; |
||||
for ( |
||||
unsigned layoutViewComponentIndex = 0; |
||||
layoutViewComponentIndex < layoutViewFlowState->flow->components.count; |
||||
layoutViewComponentIndex++ |
||||
) { |
||||
auto layoutViewComponent = layoutViewFlowState->flow->components[layoutViewComponentIndex]; |
||||
if (layoutViewComponent->type == defs_v3::COMPONENT_TYPE_INPUT_ACTION) { |
||||
auto inputActionComponentExecutionState = (InputActionComponentExecutionState *)layoutViewFlowState->componenentExecutionStates[layoutViewComponentIndex]; |
||||
if (inputActionComponentExecutionState) { |
||||
Value value; |
||||
if (getCallActionValue(layoutViewFlowState, layoutViewComponentIndex, value)) { |
||||
if (inputActionComponentExecutionState->value != value) { |
||||
addToQueue(layoutViewWidgetExecutionState->flowState, layoutViewComponentIndex); |
||||
inputActionComponentExecutionState->value = value; |
||||
} |
||||
} else { |
||||
return; |
||||
} |
||||
} |
||||
} else if (layoutViewComponent->type == defs_v3::COMPONENT_TYPE_START_ACTION) { |
||||
Value value; |
||||
if (getCallActionValue(layoutViewFlowState, layoutViewComponentIndex, value)) { |
||||
if (value.getType() != VALUE_TYPE_UNDEFINED) { |
||||
addToQueue(layoutViewWidgetExecutionState->flowState, layoutViewComponentIndex); |
||||
} |
||||
} else { |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/core/debug.h> |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
#include <eez/flow/debugger.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeLogComponent(FlowState *flowState, unsigned componentIndex) { |
||||
Value value; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::LOG_ACTION_COMPONENT_PROPERTY_VALUE, value, "Failed to evaluate Message in Log")) { |
||||
return; |
||||
} |
||||
|
||||
Value strValue = value.toString(0x0f9812ee); |
||||
const char *valueStr = strValue.getString(); |
||||
if (valueStr && *valueStr) { |
||||
logInfo(flowState, componentIndex, valueStr); |
||||
} |
||||
|
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
#include <eez/flow/operations.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct LoopComponenentExecutionState : public ComponenentExecutionState { |
||||
Value dstValue; |
||||
Value toValue; |
||||
Value currentValue; |
||||
}; |
||||
|
||||
void executeLoopComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
|
||||
auto loopComponentExecutionState = (LoopComponenentExecutionState *)flowState->componenentExecutionStates[componentIndex]; |
||||
|
||||
// restart loop if entered through "start" input
|
||||
static const unsigned START_INPUT_INDEX = 0; |
||||
auto startInputIndex = component->inputs[START_INPUT_INDEX]; |
||||
if (flowState->values[startInputIndex].type != VALUE_TYPE_UNDEFINED) { |
||||
if (loopComponentExecutionState) { |
||||
deallocateComponentExecutionState(flowState, componentIndex); |
||||
loopComponentExecutionState = nullptr; |
||||
} |
||||
} else { |
||||
if (!loopComponentExecutionState) { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
Value stepValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::LOOP_ACTION_COMPONENT_PROPERTY_STEP, stepValue, "Failed to evaluate Step in Loop")) { |
||||
return; |
||||
} |
||||
|
||||
if (!loopComponentExecutionState) { |
||||
Value dstValue; |
||||
if (!evalAssignableProperty(flowState, componentIndex, defs_v3::LOOP_ACTION_COMPONENT_PROPERTY_VARIABLE, dstValue, "Failed to evaluate Variable in Loop")) { |
||||
return; |
||||
} |
||||
|
||||
Value fromValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::LOOP_ACTION_COMPONENT_PROPERTY_FROM, fromValue, "Failed to evaluate From in Loop")) { |
||||
return; |
||||
} |
||||
|
||||
Value toValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::LOOP_ACTION_COMPONENT_PROPERTY_TO, toValue, "Failed to evaluate To in Loop")) { |
||||
return; |
||||
} |
||||
|
||||
loopComponentExecutionState = allocateComponentExecutionState<LoopComponenentExecutionState>(flowState, componentIndex); |
||||
loopComponentExecutionState->dstValue = dstValue; |
||||
loopComponentExecutionState->toValue = toValue; |
||||
|
||||
loopComponentExecutionState->currentValue = fromValue; |
||||
} else { |
||||
loopComponentExecutionState->currentValue = op_add(loopComponentExecutionState->currentValue, stepValue); |
||||
} |
||||
|
||||
bool condition; |
||||
if (stepValue.getInt() > 0) { |
||||
condition = op_great(loopComponentExecutionState->currentValue, loopComponentExecutionState->toValue).toBool(); |
||||
} else { |
||||
condition = op_less(loopComponentExecutionState->currentValue, loopComponentExecutionState->toValue).toBool(); |
||||
} |
||||
|
||||
if (condition) { |
||||
// done
|
||||
deallocateComponentExecutionState(flowState, componentIndex); |
||||
propagateValue(flowState, componentIndex, component->outputs.count - 1); |
||||
} else { |
||||
assignValue(flowState, componentIndex, loopComponentExecutionState->dstValue, loopComponentExecutionState->currentValue); |
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/core/debug.h> |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
#include <eez/flow/debugger.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeNoopComponent(FlowState *flowState, unsigned componentIndex) { |
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeOnEventComponent(FlowState *flowState, unsigned componentIndex) { |
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/components/call_action.h> |
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct OutputActionComponent : public Component { |
||||
uint8_t outputIndex; |
||||
}; |
||||
|
||||
void executeOutputComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = (OutputActionComponent *)flowState->flow->components[componentIndex]; |
||||
|
||||
if (!flowState->parentFlowState) { |
||||
throwError(flowState, componentIndex, "No parentFlowState in Output\n"); |
||||
return; |
||||
} |
||||
|
||||
if (!flowState->parentComponent) { |
||||
throwError(flowState, componentIndex, "No parentComponent in Output\n"); |
||||
return; |
||||
} |
||||
|
||||
auto inputIndex = component->inputs[0]; |
||||
if (inputIndex >= flowState->flow->componentInputs.count) { |
||||
throwError(flowState, componentIndex, "Invalid input index in Output\n"); |
||||
return; |
||||
} |
||||
|
||||
auto value = flowState->values[inputIndex]; |
||||
|
||||
auto callActionComponent = (CallActionActionComponent *)flowState->parentComponent; |
||||
|
||||
uint8_t parentComponentOutputIndex = callActionComponent->outputsStartIndex + component->outputIndex; |
||||
|
||||
if (parentComponentOutputIndex >= flowState->parentComponent->outputs.count) { |
||||
throwError(flowState, componentIndex, "Output action component, invalid output index\n"); |
||||
return; |
||||
} |
||||
|
||||
propagateValue(flowState->parentFlowState, flowState->parentComponentIndex, parentComponentOutputIndex, value); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/components/roller_widget.h> |
||||
#include <eez/gui/widgets/roller.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeRollerWidgetComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
|
||||
static const unsigned START_INPUT_INDEX = 0; |
||||
auto startInputIndex = component->inputs[START_INPUT_INDEX]; |
||||
if (flowState->values[startInputIndex].type != VALUE_TYPE_UNDEFINED) { |
||||
auto executionState = (RollerWidgetComponenentExecutionState *)flowState->componenentExecutionStates[componentIndex]; |
||||
if (!executionState) { |
||||
executionState = allocateComponentExecutionState<RollerWidgetComponenentExecutionState>(flowState, componentIndex); |
||||
} |
||||
executionState->clear = true; |
||||
} |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/flow/private.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct RollerWidgetComponenentExecutionState : public ComponenentExecutionState { |
||||
bool clear; |
||||
}; |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
#include <eez/flow/private.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeSelectLanguageComponent(FlowState *flowState, unsigned componentIndex) { |
||||
Value languageValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::SELECT_LANGUAGE_ACTION_COMPONENT_PROPERTY_LANGUAGE, languageValue, "Failed to evaluate Language in SelectLanguage")) { |
||||
return; |
||||
} |
||||
|
||||
const char *language = languageValue.getString(); |
||||
|
||||
auto languages = flowState->assets->languages; |
||||
|
||||
for (uint32_t languageIndex = 0; languageIndex < languages.count; languageIndex++) { |
||||
if (strcmp(languages[languageIndex]->languageID, language) == 0) { |
||||
g_selectedLanguage = languageIndex; |
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
char message[256]; |
||||
snprintf(message, sizeof(message), "Unknown language %s", language); |
||||
throwError(flowState, componentIndex, message); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
#include <eez/flow/private.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
#define PAGE_DIRECTION_LTR 0 |
||||
#define PAGE_DIRECTION_RTL 1 |
||||
|
||||
struct SetPageDirectionComponent : public Component { |
||||
uint8_t direction; |
||||
}; |
||||
|
||||
void executeSetPageDirectionComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = (SetPageDirectionComponent *)flowState->flow->components[componentIndex]; |
||||
|
||||
gui::g_isRTL = component->direction == PAGE_DIRECTION_RTL; |
||||
|
||||
gui::refreshScreen(); |
||||
|
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
#include <eez/flow/components/set_variable.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeSetVariableComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = (SetVariableActionComponent *)flowState->flow->components[componentIndex]; |
||||
|
||||
for (uint32_t entryIndex = 0; entryIndex < component->entries.count; entryIndex++) { |
||||
auto entry = component->entries[entryIndex]; |
||||
|
||||
char strErrorMessage[256]; |
||||
snprintf(strErrorMessage, sizeof(strErrorMessage), "Failed to evaluate Variable no. %d in SetVariable", (int)(entryIndex + 1)); |
||||
|
||||
Value dstValue; |
||||
if (!evalAssignableExpression(flowState, componentIndex, entry->variable, dstValue, strErrorMessage)) { |
||||
return; |
||||
} |
||||
|
||||
snprintf(strErrorMessage, sizeof(strErrorMessage), "Failed to evaluate Value no. %d in SetVariable", (int)(entryIndex + 1)); |
||||
|
||||
Value srcValue; |
||||
if (!evalExpression(flowState, componentIndex, entry->value, srcValue, strErrorMessage)) { |
||||
return; |
||||
} |
||||
|
||||
assignValue(flowState, componentIndex, dstValue, srcValue); |
||||
} |
||||
|
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2022-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/flow/private.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct SetVariableEntry { |
||||
eez::gui::AssetsPtr<uint8_t> variable; |
||||
eez::gui::AssetsPtr<uint8_t> value; |
||||
}; |
||||
|
||||
struct SetVariableActionComponent : public Component { |
||||
eez::gui::ListOfAssetsPtr<SetVariableEntry> entries; |
||||
}; |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/flow.h> |
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
#include <eez/flow/operations.h> |
||||
#include <eez/flow/private.h> |
||||
#include <eez/flow/hooks.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct ShowKeyboardActionComponent : public Component { |
||||
uint8_t password; |
||||
}; |
||||
|
||||
void executeShowKeyboardComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = (ShowKeyboardActionComponent *)flowState->flow->components[componentIndex]; |
||||
|
||||
Value labelValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::SHOW_KEYBOARD_ACTION_COMPONENT_PROPERTY_LABEL, labelValue, "Failed to evaluate Label in ShowKeyboard")) { |
||||
return; |
||||
} |
||||
|
||||
Value initialTextValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::SHOW_KEYBOARD_ACTION_COMPONENT_PROPERTY_INITAL_TEXT, initialTextValue, "Failed to evaluate InitialText in ShowKeyboard")) { |
||||
return; |
||||
} |
||||
|
||||
Value minCharsValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::SHOW_KEYBOARD_ACTION_COMPONENT_PROPERTY_MIN_CHARS, minCharsValue, "Failed to evaluate MinChars in ShowKeyboard")) { |
||||
return; |
||||
} |
||||
|
||||
Value maxCharsValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::SHOW_KEYBOARD_ACTION_COMPONENT_PROPERTY_MAX_CHARS, maxCharsValue, "Failed to evaluate MaxChars in ShowKeyboard")) { |
||||
return; |
||||
} |
||||
|
||||
static FlowState *g_showKeyboardFlowState; |
||||
static unsigned g_showKeyboardComponentIndex; |
||||
|
||||
g_showKeyboardFlowState = flowState; |
||||
g_showKeyboardComponentIndex = componentIndex; |
||||
|
||||
startAsyncExecution(flowState, componentIndex); |
||||
|
||||
auto onOk = [](char *value) { |
||||
propagateValue(g_showKeyboardFlowState, g_showKeyboardComponentIndex, 0, Value::makeStringRef(value, -1, 0x87d32fe2)); |
||||
getAppContextFromId(APP_CONTEXT_ID_DEVICE)->popPage(); |
||||
endAsyncExecution(g_showKeyboardFlowState, g_showKeyboardComponentIndex); |
||||
}; |
||||
|
||||
auto onCancel = []() { |
||||
propagateValue(g_showKeyboardFlowState, g_showKeyboardComponentIndex, 1, Value()); |
||||
getAppContextFromId(APP_CONTEXT_ID_DEVICE)->popPage(); |
||||
endAsyncExecution(g_showKeyboardFlowState, g_showKeyboardComponentIndex); |
||||
}; |
||||
|
||||
const char *label = labelValue.getString(); |
||||
if (label && *label) { |
||||
labelValue = op_add(labelValue, Value(": ")); |
||||
} |
||||
|
||||
showKeyboardHook(labelValue, initialTextValue, minCharsValue, maxCharsValue, component->password, onOk, onCancel); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/flow.h> |
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
#include <eez/flow/operations.h> |
||||
#include <eez/flow/private.h> |
||||
#include <eez/flow/hooks.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct ShowKeyboardActionComponent : public Component { |
||||
uint8_t password; |
||||
}; |
||||
|
||||
void executeShowKeypadComponent(FlowState *flowState, unsigned componentIndex) { |
||||
Value labelValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::SHOW_KEYBOARD_ACTION_COMPONENT_PROPERTY_LABEL, labelValue, "Failed to evaluate Label in ShowKeypad")) { |
||||
return; |
||||
} |
||||
|
||||
Value initialValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::SHOW_KEYPAD_ACTION_COMPONENT_PROPERTY_INITAL_VALUE, initialValue, "Failed to evaluate InitialValue in ShowKeypad")) { |
||||
return; |
||||
} |
||||
|
||||
Value minValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::SHOW_KEYPAD_ACTION_COMPONENT_PROPERTY_MIN, minValue, "Failed to evaluate Min in ShowKeypad")) { |
||||
return; |
||||
} |
||||
|
||||
Value maxValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::SHOW_KEYPAD_ACTION_COMPONENT_PROPERTY_MAX, maxValue, "Failed to evaluate Max in ShowKeypad")) { |
||||
return; |
||||
} |
||||
|
||||
Value unitValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::SHOW_KEYPAD_ACTION_COMPONENT_PROPERTY_UNIT, unitValue, "Failed to evaluate Unit in ShowKeypad")) { |
||||
return; |
||||
} |
||||
|
||||
static FlowState *g_showKeyboardFlowState; |
||||
static unsigned g_showKeyboardComponentIndex; |
||||
|
||||
g_showKeyboardFlowState = flowState; |
||||
g_showKeyboardComponentIndex = componentIndex; |
||||
|
||||
startAsyncExecution(flowState, componentIndex); |
||||
|
||||
auto onOk = [](float value) { |
||||
Value precisionValue; |
||||
if (!evalProperty(g_showKeyboardFlowState, g_showKeyboardComponentIndex, defs_v3::SHOW_KEYPAD_ACTION_COMPONENT_PROPERTY_PRECISION, precisionValue, "Failed to evaluate Precision in ShowKeypad")) { |
||||
return; |
||||
} |
||||
|
||||
float precision = precisionValue.toFloat(); |
||||
|
||||
Value unitValue; |
||||
if (!evalProperty(g_showKeyboardFlowState, g_showKeyboardComponentIndex, defs_v3::SHOW_KEYPAD_ACTION_COMPONENT_PROPERTY_UNIT, unitValue, "Failed to evaluate Unit in ShowKeypad")) { |
||||
return; |
||||
} |
||||
|
||||
Unit unit = getUnitFromName(unitValue.getString()); |
||||
|
||||
value = roundPrec(value, precision) / getUnitFactor(unit); |
||||
|
||||
propagateValue(g_showKeyboardFlowState, g_showKeyboardComponentIndex, 0, Value(value, VALUE_TYPE_FLOAT)); |
||||
getAppContextFromId(APP_CONTEXT_ID_DEVICE)->popPage(); |
||||
endAsyncExecution(g_showKeyboardFlowState, g_showKeyboardComponentIndex); |
||||
}; |
||||
|
||||
auto onCancel = []() { |
||||
propagateValue(g_showKeyboardFlowState, g_showKeyboardComponentIndex, 1, Value()); |
||||
getAppContextFromId(APP_CONTEXT_ID_DEVICE)->popPage(); |
||||
endAsyncExecution(g_showKeyboardFlowState, g_showKeyboardComponentIndex); |
||||
}; |
||||
|
||||
const char *label = labelValue.getString(); |
||||
if (label && *label) { |
||||
labelValue = op_add(labelValue, Value(": ")); |
||||
} |
||||
|
||||
Unit unit = getUnitFromName(unitValue.getString()); |
||||
|
||||
showKeypadHook(labelValue, initialValue, minValue, maxValue, unit, onOk, onCancel); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/flow.h> |
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
const uint8_t MESSAGE_BOX_TYPE_INFO = 1; |
||||
const uint8_t MESSAGE_BOX_TYPE_ERROR = 2; |
||||
|
||||
struct ShowMessagePageActionComponent : public Component { |
||||
uint8_t type; |
||||
}; |
||||
|
||||
void executeShowMessageBoxComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = (ShowMessagePageActionComponent *)flowState->flow->components[componentIndex]; |
||||
|
||||
Value messageValue; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::SHOW_MESSAGE_BOX_ACTION_COMPONENT_PROPERTY_MESSAGE, messageValue, "Failed to evaluate Message in ShowMessageBox")) { |
||||
return; |
||||
} |
||||
|
||||
if (component->type == MESSAGE_BOX_TYPE_INFO) { |
||||
getAppContextFromId(APP_CONTEXT_ID_DEVICE)->infoMessage(messageValue); |
||||
} else if (component->type == MESSAGE_BOX_TYPE_ERROR) { |
||||
getAppContextFromId(APP_CONTEXT_ID_DEVICE)->errorMessage(messageValue); |
||||
} |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/flow.h> |
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/debugger.h> |
||||
#include <eez/flow/hooks.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct ShowPageActionComponent : public Component { |
||||
int16_t page; |
||||
}; |
||||
|
||||
void executeShowPageComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = (ShowPageActionComponent *)flowState->flow->components[componentIndex]; |
||||
|
||||
replacePageHook(component->page); |
||||
|
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeStartComponent(FlowState *flowState, unsigned componentIndex) { |
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
|
||||
#include <eez/flow/components/switch.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void executeSwitchComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = (SwitchActionComponent *)flowState->flow->components[componentIndex]; |
||||
|
||||
for (uint32_t testIndex = 0; testIndex < component->tests.count; testIndex++) { |
||||
auto test = component->tests[testIndex]; |
||||
|
||||
char strMessage[256]; |
||||
snprintf(strMessage, sizeof(strMessage), "Failed to evaluate test condition no. %d in Switch", (int)(testIndex + 1)); |
||||
|
||||
Value conditionValue; |
||||
if (!evalExpression(flowState, componentIndex, test->conditionInstructions, conditionValue, strMessage)) { |
||||
return; |
||||
} |
||||
|
||||
int err; |
||||
bool result = conditionValue.toBool(&err); |
||||
if (err == 0) { |
||||
if (result) { |
||||
propagateValue(flowState, componentIndex, test->outputIndex); |
||||
break; |
||||
} |
||||
} else { |
||||
char strMessage[256]; |
||||
snprintf(strMessage, sizeof(strMessage), "Failed to convert Value no. %d to boolean in Switch\n", (int)(testIndex + 1)); |
||||
throwError(flowState, componentIndex, strMessage); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2022-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/flow/private.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct SwitchTest { |
||||
uint8_t outputIndex; |
||||
uint8_t conditionInstructions[1]; |
||||
}; |
||||
|
||||
struct SwitchActionComponent : public Component { |
||||
eez::gui::ListOfAssetsPtr<SwitchTest> tests; |
||||
}; |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include <eez/core/alloc.h> |
||||
#include <eez/core/os.h> |
||||
|
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/expression.h> |
||||
#include <eez/flow/queue.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
struct WatchVariableComponenentExecutionState : public ComponenentExecutionState { |
||||
Value value; |
||||
}; |
||||
|
||||
void executeWatchVariableComponent(FlowState *flowState, unsigned componentIndex) { |
||||
auto watchVariableComponentExecutionState = (WatchVariableComponenentExecutionState *)flowState->componenentExecutionStates[componentIndex]; |
||||
|
||||
Value value; |
||||
if (!evalProperty(flowState, componentIndex, defs_v3::WATCH_VARIABLE_ACTION_COMPONENT_PROPERTY_VARIABLE, value, "Failed to evaluate Variable in WatchVariable")) { |
||||
return; |
||||
} |
||||
|
||||
if (!watchVariableComponentExecutionState) { |
||||
watchVariableComponentExecutionState = allocateComponentExecutionState<WatchVariableComponenentExecutionState>(flowState, componentIndex); |
||||
watchVariableComponentExecutionState->value = value; |
||||
|
||||
propagateValue(flowState, componentIndex, 1, value); |
||||
|
||||
if (!addToQueue(flowState, componentIndex, -1, -1, -1, true)) { |
||||
throwError(flowState, componentIndex, "Execution queue is full\n"); |
||||
return; |
||||
} |
||||
} else { |
||||
if (value != watchVariableComponentExecutionState->value) { |
||||
watchVariableComponentExecutionState->value = value; |
||||
propagateValue(flowState, componentIndex, 1, value); |
||||
} |
||||
|
||||
if (canFreeFlowState(flowState, false)) { |
||||
deallocateComponentExecutionState(flowState, componentIndex); |
||||
} else { |
||||
if (!addToQueue(flowState, componentIndex, -1, -1, -1, true)) { |
||||
throwError(flowState, componentIndex, "Execution queue is full\n"); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,378 +0,0 @@
|
||||
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#if defined(__EMSCRIPTEN__) |
||||
|
||||
#include <emscripten.h> |
||||
|
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
|
||||
#include <eez/flow/flow.h> |
||||
#include <eez/flow/expression.h> |
||||
#include <eez/flow/dashboard_api.h> |
||||
|
||||
using namespace eez; |
||||
using namespace eez::gui; |
||||
using namespace eez::flow; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
int getFlowStateIndex(FlowState *flowState) { |
||||
return (int)((uint8_t *)flowState - ALLOC_BUFFER); |
||||
} |
||||
|
||||
struct DashboardComponentExecutionState : public ComponenentExecutionState { |
||||
~DashboardComponentExecutionState() { |
||||
EM_ASM({ |
||||
freeComponentExecutionState($0, $1); |
||||
}, g_wasmModuleId, state); |
||||
} |
||||
int32_t state; |
||||
}; |
||||
|
||||
} // flow
|
||||
} // eez
|
||||
|
||||
static inline FlowState *getFlowState(int flowStateIndex) { |
||||
return (FlowState *)(ALLOC_BUFFER + flowStateIndex); |
||||
} |
||||
|
||||
static void updateArrayValue(ArrayValue *arrayValue1, ArrayValue *arrayValue2) { |
||||
for (uint32_t i = 0; i < arrayValue1->arraySize; i++) { |
||||
if (arrayValue1->values[i].getType() == VALUE_TYPE_ARRAY || arrayValue1->values[i].getType() == VALUE_TYPE_ARRAY_REF) { |
||||
updateArrayValue(arrayValue1->values[i].getArray(), arrayValue2->values[i].getArray()); |
||||
} else { |
||||
arrayValue1->values[i] = arrayValue2->values[i]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
EM_PORT_API(Value *) createUndefinedValue() { |
||||
auto pValue = ObjectAllocator<Value>::allocate(0x2e821285); |
||||
*pValue = Value(0, VALUE_TYPE_UNDEFINED); |
||||
return pValue; |
||||
} |
||||
|
||||
EM_PORT_API(Value *) createNullValue() { |
||||
auto pValue = ObjectAllocator<Value>::allocate(0x69debded); |
||||
*pValue = Value(0, VALUE_TYPE_NULL); |
||||
return pValue; |
||||
} |
||||
|
||||
EM_PORT_API(Value *) createIntValue(int value) { |
||||
auto pValue = ObjectAllocator<Value>::allocate(0x20ea356c); |
||||
*pValue = Value(value, VALUE_TYPE_INT32); |
||||
return pValue; |
||||
} |
||||
|
||||
EM_PORT_API(Value *) createDoubleValue(double value) { |
||||
auto pValue = ObjectAllocator<Value>::allocate(0xecfb69a9); |
||||
*pValue = Value(value, VALUE_TYPE_DOUBLE); |
||||
return pValue; |
||||
} |
||||
|
||||
EM_PORT_API(Value *) createBooleanValue(int value) { |
||||
auto pValue = ObjectAllocator<Value>::allocate(0x76071378); |
||||
*pValue = Value(value, VALUE_TYPE_BOOLEAN); |
||||
return pValue; |
||||
} |
||||
|
||||
EM_PORT_API(Value *) createStringValue(const char *value) { |
||||
auto pValue = ObjectAllocator<Value>::allocate(0x0a8a7ed1); |
||||
Value stringValue = Value::makeStringRef(value, strlen(value), 0x5b1e51d7); |
||||
*pValue = stringValue; |
||||
return pValue; |
||||
} |
||||
|
||||
EM_PORT_API(Value *) createArrayValue(int arraySize, int arrayType) { |
||||
Value value = Value::makeArrayRef(arraySize, arrayType, 0xeabb7edc); |
||||
auto pValue = ObjectAllocator<Value>::allocate(0xbab14c6a); |
||||
if (pValue) { |
||||
*pValue = value; |
||||
} |
||||
return pValue; |
||||
} |
||||
|
||||
EM_PORT_API(Value *) createStreamValue(double value) { |
||||
auto pValue = ObjectAllocator<Value>::allocate(0x53a2e660); |
||||
*pValue = Value(value, VALUE_TYPE_STREAM); |
||||
return pValue; |
||||
} |
||||
|
||||
EM_PORT_API(Value *) createDateValue(double value) { |
||||
auto pValue = ObjectAllocator<Value>::allocate(0x90b7ce70); |
||||
*pValue = Value(value, VALUE_TYPE_DATE); |
||||
return pValue; |
||||
} |
||||
|
||||
EM_PORT_API(void) arrayValueSetElementValue(Value *arrayValuePtr, int elementIndex, Value *valuePtr) { |
||||
auto array = arrayValuePtr->getArray(); |
||||
array->values[elementIndex] = *valuePtr; |
||||
} |
||||
|
||||
EM_PORT_API(void) valueFree(Value *valuePtr) { |
||||
ObjectAllocator<Value>::deallocate(valuePtr); |
||||
} |
||||
|
||||
EM_PORT_API(void) setGlobalVariable(int globalVariableIndex, Value *valuePtr) { |
||||
auto flowDefinition = static_cast<FlowDefinition *>(g_mainAssets->flowDefinition); |
||||
Value *globalVariableValuePtr = flowDefinition->globalVariables[globalVariableIndex]; |
||||
*globalVariableValuePtr = *valuePtr; |
||||
} |
||||
|
||||
EM_PORT_API(void) updateGlobalVariable(int globalVariableIndex, Value *valuePtr) { |
||||
auto flowDefinition = static_cast<FlowDefinition *>(g_mainAssets->flowDefinition); |
||||
Value *globalVariableValuePtr = flowDefinition->globalVariables[globalVariableIndex]; |
||||
updateArrayValue(globalVariableValuePtr->getArray(), valuePtr->getArray()); |
||||
} |
||||
|
||||
EM_PORT_API(int) getFlowIndex(int flowStateIndex) { |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
return flowState->flowIndex; |
||||
} |
||||
|
||||
EM_PORT_API(int) getComponentExecutionState(int flowStateIndex, int componentIndex) { |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
auto executionState = (DashboardComponentExecutionState *)flowState->componenentExecutionStates[componentIndex]; |
||||
if (executionState) { |
||||
return executionState->state; |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
EM_PORT_API(void) setComponentExecutionState(int flowStateIndex, int componentIndex, int state) { |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
auto executionState = (DashboardComponentExecutionState *)flowState->componenentExecutionStates[componentIndex]; |
||||
if (executionState) { |
||||
if (state != -1) { |
||||
executionState->state = state; |
||||
} else { |
||||
deallocateComponentExecutionState(flowState, componentIndex); |
||||
} |
||||
} else { |
||||
if (state != -1) { |
||||
executionState = allocateComponentExecutionState<DashboardComponentExecutionState>(flowState, componentIndex); |
||||
executionState->state = state; |
||||
} |
||||
} |
||||
} |
||||
|
||||
EM_PORT_API(const char *) getStringParam(int flowStateIndex, int componentIndex, int offset) { |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
auto ptr = (const uint32_t *)((const uint8_t *)component + sizeof(Component) + offset); |
||||
return (const char *)(MEMORY_BEGIN + 4 + *ptr); |
||||
} |
||||
|
||||
struct ExpressionList { |
||||
uint32_t count; |
||||
Value values[1]; |
||||
}; |
||||
|
||||
EM_PORT_API(void *) getExpressionListParam(int flowStateIndex, int componentIndex, int offset) { |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
|
||||
struct List { |
||||
uint32_t count; |
||||
uint32_t items; |
||||
}; |
||||
auto list = (const List *)((const uint8_t *)component + sizeof(Component) + offset); |
||||
|
||||
auto expressionList = (ExpressionList *)::malloc((list->count + 1) * sizeof(Value)); |
||||
|
||||
expressionList->count = list->count; |
||||
|
||||
auto items = (const uint32_t *)(MEMORY_BEGIN + 4 + list->items); |
||||
|
||||
for (uint32_t i = 0; i < list->count; i++) { |
||||
// call Value constructor
|
||||
new (expressionList->values + i) Value(); |
||||
|
||||
auto valueExpression = (const uint8_t *)(MEMORY_BEGIN + 4 + items[i]); |
||||
if (!evalExpression(flowState, componentIndex, valueExpression, expressionList->values[i], "Failed to evaluate expression")) { |
||||
return nullptr; |
||||
} |
||||
} |
||||
|
||||
return expressionList; |
||||
} |
||||
|
||||
EM_PORT_API(void) freeExpressionListParam(void *ptr) { |
||||
auto expressionList = (ExpressionList*)ptr; |
||||
|
||||
for (uint32_t i = 0; i < expressionList->count; i++) { |
||||
// call Value desctructor
|
||||
(expressionList->values + i)->~Value(); |
||||
} |
||||
|
||||
::free(ptr); |
||||
} |
||||
|
||||
EM_PORT_API(Value*) getInputValue(int flowStateIndex, int inputIndex) { |
||||
auto flowState = getFlowState(g_mainAssets, flowStateIndex); |
||||
return flowState->values + inputIndex; |
||||
} |
||||
|
||||
EM_PORT_API(void) clearInputValue(int flowStateIndex, int inputIndex) { |
||||
auto flowState = getFlowState(g_mainAssets, flowStateIndex); |
||||
flowState->values[inputIndex] = Value(); |
||||
onValueChanged(flowState->values + inputIndex); |
||||
} |
||||
|
||||
EM_PORT_API(Value *) evalProperty(int flowStateIndex, int componentIndex, int propertyIndex, int32_t *iterators) { |
||||
auto flowState = getFlowState(g_mainAssets, flowStateIndex); |
||||
|
||||
Value result; |
||||
if (!eez::flow::evalProperty(flowState, componentIndex, propertyIndex, result, "Failed to evaluate property", nullptr, iterators)) { |
||||
return nullptr; |
||||
} |
||||
|
||||
auto pValue = ObjectAllocator<Value>::allocate(0xb7e697b8); |
||||
if (!pValue) { |
||||
throwError(flowState, componentIndex, "Out of memory\n"); |
||||
return nullptr; |
||||
} |
||||
|
||||
*pValue = result; |
||||
|
||||
return pValue; |
||||
} |
||||
|
||||
EM_PORT_API(void) assignProperty(int flowStateIndex, int componentIndex, int propertyIndex, int32_t *iterators, Value *srcValuePtr) { |
||||
auto flowState = getFlowState(g_mainAssets, flowStateIndex); |
||||
|
||||
Value dstValue; |
||||
if (evalAssignableProperty(flowState, componentIndex, propertyIndex, dstValue, nullptr, nullptr, iterators)) { |
||||
assignValue(flowState, componentIndex, dstValue, *srcValuePtr); |
||||
} |
||||
} |
||||
|
||||
EM_PORT_API(void) setPropertyField(int flowStateIndex, int componentIndex, int propertyIndex, int fieldIndex, Value *valuePtr) { |
||||
auto flowState = getFlowState(g_mainAssets, flowStateIndex); |
||||
|
||||
Value result; |
||||
if (!eez::flow::evalProperty(flowState, componentIndex, propertyIndex, result, "Failed to evaluate property")) { |
||||
return; |
||||
} |
||||
|
||||
if (result.getType() == VALUE_TYPE_VALUE_PTR) { |
||||
result = *result.pValueValue; |
||||
} |
||||
|
||||
if (result.getType() != VALUE_TYPE_ARRAY && result.getType() != VALUE_TYPE_ARRAY_REF) { |
||||
throwError(flowState, componentIndex, "Property is not an array"); |
||||
return; |
||||
} |
||||
|
||||
auto array = result.getArray(); |
||||
|
||||
if (fieldIndex < 0 || fieldIndex >= array->arraySize) { |
||||
throwError(flowState, componentIndex, "Invalid field index"); |
||||
return; |
||||
} |
||||
|
||||
array->values[fieldIndex] = *valuePtr; |
||||
onValueChanged(array->values + fieldIndex); |
||||
} |
||||
|
||||
EM_PORT_API(void) propagateValue(int flowStateIndex, int componentIndex, int outputIndex, Value *valuePtr) { |
||||
auto flowState = getFlowState(g_mainAssets, flowStateIndex); |
||||
eez::flow::propagateValue(flowState, componentIndex, outputIndex, *valuePtr); |
||||
} |
||||
|
||||
EM_PORT_API(void) propagateValueThroughSeqout(int flowStateIndex, int componentIndex) { |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
eez::flow::propagateValueThroughSeqout(flowState, componentIndex); |
||||
} |
||||
|
||||
EM_PORT_API(void) startAsyncExecution(int flowStateIndex, int componentIndex) { |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
eez::flow::startAsyncExecution(flowState, componentIndex); |
||||
} |
||||
|
||||
EM_PORT_API(void) endAsyncExecution(int flowStateIndex, int componentIndex) { |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
eez::flow::endAsyncExecution(flowState, componentIndex); |
||||
} |
||||
|
||||
EM_PORT_API(void) executeCallAction(int flowStateIndex, int componentIndex, int flowIndex) { |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
eez::flow::executeCallAction(flowState, componentIndex, flowIndex); |
||||
} |
||||
|
||||
EM_PORT_API(void) logInfo(int flowStateIndex, int componentIndex, const char *infoMessage) { |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
eez::flow::logInfo(flowState, componentIndex, infoMessage); |
||||
} |
||||
|
||||
EM_PORT_API(void) throwError(int flowStateIndex, int componentIndex, const char *errorMessage) { |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
eez::flow::throwError(flowState, componentIndex, errorMessage); |
||||
} |
||||
|
||||
EM_PORT_API(int) getFirstRootFlowState() { |
||||
if (!g_firstFlowState) { |
||||
return -1; |
||||
} |
||||
return getFlowStateIndex(g_firstFlowState); |
||||
} |
||||
|
||||
EM_PORT_API(int) getFirstChildFlowState(int flowStateIndex) { |
||||
if (flowStateIndex == -1) { |
||||
return -1; |
||||
} |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
auto firstChildFlowState = flowState->firstChild; |
||||
if (!firstChildFlowState) { |
||||
return -1; |
||||
} |
||||
return getFlowStateIndex(firstChildFlowState); |
||||
} |
||||
|
||||
EM_PORT_API(int) getNextSiblingFlowState(int flowStateIndex) { |
||||
if (flowStateIndex == -1) { |
||||
return -1; |
||||
} |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
auto nextSiblingFlowState = flowState->nextSibling; |
||||
if (!nextSiblingFlowState) { |
||||
return -1; |
||||
} |
||||
return getFlowStateIndex(nextSiblingFlowState); |
||||
} |
||||
|
||||
EM_PORT_API(int) getFlowStateFlowIndex(int flowStateIndex) { |
||||
if (flowStateIndex == -1) { |
||||
return -1; |
||||
} |
||||
auto flowState = getFlowState(flowStateIndex); |
||||
return flowState->flowIndex; |
||||
} |
||||
|
||||
EM_PORT_API(bool) isRTL() { |
||||
return g_isRTL; |
||||
} |
||||
|
||||
|
||||
#endif // __EMSCRIPTEN__
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* EEZ Framework |
||||
* Copyright (C) 2022-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/flow/private.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
int getFlowStateIndex(FlowState *flowState); |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,760 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <assert.h> |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include <inttypes.h> |
||||
|
||||
#include <eez/core/debug.h> |
||||
#include <eez/core/os.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
|
||||
#include <eez/flow/flow.h> |
||||
#include <eez/flow/private.h> |
||||
#include <eez/flow/debugger.h> |
||||
#include <eez/flow/hooks.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
enum MessagesToDebugger { |
||||
MESSAGE_TO_DEBUGGER_STATE_CHANGED, // STATE
|
||||
|
||||
MESSAGE_TO_DEBUGGER_ADD_TO_QUEUE, // FLOW_STATE_INDEX, SOURCE_COMPONENT_INDEX, SOURCE_OUTPUT_INDEX, TARGET_COMPONENT_INDEX, TARGET_INPUT_INDEX, FREE_MEMORT, ALLOC_MEMORY
|
||||
MESSAGE_TO_DEBUGGER_REMOVE_FROM_QUEUE, // no params
|
||||
|
||||
MESSAGE_TO_DEBUGGER_GLOBAL_VARIABLE_INIT, // GLOBAL_VARIABLE_INDEX, VALUE_ADDR, VALUE
|
||||
MESSAGE_TO_DEBUGGER_LOCAL_VARIABLE_INIT, // FLOW_STATE_INDEX, LOCAL_VARIABLE_INDEX, VALUE_ADDR, VALUE
|
||||
MESSAGE_TO_DEBUGGER_COMPONENT_INPUT_INIT, // FLOW_STATE_INDEX, COMPONENT_INPUT_INDEX, VALUE_ADDR, VALUE
|
||||
|
||||
MESSAGE_TO_DEBUGGER_VALUE_CHANGED, // VALUE_ADDR, VALUE
|
||||
|
||||
MESSAGE_TO_DEBUGGER_FLOW_STATE_CREATED, // FLOW_STATE_INDEX, FLOW_INDEX, PARENT_FLOW_STATE_INDEX (-1 - NO PARENT), PARENT_COMPONENT_INDEX (-1 - NO PARENT COMPONENT)
|
||||
MESSAGE_TO_DEBUGGER_FLOW_STATE_TIMELINE_CHANGED, // FLOW_STATE_INDEX, TIMELINE_POSITION
|
||||
MESSAGE_TO_DEBUGGER_FLOW_STATE_DESTROYED, // FLOW_STATE_INDEX
|
||||
|
||||
MESSAGE_TO_DEBUGGER_FLOW_STATE_ERROR, // FLOW_STATE_INDEX, COMPONENT_INDEX, ERROR_MESSAGE
|
||||
|
||||
MESSAGE_TO_DEBUGGER_LOG, // LOG_ITEM_TYPE, FLOW_STATE_INDEX, COMPONENT_INDEX, MESSAGE
|
||||
|
||||
MESSAGE_TO_DEBUGGER_PAGE_CHANGED, // PAGE_ID
|
||||
|
||||
MESSAGE_TO_DEBUGGER_COMPONENT_EXECUTION_STATE_CHANGED, // FLOW_STATE_INDEX, COMPONENT_INDEX, STATE
|
||||
MESSAGE_TO_DEBUGGER_COMPONENT_ASYNC_STATE_CHANGED // FLOW_STATE_INDEX, COMPONENT_INDEX, STATE
|
||||
}; |
||||
|
||||
enum MessagesFromDebugger { |
||||
MESSAGE_FROM_DEBUGGER_RESUME, // no params
|
||||
MESSAGE_FROM_DEBUGGER_PAUSE, // no params
|
||||
MESSAGE_FROM_DEBUGGER_SINGLE_STEP, // no params
|
||||
|
||||
MESSAGE_FROM_DEBUGGER_ADD_BREAKPOINT, // FLOW_INDEX, COMPONENT_INDEX
|
||||
MESSAGE_FROM_DEBUGGER_REMOVE_BREAKPOINT, // FLOW_INDEX, COMPONENT_INDEX
|
||||
MESSAGE_FROM_DEBUGGER_ENABLE_BREAKPOINT, // FLOW_INDEX, COMPONENT_INDEX
|
||||
MESSAGE_FROM_DEBUGGER_DISABLE_BREAKPOINT, // FLOW_INDEX, COMPONENT_INDEX
|
||||
|
||||
MESSAGE_FROM_DEBUGGER_MODE // MODE (0:RUN | 1:DEBUG)
|
||||
}; |
||||
|
||||
enum LogItemType { |
||||
LOG_ITEM_TYPE_FATAL, |
||||
LOG_ITEM_TYPE_ERROR, |
||||
LOG_ITEM_TYPE_WARNING , |
||||
LOG_ITEM_TYPE_SCPI, |
||||
LOG_ITEM_TYPE_INFO, |
||||
LOG_ITEM_TYPE_DEBUG |
||||
}; |
||||
|
||||
enum DebuggerState { |
||||
DEBUGGER_STATE_RESUMED, |
||||
DEBUGGER_STATE_PAUSED, |
||||
DEBUGGER_STATE_SINGLE_STEP, |
||||
DEBUGGER_STATE_STOPPED, |
||||
}; |
||||
|
||||
bool g_debuggerIsConnected; |
||||
static DebuggerState g_debuggerState; |
||||
static bool g_skipNextBreakpoint; |
||||
|
||||
static char g_inputFromDebugger[64]; |
||||
static unsigned g_inputFromDebuggerPosition; |
||||
|
||||
int g_debuggerMode = DEBUGGER_MODE_RUN; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void setDebuggerState(DebuggerState newState) { |
||||
if (newState != g_debuggerState) { |
||||
g_debuggerState = newState; |
||||
|
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\n", |
||||
MESSAGE_TO_DEBUGGER_STATE_CHANGED, |
||||
g_debuggerState |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void onDebuggerClientConnected() { |
||||
g_debuggerIsConnected = true; |
||||
|
||||
g_skipNextBreakpoint = false; |
||||
g_inputFromDebuggerPosition = 0; |
||||
|
||||
setDebuggerState(DEBUGGER_STATE_PAUSED); |
||||
} |
||||
|
||||
void onDebuggerClientDisconnected() { |
||||
g_debuggerIsConnected = false; |
||||
setDebuggerState(DEBUGGER_STATE_RESUMED); |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void processDebuggerInput(char *buffer, uint32_t length) { |
||||
for (uint32_t i = 0; i < length; i++) { |
||||
if (buffer[i] == '\n') { |
||||
int messageFromDebugger = g_inputFromDebugger[0] - '0'; |
||||
|
||||
if (messageFromDebugger == MESSAGE_FROM_DEBUGGER_RESUME) { |
||||
setDebuggerState(DEBUGGER_STATE_RESUMED); |
||||
} else if (messageFromDebugger == MESSAGE_FROM_DEBUGGER_PAUSE) { |
||||
setDebuggerState(DEBUGGER_STATE_PAUSED); |
||||
} else if (messageFromDebugger == MESSAGE_FROM_DEBUGGER_SINGLE_STEP) { |
||||
setDebuggerState(DEBUGGER_STATE_SINGLE_STEP); |
||||
} else if ( |
||||
messageFromDebugger >= MESSAGE_FROM_DEBUGGER_ADD_BREAKPOINT && |
||||
messageFromDebugger <= MESSAGE_FROM_DEBUGGER_DISABLE_BREAKPOINT |
||||
) { |
||||
char *p; |
||||
auto flowIndex = (uint32_t)strtol(g_inputFromDebugger + 2, &p, 10); |
||||
auto componentIndex = (uint32_t)strtol(p + 1, nullptr, 10); |
||||
|
||||
auto assets = g_firstFlowState->assets; |
||||
auto flowDefinition = static_cast<FlowDefinition *>(assets->flowDefinition); |
||||
if (flowIndex >= 0 && flowIndex < flowDefinition->flows.count) { |
||||
auto flow = flowDefinition->flows[flowIndex]; |
||||
if (componentIndex >= 0 && componentIndex < flow->components.count) { |
||||
auto component = flow->components[componentIndex]; |
||||
|
||||
component->breakpoint = messageFromDebugger == MESSAGE_FROM_DEBUGGER_ADD_BREAKPOINT || |
||||
messageFromDebugger == MESSAGE_FROM_DEBUGGER_ENABLE_BREAKPOINT ? 1 : 0; |
||||
} else { |
||||
ErrorTrace("Invalid breakpoint component index\n"); |
||||
} |
||||
} else { |
||||
ErrorTrace("Invalid breakpoint flow index\n"); |
||||
} |
||||
} else if (messageFromDebugger == MESSAGE_FROM_DEBUGGER_MODE) { |
||||
g_debuggerMode = strtol(g_inputFromDebugger + 2, nullptr, 10); |
||||
gui::refreshScreen(); |
||||
} |
||||
|
||||
g_inputFromDebuggerPosition = 0; |
||||
} else { |
||||
if (g_inputFromDebuggerPosition < sizeof(g_inputFromDebugger)) { |
||||
g_inputFromDebugger[g_inputFromDebuggerPosition++] = buffer[i]; |
||||
} else if (g_inputFromDebuggerPosition == sizeof(g_inputFromDebugger)) { |
||||
ErrorTrace("Input from debugger buffer overflow\n"); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool canExecuteStep(FlowState *&flowState, unsigned &componentIndex) { |
||||
if (!g_debuggerIsConnected) { |
||||
return true; |
||||
} |
||||
|
||||
if (g_debuggerState == DEBUGGER_STATE_PAUSED) { |
||||
return false; |
||||
} |
||||
|
||||
if (g_debuggerState == DEBUGGER_STATE_SINGLE_STEP) { |
||||
g_skipNextBreakpoint = false; |
||||
setDebuggerState(DEBUGGER_STATE_PAUSED); |
||||
return true; |
||||
} |
||||
|
||||
// g_debuggerState == DEBUGGER_STATE_RESUMED
|
||||
|
||||
if (g_skipNextBreakpoint) { |
||||
g_skipNextBreakpoint = false; |
||||
} else { |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
if (component->breakpoint) { |
||||
g_skipNextBreakpoint = true; |
||||
setDebuggerState(DEBUGGER_STATE_PAUSED); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(__EMSCRIPTEN__) |
||||
char outputBuffer[1024 * 1024]; |
||||
#else |
||||
char outputBuffer[64]; |
||||
#endif |
||||
int outputBufferPosition = 0; |
||||
|
||||
#define WRITE_TO_OUTPUT_BUFFER(ch) \ |
||||
outputBuffer[outputBufferPosition++] = ch; \
|
||||
if (outputBufferPosition == sizeof(outputBuffer)) { \
|
||||
writeDebuggerBufferHook(outputBuffer, outputBufferPosition); \
|
||||
outputBufferPosition = 0; \
|
||||
} |
||||
|
||||
#define FLUSH_OUTPUT_BUFFER() \ |
||||
if (outputBufferPosition > 0) { \
|
||||
writeDebuggerBufferHook(outputBuffer, outputBufferPosition); \
|
||||
outputBufferPosition = 0; \
|
||||
} |
||||
|
||||
void writeValueAddr(const void *pValue) { |
||||
char tmpStr[32]; |
||||
snprintf(tmpStr, sizeof(tmpStr), "%p", pValue); |
||||
auto len = strlen(tmpStr); |
||||
for (size_t i = 0; i < len; i++) { |
||||
WRITE_TO_OUTPUT_BUFFER(tmpStr[i]); |
||||
} |
||||
} |
||||
|
||||
void writeString(const char *str) { |
||||
WRITE_TO_OUTPUT_BUFFER('"'); |
||||
|
||||
for (const char *p = str; *p; p++) { |
||||
if (*p == '"') { |
||||
WRITE_TO_OUTPUT_BUFFER('\\'); |
||||
WRITE_TO_OUTPUT_BUFFER('"'); |
||||
} else if (*p == '\t') { |
||||
WRITE_TO_OUTPUT_BUFFER('\\'); |
||||
WRITE_TO_OUTPUT_BUFFER('t'); |
||||
} else if (*p == '\n') { |
||||
WRITE_TO_OUTPUT_BUFFER('\\'); |
||||
WRITE_TO_OUTPUT_BUFFER('n'); |
||||
} else { |
||||
WRITE_TO_OUTPUT_BUFFER(*p); |
||||
} |
||||
} |
||||
|
||||
WRITE_TO_OUTPUT_BUFFER('"'); |
||||
WRITE_TO_OUTPUT_BUFFER('\n'); |
||||
FLUSH_OUTPUT_BUFFER(); |
||||
} |
||||
|
||||
void writeArrayType(uint32_t arrayType) { |
||||
char tmpStr[32]; |
||||
snprintf(tmpStr, sizeof(tmpStr), "%x", (int)arrayType); |
||||
auto len = strlen(tmpStr); |
||||
for (size_t i = 0; i < len; i++) { |
||||
WRITE_TO_OUTPUT_BUFFER(tmpStr[i]); |
||||
} |
||||
} |
||||
|
||||
void writeArray(const ArrayValue *arrayValue) { |
||||
WRITE_TO_OUTPUT_BUFFER('{'); |
||||
|
||||
writeValueAddr(arrayValue); |
||||
|
||||
WRITE_TO_OUTPUT_BUFFER(','); |
||||
writeArrayType(arrayValue->arrayType); |
||||
|
||||
for (uint32_t i = 0; i < arrayValue->arraySize; i++) { |
||||
WRITE_TO_OUTPUT_BUFFER(','); |
||||
writeValueAddr(&arrayValue->values[i]); |
||||
} |
||||
|
||||
WRITE_TO_OUTPUT_BUFFER('}'); |
||||
WRITE_TO_OUTPUT_BUFFER('\n'); |
||||
FLUSH_OUTPUT_BUFFER(); |
||||
|
||||
for (uint32_t i = 0; i < arrayValue->arraySize; i++) { |
||||
onValueChanged(&arrayValue->values[i]); |
||||
} |
||||
} |
||||
|
||||
void writeHex(char *dst, uint8_t *src, size_t srcLength) { |
||||
*dst++ = 'H'; |
||||
for (size_t i = 0; i < srcLength; i++) { |
||||
*dst++ = toHexDigit(src[i] / 16); |
||||
*dst++ = toHexDigit(src[i] % 16); |
||||
} |
||||
*dst++ = 0; |
||||
} |
||||
|
||||
void writeValue(const Value &value) { |
||||
char tempStr[64]; |
||||
|
||||
#ifdef _MSC_VER |
||||
#pragma warning(push) |
||||
#pragma warning(disable : 4474) |
||||
#endif |
||||
|
||||
switch (value.getType()) { |
||||
case VALUE_TYPE_UNDEFINED: |
||||
stringCopy(tempStr, sizeof(tempStr) - 1, "undefined\n"); |
||||
break; |
||||
|
||||
case VALUE_TYPE_NULL: |
||||
stringCopy(tempStr, sizeof(tempStr) - 1, "null\n"); |
||||
break; |
||||
|
||||
case VALUE_TYPE_BOOLEAN: |
||||
stringCopy(tempStr, sizeof(tempStr) - 1, value.getBoolean() ? "true" : "false"); |
||||
break; |
||||
|
||||
case VALUE_TYPE_INT8: |
||||
snprintf(tempStr, sizeof(tempStr) - 1, "%" PRId8 "", value.int8Value); |
||||
break; |
||||
|
||||
case VALUE_TYPE_UINT8: |
||||
snprintf(tempStr, sizeof(tempStr) - 1, "%" PRIu8 "", value.uint8Value); |
||||
break; |
||||
|
||||
case VALUE_TYPE_INT16: |
||||
snprintf(tempStr, sizeof(tempStr) - 1, "%" PRId16 "", value.int16Value); |
||||
break; |
||||
|
||||
case VALUE_TYPE_UINT16: |
||||
snprintf(tempStr, sizeof(tempStr) - 1, "%" PRIu16 "", value.uint16Value); |
||||
break; |
||||
|
||||
case VALUE_TYPE_INT32: |
||||
snprintf(tempStr, sizeof(tempStr) - 1, "%" PRId32 "", value.int32Value); |
||||
break; |
||||
|
||||
case VALUE_TYPE_UINT32: |
||||
snprintf(tempStr, sizeof(tempStr) - 1, "%" PRIu32 "", value.uint32Value); |
||||
break; |
||||
|
||||
case VALUE_TYPE_INT64: |
||||
snprintf(tempStr, sizeof(tempStr) - 1, "%" PRId64 "", value.int64Value); |
||||
break; |
||||
|
||||
case VALUE_TYPE_UINT64: |
||||
snprintf(tempStr, sizeof(tempStr) - 1, "%" PRIu64 "", value.uint64Value); |
||||
break; |
||||
|
||||
case VALUE_TYPE_DOUBLE: |
||||
writeHex(tempStr, (uint8_t *)&value.doubleValue, sizeof(double)); |
||||
break; |
||||
|
||||
case VALUE_TYPE_FLOAT: |
||||
writeHex(tempStr, (uint8_t *)&value.floatValue, sizeof(float)); |
||||
break; |
||||
|
||||
case VALUE_TYPE_STRING: |
||||
case VALUE_TYPE_STRING_REF: |
||||
writeString(value.getString()); |
||||
return; |
||||
|
||||
case VALUE_TYPE_ARRAY: |
||||
case VALUE_TYPE_ARRAY_REF: |
||||
writeArray(value.getArray()); |
||||
return; |
||||
|
||||
case VALUE_TYPE_BLOB_REF: |
||||
snprintf(tempStr, sizeof(tempStr) - 1, "@%d", (int)((BlobRef *)value.refValue)->len); |
||||
break; |
||||
|
||||
case VALUE_TYPE_STREAM: |
||||
snprintf(tempStr, sizeof(tempStr) - 1, ">%d", (int)(value.int32Value)); |
||||
break; |
||||
|
||||
case VALUE_TYPE_DATE: |
||||
tempStr[0] = '!'; |
||||
writeHex(tempStr + 1, (uint8_t *)&value.doubleValue, sizeof(double)); |
||||
break; |
||||
|
||||
default: |
||||
tempStr[0] = 0; |
||||
break; |
||||
} |
||||
|
||||
#ifdef _MSC_VER |
||||
#pragma warning(pop) |
||||
#endif |
||||
|
||||
stringAppendString(tempStr, sizeof(tempStr), "\n"); |
||||
|
||||
writeDebuggerBufferHook(tempStr, strlen(tempStr)); |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void onStarted(Assets *assets) { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
auto flowDefinition = static_cast<FlowDefinition *>(assets->flowDefinition); |
||||
|
||||
for (uint32_t i = 0; i < flowDefinition->globalVariables.count; i++) { |
||||
auto pValue = flowDefinition->globalVariables[i]; |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\t%p\t", |
||||
MESSAGE_TO_DEBUGGER_GLOBAL_VARIABLE_INIT, |
||||
(int)i, |
||||
(const void *)pValue |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
|
||||
writeValue(*pValue); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void onStopped() { |
||||
setDebuggerState(DEBUGGER_STATE_STOPPED); |
||||
} |
||||
|
||||
void onAddToQueue(FlowState *flowState, int sourceComponentIndex, int sourceOutputIndex, unsigned targetComponentIndex, int targetInputIndex) { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
uint32_t free; |
||||
uint32_t alloc; |
||||
getAllocInfo(free, alloc); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", |
||||
MESSAGE_TO_DEBUGGER_ADD_TO_QUEUE, |
||||
(int)flowState->flowStateIndex, |
||||
sourceComponentIndex, |
||||
sourceOutputIndex, |
||||
targetComponentIndex, |
||||
targetInputIndex, |
||||
(int)free, |
||||
(int)ALLOC_BUFFER_SIZE |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
} |
||||
} |
||||
|
||||
void onRemoveFromQueue() { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\n", |
||||
MESSAGE_TO_DEBUGGER_REMOVE_FROM_QUEUE |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
} |
||||
} |
||||
|
||||
void onValueChanged(const Value *pValue) { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%p\t", |
||||
MESSAGE_TO_DEBUGGER_VALUE_CHANGED, |
||||
(const void *)pValue |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
|
||||
writeValue(*pValue); |
||||
} |
||||
} |
||||
|
||||
void onFlowStateCreated(FlowState *flowState) { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\t%d\t%d\t%d\n", |
||||
MESSAGE_TO_DEBUGGER_FLOW_STATE_CREATED, |
||||
(int)flowState->flowStateIndex, |
||||
flowState->flowIndex, |
||||
(int)(flowState->parentFlowState ? flowState->parentFlowState->flowStateIndex : -1), |
||||
flowState->parentComponentIndex |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
|
||||
auto flow = flowState->flow; |
||||
|
||||
for (uint32_t i = 0; i < flow->localVariables.count; i++) { |
||||
auto pValue = &flowState->values[flow->componentInputs.count + i]; |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\t%d\t%p\t", |
||||
MESSAGE_TO_DEBUGGER_LOCAL_VARIABLE_INIT, |
||||
(int)flowState->flowStateIndex, |
||||
(int)i, |
||||
(const void *)pValue |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
|
||||
writeValue(*pValue); |
||||
} |
||||
|
||||
for (uint32_t i = 0; i < flow->componentInputs.count; i++) { |
||||
//auto &input = flow->componentInputs[i];
|
||||
//if (!(input & COMPONENT_INPUT_FLAG_IS_SEQ_INPUT)) {
|
||||
auto pValue = &flowState->values[i]; |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\t%d\t%p\t", |
||||
MESSAGE_TO_DEBUGGER_COMPONENT_INPUT_INIT, |
||||
(int)flowState->flowStateIndex, |
||||
(int)i, |
||||
(const void *)pValue |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
|
||||
writeValue(*pValue); |
||||
//}
|
||||
} |
||||
} |
||||
} |
||||
|
||||
void onFlowStateDestroyed(FlowState *flowState) { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\n", |
||||
MESSAGE_TO_DEBUGGER_FLOW_STATE_DESTROYED, |
||||
(int)flowState->flowStateIndex |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
} |
||||
} |
||||
|
||||
void onFlowStateTimelineChanged(FlowState *flowState) { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\t%g\n", |
||||
MESSAGE_TO_DEBUGGER_FLOW_STATE_TIMELINE_CHANGED, |
||||
(int)flowState->flowStateIndex, |
||||
flowState->timelinePosition |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
} |
||||
} |
||||
|
||||
void onFlowError(FlowState *flowState, int componentIndex, const char *errorMessage) { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\t%d\t", |
||||
MESSAGE_TO_DEBUGGER_FLOW_STATE_ERROR, |
||||
(int)flowState->flowStateIndex, |
||||
componentIndex |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
writeString(errorMessage); |
||||
} |
||||
} |
||||
|
||||
void onComponentExecutionStateChanged(FlowState *flowState, int componentIndex) { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\t%d\t%d\n", |
||||
MESSAGE_TO_DEBUGGER_COMPONENT_EXECUTION_STATE_CHANGED, |
||||
(int)flowState->flowStateIndex, |
||||
componentIndex, |
||||
flowState->componenentExecutionStates[componentIndex] ? 1 : 0 |
||||
); |
||||
|
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
} |
||||
} |
||||
|
||||
void onComponentAsyncStateChanged(FlowState *flowState, int componentIndex) { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\t%d\t%d\n", |
||||
MESSAGE_TO_DEBUGGER_COMPONENT_ASYNC_STATE_CHANGED, |
||||
(int)flowState->flowStateIndex, |
||||
componentIndex, |
||||
flowState->componenentAsyncStates[componentIndex] ? 1 : 0 |
||||
); |
||||
|
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
} |
||||
} |
||||
|
||||
void writeLogMessage(const char *str) { |
||||
for (const char *p = str; *p; p++) { |
||||
if (*p == '\t') { |
||||
WRITE_TO_OUTPUT_BUFFER('\\'); |
||||
WRITE_TO_OUTPUT_BUFFER('t'); |
||||
} if (*p == '\n') { |
||||
WRITE_TO_OUTPUT_BUFFER('\\'); |
||||
WRITE_TO_OUTPUT_BUFFER('n'); |
||||
} else { |
||||
WRITE_TO_OUTPUT_BUFFER(*p); |
||||
} |
||||
} |
||||
|
||||
WRITE_TO_OUTPUT_BUFFER('\n'); |
||||
FLUSH_OUTPUT_BUFFER(); |
||||
} |
||||
|
||||
void writeLogMessage(const char *str, size_t len) { |
||||
for (size_t i = 0; i < len; i++) { |
||||
if (str[i] == '\t') { |
||||
WRITE_TO_OUTPUT_BUFFER('\\'); |
||||
WRITE_TO_OUTPUT_BUFFER('t'); |
||||
} if (str[i] == '\n') { |
||||
WRITE_TO_OUTPUT_BUFFER('\\'); |
||||
WRITE_TO_OUTPUT_BUFFER('n'); |
||||
} else { |
||||
WRITE_TO_OUTPUT_BUFFER(str[i]); |
||||
} |
||||
} |
||||
|
||||
WRITE_TO_OUTPUT_BUFFER('\n'); |
||||
FLUSH_OUTPUT_BUFFER(); |
||||
} |
||||
|
||||
void logInfo(FlowState *flowState, unsigned componentIndex, const char *message) { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\t%d\t%d\t", |
||||
MESSAGE_TO_DEBUGGER_LOG, |
||||
LOG_ITEM_TYPE_INFO, |
||||
(int)flowState->flowStateIndex, |
||||
componentIndex |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
writeLogMessage(message); |
||||
} |
||||
} |
||||
|
||||
void logScpiCommand(FlowState *flowState, unsigned componentIndex, const char *cmd) { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\t%d\t%d\tSCPI COMMAND: ", |
||||
MESSAGE_TO_DEBUGGER_LOG, |
||||
LOG_ITEM_TYPE_SCPI, |
||||
(int)flowState->flowStateIndex, |
||||
componentIndex |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
writeLogMessage(cmd); |
||||
} |
||||
} |
||||
|
||||
void logScpiQuery(FlowState *flowState, unsigned componentIndex, const char *query) { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\t%d\t%d\tSCPI QUERY: ", |
||||
MESSAGE_TO_DEBUGGER_LOG, |
||||
LOG_ITEM_TYPE_SCPI, |
||||
(int)flowState->flowStateIndex, |
||||
componentIndex |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
writeLogMessage(query); |
||||
} |
||||
} |
||||
|
||||
void logScpiQueryResult(FlowState *flowState, unsigned componentIndex, const char *resultText, size_t resultTextLen) { |
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer) - 1, "%d\t%d\t%d\t%d\tSCPI QUERY RESULT: ", |
||||
MESSAGE_TO_DEBUGGER_LOG, |
||||
LOG_ITEM_TYPE_SCPI, |
||||
(int)flowState->flowStateIndex, |
||||
componentIndex |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
writeLogMessage(resultText, resultTextLen); |
||||
} |
||||
} |
||||
|
||||
void onPageChanged(int previousPageId, int activePageId) { |
||||
if (flow::isFlowStopped()) { |
||||
return; |
||||
} |
||||
|
||||
if (previousPageId == activePageId) { |
||||
return; |
||||
} |
||||
|
||||
if (previousPageId > 0 && previousPageId < FIRST_INTERNAL_PAGE_ID) { |
||||
auto flowState = getFlowState(g_mainAssets, previousPageId - 1, WidgetCursor()); |
||||
if (flowState) { |
||||
onEvent(flowState, FLOW_EVENT_CLOSE_PAGE); |
||||
} |
||||
} else if (previousPageId < 0) { |
||||
auto flowState = getFlowState(g_externalAssets, -previousPageId - 1, WidgetCursor()); |
||||
if (flowState) { |
||||
onEvent(flowState, FLOW_EVENT_CLOSE_PAGE); |
||||
} |
||||
} |
||||
|
||||
if (activePageId > 0 && activePageId < FIRST_INTERNAL_PAGE_ID) { |
||||
auto flowState = getFlowState(g_mainAssets, activePageId - 1, WidgetCursor()); |
||||
if (flowState) { |
||||
onEvent(flowState, FLOW_EVENT_OPEN_PAGE); |
||||
} |
||||
} else if (activePageId < 0) { |
||||
auto flowState = getFlowState(g_externalAssets, -activePageId - 1, WidgetCursor()); |
||||
if (flowState) { |
||||
onEvent(flowState, FLOW_EVENT_OPEN_PAGE); |
||||
} |
||||
} |
||||
|
||||
if (g_debuggerIsConnected) { |
||||
startToDebuggerMessageHook(); |
||||
|
||||
char buffer[256]; |
||||
snprintf(buffer, sizeof(buffer), "%d\t%d\n", |
||||
MESSAGE_TO_DEBUGGER_PAGE_CHANGED, |
||||
activePageId |
||||
); |
||||
writeDebuggerBufferHook(buffer, strlen(buffer)); |
||||
} |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
extern bool g_debuggerIsConnected; |
||||
|
||||
enum { |
||||
DEBUGGER_MODE_RUN, |
||||
DEBUGGER_MODE_DEBUG, |
||||
}; |
||||
extern int g_debuggerMode; |
||||
|
||||
bool canExecuteStep(FlowState *&flowState, unsigned &componentIndex); |
||||
|
||||
void onStarted(gui::Assets *assets); |
||||
void onStopped(); |
||||
|
||||
void onAddToQueue(FlowState *flowState, int sourceComponentIndex, int sourceOutputIndex, unsigned targetComponentIndex, int targetInputIndex); |
||||
void onRemoveFromQueue(); |
||||
|
||||
void onValueChanged(const gui::Value *pValue); |
||||
|
||||
void onFlowStateCreated(FlowState *flowState); |
||||
void onFlowStateDestroyed(FlowState *flowState); |
||||
void onFlowStateTimelineChanged(FlowState *flowState); |
||||
|
||||
void onFlowError(FlowState *flowState, int componentIndex, const char *errorMessage); |
||||
|
||||
void onComponentExecutionStateChanged(FlowState *flowState, int componentIndex); |
||||
void onComponentAsyncStateChanged(FlowState *flowState, int componentIndex); |
||||
|
||||
void logInfo(FlowState *flowState, unsigned componentIndex, const char *message); |
||||
|
||||
void logScpiCommand(FlowState *flowState, unsigned componentIndex, const char *cmd); |
||||
void logScpiQuery(FlowState *flowState, unsigned componentIndex, const char *query); |
||||
void logScpiQueryResult(FlowState *flowState, unsigned componentIndex, const char *resultText, size_t resultTextLen); |
||||
|
||||
void onPageChanged(int previousPageId, int activePageId); |
||||
|
||||
void processDebuggerInput(char *buffer, uint32_t length); |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,221 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include <eez/flow/private.h> |
||||
#include <eez/flow/operations.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
EvalStack g_stack; |
||||
|
||||
static bool evalExpression(FlowState *flowState, const uint8_t *instructions, int *numInstructionBytes, const char *errorMessage) { |
||||
auto flowDefinition = flowState->flowDefinition; |
||||
auto flow = flowState->flow; |
||||
|
||||
int i = 0; |
||||
while (true) { |
||||
uint16_t instruction = instructions[i] + (instructions[i + 1] << 8); |
||||
auto instructionType = instruction & EXPR_EVAL_INSTRUCTION_TYPE_MASK; |
||||
auto instructionArg = instruction & EXPR_EVAL_INSTRUCTION_PARAM_MASK; |
||||
if (instructionType == EXPR_EVAL_INSTRUCTION_TYPE_PUSH_CONSTANT) { |
||||
if (!g_stack.push(*flowDefinition->constants[instructionArg])) { |
||||
return false; |
||||
} |
||||
} else if (instructionType == EXPR_EVAL_INSTRUCTION_TYPE_PUSH_INPUT) { |
||||
if (!g_stack.push(flowState->values[instructionArg])) { |
||||
return false; |
||||
} |
||||
} else if (instructionType == EXPR_EVAL_INSTRUCTION_TYPE_PUSH_LOCAL_VAR) { |
||||
if (!g_stack.push(&flowState->values[flow->componentInputs.count + instructionArg])) { |
||||
return false; |
||||
} |
||||
} else if (instructionType == EXPR_EVAL_INSTRUCTION_TYPE_PUSH_GLOBAL_VAR) { |
||||
if ((uint32_t)instructionArg < flowDefinition->globalVariables.count) { |
||||
if (!g_stack.push(flowDefinition->globalVariables[instructionArg])) { |
||||
return false; |
||||
} |
||||
} else { |
||||
// native variable
|
||||
if (!g_stack.push(Value((int)(instructionArg - flowDefinition->globalVariables.count + 1), VALUE_TYPE_NATIVE_VARIABLE))) { |
||||
return false; |
||||
} |
||||
} |
||||
} else if (instructionType == EXPR_EVAL_INSTRUCTION_TYPE_PUSH_OUTPUT) { |
||||
if (!g_stack.push(Value((uint16_t)instructionArg, VALUE_TYPE_FLOW_OUTPUT))) { |
||||
return false; |
||||
} |
||||
} else if (instructionType == EXPR_EVAL_INSTRUCTION_ARRAY_ELEMENT) { |
||||
auto elementIndexValue = g_stack.pop().getValue(); |
||||
auto arrayValue = g_stack.pop().getValue(); |
||||
|
||||
if (arrayValue.getType() == VALUE_TYPE_UNDEFINED || arrayValue.getType() == VALUE_TYPE_NULL) { |
||||
if (!g_stack.push(Value(0, VALUE_TYPE_UNDEFINED))) { |
||||
return false; |
||||
} |
||||
} else { |
||||
if (arrayValue.type != VALUE_TYPE_ARRAY && arrayValue.type != VALUE_TYPE_ARRAY_REF) { |
||||
throwError(flowState, g_stack.componentIndex, errorMessage, "Array value expected\n"); |
||||
return false; |
||||
} |
||||
|
||||
auto array = arrayValue.getArray(); |
||||
|
||||
int err; |
||||
auto elementIndex = elementIndexValue.toInt32(&err); |
||||
if (err) { |
||||
throwError(flowState, g_stack.componentIndex, errorMessage, "Integer value expected for array element index\n"); |
||||
return false; |
||||
} |
||||
|
||||
if (elementIndex < 0 || elementIndex >= (int)array->arraySize) { |
||||
throwError(flowState, g_stack.componentIndex, errorMessage, "Array element index out of bounds\n"); |
||||
return false; |
||||
} |
||||
|
||||
if (!g_stack.push(Value::makeArrayElementRef(arrayValue, elementIndex, 0x132e0e2f))) { |
||||
return false; |
||||
} |
||||
} |
||||
} else if (instructionType == EXPR_EVAL_INSTRUCTION_TYPE_OPERATION) { |
||||
if (!g_evalOperations[instructionArg](g_stack)) { |
||||
return false; |
||||
} |
||||
} else { |
||||
i += 2; |
||||
break; |
||||
} |
||||
|
||||
i += 2; |
||||
} |
||||
|
||||
if (numInstructionBytes) { |
||||
*numInstructionBytes = i; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool evalExpression(FlowState *flowState, int componentIndex, const uint8_t *instructions, Value &result, const char *errorMessage, int *numInstructionBytes, const int32_t *iterators, DataOperationEnum operation) { |
||||
g_stack.sp = 0; |
||||
g_stack.flowState = flowState; |
||||
g_stack.componentIndex = componentIndex; |
||||
g_stack.iterators = iterators; |
||||
|
||||
if (evalExpression(flowState, instructions, numInstructionBytes, errorMessage)) { |
||||
if (g_stack.sp == 1) { |
||||
result = g_stack.pop().getValue(); |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
result = Value(); |
||||
return false; |
||||
} |
||||
|
||||
bool evalAssignableExpression(FlowState *flowState, int componentIndex, const uint8_t *instructions, Value &result, const char *errorMessage, int *numInstructionBytes, const int32_t *iterators) { |
||||
g_stack.sp = 0; |
||||
g_stack.flowState = flowState; |
||||
g_stack.componentIndex = componentIndex; |
||||
g_stack.iterators = iterators; |
||||
|
||||
if (evalExpression(flowState, instructions, numInstructionBytes, errorMessage)) { |
||||
if (g_stack.sp == 1) { |
||||
auto finalResult = g_stack.pop(); |
||||
if (finalResult.getType() == VALUE_TYPE_VALUE_PTR || finalResult.getType() == VALUE_TYPE_NATIVE_VARIABLE || finalResult.getType() == VALUE_TYPE_FLOW_OUTPUT || finalResult.getType() == VALUE_TYPE_ARRAY_ELEMENT_VALUE) { |
||||
result = finalResult; |
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool evalProperty(FlowState *flowState, int componentIndex, int propertyIndex, Value &result, const char *errorMessage, int *numInstructionBytes, const int32_t *iterators, DataOperationEnum operation) { |
||||
if (componentIndex < 0 || componentIndex >= (int)flowState->flow->components.count) { |
||||
char message[256]; |
||||
snprintf(message, sizeof(message), "invalid component index %d in flow at index %d", componentIndex, flowState->flowIndex); |
||||
throwError(flowState, componentIndex, errorMessage, message); |
||||
return false; |
||||
} |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
if (propertyIndex < 0 || propertyIndex >= (int)component->properties.count) { |
||||
char message[256]; |
||||
snprintf(message, sizeof(message), "invalid property index %d at component index %d in flow at index %d", propertyIndex, componentIndex, flowState->flowIndex); |
||||
throwError(flowState, componentIndex, errorMessage, message); |
||||
return false; |
||||
} |
||||
return evalExpression(flowState, componentIndex, component->properties[propertyIndex]->evalInstructions, result, errorMessage, numInstructionBytes, iterators, operation); |
||||
} |
||||
|
||||
bool evalAssignableProperty(FlowState *flowState, int componentIndex, int propertyIndex, Value &result, const char *errorMessage, int *numInstructionBytes, const int32_t *iterators) { |
||||
if (componentIndex < 0 || componentIndex >= (int)flowState->flow->components.count) { |
||||
char message[256]; |
||||
snprintf(message, sizeof(message), "invalid component index %d in flow at index %d", componentIndex, flowState->flowIndex); |
||||
throwError(flowState, componentIndex, errorMessage, message); |
||||
return false; |
||||
} |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
if (propertyIndex < 0 || propertyIndex >= (int)component->properties.count) { |
||||
char message[256]; |
||||
snprintf(message, sizeof(message), "invalid property index %d (max: %d) in component at index %d in flow at index %d", propertyIndex, (int)component->properties.count, componentIndex, flowState->flowIndex); |
||||
throwError(flowState, componentIndex, errorMessage, message); |
||||
return false; |
||||
} |
||||
return evalAssignableExpression(flowState, componentIndex, component->properties[propertyIndex]->evalInstructions, result, errorMessage, numInstructionBytes, iterators); |
||||
} |
||||
|
||||
int16_t getNativeVariableId(const WidgetCursor &widgetCursor) { |
||||
if (widgetCursor.flowState) { |
||||
FlowState *flowState = widgetCursor.flowState; |
||||
auto flow = flowState->flow; |
||||
|
||||
WidgetDataItem *widgetDataItem = flow->widgetDataItems[-(widgetCursor.widget->data + 1)]; |
||||
if (widgetDataItem && widgetDataItem->componentIndex != -1 && widgetDataItem->propertyValueIndex != -1) { |
||||
auto component = flow->components[widgetDataItem->componentIndex]; |
||||
auto property = component->properties[widgetDataItem->propertyValueIndex]; |
||||
|
||||
g_stack.sp = 0; |
||||
g_stack.flowState = flowState; |
||||
g_stack.componentIndex = widgetDataItem->componentIndex; |
||||
g_stack.iterators = widgetCursor.iterators; |
||||
|
||||
if (evalExpression(flowState, property->evalInstructions, nullptr, nullptr)) { |
||||
if (g_stack.sp == 1) { |
||||
auto finalResult = g_stack.pop(); |
||||
|
||||
if (finalResult.getType() == VALUE_TYPE_NATIVE_VARIABLE) { |
||||
return finalResult.getInt(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return DATA_ID_NONE; |
||||
} |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/flow/private.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
static const size_t STACK_SIZE = 20; |
||||
|
||||
struct EvalStack { |
||||
FlowState *flowState; |
||||
int componentIndex; |
||||
const int32_t *iterators; |
||||
|
||||
Value stack[STACK_SIZE]; |
||||
size_t sp = 0; |
||||
|
||||
bool push(const Value &value) { |
||||
if (sp >= STACK_SIZE) { |
||||
throwError(flowState, componentIndex, "Evaluation stack is full\n"); |
||||
return false; |
||||
} |
||||
stack[sp++] = value; |
||||
return true; |
||||
} |
||||
|
||||
bool push(Value *pValue) { |
||||
if (sp >= STACK_SIZE) { |
||||
return false; |
||||
} |
||||
stack[sp++] = Value(pValue, VALUE_TYPE_VALUE_PTR); |
||||
return true; |
||||
} |
||||
|
||||
Value pop() { |
||||
return stack[--sp]; |
||||
} |
||||
|
||||
}; |
||||
|
||||
bool evalExpression(FlowState *flowState, int componentIndex, const uint8_t *instructions, Value &result, const char *errorMessage, int *numInstructionBytes = nullptr, const int32_t *iterators = nullptr, eez::gui::DataOperationEnum operation = eez::gui::DATA_OPERATION_GET); |
||||
bool evalAssignableExpression(FlowState *flowState, int componentIndex, const uint8_t *instructions, Value &result, const char *errorMessage, int *numInstructionBytes = nullptr, const int32_t *iterators = nullptr); |
||||
|
||||
bool evalProperty(FlowState *flowState, int componentIndex, int propertyIndex, Value &result, const char *errorMessage, int *numInstructionBytes = nullptr, const int32_t *iterators = nullptr, eez::gui::DataOperationEnum operation = eez::gui::DATA_OPERATION_GET); |
||||
bool evalAssignableProperty(FlowState *flowState, int componentIndex, int propertyIndex, Value &result, const char *errorMessage, int *numInstructionBytes = nullptr, const int32_t *iterators = nullptr); |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,331 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include <eez/core/util.h> |
||||
|
||||
#include <eez/core/os.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
#include <eez/gui/keypad.h> |
||||
#include <eez/gui/widgets/input.h> |
||||
|
||||
#include <eez/gui/widgets/containers/layout_view.h> |
||||
|
||||
#include <eez/flow/flow.h> |
||||
#include <eez/flow/components.h> |
||||
#include <eez/flow/queue.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/debugger.h> |
||||
#include <eez/flow/hooks.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
#if defined(__EMSCRIPTEN__) |
||||
uint32_t g_wasmModuleId = 0; |
||||
#endif |
||||
|
||||
static const uint32_t FLOW_TICK_MAX_DURATION_MS = 5; |
||||
|
||||
int g_selectedLanguage = 0; |
||||
FlowState *g_firstFlowState; |
||||
FlowState *g_lastFlowState; |
||||
|
||||
static bool g_isStopped = true; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned start(Assets *assets) { |
||||
auto flowDefinition = static_cast<FlowDefinition *>(assets->flowDefinition); |
||||
if (flowDefinition->flows.count == 0) { |
||||
return 0; |
||||
} |
||||
|
||||
g_isStopped = false; |
||||
|
||||
queueReset(); |
||||
|
||||
scpiComponentInitHook(); |
||||
|
||||
onStarted(assets); |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
void tick() { |
||||
if (!isFlowRunningHook()) { |
||||
return; |
||||
} |
||||
|
||||
uint32_t startTickCount = millis(); |
||||
|
||||
while (true) { |
||||
FlowState *flowState; |
||||
unsigned componentIndex; |
||||
bool continuousTask; |
||||
if (!peekNextTaskFromQueue(flowState, componentIndex, continuousTask)) { |
||||
break; |
||||
} |
||||
|
||||
if (!continuousTask && !canExecuteStep(flowState, componentIndex)) { |
||||
break; |
||||
} |
||||
|
||||
removeNextTaskFromQueue(); |
||||
|
||||
executeComponent(flowState, componentIndex); |
||||
|
||||
if (isFlowStopped()) { |
||||
break; |
||||
} |
||||
|
||||
auto component = flowState->flow->components[componentIndex]; |
||||
|
||||
for (uint32_t i = 0; i < component->inputs.count; i++) { |
||||
auto inputIndex = component->inputs[i]; |
||||
if (flowState->flow->componentInputs[inputIndex] & COMPONENT_INPUT_FLAG_IS_SEQ_INPUT) { |
||||
auto pValue = &flowState->values[inputIndex]; |
||||
*pValue = Value(); |
||||
onValueChanged(pValue); |
||||
} |
||||
} |
||||
|
||||
if (canFreeFlowState(flowState)) { |
||||
freeFlowState(flowState); |
||||
} |
||||
|
||||
if (millis() - startTickCount >= FLOW_TICK_MAX_DURATION_MS) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
finishToDebuggerMessageHook(); |
||||
} |
||||
|
||||
void freeAllChildrenFlowStates(FlowState *firstChildFlowState) { |
||||
auto flowState = firstChildFlowState; |
||||
while (flowState != nullptr) { |
||||
auto nextFlowState = flowState->nextSibling; |
||||
freeAllChildrenFlowStates(flowState->firstChild); |
||||
freeFlowState(flowState); |
||||
flowState = nextFlowState; |
||||
} |
||||
} |
||||
|
||||
void stop() { |
||||
freeAllChildrenFlowStates(g_firstFlowState); |
||||
g_firstFlowState = nullptr; |
||||
g_lastFlowState = nullptr; |
||||
|
||||
g_isStopped = true; |
||||
|
||||
queueReset(); |
||||
onStopped(); |
||||
} |
||||
|
||||
bool isFlowStopped() { |
||||
return g_isStopped; |
||||
} |
||||
|
||||
FlowState *getFlowState(Assets *assets, int flowStateIndex) { |
||||
return (FlowState *)(ALLOC_BUFFER + flowStateIndex); |
||||
} |
||||
|
||||
FlowState *getFlowState(Assets *assets, int16_t pageIndex, const WidgetCursor &widgetCursor) { |
||||
if (!assets->flowDefinition) { |
||||
return nullptr; |
||||
} |
||||
|
||||
if (!isFlowRunningHook()) { |
||||
return nullptr; |
||||
} |
||||
|
||||
if (widgetCursor.widget && widgetCursor.widget->type == WIDGET_TYPE_LAYOUT_VIEW) { |
||||
if (widgetCursor.flowState) { |
||||
auto layoutViewWidget = (LayoutViewWidget *)widgetCursor.widget; |
||||
auto flowState = widgetCursor.flowState; |
||||
auto layoutViewWidgetComponentIndex = layoutViewWidget->componentIndex; |
||||
|
||||
return getLayoutViewFlowState(flowState, layoutViewWidgetComponentIndex, pageIndex); |
||||
} |
||||
} else { |
||||
auto page = assets->pages[pageIndex]; |
||||
if (!(page->flags & PAGE_IS_USED_AS_CUSTOM_WIDGET)) { |
||||
FlowState *flowState; |
||||
for (flowState = g_firstFlowState; flowState; flowState = flowState->nextSibling) { |
||||
if (flowState->flowIndex == pageIndex) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!flowState) { |
||||
flowState = initPageFlowState(assets, pageIndex, nullptr, 0); |
||||
} |
||||
|
||||
return flowState; |
||||
} |
||||
} |
||||
|
||||
return nullptr; |
||||
} |
||||
|
||||
int getPageIndex(FlowState *flowState) { |
||||
return flowState->flowIndex; |
||||
} |
||||
|
||||
void executeFlowAction(const gui::WidgetCursor &widgetCursor, int16_t actionId, void *param) { |
||||
if (!isFlowRunningHook()) { |
||||
return; |
||||
} |
||||
|
||||
auto flowState = widgetCursor.flowState; |
||||
actionId = -actionId - 1; |
||||
|
||||
auto flow = flowState->flow; |
||||
|
||||
if (actionId >= 0 && actionId < (int16_t)flow->widgetActions.count) { |
||||
auto componentOutput = flow->widgetActions[actionId]; |
||||
if (componentOutput->componentIndex != -1 && componentOutput->componentOutputIndex != -1) { |
||||
if (widgetCursor.widget->type == WIDGET_TYPE_DROP_DOWN_LIST) { |
||||
auto params = Value::makeArrayRef(defs_v3::SYSTEM_STRUCTURE_DROP_DOWN_LIST_ACTION_PARAMS_NUM_FIELDS, defs_v3::SYSTEM_STRUCTURE_DROP_DOWN_LIST_ACTION_PARAMS, 0x53e3b30b); |
||||
|
||||
// index
|
||||
((ArrayValueRef *)params.refValue)->arrayValue.values[defs_v3::SYSTEM_STRUCTURE_DROP_DOWN_LIST_ACTION_PARAMS_FIELD_INDEX] = widgetCursor.iterators[0]; |
||||
|
||||
// indexes
|
||||
auto indexes = Value::makeArrayRef(MAX_ITERATORS, defs_v3::ARRAY_TYPE_INTEGER, 0xb1f68ef8); |
||||
for (size_t i = 0; i < MAX_ITERATORS; i++) { |
||||
((ArrayValueRef *)indexes.refValue)->arrayValue.values[i] = (int)widgetCursor.iterators[i]; |
||||
} |
||||
((ArrayValueRef *)params.refValue)->arrayValue.values[defs_v3::SYSTEM_STRUCTURE_DROP_DOWN_LIST_ACTION_PARAMS_FIELD_INDEXES] = indexes; |
||||
|
||||
// selectedIndex
|
||||
((ArrayValueRef *)params.refValue)->arrayValue.values[defs_v3::SYSTEM_STRUCTURE_DROP_DOWN_LIST_ACTION_PARAMS_FIELD_SELECTED_INDEX] = *((int *)param); |
||||
|
||||
propagateValue(flowState, componentOutput->componentIndex, componentOutput->componentOutputIndex, params); |
||||
} else { |
||||
auto params = Value::makeArrayRef(defs_v3::SYSTEM_STRUCTURE_ACTION_PARAMS_NUM_FIELDS, defs_v3::SYSTEM_STRUCTURE_ACTION_PARAMS, 0x285940bb); |
||||
|
||||
// index
|
||||
((ArrayValueRef *)params.refValue)->arrayValue.values[defs_v3::SYSTEM_STRUCTURE_ACTION_PARAMS_FIELD_INDEX] = widgetCursor.iterators[0]; |
||||
|
||||
// indexes
|
||||
auto indexes = Value::makeArrayRef(MAX_ITERATORS, defs_v3::ARRAY_TYPE_INTEGER, 0xb1f68ef8); |
||||
for (size_t i = 0; i < MAX_ITERATORS; i++) { |
||||
((ArrayValueRef *)indexes.refValue)->arrayValue.values[i] = (int)widgetCursor.iterators[i]; |
||||
} |
||||
((ArrayValueRef *)params.refValue)->arrayValue.values[defs_v3::SYSTEM_STRUCTURE_ACTION_PARAMS_FIELD_INDEXES] = indexes; |
||||
|
||||
propagateValue(flowState, componentOutput->componentIndex, componentOutput->componentOutputIndex, params); |
||||
} |
||||
} |
||||
} |
||||
|
||||
for (int i = 0; i < 3; i++) { |
||||
tick(); |
||||
} |
||||
} |
||||
|
||||
void dataOperation(int16_t dataId, DataOperationEnum operation, const gui::WidgetCursor &widgetCursor, Value &value) { |
||||
if (!isFlowRunningHook()) { |
||||
return; |
||||
} |
||||
|
||||
auto flowState = widgetCursor.flowState; |
||||
|
||||
auto flowDataId = -dataId - 1; |
||||
|
||||
auto flow = flowState->flow; |
||||
|
||||
if (flowDataId >= 0 && flowDataId < (int16_t)flow->widgetDataItems.count) { |
||||
WidgetDataItem *widgetDataItem = flow->widgetDataItems[flowDataId]; |
||||
auto component = flow->components[widgetDataItem->componentIndex]; |
||||
|
||||
if (operation == DATA_OPERATION_GET) { |
||||
getValue(flowDataId, operation, widgetCursor, value); |
||||
if (component->type == WIDGET_TYPE_INPUT && dataId == widgetCursor.widget->data) { |
||||
value = getInputWidgetData(widgetCursor, value); |
||||
} |
||||
} else if (operation == DATA_OPERATION_COUNT) { |
||||
Value arrayValue; |
||||
getValue(flowDataId, operation, widgetCursor, arrayValue); |
||||
if (arrayValue.getType() == VALUE_TYPE_ARRAY || arrayValue.getType() == VALUE_TYPE_ARRAY_REF) { |
||||
value = arrayValue.getArray()->arraySize; |
||||
} else { |
||||
value = 0; |
||||
} |
||||
}
|
||||
#if OPTION_KEYPAD |
||||
else if (operation == DATA_OPERATION_GET_TEXT_CURSOR_POSITION) { |
||||
|
||||
Keypad *keypad = getActiveKeypad(); |
||||
if (keypad) { |
||||
value = keypad->getCursorPosition(); |
||||
} |
||||
}
|
||||
#endif |
||||
else if (operation == DATA_OPERATION_GET_MIN) { |
||||
if (component->type == WIDGET_TYPE_INPUT) { |
||||
value = getInputWidgetMin(widgetCursor); |
||||
} |
||||
} else if (operation == DATA_OPERATION_GET_MAX) { |
||||
if (component->type == WIDGET_TYPE_INPUT) { |
||||
value = getInputWidgetMax(widgetCursor); |
||||
} |
||||
} else if (operation == DATA_OPERATION_GET_PRECISION) { |
||||
if (component->type == WIDGET_TYPE_INPUT) { |
||||
value = getInputWidgetPrecision(widgetCursor); |
||||
} |
||||
} else if (operation == DATA_OPERATION_GET_UNIT) { |
||||
if (component->type == WIDGET_TYPE_INPUT) { |
||||
value = getBaseUnit(getInputWidgetUnit(widgetCursor)); |
||||
} |
||||
} else if (operation == DATA_OPERATION_SET) { |
||||
if (component->type == WIDGET_TYPE_INPUT) { |
||||
auto inputWidget = (InputWidget *)widgetCursor.widget; |
||||
if (inputWidget->flags & INPUT_WIDGET_TYPE_NUMBER) { |
||||
if (value.isInt32()) { |
||||
setValue(flowDataId, widgetCursor, value); |
||||
} else { |
||||
Value precisionValue = getInputWidgetPrecision(widgetCursor); |
||||
float precision = precisionValue.toFloat(); |
||||
float valueFloat = value.toFloat(); |
||||
Unit unit = getInputWidgetUnit(widgetCursor); |
||||
setValue(flowDataId, widgetCursor, Value(roundPrec(valueFloat, precision) / getUnitFactor(unit), VALUE_TYPE_FLOAT)); |
||||
} |
||||
} else { |
||||
setValue(flowDataId, widgetCursor, value); |
||||
} |
||||
|
||||
executeFlowAction(widgetCursor, inputWidget->action, nullptr); |
||||
} else { |
||||
setValue(flowDataId, widgetCursor, value); |
||||
} |
||||
} |
||||
} else { |
||||
// TODO this shouldn't happen
|
||||
value = Value(); |
||||
} |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/gui/assets.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
#if defined(__EMSCRIPTEN__) |
||||
extern uint32_t g_wasmModuleId; |
||||
#endif |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
struct FlowState; |
||||
|
||||
unsigned start(eez::gui::Assets *assets); |
||||
void tick(); |
||||
void stop(); |
||||
|
||||
bool isFlowStopped(); |
||||
|
||||
FlowState *getFlowState(Assets *assets, int flowStateIndex); |
||||
|
||||
FlowState *getFlowState(Assets *assets, int16_t pageIndex, const WidgetCursor &widgetCursor); |
||||
int getPageIndex(FlowState *flowState); |
||||
|
||||
FlowState *getLayoutViewFlowState(FlowState *flowState, uint16_t layoutViewWidgetComponentIndex, int16_t pageId); |
||||
|
||||
void executeFlowAction(const WidgetCursor &widgetCursor, int16_t actionId, void *param); |
||||
void dataOperation(int16_t dataId, DataOperationEnum operation, const WidgetCursor &widgetCursor, Value &value); |
||||
int16_t getNativeVariableId(const WidgetCursor &widgetCursor); |
||||
|
||||
void onDebuggerClientConnected(); |
||||
void onDebuggerClientDisconnected(); |
||||
|
||||
void executeScpi(); |
||||
void flushToDebuggerMessage(); |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,444 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
namespace defs_v3 { |
||||
|
||||
enum ComponentTypes { |
||||
COMPONENT_TYPE_NONE = 0, |
||||
COMPONENT_TYPE_CONTAINER_WIDGET = 1, |
||||
COMPONENT_TYPE_LIST_WIDGET = 2, |
||||
COMPONENT_TYPE_GRID_WIDGET = 3, |
||||
COMPONENT_TYPE_SELECT_WIDGET = 4, |
||||
COMPONENT_TYPE_DISPLAY_DATA_WIDGET = 5, |
||||
COMPONENT_TYPE_TEXT_WIDGET = 6, |
||||
COMPONENT_TYPE_MULTILINE_TEXT_WIDGET = 7, |
||||
COMPONENT_TYPE_RECTANGLE_WIDGET = 8, |
||||
COMPONENT_TYPE_BITMAP_WIDGET = 9, |
||||
COMPONENT_TYPE_BUTTON_WIDGET = 10, |
||||
COMPONENT_TYPE_TOGGLE_BUTTON_WIDGET = 11, |
||||
COMPONENT_TYPE_BUTTON_GROUP_WIDGET = 12, |
||||
COMPONENT_TYPE_BAR_GRAPH_WIDGET = 14, |
||||
COMPONENT_TYPE_LAYOUT_VIEW_WIDGET = 15, |
||||
COMPONENT_TYPE_YTGRAPH_WIDGET = 16, |
||||
COMPONENT_TYPE_UP_DOWN_WIDGET = 17, |
||||
COMPONENT_TYPE_LIST_GRAPH_WIDGET = 18, |
||||
COMPONENT_TYPE_APP_VIEW_WIDGET = 19, |
||||
COMPONENT_TYPE_SCROLL_BAR_WIDGET = 20, |
||||
COMPONENT_TYPE_PROGRESS_WIDGET = 21, |
||||
COMPONENT_TYPE_CANVAS_WIDGET = 22, |
||||
COMPONENT_TYPE_GAUGE_EMBEDDED_WIDGET = 23, |
||||
COMPONENT_TYPE_INPUT_EMBEDDED_WIDGET = 24, |
||||
COMPONENT_TYPE_ROLLER_WIDGET = 25, |
||||
COMPONENT_TYPE_SWITCH_WIDGET = 26, |
||||
COMPONENT_TYPE_SLIDER_WIDGET = 27, |
||||
COMPONENT_TYPE_DROP_DOWN_LIST_WIDGET = 28, |
||||
COMPONENT_TYPE_START_ACTION = 1001, |
||||
COMPONENT_TYPE_END_ACTION = 1002, |
||||
COMPONENT_TYPE_INPUT_ACTION = 1003, |
||||
COMPONENT_TYPE_OUTPUT_ACTION = 1004, |
||||
COMPONENT_TYPE_WATCH_VARIABLE_ACTION = 1005, |
||||
COMPONENT_TYPE_EVAL_EXPR_ACTION = 1006, |
||||
COMPONENT_TYPE_SET_VARIABLE_ACTION = 1007, |
||||
COMPONENT_TYPE_SWITCH_ACTION = 1008, |
||||
COMPONENT_TYPE_COMPARE_ACTION = 1009, |
||||
COMPONENT_TYPE_IS_TRUE_ACTION = 1010, |
||||
COMPONENT_TYPE_CONSTANT_ACTION = 1011, |
||||
COMPONENT_TYPE_LOG_ACTION = 1012, |
||||
COMPONENT_TYPE_CALL_ACTION_ACTION = 1013, |
||||
COMPONENT_TYPE_DELAY_ACTION = 1014, |
||||
COMPONENT_TYPE_ERROR_ACTION = 1015, |
||||
COMPONENT_TYPE_CATCH_ERROR_ACTION = 1016, |
||||
COMPONENT_TYPE_COUNTER_ACTION = 1017, |
||||
COMPONENT_TYPE_LOOP_ACTION = 1018, |
||||
COMPONENT_TYPE_SHOW_PAGE_ACTION = 1019, |
||||
COMPONENT_TYPE_SCPIACTION = 1020, |
||||
COMPONENT_TYPE_SHOW_MESSAGE_BOX_ACTION = 1021, |
||||
COMPONENT_TYPE_SHOW_KEYBOARD_ACTION = 1022, |
||||
COMPONENT_TYPE_SHOW_KEYPAD_ACTION = 1023, |
||||
COMPONENT_TYPE_NOOP_ACTION = 1024, |
||||
COMPONENT_TYPE_COMMENT_ACTION = 1025, |
||||
COMPONENT_TYPE_SELECT_LANGUAGE_ACTION = 1026, |
||||
COMPONENT_TYPE_SET_PAGE_DIRECTION_ACTION = 1027, |
||||
COMPONENT_TYPE_ANIMATE_ACTION = 1028, |
||||
COMPONENT_TYPE_ON_EVENT_ACTION = 1029, |
||||
FIRST_DASHBOARD_COMPONENT_TYPE = 10000 |
||||
}; |
||||
|
||||
enum Component_CONTAINER_WIDGET_Properties { |
||||
CONTAINER_WIDGET_PROPERTY_DATA = 0, |
||||
CONTAINER_WIDGET_PROPERTY_VISIBLE = 1, |
||||
CONTAINER_WIDGET_PROPERTY_OVERLAY = 2 |
||||
}; |
||||
|
||||
enum Component_LIST_WIDGET_Properties { |
||||
LIST_WIDGET_PROPERTY_DATA = 0, |
||||
LIST_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_GRID_WIDGET_Properties { |
||||
GRID_WIDGET_PROPERTY_DATA = 0, |
||||
GRID_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_SELECT_WIDGET_Properties { |
||||
SELECT_WIDGET_PROPERTY_DATA = 0, |
||||
SELECT_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_DISPLAY_DATA_WIDGET_Properties { |
||||
DISPLAY_DATA_WIDGET_PROPERTY_DATA = 0, |
||||
DISPLAY_DATA_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_TEXT_WIDGET_Properties { |
||||
TEXT_WIDGET_PROPERTY_DATA = 0, |
||||
TEXT_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_MULTILINE_TEXT_WIDGET_Properties { |
||||
MULTILINE_TEXT_WIDGET_PROPERTY_DATA = 0, |
||||
MULTILINE_TEXT_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_RECTANGLE_WIDGET_Properties { |
||||
RECTANGLE_WIDGET_PROPERTY_DATA = 0, |
||||
RECTANGLE_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_BITMAP_WIDGET_Properties { |
||||
BITMAP_WIDGET_PROPERTY_DATA = 0, |
||||
BITMAP_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_BUTTON_WIDGET_Properties { |
||||
BUTTON_WIDGET_PROPERTY_DATA = 0, |
||||
BUTTON_WIDGET_PROPERTY_VISIBLE = 1, |
||||
BUTTON_WIDGET_PROPERTY_ENABLED = 2 |
||||
}; |
||||
|
||||
enum Component_TOGGLE_BUTTON_WIDGET_Properties { |
||||
TOGGLE_BUTTON_WIDGET_PROPERTY_DATA = 0, |
||||
TOGGLE_BUTTON_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_BUTTON_GROUP_WIDGET_Properties { |
||||
BUTTON_GROUP_WIDGET_PROPERTY_DATA = 0, |
||||
BUTTON_GROUP_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_BAR_GRAPH_WIDGET_Properties { |
||||
BAR_GRAPH_WIDGET_PROPERTY_DATA = 0, |
||||
BAR_GRAPH_WIDGET_PROPERTY_VISIBLE = 1, |
||||
BAR_GRAPH_WIDGET_PROPERTY_LINE1_DATA = 2, |
||||
BAR_GRAPH_WIDGET_PROPERTY_LINE2_DATA = 3 |
||||
}; |
||||
|
||||
enum Component_LAYOUT_VIEW_WIDGET_Properties { |
||||
LAYOUT_VIEW_WIDGET_PROPERTY_DATA = 0, |
||||
LAYOUT_VIEW_WIDGET_PROPERTY_VISIBLE = 1, |
||||
LAYOUT_VIEW_WIDGET_PROPERTY_CONTEXT = 2 |
||||
}; |
||||
|
||||
enum Component_YTGRAPH_WIDGET_Properties { |
||||
YTGRAPH_WIDGET_PROPERTY_DATA = 0, |
||||
YTGRAPH_WIDGET_PROPERTY_VISIBLE = 1, |
||||
YTGRAPH_WIDGET_PROPERTY_Y2_DATA = 2 |
||||
}; |
||||
|
||||
enum Component_UP_DOWN_WIDGET_Properties { |
||||
UP_DOWN_WIDGET_PROPERTY_DATA = 0, |
||||
UP_DOWN_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_LIST_GRAPH_WIDGET_Properties { |
||||
LIST_GRAPH_WIDGET_PROPERTY_DATA = 0, |
||||
LIST_GRAPH_WIDGET_PROPERTY_VISIBLE = 1, |
||||
LIST_GRAPH_WIDGET_PROPERTY_DWELL_DATA = 2, |
||||
LIST_GRAPH_WIDGET_PROPERTY_Y1_DATA = 3, |
||||
LIST_GRAPH_WIDGET_PROPERTY_Y2_DATA = 4, |
||||
LIST_GRAPH_WIDGET_PROPERTY_CURSOR_DATA = 5 |
||||
}; |
||||
|
||||
enum Component_APP_VIEW_WIDGET_Properties { |
||||
APP_VIEW_WIDGET_PROPERTY_DATA = 0, |
||||
APP_VIEW_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_SCROLL_BAR_WIDGET_Properties { |
||||
SCROLL_BAR_WIDGET_PROPERTY_DATA = 0, |
||||
SCROLL_BAR_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_PROGRESS_WIDGET_Properties { |
||||
PROGRESS_WIDGET_PROPERTY_DATA = 0, |
||||
PROGRESS_WIDGET_PROPERTY_VISIBLE = 1, |
||||
PROGRESS_WIDGET_PROPERTY_MIN = 2, |
||||
PROGRESS_WIDGET_PROPERTY_MAX = 3 |
||||
}; |
||||
|
||||
enum Component_CANVAS_WIDGET_Properties { |
||||
CANVAS_WIDGET_PROPERTY_DATA = 0, |
||||
CANVAS_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_GAUGE_EMBEDDED_WIDGET_Properties { |
||||
GAUGE_EMBEDDED_WIDGET_PROPERTY_DATA = 0, |
||||
GAUGE_EMBEDDED_WIDGET_PROPERTY_VISIBLE = 1, |
||||
GAUGE_EMBEDDED_WIDGET_PROPERTY_MIN = 2, |
||||
GAUGE_EMBEDDED_WIDGET_PROPERTY_MAX = 3, |
||||
GAUGE_EMBEDDED_WIDGET_PROPERTY_THRESHOLD = 4, |
||||
GAUGE_EMBEDDED_WIDGET_PROPERTY_UNIT = 5 |
||||
}; |
||||
|
||||
enum Component_INPUT_EMBEDDED_WIDGET_Properties { |
||||
INPUT_EMBEDDED_WIDGET_PROPERTY_DATA = 0, |
||||
INPUT_EMBEDDED_WIDGET_PROPERTY_VISIBLE = 1, |
||||
INPUT_EMBEDDED_WIDGET_PROPERTY_MIN = 2, |
||||
INPUT_EMBEDDED_WIDGET_PROPERTY_MAX = 3, |
||||
INPUT_EMBEDDED_WIDGET_PROPERTY_PRECISION = 4, |
||||
INPUT_EMBEDDED_WIDGET_PROPERTY_UNIT = 5 |
||||
}; |
||||
|
||||
enum Component_ROLLER_WIDGET_Properties { |
||||
ROLLER_WIDGET_PROPERTY_DATA = 0, |
||||
ROLLER_WIDGET_PROPERTY_VISIBLE = 1, |
||||
ROLLER_WIDGET_PROPERTY_MIN = 2, |
||||
ROLLER_WIDGET_PROPERTY_MAX = 3, |
||||
ROLLER_WIDGET_PROPERTY_TEXT = 4 |
||||
}; |
||||
|
||||
enum Component_SWITCH_WIDGET_Properties { |
||||
SWITCH_WIDGET_PROPERTY_DATA = 0, |
||||
SWITCH_WIDGET_PROPERTY_VISIBLE = 1 |
||||
}; |
||||
|
||||
enum Component_SLIDER_WIDGET_Properties { |
||||
SLIDER_WIDGET_PROPERTY_DATA = 0, |
||||
SLIDER_WIDGET_PROPERTY_VISIBLE = 1, |
||||
SLIDER_WIDGET_PROPERTY_MIN = 2, |
||||
SLIDER_WIDGET_PROPERTY_MAX = 3 |
||||
}; |
||||
|
||||
enum Component_DROP_DOWN_LIST_WIDGET_Properties { |
||||
DROP_DOWN_LIST_WIDGET_PROPERTY_DATA = 0, |
||||
DROP_DOWN_LIST_WIDGET_PROPERTY_VISIBLE = 1, |
||||
DROP_DOWN_LIST_WIDGET_PROPERTY_OPTIONS = 2 |
||||
}; |
||||
|
||||
enum Component_WATCH_VARIABLE_ACTION_COMPONENT_Properties { |
||||
WATCH_VARIABLE_ACTION_COMPONENT_PROPERTY_VARIABLE = 0 |
||||
}; |
||||
|
||||
enum Component_EVAL_EXPR_ACTION_COMPONENT_Properties { |
||||
EVAL_EXPR_ACTION_COMPONENT_PROPERTY_EXPRESSION = 0 |
||||
}; |
||||
|
||||
enum Component_COMPARE_ACTION_COMPONENT_Properties { |
||||
COMPARE_ACTION_COMPONENT_PROPERTY_A = 0, |
||||
COMPARE_ACTION_COMPONENT_PROPERTY_B = 1, |
||||
COMPARE_ACTION_COMPONENT_PROPERTY_C = 2 |
||||
}; |
||||
|
||||
enum Component_IS_TRUE_ACTION_COMPONENT_Properties { |
||||
IS_TRUE_ACTION_COMPONENT_PROPERTY_VALUE = 0 |
||||
}; |
||||
|
||||
enum Component_CONSTANT_ACTION_COMPONENT_Properties { |
||||
CONSTANT_ACTION_COMPONENT_PROPERTY_VALUE = 0 |
||||
}; |
||||
|
||||
enum Component_LOG_ACTION_COMPONENT_Properties { |
||||
LOG_ACTION_COMPONENT_PROPERTY_VALUE = 0 |
||||
}; |
||||
|
||||
enum Component_DELAY_ACTION_COMPONENT_Properties { |
||||
DELAY_ACTION_COMPONENT_PROPERTY_MILLISECONDS = 0 |
||||
}; |
||||
|
||||
enum Component_ERROR_ACTION_COMPONENT_Properties { |
||||
ERROR_ACTION_COMPONENT_PROPERTY_MESSAGE = 0 |
||||
}; |
||||
|
||||
enum Component_COUNTER_ACTION_COMPONENT_Properties { |
||||
COUNTER_ACTION_COMPONENT_PROPERTY_COUNT_VALUE = 0 |
||||
}; |
||||
|
||||
enum Component_LOOP_ACTION_COMPONENT_Properties { |
||||
LOOP_ACTION_COMPONENT_PROPERTY_VARIABLE = 0, |
||||
LOOP_ACTION_COMPONENT_PROPERTY_FROM = 1, |
||||
LOOP_ACTION_COMPONENT_PROPERTY_TO = 2, |
||||
LOOP_ACTION_COMPONENT_PROPERTY_STEP = 3 |
||||
}; |
||||
|
||||
enum Component_SCPIACTION_COMPONENT_Properties { |
||||
SCPIACTION_COMPONENT_PROPERTY_INSTRUMENT = 0 |
||||
}; |
||||
|
||||
enum Component_SHOW_MESSAGE_BOX_ACTION_COMPONENT_Properties { |
||||
SHOW_MESSAGE_BOX_ACTION_COMPONENT_PROPERTY_MESSAGE = 0 |
||||
}; |
||||
|
||||
enum Component_SHOW_KEYBOARD_ACTION_COMPONENT_Properties { |
||||
SHOW_KEYBOARD_ACTION_COMPONENT_PROPERTY_LABEL = 0, |
||||
SHOW_KEYBOARD_ACTION_COMPONENT_PROPERTY_INITAL_TEXT = 1, |
||||
SHOW_KEYBOARD_ACTION_COMPONENT_PROPERTY_MIN_CHARS = 2, |
||||
SHOW_KEYBOARD_ACTION_COMPONENT_PROPERTY_MAX_CHARS = 3 |
||||
}; |
||||
|
||||
enum Component_SHOW_KEYPAD_ACTION_COMPONENT_Properties { |
||||
SHOW_KEYPAD_ACTION_COMPONENT_PROPERTY_LABEL = 0, |
||||
SHOW_KEYPAD_ACTION_COMPONENT_PROPERTY_INITAL_VALUE = 1, |
||||
SHOW_KEYPAD_ACTION_COMPONENT_PROPERTY_MIN = 2, |
||||
SHOW_KEYPAD_ACTION_COMPONENT_PROPERTY_MAX = 3, |
||||
SHOW_KEYPAD_ACTION_COMPONENT_PROPERTY_PRECISION = 4, |
||||
SHOW_KEYPAD_ACTION_COMPONENT_PROPERTY_UNIT = 5 |
||||
}; |
||||
|
||||
enum Component_SELECT_LANGUAGE_ACTION_COMPONENT_Properties { |
||||
SELECT_LANGUAGE_ACTION_COMPONENT_PROPERTY_LANGUAGE = 0 |
||||
}; |
||||
|
||||
enum Component_ANIMATE_ACTION_COMPONENT_Properties { |
||||
ANIMATE_ACTION_COMPONENT_PROPERTY_FROM = 0, |
||||
ANIMATE_ACTION_COMPONENT_PROPERTY_TO = 1, |
||||
ANIMATE_ACTION_COMPONENT_PROPERTY_SPEED = 2 |
||||
}; |
||||
|
||||
enum OperationTypes { |
||||
OPERATION_TYPE_ADD = 0, |
||||
OPERATION_TYPE_SUB = 1, |
||||
OPERATION_TYPE_MUL = 2, |
||||
OPERATION_TYPE_DIV = 3, |
||||
OPERATION_TYPE_MOD = 4, |
||||
OPERATION_TYPE_LEFT_SHIFT = 5, |
||||
OPERATION_TYPE_RIGHT_SHIFT = 6, |
||||
OPERATION_TYPE_BINARY_AND = 7, |
||||
OPERATION_TYPE_BINARY_OR = 8, |
||||
OPERATION_TYPE_BINARY_XOR = 9, |
||||
OPERATION_TYPE_EQUAL = 10, |
||||
OPERATION_TYPE_NOT_EQUAL = 11, |
||||
OPERATION_TYPE_LESS = 12, |
||||
OPERATION_TYPE_GREATER = 13, |
||||
OPERATION_TYPE_LESS_OR_EQUAL = 14, |
||||
OPERATION_TYPE_GREATER_OR_EQUAL = 15, |
||||
OPERATION_TYPE_LOGICAL_AND = 16, |
||||
OPERATION_TYPE_LOGICAL_OR = 17, |
||||
OPERATION_TYPE_UNARY_PLUS = 18, |
||||
OPERATION_TYPE_UNARY_MINUS = 19, |
||||
OPERATION_TYPE_BINARY_ONE_COMPLEMENT = 20, |
||||
OPERATION_TYPE_NOT = 21, |
||||
OPERATION_TYPE_CONDITIONAL = 22, |
||||
OPERATION_TYPE_SYSTEM_GET_TICK = 23, |
||||
OPERATION_TYPE_FLOW_INDEX = 24, |
||||
OPERATION_TYPE_FLOW_IS_PAGE_ACTIVE = 25, |
||||
OPERATION_TYPE_FLOW_PAGE_TIMELINE_POSITION = 26, |
||||
OPERATION_TYPE_FLOW_MAKE_VALUE = 27, |
||||
OPERATION_TYPE_FLOW_MAKE_ARRAY_VALUE = 28, |
||||
OPERATION_TYPE_FLOW_LANGUAGES = 29, |
||||
OPERATION_TYPE_FLOW_TRANSLATE = 30, |
||||
OPERATION_TYPE_FLOW_PARSE_INTEGER = 31, |
||||
OPERATION_TYPE_FLOW_PARSE_FLOAT = 32, |
||||
OPERATION_TYPE_FLOW_PARSE_DOUBLE = 33, |
||||
OPERATION_TYPE_DATE_NOW = 34, |
||||
OPERATION_TYPE_DATE_TO_STRING = 35, |
||||
OPERATION_TYPE_DATE_FROM_STRING = 36, |
||||
OPERATION_TYPE_MATH_SIN = 37, |
||||
OPERATION_TYPE_MATH_COS = 38, |
||||
OPERATION_TYPE_MATH_LOG = 39, |
||||
OPERATION_TYPE_MATH_LOG10 = 40, |
||||
OPERATION_TYPE_MATH_ABS = 41, |
||||
OPERATION_TYPE_MATH_FLOOR = 42, |
||||
OPERATION_TYPE_MATH_CEIL = 43, |
||||
OPERATION_TYPE_MATH_ROUND = 44, |
||||
OPERATION_TYPE_MATH_MIN = 45, |
||||
OPERATION_TYPE_MATH_MAX = 46, |
||||
OPERATION_TYPE_STRING_FIND = 47, |
||||
OPERATION_TYPE_STRING_PAD_START = 48, |
||||
OPERATION_TYPE_STRING_SPLIT = 49, |
||||
OPERATION_TYPE_ARRAY_LENGTH = 50, |
||||
OPERATION_TYPE_ARRAY_SLICE = 51 |
||||
}; |
||||
|
||||
enum SystemStructures { |
||||
SYSTEM_STRUCTURE_ACTION_PARAMS = 20, |
||||
SYSTEM_STRUCTURE_CHECKBOX_ACTION_PARAMS = 21, |
||||
SYSTEM_STRUCTURE_TEXT_INPUT_ACTION_PARAMS = 22, |
||||
SYSTEM_STRUCTURE_DROP_DOWN_LIST_ACTION_PARAMS = 23, |
||||
SYSTEM_STRUCTURE_SERIAL_PORT = 24, |
||||
SYSTEM_STRUCTURE_TERMINAL_WIDGET_ON_DATA_PARAMS = 25 |
||||
}; |
||||
|
||||
enum ActionParamsSystemStructureFields { |
||||
SYSTEM_STRUCTURE_ACTION_PARAMS_FIELD_INDEX = 0, |
||||
SYSTEM_STRUCTURE_ACTION_PARAMS_FIELD_INDEXES = 1, |
||||
SYSTEM_STRUCTURE_ACTION_PARAMS_NUM_FIELDS |
||||
}; |
||||
|
||||
enum CheckboxActionParamsSystemStructureFields { |
||||
SYSTEM_STRUCTURE_CHECKBOX_ACTION_PARAMS_FIELD_INDEX = 0, |
||||
SYSTEM_STRUCTURE_CHECKBOX_ACTION_PARAMS_FIELD_INDEXES = 1, |
||||
SYSTEM_STRUCTURE_CHECKBOX_ACTION_PARAMS_FIELD_VALUE = 2, |
||||
SYSTEM_STRUCTURE_CHECKBOX_ACTION_PARAMS_NUM_FIELDS |
||||
}; |
||||
|
||||
enum TextInputActionParamsSystemStructureFields { |
||||
SYSTEM_STRUCTURE_TEXT_INPUT_ACTION_PARAMS_FIELD_INDEX = 0, |
||||
SYSTEM_STRUCTURE_TEXT_INPUT_ACTION_PARAMS_FIELD_INDEXES = 1, |
||||
SYSTEM_STRUCTURE_TEXT_INPUT_ACTION_PARAMS_FIELD_VALUE = 2, |
||||
SYSTEM_STRUCTURE_TEXT_INPUT_ACTION_PARAMS_NUM_FIELDS |
||||
}; |
||||
|
||||
enum DropDownListActionParamsSystemStructureFields { |
||||
SYSTEM_STRUCTURE_DROP_DOWN_LIST_ACTION_PARAMS_FIELD_INDEX = 0, |
||||
SYSTEM_STRUCTURE_DROP_DOWN_LIST_ACTION_PARAMS_FIELD_INDEXES = 1, |
||||
SYSTEM_STRUCTURE_DROP_DOWN_LIST_ACTION_PARAMS_FIELD_SELECTED_INDEX = 2, |
||||
SYSTEM_STRUCTURE_DROP_DOWN_LIST_ACTION_PARAMS_NUM_FIELDS |
||||
}; |
||||
|
||||
enum SerialPortSystemStructureFields { |
||||
SYSTEM_STRUCTURE_SERIAL_PORT_FIELD_MANUFACTURER = 0, |
||||
SYSTEM_STRUCTURE_SERIAL_PORT_FIELD_SERIAL_NUMBER = 1, |
||||
SYSTEM_STRUCTURE_SERIAL_PORT_FIELD_PATH = 2, |
||||
SYSTEM_STRUCTURE_SERIAL_PORT_NUM_FIELDS |
||||
}; |
||||
|
||||
enum TerminalWidgetOnDataParamsSystemStructureFields { |
||||
SYSTEM_STRUCTURE_TERMINAL_WIDGET_ON_DATA_PARAMS_FIELD_INDEX = 0, |
||||
SYSTEM_STRUCTURE_TERMINAL_WIDGET_ON_DATA_PARAMS_FIELD_INDEXES = 1, |
||||
SYSTEM_STRUCTURE_TERMINAL_WIDGET_ON_DATA_PARAMS_FIELD_DATA = 2, |
||||
SYSTEM_STRUCTURE_TERMINAL_WIDGET_ON_DATA_PARAMS_NUM_FIELDS |
||||
}; |
||||
|
||||
enum ArrayTypes { |
||||
ARRAY_TYPE_INTEGER = 26, |
||||
ARRAY_TYPE_FLOAT = 27, |
||||
ARRAY_TYPE_DOUBLE = 28, |
||||
ARRAY_TYPE_BOOLEAN = 29, |
||||
ARRAY_TYPE_STRING = 30, |
||||
ARRAY_TYPE_DATE = 31, |
||||
ARRAY_TYPE_BLOB = 32, |
||||
ARRAY_TYPE_ANY = 14 |
||||
}; |
||||
|
||||
} // defs_v3
|
||||
} // flow
|
||||
} // eez
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <math.h> |
||||
|
||||
#include <eez/flow/hooks.h> |
||||
#include <eez/gui/gui.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
static bool isFlowRunning() { |
||||
return true; |
||||
} |
||||
|
||||
static void replacePage(int16_t pageId) { |
||||
eez::gui::getAppContextFromId(APP_CONTEXT_ID_DEVICE)->replacePage(pageId); |
||||
} |
||||
|
||||
static void showKeyboard(Value label, Value initialText, Value minChars, Value maxChars, bool isPassword, void(*onOk)(char *), void(*onCancel)()) { |
||||
} |
||||
|
||||
static void showKeypad(Value label, Value initialValue, Value min, Value max, Unit unit, void(*onOk)(float), void(*onCancel)()) { |
||||
} |
||||
|
||||
static void stopScript() { |
||||
assert(false); |
||||
} |
||||
|
||||
static void scpiComponentInit() { |
||||
} |
||||
|
||||
static void startToDebuggerMessage() { |
||||
} |
||||
|
||||
static void writeDebuggerBuffer(const char *buffer, uint32_t length) { |
||||
} |
||||
|
||||
static void finishToDebuggerMessage() { |
||||
} |
||||
|
||||
static void onDebuggerInputAvailable() { |
||||
} |
||||
|
||||
bool (*isFlowRunningHook)() = isFlowRunning; |
||||
void (*replacePageHook)(int16_t pageId) = replacePage; |
||||
void (*showKeyboardHook)(Value label, Value initialText, Value minChars, Value maxChars, bool isPassword, void(*onOk)(char *), void(*onCancel)()) = showKeyboard; |
||||
void (*showKeypadHook)(Value label, Value initialValue, Value min, Value max, Unit unit, void(*onOk)(float), void(*onCancel)()) = showKeypad; |
||||
void (*stopScriptHook)() = stopScript; |
||||
|
||||
void (*scpiComponentInitHook)() = scpiComponentInit; |
||||
|
||||
void (*startToDebuggerMessageHook)() = startToDebuggerMessage; |
||||
void (*writeDebuggerBufferHook)(const char *buffer, uint32_t length) = writeDebuggerBuffer; |
||||
void (*finishToDebuggerMessageHook)() = finishToDebuggerMessage; |
||||
void (*onDebuggerInputAvailableHook)() = onDebuggerInputAvailable; |
||||
|
||||
void (*executeDashboardComponentHook)(uint16_t componentType, int flowStateIndex, int componentIndex) = nullptr; |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
||||
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2022-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include <eez/flow/private.h> |
||||
#include <eez/gui/data.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
using eez::gui::Value; |
||||
|
||||
extern bool (*isFlowRunningHook)(); |
||||
extern void (*replacePageHook)(int16_t pageId); |
||||
extern void (*showKeyboardHook)(Value label, Value initialText, Value minChars, Value maxChars, bool isPassword, void(*onOk)(char *), void(*onCancel)()); |
||||
extern void (*showKeypadHook)(Value label, Value initialValue, Value min, Value max, Unit unit, void(*onOk)(float), void(*onCancel)()); |
||||
extern void (*stopScriptHook)(); |
||||
|
||||
extern void (*scpiComponentInitHook)(); |
||||
|
||||
extern void (*startToDebuggerMessageHook)(); |
||||
extern void (*writeDebuggerBufferHook)(const char *buffer, uint32_t length); |
||||
extern void (*finishToDebuggerMessageHook)(); |
||||
extern void (*onDebuggerInputAvailableHook)(); |
||||
|
||||
extern void (*executeDashboardComponentHook)(uint16_t componentType, int flowStateIndex, int componentIndex); |
||||
|
||||
} // flow
|
||||
} // eez
|
File diff suppressed because it is too large
Load Diff
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/flow/expression.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
typedef bool (*EvalOperation)(EvalStack &); |
||||
|
||||
extern EvalOperation g_evalOperations[]; |
||||
|
||||
Value op_add(const Value& a1, const Value& b1); |
||||
Value op_sub(const Value& a1, const Value& b1); |
||||
Value op_mul(const Value& a1, const Value& b1); |
||||
Value op_div(const Value& a1, const Value& b1); |
||||
Value op_mod(const Value& a1, const Value& b1); |
||||
|
||||
Value op_left_shift(const Value& a1, const Value& b1); |
||||
Value op_right_shift(const Value& a1, const Value& b1); |
||||
Value op_binary_and(const Value& a1, const Value& b1); |
||||
Value op_binary_or(const Value& a1, const Value& b1); |
||||
Value op_binary_xor(const Value& a1, const Value& b1); |
||||
|
||||
Value op_eq(const Value& a1, const Value& b1); |
||||
Value op_neq(const Value& a1, const Value& b1); |
||||
Value op_less(const Value& a1, const Value& b1); |
||||
Value op_great(const Value& a1, const Value& b1); |
||||
Value op_less_eq(const Value& a1, const Value& b1); |
||||
Value op_great_eq(const Value& a1, const Value& b1); |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,525 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include <eez/core/debug.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
|
||||
#include <eez/flow/flow.h> |
||||
#include <eez/flow/operations.h> |
||||
#include <eez/flow/queue.h> |
||||
#include <eez/flow/debugger.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/hooks.h> |
||||
#include <eez/flow/components/call_action.h> |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
bool isComponentReadyToRun(FlowState *flowState, unsigned componentIndex) { |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
|
||||
if (component->type == defs_v3::COMPONENT_TYPE_CATCH_ERROR_ACTION) { |
||||
return false; |
||||
} |
||||
|
||||
if (component->type == defs_v3::COMPONENT_TYPE_ON_EVENT_ACTION) { |
||||
return false; |
||||
} |
||||
|
||||
if (component->type < defs_v3::COMPONENT_TYPE_START_ACTION) { |
||||
// always execute widget
|
||||
return true; |
||||
} |
||||
|
||||
if (component->type == defs_v3::COMPONENT_TYPE_START_ACTION) { |
||||
auto parentComponent = flowState->parentComponent; |
||||
if (parentComponent) { |
||||
auto flowInputIndex = parentComponent->inputs[0]; |
||||
auto value = flowState->parentFlowState->values[flowInputIndex]; |
||||
return value.getType() != VALUE_TYPE_UNDEFINED; |
||||
} else { |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
// check if required inputs are defined:
|
||||
// - at least 1 seq input must be defined
|
||||
// - all non optional data inputs must be defined
|
||||
int numSeqInputs = 0; |
||||
int numDefinedSeqInputs = 0; |
||||
for (unsigned inputIndex = 0; inputIndex < component->inputs.count; inputIndex++) { |
||||
auto inputValueIndex = component->inputs[inputIndex]; |
||||
|
||||
auto input = flowState->flow->componentInputs[inputValueIndex]; |
||||
|
||||
if (input & COMPONENT_INPUT_FLAG_IS_SEQ_INPUT) { |
||||
numSeqInputs++; |
||||
auto &value = flowState->values[inputValueIndex]; |
||||
if (value.type != VALUE_TYPE_UNDEFINED) { |
||||
numDefinedSeqInputs++; |
||||
} |
||||
} else { |
||||
if (!(input & COMPONENT_INPUT_FLAG_IS_OPTIONAL)) { |
||||
auto &value = flowState->values[inputValueIndex]; |
||||
if (value.type == VALUE_TYPE_UNDEFINED) { |
||||
// non optional data input is undefined
|
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (numSeqInputs && !numDefinedSeqInputs) { |
||||
// no seq input is defined
|
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
static bool pingComponent(FlowState *flowState, unsigned componentIndex, int sourceComponentIndex = -1, int sourceOutputIndex = -1, int targetInputIndex = -1) { |
||||
if (isComponentReadyToRun(flowState, componentIndex)) { |
||||
if (!addToQueue(flowState, componentIndex, sourceComponentIndex, sourceOutputIndex, targetInputIndex)) { |
||||
throwError(flowState, componentIndex, "Execution queue is full\n"); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
|
||||
static FlowState *initFlowState(Assets *assets, int flowIndex, FlowState *parentFlowState, int parentComponentIndex) { |
||||
auto flowDefinition = static_cast<FlowDefinition *>(assets->flowDefinition); |
||||
auto flow = flowDefinition->flows[flowIndex]; |
||||
|
||||
auto nValues = flow->componentInputs.count + flow->localVariables.count; |
||||
|
||||
FlowState *flowState = (FlowState *)alloc( |
||||
sizeof(FlowState) + |
||||
nValues * sizeof(Value) + |
||||
flow->components.count * sizeof(ComponenentExecutionState *) + |
||||
flow->components.count * sizeof(bool), |
||||
0x4c3b6ef5 |
||||
); |
||||
|
||||
flowState->flowStateIndex = (int)((uint8_t *)flowState - ALLOC_BUFFER); |
||||
flowState->assets = assets; |
||||
flowState->flowDefinition = static_cast<FlowDefinition *>(assets->flowDefinition); |
||||
flowState->flow = flowDefinition->flows[flowIndex]; |
||||
flowState->flowIndex = flowIndex; |
||||
flowState->error = false; |
||||
flowState->numAsyncComponents = 0; |
||||
flowState->parentFlowState = parentFlowState; |
||||
|
||||
flowState->timelinePosition = 0; |
||||
|
||||
if (parentFlowState) { |
||||
if (parentFlowState->lastChild) { |
||||
parentFlowState->lastChild->nextSibling = flowState; |
||||
flowState->previousSibling = parentFlowState->lastChild; |
||||
parentFlowState->lastChild = flowState; |
||||
} else { |
||||
flowState->previousSibling = nullptr; |
||||
parentFlowState->firstChild = flowState; |
||||
parentFlowState->lastChild = flowState; |
||||
} |
||||
|
||||
flowState->parentComponentIndex = parentComponentIndex; |
||||
flowState->parentComponent = parentFlowState->flow->components[parentComponentIndex]; |
||||
} else { |
||||
if (g_lastFlowState) { |
||||
g_lastFlowState->nextSibling = flowState; |
||||
flowState->previousSibling = g_lastFlowState; |
||||
g_lastFlowState = flowState; |
||||
} else { |
||||
flowState->previousSibling = nullptr; |
||||
g_firstFlowState = flowState; |
||||
g_lastFlowState = flowState; |
||||
} |
||||
|
||||
flowState->parentComponentIndex = -1; |
||||
flowState->parentComponent = nullptr; |
||||
} |
||||
|
||||
flowState->firstChild = nullptr; |
||||
flowState->lastChild = nullptr; |
||||
flowState->nextSibling = nullptr; |
||||
|
||||
flowState->values = (Value *)(flowState + 1); |
||||
flowState->componenentExecutionStates = (ComponenentExecutionState **)(flowState->values + nValues); |
||||
flowState->componenentAsyncStates = (bool *)(flowState->componenentExecutionStates + flow->components.count); |
||||
|
||||
for (unsigned i = 0; i < nValues; i++) { |
||||
new (flowState->values + i) Value(); |
||||
} |
||||
|
||||
auto &undefinedValue = *flowDefinition->constants[UNDEFINED_VALUE_INDEX]; |
||||
for (unsigned i = 0; i < flow->componentInputs.count; i++) { |
||||
flowState->values[i] = undefinedValue; |
||||
} |
||||
|
||||
for (unsigned i = 0; i < flow->localVariables.count; i++) { |
||||
auto value = flow->localVariables[i]; |
||||
flowState->values[flow->componentInputs.count + i] = *value; |
||||
} |
||||
|
||||
for (unsigned i = 0; i < flow->components.count; i++) { |
||||
flowState->componenentExecutionStates[i] = nullptr; |
||||
flowState->componenentAsyncStates[i] = false; |
||||
} |
||||
|
||||
onFlowStateCreated(flowState); |
||||
|
||||
for (unsigned componentIndex = 0; componentIndex < flow->components.count; componentIndex++) { |
||||
pingComponent(flowState, componentIndex); |
||||
} |
||||
|
||||
return flowState; |
||||
} |
||||
|
||||
FlowState *initActionFlowState(int flowIndex, FlowState *parentFlowState, int parentComponentIndex) { |
||||
auto flowState = initFlowState(parentFlowState->assets, flowIndex, parentFlowState, parentComponentIndex); |
||||
if (flowState) { |
||||
flowState->isAction = true; |
||||
} |
||||
return flowState; |
||||
} |
||||
|
||||
FlowState *initPageFlowState(Assets *assets, int flowIndex, FlowState *parentFlowState, int parentComponentIndex) { |
||||
auto flowState = initFlowState(assets, flowIndex, parentFlowState, parentComponentIndex); |
||||
if (flowState) { |
||||
flowState->isAction = false; |
||||
} |
||||
return flowState; |
||||
} |
||||
|
||||
bool canFreeFlowState(FlowState *flowState, bool includingWatchVariable) { |
||||
if (!flowState->isAction) { |
||||
return false; |
||||
} |
||||
|
||||
if (flowState->numAsyncComponents > 0) { |
||||
return false; |
||||
} |
||||
|
||||
if (isThereAnyTaskInQueueForFlowState(flowState, includingWatchVariable)) { |
||||
return false; |
||||
} |
||||
|
||||
for (uint32_t componentIndex = 0; componentIndex < flowState->flow->components.count; componentIndex++) { |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
if ( |
||||
component->type != defs_v3::COMPONENT_TYPE_INPUT_ACTION && |
||||
component->type != defs_v3::COMPONENT_TYPE_LOOP_ACTION && |
||||
component->type != defs_v3::COMPONENT_TYPE_COUNTER_ACTION && |
||||
(includingWatchVariable || component->type != defs_v3::COMPONENT_TYPE_WATCH_VARIABLE_ACTION) && |
||||
flowState->componenentExecutionStates[componentIndex] |
||||
) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void freeFlowState(FlowState *flowState) { |
||||
auto parentFlowState = flowState->parentFlowState; |
||||
if (flowState->parentFlowState) { |
||||
auto componentExecutionState = flowState->parentFlowState->componenentExecutionStates[flowState->parentComponentIndex]; |
||||
if (componentExecutionState) { |
||||
deallocateComponentExecutionState(flowState->parentFlowState, flowState->parentComponentIndex); |
||||
return; |
||||
} |
||||
|
||||
if (parentFlowState->firstChild == flowState) { |
||||
parentFlowState->firstChild = flowState->nextSibling; |
||||
} |
||||
if (parentFlowState->lastChild == flowState) { |
||||
parentFlowState->lastChild = flowState->previousSibling; |
||||
} |
||||
} else { |
||||
if (g_firstFlowState == flowState) { |
||||
g_firstFlowState = flowState->nextSibling; |
||||
} |
||||
if (g_lastFlowState == flowState) { |
||||
g_lastFlowState = flowState->previousSibling; |
||||
} |
||||
} |
||||
|
||||
if (flowState->previousSibling) { |
||||
flowState->previousSibling->nextSibling = flowState->nextSibling; |
||||
} |
||||
if (flowState->nextSibling) { |
||||
flowState->nextSibling->previousSibling = flowState->previousSibling; |
||||
} |
||||
|
||||
auto flow = flowState->flow; |
||||
|
||||
auto valuesCount = flow->componentInputs.count + flow->localVariables.count; |
||||
|
||||
for (unsigned int i = 0; i < valuesCount; i++) { |
||||
(flowState->values + i)->~Value(); |
||||
} |
||||
|
||||
for (unsigned i = 0; i < flow->components.count; i++) { |
||||
deallocateComponentExecutionState(flowState, i); |
||||
} |
||||
|
||||
onFlowStateDestroyed(flowState); |
||||
|
||||
free(flowState); |
||||
|
||||
if (parentFlowState) { |
||||
if (canFreeFlowState(parentFlowState)) { |
||||
freeFlowState(parentFlowState); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void deallocateComponentExecutionState(FlowState *flowState, unsigned componentIndex) { |
||||
auto executionState = flowState->componenentExecutionStates[componentIndex]; |
||||
if (executionState) { |
||||
flowState->componenentExecutionStates[componentIndex] = nullptr; |
||||
onComponentExecutionStateChanged(flowState, componentIndex); |
||||
ObjectAllocator<ComponenentExecutionState>::deallocate(executionState); |
||||
} |
||||
} |
||||
|
||||
void propagateValue(FlowState *flowState, unsigned componentIndex, unsigned outputIndex, const gui::Value &value) { |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
auto componentOutput = component->outputs[outputIndex]; |
||||
|
||||
auto value2 = value.getValue(); |
||||
|
||||
for (unsigned connectionIndex = 0; connectionIndex < componentOutput->connections.count; connectionIndex++) { |
||||
auto connection = componentOutput->connections[connectionIndex]; |
||||
|
||||
auto pValue = &flowState->values[connection->targetInputIndex]; |
||||
|
||||
if (*pValue != value2) { |
||||
*pValue = value2; |
||||
|
||||
//if (!(flowState->flow->componentInputs[connection->targetInputIndex] & COMPONENT_INPUT_FLAG_IS_SEQ_INPUT)) {
|
||||
onValueChanged(pValue); |
||||
//}
|
||||
} |
||||
|
||||
pingComponent(flowState, connection->targetComponentIndex, componentIndex, outputIndex, connection->targetInputIndex); |
||||
} |
||||
} |
||||
|
||||
void propagateValue(FlowState *flowState, unsigned componentIndex, unsigned outputIndex) { |
||||
auto &nullValue = *flowState->flowDefinition->constants[NULL_VALUE_INDEX]; |
||||
propagateValue(flowState, componentIndex, outputIndex, nullValue); |
||||
} |
||||
|
||||
void propagateValueThroughSeqout(FlowState *flowState, unsigned componentIndex) { |
||||
// find @seqout output
|
||||
// TODO optimization hint: always place @seqout at 0-th index
|
||||
auto component = flowState->flow->components[componentIndex]; |
||||
for (uint32_t i = 0; i < component->outputs.count; i++) { |
||||
if (component->outputs[i]->isSeqOut) { |
||||
propagateValue(flowState, componentIndex, i); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void getValue(uint16_t dataId, DataOperationEnum operation, const WidgetCursor &widgetCursor, Value &value) { |
||||
if (isFlowRunningHook()) { |
||||
FlowState *flowState = widgetCursor.flowState; |
||||
auto flow = flowState->flow; |
||||
|
||||
WidgetDataItem *widgetDataItem = flow->widgetDataItems[dataId]; |
||||
if (widgetDataItem && widgetDataItem->componentIndex != -1 && widgetDataItem->propertyValueIndex != -1) { |
||||
evalProperty(flowState, widgetDataItem->componentIndex, widgetDataItem->propertyValueIndex, value, "doGetFlowValue failed", nullptr, widgetCursor.iterators, operation); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void setValue(uint16_t dataId, const WidgetCursor &widgetCursor, const Value& value) { |
||||
if (isFlowRunningHook()) { |
||||
FlowState *flowState = widgetCursor.flowState; |
||||
auto flow = flowState->flow; |
||||
|
||||
WidgetDataItem *widgetDataItem = flow->widgetDataItems[dataId]; |
||||
if (widgetDataItem && widgetDataItem->componentIndex != -1 && widgetDataItem->propertyValueIndex != -1) { |
||||
auto component = flow->components[widgetDataItem->componentIndex]; |
||||
auto property = component->properties[widgetDataItem->propertyValueIndex]; |
||||
Value dstValue; |
||||
if (evalAssignableExpression(flowState, widgetDataItem->componentIndex, property->evalInstructions, dstValue, "doSetFlowValue failed", nullptr, widgetCursor.iterators)) { |
||||
assignValue(flowState, widgetDataItem->componentIndex, dstValue, value); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void assignValue(FlowState *flowState, int componentIndex, Value &dstValue, const Value &srcValue) { |
||||
if (dstValue.getType() == VALUE_TYPE_FLOW_OUTPUT) { |
||||
propagateValue(flowState, componentIndex, dstValue.getUInt16(), srcValue); |
||||
} else if (dstValue.getType() == VALUE_TYPE_NATIVE_VARIABLE) { |
||||
set(g_widgetCursor, dstValue.getInt(), srcValue); |
||||
} else { |
||||
Value *pDstValue; |
||||
if (dstValue.getType() == VALUE_TYPE_ARRAY_ELEMENT_VALUE) { |
||||
auto arrayElementValue = (ArrayElementValue *)dstValue.refValue; |
||||
auto array = arrayElementValue->arrayValue.getArray(); |
||||
pDstValue = &array->values[arrayElementValue->elementIndex]; |
||||
} else { |
||||
pDstValue = dstValue.pValueValue; |
||||
} |
||||
|
||||
if (assignValue(*pDstValue, srcValue)) { |
||||
onValueChanged(pDstValue); |
||||
} else { |
||||
char errorMessage[100]; |
||||
snprintf(errorMessage, sizeof(errorMessage), "Can not assign %s to %s\n", |
||||
g_valueTypeNames[pDstValue->type](srcValue), g_valueTypeNames[srcValue.type](*pDstValue) |
||||
); |
||||
throwError(flowState, componentIndex, errorMessage); |
||||
} |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void startAsyncExecution(FlowState *flowState, int componentIndex) { |
||||
if (!flowState->componenentAsyncStates[componentIndex]) { |
||||
flowState->componenentAsyncStates[componentIndex] = true; |
||||
onComponentAsyncStateChanged(flowState, componentIndex); |
||||
|
||||
flowState->numAsyncComponents++; |
||||
} |
||||
} |
||||
|
||||
void endAsyncExecution(FlowState *flowState, int componentIndex) { |
||||
if (!g_firstFlowState) { |
||||
return; |
||||
} |
||||
|
||||
if (flowState->componenentAsyncStates[componentIndex]) { |
||||
flowState->componenentAsyncStates[componentIndex] = false; |
||||
onComponentAsyncStateChanged(flowState, componentIndex); |
||||
|
||||
flowState->numAsyncComponents--; |
||||
|
||||
if (canFreeFlowState(flowState)) { |
||||
freeFlowState(flowState); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void onEvent(FlowState *flowState, FlowEvent flowEvent) { |
||||
for (unsigned componentIndex = 0; componentIndex < flowState->flow->components.count; componentIndex++) { |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
if (component->type == defs_v3::COMPONENT_TYPE_ON_EVENT_ACTION) { |
||||
struct OnEventComponent : public Component { |
||||
uint8_t event; |
||||
}; |
||||
auto onEventComponent = (OnEventComponent *)component; |
||||
if (onEventComponent->event == flowEvent) { |
||||
if (!addToQueue(flowState, componentIndex, -1, -1, -1, false)) { |
||||
throwError(flowState, componentIndex, "Execution queue is full\n"); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool findCatchErrorComponent(FlowState *flowState, FlowState *&catchErrorFlowState, int &catchErrorComponentIndex) { |
||||
if (!flowState) { |
||||
return false; |
||||
} |
||||
|
||||
for (unsigned componentIndex = 0; componentIndex < flowState->flow->components.count; componentIndex++) { |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
if (component->type == defs_v3::COMPONENT_TYPE_CATCH_ERROR_ACTION) { |
||||
catchErrorFlowState = flowState; |
||||
catchErrorComponentIndex = componentIndex; |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
return findCatchErrorComponent(flowState->parentFlowState, catchErrorFlowState, catchErrorComponentIndex); |
||||
} |
||||
|
||||
void throwError(FlowState *flowState, int componentIndex, const char *errorMessage) { |
||||
auto component = flowState->flow->components[componentIndex]; |
||||
|
||||
#if defined(__EMSCRIPTEN__) |
||||
printf("throwError: %s\n", errorMessage); |
||||
#endif |
||||
|
||||
if (component->errorCatchOutput != -1) { |
||||
propagateValue( |
||||
flowState, |
||||
componentIndex, |
||||
component->errorCatchOutput, |
||||
Value::makeStringRef(errorMessage, strlen(errorMessage), 0xef6f8414) |
||||
); |
||||
} else { |
||||
FlowState *catchErrorFlowState; |
||||
int catchErrorComponentIndex; |
||||
if ( |
||||
findCatchErrorComponent( |
||||
component->type == defs_v3::COMPONENT_TYPE_ERROR_ACTION ? flowState->parentFlowState : flowState, |
||||
catchErrorFlowState, |
||||
catchErrorComponentIndex |
||||
) |
||||
) { |
||||
auto catchErrorComponentExecutionState = allocateComponentExecutionState<CatchErrorComponenentExecutionState>(catchErrorFlowState, catchErrorComponentIndex); |
||||
catchErrorComponentExecutionState->message = Value::makeStringRef(errorMessage, strlen(errorMessage), 0x9473eef2); |
||||
|
||||
if (!addToQueue(catchErrorFlowState, catchErrorComponentIndex, -1, -1, -1)) { |
||||
catchErrorFlowState->error = true; |
||||
onFlowError(catchErrorFlowState, catchErrorComponentIndex, "Execution queue is full\n"); |
||||
stopScriptHook(); |
||||
} |
||||
} else { |
||||
flowState->error = true; |
||||
onFlowError(flowState, componentIndex, errorMessage); |
||||
stopScriptHook(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void throwError(FlowState *flowState, int componentIndex, const char *errorMessage, const char *errorMessageDescription) { |
||||
if (errorMessage) { |
||||
char throwErrorMessage[512]; |
||||
snprintf(throwErrorMessage, sizeof(throwErrorMessage), "%s: %s", errorMessage, errorMessageDescription); |
||||
throwError(flowState, componentIndex, throwErrorMessage); |
||||
} else { |
||||
throwError(flowState, componentIndex, errorMessageDescription); |
||||
} |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/gui/assets.h> |
||||
#include <eez/flow/debugger.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
using eez::gui::Value; |
||||
using eez::gui::Assets; |
||||
using eez::gui::FlowDefinition; |
||||
using eez::gui::Flow; |
||||
using eez::gui::Component; |
||||
using eez::gui::ComponentOutput; |
||||
using eez::gui::WidgetCursor; |
||||
|
||||
static const int UNDEFINED_VALUE_INDEX = 0; |
||||
static const int NULL_VALUE_INDEX = 1; |
||||
|
||||
struct ComponenentExecutionState { |
||||
virtual ~ComponenentExecutionState() {} |
||||
}; |
||||
|
||||
struct CatchErrorComponenentExecutionState : public ComponenentExecutionState { |
||||
Value message; |
||||
}; |
||||
|
||||
struct FlowState { |
||||
uint32_t flowStateIndex; |
||||
Assets *assets; |
||||
FlowDefinition *flowDefinition; |
||||
Flow *flow; |
||||
uint16_t flowIndex; |
||||
bool isAction; |
||||
uint16_t error; |
||||
uint32_t numAsyncComponents; |
||||
FlowState *parentFlowState; |
||||
Component *parentComponent; |
||||
int parentComponentIndex; |
||||
Value *values; |
||||
ComponenentExecutionState **componenentExecutionStates; |
||||
bool *componenentAsyncStates; |
||||
float timelinePosition; |
||||
|
||||
FlowState *firstChild; |
||||
FlowState *lastChild; |
||||
FlowState *previousSibling; |
||||
FlowState *nextSibling; |
||||
}; |
||||
|
||||
extern int g_selectedLanguage; |
||||
extern FlowState *g_firstFlowState; |
||||
extern FlowState *g_lastFlowState; |
||||
|
||||
FlowState *initActionFlowState(int flowIndex, FlowState *parentFlowState, int parentComponentIndex); |
||||
FlowState *initPageFlowState(Assets *assets, int flowIndex, FlowState *parentFlowState, int parentComponentIndex); |
||||
|
||||
bool canFreeFlowState(FlowState *flowState, bool includingWatchVariable = true); |
||||
void freeFlowState(FlowState *flowState); |
||||
|
||||
void deallocateComponentExecutionState(FlowState *flowState, unsigned componentIndex); |
||||
|
||||
template<class T> |
||||
T *allocateComponentExecutionState(FlowState *flowState, unsigned componentIndex) { |
||||
if (flowState->componenentExecutionStates[componentIndex]) { |
||||
deallocateComponentExecutionState(flowState, componentIndex); |
||||
} |
||||
auto executionState = ObjectAllocator<T>::allocate(0x72dc3bf4); |
||||
flowState->componenentExecutionStates[componentIndex] = executionState; |
||||
onComponentExecutionStateChanged(flowState, componentIndex); |
||||
return executionState; |
||||
} |
||||
|
||||
void propagateValue(FlowState *flowState, unsigned componentIndex, unsigned outputIndex, const gui::Value &value); |
||||
void propagateValue(FlowState *flowState, unsigned componentIndex, unsigned outputIndex); // propagates null value
|
||||
void propagateValueThroughSeqout(FlowState *flowState, unsigned componentIndex); // propagates null value through @seqout (0-th output)
|
||||
|
||||
void getValue(uint16_t dataId, eez::gui::DataOperationEnum operation, const WidgetCursor &widgetCursor, Value &value); |
||||
void setValue(uint16_t dataId, const WidgetCursor &widgetCursor, const Value& value); |
||||
|
||||
void assignValue(FlowState *flowState, int componentIndex, Value &dstValue, const Value &srcValue); |
||||
|
||||
void startAsyncExecution(FlowState *flowState, int componentIndex); |
||||
void endAsyncExecution(FlowState *flowState, int componentIndex); |
||||
|
||||
void executeCallAction(FlowState *flowState, unsigned componentIndex, int flowIndex); |
||||
|
||||
enum FlowEvent { |
||||
FLOW_EVENT_OPEN_PAGE, |
||||
FLOW_EVENT_CLOSE_PAGE |
||||
}; |
||||
|
||||
void onEvent(FlowState *flowState, FlowEvent flowEvent); |
||||
|
||||
void throwError(FlowState *flowState, int componentIndex, const char *errorMessage); |
||||
void throwError(FlowState *flowState, int componentIndex, const char *errorMessage, const char *errorMessageDescription); |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,126 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/flow/queue.h> |
||||
#include <eez/flow/debugger.h> |
||||
#include <eez/flow/flow_defs_v3.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
static const unsigned QUEUE_SIZE = 1000; |
||||
static struct { |
||||
FlowState *flowState; |
||||
unsigned componentIndex; |
||||
bool continuousTask; |
||||
} g_queue[QUEUE_SIZE]; |
||||
static unsigned g_queueHead; |
||||
static unsigned g_queueTail; |
||||
static bool g_queueIsFull = false; |
||||
|
||||
void queueReset() { |
||||
g_queueHead = 0; |
||||
g_queueTail = 0; |
||||
g_queueIsFull = false; |
||||
} |
||||
|
||||
size_t getQueueSize() { |
||||
if (g_queueHead == g_queueTail) { |
||||
if (g_queueIsFull) { |
||||
return QUEUE_SIZE; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
if (g_queueHead < g_queueTail) { |
||||
return g_queueTail - g_queueHead; |
||||
} |
||||
|
||||
return QUEUE_SIZE - g_queueHead + g_queueTail; |
||||
} |
||||
|
||||
bool addToQueue(FlowState *flowState, unsigned componentIndex, int sourceComponentIndex, int sourceOutputIndex, int targetInputIndex, bool continuousTask) { |
||||
if (g_queueIsFull) { |
||||
return false; |
||||
} |
||||
|
||||
g_queue[g_queueTail].flowState = flowState; |
||||
g_queue[g_queueTail].componentIndex = componentIndex; |
||||
g_queue[g_queueTail].continuousTask = continuousTask; |
||||
|
||||
g_queueTail = (g_queueTail + 1) % QUEUE_SIZE; |
||||
|
||||
if (g_queueHead == g_queueTail) { |
||||
g_queueIsFull = true; |
||||
} |
||||
|
||||
if (!continuousTask) { |
||||
onAddToQueue(flowState, sourceComponentIndex, sourceOutputIndex, componentIndex, targetInputIndex); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool peekNextTaskFromQueue(FlowState *&flowState, unsigned &componentIndex, bool &continuousTask) { |
||||
if (g_queueHead == g_queueTail && !g_queueIsFull) { |
||||
return false; |
||||
} |
||||
|
||||
flowState = g_queue[g_queueHead].flowState; |
||||
componentIndex = g_queue[g_queueHead].componentIndex; |
||||
continuousTask = g_queue[g_queueHead].continuousTask; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void removeNextTaskFromQueue() { |
||||
auto continuousTask = g_queue[g_queueHead].continuousTask; |
||||
|
||||
g_queueHead = (g_queueHead + 1) % QUEUE_SIZE; |
||||
g_queueIsFull = false; |
||||
|
||||
if (!continuousTask) { |
||||
onRemoveFromQueue(); |
||||
} |
||||
} |
||||
|
||||
bool isThereAnyTaskInQueueForFlowState(FlowState *flowState, bool includingWatchVariable) { |
||||
if (g_queueHead == g_queueTail && !g_queueIsFull) { |
||||
return false; |
||||
} |
||||
|
||||
unsigned int it = g_queueHead; |
||||
while (true) { |
||||
if (g_queue[it].flowState == flowState) { |
||||
auto component = flowState->flow->components[g_queue[it].componentIndex]; |
||||
if (includingWatchVariable || component->type != defs_v3::COMPONENT_TYPE_WATCH_VARIABLE_ACTION) { |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
it = (it + 1) % QUEUE_SIZE; |
||||
if (it == g_queueTail) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
} // namespace flow
|
||||
} // namespace eez
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2021-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/flow/private.h> |
||||
|
||||
namespace eez { |
||||
namespace flow { |
||||
|
||||
void queueReset(); |
||||
size_t getQueueSize(); |
||||
bool addToQueue(FlowState *flowState, unsigned componentIndex, |
||||
int sourceComponentIndex = -1, int sourceOutputIndex = -1, int targetInputIndex = -1, |
||||
bool continuousTask = false); |
||||
bool peekNextTaskFromQueue(FlowState *&flowState, unsigned &componentIndex, bool &continuousTask); |
||||
void removeNextTaskFromQueue(); |
||||
|
||||
bool isThereAnyTaskInQueueForFlowState(FlowState *flowState, bool includingWatchVariable); |
||||
|
||||
} // flow
|
||||
} // eez
|
@ -1,162 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
|
||||
#ifdef EEZ_PLATFORM_STM32 |
||||
#include <fatfs.h> |
||||
#endif |
||||
|
||||
#ifdef EEZ_PLATFORM_SIMULATOR |
||||
#include <filesystem> |
||||
#endif |
||||
|
||||
#define FILE_READ 0x01 |
||||
#define FILE_WRITE 0x02 |
||||
#define FILE_OPEN_EXISTING 0x00 |
||||
#define FILE_CREATE_NEW 0x04 |
||||
#define FILE_CREATE_ALWAYS 0x08 |
||||
#define FILE_OPEN_ALWAYS 0x10 |
||||
#define FILE_OPEN_APPEND 0x30 |
||||
|
||||
namespace eez { |
||||
|
||||
// clang-format off
|
||||
enum SdFatResult { |
||||
SD_FAT_RESULT_OK = 0, /* (0) Succeeded */ |
||||
SD_FAT_RESULT_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ |
||||
SD_FAT_RESULT_INT_ERR, /* (2) Assertion failed */ |
||||
SD_FAT_RESULT_NOT_READY, /* (3) The physical drive cannot work */ |
||||
SD_FAT_RESULT_NO_FILE, /* (4) Could not find the file */ |
||||
SD_FAT_RESULT_NO_PATH, /* (5) Could not find the path */ |
||||
SD_FAT_RESULT_INVALID_NAME, /* (6) The path name format is invalid */ |
||||
SD_FAT_RESULT_DENIED, /* (7) Access denied due to prohibited access or directory full */ |
||||
SD_FAT_RESULT_EXIST, /* (8) Access denied due to prohibited access */ |
||||
SD_FAT_RESULT_INVALID_OBJECT, /* (9) The file/directory object is invalid */ |
||||
SD_FAT_RESULT_WRITE_PROTECTED, /* (10) The physical drive is write protected */ |
||||
SD_FAT_RESULT_INVALID_DRIVE, /* (11) The logical drive number is invalid */ |
||||
SD_FAT_RESULT_NOT_ENABLED, /* (12) The volume has no work area */ |
||||
SD_FAT_RESULT_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ |
||||
SD_FAT_RESULT_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ |
||||
SD_FAT_RESULT_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ |
||||
SD_FAT_RESULT_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ |
||||
SD_FAT_RESULT_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ |
||||
SD_FAT_RESULT_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */ |
||||
SD_FAT_RESULT_INVALID_PARAMETER, /* (19) Given parameter is invalid */ |
||||
}; |
||||
// clang-format on
|
||||
|
||||
struct FileInfo { |
||||
FileInfo(); |
||||
|
||||
SdFatResult fstat(const char *filePath); |
||||
|
||||
operator bool(); // fname[0]
|
||||
bool isDirectory(); |
||||
void getName(char *name, size_t size); |
||||
size_t getSize(); |
||||
bool isHiddenOrSystemFile(); |
||||
|
||||
int getModifiedYear(); |
||||
int getModifiedMonth(); |
||||
int getModifiedDay(); |
||||
|
||||
int getModifiedHour(); |
||||
int getModifiedMinute(); |
||||
int getModifiedSecond(); |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
FILINFO m_fno; |
||||
#else |
||||
std::filesystem::directory_entry m_entry; |
||||
#endif |
||||
}; |
||||
|
||||
struct Directory { |
||||
Directory(); |
||||
~Directory(); |
||||
|
||||
void close(); |
||||
|
||||
SdFatResult findFirst(const char *path, FileInfo &fileInfo); |
||||
SdFatResult findNext(FileInfo &fileInfo); |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
DIR m_dj; |
||||
#else |
||||
std::filesystem::directory_iterator m_it; |
||||
#endif |
||||
}; |
||||
|
||||
class File { |
||||
File(const File &file); |
||||
const File &operator=(const File &file); |
||||
|
||||
public: |
||||
File(); |
||||
|
||||
bool open(const char *path, uint8_t mode = FILE_READ); |
||||
|
||||
~File(); |
||||
bool close(); |
||||
|
||||
bool isOpen(); |
||||
|
||||
bool truncate(uint32_t length); |
||||
|
||||
bool available(); |
||||
size_t size(); |
||||
bool seek(uint32_t pos); |
||||
size_t tell(); |
||||
int peek(); |
||||
int read(); |
||||
size_t read(void *buf, uint32_t nbyte); |
||||
size_t write(const void *buf, size_t size); |
||||
bool sync(); |
||||
|
||||
void print(float value, int numDecimalDigits); |
||||
void print(char value); |
||||
|
||||
private: |
||||
bool m_isOpen{false}; |
||||
#ifdef EEZ_PLATFORM_SIMULATOR |
||||
FILE *m_fp{NULL}; |
||||
#else |
||||
FIL m_file; |
||||
#endif |
||||
}; |
||||
|
||||
class SdFat { |
||||
public: |
||||
bool mount(int *err); |
||||
void unmount(); |
||||
bool exists(const char *path); |
||||
bool rename(const char *sourcePath, const char *destinationPath); |
||||
bool remove(const char *path); |
||||
bool mkdir(const char *path); |
||||
bool rmdir(const char *path); |
||||
|
||||
bool getInfo(int diskDriveIndex, uint64_t &usedSpace, uint64_t &freeSpace); |
||||
}; |
||||
|
||||
char *getConfFilePath(const char *file_name); |
||||
|
||||
} // namespace eez
|
@ -1,411 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#if OPTION_SCPI |
||||
#include <scpi/scpi.h> |
||||
#else |
||||
#define SCPI_ERROR_MASS_MEDIA_NO_FILESYSTEM 410 |
||||
#define SCPI_ERROR_MASS_STORAGE_ERROR -250 |
||||
#define SCPI_RES_OK 1 |
||||
#endif |
||||
|
||||
#include <eez/core/debug.h> |
||||
#include <eez/core/util.h> |
||||
#include <eez/fs/fs.h> |
||||
|
||||
#define CHECK_ERROR(desc, err) (void)(desc); (void)(err); |
||||
//#define CHECK_ERROR(desc, err) if (err != FR_OK) DebugTrace("%s: %d\n", desc, (int)err)
|
||||
|
||||
namespace eez { |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FileInfo::FileInfo() { |
||||
memset(&m_fno, 0, sizeof(m_fno)); |
||||
} |
||||
|
||||
SdFatResult FileInfo::fstat(const char *filePath) { |
||||
auto result = f_stat(filePath, &m_fno); |
||||
CHECK_ERROR("FileInfo::fstat", result); |
||||
return (SdFatResult)result; |
||||
} |
||||
|
||||
FileInfo::operator bool() { |
||||
return m_fno.fname[0] ? true : false; |
||||
} |
||||
|
||||
bool FileInfo::isDirectory() { |
||||
return m_fno.fattrib & AM_DIR ? true : false; |
||||
} |
||||
|
||||
void FileInfo::getName(char *name, size_t size) { |
||||
const char *str1 = strrchr(m_fno.fname, '\\'); |
||||
if (!str1) { |
||||
str1 = m_fno.fname; |
||||
} |
||||
|
||||
const char *str2 = strrchr(str1, '/'); |
||||
if (!str2) { |
||||
str2 = str1; |
||||
} |
||||
|
||||
stringCopy(name, size, str2); |
||||
} |
||||
|
||||
size_t FileInfo::getSize() { |
||||
return m_fno.fsize; |
||||
} |
||||
|
||||
bool FileInfo::isHiddenOrSystemFile() { |
||||
return (m_fno.fattrib & (AM_HID | AM_SYS)) != 0; |
||||
} |
||||
|
||||
#define FAT_YEAR(date) (1980 + ((date) >> 9)) |
||||
#define FAT_MONTH(date) (((date) >> 5) & 0XF) |
||||
#define FAT_DAY(date) ((date)&0X1F) |
||||
|
||||
#define FAT_HOUR(time) ((time) >> 11) |
||||
#define FAT_MINUTE(time) (((time) >> 5) & 0X3F) |
||||
#define FAT_SECOND(time) (2 * ((time)&0X1F)) |
||||
|
||||
int FileInfo::getModifiedYear() { |
||||
return FAT_YEAR(m_fno.fdate); |
||||
} |
||||
|
||||
int FileInfo::getModifiedMonth() { |
||||
return FAT_MONTH(m_fno.fdate); |
||||
} |
||||
|
||||
int FileInfo::getModifiedDay() { |
||||
return FAT_DAY(m_fno.fdate); |
||||
} |
||||
|
||||
int FileInfo::getModifiedHour() { |
||||
return FAT_HOUR(m_fno.ftime); |
||||
} |
||||
|
||||
int FileInfo::getModifiedMinute() { |
||||
return FAT_MINUTE(m_fno.ftime); |
||||
} |
||||
|
||||
int FileInfo::getModifiedSecond() { |
||||
return FAT_SECOND(m_fno.ftime); |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Directory::Directory() { |
||||
memset(&m_dj, 0, sizeof(m_dj)); |
||||
} |
||||
|
||||
Directory::~Directory() { |
||||
close(); |
||||
} |
||||
|
||||
void Directory::close() { |
||||
auto result = f_closedir(&m_dj); |
||||
CHECK_ERROR("Directory::close", result); |
||||
} |
||||
|
||||
SdFatResult Directory::findFirst(const char *path, FileInfo &fileInfo) { |
||||
auto result = f_findfirst(&m_dj, &fileInfo.m_fno, path, "*"); |
||||
CHECK_ERROR("Directory::findFirst", result); |
||||
return (SdFatResult)result; |
||||
} |
||||
|
||||
SdFatResult Directory::findNext(FileInfo &fileInfo) { |
||||
auto result = f_findnext(&m_dj, &fileInfo.m_fno); |
||||
CHECK_ERROR("Directory::findNext", result); |
||||
return (SdFatResult)result; |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
File::File() : m_isOpen(false) { |
||||
} |
||||
|
||||
bool File::open(const char *path, uint8_t mode) { |
||||
auto result = f_open(&m_file, path, mode); |
||||
CHECK_ERROR("File::open", result); |
||||
m_isOpen = result == FR_OK; |
||||
return m_isOpen; |
||||
} |
||||
|
||||
File::~File() { |
||||
} |
||||
|
||||
bool File::close() { |
||||
auto result = f_close(&m_file); |
||||
CHECK_ERROR("File::close", result); |
||||
m_isOpen = false; |
||||
return result == FR_OK; |
||||
} |
||||
|
||||
bool File::isOpen() { |
||||
return m_isOpen; |
||||
} |
||||
|
||||
bool File::truncate(uint32_t length) { |
||||
auto result1 = f_lseek(&m_file, length); |
||||
CHECK_ERROR("File::truncate 1", result1); |
||||
auto result2 = f_truncate(&m_file); |
||||
CHECK_ERROR("File::truncate 2", result2); |
||||
return result1 == FR_OK && result2 == FR_OK; |
||||
} |
||||
|
||||
size_t File::size() { |
||||
return f_size(&m_file); |
||||
} |
||||
|
||||
bool File::available() { |
||||
return peek() != EOF; |
||||
} |
||||
|
||||
bool File::seek(uint32_t pos) { |
||||
auto result = f_lseek(&m_file, pos); |
||||
CHECK_ERROR("File::seek", result); |
||||
return result == FR_OK; |
||||
} |
||||
|
||||
size_t File::tell() { |
||||
auto result = f_tell(&m_file); |
||||
CHECK_ERROR("File::tell", result); |
||||
return result; |
||||
} |
||||
|
||||
int File::peek() { |
||||
auto pos = f_tell(&m_file); |
||||
int ch = read(); |
||||
auto result = f_lseek(&m_file, pos); |
||||
CHECK_ERROR("File::peek", result); |
||||
return ch; |
||||
} |
||||
|
||||
int File::read() { |
||||
uint8_t value; |
||||
UINT br; |
||||
auto result = f_read(&m_file, &value, 1, &br); |
||||
CHECK_ERROR("File::read", result); |
||||
return result != FR_OK || br != 1 ? EOF : (int)value; |
||||
} |
||||
|
||||
size_t File::read(void *buf, uint32_t size) { |
||||
uint32_t CHUNK_SIZE = 512; // unfortunately, it doesn't work when CHUNK_SIZE is > 512
|
||||
|
||||
UINT brTotal = 0; |
||||
|
||||
size_t unalignedLength = ((uint32_t)buf) & 3; |
||||
if (unalignedLength > 0) { |
||||
CHUNK_SIZE = 512; |
||||
unalignedLength = MIN(4 - unalignedLength, size); |
||||
uint8_t unalignedBuffer[4] __attribute__((aligned)); |
||||
UINT br; |
||||
auto result = f_read(&m_file, unalignedBuffer, unalignedLength, &br); |
||||
CHECK_ERROR("File::read 1", result); |
||||
if (result != FR_OK) { |
||||
return 0; |
||||
} |
||||
|
||||
for (size_t i = 0; i < br; i++) { |
||||
((uint8_t *)buf)[i] = unalignedBuffer[i]; |
||||
} |
||||
|
||||
brTotal += br; |
||||
|
||||
if (br < unalignedLength) { |
||||
return brTotal; |
||||
} |
||||
} |
||||
|
||||
while (brTotal < size) { |
||||
uint32_t btr = MIN(CHUNK_SIZE, size - brTotal); |
||||
|
||||
UINT br; |
||||
auto result = f_read(&m_file, (uint8_t *)buf + brTotal, btr, &br); |
||||
CHECK_ERROR("File::read 2", result); |
||||
if (result != FR_OK) { |
||||
return brTotal; |
||||
} |
||||
|
||||
brTotal += br; |
||||
|
||||
if (br < btr) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return brTotal;
|
||||
} |
||||
|
||||
size_t File::write(const void *buf, size_t size) { |
||||
uint32_t CHUNK_SIZE = 64 * 1024; |
||||
|
||||
UINT bwTotal = 0; |
||||
|
||||
size_t unalignedLength = ((uint32_t)buf) & 3; |
||||
if (unalignedLength > 0) { |
||||
CHUNK_SIZE = 512; |
||||
|
||||
unalignedLength = MIN(4 - unalignedLength, size); |
||||
uint8_t unalignedBuffer[4] __attribute__((aligned)); |
||||
for (size_t i = 0; i < unalignedLength; i++) { |
||||
unalignedBuffer[i] = ((uint8_t *)buf)[i]; |
||||
} |
||||
|
||||
UINT bw; |
||||
auto result = f_write(&m_file, unalignedBuffer, unalignedLength, &bw); |
||||
CHECK_ERROR("File::write 1", result); |
||||
if (result != FR_OK) { |
||||
return 0; |
||||
} |
||||
|
||||
bwTotal += bw; |
||||
|
||||
if (bw < unalignedLength) { |
||||
return bwTotal; |
||||
}
|
||||
} |
||||
|
||||
while (bwTotal < size) { |
||||
auto btw = MIN(CHUNK_SIZE, size - bwTotal); |
||||
|
||||
UINT bw; |
||||
auto result = f_write(&m_file, (const uint8_t *)buf + bwTotal, btw, &bw); |
||||
CHECK_ERROR("File::write 2", result); |
||||
if (result != FR_OK) { |
||||
return bwTotal; |
||||
} |
||||
|
||||
bwTotal += bw; |
||||
|
||||
if (bw < btw) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return bwTotal; |
||||
} |
||||
|
||||
bool File::sync() { |
||||
auto result = f_sync(&m_file); |
||||
CHECK_ERROR("File::sync", result); |
||||
return result == FR_OK; |
||||
} |
||||
|
||||
void File::print(float value, int numDecimalDigits) { |
||||
char buffer[32]; |
||||
snprintf(buffer, sizeof(buffer), "%.*f", numDecimalDigits, value); |
||||
write((uint8_t *)buffer, strlen(buffer)); |
||||
} |
||||
|
||||
void File::print(char value) { |
||||
auto result = f_printf(&m_file, "%c", value); |
||||
CHECK_ERROR("File:print", result); |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SdFat::mount(int *err) { |
||||
auto result = f_mount(&SDFatFS, SDPath, 1); |
||||
CHECK_ERROR("SdFat::mount", result); |
||||
if (result != FR_OK) { |
||||
if (result == FR_NO_FILESYSTEM) { |
||||
*err = SCPI_ERROR_MASS_MEDIA_NO_FILESYSTEM; |
||||
} else { |
||||
*err = SCPI_ERROR_MASS_STORAGE_ERROR; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
*err = SCPI_RES_OK; |
||||
return true; |
||||
} |
||||
|
||||
void SdFat::unmount() { |
||||
auto result = f_mount(0, "", 0); |
||||
CHECK_ERROR("SdFat::unmount", result); |
||||
memset(&SDFatFS, 0, sizeof(SDFatFS)); |
||||
} |
||||
|
||||
bool SdFat::exists(const char *path) { |
||||
if (strcmp(path, "/") == 0) { |
||||
return true; |
||||
} |
||||
FILINFO fno; |
||||
auto result = f_stat(path, &fno); |
||||
CHECK_ERROR("SdFat::exists", result); |
||||
return result == FR_OK; |
||||
} |
||||
|
||||
bool SdFat::rename(const char *sourcePath, const char *destinationPath) { |
||||
auto result = f_rename(sourcePath, destinationPath); |
||||
CHECK_ERROR("SdFat::rename", result); |
||||
return result == FR_OK; |
||||
} |
||||
|
||||
bool SdFat::remove(const char *path) { |
||||
auto result = f_unlink(path); |
||||
CHECK_ERROR("SdFat::remove", result); |
||||
return result == FR_OK; |
||||
} |
||||
|
||||
bool SdFat::mkdir(const char *path) { |
||||
auto result = f_mkdir(path); |
||||
CHECK_ERROR("SdFat::mkdir", result); |
||||
return result == FR_OK; |
||||
} |
||||
|
||||
bool SdFat::rmdir(const char *path) { |
||||
auto result = f_unlink(path); |
||||
CHECK_ERROR("SdFat::rmdir", result); |
||||
return result == FR_OK; |
||||
} |
||||
|
||||
bool SdFat::getInfo(int diskDriveIndex, uint64_t &usedSpace, uint64_t &freeSpace) { |
||||
char path[3]; |
||||
|
||||
path[0] = '0' + diskDriveIndex; |
||||
path[1] = ':'; |
||||
path[2] = 0; |
||||
|
||||
DWORD freeClusters; |
||||
FATFS *fs; |
||||
auto result = f_getfree(path, &freeClusters, &fs); |
||||
CHECK_ERROR("SdFat::getInfo", result); |
||||
if (result != FR_OK) { |
||||
return false; |
||||
} |
||||
|
||||
DWORD totalSector = (fs->n_fatent - 2) * fs->csize; |
||||
DWORD freeSector = freeClusters * fs->csize; |
||||
|
||||
uint64_t totalSpace = totalSector * uint64_t(512); |
||||
freeSpace = freeSector * uint64_t(512); |
||||
usedSpace = totalSpace - freeSpace; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
} // namespace eez
|
||||
|
||||
#endif // EEZ_PLATFORM_STM32
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/gui/gui.h> |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
|
||||
void action_yes() { |
||||
auto appContext = getAppContextFromId(APP_CONTEXT_ID_DEVICE); |
||||
auto callback = appContext->m_dialogYesCallback; |
||||
appContext->popPage(); |
||||
if (callback) { |
||||
callback(); |
||||
} |
||||
} |
||||
|
||||
void action_no() { |
||||
auto appContext = getAppContextFromId(APP_CONTEXT_ID_DEVICE); |
||||
auto callback = appContext->m_dialogNoCallback; |
||||
appContext->popPage(); |
||||
if (callback) { |
||||
callback(); |
||||
} |
||||
} |
||||
|
||||
void action_ok() { |
||||
action_yes(); |
||||
} |
||||
|
||||
void action_cancel() { |
||||
auto appContext = getAppContextFromId(APP_CONTEXT_ID_DEVICE); |
||||
auto callback = appContext->m_dialogCancelCallback; |
||||
appContext->popPage(); |
||||
if (callback) { |
||||
callback(); |
||||
} |
||||
} |
||||
|
||||
void action_later() { |
||||
auto appContext = getAppContextFromId(APP_CONTEXT_ID_DEVICE); |
||||
auto callback = appContext->m_dialogLaterCallback; |
||||
appContext->popPage(); |
||||
if (callback) { |
||||
callback(); |
||||
} |
||||
} |
||||
|
||||
void action_drag_overlay() { |
||||
} |
||||
|
||||
void action_scroll() { |
||||
} |
||||
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,369 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/gui/gui.h> |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
|
||||
using namespace display; |
||||
|
||||
AnimationState g_animationState; |
||||
static bool g_animationStateDirection; |
||||
static Rect g_animationStateSrcRect; |
||||
static Rect g_animationStateDstRect; |
||||
|
||||
void animateOpenCloseCallback(float t, VideoBuffer bufferOld, VideoBuffer bufferNew, VideoBuffer bufferDst) { |
||||
if (!g_animationStateDirection) { |
||||
auto bufferTemp = bufferOld; |
||||
bufferOld = bufferNew; |
||||
bufferNew = bufferTemp; |
||||
} |
||||
|
||||
auto remapX = g_animationStateDirection ? remapExp : remapOutExp; |
||||
auto remapY = g_animationStateDirection ? remapExp : remapOutExp; |
||||
|
||||
int srcX1; |
||||
int srcY1; |
||||
int srcX2; |
||||
int srcY2; |
||||
|
||||
int dstX1; |
||||
int dstY1; |
||||
int dstX2; |
||||
int dstY2; |
||||
|
||||
if (g_animationStateDirection) { |
||||
srcX1 = g_animationStateSrcRect.x; |
||||
srcY1 = g_animationStateSrcRect.y; |
||||
srcX2 = g_animationStateSrcRect.x + g_animationStateSrcRect.w; |
||||
srcY2 = g_animationStateSrcRect.y + g_animationStateSrcRect.h; |
||||
|
||||
int dx = MAX(g_animationStateSrcRect.x - g_animationStateDstRect.x, |
||||
g_animationStateDstRect.x + g_animationStateDstRect.w - |
||||
(g_animationStateSrcRect.x + g_animationStateSrcRect.w)); |
||||
|
||||
int dy = MAX(g_animationStateSrcRect.y - g_animationStateDstRect.y, |
||||
g_animationStateDstRect.y + g_animationStateDstRect.h - |
||||
(g_animationStateSrcRect.y + g_animationStateSrcRect.h)); |
||||
|
||||
dstX1 = g_animationStateSrcRect.x - dx; |
||||
dstY1 = g_animationStateSrcRect.y - dy; |
||||
dstX2 = g_animationStateSrcRect.x + g_animationStateSrcRect.w + dx; |
||||
dstY2 = g_animationStateSrcRect.y + g_animationStateSrcRect.h + dy; |
||||
} else { |
||||
int dx = MAX(g_animationStateDstRect.x - g_animationStateSrcRect.x, |
||||
g_animationStateSrcRect.x + g_animationStateSrcRect.w - |
||||
(g_animationStateDstRect.x + g_animationStateDstRect.w)); |
||||
|
||||
int dy = MAX(g_animationStateDstRect.y - g_animationStateSrcRect.y, |
||||
g_animationStateSrcRect.y + g_animationStateSrcRect.h - |
||||
g_animationStateDstRect.y + g_animationStateDstRect.h); |
||||
|
||||
srcX1 = g_animationStateDstRect.x - dx; |
||||
srcY1 = g_animationStateDstRect.y - dx; |
||||
srcX2 = g_animationStateDstRect.x + g_animationStateDstRect.w + dx; |
||||
srcY2 = g_animationStateDstRect.y + g_animationStateDstRect.h + dy; |
||||
|
||||
dstX1 = g_animationStateDstRect.x; |
||||
dstY1 = g_animationStateDstRect.y; |
||||
dstX2 = g_animationStateDstRect.x + g_animationStateDstRect.w; |
||||
dstY2 = g_animationStateDstRect.y + g_animationStateDstRect.h; |
||||
} |
||||
|
||||
int x1 = (int)round(remapX((float)t, 0, (float)srcX1, 1, (float)dstX1)); |
||||
if (g_animationStateDirection) { |
||||
if (x1 < g_animationStateDstRect.x) { |
||||
x1 = g_animationStateDstRect.x; |
||||
} |
||||
} else { |
||||
if (x1 < g_animationStateSrcRect.x) { |
||||
x1 = g_animationStateSrcRect.x; |
||||
} |
||||
} |
||||
|
||||
int y1 = (int)round(remapY((float)t, 0, (float)srcY1, 1, (float)dstY1)); |
||||
if (g_animationStateDirection) { |
||||
if (y1 < g_animationStateDstRect.y) { |
||||
y1 = g_animationStateDstRect.y; |
||||
} |
||||
} else { |
||||
if (y1 < g_animationStateSrcRect.y) { |
||||
y1 = g_animationStateSrcRect.y; |
||||
} |
||||
} |
||||
|
||||
int x2 = (int)round(remapX((float)t, 0, (float)srcX2, 1, (float)dstX2)); |
||||
if (g_animationStateDirection) { |
||||
if (x2 > g_animationStateDstRect.x + g_animationStateDstRect.w) { |
||||
x2 = g_animationStateDstRect.x + g_animationStateDstRect.w; |
||||
} |
||||
} else { |
||||
if (x2 > g_animationStateSrcRect.x + g_animationStateSrcRect.w) { |
||||
x2 = g_animationStateSrcRect.x + g_animationStateSrcRect.w; |
||||
} |
||||
} |
||||
|
||||
int y2 = (int)round(remapY((float)t, 0, (float)srcY2, 1, (float)dstY2)); |
||||
if (g_animationStateDirection) { |
||||
if (y2 > g_animationStateDstRect.y + g_animationStateDstRect.h) { |
||||
y2 = g_animationStateDstRect.y + g_animationStateDstRect.h; |
||||
} |
||||
} else { |
||||
if (y2 > g_animationStateSrcRect.y + g_animationStateSrcRect.h) { |
||||
y2 = g_animationStateSrcRect.y + g_animationStateSrcRect.h; |
||||
} |
||||
} |
||||
|
||||
bitBlt(bufferOld, bufferDst, 0, 0, getDisplayWidth() - 1, getDisplayHeight() - 1); |
||||
bitBlt(bufferNew, bufferDst, x1, y1, x2, y2); |
||||
} |
||||
|
||||
void animateOpenClose(const Rect &srcRect, const Rect &dstRect, bool direction) { |
||||
display::animate(BUFFER_OLD, animateOpenCloseCallback); |
||||
g_animationStateSrcRect = srcRect; |
||||
g_animationStateDstRect = dstRect; |
||||
g_animationStateDirection = direction; |
||||
} |
||||
|
||||
void animateOpen(const Rect &srcRect, const Rect &dstRect) { |
||||
animateOpenClose(srcRect, dstRect, true); |
||||
} |
||||
|
||||
void animateClose(const Rect &srcRect, const Rect &dstRect) { |
||||
animateOpenClose(srcRect, dstRect, false); |
||||
} |
||||
|
||||
static Rect g_clipRect; |
||||
static int g_numRects; |
||||
AnimRect g_animRects[MAX_ANIM_RECTS]; |
||||
|
||||
void animateRectsStep(float t, VideoBuffer bufferOld, VideoBuffer bufferNew, VideoBuffer bufferDst) { |
||||
bitBlt(g_animationState.startBuffer == BUFFER_OLD ? bufferOld : bufferNew, bufferDst, 0, 0, getDisplayWidth() - 1, getDisplayHeight() - 1); |
||||
|
||||
float t1 = g_animationState.easingRects(t, 0, 0, 1, 1); // rects
|
||||
float t2 = g_animationState.easingOpacity(t, 0, 0, 1, 1); // opacity
|
||||
|
||||
for (int i = 0; i < g_numRects; i++) { |
||||
AnimRect &animRect = g_animRects[i]; |
||||
|
||||
int x, y, w, h; |
||||
|
||||
if (animRect.srcRect == animRect.dstRect) { |
||||
x = animRect.srcRect.x; |
||||
y = animRect.srcRect.y; |
||||
w = animRect.srcRect.w; |
||||
h = animRect.srcRect.h; |
||||
} else { |
||||
if (animRect.dstRect.x > animRect.srcRect.x) |
||||
x = (int)roundf(animRect.srcRect.x + t1 * (animRect.dstRect.x - animRect.srcRect.x)); |
||||
else |
||||
x = (int)floorf(animRect.srcRect.x + t1 * (animRect.dstRect.x - animRect.srcRect.x)); |
||||
|
||||
if (animRect.dstRect.y > animRect.srcRect.y) |
||||
y = (int)roundf(animRect.srcRect.y + t1 * (animRect.dstRect.y - animRect.srcRect.y)); |
||||
else |
||||
y = (int)floorf(animRect.srcRect.y + t1 * (animRect.dstRect.y - animRect.srcRect.y)); |
||||
|
||||
if (animRect.dstRect.w > animRect.srcRect.w) |
||||
w = (int)ceilf(animRect.srcRect.w + t1 * (animRect.dstRect.w - animRect.srcRect.w)); |
||||
else |
||||
w = (int)floorf(animRect.srcRect.w + t1 * (animRect.dstRect.w - animRect.srcRect.w)); |
||||
|
||||
if (animRect.dstRect.h > animRect.srcRect.h) |
||||
h = (int)ceilf(animRect.srcRect.h + t1 * (animRect.dstRect.h - animRect.srcRect.h)); |
||||
else |
||||
h = (int)floorf(animRect.srcRect.h + t1 * (animRect.dstRect.h - animRect.srcRect.h)); |
||||
} |
||||
|
||||
uint8_t opacity; |
||||
if (animRect.opacity == OPACITY_FADE_IN) { |
||||
opacity = (uint8_t)roundf(clamp(roundf(t2 * 255), 0, 255)); |
||||
} else if (animRect.opacity == OPACITY_FADE_OUT) { |
||||
opacity = (uint8_t)roundf(clamp((1 - t2) * 255, 0, 255)); |
||||
} else { |
||||
opacity = 255; |
||||
} |
||||
|
||||
if (animRect.buffer == BUFFER_SOLID_COLOR) { |
||||
auto savedOpacity = setOpacity(opacity); |
||||
setColor(animRect.color); |
||||
|
||||
// clip
|
||||
if (x < g_clipRect.x) { |
||||
w -= g_clipRect.x - x; |
||||
x = g_clipRect.x; |
||||
} |
||||
|
||||
if (x + w > g_clipRect.x + g_clipRect.w) { |
||||
w -= (x + w) - (g_clipRect.x + g_clipRect.w); |
||||
} |
||||
|
||||
if (y < g_clipRect.y) { |
||||
h -= g_clipRect.y - y; |
||||
y = g_clipRect.y; |
||||
} |
||||
|
||||
if (y + h > g_clipRect.y + g_clipRect.h) { |
||||
h -= (y + h) - (g_clipRect.y + g_clipRect.y); |
||||
} |
||||
|
||||
fillRect(bufferDst, x, y, x + w - 1, y + h - 1); |
||||
|
||||
setOpacity(savedOpacity); |
||||
} else { |
||||
void *buffer = animRect.buffer == BUFFER_OLD ? bufferOld : bufferNew; |
||||
Rect &srcRect = animRect.buffer == BUFFER_OLD ? animRect.srcRect : animRect.dstRect; |
||||
|
||||
int sx; |
||||
int sy; |
||||
int sw; |
||||
int sh; |
||||
|
||||
int dx; |
||||
int dy; |
||||
|
||||
if (animRect.position == POSITION_TOP_LEFT || animRect.position == POSITION_LEFT || animRect.position == POSITION_BOTTOM_LEFT) { |
||||
sx = srcRect.x; |
||||
sw = MIN(srcRect.w, w); |
||||
dx = x; |
||||
} else if (animRect.position == POSITION_TOP || animRect.position == POSITION_CENTER || animRect.position == POSITION_BOTTOM) { |
||||
if (srcRect.w < w) { |
||||
sx = srcRect.x; |
||||
sw = srcRect.w; |
||||
dx = x + (w - srcRect.w) / 2; |
||||
} else if (srcRect.w > w) { |
||||
sx = srcRect.x + (srcRect.w - w) / 2; |
||||
sw = w; |
||||
dx = x; |
||||
} else { |
||||
sx = srcRect.x; |
||||
sw = srcRect.w; |
||||
dx = x; |
||||
} |
||||
} else { |
||||
sw = MIN(srcRect.w, w); |
||||
sx = srcRect.x + srcRect.w - sw; |
||||
dx = x + w - sw; |
||||
} |
||||
|
||||
if (animRect.position == POSITION_TOP_LEFT || animRect.position == POSITION_TOP || animRect.position == POSITION_TOP_RIGHT) { |
||||
sy = srcRect.y; |
||||
sh = MIN(srcRect.h, h); |
||||
dy = y; |
||||
} else if (animRect.position == POSITION_LEFT || animRect.position == POSITION_CENTER || animRect.position == POSITION_RIGHT) { |
||||
if (srcRect.h < h) { |
||||
sy = srcRect.y; |
||||
sh = srcRect.h; |
||||
dy = y + (h - srcRect.h) / 2; |
||||
} else if (srcRect.h > h) { |
||||
sy = srcRect.y + (srcRect.h - h) / 2; |
||||
sh = h; |
||||
dy = y; |
||||
} else { |
||||
sy = srcRect.y; |
||||
sh = srcRect.h; |
||||
dy = y; |
||||
} |
||||
} else { |
||||
sh = MIN(srcRect.h, h); |
||||
sy = srcRect.y + srcRect.h - sh; |
||||
dy = y + h - sh; |
||||
} |
||||
|
||||
// clip
|
||||
if (sx < g_clipRect.x) { |
||||
sw -= g_clipRect.x - sx; |
||||
dx += g_clipRect.x - sx; |
||||
sx = g_clipRect.x; |
||||
} |
||||
|
||||
if (dx < g_clipRect.x) { |
||||
sw -= g_clipRect.x - dx; |
||||
sx += g_clipRect.x - dx; |
||||
dx = g_clipRect.x; |
||||
} |
||||
|
||||
if (sx + sw > g_clipRect.x + g_clipRect.w) { |
||||
sw -= (sx + sw) - (g_clipRect.x + g_clipRect.w); |
||||
} |
||||
|
||||
if (dx + sw > g_clipRect.x + g_clipRect.w) { |
||||
sw -= (dx + sw) - (g_clipRect.x + g_clipRect.w); |
||||
} |
||||
|
||||
if (sy < g_clipRect.y) { |
||||
sh -= g_clipRect.y - sy; |
||||
dy += g_clipRect.y - sy; |
||||
sy = g_clipRect.y; |
||||
} |
||||
|
||||
if (dy < g_clipRect.y) { |
||||
sh -= g_clipRect.y - dy; |
||||
sy += g_clipRect.y - dy; |
||||
dy = g_clipRect.y; |
||||
} |
||||
|
||||
if (dy + sh > g_clipRect.y + g_clipRect.h) { |
||||
sh -= (dy + sh) - (g_clipRect.y + g_clipRect.h); |
||||
} |
||||
|
||||
if (sy + sh > g_clipRect.y + g_clipRect.h) { |
||||
sy -= (sy + sh) - (g_clipRect.y + g_clipRect.h); |
||||
} |
||||
|
||||
bitBlt(buffer, bufferDst, sx, sy, sw, sh, dx, dy, opacity); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void prepareRect(AppContext *appContext, Rect &rect) { |
||||
if (appContext->rect.x > 0) { |
||||
rect.x += appContext->rect.x; |
||||
} |
||||
if (appContext->rect.y > 0) { |
||||
rect.y += appContext->rect.y; |
||||
} |
||||
} |
||||
|
||||
void animateRects(AppContext *appContext, Buffer startBuffer, int numRects, float duration, const Rect *clipRect) { |
||||
display::animate(startBuffer, animateRectsStep, duration); |
||||
|
||||
g_numRects = numRects; |
||||
|
||||
if (clipRect) { |
||||
g_clipRect.x = clipRect->x; |
||||
g_clipRect.y = clipRect->y; |
||||
g_clipRect.w = clipRect->w; |
||||
g_clipRect.h = clipRect->h; |
||||
prepareRect(appContext, g_clipRect); |
||||
} else { |
||||
g_clipRect.x = appContext->rect.x; |
||||
g_clipRect.y = appContext->rect.y; |
||||
g_clipRect.w = appContext->rect.w; |
||||
g_clipRect.h = appContext->rect.h; |
||||
} |
||||
|
||||
for (int i = 0; i < numRects; i++) { |
||||
prepareRect(appContext, g_animRects[i].srcRect); |
||||
prepareRect(appContext, g_animRects[i].dstRect); |
||||
} |
||||
} |
||||
|
||||
} // gui
|
||||
} // eez
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
|
||||
enum Buffer { |
||||
BUFFER_OLD, |
||||
BUFFER_NEW, |
||||
BUFFER_SOLID_COLOR |
||||
}; |
||||
|
||||
enum Opacity { |
||||
OPACITY_SOLID, |
||||
OPACITY_FADE_IN, |
||||
OPACITY_FADE_OUT |
||||
}; |
||||
|
||||
enum Position { |
||||
POSITION_TOP_LEFT, |
||||
POSITION_TOP, |
||||
POSITION_TOP_RIGHT, |
||||
POSITION_LEFT, |
||||
POSITION_CENTER, |
||||
POSITION_RIGHT, |
||||
POSITION_BOTTOM_LEFT, |
||||
POSITION_BOTTOM, |
||||
POSITION_BOTTOM_RIGHT |
||||
}; |
||||
|
||||
struct AnimationState { |
||||
bool enabled; |
||||
uint32_t startTime; |
||||
float duration; |
||||
Buffer startBuffer; |
||||
void (*callback)(float t, VideoBuffer bufferOld, VideoBuffer bufferNew, VideoBuffer bufferDst); |
||||
float (*easingRects)(float x, float x1, float y1, float x2, float y2); |
||||
float (*easingOpacity)(float x, float x1, float y1, float x2, float y2); |
||||
}; |
||||
|
||||
struct AnimRect { |
||||
Buffer buffer; |
||||
Rect srcRect; |
||||
Rect dstRect; |
||||
uint16_t color; |
||||
Opacity opacity; |
||||
Position position; |
||||
}; |
||||
|
||||
extern AnimationState g_animationState; |
||||
|
||||
#define MAX_ANIM_RECTS 10 |
||||
|
||||
extern AnimRect g_animRects[MAX_ANIM_RECTS]; |
||||
|
||||
void animateOpen(const Rect &srcRect, const Rect &dstRect); |
||||
void animateClose(const Rect &srcRect, const Rect &dstRect); |
||||
void animateRects(AppContext *appContext, Buffer startBuffer, int numRects, float duration = -1, const Rect *clipRect = nullptr); |
||||
|
||||
} // gui
|
||||
} // eez
|
@ -1,543 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <math.h> |
||||
#include <assert.h> |
||||
#include <memory.h> |
||||
|
||||
#include <eez/conf.h> |
||||
#include <eez/core/sound.h> |
||||
#include <eez/core/os.h> |
||||
#include <eez/core/util.h> |
||||
|
||||
#if OPTION_KEYBOARD |
||||
#include <eez/core/keyboard.h> |
||||
#endif |
||||
|
||||
#if OPTION_MOUSE |
||||
#include <eez/core/mouse.h> |
||||
#endif |
||||
|
||||
#include <eez/gui/gui.h> |
||||
#include <eez/gui/thread.h> |
||||
#include <eez/gui/touch_calibration.h> |
||||
#include <eez/gui/widgets/button.h> |
||||
|
||||
#include <eez/flow/debugger.h> |
||||
#include <eez/flow/private.h> |
||||
|
||||
#include <eez/core/hmi.h> |
||||
|
||||
#define CONF_GUI_TOAST_DURATION_MS 1000L |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AppContext::AppContext() { |
||||
m_updatePageIndex = -1; |
||||
} |
||||
|
||||
void AppContext::stateManagment() { |
||||
// remove alert message after period of time
|
||||
if (getActivePageId() == INTERNAL_PAGE_ID_TOAST_MESSAGE) { |
||||
ToastMessagePage *page = (ToastMessagePage *)getActivePage(); |
||||
if (!page->hasAction() && eez::hmi::getInactivityPeriodMs() >= CONF_GUI_TOAST_DURATION_MS) { |
||||
popPage(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool AppContext::isActivePageInternal() { |
||||
return isPageInternal(getActivePageId()); |
||||
} |
||||
|
||||
bool AppContext::isWidgetActionEnabled(const WidgetCursor &widgetCursor) { |
||||
const Widget *widget = widgetCursor.widget; |
||||
auto action = getWidgetAction(widgetCursor); |
||||
if (action) { |
||||
if (widget->type == WIDGET_TYPE_BUTTON) { |
||||
auto buttonWidget = (const ButtonWidget *)widget; |
||||
auto enabled = get(widgetCursor, buttonWidget->enabled); |
||||
if (!(enabled.getType() == VALUE_TYPE_UNDEFINED || enabled.getInt() ? 1 : 0)) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool AppContext::isAutoRepeatAction(int action) { |
||||
return false; |
||||
} |
||||
|
||||
bool AppContext::isFocusWidget(const WidgetCursor &widgetCursor) { |
||||
return false; |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AppContext::onPageChanged(int previousPageId, int activePageId) { |
||||
display::turnOn(); |
||||
hmi::noteActivity(); |
||||
|
||||
#if OPTION_MOUSE |
||||
mouse::onPageChanged(); |
||||
#endif |
||||
|
||||
#if OPTION_KEYBOARD |
||||
keyboard::onPageChanged(); |
||||
#endif |
||||
|
||||
flow::onPageChanged(previousPageId, activePageId); |
||||
} |
||||
|
||||
void AppContext::doShowPage(int pageId, Page *page, int previousPageId) { |
||||
#if CONF_OPTION_FPGA |
||||
pageId = PAGE_ID_WELCOME_800X480; |
||||
page = nullptr; |
||||
#endif |
||||
|
||||
page = page ? page : g_hooks.getPageFromId(pageId); |
||||
|
||||
m_pageNavigationStack[m_pageNavigationStackPointer].page = page; |
||||
m_pageNavigationStack[m_pageNavigationStackPointer].pageId = pageId; |
||||
m_pageNavigationStack[m_pageNavigationStackPointer].displayBufferIndex = -1; |
||||
m_pageNavigationStack[m_pageNavigationStackPointer].timelinePosition = 0; |
||||
|
||||
if (page) { |
||||
page->pageWillAppear(); |
||||
} |
||||
|
||||
m_showPageTime = millis(); |
||||
|
||||
onPageChanged(previousPageId, pageId); |
||||
|
||||
refreshScreen(); |
||||
} |
||||
|
||||
void AppContext::setPage(int pageId) { |
||||
int previousPageId = getActivePageId(); |
||||
|
||||
// delete stack
|
||||
for (int i = 0; i <= m_pageNavigationStackPointer; ++i) { |
||||
if (m_pageNavigationStack[i].page) { |
||||
m_pageNavigationStack[i].page->pageFree(); |
||||
} |
||||
} |
||||
m_pageNavigationStackPointer = 0; |
||||
|
||||
//
|
||||
doShowPage(pageId, nullptr, previousPageId); |
||||
} |
||||
|
||||
void AppContext::replacePage(int pageId, Page *page) { |
||||
int previousPageId = getActivePageId(); |
||||
|
||||
Page *activePage = getActivePage(); |
||||
if (activePage) { |
||||
activePage->pageFree(); |
||||
} |
||||
|
||||
doShowPage(pageId, page, previousPageId); |
||||
} |
||||
|
||||
void AppContext::pushPage(int pageId, Page *page) { |
||||
if (pushPageInGuiThread(this, pageId, page)) { |
||||
return; |
||||
} |
||||
|
||||
int previousPageId = getActivePageId(); |
||||
|
||||
// advance stack pointer
|
||||
if (getActivePageId() != PAGE_ID_NONE && getActivePageId() != PAGE_ID_ASYNC_OPERATION_IN_PROGRESS && getActivePageId() != INTERNAL_PAGE_ID_TOAST_MESSAGE) { |
||||
m_pageNavigationStackPointer++; |
||||
assert (m_pageNavigationStackPointer < CONF_GUI_PAGE_NAVIGATION_STACK_SIZE); |
||||
} |
||||
|
||||
doShowPage(pageId, page, previousPageId); |
||||
} |
||||
|
||||
void AppContext::popPage() { |
||||
if (m_pageNavigationStackPointer > 0) { |
||||
int previousPageId = getActivePageId(); |
||||
|
||||
if (m_pageNavigationStack[m_pageNavigationStackPointer].page) { |
||||
m_pageNavigationStack[m_pageNavigationStackPointer].page->pageFree(); |
||||
m_pageNavigationStack[m_pageNavigationStackPointer].page = nullptr; |
||||
} |
||||
--m_pageNavigationStackPointer; |
||||
|
||||
doShowPage(m_pageNavigationStack[m_pageNavigationStackPointer].pageId, m_pageNavigationStack[m_pageNavigationStackPointer].page, previousPageId); |
||||
} |
||||
} |
||||
|
||||
void AppContext::removePageFromStack(int pageId) { |
||||
for (int i = m_pageNavigationStackPointer; i > 0; i--) { |
||||
if (m_pageNavigationStack[i].pageId == pageId) { |
||||
if (i == m_pageNavigationStackPointer) { |
||||
popPage(); |
||||
} else { |
||||
if (m_pageNavigationStack[i].page) { |
||||
m_pageNavigationStack[i].page->pageFree(); |
||||
} |
||||
|
||||
for (int j = i + 1; j <= m_pageNavigationStackPointer; j++) { |
||||
memcpy(m_pageNavigationStack + j - 1, m_pageNavigationStack + j, sizeof(PageOnStack)); |
||||
} |
||||
|
||||
m_pageNavigationStack[m_pageNavigationStackPointer].page = nullptr; |
||||
|
||||
--m_pageNavigationStackPointer; |
||||
} |
||||
refreshScreen(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
Page *AppContext::getPage(int pageId) { |
||||
for (int i = 0; i <= m_pageNavigationStackPointer; ++i) { |
||||
if (m_pageNavigationStack[i].pageId == pageId) { |
||||
return m_pageNavigationStack[i].page; |
||||
} |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
bool AppContext::isPageOnStack(int pageId) { |
||||
for (int i = 0; i <= m_pageNavigationStackPointer; ++i) { |
||||
if (m_pageNavigationStack[i].pageId == pageId) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
bool AppContext::isExternalPageOnStack() { |
||||
for (int i = 0; i <= m_pageNavigationStackPointer; ++i) { |
||||
if (m_pageNavigationStack[i].pageId < 0) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
void AppContext::removeExternalPagesFromTheStack() { |
||||
for (int i = 0; i <= m_pageNavigationStackPointer; ++i) { |
||||
if (m_pageNavigationStack[i].pageId < 0) { |
||||
removePageFromStack(m_pageNavigationStack[i].pageId); |
||||
i = 0; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void AppContext::showPage(int pageId) { |
||||
if (showPageInGuiThread(this, pageId)) { |
||||
return; |
||||
} |
||||
|
||||
if (pageId != getActivePageId()) { |
||||
setPage(pageId); |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool AppContext::testExecuteActionOnTouchDown(int action) { |
||||
return false; |
||||
} |
||||
|
||||
bool AppContext::isBlinking(const WidgetCursor &widgetCursor, int16_t id) { |
||||
return false; |
||||
} |
||||
|
||||
bool AppContext::canExecuteActionWhenTouchedOutsideOfActivePage(int pageId, int action) { |
||||
return false; |
||||
} |
||||
|
||||
void AppContext::onPageTouch(const WidgetCursor &foundWidget, Event &touchEvent) { |
||||
int activePageId = getActivePageId(); |
||||
#if OPTION_TOUCH_CALIBRATION |
||||
if (activePageId == PAGE_ID_TOUCH_CALIBRATION) { |
||||
onTouchCalibrationPageTouch(foundWidget, touchEvent); |
||||
return; |
||||
} |
||||
#endif |
||||
|
||||
if (activePageId != PAGE_ID_NONE && !isPageInternal(activePageId)) { |
||||
auto page = getPageAsset(activePageId); |
||||
if ((page->flags & CLOSE_PAGE_IF_TOUCHED_OUTSIDE_FLAG) != 0) { |
||||
int xPage; |
||||
int yPage; |
||||
int wPage; |
||||
int hPage; |
||||
getPageRect(activePageId, getActivePage(), xPage, yPage, wPage, hPage); |
||||
|
||||
if (!pointInsideRect(touchEvent.x, touchEvent.y, xPage, yPage, wPage, hPage)) { |
||||
int activePageId = getActivePageId(); |
||||
|
||||
// clicked outside page, close page
|
||||
popPage(); |
||||
|
||||
auto widgetCursor = findWidget(touchEvent.x, touchEvent.y); |
||||
|
||||
if (widgetCursor.widget) { |
||||
auto action = getWidgetAction(widgetCursor); |
||||
if (action != ACTION_ID_NONE && canExecuteActionWhenTouchedOutsideOfActivePage(activePageId, action)) { |
||||
processTouchEvent(touchEvent); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AppContext::updatePage(int i, WidgetCursor &widgetCursor) { |
||||
if (g_findCallback == nullptr) { |
||||
m_pageNavigationStack[i].displayBufferIndex = display::beginBufferRendering(); |
||||
} |
||||
|
||||
m_updatePageIndex = i; |
||||
|
||||
int x; |
||||
int y; |
||||
int width; |
||||
int height; |
||||
bool withShadow; |
||||
|
||||
if (isPageInternal(m_pageNavigationStack[i].pageId)) { |
||||
auto internalPage = ((InternalPage *)m_pageNavigationStack[i].page); |
||||
|
||||
x = internalPage->x; |
||||
y = internalPage->y; |
||||
width = internalPage->width; |
||||
height = internalPage->height; |
||||
withShadow = true; |
||||
|
||||
widgetCursor.w = width; |
||||
widgetCursor.h = height; |
||||
|
||||
if (g_findCallback == nullptr) { |
||||
internalPage->updateInternalPage(); |
||||
} |
||||
|
||||
enumNoneWidget(); |
||||
} else { |
||||
auto page = getPageAsset(m_pageNavigationStack[i].pageId, widgetCursor); |
||||
|
||||
if (widgetCursor.flowState && widgetCursor.flowState->timelinePosition != m_pageNavigationStack[i].timelinePosition) { |
||||
widgetCursor.hasPreviousState = false; |
||||
m_pageNavigationStack[i].timelinePosition = widgetCursor.flowState->timelinePosition; |
||||
} |
||||
|
||||
auto savedWidget = widgetCursor.widget; |
||||
widgetCursor.widget = page; |
||||
|
||||
if ((page->flags & PAGE_SCALE_TO_FIT) && flow::g_debuggerMode == flow::DEBUGGER_MODE_RUN) { |
||||
x = rect.x; |
||||
y = rect.y; |
||||
width = rect.w; |
||||
height = rect.h; |
||||
} else { |
||||
x = widgetCursor.x + page->x; |
||||
y = widgetCursor.y + page->y; |
||||
width = page->width; |
||||
height = page->height; |
||||
} |
||||
|
||||
withShadow = page->x > 0; |
||||
|
||||
auto savedX = widgetCursor.x; |
||||
auto savedY = widgetCursor.y; |
||||
|
||||
widgetCursor.x = x; |
||||
widgetCursor.y = y; |
||||
|
||||
widgetCursor.w = width; |
||||
widgetCursor.h = height; |
||||
|
||||
enumWidget(); |
||||
|
||||
widgetCursor.x = savedX; |
||||
widgetCursor.y = savedY; |
||||
|
||||
widgetCursor.widget = savedWidget; |
||||
} |
||||
|
||||
if (g_findCallback == nullptr) { |
||||
pageRenderCustom(i, widgetCursor); |
||||
display::endBufferRendering(m_pageNavigationStack[i].displayBufferIndex, x, y, width, height, withShadow, 255, 0, 0, withShadow && g_hooks.activePageHasBackdrop() ? &rect : nullptr); |
||||
} |
||||
|
||||
m_updatePageIndex = -1; |
||||
} |
||||
|
||||
void AppContext::pageRenderCustom(int i, WidgetCursor &widgetCursor) { |
||||
} |
||||
|
||||
bool isRect1FullyCoveredByRect2(int xRect1, int yRect1, int wRect1, int hRect1, int xRect2, int yRect2, int wRect2, int hRect2) { |
||||
return xRect2 <= xRect1 && yRect2 <= yRect1 && xRect2 + wRect2 >= xRect1 + wRect1 && yRect2 + hRect2 >= yRect1 + hRect1; |
||||
} |
||||
|
||||
void AppContext::getPageRect(int pageId, const Page *page, int &x, int &y, int &w, int &h) { |
||||
if (isPageInternal(pageId)) { |
||||
x = rect.x + ((InternalPage *)page)->x; |
||||
y = rect.y + ((InternalPage *)page)->y; |
||||
w = ((InternalPage *)page)->width; |
||||
h = ((InternalPage *)page)->height; |
||||
} else { |
||||
auto page = getPageAsset(pageId); |
||||
if ((page->flags & PAGE_SCALE_TO_FIT) && flow::g_debuggerMode == flow::DEBUGGER_MODE_RUN) { |
||||
x = rect.x; |
||||
y = rect.y; |
||||
w = rect.w; |
||||
h = rect.h; |
||||
} else { |
||||
x = rect.x + page->x; |
||||
y = rect.y + page->y; |
||||
w = page->width; |
||||
h = page->height; |
||||
} |
||||
} |
||||
} |
||||
|
||||
bool AppContext::isPageFullyCovered(int pageNavigationStackIndex) { |
||||
int xPage, yPage, wPage, hPage; |
||||
getPageRect(m_pageNavigationStack[pageNavigationStackIndex].pageId, m_pageNavigationStack[pageNavigationStackIndex].page, xPage, yPage, wPage, hPage); |
||||
|
||||
for (int i = pageNavigationStackIndex + 1; i <= m_pageNavigationStackPointer; i++) { |
||||
int xPageAbove, yPageAbove, wPageAbove, hPageAbove; |
||||
getPageRect(m_pageNavigationStack[i].pageId, m_pageNavigationStack[i].page, xPageAbove, yPageAbove, wPageAbove, hPageAbove); |
||||
|
||||
if (isRect1FullyCoveredByRect2(xPage, yPage, wPage, hPage, xPageAbove, yPageAbove, wPageAbove, hPageAbove)) { |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
int AppContext::getLongTouchActionHook(const WidgetCursor &widgetCursor) { |
||||
return ACTION_ID_NONE; |
||||
} |
||||
|
||||
void AppContext::yesNoDialog(int yesNoPageId, const char *message, void (*yes_callback)(), void (*no_callback)(), void (*cancel_callback)()) { |
||||
set(WidgetCursor(), DATA_ID_ALERT_MESSAGE, Value(message)); |
||||
|
||||
m_dialogYesCallback = yes_callback; |
||||
m_dialogNoCallback = no_callback; |
||||
m_dialogCancelCallback = cancel_callback; |
||||
|
||||
pushPage(yesNoPageId); |
||||
} |
||||
|
||||
void AppContext::yesNoDialog(int yesNoPageId, Value value, void(*yes_callback)(), void(*no_callback)(), void(*cancel_callback)()) { |
||||
set(WidgetCursor(), DATA_ID_ALERT_MESSAGE, value); |
||||
|
||||
m_dialogYesCallback = yes_callback; |
||||
m_dialogNoCallback = no_callback; |
||||
m_dialogCancelCallback = cancel_callback; |
||||
|
||||
pushPage(yesNoPageId); |
||||
} |
||||
|
||||
void AppContext::infoMessage(const char *message) { |
||||
pushToastMessage(ToastMessagePage::create(this, INFO_TOAST, message)); |
||||
} |
||||
|
||||
void AppContext::infoMessage(Value value) { |
||||
pushToastMessage(ToastMessagePage::create(this, INFO_TOAST, value)); |
||||
} |
||||
|
||||
void AppContext::infoMessage(const char *message, void (*action)(), const char *actionLabel) { |
||||
pushToastMessage(ToastMessagePage::create(this, INFO_TOAST, message, action, actionLabel)); |
||||
} |
||||
|
||||
void AppContext::errorMessage(const char *message, bool autoDismiss) { |
||||
AppContext::pushToastMessage(ToastMessagePage::create(this, ERROR_TOAST, message, autoDismiss)); |
||||
sound::playBeep(); |
||||
} |
||||
|
||||
void AppContext::errorMessage(Value value) { |
||||
AppContext::pushToastMessage(ToastMessagePage::create(this, ERROR_TOAST, value)); |
||||
sound::playBeep(); |
||||
} |
||||
|
||||
void AppContext::errorMessageWithAction(Value value, void (*action)(int param), const char *actionLabel, int actionParam) { |
||||
AppContext::pushToastMessage(ToastMessagePage::create(this, ERROR_TOAST, value, action, actionLabel, actionParam)); |
||||
sound::playBeep(); |
||||
} |
||||
|
||||
void AppContext::errorMessageWithAction(const char *message, void (*action)(), const char *actionLabel) { |
||||
AppContext::pushToastMessage(ToastMessagePage::create(this, ERROR_TOAST, message, action, actionLabel)); |
||||
sound::playBeep(); |
||||
} |
||||
|
||||
void AppContext::pushToastMessage(ToastMessagePage *toastMessage) { |
||||
pushPage(INTERNAL_PAGE_ID_TOAST_MESSAGE, toastMessage); |
||||
} |
||||
|
||||
void AppContext::getBoundingRect(Rect &rectBounding) { |
||||
if (m_pageNavigationStackPointer >= 0) { |
||||
int x1 = rect.x + rect.w; |
||||
int y1 = rect.y + rect.h; |
||||
int x2 = rect.x; |
||||
int y2 = rect.y; |
||||
|
||||
for (int i = 0; i <= m_pageNavigationStackPointer; ++i) { |
||||
if (!isPageInternal(m_pageNavigationStack[i].pageId)) { |
||||
int xPage, yPage, wPage, hPage; |
||||
getPageRect(m_pageNavigationStack[i].pageId, m_pageNavigationStack[i].page, xPage, yPage, wPage, hPage); |
||||
if (xPage < x1) x1 = xPage; |
||||
if (xPage + wPage > x2) x2 = xPage + wPage; |
||||
if (yPage < y1) y1 = yPage; |
||||
if (yPage + hPage > y2) y2 = yPage + hPage; |
||||
} |
||||
} |
||||
|
||||
rectBounding.x = x1; |
||||
rectBounding.y = y1; |
||||
rectBounding.w = x2 - x1; |
||||
rectBounding.h = y2 - y1; |
||||
} else { |
||||
rectBounding.x = rect.x; |
||||
rectBounding.y = rect.y; |
||||
rectBounding.w = rect.w; |
||||
rectBounding.h = rect.h; |
||||
} |
||||
} |
||||
|
||||
AppContext *getRootAppContext() { |
||||
#ifdef EEZ_PLATFORM_SIMULATOR |
||||
return getAppContextFromId(APP_CONTEXT_ID_SIMULATOR_FRONT_PANEL); |
||||
#else |
||||
return getAppContextFromId(APP_CONTEXT_ID_DEVICE); |
||||
#endif |
||||
} |
||||
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,146 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#define CONF_GUI_PAGE_NAVIGATION_STACK_SIZE 10 |
||||
|
||||
#define APP_CONTEXT_ID_DEVICE 0 |
||||
#define APP_CONTEXT_ID_SIMULATOR_FRONT_PANEL 1 |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
|
||||
class Page; |
||||
|
||||
struct PageOnStack { |
||||
int pageId = PAGE_ID_NONE; |
||||
Page *page = nullptr; |
||||
int displayBufferIndex = -1; |
||||
float timelinePosition; |
||||
}; |
||||
|
||||
class ToastMessagePage; |
||||
|
||||
class AppContext { |
||||
friend struct AppViewWidgetState; |
||||
|
||||
public: |
||||
Rect rect; |
||||
|
||||
AppContext(); |
||||
|
||||
virtual void stateManagment(); |
||||
|
||||
void showPage(int pageId); |
||||
void pushPage(int pageId, Page *page = nullptr); |
||||
void popPage(); |
||||
void removePageFromStack(int pageId); |
||||
|
||||
int getActivePageStackPointer() { |
||||
return m_updatePageIndex != -1 ? m_updatePageIndex : m_pageNavigationStackPointer; |
||||
} |
||||
|
||||
int getActivePageId() { |
||||
return m_pageNavigationStack[getActivePageStackPointer()].pageId; |
||||
} |
||||
|
||||
Page *getActivePage() { |
||||
return m_pageNavigationStack[getActivePageStackPointer()].page; |
||||
} |
||||
|
||||
bool isActivePageInternal(); |
||||
|
||||
int getPreviousPageId() { |
||||
int index = getActivePageStackPointer(); |
||||
return index == 0 ? PAGE_ID_NONE : m_pageNavigationStack[index - 1].pageId; |
||||
} |
||||
|
||||
void replacePage(int pageId, Page *page = nullptr); |
||||
|
||||
Page *getPage(int pageId); |
||||
bool isPageOnStack(int pageId); |
||||
bool isExternalPageOnStack(); |
||||
void removeExternalPagesFromTheStack(); |
||||
|
||||
int getNumPagesOnStack() { |
||||
return m_pageNavigationStackPointer + 1; |
||||
} |
||||
|
||||
virtual bool isFocusWidget(const WidgetCursor &widgetCursor); |
||||
|
||||
virtual bool isBlinking(const WidgetCursor &widgetCursor, int16_t id); |
||||
|
||||
virtual void onPageTouch(const WidgetCursor &foundWidget, Event &touchEvent); |
||||
|
||||
virtual bool testExecuteActionOnTouchDown(int action); |
||||
|
||||
virtual bool isAutoRepeatAction(int action); |
||||
|
||||
virtual bool isWidgetActionEnabled(const WidgetCursor &widgetCursor); |
||||
|
||||
virtual int getLongTouchActionHook(const WidgetCursor &widgetCursor); |
||||
|
||||
void infoMessage(const char *message); |
||||
void infoMessage(Value value); |
||||
void infoMessage(const char *message, void (*action)(), const char *actionLabel); |
||||
void errorMessage(const char *message, bool autoDismiss = false); |
||||
void errorMessage(Value value); |
||||
void errorMessageWithAction(Value value, void (*action)(int param), const char *actionLabel, int actionParam); |
||||
void errorMessageWithAction(const char *message, void (*action)(), const char *actionLabel); |
||||
|
||||
void yesNoDialog(int yesNoPageId, const char *message, void (*yes_callback)(), void (*no_callback)(), void (*cancel_callback)()); |
||||
void yesNoDialog(int yesNoPageId, Value value, void(*yes_callback)(), void(*no_callback)(), void(*cancel_callback)()); |
||||
|
||||
// TODO these should be private
|
||||
void(*m_dialogYesCallback)(); |
||||
void(*m_dialogNoCallback)(); |
||||
void(*m_dialogCancelCallback)(); |
||||
void(*m_dialogLaterCallback)(); |
||||
|
||||
virtual int getMainPageId() = 0; |
||||
|
||||
void getBoundingRect(Rect &rect); |
||||
|
||||
protected: |
||||
PageOnStack m_pageNavigationStack[CONF_GUI_PAGE_NAVIGATION_STACK_SIZE]; |
||||
int m_pageNavigationStackPointer = 0; |
||||
int m_updatePageIndex; |
||||
|
||||
uint32_t m_showPageTime; |
||||
|
||||
virtual void onPageChanged(int previousPageId, int activePageId); |
||||
|
||||
void doShowPage(int index, Page *page, int previousPageId); |
||||
void setPage(int pageId); |
||||
|
||||
void updatePage(int i, WidgetCursor &widgetCursor); |
||||
virtual void pageRenderCustom(int i, WidgetCursor &widgetCursor); |
||||
|
||||
void getPageRect(int pageId, const Page *page, int &x, int &y, int &w, int &h); |
||||
bool isPageFullyCovered(int pageNavigationStackIndex); |
||||
|
||||
virtual bool canExecuteActionWhenTouchedOutsideOfActivePage(int pageId, int action); |
||||
|
||||
void pushToastMessage(ToastMessagePage *toastMessage); |
||||
}; |
||||
|
||||
AppContext *getRootAppContext(); |
||||
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,256 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <assert.h> |
||||
#include <stdlib.h> |
||||
#include <memory.h> |
||||
|
||||
#include <eez/core/alloc.h> |
||||
#include <eez/core/os.h> |
||||
#include <eez/core/memory.h> |
||||
#include <eez/core/debug.h> |
||||
#include <eez/flow/flow.h> |
||||
|
||||
#include <eez/libs/lz4/lz4.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
#include <eez/gui/widget.h> |
||||
|
||||
#if OPTION_SCPI |
||||
#include <scpi/scpi.h> |
||||
#else |
||||
#define SCPI_ERROR_OUT_OF_DEVICE_MEMORY -321 |
||||
#define SCPI_ERROR_INVALID_BLOCK_DATA -161 |
||||
#endif |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
|
||||
bool g_isMainAssetsLoaded; |
||||
Assets *g_mainAssets; |
||||
Assets *g_externalAssets; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void fixOffsets(Assets *assets); |
||||
|
||||
bool decompressAssetsData(const uint8_t *assetsData, uint32_t assetsDataSize, Assets *decompressedAssets, uint32_t maxDecompressedAssetsSize, int *err) { |
||||
uint32_t compressedDataOffset; |
||||
uint32_t decompressedSize; |
||||
|
||||
auto header = (Header *)assetsData; |
||||
|
||||
if (header->tag == HEADER_TAG) { |
||||
decompressedAssets->projectMajorVersion = header->projectMajorVersion; |
||||
decompressedAssets->projectMinorVersion = header->projectMinorVersion; |
||||
decompressedAssets->assetsType = header->assetsType; |
||||
|
||||
compressedDataOffset = sizeof(Header); |
||||
decompressedSize = header->decompressedSize; |
||||
} else { |
||||
decompressedAssets->projectMajorVersion = PROJECT_VERSION_V2; |
||||
decompressedAssets->projectMinorVersion = 0; |
||||
decompressedAssets->assetsType = ASSETS_TYPE_RESOURCE; |
||||
|
||||
compressedDataOffset = 4; |
||||
decompressedSize = header->tag; |
||||
} |
||||
|
||||
// disable warning: offsetof within non-standard-layout type ... is conditionally-supported [-Winvalid-offsetof]
|
||||
#ifdef __GNUC__ |
||||
#pragma GCC diagnostic push |
||||
#pragma GCC diagnostic ignored "-Winvalid-offsetof" |
||||
#endif |
||||
|
||||
auto decompressedDataOffset = offsetof(Assets, settings); |
||||
|
||||
#ifdef __GNUC__ |
||||
#pragma GCC diagnostic pop |
||||
#endif |
||||
|
||||
|
||||
if (decompressedDataOffset + decompressedSize > maxDecompressedAssetsSize) { |
||||
if (err) { |
||||
*err = SCPI_ERROR_OUT_OF_DEVICE_MEMORY; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
int compressedSize = assetsDataSize - compressedDataOffset; |
||||
|
||||
int decompressResult = LZ4_decompress_safe( |
||||
(const char *)(assetsData + compressedDataOffset), |
||||
(char *)decompressedAssets + decompressedDataOffset, |
||||
compressedSize, |
||||
decompressedSize |
||||
); |
||||
|
||||
if (decompressResult != (int)decompressedSize) { |
||||
if (err) { |
||||
*err = SCPI_ERROR_INVALID_BLOCK_DATA; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
if (decompressedAssets->projectMajorVersion >= PROJECT_VERSION_V3) { |
||||
fixOffsets(decompressedAssets); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void loadMainAssets(const uint8_t *assets, uint32_t assetsSize) { |
||||
g_mainAssets = (Assets *)DECOMPRESSED_ASSETS_START_ADDRESS; |
||||
g_mainAssets->external = false; |
||||
auto decompressedSize = decompressAssetsData(assets, assetsSize, g_mainAssets, MAX_DECOMPRESSED_ASSETS_SIZE, nullptr); |
||||
assert(decompressedSize); |
||||
g_isMainAssetsLoaded = true; |
||||
} |
||||
|
||||
void unloadExternalAssets() { |
||||
if (g_externalAssets) { |
||||
removeExternalPagesFromTheStack(); |
||||
|
||||
free(g_externalAssets); |
||||
g_externalAssets = nullptr; |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const PageAsset* getPageAsset(int pageId) { |
||||
if (pageId > 0) { |
||||
return g_mainAssets->pages[pageId - 1]; |
||||
} else if (pageId < 0) { |
||||
if (g_externalAssets == nullptr) { |
||||
return nullptr; |
||||
} |
||||
return g_externalAssets->pages[-pageId - 1]; |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
const PageAsset* getPageAsset(int pageId, WidgetCursor& widgetCursor) { |
||||
if (pageId < 0) { |
||||
widgetCursor.assets = g_externalAssets; |
||||
widgetCursor.flowState = flow::getFlowState(g_externalAssets, -pageId - 1, widgetCursor); |
||||
} else { |
||||
widgetCursor.assets = g_mainAssets; |
||||
if (g_mainAssets->flowDefinition) { |
||||
widgetCursor.flowState = flow::getFlowState(g_mainAssets, pageId - 1, widgetCursor); |
||||
} |
||||
} |
||||
return getPageAsset(pageId); |
||||
} |
||||
|
||||
const Style *getStyle(int styleID) { |
||||
if (styleID > 0) { |
||||
return g_mainAssets->styles[styleID - 1]; |
||||
} else if (styleID < 0) { |
||||
if (g_externalAssets == nullptr) { |
||||
return getStyle(STYLE_ID_DEFAULT); |
||||
} |
||||
return g_externalAssets->styles[-styleID - 1]; |
||||
} |
||||
return getStyle(STYLE_ID_DEFAULT); |
||||
} |
||||
|
||||
const FontData *getFontData(int fontID) { |
||||
if (fontID > 0) { |
||||
return g_mainAssets->fonts[fontID - 1]; |
||||
} else if (fontID < 0) { |
||||
if (g_externalAssets == nullptr) { |
||||
return nullptr; |
||||
} |
||||
return g_externalAssets->fonts[-fontID - 1]; |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
const Bitmap *getBitmap(int bitmapID) { |
||||
if (bitmapID > 0) { |
||||
return g_mainAssets->bitmaps[bitmapID - 1]; |
||||
} else if (bitmapID < 0) { |
||||
if (g_externalAssets == nullptr) { |
||||
return nullptr; |
||||
} |
||||
return g_externalAssets->bitmaps[-bitmapID - 1]; |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
int getThemesCount() { |
||||
return (int)g_mainAssets->colorsDefinition->themes.count; |
||||
} |
||||
|
||||
Theme *getTheme(int i) { |
||||
return g_mainAssets->colorsDefinition->themes[i]; |
||||
} |
||||
|
||||
const char *getThemeName(int i) { |
||||
return static_cast<const char *>(getTheme(i)->name); |
||||
} |
||||
|
||||
const uint32_t getThemeColorsCount(int themeIndex) { |
||||
return getTheme(themeIndex)->colors.count; |
||||
} |
||||
|
||||
const uint16_t *getThemeColors(int themeIndex) { |
||||
return static_cast<uint16_t *>(getTheme(themeIndex)->colors.items); |
||||
} |
||||
|
||||
const uint16_t *getColors() { |
||||
return static_cast<uint16_t *>(g_mainAssets->colorsDefinition->colors.items); |
||||
} |
||||
|
||||
int getExternalAssetsMainPageId() { |
||||
return -1; |
||||
} |
||||
|
||||
const char *getActionName(const WidgetCursor &widgetCursor, int16_t actionId) { |
||||
if (actionId == 0) { |
||||
return nullptr; |
||||
} |
||||
|
||||
if (actionId < 0) { |
||||
actionId = -actionId; |
||||
} |
||||
actionId--; |
||||
|
||||
if (!widgetCursor.assets) { |
||||
return ""; |
||||
} |
||||
|
||||
return widgetCursor.assets->actionNames[actionId]; |
||||
} |
||||
|
||||
int16_t getDataIdFromName(const WidgetCursor &widgetCursor, const char *name) { |
||||
if (!widgetCursor.assets) { |
||||
return 0; |
||||
} |
||||
|
||||
for (uint32_t i = 0; i < widgetCursor.assets->variableNames.count; i++) { |
||||
if (strcmp(widgetCursor.assets->variableNames[i], name) == 0) { |
||||
return -((int16_t)i + 1); |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,493 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <eez/gui/data.h> |
||||
#include <eez/gui/widget.h> |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
|
||||
static const uint32_t HEADER_TAG = 0x7A65657E; |
||||
|
||||
static const uint8_t PROJECT_VERSION_V2 = 2; |
||||
static const uint8_t PROJECT_VERSION_V3 = 3; |
||||
|
||||
static const uint8_t ASSETS_TYPE_FIRMWARE = 1; |
||||
static const uint8_t ASSETS_TYPE_FIRMWARE_MODULE = 2; |
||||
static const uint8_t ASSETS_TYPE_RESOURCE = 3; |
||||
static const uint8_t ASSETS_TYPE_APPLET = 4; |
||||
static const uint8_t ASSETS_TYPE_DASHBOARD = 5; |
||||
|
||||
struct Header { |
||||
uint32_t tag; // HEADER_TAG
|
||||
uint8_t projectMajorVersion; |
||||
uint8_t projectMinorVersion; |
||||
uint8_t assetsType; |
||||
uint8_t reserved; |
||||
uint32_t decompressedSize; |
||||
}; |
||||
|
||||
extern bool g_isMainAssetsLoaded; |
||||
extern Assets *g_mainAssets; |
||||
extern Assets *g_externalAssets; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* This template is used (on 64-bit systems) to pack asset pointers into 32-bit values.
|
||||
* All pointers are relative to MEMORY_BEGIN. |
||||
* This way, the assets created by Studio can be used without having to fix all |
||||
* the sizes - Studio creates 32-bit pointers that are relative to the |
||||
* beginning of the assets, which the firmware rewrites to global pointers |
||||
* during initialization. On a 32-bit system this works just fine, but for a |
||||
* 64-bit system the pointers have different sizes and this breaks. By |
||||
* inserting a 'middleman' structure that stores the pointers as a 32-bit |
||||
* offset to MEMORY_BEGIN, we can keep the pointer sizes and initialization |
||||
* code the same. |
||||
*/ |
||||
template<typename T> |
||||
struct AssetsPtrImpl { |
||||
/* Conversion to a T pointer */ |
||||
operator T*() { return ptr(); } |
||||
operator const T*() const { return ptr(); } |
||||
/* Dereferencing operators */ |
||||
T* operator->() { return ptr(); } |
||||
const T* operator->() const { return ptr(); } |
||||
|
||||
void operator=(T* ptr) { |
||||
if (ptr != nullptr) { |
||||
offset = (uint8_t *)ptr - MEMORY_BEGIN; |
||||
} else { |
||||
offset = 0; |
||||
} |
||||
} |
||||
|
||||
uint32_t offset = 0; |
||||
|
||||
private: |
||||
T* ptr() { |
||||
return offset ? (T *)(MEMORY_BEGIN + offset) : nullptr; |
||||
} |
||||
|
||||
const T* ptr() const { |
||||
return offset ? (const T *)(MEMORY_BEGIN + offset) : nullptr; |
||||
} |
||||
}; |
||||
|
||||
/* This struct chooses the type used for AssetsPtr<T> - by default it uses an AssetsPtrImpl<> */ |
||||
template<typename T, uint32_t ptrSize> |
||||
struct AssetsPtrChooser |
||||
{ |
||||
using type = AssetsPtrImpl<T>; |
||||
}; |
||||
|
||||
/* On 32-bit systems, we can just use raw pointers */ |
||||
template<typename T> |
||||
struct AssetsPtrChooser<T, 4> |
||||
{ |
||||
using type = T*; |
||||
}; |
||||
|
||||
/* Utility typedef that delegates to AssetsPtrChooser */ |
||||
template<typename T> |
||||
using AssetsPtr = typename AssetsPtrChooser<T, sizeof(void*)>::type; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T> |
||||
struct ListOfAssetsPtr { |
||||
/* Array access */ |
||||
T* operator[](uint32_t i) { return item(i); } |
||||
const T* operator[](uint32_t i) const { return item(i); } |
||||
|
||||
uint32_t count = 0; |
||||
AssetsPtr<AssetsPtr<T>> items; |
||||
|
||||
private: |
||||
T* item(int i) { |
||||
return static_cast<T *>(static_cast<AssetsPtr<T> *>(items)[i]); |
||||
} |
||||
|
||||
const T* item(int i) const { |
||||
return static_cast<const T *>(static_cast<const AssetsPtr<T> *>(items)[i]); |
||||
} |
||||
}; |
||||
|
||||
template<typename T> |
||||
struct ListOfFundamentalType { |
||||
/* Array access */ |
||||
T& operator[](uint32_t i) { return ptr()[i]; } |
||||
const T& operator[](uint32_t i) const { return ptr()[i]; } |
||||
|
||||
uint32_t count; |
||||
AssetsPtr<T> items; |
||||
|
||||
private: |
||||
T *ptr() { |
||||
return static_cast<T *>(items); |
||||
} |
||||
}; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Settings { |
||||
uint16_t displayWidth; |
||||
uint16_t displayHeight; |
||||
}; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define WIDGET_FLAG_PIN_TO_LEFT (1 << 0) |
||||
#define WIDGET_FLAG_PIN_TO_RIGHT (1 << 1) |
||||
#define WIDGET_FLAG_PIN_TO_TOP (1 << 2) |
||||
#define WIDGET_FLAG_PIN_TO_BOTTOM (1 << 3) |
||||
|
||||
#define WIDGET_FLAG_FIX_WIDTH (1 << 4) |
||||
#define WIDGET_FLAG_FIX_HEIGHT (1 << 5) |
||||
|
||||
#define WIDGET_TIMELINE_PROPERTY_X (1 << 0) |
||||
#define WIDGET_TIMELINE_PROPERTY_Y (1 << 1) |
||||
#define WIDGET_TIMELINE_PROPERTY_WIDTH (1 << 2) |
||||
#define WIDGET_TIMELINE_PROPERTY_HEIGHT (1 << 3) |
||||
#define WIDGET_TIMELINE_PROPERTY_OPACITY (1 << 4) |
||||
|
||||
#define EASING_FUNC_LINEAR 0 |
||||
#define EASING_FUNC_IN_QUAD 1 |
||||
#define EASING_FUNC_OUT_QUAD 2 |
||||
#define EASING_FUNC_IN_OUT_QUAD 3 |
||||
#define EASING_FUNC_IN_CUBIC 4 |
||||
#define EASING_FUNC_OUT_CUBIC 5 |
||||
#define EASING_FUNC_IN_OUT_CUBIC 6 |
||||
#define EASING_FUNC_IN__QUART 7 |
||||
#define EASING_FUNC_OUT_QUART 8 |
||||
#define EASING_FUNC_IN_OUT_QUART 9 |
||||
#define EASING_FUNC_IN_QUINT 10 |
||||
#define EASING_FUNC_OUT_QUINT 11 |
||||
#define EASING_FUNC_IN_OUT_QUINT 12 |
||||
#define EASING_FUNC_IN_SINE 13 |
||||
#define EASING_FUNC_OUT_SINE 14 |
||||
#define EASING_FUNC_IN_OUT_SINE 15 |
||||
#define EASING_FUNC_IN_EXPO 16 |
||||
#define EASING_FUNC_OUT_EXPO 17 |
||||
#define EASING_FUNC_IN_OUT_EXPO 18 |
||||
#define EASING_FUNC_IN_CIRC 19 |
||||
#define EASING_FUNC_OUT_CIRC 20 |
||||
#define EASING_FUNC_IN_OUT_CIRC 21 |
||||
#define EASING_FUNC_IN_BACK 22 |
||||
#define EASING_FUNC_OUT_BACK 23 |
||||
#define EASING_FUNC_IN_OUT_BACK 24 |
||||
#define EASING_FUNC_IN_ELASTIC 25 |
||||
#define EASING_FUNC_OUT_ELASTIC 26 |
||||
#define EASING_FUNC_IN_OUT_ELASTIC 27 |
||||
#define EASING_FUNC_IN_BOUNCE 28 |
||||
#define EASING_FUNC_OUT_BOUNCE 29 |
||||
#define EASING_FUNC_IN_OUT_BOUNCE 30 |
||||
|
||||
struct TimelineKeyframe { |
||||
float start; |
||||
float end; |
||||
|
||||
uint32_t enabledProperties; |
||||
|
||||
int16_t x; |
||||
int16_t y; |
||||
int16_t width; |
||||
int16_t height; |
||||
float opacity; |
||||
|
||||
uint8_t xEasingFunc; |
||||
uint8_t yEasingFunc; |
||||
uint8_t widthEasingFunc; |
||||
uint8_t heightEasingFunc; |
||||
uint8_t opacityEasingFunc; |
||||
|
||||
uint8_t reserved1; |
||||
uint8_t reserved2; |
||||
uint8_t reserved3; |
||||
}; |
||||
|
||||
struct Widget { |
||||
uint16_t type; |
||||
int16_t data; |
||||
int16_t visible; |
||||
int16_t action; |
||||
int16_t x; |
||||
int16_t y; |
||||
int16_t width; |
||||
int16_t height; |
||||
int16_t style; |
||||
uint16_t flags; |
||||
ListOfAssetsPtr<TimelineKeyframe> timeline; |
||||
}; |
||||
|
||||
#define SHADOW_FLAG (1 << 0) |
||||
#define CLOSE_PAGE_IF_TOUCHED_OUTSIDE_FLAG (1 << 1) |
||||
#define PAGE_IS_USED_AS_CUSTOM_WIDGET (1 << 2) |
||||
#define PAGE_CONTAINER (1 << 3) |
||||
#define PAGE_SCALE_TO_FIT (1 << 4) |
||||
|
||||
struct PageAsset : public Widget { |
||||
ListOfAssetsPtr<Widget> widgets; |
||||
uint16_t flags; |
||||
int16_t overlay; |
||||
}; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define STYLE_FLAGS_HORZ_ALIGN_MASK 0x7 |
||||
#define STYLE_FLAGS_HORZ_ALIGN_LEFT 0 |
||||
#define STYLE_FLAGS_HORZ_ALIGN_RIGHT 1 |
||||
#define STYLE_FLAGS_HORZ_ALIGN_CENTER 2 |
||||
|
||||
#define STYLE_FLAGS_VERT_ALIGN_MASK (0x7 << 3) |
||||
#define STYLE_FLAGS_VERT_ALIGN_TOP (0 << 3) |
||||
#define STYLE_FLAGS_VERT_ALIGN_BOTTOM (1 << 3) |
||||
#define STYLE_FLAGS_VERT_ALIGN_CENTER (2 << 3) |
||||
|
||||
#define STYLE_FLAGS_BLINK (1 << 6) |
||||
|
||||
struct Style { |
||||
uint16_t flags; // STYLE_FLAGS_...
|
||||
|
||||
uint16_t backgroundColor; |
||||
uint16_t color; |
||||
|
||||
uint16_t activeBackgroundColor; |
||||
uint16_t activeColor; |
||||
|
||||
uint16_t focusBackgroundColor; |
||||
uint16_t focusColor; |
||||
|
||||
uint8_t borderSizeTop; |
||||
uint8_t borderSizeRight; |
||||
uint8_t borderSizeBottom; |
||||
uint8_t borderSizeLeft; |
||||
|
||||
uint16_t borderColor; |
||||
|
||||
uint8_t borderRadiusTLX; |
||||
uint8_t borderRadiusTLY; |
||||
uint8_t borderRadiusTRX; |
||||
uint8_t borderRadiusTRY; |
||||
uint8_t borderRadiusBLX; |
||||
uint8_t borderRadiusBLY; |
||||
uint8_t borderRadiusBRX; |
||||
uint8_t borderRadiusBRY; |
||||
|
||||
uint8_t font; |
||||
uint8_t opacity; // 0 - 255
|
||||
|
||||
uint8_t paddingTop; |
||||
uint8_t paddingRight; |
||||
uint8_t paddingBottom; |
||||
uint8_t paddingLeft; |
||||
|
||||
int16_t backgroundImage; |
||||
}; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct GlyphData { |
||||
int8_t dx; // DWIDTH (-128 indicated empty glyph)
|
||||
uint8_t width; // BBX width
|
||||
uint8_t height; // BBX height
|
||||
int8_t x; // BBX xoffset
|
||||
int8_t y; // BBX yoffset
|
||||
uint8_t reserved1; |
||||
uint8_t reserved2; |
||||
uint8_t reserved3; |
||||
uint8_t pixels[1]; |
||||
}; |
||||
|
||||
struct GlyphsGroup { |
||||
uint32_t encoding; |
||||
uint32_t glyphIndex; |
||||
uint32_t length; |
||||
}; |
||||
|
||||
struct FontData { |
||||
uint8_t ascent; |
||||
uint8_t descent; |
||||
uint8_t reserved1; |
||||
uint8_t reserved2; |
||||
uint32_t encodingStart; |
||||
uint32_t encodingEnd; |
||||
ListOfAssetsPtr<GlyphsGroup> groups; |
||||
ListOfAssetsPtr<GlyphData> glyphs; |
||||
}; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Bitmap { |
||||
int16_t w; |
||||
int16_t h; |
||||
int16_t bpp; |
||||
int16_t reserved; |
||||
const uint8_t pixels[1]; |
||||
}; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Theme { |
||||
AssetsPtr<const char> name; |
||||
ListOfFundamentalType<uint16_t> colors; |
||||
}; |
||||
|
||||
struct Colors { |
||||
ListOfAssetsPtr<Theme> themes; |
||||
ListOfFundamentalType<uint16_t> colors; |
||||
}; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const uint16_t EXPR_EVAL_INSTRUCTION_TYPE_MASK = 0x0007 << 13; |
||||
static const uint16_t EXPR_EVAL_INSTRUCTION_PARAM_MASK = 0xFFFF >> 3; |
||||
|
||||
static const uint16_t EXPR_EVAL_INSTRUCTION_TYPE_PUSH_CONSTANT = (0 << 13); |
||||
static const uint16_t EXPR_EVAL_INSTRUCTION_TYPE_PUSH_INPUT = (1 << 13); |
||||
static const uint16_t EXPR_EVAL_INSTRUCTION_TYPE_PUSH_LOCAL_VAR = (2 << 13); |
||||
static const uint16_t EXPR_EVAL_INSTRUCTION_TYPE_PUSH_GLOBAL_VAR = (3 << 13); |
||||
static const uint16_t EXPR_EVAL_INSTRUCTION_TYPE_PUSH_OUTPUT = (4 << 13); |
||||
static const uint16_t EXPR_EVAL_INSTRUCTION_ARRAY_ELEMENT = (5 << 13); |
||||
static const uint16_t EXPR_EVAL_INSTRUCTION_TYPE_OPERATION = (6 << 13); |
||||
static const uint16_t EXPR_EVAL_INSTRUCTION_TYPE_END = (7 << 13); |
||||
|
||||
struct Property { |
||||
uint8_t evalInstructions[1]; |
||||
}; |
||||
|
||||
struct Connection { |
||||
uint16_t targetComponentIndex; |
||||
uint16_t targetInputIndex; |
||||
}; |
||||
|
||||
struct ComponentOutput { |
||||
ListOfAssetsPtr<Connection> connections; |
||||
uint32_t isSeqOut; |
||||
}; |
||||
|
||||
static const uint16_t BREAKPOINT_ENABLED = 1; |
||||
static const uint16_t BREAKPOINT_DISABLED = 2; |
||||
|
||||
struct Component { |
||||
uint16_t type; |
||||
uint16_t breakpoint; |
||||
|
||||
// These are indexes to Flow::componentInputs.
|
||||
// We use this to check if component is ready to run (i.e. all mandatory inputs have a value).
|
||||
ListOfFundamentalType<uint16_t> inputs; |
||||
|
||||
ListOfAssetsPtr<Property> properties; |
||||
ListOfAssetsPtr<ComponentOutput> outputs; |
||||
int16_t errorCatchOutput; |
||||
uint16_t reserved; |
||||
}; |
||||
|
||||
struct WidgetDataItem { |
||||
int16_t componentIndex; |
||||
int16_t propertyValueIndex; |
||||
}; |
||||
|
||||
struct WidgetActionItem { |
||||
int16_t componentIndex; |
||||
int16_t componentOutputIndex; |
||||
}; |
||||
|
||||
#define COMPONENT_INPUT_FLAG_IS_SEQ_INPUT (1 << 0) |
||||
#define COMPONENT_INPUT_FLAG_IS_OPTIONAL (1 << 1) |
||||
typedef uint8_t ComponentInput; |
||||
|
||||
struct Flow { |
||||
ListOfAssetsPtr<Component> components; |
||||
ListOfAssetsPtr<Value> localVariables; |
||||
|
||||
// List of all component inputs of all components in this flow
|
||||
// When flow state is created we reserve this many Value's in memory
|
||||
// to keep the latest value of component input.
|
||||
ListOfFundamentalType<ComponentInput> componentInputs; |
||||
|
||||
ListOfAssetsPtr<WidgetDataItem> widgetDataItems; |
||||
ListOfAssetsPtr<WidgetActionItem> widgetActions; |
||||
}; |
||||
|
||||
struct FlowDefinition { |
||||
ListOfAssetsPtr<Flow> flows; |
||||
ListOfAssetsPtr<Value> constants; |
||||
ListOfAssetsPtr<Value> globalVariables; |
||||
}; |
||||
|
||||
struct Language { |
||||
AssetsPtr<const char> languageID; |
||||
ListOfAssetsPtr<const char> translations; |
||||
}; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Assets { |
||||
uint8_t projectMajorVersion; |
||||
uint8_t projectMinorVersion; |
||||
uint8_t assetsType; |
||||
uint8_t external; |
||||
|
||||
AssetsPtr<Settings> settings; |
||||
ListOfAssetsPtr<PageAsset> pages; |
||||
ListOfAssetsPtr<Style> styles; |
||||
ListOfAssetsPtr<FontData> fonts; |
||||
ListOfAssetsPtr<Bitmap> bitmaps; |
||||
AssetsPtr<Colors> colorsDefinition; |
||||
ListOfAssetsPtr<const char> actionNames; |
||||
ListOfAssetsPtr<const char> variableNames; |
||||
AssetsPtr<FlowDefinition> flowDefinition; |
||||
ListOfAssetsPtr<Language> languages; |
||||
}; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool decompressAssetsData(const uint8_t *assetsData, uint32_t assetsDataSize, Assets *decompressedAssets, uint32_t maxDecompressedAssetsSize, int *err); |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void loadMainAssets(const uint8_t *assets, uint32_t assetsSize); |
||||
bool loadExternalAssets(const char *filePath, int *err); |
||||
void unloadExternalAssets(); |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const PageAsset *getPageAsset(int pageId); |
||||
const PageAsset* getPageAsset(int pageId, WidgetCursor& widgetCursor); |
||||
|
||||
const Style *getStyle(int styleID); |
||||
const FontData *getFontData(int fontID); |
||||
const Bitmap *getBitmap(int bitmapID); |
||||
|
||||
int getThemesCount(); |
||||
const char *getThemeName(int i); |
||||
const uint32_t getThemeColorsCount(int themeIndex); |
||||
const uint16_t *getThemeColors(int themeIndex); |
||||
const uint16_t *getColors(); |
||||
|
||||
int getExternalAssetsMainPageId(); |
||||
|
||||
const char *getActionName(const WidgetCursor &widgetCursor, int16_t actionId); |
||||
int16_t getDataIdFromName(const WidgetCursor &widgetCursor, const char *name); |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,275 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/gui/assets.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
|
||||
#include <eez/gui/widgets/containers/container.h> |
||||
#include <eez/gui/widgets/containers/grid.h> |
||||
#include <eez/gui/widgets/containers/list.h> |
||||
#include <eez/gui/widgets/containers/select.h> |
||||
|
||||
#include <eez/gui/widgets/button.h> |
||||
#include <eez/gui/widgets/multiline_text.h> |
||||
#include <eez/gui/widgets/scroll_bar.h> |
||||
#include <eez/gui/widgets/text.h> |
||||
#include <eez/gui/widgets/toggle_button.h> |
||||
#include <eez/gui/widgets/up_down.h> |
||||
|
||||
#include <eez/flow/flow_defs_v3.h> |
||||
#include <eez/flow/components/switch.h> |
||||
#include <eez/flow/components/set_variable.h> |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
|
||||
template<typename T> |
||||
void fixOffset(AssetsPtrImpl<T> &ptr, void *assets) { |
||||
if (ptr.offset) { |
||||
ptr.offset += (uint8_t *)assets + 4 - MEMORY_BEGIN; |
||||
} |
||||
} |
||||
|
||||
template<typename T> |
||||
void fixOffset(T *&ptr, Assets *assets) { |
||||
if (ptr) { |
||||
ptr = reinterpret_cast<T *>((uint8_t *)ptr + (uint32_t)assets + 4); |
||||
} |
||||
} |
||||
|
||||
template<typename T> |
||||
void fixOffset(ListOfAssetsPtr<T> &list, Assets *assets) { |
||||
fixOffset(list.items, assets); |
||||
AssetsPtr<T> *items = (AssetsPtr<T> *)list.items; |
||||
for (uint32_t i = 0; i < list.count; i++) { |
||||
fixOffset(items[i], assets); |
||||
} |
||||
} |
||||
|
||||
template<typename T> |
||||
void fixOffset(ListOfFundamentalType<T> &list, Assets *assets) { |
||||
fixOffset(list.items, assets); |
||||
} |
||||
|
||||
void fixOffsets(Assets *assets, ListOfAssetsPtr<Widget> &widgets); |
||||
void fixOffsets(Assets *assets, Widget *widget); |
||||
void fixOffsets(Assets *assets, ListOfAssetsPtr<Value> &values); |
||||
void fixOffsets(Assets *assets, ListOfAssetsPtr<Language> &languages); |
||||
void fixOffsets(Assets *assets, Value &value); |
||||
|
||||
void fixOffsets(Assets *assets) { |
||||
fixOffset(assets->settings, assets); |
||||
|
||||
fixOffset(assets->pages, assets); |
||||
for (uint32_t i = 0; i < assets->pages.count; i++) { |
||||
fixOffsets(assets, assets->pages[i]->widgets); |
||||
} |
||||
|
||||
fixOffset(assets->styles, assets); |
||||
|
||||
fixOffset(assets->fonts, assets); |
||||
for (uint32_t i = 0; i < assets->fonts.count; i++) { |
||||
auto font = assets->fonts[i]; |
||||
fixOffset(font->groups, assets); |
||||
fixOffset(font->glyphs, assets); |
||||
} |
||||
|
||||
fixOffset(assets->bitmaps, assets); |
||||
|
||||
if (assets->colorsDefinition) { |
||||
fixOffset(assets->colorsDefinition, assets); |
||||
auto colorsDefinition = static_cast<Colors *>(assets->colorsDefinition); |
||||
auto &themes = colorsDefinition->themes; |
||||
fixOffset(themes, assets); |
||||
for (uint32_t i = 0; i < themes.count; i++) { |
||||
auto theme = themes[i]; |
||||
fixOffset(theme->name, assets); |
||||
fixOffset(theme->colors, assets); |
||||
} |
||||
fixOffset(colorsDefinition->colors, assets); |
||||
} |
||||
|
||||
fixOffset(assets->actionNames, assets); |
||||
|
||||
fixOffset(assets->variableNames, assets); |
||||
|
||||
if (assets->flowDefinition) { |
||||
fixOffset(assets->flowDefinition, assets); |
||||
auto flowDefinition = static_cast<FlowDefinition *>(assets->flowDefinition); |
||||
|
||||
fixOffset(flowDefinition->flows, assets); |
||||
for (uint32_t i = 0; i < flowDefinition->flows.count; i++) { |
||||
auto flow = flowDefinition->flows[i]; |
||||
|
||||
fixOffset(flow->components, assets); |
||||
for (uint32_t i = 0; i < flow->components.count; i++) { |
||||
auto component = flow->components[i]; |
||||
|
||||
using namespace eez::flow; |
||||
using namespace eez::flow::defs_v3; |
||||
|
||||
switch (component->type) { |
||||
case COMPONENT_TYPE_SWITCH_ACTION: |
||||
fixOffset(((SwitchActionComponent *)component)->tests, assets); |
||||
break; |
||||
case COMPONENT_TYPE_SET_VARIABLE_ACTION: |
||||
{ |
||||
auto setVariableActionComponent = (SetVariableActionComponent *)component; |
||||
fixOffset(setVariableActionComponent->entries, assets); |
||||
for (uint32_t entryIndex = 0; entryIndex < setVariableActionComponent->entries.count; entryIndex++) { |
||||
auto entry = setVariableActionComponent->entries[entryIndex]; |
||||
fixOffset(entry->variable, assets); |
||||
fixOffset(entry->value, assets); |
||||
} |
||||
} |
||||
break; |
||||
} |
||||
|
||||
fixOffset(component->inputs, assets); |
||||
fixOffset(component->properties, assets); |
||||
|
||||
fixOffset(component->outputs, assets); |
||||
for (uint32_t i = 0; i < component->outputs.count; i++) { |
||||
auto componentOutput = component->outputs[i]; |
||||
fixOffset(componentOutput->connections, assets); |
||||
} |
||||
} |
||||
|
||||
fixOffsets(assets, flow->localVariables); |
||||
fixOffset(flow->componentInputs, assets); |
||||
fixOffset(flow->widgetDataItems, assets); |
||||
fixOffset(flow->widgetActions, assets); |
||||
} |
||||
|
||||
fixOffsets(assets, flowDefinition->constants); |
||||
fixOffsets(assets, flowDefinition->globalVariables); |
||||
} |
||||
|
||||
fixOffsets(assets, assets->languages); |
||||
} |
||||
|
||||
void fixOffsets(Assets *assets, ListOfAssetsPtr<Widget> &widgets) { |
||||
fixOffset(widgets, assets); |
||||
for (uint32_t i = 0; i < widgets.count; i++) { |
||||
fixOffsets(assets, widgets[i]); |
||||
} |
||||
} |
||||
|
||||
void fixOffsets(Assets *assets, Widget *widget) { |
||||
fixOffset(widget->timeline, assets); |
||||
|
||||
switch (widget->type) { |
||||
case WIDGET_TYPE_CONTAINER: |
||||
fixOffsets(assets, ((ContainerWidget *)widget)->widgets); |
||||
break; |
||||
case WIDGET_TYPE_GRID: |
||||
{ |
||||
auto gridWidget = (GridWidget *)widget; |
||||
if (gridWidget->itemWidget) { |
||||
fixOffset(gridWidget->itemWidget, assets); |
||||
fixOffsets(assets, static_cast<Widget *>(gridWidget->itemWidget)); |
||||
} |
||||
} |
||||
break; |
||||
case WIDGET_TYPE_LIST: |
||||
{ |
||||
auto listWidget = (ListWidget *)widget; |
||||
if (listWidget->itemWidget) { |
||||
fixOffset(listWidget->itemWidget, assets); |
||||
fixOffsets(assets, static_cast<Widget *>(listWidget->itemWidget)); |
||||
} |
||||
} |
||||
break; |
||||
case WIDGET_TYPE_SELECT: |
||||
fixOffsets(assets, ((SelectWidget *)widget)->widgets); |
||||
break; |
||||
case WIDGET_TYPE_BUTTON: |
||||
fixOffset(((ButtonWidget*)widget)->text, assets); |
||||
break; |
||||
case WIDGET_TYPE_MULTILINE_TEXT: |
||||
fixOffset(((MultilineTextWidget*)widget)->text, assets); |
||||
break; |
||||
case WIDGET_TYPE_SCROLL_BAR: |
||||
fixOffset(((ScrollBarWidget*)widget)->leftButtonText, assets); |
||||
fixOffset(((ScrollBarWidget*)widget)->rightButtonText, assets); |
||||
break; |
||||
case WIDGET_TYPE_TEXT: |
||||
fixOffset(((TextWidget*)widget)->text, assets); |
||||
break; |
||||
case WIDGET_TYPE_TOGGLE_BUTTON: |
||||
fixOffset(((ToggleButtonWidget*)widget)->text1, assets); |
||||
fixOffset(((ToggleButtonWidget*)widget)->text2, assets); |
||||
break; |
||||
case WIDGET_TYPE_UP_DOWN: |
||||
fixOffset(((UpDownWidget*)widget)->downButtonText, assets); |
||||
fixOffset(((UpDownWidget*)widget)->upButtonText, assets); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void fixOffsets(Assets *assets, ListOfAssetsPtr<Value> &values) { |
||||
fixOffset(values, assets); |
||||
|
||||
for (uint32_t i = 0; i < values.count; i++) { |
||||
auto value = values[i]; |
||||
fixOffsets(assets, *value); |
||||
} |
||||
} |
||||
|
||||
void fixOffsets(Assets *assets, ListOfAssetsPtr<Language> &languages) { |
||||
fixOffset(languages, assets); |
||||
|
||||
for (uint32_t i = 0; i < languages.count; i++) { |
||||
auto language = languages[i]; |
||||
fixOffset(language->languageID, assets); |
||||
fixOffset(language->translations, assets); |
||||
} |
||||
} |
||||
|
||||
void fixOffsets(Assets *assets, Value &value) { |
||||
if (value.getType() == VALUE_TYPE_STRING) { |
||||
AssetsPtr<const char> assetsPtr; |
||||
|
||||
#if _WIN64 || __x86_64__ || __ppc64__ |
||||
assetsPtr.offset = value.uint32Value; |
||||
#else |
||||
assetsPtr = (const char *)value.uint32Value; |
||||
#endif |
||||
|
||||
fixOffset(assetsPtr, assets); |
||||
value.strValue = (const char *)assetsPtr; |
||||
} else if (value.getType() == VALUE_TYPE_ARRAY) { |
||||
AssetsPtr<ArrayValue> assetsPtr; |
||||
|
||||
#if _WIN64 || __x86_64__ || __ppc64__ |
||||
assetsPtr.offset = value.uint32Value; |
||||
#else |
||||
assetsPtr = (ArrayValue *)value.uint32Value; |
||||
#endif |
||||
|
||||
fixOffset(assetsPtr, assets); |
||||
value.arrayValue = (eez::gui::ArrayValue *)(assetsPtr); |
||||
for (uint32_t i = 0; i < value.arrayValue->arraySize; i++) { |
||||
fixOffsets(assets, value.arrayValue->values[i]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,761 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <assert.h> |
||||
#include <stdio.h> |
||||
#include <stdint.h> |
||||
#include <math.h> |
||||
#include <memory.h> |
||||
#include <cstring> |
||||
|
||||
#include <eez/core/step_values.h> |
||||
|
||||
#include <eez/core/unit.h> |
||||
#include <eez/core/alloc.h> |
||||
#include <eez/core/util.h> |
||||
#include <eez/gui/event.h> |
||||
#include <eez/core/value_types.h> |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AppContext; |
||||
struct WidgetCursor; |
||||
struct Style; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct EnumItem { |
||||
uint16_t value; |
||||
const char *menuLabel; |
||||
const char *widgetLabel; |
||||
}; |
||||
|
||||
extern const EnumItem *g_enumDefinitions[]; |
||||
extern volatile int g_set_pin_status; |
||||
|
||||
struct EnumValue { |
||||
uint16_t enumValue; |
||||
uint16_t enumDefinition; |
||||
}; |
||||
|
||||
const char *getWidgetLabel(EnumItem *enumDefinition, uint16_t value); |
||||
|
||||
extern WidgetCursor g_widgetCursor; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define VALUE_OPTIONS_REF (1 << 0) |
||||
|
||||
#define STRING_OPTIONS_FILE_ELLIPSIS (1 << 1) |
||||
|
||||
#define FLOAT_OPTIONS_LESS_THEN (1 << 1) |
||||
#define FLOAT_OPTIONS_FIXED_DECIMALS (1 << 2) |
||||
#define FLOAT_OPTIONS_GET_NUM_FIXED_DECIMALS(options) (((options) >> 3) & 0b111) |
||||
#define FLOAT_OPTIONS_SET_NUM_FIXED_DECIMALS(n) (FLOAT_OPTIONS_FIXED_DECIMALS | ((n & 0b111) << 3)) |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Value; |
||||
|
||||
Value get(const WidgetCursor &widgetCursor, int16_t id); |
||||
|
||||
typedef bool (*CompareValueFunction)(const Value &a, const Value &b); |
||||
typedef void (*ValueToTextFunction)(const Value &value, char *text, int count); |
||||
typedef const char * (*ValueTypeNameFunction)(const Value &value); |
||||
typedef void (*CopyValueFunction)(Value &a, const Value &b); |
||||
|
||||
extern CompareValueFunction g_valueTypeCompareFunctions[]; |
||||
extern ValueToTextFunction g_valueTypeToTextFunctions[]; |
||||
extern ValueTypeNameFunction g_valueTypeNames[]; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct PairOfUint8Value { |
||||
uint8_t first; |
||||
uint8_t second; |
||||
}; |
||||
|
||||
struct PairOfUint16Value { |
||||
uint16_t first; |
||||
uint16_t second; |
||||
}; |
||||
|
||||
struct PairOfInt16Value { |
||||
int16_t first; |
||||
int16_t second; |
||||
}; |
||||
|
||||
struct Ref { |
||||
uint32_t refCounter; |
||||
virtual ~Ref() {} |
||||
}; |
||||
|
||||
struct ArrayValue; |
||||
struct ArrayElementValue; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Value { |
||||
public: |
||||
Value() |
||||
: type(VALUE_TYPE_UNDEFINED), unit(UNIT_UNKNOWN), options(0), uint64Value(0) |
||||
{ |
||||
} |
||||
|
||||
Value(int value) |
||||
: type(VALUE_TYPE_INT32), unit(UNIT_UNKNOWN), options(0), int32Value(value) |
||||
{ |
||||
} |
||||
|
||||
Value(const char *str) |
||||
: type(VALUE_TYPE_STRING), unit(UNIT_UNKNOWN), options(0), strValue(str) |
||||
{ |
||||
} |
||||
|
||||
Value(uint8_t version, const char *str) |
||||
: type(VALUE_TYPE_VERSIONED_STRING), unit(version), options(0), strValue(str) |
||||
{ |
||||
} |
||||
|
||||
Value(Value *pValue) |
||||
: type(VALUE_TYPE_VALUE_PTR), unit(UNIT_UNKNOWN), options(0), pValueValue(pValue) |
||||
{ |
||||
// if (pValue->options & VALUE_OPTIONS_REF) {
|
||||
// pValue->refValue->refCounter++;
|
||||
// }
|
||||
} |
||||
|
||||
Value(const char *str, ValueType type) |
||||
: type(type), unit(UNIT_UNKNOWN), options(0), strValue(str) |
||||
{ |
||||
} |
||||
|
||||
Value(int value, ValueType type) |
||||
: type(type), unit(UNIT_UNKNOWN), options(0), int32Value(value) |
||||
{ |
||||
} |
||||
|
||||
Value(int value, ValueType type, uint16_t options) |
||||
: type(type), unit(UNIT_UNKNOWN), options(options), int32Value(value) |
||||
{ |
||||
} |
||||
|
||||
Value(int8_t value, ValueType type) |
||||
: type(type), unit(UNIT_UNKNOWN), options(0), int8Value(value) |
||||
{ |
||||
} |
||||
|
||||
Value(uint8_t value, ValueType type) |
||||
: type(type), unit(UNIT_UNKNOWN), options(0), uint8Value(value) |
||||
{ |
||||
} |
||||
|
||||
Value(int16_t value, ValueType type) |
||||
: type(type), unit(UNIT_UNKNOWN), options(0), int16Value(value) |
||||
{ |
||||
} |
||||
|
||||
Value(uint16_t value, ValueType type) |
||||
: type(type), unit(UNIT_UNKNOWN), options(0), uint16Value(value) |
||||
{ |
||||
} |
||||
|
||||
Value(uint32_t value, ValueType type) |
||||
: type(type), unit(UNIT_UNKNOWN), options(0), uint32Value(value) |
||||
{ |
||||
} |
||||
|
||||
Value(int64_t value, ValueType type) |
||||
: type(type), unit(UNIT_UNKNOWN), options(0), int64Value(value) |
||||
{ |
||||
} |
||||
|
||||
Value(uint64_t value, ValueType type) |
||||
: type(type), unit(UNIT_UNKNOWN), options(0), uint64Value(value) |
||||
{ |
||||
} |
||||
|
||||
Value(float value, Unit unit) |
||||
: type(VALUE_TYPE_FLOAT), unit(unit), options(0), floatValue(value) |
||||
{ |
||||
} |
||||
|
||||
Value(float value, Unit unit, uint16_t options) |
||||
: type(VALUE_TYPE_FLOAT), unit(unit), options(options), floatValue(value) |
||||
{ |
||||
} |
||||
|
||||
Value(float value, ValueType type) |
||||
: type(type), unit(UNIT_UNKNOWN), options(0), floatValue(value) |
||||
{ |
||||
} |
||||
|
||||
Value(double value, ValueType type) |
||||
: type(type), unit(UNIT_UNKNOWN), options(0), doubleValue(value) { |
||||
} |
||||
|
||||
Value(const char *value, ValueType type, uint16_t options) |
||||
: type(type), unit(UNIT_UNKNOWN), options(options), strValue(value) |
||||
{ |
||||
} |
||||
|
||||
Value(void *value, ValueType type) |
||||
: type(type), unit(UNIT_UNKNOWN), options(0), pVoidValue(value) |
||||
{ |
||||
} |
||||
|
||||
Value(AppContext *appContext) |
||||
: type(VALUE_TYPE_POINTER), unit(UNIT_UNKNOWN), options(0), pVoidValue(appContext) |
||||
{ |
||||
} |
||||
|
||||
typedef float (*YtDataGetValueFunctionPointer)(uint32_t rowIndex, uint8_t columnIndex, float *max); |
||||
|
||||
Value(YtDataGetValueFunctionPointer ytDataGetValueFunctionPointer) |
||||
: type(VALUE_TYPE_YT_DATA_GET_VALUE_FUNCTION_POINTER), unit(UNIT_UNKNOWN), options(0), pVoidValue((void *)ytDataGetValueFunctionPointer) |
||||
{ |
||||
} |
||||
|
||||
Value(const Value& value) |
||||
: type(VALUE_TYPE_UNDEFINED), unit(UNIT_UNKNOWN), options(0), uint64Value(0) |
||||
{ |
||||
*this = value; |
||||
} |
||||
|
||||
~Value() { |
||||
freeRef(); |
||||
} |
||||
|
||||
void freeRef() { |
||||
if (options & VALUE_OPTIONS_REF) { |
||||
if (--refValue->refCounter == 0) { |
||||
ObjectAllocator<Ref>::deallocate(refValue); |
||||
} |
||||
}/* else if (type == VALUE_TYPE_VALUE_PTR) {
|
||||
if (pValueValue->options & VALUE_OPTIONS_REF) { |
||||
if (--pValueValue->refValue->refCounter == 0) { |
||||
ObjectAllocator<Ref>::deallocate(pValueValue->refValue); |
||||
} |
||||
} |
||||
}*/ |
||||
} |
||||
|
||||
Value& operator = (const Value &value) { |
||||
freeRef(); |
||||
|
||||
type = value.type; |
||||
unit = value.unit; |
||||
options = value.options; |
||||
memcpy((void *)&int64Value, (const void *)&value.int64Value, sizeof(int64_t)); |
||||
|
||||
if (options & VALUE_OPTIONS_REF) { |
||||
refValue->refCounter++; |
||||
}/* else if (type == VALUE_TYPE_VALUE_PTR) {
|
||||
if (pValueValue->options & VALUE_OPTIONS_REF) { |
||||
pValueValue->refValue->refCounter++; |
||||
} |
||||
}*/ |
||||
|
||||
return *this; |
||||
} |
||||
|
||||
bool operator==(const Value &other) const { |
||||
return type == other.type && g_valueTypeCompareFunctions[type](*this, other); |
||||
} |
||||
|
||||
|
||||
bool operator!=(const Value &other) const { |
||||
return !(*this == other); |
||||
} |
||||
|
||||
ValueType getType() const { |
||||
return (ValueType)type; |
||||
} |
||||
|
||||
Value getValue() const; |
||||
|
||||
bool isInt32OrLess() const { |
||||
return (type >= VALUE_TYPE_INT8 && type <= VALUE_TYPE_UINT32) || type == VALUE_TYPE_BOOLEAN; |
||||
} |
||||
|
||||
bool isInt64() const { |
||||
return type == VALUE_TYPE_INT64 || type == VALUE_TYPE_UINT64; |
||||
} |
||||
|
||||
bool isInt32() const { |
||||
return type == VALUE_TYPE_INT32 || type == VALUE_TYPE_UINT32; |
||||
} |
||||
|
||||
bool isInt16() const { |
||||
return type == VALUE_TYPE_INT16 || type == VALUE_TYPE_UINT16; |
||||
} |
||||
|
||||
bool isInt8() const { |
||||
return type == VALUE_TYPE_INT8 || type == VALUE_TYPE_UINT8; |
||||
} |
||||
|
||||
bool isFloat() const { |
||||
return type == VALUE_TYPE_FLOAT; |
||||
} |
||||
|
||||
bool isDouble() const { |
||||
return type == VALUE_TYPE_DOUBLE; |
||||
} |
||||
|
||||
bool isBoolean() const { |
||||
return type == VALUE_TYPE_BOOLEAN; |
||||
} |
||||
|
||||
bool isString() const { |
||||
return type == VALUE_TYPE_STRING; |
||||
} |
||||
|
||||
bool isAnyStringType() const { |
||||
return type == VALUE_TYPE_STRING || type == VALUE_TYPE_STRING_REF; |
||||
} |
||||
|
||||
Unit getUnit() const { |
||||
return (Unit)unit; |
||||
} |
||||
|
||||
bool getBoolean() const { |
||||
return int32Value; |
||||
} |
||||
|
||||
int8_t getInt8() const { |
||||
return int8Value; |
||||
} |
||||
|
||||
uint8_t getUInt8() const { |
||||
return uint8Value; |
||||
} |
||||
|
||||
int16_t getInt16() const { |
||||
return int16Value; |
||||
} |
||||
|
||||
uint16_t getUInt16() const { |
||||
return uint16Value; |
||||
} |
||||
|
||||
int32_t getInt32() const { |
||||
return int32Value; |
||||
} |
||||
|
||||
uint32_t getUInt32() const { |
||||
return uint32Value; |
||||
} |
||||
|
||||
int64_t getInt64() const { |
||||
return int64Value; |
||||
} |
||||
|
||||
uint32_t getUInt64() const { |
||||
return uint64Value; |
||||
} |
||||
|
||||
float getFloat() const { |
||||
return floatValue; |
||||
} |
||||
|
||||
double getDouble() const { |
||||
return doubleValue; |
||||
} |
||||
|
||||
const char *getString() const; |
||||
|
||||
const ArrayValue *getArray() const; |
||||
ArrayValue *getArray(); |
||||
|
||||
//////////
|
||||
|
||||
int getInt() const { |
||||
if (type == VALUE_TYPE_ENUM) { |
||||
return enumValue.enumValue; |
||||
} |
||||
return int32Value; |
||||
} |
||||
|
||||
const EnumValue &getEnum() const { |
||||
return enumValue; |
||||
} |
||||
|
||||
int16_t getScpiError() const { |
||||
return int16Value; |
||||
} |
||||
|
||||
uint8_t *getPUint8() const { |
||||
return puint8Value; |
||||
} |
||||
|
||||
StepValues *getStepValues() const { |
||||
return (StepValues *)pVoidValue; |
||||
} |
||||
|
||||
float *getFloatList() const { |
||||
return pFloatValue; |
||||
} |
||||
|
||||
void *getVoidPointer() const { |
||||
return pVoidValue; |
||||
} |
||||
|
||||
AppContext *getAppContext() const { |
||||
return (AppContext *)pVoidValue; |
||||
} |
||||
|
||||
YtDataGetValueFunctionPointer getYtDataGetValueFunctionPointer() const { |
||||
return (YtDataGetValueFunctionPointer)pVoidValue; |
||||
} |
||||
|
||||
uint8_t getFirstUInt8() const { |
||||
return pairOfUint8Value.first; |
||||
} |
||||
uint8_t getSecondUInt8() const { |
||||
return pairOfUint8Value.second; |
||||
} |
||||
|
||||
uint16_t getFirstUInt16() const { |
||||
return pairOfUint16Value.first; |
||||
} |
||||
uint16_t getSecondUInt16() const { |
||||
return pairOfUint16Value.second; |
||||
} |
||||
|
||||
int16_t getFirstInt16() const { |
||||
return pairOfInt16Value.first; |
||||
} |
||||
int16_t getSecondInt16() const { |
||||
return pairOfInt16Value.second; |
||||
} |
||||
|
||||
void toText(char *text, int count) const { |
||||
*text = 0; |
||||
g_valueTypeToTextFunctions[type](*this, text, count); |
||||
} |
||||
|
||||
uint16_t getOptions() const { |
||||
return options; |
||||
} |
||||
|
||||
uint16_t getRangeFrom() { |
||||
return pairOfUint16Value.first; |
||||
} |
||||
|
||||
uint16_t getRangeTo() { |
||||
return pairOfUint16Value.second; |
||||
} |
||||
|
||||
double toDouble(int *err = nullptr) const; |
||||
float toFloat(int *err = nullptr) const; |
||||
int32_t toInt32(int *err = nullptr) const; |
||||
int64_t toInt64(int *err = nullptr) const; |
||||
bool toBool(int *err = nullptr) const; |
||||
|
||||
Value toString(uint32_t id) const; |
||||
|
||||
static Value makeStringRef(const char *str, int len, uint32_t id); |
||||
static Value concatenateString(const Value &str1, const Value &str2); |
||||
|
||||
static Value makeArrayRef(int arraySize, int arrayType, uint32_t id); |
||||
static Value makeArrayElementRef(Value arrayValue, int elementIndex, uint32_t id); |
||||
|
||||
static Value makeBlobRef(const uint8_t *blob, uint32_t len, uint32_t id); |
||||
|
||||
//////////
|
||||
|
||||
public: |
||||
uint8_t type; |
||||
uint8_t unit; |
||||
uint16_t options; |
||||
uint32_t reserved; |
||||
|
||||
union { |
||||
int8_t int8Value; |
||||
uint8_t uint8Value; |
||||
int16_t int16Value; |
||||
uint16_t uint16Value; |
||||
int32_t int32Value; |
||||
uint32_t uint32Value; |
||||
int64_t int64Value; |
||||
uint64_t uint64Value; |
||||
|
||||
float floatValue; |
||||
double doubleValue; |
||||
|
||||
const char *strValue; |
||||
ArrayValue *arrayValue; |
||||
Ref *refValue; |
||||
|
||||
uint8_t *puint8Value; |
||||
float *pFloatValue; |
||||
void *pVoidValue; |
||||
Value *pValueValue; |
||||
|
||||
EnumValue enumValue; |
||||
|
||||
PairOfUint8Value pairOfUint8Value; |
||||
PairOfUint16Value pairOfUint16Value; |
||||
PairOfInt16Value pairOfInt16Value; |
||||
}; |
||||
}; |
||||
|
||||
struct StringRef : public Ref { |
||||
~StringRef() { |
||||
if (str) { |
||||
eez::free(str); |
||||
} |
||||
} |
||||
char *str; |
||||
}; |
||||
|
||||
struct ArrayValue { |
||||
uint32_t arraySize; |
||||
uint32_t arrayType; |
||||
Value values[1]; |
||||
}; |
||||
|
||||
struct ArrayValueRef : public Ref { |
||||
~ArrayValueRef(); |
||||
ArrayValue arrayValue; |
||||
}; |
||||
|
||||
struct BlobRef : public Ref { |
||||
~BlobRef() { |
||||
if (blob) { |
||||
eez::free(blob); |
||||
} |
||||
} |
||||
uint8_t *blob; |
||||
uint32_t len; |
||||
}; |
||||
|
||||
struct ArrayElementValue : public Ref { |
||||
Value arrayValue; |
||||
int elementIndex; |
||||
}; |
||||
|
||||
inline Value Value::getValue() const { |
||||
if (type == VALUE_TYPE_VALUE_PTR) { |
||||
return *pValueValue; |
||||
} |
||||
if (type == VALUE_TYPE_NATIVE_VARIABLE) { |
||||
return get(g_widgetCursor, int32Value); |
||||
} |
||||
if (type == VALUE_TYPE_ARRAY_ELEMENT_VALUE) { |
||||
auto arrayElementValue = (ArrayElementValue *)refValue; |
||||
auto array = arrayElementValue->arrayValue.getArray(); |
||||
return array->values[arrayElementValue->elementIndex]; |
||||
} |
||||
return *this; |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool assignValue(Value &dstValue, const Value &srcValue); |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint16_t getPageIndexFromValue(const Value &value); |
||||
uint16_t getNumPagesFromValue(const Value &value); |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Value MakeRangeValue(uint16_t from, uint16_t to); |
||||
Value MakeEnumDefinitionValue(uint8_t enumValue, uint8_t enumDefinition); |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum DataOperationEnum { |
||||
DATA_OPERATION_GET, |
||||
DATA_OPERATION_GET_DISPLAY_VALUE_RANGE, |
||||
DATA_OPERATION_GET_EDIT_VALUE, |
||||
DATA_OPERATION_GET_ALLOW_ZERO, |
||||
DATA_OPERATION_GET_MIN, |
||||
DATA_OPERATION_GET_MAX, |
||||
DATA_OPERATION_GET_DEF, |
||||
DATA_OPERATION_GET_PRECISION, |
||||
DATA_OPERATION_GET_LIMIT, |
||||
DATA_OPERATION_GET_NAME, |
||||
DATA_OPERATION_GET_UNIT, |
||||
DATA_OPERATION_GET_IS_CHANNEL_DATA, |
||||
DATA_OPERATION_GET_ENCODER_STEP_VALUES, |
||||
DATA_OPERATION_SET_ENCODER_MODE, |
||||
DATA_OPERATION_GET_ENCODER_RANGE_AND_STEP, |
||||
DATA_OPERATION_GET_FLOAT_LIST_LENGTH, |
||||
DATA_OPERATION_GET_FLOAT_LIST, |
||||
DATA_OPERATION_GET_BITMAP_IMAGE, |
||||
DATA_OPERATION_GET_VALUE, |
||||
DATA_OPERATION_GET_LABEL, |
||||
DATA_OPERATION_GET_OVERLAY_DATA, |
||||
DATA_OPERATION_UPDATE_OVERLAY_DATA, |
||||
DATA_OPERATION_COUNT, |
||||
DATA_OPERATION_GET_CURSOR_VALUE, |
||||
DATA_OPERATION_SELECT, |
||||
DATA_OPERATION_DESELECT, |
||||
DATA_OPERATION_GET_CONTEXT, |
||||
DATA_OPERATION_SET_CONTEXT, |
||||
DATA_OPERATION_GET_CONTEXT_CURSOR, |
||||
DATA_OPERATION_RESTORE_CONTEXT, |
||||
DATA_OPERATION_GET_TEXT_REFRESH_RATE, |
||||
DATA_OPERATION_GET_COLOR, |
||||
DATA_OPERATION_GET_BACKGROUND_COLOR, |
||||
DATA_OPERATION_GET_ACTIVE_COLOR, |
||||
DATA_OPERATION_GET_ACTIVE_BACKGROUND_COLOR, |
||||
DATA_OPERATION_IS_BLINKING, |
||||
DATA_OPERATION_IS_VALID_VALUE, |
||||
DATA_OPERATION_SET, |
||||
DATA_OPERATION_YT_DATA_GET_REFRESH_COUNTER, |
||||
DATA_OPERATION_YT_DATA_GET_SIZE, |
||||
DATA_OPERATION_YT_DATA_GET_POSITION, |
||||
DATA_OPERATION_YT_DATA_SET_POSITION, |
||||
DATA_OPERATION_YT_DATA_GET_POSITION_INCREMENT, |
||||
DATA_OPERATION_YT_DATA_GET_PAGE_SIZE, |
||||
DATA_OPERATION_YT_DATA_GET_STYLE, |
||||
DATA_OPERATION_YT_DATA_GET_MIN, |
||||
DATA_OPERATION_YT_DATA_GET_MAX, |
||||
DATA_OPERATION_YT_DATA_GET_HORZ_DIVISIONS, |
||||
DATA_OPERATION_YT_DATA_GET_VERT_DIVISIONS, |
||||
DATA_OPERATION_YT_DATA_GET_DIV, |
||||
DATA_OPERATION_YT_DATA_GET_OFFSET, |
||||
DATA_OPERATION_YT_DATA_VALUE_IS_VISIBLE, |
||||
DATA_OPERATION_YT_DATA_GET_SHOW_LABELS, |
||||
DATA_OPERATION_YT_DATA_GET_SELECTED_VALUE_INDEX, |
||||
DATA_OPERATION_YT_DATA_GET_LABEL, |
||||
DATA_OPERATION_YT_DATA_GET_GET_VALUE_FUNC, |
||||
DATA_OPERATION_YT_DATA_GET_GRAPH_UPDATE_METHOD, |
||||
DATA_OPERATION_YT_DATA_GET_PERIOD, |
||||
DATA_OPERATION_YT_DATA_GET_BOOKMARKS, |
||||
DATA_OPERATION_YT_DATA_IS_CURSOR_VISIBLE, |
||||
DATA_OPERATION_YT_DATA_GET_CURSOR_OFFSET, |
||||
DATA_OPERATION_YT_DATA_GET_CURSOR_X_VALUE, |
||||
DATA_OPERATION_YT_DATA_TOUCH_DRAG, |
||||
DATA_OPERATION_GET_CANVAS_REFRESH_STATE, |
||||
DATA_OPERATION_GET_TEXT_CURSOR_POSITION, |
||||
DATA_OPERATION_GET_X_SCROLL, |
||||
DATA_OPERATION_GET_SLOT_AND_SUBCHANNEL_INDEX, |
||||
DATA_OPERATION_IS_MICRO_AMPER_ALLOWED, |
||||
DATA_OPERATION_IS_AMPER_ALLOWED |
||||
}; |
||||
|
||||
int count(const WidgetCursor &widgetCursor, int16_t id); |
||||
void select(WidgetCursor &widgetCursor, int16_t id, int index, Value &oldValue); |
||||
void deselect(WidgetCursor &widgetCursor, int16_t id, Value &oldValue); |
||||
|
||||
void setContext(WidgetCursor &widgetCursor, int16_t id, Value &oldContext, Value &newContext); |
||||
void restoreContext(WidgetCursor &widgetCursor, int16_t id, Value &oldContext); |
||||
|
||||
int getFloatListLength(const WidgetCursor &widgetCursor, int16_t id); |
||||
float *getFloatList(const WidgetCursor &widgetCursor, int16_t id); |
||||
|
||||
bool getAllowZero(const WidgetCursor &widgetCursor, int16_t id); |
||||
Value getMin(const WidgetCursor &widgetCursor, int16_t id); |
||||
Value getMax(const WidgetCursor &widgetCursor, int16_t id); |
||||
Value getDef(const WidgetCursor &widgetCursor, int16_t id); |
||||
Value getPrecision(const WidgetCursor &widgetCursor, int16_t id); |
||||
Value getLimit(const WidgetCursor &widgetCursor, int16_t id); |
||||
const char *getName(const WidgetCursor &widgetCursor, int16_t id); |
||||
Unit getUnit(const WidgetCursor &widgetCursor, int16_t id); |
||||
bool isChannelData(const WidgetCursor &widgetCursor, int16_t id); |
||||
|
||||
void getLabel(const WidgetCursor &widgetCursor, int16_t id, char *text, int count); |
||||
|
||||
void getEncoderStepValues(const WidgetCursor &widgetCursor, int16_t id, StepValues &stepValues); |
||||
void setEncoderMode(const WidgetCursor &widgetCursor, int16_t id, EncoderMode encoderMode); |
||||
|
||||
Value get(const WidgetCursor &widgetCursor, int16_t id); |
||||
const char *isValidValue(const WidgetCursor &widgetCursor, int16_t id, Value value); |
||||
Value set(const WidgetCursor &widgetCursor, int16_t id, Value value); |
||||
|
||||
Value getDisplayValueRange(const WidgetCursor &widgetCursor, int16_t id); |
||||
|
||||
uint32_t getTextRefreshRate(const WidgetCursor &widgetCursor, int16_t id); |
||||
|
||||
uint16_t getColor(const WidgetCursor &widgetCursor, int16_t id, const Style *style); |
||||
uint16_t getBackgroundColor(const WidgetCursor &widgetCursor, int16_t id, const Style *style); |
||||
uint16_t getActiveColor(const WidgetCursor &widgetCursor, int16_t id, const Style *style); |
||||
uint16_t getActiveBackgroundColor(const WidgetCursor &widgetCursor, int16_t id, const Style *style); |
||||
|
||||
bool isBlinking(const WidgetCursor &widgetCursor, int16_t id); |
||||
Value getEditValue(const WidgetCursor &widgetCursor, int16_t id); |
||||
|
||||
Value getBitmapImage(const WidgetCursor &widgetCursor, int16_t id); |
||||
|
||||
uint32_t ytDataGetRefreshCounter(const WidgetCursor &widgetCursor, int16_t id); |
||||
uint32_t ytDataGetSize(const WidgetCursor &widgetCursor, int16_t id); |
||||
uint32_t ytDataGetPosition(const WidgetCursor &widgetCursor, int16_t id); |
||||
void ytDataSetPosition(const WidgetCursor &widgetCursor, int16_t id, uint32_t newPosition); |
||||
uint32_t ytDataGetPositionIncrement(const WidgetCursor &widgetCursor, int16_t id); |
||||
uint32_t ytDataGetPageSize(const WidgetCursor &widgetCursor, int16_t id); |
||||
const Style *ytDataGetStyle(const WidgetCursor &widgetCursor, int16_t id, uint8_t valueIndex); |
||||
Value ytDataGetMin(const WidgetCursor &widgetCursor, int16_t id, uint8_t valueIndex); |
||||
Value ytDataGetMax(const WidgetCursor &widgetCursor, int16_t id, uint8_t valueIndex); |
||||
int ytDataGetVertDivisions(const WidgetCursor &widgetCursor, int16_t id); |
||||
int ytDataGetHorzDivisions(const WidgetCursor &widgetCursor, int16_t id); |
||||
float ytDataGetDiv(const WidgetCursor &widgetCursor, int16_t id, uint8_t valueIndex); |
||||
float ytDataGetOffset(const WidgetCursor &widgetCursor, int16_t id, uint8_t valueIndex); |
||||
bool ytDataDataValueIsVisible(const WidgetCursor &widgetCursor, int16_t id, uint8_t valueIndex); |
||||
bool ytDataGetShowLabels(const WidgetCursor &widgetCursor, int16_t id); |
||||
int8_t ytDataGetSelectedValueIndex(const WidgetCursor &widgetCursor, int16_t id); |
||||
struct YtDataGetLabelParams { |
||||
uint8_t valueIndex; |
||||
char *text; |
||||
int count; |
||||
}; |
||||
void ytDataGetLabel(const WidgetCursor &widgetCursor, int16_t id, uint8_t valueIndex, char *text, int count); |
||||
Value::YtDataGetValueFunctionPointer ytDataGetGetValueFunc(const WidgetCursor &widgetCursor, int16_t id); |
||||
uint8_t ytDataGetGraphUpdateMethod(const WidgetCursor &widgetCursor, int16_t id); |
||||
float ytDataGetPeriod(const WidgetCursor &widgetCursor, int16_t id); |
||||
uint8_t *ytDataGetBookmarks(const WidgetCursor &widgetCursor, int16_t id); |
||||
bool ytDataIsCursorVisible(const WidgetCursor &widgetCursor, int16_t id); |
||||
uint32_t ytDataGetCursorOffset(const WidgetCursor &widgetCursor, int16_t id); |
||||
Value ytDataGetCursorXValue(const WidgetCursor &widgetCursor, int16_t id); |
||||
|
||||
struct TouchDrag { |
||||
const WidgetCursor &widgetCursor; |
||||
EventType type; |
||||
int x; |
||||
int y; |
||||
}; |
||||
void ytDataTouchDrag(const WidgetCursor &widgetCursor, int16_t id, TouchDrag *touchDrag); |
||||
|
||||
int getTextCursorPosition(const WidgetCursor &widgetCursor, int16_t id); |
||||
int getXScroll(const WidgetCursor &widgetCursor); |
||||
|
||||
void getSlotAndSubchannelIndex(const WidgetCursor &widgetCursor, int16_t id, int &slotIndex, int &subchannelIndex); |
||||
|
||||
bool isMicroAmperAllowed(const WidgetCursor &widgetCursor, int16_t id); |
||||
bool isAmperAllowed(const WidgetCursor &widgetCursor, int16_t id); |
||||
|
||||
typedef void (*CanvasDrawFunction)(const WidgetCursor &widgetCursor); |
||||
CanvasDrawFunction getCanvasDrawFunction(const WidgetCursor &widgetCursor, int16_t id); |
||||
Value getCanvasRefreshState(const WidgetCursor &widgetCursor, int16_t id); |
||||
|
||||
typedef void(*DataOperationsFunction)(DataOperationEnum operation, const WidgetCursor &widgetCursor, Value &value); |
||||
extern DataOperationsFunction g_dataOperationsFunctions[]; |
||||
|
||||
typedef void (*ActionExecFunc)(); |
||||
extern ActionExecFunc g_actionExecFunctions[]; |
||||
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,94 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include <eez/gui/font.h> |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
namespace display { |
||||
|
||||
void initDriver(); |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
typedef uint16_t *VideoBuffer; |
||||
#endif |
||||
#if defined(EEZ_PLATFORM_SIMULATOR) |
||||
typedef uint32_t *VideoBuffer; |
||||
#endif |
||||
|
||||
enum DisplayState { |
||||
OFF, |
||||
TURNING_ON, |
||||
ON, |
||||
TURNING_OFF |
||||
}; |
||||
|
||||
extern DisplayState g_displayState; |
||||
|
||||
extern VideoBuffer g_syncedBuffer; |
||||
void syncBuffer(); |
||||
|
||||
void copySyncedBufferToScreenshotBuffer(); |
||||
|
||||
extern uint16_t g_fc, g_bc; |
||||
extern uint8_t g_opacity; |
||||
|
||||
extern gui::font::Font g_font; |
||||
|
||||
void drawStrInit(); |
||||
void drawGlyph(const uint8_t *src, uint32_t srcLineOffset, int x, int y, int width, int height); |
||||
|
||||
static const int NUM_BUFFERS = 6; |
||||
|
||||
struct RenderBuffer { |
||||
VideoBuffer bufferPointer; |
||||
VideoBuffer previousBuffer; |
||||
int x; |
||||
int y; |
||||
int width; |
||||
int height; |
||||
bool withShadow; |
||||
uint8_t opacity; |
||||
int xOffset; |
||||
int yOffset; |
||||
gui::Rect *backdrop; |
||||
}; |
||||
extern RenderBuffer g_renderBuffers[NUM_BUFFERS]; |
||||
|
||||
void setBufferPointer(VideoBuffer buffer); |
||||
|
||||
extern bool g_dirty; |
||||
inline void clearDirty() { g_dirty = false; } |
||||
inline void setDirty() { g_dirty = true; } |
||||
inline bool isDirty() { return g_dirty; } |
||||
|
||||
extern bool g_screenshotAllocated; |
||||
|
||||
#ifdef GUI_CALC_FPS |
||||
static const size_t NUM_FPS_VALUES = 60; |
||||
extern uint32_t g_fpsValues[NUM_FPS_VALUES]; |
||||
void calcFPS(); |
||||
#endif |
||||
|
||||
} // namespace display
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,987 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <memory.h> |
||||
|
||||
#include <eez/core/utf8.h> |
||||
|
||||
#include <eez/conf.h> |
||||
#include <eez/core/util.h> |
||||
|
||||
#if OPTION_KEYBOARD |
||||
#include <eez/core/keyboard.h> |
||||
#endif |
||||
|
||||
#if OPTION_MOUSE |
||||
#include <eez/core/mouse.h> |
||||
#endif |
||||
|
||||
#include <eez/gui/gui.h> |
||||
#include <eez/gui/thread.h> |
||||
|
||||
#include <eez/gui/display-private.h> |
||||
|
||||
#define CONF_BACKDROP_OPACITY 128 |
||||
|
||||
using namespace eez::gui; |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
namespace display { |
||||
|
||||
DisplayState g_displayState; |
||||
|
||||
VideoBuffer g_renderBuffer1; |
||||
VideoBuffer g_renderBuffer2; |
||||
|
||||
VideoBuffer g_animationBuffer1; |
||||
VideoBuffer g_animationBuffer2; |
||||
|
||||
VideoBuffer g_syncedBuffer; |
||||
VideoBuffer g_renderBuffer; |
||||
VideoBuffer g_animationBuffer; |
||||
|
||||
bool g_takeScreenshot; |
||||
|
||||
uint16_t g_fc, g_bc; |
||||
uint8_t g_opacity = 255; |
||||
|
||||
gui::font::Font g_font; |
||||
|
||||
static uint8_t g_colorCache[256][4]; |
||||
|
||||
#define FLOAT_TO_COLOR_COMPONENT(F) ((F) < 0 ? 0 : (F) > 255 ? 255 : (uint8_t)(F)) |
||||
#define RGB_TO_HIGH_BYTE(R, G, B) (((R) & 248) | (G) >> 5) |
||||
#define RGB_TO_LOW_BYTE(R, G, B) (((G) & 28) << 3 | (B) >> 3) |
||||
|
||||
static const uint16_t *g_themeColors; |
||||
static uint32_t g_themeColorsCount; |
||||
static const uint16_t *g_colors; |
||||
|
||||
bool g_dirty; |
||||
|
||||
RenderBuffer g_renderBuffers[NUM_BUFFERS]; |
||||
static VideoBuffer g_mainBufferPointer; |
||||
static int g_numBuffersToDraw; |
||||
|
||||
bool g_screenshotAllocated; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void init() { |
||||
onLuminocityChanged(); |
||||
onThemeChanged(); |
||||
|
||||
g_renderBuffer1 = (VideoBuffer)VRAM_BUFFER1_START_ADDRESS; |
||||
g_renderBuffer2 = (VideoBuffer)VRAM_BUFFER2_START_ADDRESS; |
||||
|
||||
g_animationBuffer1 = (VideoBuffer)VRAM_ANIMATION_BUFFER1_START_ADDRESS; |
||||
g_animationBuffer2 = (VideoBuffer)VRAM_ANIMATION_BUFFER2_START_ADDRESS; |
||||
|
||||
g_renderBuffers[0].bufferPointer = (VideoBuffer)(VRAM_AUX_BUFFER1_START_ADDRESS); |
||||
g_renderBuffers[1].bufferPointer = (VideoBuffer)(VRAM_AUX_BUFFER2_START_ADDRESS); |
||||
g_renderBuffers[2].bufferPointer = (VideoBuffer)(VRAM_AUX_BUFFER3_START_ADDRESS); |
||||
g_renderBuffers[3].bufferPointer = (VideoBuffer)(VRAM_AUX_BUFFER4_START_ADDRESS); |
||||
g_renderBuffers[4].bufferPointer = (VideoBuffer)(VRAM_AUX_BUFFER5_START_ADDRESS); |
||||
g_renderBuffers[5].bufferPointer = (VideoBuffer)(VRAM_AUX_BUFFER6_START_ADDRESS); |
||||
|
||||
initDriver(); |
||||
|
||||
// start with the black screen
|
||||
setColor(0, 0, 0); |
||||
g_renderBuffer = g_renderBuffer1; |
||||
fillRect(0, 0, getDisplayWidth() - 1, getDisplayHeight() - 1); |
||||
g_renderBuffer = g_renderBuffer2; |
||||
fillRect(0, 0, getDisplayWidth() - 1, getDisplayHeight() - 1); |
||||
|
||||
g_animationBuffer = g_animationBuffer1; |
||||
|
||||
g_syncedBuffer = g_renderBuffer1; |
||||
syncBuffer(); |
||||
} |
||||
|
||||
void turnOn() { |
||||
if (g_displayState != ON && g_displayState != TURNING_ON) { |
||||
g_hooks.turnOnDisplayStart(); |
||||
} |
||||
} |
||||
|
||||
bool isOn() { |
||||
return g_displayState == ON || g_displayState == TURNING_ON; |
||||
} |
||||
|
||||
void turnOff() { |
||||
if (g_displayState != OFF && g_displayState != TURNING_OFF) { |
||||
g_hooks.turnOffDisplayStart(); |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef GUI_CALC_FPS |
||||
bool g_calcFpsEnabled; |
||||
#if defined(STYLE_ID_FPS_GRAPH) |
||||
bool g_drawFpsGraphEnabled; |
||||
#endif |
||||
uint32_t g_fpsValues[NUM_FPS_VALUES]; |
||||
uint32_t g_fpsAvg; |
||||
static uint32_t g_fpsTotal; |
||||
static uint32_t g_lastTimeFPS; |
||||
|
||||
void calcFPS() { |
||||
// calculate last FPS value
|
||||
g_fpsTotal -= g_fpsValues[0]; |
||||
|
||||
for (size_t i = 1; i < NUM_FPS_VALUES; i++) { |
||||
g_fpsValues[i - 1] = g_fpsValues[i]; |
||||
} |
||||
|
||||
uint32_t time = millis(); |
||||
auto diff = time - g_lastTimeFPS; |
||||
|
||||
auto fps = 1000 / diff; |
||||
if (fps > 60) { |
||||
fps = 60; |
||||
} |
||||
g_fpsValues[NUM_FPS_VALUES - 1] = fps; |
||||
|
||||
g_fpsTotal += g_fpsValues[NUM_FPS_VALUES - 1]; |
||||
g_fpsAvg = g_fpsTotal / NUM_FPS_VALUES; |
||||
} |
||||
|
||||
void drawFpsGraph(int x, int y, int w, int h, const Style *style) { |
||||
int x1 = x; |
||||
int y1 = y; |
||||
int x2 = x + w - 1; |
||||
int y2 = y + h - 1; |
||||
drawBorderAndBackground(x1, y1, x2, y2, style, style->backgroundColor); |
||||
|
||||
x1++; |
||||
y1++; |
||||
x2--; |
||||
y2--; |
||||
|
||||
bool isRed = false; |
||||
display::setColor(style->color); |
||||
|
||||
x = x1; |
||||
for (size_t i = 0; i < NUM_FPS_VALUES && x <= x2; i++, x++) { |
||||
int y = y2 - g_fpsValues[i] * (y2 - y1) / 60; |
||||
if (y < y1) { |
||||
y = y1; |
||||
} |
||||
|
||||
if (g_fpsValues[i] < 40) { |
||||
if (!isRed) { |
||||
display::setColor16(COLOR_RED); |
||||
isRed = true; |
||||
} |
||||
} else { |
||||
if (isRed) { |
||||
display::setColor(style->color); |
||||
isRed = false; |
||||
} |
||||
} |
||||
|
||||
display::drawVLine(x, y, y2 - y); |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void finishAnimation() { |
||||
g_animationState.enabled = false; |
||||
|
||||
if (g_renderBuffer == g_renderBuffer1) { |
||||
g_renderBuffer = g_renderBuffer2; |
||||
bitBlt(g_renderBuffer1, 0, 0, getDisplayWidth() - 1, getDisplayHeight() - 1); |
||||
} else { |
||||
g_renderBuffer = g_renderBuffer1; |
||||
bitBlt(g_renderBuffer2, 0, 0, getDisplayWidth() - 1, getDisplayHeight() - 1); |
||||
} |
||||
|
||||
g_syncedBuffer = g_renderBuffer1; |
||||
syncBuffer(); |
||||
} |
||||
|
||||
void animate(Buffer startBuffer, void (*callback)(float t, VideoBuffer bufferOld, VideoBuffer bufferNew, VideoBuffer bufferDst), float duration) { |
||||
if (g_animationState.enabled) { |
||||
display::finishAnimation(); |
||||
} |
||||
|
||||
g_animationState.enabled = true; |
||||
g_animationState.startTime = 0; |
||||
g_animationState.duration = duration != -1 ? duration : g_hooks.getDefaultAnimationDuration(); |
||||
g_animationState.startBuffer = startBuffer; |
||||
g_animationState.callback = callback; |
||||
g_animationState.easingRects = remapOutQuad; |
||||
g_animationState.easingOpacity = remapOutCubic; |
||||
} |
||||
|
||||
static void animateStep() { |
||||
uint32_t time = millis(); |
||||
if (time == 0) { |
||||
time = 1; |
||||
} |
||||
if (g_animationState.startTime == 0) { |
||||
g_animationState.startTime = time; |
||||
} |
||||
float t = (time - g_animationState.startTime) / (1000.0f * g_animationState.duration); |
||||
if (t < 1.0f) { |
||||
if (g_syncedBuffer == g_animationBuffer1) { |
||||
g_animationBuffer = g_animationBuffer2; |
||||
} else { |
||||
g_animationBuffer = g_animationBuffer1; |
||||
} |
||||
|
||||
if (g_renderBuffer == g_renderBuffer1) { |
||||
g_animationState.callback(t, g_renderBuffer2, g_renderBuffer1, g_animationBuffer); |
||||
} else { |
||||
g_animationState.callback(t, g_renderBuffer1, g_renderBuffer2, g_animationBuffer); |
||||
} |
||||
|
||||
g_syncedBuffer = g_animationBuffer; |
||||
syncBuffer(); |
||||
} else { |
||||
finishAnimation(); |
||||
} |
||||
} |
||||
|
||||
void update() { |
||||
if (g_displayState == TURNING_ON) { |
||||
g_hooks.turnOnDisplayTick(); |
||||
} else if (g_displayState == TURNING_OFF) { |
||||
g_hooks.turnOffDisplayTick(); |
||||
} else if (g_displayState == OFF) { |
||||
if (g_animationState.enabled) { |
||||
display::finishAnimation(); |
||||
} |
||||
osDelay(16); |
||||
sendMessageToGuiThread(GUI_QUEUE_MESSAGE_TYPE_DISPLAY_VSYNC, 0, 0); |
||||
return; |
||||
} |
||||
|
||||
#ifdef GUI_CALC_FPS |
||||
g_lastTimeFPS = millis(); |
||||
#endif |
||||
|
||||
display::beginRendering(); |
||||
updateScreen(); |
||||
display::endRendering(); |
||||
|
||||
#ifdef GUI_CALC_FPS |
||||
if (g_calcFpsEnabled) { |
||||
calcFPS(); |
||||
} |
||||
#endif |
||||
|
||||
if (!g_screenshotAllocated && g_animationState.enabled) { |
||||
animateStep(); |
||||
} else { |
||||
g_syncedBuffer = g_renderBuffer; |
||||
syncBuffer(); |
||||
|
||||
if (g_takeScreenshot) { |
||||
copySyncedBufferToScreenshotBuffer(); |
||||
|
||||
g_takeScreenshot = false; |
||||
g_screenshotAllocated = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
const uint8_t *takeScreenshot() { |
||||
#ifdef __EMSCRIPTEN__ |
||||
copySyncedBufferToScreenshotBuffer(); |
||||
#else |
||||
while (g_screenshotAllocated) { |
||||
} |
||||
|
||||
g_takeScreenshot = true; |
||||
|
||||
do { |
||||
osDelay(0); |
||||
} while (g_takeScreenshot); |
||||
|
||||
#endif |
||||
|
||||
return SCREENSHOOT_BUFFER_START_ADDRESS; |
||||
} |
||||
|
||||
void releaseScreenshot() { |
||||
g_screenshotAllocated = false; |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VideoBuffer getBufferPointer() { |
||||
return g_renderBuffer; |
||||
} |
||||
|
||||
void setBufferPointer(VideoBuffer buffer) { |
||||
g_renderBuffer = buffer; |
||||
} |
||||
|
||||
void beginRendering() { |
||||
if (g_syncedBuffer == g_renderBuffer1) { |
||||
g_renderBuffer = g_renderBuffer2; |
||||
} else if (g_syncedBuffer == g_renderBuffer2) { |
||||
g_renderBuffer = g_renderBuffer1; |
||||
} |
||||
|
||||
clearDirty(); |
||||
|
||||
g_mainBufferPointer = getBufferPointer(); |
||||
g_numBuffersToDraw = 0; |
||||
} |
||||
|
||||
int beginBufferRendering() { |
||||
int bufferIndex = g_numBuffersToDraw++; |
||||
g_renderBuffers[bufferIndex].previousBuffer = getBufferPointer(); |
||||
setBufferPointer(g_renderBuffers[bufferIndex].bufferPointer); |
||||
return bufferIndex; |
||||
} |
||||
|
||||
void endBufferRendering(int bufferIndex, int x, int y, int width, int height, bool withShadow, uint8_t opacity, int xOffset, int yOffset, Rect *backdrop) { |
||||
RenderBuffer &renderBuffer = g_renderBuffers[bufferIndex]; |
||||
|
||||
renderBuffer.x = x; |
||||
renderBuffer.y = y; |
||||
renderBuffer.width = width; |
||||
renderBuffer.height = height; |
||||
renderBuffer.withShadow = withShadow; |
||||
renderBuffer.opacity = opacity; |
||||
renderBuffer.xOffset = xOffset; |
||||
renderBuffer.yOffset = yOffset; |
||||
renderBuffer.backdrop = backdrop; |
||||
|
||||
setBufferPointer(renderBuffer.previousBuffer); |
||||
} |
||||
|
||||
void endRendering() { |
||||
setBufferPointer(g_mainBufferPointer); |
||||
|
||||
#if OPTION_KEYBOARD |
||||
if (keyboard::isDisplayDirty()) { |
||||
setDirty(); |
||||
} |
||||
#endif |
||||
|
||||
#if OPTION_MOUSE |
||||
if (mouse::isDisplayDirty()) { |
||||
setDirty(); |
||||
} |
||||
#endif |
||||
|
||||
#if defined(GUI_CALC_FPS) && defined(STYLE_ID_FPS_GRAPH) |
||||
if (g_drawFpsGraphEnabled) { |
||||
setDirty(); |
||||
} |
||||
#endif |
||||
|
||||
if (isDirty()) { |
||||
for (int bufferIndex = 0; bufferIndex < g_numBuffersToDraw; bufferIndex++) { |
||||
RenderBuffer &renderBuffer = g_renderBuffers[bufferIndex]; |
||||
|
||||
int sx = renderBuffer.x; |
||||
int sy = renderBuffer.y; |
||||
|
||||
int x1 = renderBuffer.x + renderBuffer.xOffset; |
||||
int y1 = renderBuffer.y + renderBuffer.yOffset; |
||||
int x2 = x1 + renderBuffer.width - 1; |
||||
int y2 = y1 + renderBuffer.height - 1; |
||||
|
||||
if (renderBuffer.backdrop) { |
||||
// opacity backdrop
|
||||
auto savedOpacity = setOpacity(CONF_BACKDROP_OPACITY); |
||||
setColor(COLOR_ID_BACKDROP); |
||||
fillRect(renderBuffer.backdrop->x, renderBuffer.backdrop->y, renderBuffer.backdrop->x + renderBuffer.backdrop->w - 1, renderBuffer.backdrop->y + renderBuffer.backdrop->h - 1); |
||||
setOpacity(savedOpacity); |
||||
} |
||||
|
||||
if (renderBuffer.withShadow) { |
||||
drawShadow(x1, y1, x2, y2); |
||||
} |
||||
|
||||
bitBlt(g_renderBuffers[bufferIndex].bufferPointer, nullptr, sx, sy, x2 - x1 + 1, y2 - y1 + 1, x1, y1, renderBuffer.opacity); |
||||
} |
||||
|
||||
#if defined(GUI_CALC_FPS) && defined(STYLE_ID_FPS_GRAPH) |
||||
if (g_drawFpsGraphEnabled) { |
||||
drawFpsGraph(getDisplayWidth() - 64 - 4, 4, 64, 32, getStyle(STYLE_ID_FPS_GRAPH)); |
||||
} |
||||
#endif |
||||
|
||||
#if OPTION_KEYBOARD |
||||
keyboard::updateDisplay(); |
||||
#endif |
||||
|
||||
#if OPTION_MOUSE |
||||
mouse::updateDisplay(); |
||||
#endif |
||||
} else { |
||||
if (g_syncedBuffer == g_renderBuffer1) { |
||||
bitBlt(g_renderBuffer1, 0, 0, getDisplayWidth() - 1, getDisplayHeight() - 1); |
||||
} else if (g_syncedBuffer == g_renderBuffer2) { |
||||
bitBlt(g_renderBuffer2, 0, 0, getDisplayWidth() - 1, getDisplayHeight() - 1); |
||||
} |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint32_t color16to32(uint16_t color, uint8_t opacity) { |
||||
uint32_t color32; |
||||
((uint8_t *)&color32)[0] = COLOR_TO_R(color); |
||||
((uint8_t *)&color32)[1] = COLOR_TO_G(color); |
||||
((uint8_t *)&color32)[2] = COLOR_TO_B(color); |
||||
((uint8_t *)&color32)[3] = opacity; |
||||
return color32; |
||||
} |
||||
|
||||
uint16_t color32to16(uint32_t color) { |
||||
auto pcolor = (uint8_t *)&color; |
||||
return RGB_TO_COLOR(pcolor[0], pcolor[1], pcolor[1]); |
||||
} |
||||
|
||||
uint32_t blendColor(uint32_t fgColor, uint32_t bgColor) { |
||||
uint8_t *fg = (uint8_t *)&fgColor; |
||||
uint8_t *bg = (uint8_t *)&bgColor; |
||||
|
||||
float alphaMult = fg[3] * bg[3] / 255.0f; |
||||
float alphaOut = fg[3] + bg[3] - alphaMult; |
||||
|
||||
float r = (fg[0] * fg[3] + bg[0] * bg[3] - bg[0] * alphaMult) / alphaOut; |
||||
float g = (fg[1] * fg[3] + bg[1] * bg[3] - bg[1] * alphaMult) / alphaOut; |
||||
float b = (fg[2] * fg[3] + bg[2] * bg[3] - bg[2] * alphaMult) / alphaOut; |
||||
|
||||
r = clamp(r, 0.0f, 255.0f); |
||||
g = clamp(g, 0.0f, 255.0f); |
||||
b = clamp(b, 0.0f, 255.0f); |
||||
|
||||
uint32_t result; |
||||
uint8_t *presult = (uint8_t *)&result; |
||||
presult[0] = (uint8_t)r; |
||||
presult[1] = (uint8_t)g; |
||||
presult[2] = (uint8_t)b; |
||||
presult[3] = (uint8_t)alphaOut; |
||||
|
||||
return result; |
||||
} |
||||
|
||||
void onThemeChanged() { |
||||
auto selectedThemeIndex = g_hooks.getSelectedThemeIndex(); |
||||
g_themeColors = getThemeColors(selectedThemeIndex); |
||||
g_themeColorsCount = getThemeColorsCount(selectedThemeIndex); |
||||
g_colors = getColors(); |
||||
} |
||||
|
||||
void onLuminocityChanged() { |
||||
// invalidate cache
|
||||
for (int i = 0; i < 256; ++i) { |
||||
g_colorCache[i][0] = 0; |
||||
g_colorCache[i][1] = 0; |
||||
g_colorCache[i][2] = 0; |
||||
g_colorCache[i][3] = 0; |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define swap(type, i, j) {type t = i; i = j; j = t;} |
||||
|
||||
void rgbToHsl(float r, float g, float b, float &h, float &s, float &l) { |
||||
r /= 255; |
||||
g /= 255; |
||||
b /= 255; |
||||
|
||||
float min = r; |
||||
float mid = g; |
||||
float max = b; |
||||
|
||||
if (min > mid) { |
||||
swap(float, min, mid); |
||||
} |
||||
if (mid > max) { |
||||
swap(float, mid, max); |
||||
} |
||||
if (min > mid) { |
||||
swap(float, min, mid); |
||||
} |
||||
|
||||
l = (max + min) / 2; |
||||
|
||||
if (max == min) { |
||||
h = s = 0; // achromatic
|
||||
} else { |
||||
float d = max - min; |
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min); |
||||
|
||||
if (max == r) { |
||||
h = (g - b) / d + (g < b ? 6 : 0); |
||||
} else if (max == g) { |
||||
h = (b - r) / d + 2; |
||||
} else if (max == b) { |
||||
h = (r - g) / d + 4; |
||||
} |
||||
|
||||
h /= 6; |
||||
} |
||||
} |
||||
|
||||
float hue2rgb(float p, float q, float t) { |
||||
if (t < 0) t += 1; |
||||
if (t > 1) t -= 1; |
||||
if (t < 1.0f/6) return p + (q - p) * 6 * t; |
||||
if (t < 1.0f/2) return q; |
||||
if (t < 2.0f/3) return p + (q - p) * (2.0f/3 - t) * 6; |
||||
return p; |
||||
} |
||||
|
||||
void hslToRgb(float h, float s, float l, float &r, float &g, float &b) { |
||||
if (s == 0) { |
||||
r = g = b = l; // achromatic
|
||||
} else { |
||||
float q = l < 0.5 ? l * (1 + s) : l + s - l * s; |
||||
float p = 2 * l - q; |
||||
|
||||
r = hue2rgb(p, q, h + 1.0f/3); |
||||
g = hue2rgb(p, q, h); |
||||
b = hue2rgb(p, q, h - 1.0f/3); |
||||
} |
||||
|
||||
r *= 255; |
||||
g *= 255; |
||||
b *= 255; |
||||
} |
||||
|
||||
void adjustColor(uint16_t &c) { |
||||
if (g_hooks.getDisplayBackgroundLuminosityStep() == DISPLAY_BACKGROUND_LUMINOSITY_STEP_DEFAULT) { |
||||
return; |
||||
} |
||||
|
||||
uint8_t ch = c >> 8; |
||||
uint8_t cl = c & 0xFF; |
||||
|
||||
int i = (ch & 0xF0) | (cl & 0x0F); |
||||
if (ch == g_colorCache[i][0] && cl == g_colorCache[i][1]) { |
||||
// cache hit!
|
||||
c = (g_colorCache[i][2] << 8) | g_colorCache[i][3]; |
||||
return; |
||||
} |
||||
|
||||
uint8_t r, g, b; |
||||
r = ch & 248; |
||||
g = ((ch << 5) | (cl >> 3)) & 252; |
||||
b = cl << 3; |
||||
|
||||
float h, s, l; |
||||
rgbToHsl(r, g, b, h, s, l); |
||||
|
||||
float a = l < 0.5 ? l : 1 - l; |
||||
if (a > 0.3f) { |
||||
a = 0.3f; |
||||
} |
||||
float lmin = l - a; |
||||
float lmax = l + a; |
||||
|
||||
float lNew = remap((float)g_hooks.getDisplayBackgroundLuminosityStep(), |
||||
(float)DISPLAY_BACKGROUND_LUMINOSITY_STEP_MIN, |
||||
lmin, |
||||
(float)DISPLAY_BACKGROUND_LUMINOSITY_STEP_MAX, |
||||
lmax); |
||||
|
||||
float floatR, floatG, floatB; |
||||
hslToRgb(h, s, lNew, floatR, floatG, floatB); |
||||
|
||||
r = FLOAT_TO_COLOR_COMPONENT(floatR); |
||||
g = FLOAT_TO_COLOR_COMPONENT(floatG); |
||||
b = FLOAT_TO_COLOR_COMPONENT(floatB); |
||||
|
||||
uint8_t chNew = RGB_TO_HIGH_BYTE(r, g, b); |
||||
uint8_t clNew = RGB_TO_LOW_BYTE(r, g, b); |
||||
|
||||
// store new color in the cache
|
||||
g_colorCache[i][0] = ch; |
||||
g_colorCache[i][1] = cl; |
||||
g_colorCache[i][2] = chNew; |
||||
g_colorCache[i][3] = clNew; |
||||
|
||||
c = (chNew << 8) | clNew; |
||||
} |
||||
|
||||
uint16_t getColor16FromIndex(uint16_t color) { |
||||
color = g_hooks.transformColor(color); |
||||
return color < g_themeColorsCount ? g_themeColors[color] : g_colors[color - g_themeColorsCount]; |
||||
} |
||||
|
||||
void setColor(uint8_t r, uint8_t g, uint8_t b) { |
||||
g_fc = RGB_TO_COLOR(r, g, b); |
||||
adjustColor(g_fc); |
||||
} |
||||
|
||||
void setColor16(uint16_t color) { |
||||
g_fc = color; |
||||
adjustColor(g_fc); |
||||
} |
||||
|
||||
void setColor(uint16_t color, bool ignoreLuminocity) { |
||||
g_fc = getColor16FromIndex(color); |
||||
if (!ignoreLuminocity) { |
||||
adjustColor(g_fc); |
||||
} |
||||
} |
||||
|
||||
uint16_t getColor() { |
||||
return g_fc; |
||||
} |
||||
|
||||
void setBackColor(uint8_t r, uint8_t g, uint8_t b) { |
||||
g_bc = RGB_TO_COLOR(r, g, b); |
||||
adjustColor(g_bc); |
||||
} |
||||
|
||||
void setBackColor(uint16_t color, bool ignoreLuminocity) { |
||||
g_bc = getColor16FromIndex(color); |
||||
if (!ignoreLuminocity) { |
||||
adjustColor(g_bc); |
||||
} |
||||
} |
||||
|
||||
uint16_t getBackColor() { |
||||
return g_bc; |
||||
} |
||||
|
||||
uint8_t setOpacity(uint8_t opacity) { |
||||
uint8_t savedOpacity = g_opacity; |
||||
g_opacity = opacity; |
||||
return savedOpacity; |
||||
} |
||||
|
||||
uint8_t getOpacity() { |
||||
return g_opacity; |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void drawHLine(int x, int y, int l) { |
||||
fillRect(x, y, x + l, y); |
||||
} |
||||
|
||||
void drawVLine(int x, int y, int l) { |
||||
fillRect(x, y, x, y + l); |
||||
} |
||||
|
||||
void drawRect(int x1, int y1, int x2, int y2) { |
||||
drawHLine(x1, y1, x2 - x1); |
||||
drawHLine(x1, y2, x2 - x1); |
||||
drawVLine(x1, y1, y2 - y1); |
||||
drawVLine(x2, y1, y2 - y1); |
||||
} |
||||
|
||||
void drawFocusFrame(int x, int y, int w, int h) { |
||||
int lineWidth = MIN(MIN(3, w), h); |
||||
|
||||
setColor16(RGB_TO_COLOR(255, 0, 255)); |
||||
|
||||
// top
|
||||
fillRect(x, y, x + w - 1, y + lineWidth - 1); |
||||
|
||||
// left
|
||||
fillRect(x, y + lineWidth, x + lineWidth - 1, y + h - lineWidth - 1); |
||||
|
||||
// right
|
||||
fillRect(x + w - lineWidth, y + lineWidth, x + w - 1, y + h - lineWidth - 1); |
||||
|
||||
// bottom
|
||||
fillRect(x, y + h - lineWidth, x + w - 1, y + h - 1); |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void aggInit(AggDrawing& aggDrawing) { |
||||
aggDrawing.rbuf.attach((uint8_t *)getBufferPointer(), getDisplayWidth(), getDisplayHeight(), getDisplayWidth() * DISPLAY_BPP / 8); |
||||
aggDrawing.graphics.attach(aggDrawing.rbuf.buf(), aggDrawing.rbuf.width(), aggDrawing.rbuf.height(), aggDrawing.rbuf.stride()); |
||||
} |
||||
|
||||
void drawRoundedRect( |
||||
AggDrawing& aggDrawing, |
||||
double x1, double y1, double x2, double y2, |
||||
double lineWidth, |
||||
double rtlx, double rtly, double rtrx, double rtry, |
||||
double rbrx, double rbry, double rblx, double rbly |
||||
) { |
||||
fillRoundedRect( |
||||
aggDrawing, |
||||
x1, y1, x2, y2, |
||||
lineWidth, |
||||
rtlx, rtly, rtrx, rtry, |
||||
rbrx, rbry, rblx, rbly, |
||||
true, false |
||||
); |
||||
} |
||||
|
||||
void fillRoundedRect( |
||||
AggDrawing& aggDrawing, |
||||
double x1, double y1, double x2, double y2, |
||||
double lineWidth, |
||||
double rtlx, double rtly, double rtrx, double rtry, |
||||
double rbrx, double rbry, double rblx, double rbly, |
||||
bool drawLine, bool fill, |
||||
double clip_x1, double clip_y1, double clip_x2, double clip_y2 |
||||
) { |
||||
auto &graphics = aggDrawing.graphics; |
||||
|
||||
if (clip_x1 != -1) { |
||||
graphics.clipBox(clip_x1, clip_y1, clip_x2 + 1, clip_y2 + 1); |
||||
} else { |
||||
graphics.clipBox(x1, y1, x2 + 1, y2 + 1); |
||||
} |
||||
graphics.masterAlpha(g_opacity / 255.0); |
||||
graphics.translate(x1, y1); |
||||
graphics.lineWidth(lineWidth); |
||||
if (lineWidth > 0 && drawLine) { |
||||
graphics.lineColor(COLOR_TO_R(g_fc), COLOR_TO_G(g_fc), COLOR_TO_B(g_fc)); |
||||
} else { |
||||
graphics.noLine(); |
||||
} |
||||
if (fill) { |
||||
graphics.fillColor(COLOR_TO_R(g_bc), COLOR_TO_G(g_bc), COLOR_TO_B(g_bc)); |
||||
} else { |
||||
graphics.noFill(); |
||||
} |
||||
auto w = x2 - x1 + 1; |
||||
auto h = y2 - y1 + 1; |
||||
graphics.roundedRect( |
||||
lineWidth / 2.0, lineWidth / 2.0, w - lineWidth, h - lineWidth, |
||||
rtlx, rtly, rtrx, rtry, rbrx, rbry, rblx, rbly |
||||
); |
||||
|
||||
graphics.translate(-x1, -y1); |
||||
graphics.clipBox(0, 0, aggDrawing.rbuf.width(), aggDrawing.rbuf.height()); |
||||
} |
||||
|
||||
void fillRoundedRect( |
||||
AggDrawing& aggDrawing, |
||||
double x1, double y1, double x2, double y2, |
||||
double lineWidth, |
||||
double r, |
||||
bool drawLine, bool fill, |
||||
double clip_x1, double clip_y1, double clip_x2, double clip_y2 |
||||
) { |
||||
fillRoundedRect(aggDrawing, x1, y1, x2, y2, lineWidth, r, r, r, r, r, r, r, r, drawLine, fill, clip_x1, clip_y1, clip_x2, clip_y2); |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int8_t measureGlyph(int32_t encoding) { |
||||
auto glyph = g_font.getGlyph(encoding); |
||||
if (!glyph) |
||||
return 0; |
||||
|
||||
return glyph->dx; |
||||
} |
||||
|
||||
int8_t measureGlyph(int32_t encoding, gui::font::Font &font) { |
||||
auto glyph = font.getGlyph(encoding); |
||||
if (!glyph) |
||||
return 0; |
||||
|
||||
return glyph->dx; |
||||
} |
||||
|
||||
int measureStr(const char *text, int textLength, gui::font::Font &font, int max_width) { |
||||
g_font = font; |
||||
|
||||
int width = 0; |
||||
|
||||
if (textLength == -1) { |
||||
while (true) { |
||||
utf8_int32_t encoding; |
||||
text = utf8codepoint(text, &encoding); |
||||
if (!encoding) { |
||||
break; |
||||
} |
||||
int glyph_width = measureGlyph(encoding); |
||||
if (max_width > 0 && width + glyph_width > max_width) { |
||||
return max_width; |
||||
} |
||||
width += glyph_width; |
||||
} |
||||
} else { |
||||
for (int i = 0; i < textLength; ++i) { |
||||
utf8_int32_t encoding; |
||||
text = utf8codepoint(text, &encoding); |
||||
if (!encoding) { |
||||
break; |
||||
} |
||||
int glyph_width = measureGlyph(encoding); |
||||
if (max_width > 0 && width + glyph_width > max_width) { |
||||
return max_width; |
||||
} |
||||
width += glyph_width; |
||||
} |
||||
} |
||||
|
||||
return width; |
||||
} |
||||
|
||||
void drawStr(const char *text, int textLength, int x, int y, int clip_x1, int clip_y1, int clip_x2, int clip_y2, gui::font::Font &font, int cursorPosition) { |
||||
g_font = font; |
||||
|
||||
drawStrInit(); |
||||
|
||||
if (textLength == -1) { |
||||
textLength = utf8len(text); |
||||
} |
||||
|
||||
int xCursor = x; |
||||
|
||||
int i; |
||||
|
||||
for (i = 0; i < textLength; ++i) { |
||||
utf8_int32_t encoding; |
||||
text = utf8codepoint(text, &encoding); |
||||
if (!encoding) { |
||||
break; |
||||
} |
||||
|
||||
if (i == cursorPosition) { |
||||
xCursor = x; |
||||
} |
||||
|
||||
auto x1 = x; |
||||
auto y1 = y; |
||||
|
||||
auto glyph = g_font.getGlyph(encoding); |
||||
if (glyph) { |
||||
int x_glyph = x1 + glyph->x; |
||||
int y_glyph = y1 + g_font.getAscent() - (glyph->y + glyph->height); |
||||
|
||||
// draw glyph pixels
|
||||
int iStartByte = 0; |
||||
if (x_glyph < clip_x1) { |
||||
int dx_off = clip_x1 - x_glyph; |
||||
iStartByte = dx_off; |
||||
x_glyph = clip_x1; |
||||
} |
||||
|
||||
if (iStartByte < glyph->width) { |
||||
int offset = 0; |
||||
int glyphHeight = glyph->height; |
||||
if (y_glyph < clip_y1) { |
||||
int dy_off = clip_y1 - y_glyph; |
||||
offset += dy_off * glyph->width; |
||||
glyphHeight -= dy_off; |
||||
y_glyph = clip_y1; |
||||
} |
||||
|
||||
int width; |
||||
if (x_glyph + (glyph->width - iStartByte) - 1 > clip_x2) { |
||||
width = clip_x2 - x_glyph + 1; |
||||
} else { |
||||
width = (glyph->width - iStartByte); |
||||
} |
||||
|
||||
int height; |
||||
if (y_glyph + glyphHeight - 1 > clip_y2) { |
||||
height = clip_y2 - y_glyph + 1; |
||||
} else { |
||||
height = glyphHeight; |
||||
} |
||||
|
||||
if (width > 0 && height > 0) { |
||||
drawGlyph(glyph->pixels + offset + iStartByte, glyph->width - width, x_glyph, y_glyph, width, height); |
||||
} |
||||
} |
||||
|
||||
x += glyph->dx; |
||||
} |
||||
} |
||||
|
||||
if (i == cursorPosition) { |
||||
xCursor = x; |
||||
} |
||||
|
||||
if (cursorPosition != -1 && xCursor - CURSOR_WIDTH / 2 >= clip_x1 && xCursor + CURSOR_WIDTH / 2 - 1 <= clip_x2) { |
||||
auto d = MAX(((clip_y2 - clip_y1) - font.getHeight()) / 2, 0); |
||||
fillRect(xCursor - CURSOR_WIDTH / 2, clip_y1 + d, xCursor + CURSOR_WIDTH / 2 - 1, clip_y2 - d); |
||||
} |
||||
|
||||
setDirty(); |
||||
} |
||||
|
||||
int getCharIndexAtPosition(int xPos, const char *text, int textLength, int x, int y, int clip_x1, int clip_y1, int clip_x2,int clip_y2, gui::font::Font &font) { |
||||
if (textLength == -1) { |
||||
textLength = utf8len(text); |
||||
} |
||||
|
||||
int i; |
||||
|
||||
for (i = 0; i < textLength; ++i) { |
||||
utf8_int32_t encoding; |
||||
text = utf8codepoint(text, &encoding); |
||||
if (!encoding) { |
||||
break; |
||||
} |
||||
|
||||
auto glyph = font.getGlyph(encoding); |
||||
auto dx = 0; |
||||
if (glyph) { |
||||
dx = glyph->dx; |
||||
} |
||||
if (xPos < x + dx / 2) { |
||||
return i; |
||||
} |
||||
x += dx; |
||||
} |
||||
|
||||
return i; |
||||
} |
||||
|
||||
int getCursorXPosition(int cursorPosition, const char *text, int textLength, int x, int y, int clip_x1, int clip_y1, int clip_x2,int clip_y2, gui::font::Font &font) { |
||||
if (textLength == -1) { |
||||
textLength = utf8len(text); |
||||
} |
||||
|
||||
for (int i = 0; i < textLength; ++i) { |
||||
utf8_int32_t encoding; |
||||
text = utf8codepoint(text, &encoding); |
||||
if (!encoding) { |
||||
break; |
||||
} |
||||
|
||||
if (i == cursorPosition) { |
||||
return x; |
||||
} |
||||
|
||||
auto glyph = font.getGlyph(encoding); |
||||
if (glyph) { |
||||
x += glyph->dx; |
||||
} |
||||
} |
||||
|
||||
return x; |
||||
} |
||||
|
||||
} // namespace display
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,180 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include <agg2d.h> |
||||
#include <agg_rendering_buffer.h> |
||||
|
||||
#if defined(EEZ_PLATFORM_STM32) |
||||
typedef uint16_t *VideoBuffer; |
||||
#endif |
||||
#if defined(EEZ_PLATFORM_SIMULATOR) |
||||
typedef uint32_t *VideoBuffer; |
||||
#endif |
||||
|
||||
#include <eez/gui/animation.h> |
||||
#include <eez/gui/font.h> |
||||
#include <eez/gui/geometry.h> |
||||
#include <eez/gui/image.h> |
||||
|
||||
static const int CURSOR_WIDTH = 2; |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
namespace display { |
||||
|
||||
#define TRANSPARENT_COLOR_INDEX 0xFFFF |
||||
|
||||
#define COLOR_BLACK 0x0000 |
||||
#define COLOR_WHITE 0xFFFF |
||||
#define COLOR_RED 0xF800 |
||||
#define COLOR_GREEN 0x0400 |
||||
#define COLOR_BLUE 0x001F |
||||
|
||||
// C: rrrrrggggggbbbbb
|
||||
#define RGB_TO_COLOR(R, G, B) (uint16_t((R)&0xF8) << 8) | (uint16_t((G)&0xFC) << 3) | (((B)&0xF8) >> 3) |
||||
|
||||
#define COLOR_TO_R(C) (uint8_t(((C) >> 11) << 3)) |
||||
#define COLOR_TO_G(C) (uint8_t((((C) >> 5) << 2) & 0xFF)) |
||||
#define COLOR_TO_B(C) (uint8_t(((C) << 3) & 0xFF)) |
||||
|
||||
extern VideoBuffer g_renderBuffer; |
||||
|
||||
void init(); |
||||
|
||||
void turnOn(); |
||||
void turnOff(); |
||||
bool isOn(); |
||||
|
||||
void onThemeChanged(); |
||||
void onLuminocityChanged(); |
||||
void updateBrightness(); |
||||
|
||||
void update(); |
||||
|
||||
void animate(Buffer startBuffer, void (*callback)(float t, VideoBuffer bufferOld, VideoBuffer bufferNew, VideoBuffer bufferDst), float duration = -1); |
||||
|
||||
void beginRendering(); |
||||
int beginBufferRendering(); |
||||
void endBufferRendering(int bufferIndex, int x, int y, int width, int height, bool withShadow, uint8_t opacity, int xOffset, int yOffset, gui::Rect *backdrop); |
||||
void endRendering(); |
||||
|
||||
VideoBuffer getBufferPointer(); |
||||
|
||||
const uint8_t *takeScreenshot(); |
||||
void releaseScreenshot(); |
||||
|
||||
#ifdef GUI_CALC_FPS |
||||
extern bool g_calcFpsEnabled; |
||||
#if defined(STYLE_ID_FPS_GRAPH) |
||||
extern bool g_drawFpsGraphEnabled; |
||||
#endif |
||||
extern uint32_t g_fpsAvg; |
||||
void drawFpsGraph(int x, int y, int w, int h, const Style *style); |
||||
#endif |
||||
|
||||
|
||||
uint32_t color16to32(uint16_t color, uint8_t opacity = 255); |
||||
uint16_t color32to16(uint32_t color); |
||||
uint32_t blendColor(uint32_t fgColor, uint32_t bgColor); |
||||
|
||||
inline int getDisplayWidth() { return DISPLAY_WIDTH; } |
||||
inline int getDisplayHeight() { return DISPLAY_HEIGHT; } |
||||
|
||||
uint16_t getColor16FromIndex(uint16_t color); |
||||
|
||||
void setColor(uint8_t r, uint8_t g, uint8_t b); |
||||
void setColor16(uint16_t color16); |
||||
void setColor(uint16_t color, bool ignoreLuminocity = false); |
||||
uint16_t getColor(); |
||||
|
||||
void setBackColor(uint8_t r, uint8_t g, uint8_t b); |
||||
void setBackColor(uint16_t color, bool ignoreLuminocity = false); |
||||
uint16_t getBackColor(); |
||||
|
||||
uint8_t setOpacity(uint8_t opacity); |
||||
uint8_t getOpacity(); |
||||
|
||||
// these are the basic drawing operations
|
||||
void startPixelsDraw(); |
||||
void drawPixel(int x, int y); |
||||
void drawPixel(int x, int y, uint8_t opacity); |
||||
void endPixelsDraw(); |
||||
void fillRect(int x1, int y1, int x2, int y2); |
||||
void bitBlt(int x1, int y1, int x2, int y2, int x, int y); |
||||
void drawBitmap(Image *image, int x, int y); |
||||
|
||||
// used by animation
|
||||
void fillRect(void *dst, int x1, int y1, int x2, int y2); |
||||
void bitBlt(void *src, int x1, int y1, int x2, int y2); |
||||
void bitBlt(void *src, void *dst, int x1, int y1, int x2, int y2); |
||||
void bitBlt(void *src, void *dst, int sx, int sy, int sw, int sh, int dx, int dy, uint8_t opacity); // also used for buffer rendering (see endRendering)
|
||||
|
||||
// these are implemented by calling basic drawing operations
|
||||
void drawHLine(int x, int y, int l); |
||||
void drawVLine(int x, int y, int l); |
||||
void drawRect(int x1, int y1, int x2, int y2); |
||||
void drawFocusFrame(int x, int y, int w, int h); |
||||
|
||||
// AGG based drawing
|
||||
struct AggDrawing { |
||||
agg::rendering_buffer rbuf; |
||||
Agg2D graphics; |
||||
}; |
||||
|
||||
void aggInit(AggDrawing& aggDrawing); |
||||
|
||||
void drawRoundedRect( |
||||
AggDrawing &aggDrawing, |
||||
double x1, double y1, double x2, double y2, |
||||
double lineWidth, |
||||
double rtlx, double rtly, double rtrx, double rtry, |
||||
double rbrx, double rbry, double rblx, double rbly |
||||
); |
||||
|
||||
void fillRoundedRect( |
||||
AggDrawing &aggDrawing, |
||||
double x1, double y1, double x2, double y2, |
||||
double lineWidth, |
||||
double rtlx, double rtly, double rtrx, double rtry, |
||||
double rbrx, double rbry, double rblx, double rbly, |
||||
bool drawLine, bool fill, |
||||
double clip_x1 = -1, double clip_y1 = -1, double clip_x2 = -1, double clip_y2 = -1 |
||||
); |
||||
|
||||
void fillRoundedRect( |
||||
AggDrawing &aggDrawing, |
||||
double x1, double y1, double x2, double y2, |
||||
double lineWidth, |
||||
double r, |
||||
bool drawLine, bool fill, |
||||
double clip_x1 = -1, double clip_y1 = -1, double clip_x2 = -1, double clip_y2 = -1 |
||||
); |
||||
|
||||
void drawStr(const char *text, int textLength, int x, int y, int clip_x1, int clip_y1, int clip_x2, int clip_y2, gui::font::Font &font, int cursorPosition); |
||||
int getCharIndexAtPosition(int xPos, const char *text, int textLength, int x, int y, int clip_x1, int clip_y1, int clip_x2,int clip_y2, gui::font::Font &font); |
||||
int getCursorXPosition(int cursorPosition, const char *text, int textLength, int x, int y, int clip_x1, int clip_y1, int clip_x2,int clip_y2, gui::font::Font &font); |
||||
int8_t measureGlyph(int32_t encoding, gui::font::Font &font); |
||||
int measureStr(const char *text, int textLength, gui::font::Font &font, int max_width = 0); |
||||
|
||||
} // namespace display
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,856 +0,0 @@
|
||||
/*
|
||||
* EEZ Generic Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <string.h> |
||||
#define _USE_MATH_DEFINES |
||||
#include <math.h> |
||||
|
||||
#include <eez/core/util.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool styleIsHorzAlignLeft(const Style *style) { |
||||
return (style->flags & STYLE_FLAGS_HORZ_ALIGN_MASK) == STYLE_FLAGS_HORZ_ALIGN_LEFT; |
||||
} |
||||
|
||||
bool styleIsHorzAlignRight(const Style *style) { |
||||
return (style->flags & STYLE_FLAGS_HORZ_ALIGN_MASK) == STYLE_FLAGS_HORZ_ALIGN_RIGHT; |
||||
} |
||||
|
||||
bool styleIsVertAlignTop(const Style *style) { |
||||
return (style->flags & STYLE_FLAGS_VERT_ALIGN_MASK) == STYLE_FLAGS_VERT_ALIGN_TOP; |
||||
} |
||||
|
||||
bool styleIsVertAlignBottom(const Style *style) { |
||||
return (style->flags & STYLE_FLAGS_VERT_ALIGN_MASK) == STYLE_FLAGS_VERT_ALIGN_BOTTOM; |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void drawBorderAndBackground(int &x1, int &y1, int &x2, int &y2, const Style *style, uint16_t color, bool ignoreLuminocity) { |
||||
const WidgetCursor& widgetCursor = g_widgetCursor; |
||||
|
||||
bool isTransparent = true; |
||||
bool hasBorder = false; |
||||
bool hasBorderRadius = false; |
||||
|
||||
if (style) { |
||||
hasBorder = style->borderSizeTop > 0 || style->borderSizeRight > 0 || style->borderSizeBottom > 0 || style->borderSizeLeft > 0; |
||||
|
||||
hasBorderRadius = |
||||
style->borderRadiusTLX > 0 || style->borderRadiusTLY > 0 || style->borderRadiusTRX > 0 || style->borderRadiusTRY > 0 || |
||||
style->borderRadiusBRX > 0 || style->borderRadiusBRY > 0 || style->borderRadiusBLX > 0 || style->borderRadiusBLY > 0; |
||||
|
||||
if (color != TRANSPARENT_COLOR_INDEX && style && style->opacity == 255 && !(hasBorder && hasBorderRadius)) { |
||||
// non-transparent color
|
||||
isTransparent = false; |
||||
} else if (style->backgroundImage) { |
||||
auto bitmap = getBitmap(style->backgroundImage); |
||||
if (bitmap->bpp != 32) { |
||||
// non-transparent bitmap
|
||||
isTransparent = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (isTransparent && !widgetCursor.refreshed) { |
||||
size_t startStackPointer; |
||||
if (widgetCursor.backgroundStyleStackPointer > 0) { |
||||
for (startStackPointer = widgetCursor.backgroundStyleStackPointer - 1; startStackPointer > 0; startStackPointer--) { |
||||
auto &backgroundStyle = widgetCursor.backgroundStyleStack[startStackPointer]; |
||||
|
||||
auto color = backgroundStyle.active ? backgroundStyle.style->activeBackgroundColor : backgroundStyle.style->backgroundColor; |
||||
if (color != TRANSPARENT_COLOR_INDEX && backgroundStyle.style->opacity == 255) { |
||||
// non-transparent color
|
||||
break; |
||||
} else if (backgroundStyle.style->backgroundImage) { |
||||
auto bitmap = getBitmap(backgroundStyle.style->backgroundImage); |
||||
if (bitmap) { |
||||
if (bitmap->bpp != 32) { |
||||
// non-transparent bitmap
|
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
startStackPointer = 0; |
||||
} |
||||
|
||||
for (size_t i = startStackPointer; i < widgetCursor.backgroundStyleStackPointer; i++) { |
||||
auto &backgroundStyle = widgetCursor.backgroundStyleStack[i]; |
||||
|
||||
auto color = backgroundStyle.active ? backgroundStyle.style->activeBackgroundColor : backgroundStyle.style->backgroundColor; |
||||
if (color != TRANSPARENT_COLOR_INDEX) { |
||||
display::setColor(color, ignoreLuminocity); |
||||
auto savedOpacity = display::setOpacity(backgroundStyle.style->opacity); |
||||
display::fillRect(x1, y1, x2, y2); |
||||
display::setOpacity(savedOpacity); |
||||
} |
||||
|
||||
if (backgroundStyle.style->backgroundImage) { |
||||
auto bitmap = getBitmap(backgroundStyle.style->backgroundImage); |
||||
if (bitmap) { |
||||
int x = backgroundStyle.x; |
||||
int y = backgroundStyle.y; |
||||
int w = MIN(x2 - x1 + 1, x + bitmap->w - x1); |
||||
int h = MIN(y2 - y1 + 1, y + bitmap->h - y1); |
||||
|
||||
if (w >= 0 && h > 0) { |
||||
auto bytesPerPixel = bitmap->bpp / 8; |
||||
|
||||
uint32_t offset = 0; |
||||
|
||||
if (x < x1) { |
||||
offset += (x1 - x) * bytesPerPixel; |
||||
} |
||||
|
||||
if (y < y1) { |
||||
offset += (y1 - y) * bitmap->w * bytesPerPixel; |
||||
} |
||||
|
||||
Image image; |
||||
|
||||
image.width = w; |
||||
image.height = h; |
||||
image.bpp = bitmap->bpp; |
||||
image.lineOffset = bitmap->w - w; |
||||
image.pixels = (uint8_t *)bitmap->pixels + offset; |
||||
|
||||
display::drawBitmap(&image, x1, y1); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (!style) { |
||||
return; |
||||
} |
||||
|
||||
if (hasBorder) { |
||||
if (style->borderColor != TRANSPARENT_COLOR_INDEX) { |
||||
display::setColor(style->borderColor, ignoreLuminocity); |
||||
} |
||||
|
||||
if (hasBorderRadius) { |
||||
if (color != TRANSPARENT_COLOR_INDEX) { |
||||
display::setBackColor(color, ignoreLuminocity); |
||||
} |
||||
|
||||
int lineWidth = style->borderSizeTop; |
||||
if (lineWidth < style->borderSizeRight) { |
||||
lineWidth = style->borderSizeRight; |
||||
} |
||||
if (lineWidth < style->borderSizeBottom) { |
||||
lineWidth = style->borderSizeBottom; |
||||
} |
||||
if (lineWidth < style->borderSizeLeft) { |
||||
lineWidth = style->borderSizeLeft; |
||||
} |
||||
|
||||
auto savedOpacity = display::setOpacity(style->opacity); |
||||
display::AggDrawing aggDrawing; |
||||
display::aggInit(aggDrawing); |
||||
display::fillRoundedRect( |
||||
aggDrawing, |
||||
x1, y1, x2, y2, |
||||
lineWidth, |
||||
style->borderRadiusTLX, style->borderRadiusTLY, style->borderRadiusTRX, style->borderRadiusTRY, |
||||
style->borderRadiusBRX, style->borderRadiusBRY, style->borderRadiusBLX, style->borderRadiusBLY, |
||||
style->borderColor != TRANSPARENT_COLOR_INDEX, color != TRANSPARENT_COLOR_INDEX |
||||
); |
||||
display::setOpacity(savedOpacity); |
||||
|
||||
lineWidth++; |
||||
|
||||
x1 += lineWidth; |
||||
y1 += lineWidth; |
||||
x2 -= lineWidth; |
||||
y2 -= lineWidth; |
||||
|
||||
return; |
||||
} |
||||
|
||||
if (style->borderColor != TRANSPARENT_COLOR_INDEX) { |
||||
if (style->borderSizeLeft > 0) { |
||||
display::fillRect(x1, y1, x1 + style->borderSizeLeft - 1, y2); |
||||
} |
||||
if (style->borderSizeTop > 0) { |
||||
display::fillRect(x1, y1, x2, y1 + style->borderSizeTop - 1); |
||||
} |
||||
if (style->borderSizeRight > 0) { |
||||
display::fillRect(x2 - (style->borderSizeRight - 1), y1, x2, y2); |
||||
} |
||||
if (style->borderSizeBottom > 0) { |
||||
display::fillRect(x1, y2 - (style->borderSizeBottom - 1), x2, y2); |
||||
} |
||||
} |
||||
|
||||
x1 += style->borderSizeLeft; |
||||
y1 += style->borderSizeTop; |
||||
x2 -= style->borderSizeRight; |
||||
y2 -= style->borderSizeBottom; |
||||
} else { |
||||
if (hasBorderRadius) { |
||||
if (color != TRANSPARENT_COLOR_INDEX) { |
||||
display::setBackColor(color, ignoreLuminocity); |
||||
auto savedOpacity = display::setOpacity(style->opacity); |
||||
display::AggDrawing aggDrawing; |
||||
display::aggInit(aggDrawing); |
||||
display::fillRoundedRect( |
||||
aggDrawing, |
||||
x1, y1, x2, y2, |
||||
0, |
||||
style->borderRadiusTLX, style->borderRadiusTLY, style->borderRadiusTRX, style->borderRadiusTRY, |
||||
style->borderRadiusBRX, style->borderRadiusBRY, style->borderRadiusBLX, style->borderRadiusBLY, |
||||
style->borderColor != TRANSPARENT_COLOR_INDEX, color != TRANSPARENT_COLOR_INDEX |
||||
); |
||||
display::setOpacity(savedOpacity); |
||||
} |
||||
return; |
||||
} |
||||
} |
||||
|
||||
if (color != TRANSPARENT_COLOR_INDEX) { |
||||
display::setColor(color, ignoreLuminocity); |
||||
auto savedOpacity = display::setOpacity(style->opacity); |
||||
display::fillRect(x1, y1, x2, y2); |
||||
display::setOpacity(savedOpacity); |
||||
} |
||||
|
||||
if (style->backgroundImage) { |
||||
auto bitmap = getBitmap(style->backgroundImage); |
||||
if (bitmap) { |
||||
Image image; |
||||
|
||||
int w = MIN(x2 - x1 + 1, bitmap->w); |
||||
int h = MIN(y2 - y1 + 1, bitmap->h); |
||||
|
||||
image.width = w; |
||||
image.height = h; |
||||
image.bpp = bitmap->bpp; |
||||
image.lineOffset = bitmap->w - w; |
||||
image.pixels = (uint8_t *)bitmap->pixels; |
||||
|
||||
display::drawBitmap(&image, x1, y1); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void drawText( |
||||
const char *text, int textLength, |
||||
int x, int y, int w, int h, |
||||
const Style *style, |
||||
bool active, bool blink, bool ignoreLuminocity, |
||||
uint16_t *overrideColor, uint16_t *overrideBackgroundColor, |
||||
uint16_t *overrideActiveColor, uint16_t *overrideActiveBackgroundColor, |
||||
bool useSmallerFontIfDoesNotFit, int cursorPosition, int xScroll, |
||||
bool boolSkipBackground |
||||
) { |
||||
int x1 = x; |
||||
int y1 = y; |
||||
int x2 = x + w - 1; |
||||
int y2 = y + h - 1; |
||||
|
||||
if (!boolSkipBackground) { |
||||
uint16_t backgroundColor; |
||||
if (active || blink) { |
||||
if (overrideActiveBackgroundColor) { |
||||
backgroundColor = *overrideActiveBackgroundColor; |
||||
} else { |
||||
backgroundColor = style->activeBackgroundColor; |
||||
} |
||||
} else { |
||||
if (overrideBackgroundColor) { |
||||
backgroundColor = *overrideBackgroundColor; |
||||
} else { |
||||
backgroundColor = style->backgroundColor; |
||||
} |
||||
} |
||||
drawBorderAndBackground(x1, y1, x2, y2, style, backgroundColor, ignoreLuminocity); |
||||
} |
||||
|
||||
font::Font font = styleGetFont(style); |
||||
if (!font) { |
||||
return; |
||||
} |
||||
|
||||
int width = display::measureStr(text, textLength, font, 0); |
||||
while (useSmallerFontIfDoesNotFit && width > x2 - x1 + 1 && g_hooks.styleGetSmallerFont(font)) { |
||||
width = display::measureStr(text, textLength, font, 0); |
||||
} |
||||
int height = font.getHeight(); |
||||
|
||||
int x_offset; |
||||
if (styleIsHorzAlignLeft(style)) { |
||||
x_offset = x1 + style->paddingLeft; |
||||
} else if (styleIsHorzAlignRight(style)) { |
||||
x_offset = x2 - style->paddingRight - width; |
||||
} else { |
||||
x_offset = x1 + ((x2 - x1 + 1) - width) / 2; |
||||
if (x_offset < x1) { |
||||
x_offset = x1; |
||||
} |
||||
} |
||||
|
||||
int y_offset; |
||||
if (styleIsVertAlignTop(style)) { |
||||
y_offset = y1 + style->paddingTop; |
||||
} else if (styleIsVertAlignBottom(style)) { |
||||
y_offset = y2 - style->paddingBottom - height; |
||||
} else { |
||||
y_offset = y1 + ((y2 - y1 + 1) - height) / 2; |
||||
} |
||||
if (y_offset < 0) { |
||||
y_offset = y1; |
||||
} |
||||
|
||||
// draw text
|
||||
if (active || blink) { |
||||
if (overrideActiveColor) { |
||||
display::setColor(*overrideActiveColor, ignoreLuminocity); |
||||
} else { |
||||
display::setColor(style->activeColor, ignoreLuminocity); |
||||
} |
||||
} else { |
||||
if (overrideColor) { |
||||
display::setColor(*overrideColor, ignoreLuminocity); |
||||
} else { |
||||
display::setColor(style->color, ignoreLuminocity); |
||||
} |
||||
} |
||||
display::drawStr(text, textLength, x_offset - xScroll, y_offset, x1, y1, x2, y2, font, cursorPosition); |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int getCharIndexAtPosition(int xPos, const char *text, int textLength, int x, int y, int w, int h, const Style *style) { |
||||
int x1 = x; |
||||
int y1 = y; |
||||
int x2 = x + w - 1; |
||||
int y2 = y + h - 1; |
||||
|
||||
x1 += style->borderSizeLeft; |
||||
y1 += style->borderSizeTop; |
||||
x2 -= style->borderSizeRight; |
||||
y2 -= style->borderSizeBottom; |
||||
|
||||
font::Font font = styleGetFont(style); |
||||
|
||||
int width = display::measureStr(text, textLength, font, 0); |
||||
int height = font.getHeight(); |
||||
|
||||
int x_offset; |
||||
if (styleIsHorzAlignLeft(style)) { |
||||
x_offset = x1 + style->paddingLeft; |
||||
} else if (styleIsHorzAlignRight(style)) { |
||||
x_offset = x2 - style->paddingRight - width; |
||||
} else { |
||||
x_offset = x1 + ((x2 - x1 + 1) - width) / 2; |
||||
if (x_offset < x1) { |
||||
x_offset = x1; |
||||
} |
||||
} |
||||
|
||||
int y_offset; |
||||
if (styleIsVertAlignTop(style)) { |
||||
y_offset = y1 + style->paddingTop; |
||||
} else if (styleIsVertAlignBottom(style)) { |
||||
y_offset = y2 - style->paddingBottom - height; |
||||
} else { |
||||
y_offset = y1 + ((y2 - y1 + 1) - height) / 2; |
||||
} |
||||
if (y_offset < 0) { |
||||
y_offset = y1; |
||||
} |
||||
|
||||
return display::getCharIndexAtPosition(xPos, text, textLength, x_offset, y_offset, x1, y1, x2, y2, font); |
||||
} |
||||
|
||||
int getCursorXPosition(int cursorPosition, const char *text, int textLength, int x, int y, int w, int h, const Style *style) { |
||||
int x1 = x; |
||||
int y1 = y; |
||||
int x2 = x + w - 1; |
||||
int y2 = y + h - 1; |
||||
|
||||
x1 += style->borderSizeLeft; |
||||
y1 += style->borderSizeTop; |
||||
x2 -= style->borderSizeRight; |
||||
y2 -= style->borderSizeBottom; |
||||
|
||||
font::Font font = styleGetFont(style); |
||||
|
||||
int width = display::measureStr(text, textLength, font, 0); |
||||
int height = font.getHeight(); |
||||
|
||||
int x_offset; |
||||
if (styleIsHorzAlignLeft(style)) { |
||||
x_offset = x1 + style->paddingLeft; |
||||
} else if (styleIsHorzAlignRight(style)) { |
||||
x_offset = x2 - style->paddingRight - width; |
||||
} else { |
||||
x_offset = x1 + ((x2 - x1 + 1) - width) / 2; |
||||
if (x_offset < x1) { |
||||
x_offset = x1; |
||||
} |
||||
} |
||||
|
||||
int y_offset; |
||||
if (styleIsVertAlignTop(style)) { |
||||
y_offset = y1 + style->paddingTop; |
||||
} else if (styleIsVertAlignBottom(style)) { |
||||
y_offset = y2 - style->paddingBottom - height; |
||||
} else { |
||||
y_offset = y1 + ((y2 - y1 + 1) - height) / 2; |
||||
} |
||||
if (y_offset < 0) { |
||||
y_offset = y1; |
||||
} |
||||
|
||||
return display::getCursorXPosition(cursorPosition, text, textLength, x_offset, y_offset, x1, y1, x2, y2, font); |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const unsigned int CONF_MULTILINE_TEXT_MAX_LINE_LENGTH = 1000; |
||||
|
||||
enum MultilineTextRenderStep { |
||||
MEASURE, |
||||
RENDER |
||||
}; |
||||
|
||||
struct MultilineTextRender { |
||||
const char *text; |
||||
int x1; |
||||
int y1; |
||||
int x2; |
||||
int y2; |
||||
const Style *style; |
||||
bool active; |
||||
int firstLineIndent; |
||||
int hangingIndent; |
||||
|
||||
font::Font font; |
||||
int spaceWidth; |
||||
|
||||
int lineHeight; |
||||
int textHeight; |
||||
|
||||
char line[CONF_MULTILINE_TEXT_MAX_LINE_LENGTH + 1]; |
||||
int lineIndent; |
||||
int lineWidth; |
||||
|
||||
void appendToLine(const char *str, size_t n) { |
||||
size_t j = strlen(line); |
||||
for (size_t i = 0; i < n && j < CONF_MULTILINE_TEXT_MAX_LINE_LENGTH; i++, j++) { |
||||
line[j] = str[i]; |
||||
} |
||||
line[j] = 0; |
||||
} |
||||
|
||||
void flushLine(int y, MultilineTextRenderStep step) { |
||||
if (line[0] && lineWidth) { |
||||
if (step == RENDER) { |
||||
int x; |
||||
|
||||
if (styleIsHorzAlignLeft(style)) { |
||||
x = x1; |
||||
} else if (styleIsHorzAlignRight(style)) { |
||||
x = x2 + 1 - lineWidth; |
||||
} else { |
||||
x = x1 + int((x2 - x1 + 1 - lineWidth) / 2); |
||||
} |
||||
|
||||
display::drawStr(line, -1, x + lineIndent, y, x, y, x + lineWidth - 1, y + font.getHeight() - 1, font, -1); |
||||
} else { |
||||
textHeight = MAX(textHeight, y + lineHeight - y1); |
||||
} |
||||
|
||||
line[0] = 0; |
||||
lineWidth = lineIndent = hangingIndent; |
||||
} |
||||
} |
||||
|
||||
int executeStep(MultilineTextRenderStep step) { |
||||
textHeight = 0; |
||||
|
||||
int y = y1; |
||||
|
||||
line[0] = 0; |
||||
lineWidth = lineIndent = firstLineIndent; |
||||
|
||||
int i = 0; |
||||
while (true) { |
||||
int j = i; |
||||
while (text[i] != 0 && text[i] != ' ' && text[i] != '\n') |
||||
++i; |
||||
|
||||
int width = display::measureStr(text + j, i - j, font); |
||||
|
||||
while (lineWidth + (line[0] ? spaceWidth : 0) + width > x2 - x1 + 1) { |
||||
if (!line[0]) { |
||||
i--; |
||||
width = display::measureStr(text + j, i - j, font); |
||||
continue; |
||||
} |
||||
|
||||
flushLine(y, step); |
||||
|
||||
y += lineHeight; |
||||
if (y + lineHeight - 1 > y2) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (y + lineHeight - 1 > y2) { |
||||
break; |
||||
} |
||||
|
||||
if (line[0]) { |
||||
appendToLine(" ", 1); |
||||
lineWidth += spaceWidth; |
||||
} |
||||
appendToLine(text + j, i - j); |
||||
lineWidth += width; |
||||
|
||||
while (text[i] == ' ') { |
||||
++i; |
||||
} |
||||
|
||||
if (text[i] == 0 || text[i] == '\n') { |
||||
flushLine(y, step); |
||||
|
||||
y += lineHeight; |
||||
|
||||
if (text[i] == 0) { |
||||
break; |
||||
} |
||||
|
||||
++i; |
||||
|
||||
int extraHeightBetweenParagraphs = (int)(0.2 * lineHeight); |
||||
y += extraHeightBetweenParagraphs; |
||||
|
||||
if (y + lineHeight - 1 > y2) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
flushLine(y, step); |
||||
|
||||
return textHeight + font.getHeight() - lineHeight; |
||||
} |
||||
|
||||
int measure() { |
||||
x1 += style->borderSizeLeft; |
||||
y1 += style->borderSizeTop; |
||||
x2 -= style->borderSizeRight; |
||||
y2 -= style->borderSizeBottom; |
||||
|
||||
font = styleGetFont(style); |
||||
|
||||
lineHeight = (int)(0.9 * font.getHeight()); |
||||
if (lineHeight <= 0) { |
||||
return 0; |
||||
} |
||||
|
||||
auto spaceGlyph = font.getGlyph(' '); |
||||
spaceWidth = spaceGlyph->dx; |
||||
|
||||
x1 += style->paddingLeft; |
||||
x2 -= style->paddingRight; |
||||
y1 += style->paddingTop; |
||||
y2 -= style->paddingBottom; |
||||
|
||||
return executeStep(MEASURE); |
||||
} |
||||
|
||||
void render() { |
||||
drawBorderAndBackground(x1, y1, x2, y2, style, active ? style->activeBackgroundColor : style->backgroundColor); |
||||
|
||||
//
|
||||
font = styleGetFont(style); |
||||
|
||||
lineHeight = (int)(0.9 * font.getHeight()); |
||||
if (lineHeight <= 0) { |
||||
return; |
||||
} |
||||
|
||||
auto spaceGlyph = font.getGlyph(' '); |
||||
spaceWidth = spaceGlyph->dx; |
||||
|
||||
// draw text
|
||||
display::setColor(active ? style->activeColor : style->color); |
||||
|
||||
x1 += style->paddingLeft; |
||||
x2 -= style->paddingRight; |
||||
y1 += style->paddingTop; |
||||
y2 -= style->paddingBottom; |
||||
|
||||
int textHeight = executeStep(MEASURE); |
||||
|
||||
if (styleIsVertAlignTop(style)) { |
||||
} else if (styleIsVertAlignBottom(style)) { |
||||
y1 = y2 + 1 - textHeight; |
||||
} else { |
||||
y1 += (int)((y2 - y1 + 1 - textHeight) / 2); |
||||
} |
||||
y2 = y1 + textHeight - 1; |
||||
|
||||
executeStep(RENDER); |
||||
} |
||||
}; |
||||
|
||||
void drawMultilineText(const char *text, int x, int y, int w, int h, const Style *style, bool active, bool blinking, int firstLineIndent, int hangingIndent) { |
||||
MultilineTextRender multilineTextRender; |
||||
|
||||
multilineTextRender.text = text; |
||||
multilineTextRender.x1 = x; |
||||
multilineTextRender.y1 = y; |
||||
multilineTextRender.x2 = x + w - 1; |
||||
multilineTextRender.y2 = y + h - 1; |
||||
multilineTextRender.style = style; |
||||
multilineTextRender.active = active || blinking; |
||||
multilineTextRender.firstLineIndent = firstLineIndent; |
||||
multilineTextRender.hangingIndent = hangingIndent; |
||||
|
||||
multilineTextRender.render(); |
||||
} |
||||
|
||||
int measureMultilineText(const char *text, int x, int y, int w, int h, const Style *style, int firstLineIndent, int hangingIndent) { |
||||
MultilineTextRender multilineTextRender; |
||||
|
||||
multilineTextRender.text = text; |
||||
multilineTextRender.x1 = x; |
||||
multilineTextRender.y1 = y; |
||||
multilineTextRender.x2 = x + w - 1; |
||||
multilineTextRender.y2 = y + h - 1; |
||||
multilineTextRender.style = style; |
||||
multilineTextRender.active = false; |
||||
multilineTextRender.firstLineIndent = firstLineIndent; |
||||
multilineTextRender.hangingIndent = hangingIndent; |
||||
|
||||
return multilineTextRender.measure(); |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void drawBitmap(Image *image, int x, int y, int w, int h, const Style *style, bool active) { |
||||
int x1 = x; |
||||
int y1 = y; |
||||
int x2 = x + w - 1; |
||||
int y2 = y + h - 1; |
||||
|
||||
int width = image->width; |
||||
int height = image->height; |
||||
|
||||
int x_offset; |
||||
if (styleIsHorzAlignLeft(style)) |
||||
x_offset = x1 + style->paddingLeft; |
||||
else if (styleIsHorzAlignRight(style)) |
||||
x_offset = x2 - style->paddingRight - width; |
||||
else |
||||
x_offset = x1 + ((x2 - x1) - width) / 2; |
||||
if (x_offset < 0) |
||||
x_offset = x1; |
||||
|
||||
int y_offset; |
||||
if (styleIsVertAlignTop(style)) |
||||
y_offset = y1 + style->paddingTop; |
||||
else if (styleIsVertAlignBottom(style)) |
||||
y_offset = y2 - style->paddingBottom - height; |
||||
else |
||||
y_offset = y1 + ((y2 - y1) - height) / 2; |
||||
if (y_offset < 0) |
||||
y_offset = y1; |
||||
|
||||
|
||||
// draw bitmap
|
||||
uint8_t savedOpacity = display::getOpacity(); |
||||
|
||||
if (active) { |
||||
display::setBackColor(style->activeBackgroundColor); |
||||
display::setColor(style->activeColor); |
||||
display::setOpacity(style->opacity); |
||||
} else { |
||||
display::setBackColor(style->backgroundColor); |
||||
display::setColor(style->color); |
||||
display::setOpacity(style->opacity); |
||||
} |
||||
|
||||
display::drawBitmap(image, x_offset, y_offset); |
||||
|
||||
display::setOpacity(savedOpacity); |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void drawRectangle(int x, int y, int w, int h, const Style *style, bool active, bool ignoreLuminocity, bool invertColors) { |
||||
if (w > 0 && h > 0) { |
||||
int x1 = x; |
||||
int y1 = y; |
||||
int x2 = x + w - 1; |
||||
int y2 = y + h - 1; |
||||
|
||||
uint16_t color; |
||||
if (style) { |
||||
if (invertColors) { |
||||
color = active ? style->activeBackgroundColor : style->backgroundColor; |
||||
} else { |
||||
color = active ? style->activeColor : style->color; |
||||
} |
||||
} else { |
||||
color = TRANSPARENT_COLOR_INDEX; |
||||
} |
||||
|
||||
drawBorderAndBackground(x1, y1, x2, y2, style, color, ignoreLuminocity); |
||||
} |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum ShadowGlpyh { |
||||
SHADOW_GLYPH_TOP_LEFT, |
||||
SHADOW_GLYPH_TOP, |
||||
SHADOW_GLYPH_TOP_RIGHT, |
||||
SHADOW_GLYPH_LEFT, |
||||
SHADOW_GLYPH_RIGHT, |
||||
SHADOW_GLYPH_BOTTOM_LEFT, |
||||
SHADOW_GLYPH_BOTTOM, |
||||
SHADOW_GLYPH_BOTTOM_RIGHT, |
||||
}; |
||||
|
||||
static const int T = 4; |
||||
static const int R = 7; |
||||
static const int B = 10; |
||||
static const int L = 7; |
||||
|
||||
static const int W = 20; |
||||
static const int H = 20; |
||||
|
||||
void drawShadowGlyph(ShadowGlpyh shadowGlyph, int x, int y, int xClip = -1, int yClip = -1) { |
||||
font::Font font(getFontData(FONT_ID_SHADOW)); |
||||
|
||||
if (xClip == -1) { |
||||
xClip = x + W - 1; |
||||
} |
||||
if (yClip == -1) { |
||||
yClip = y + H - 1; |
||||
} |
||||
char glyph = 32 + shadowGlyph; |
||||
display::drawStr(&glyph, 1, x, y, x, y, xClip, yClip, font, -1); |
||||
} |
||||
|
||||
void drawShadow(int x1, int y1, int x2, int y2) { |
||||
display::setColor(64, 64, 64); |
||||
|
||||
int left = x1 - L; |
||||
int top = y1 - T; |
||||
|
||||
int right = x2 + R - (W - 1); |
||||
int bottom = y2 + B - (H - 1); |
||||
|
||||
drawShadowGlyph(SHADOW_GLYPH_TOP_LEFT, left, top); |
||||
for (int x = left + W; x < right; x += W) { |
||||
drawShadowGlyph(SHADOW_GLYPH_TOP, x, top, right - 1); |
||||
} |
||||
drawShadowGlyph(SHADOW_GLYPH_TOP_RIGHT, right, top); |
||||
for (int y = top + H; y < bottom; y += H) { |
||||
drawShadowGlyph(SHADOW_GLYPH_LEFT, left, y, -1, bottom - 1); |
||||
} |
||||
for (int y = top + H; y < bottom; y += H) { |
||||
drawShadowGlyph(SHADOW_GLYPH_RIGHT, right, y, -1, bottom - 1); |
||||
} |
||||
drawShadowGlyph(SHADOW_GLYPH_BOTTOM_LEFT, left, bottom); |
||||
for (int x = left + W; x < right; x += W) { |
||||
drawShadowGlyph(SHADOW_GLYPH_BOTTOM, x, bottom, right - 1); |
||||
} |
||||
drawShadowGlyph(SHADOW_GLYPH_BOTTOM_RIGHT, right, bottom); |
||||
} |
||||
|
||||
void expandRectWithShadow(int &x1, int &y1, int &x2, int &y2) { |
||||
x1 -= L; |
||||
y1 -= T; |
||||
x2 += R; |
||||
y2 += B; |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void drawLine(int x1, int y1, int x2, int y2) { |
||||
display::startPixelsDraw(); |
||||
|
||||
int dx = x2 - x1; |
||||
int dy = y2 - y1; |
||||
|
||||
int length; |
||||
if (abs(dx) > abs(dy)) { |
||||
length = abs(dx); |
||||
} else { |
||||
length = abs(dy); |
||||
} |
||||
|
||||
float xinc = (float)dx / length; |
||||
float yinc = (float)dy / length; |
||||
float x = (float)x1; |
||||
float y = (float)y1; |
||||
for (int i = 0; i < length; i++) { |
||||
display::drawPixel((int)roundf(x), (int)roundf(y)); |
||||
x += xinc; |
||||
y += yinc; |
||||
} |
||||
|
||||
display::endPixelsDraw(); |
||||
} |
||||
|
||||
// http://members.chello.at/~easyfilter/bresenham.html
|
||||
void drawAntialiasedLine(int x0, int y0, int x1, int y1) { |
||||
display::startPixelsDraw(); |
||||
|
||||
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1; |
||||
int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1; |
||||
int err = dx - dy, e2, x2; /* error value e_xy */ |
||||
int ed = dx + dy == 0 ? 1 : (int)sqrt((float)dx*dx + (float)dy*dy); |
||||
|
||||
for (; ; ) { /* pixel loop */ |
||||
display::drawPixel(x0, y0, 255 - 255 * abs(err - dx + dy) / ed); |
||||
e2 = err; x2 = x0; |
||||
if (2 * e2 >= -dx) { /* x step */ |
||||
if (x0 == x1) break; |
||||
if (e2 + dy < ed) display::drawPixel(x0, y0 + sy, 255 - 255 * (e2 + dy) / ed); |
||||
err -= dy; x0 += sx; |
||||
} |
||||
if (2 * e2 <= dy) { /* y step */ |
||||
if (y0 == y1) break; |
||||
if (dx - e2 < ed) display::drawPixel(x2 + sx, y0, 255 - 255 * (dx - e2) / ed); |
||||
err += dx; y0 += sy; |
||||
} |
||||
} |
||||
|
||||
display::endPixelsDraw(); |
||||
} |
||||
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
|
||||
inline font::Font styleGetFont(const Style *style) { |
||||
return font::Font(getFontData(style->font)); |
||||
} |
||||
|
||||
inline bool styleIsBlink(const Style *style) { |
||||
return style->flags & STYLE_FLAGS_BLINK; |
||||
} |
||||
|
||||
void drawBorderAndBackground(int &x1, int &y1, int &x2, int &y2, const Style *style, uint16_t color, bool ignoreLuminocity = false); |
||||
|
||||
void drawText( |
||||
const char *text, int textLength, |
||||
int x, int y, int w, int h, |
||||
const Style *style, |
||||
bool active = false, bool blink = false, bool ignoreLuminocity = false, |
||||
uint16_t *overrideColor = nullptr, uint16_t *overrideBackgroundColor = nullptr, |
||||
uint16_t *overrideActiveColor = nullptr, uint16_t *overrideActiveBackgroundColor = nullptr, |
||||
bool useSmallerFontIfDoesNotFit = false, int cursorPosition = -1, int xScroll = 0, |
||||
bool boolSkipBackground = false |
||||
); |
||||
int getCharIndexAtPosition(int xPos, const char *text, int textLength, int x, int y, int w, int h, const Style *style); |
||||
int getCursorXPosition(int cursorPosition, const char *text, int textLength, int x, int y, int w, int h, const Style *style); |
||||
|
||||
void drawMultilineText(const char *text, int x, int y, int w, int h, const Style *style, bool active, bool blinking, int firstLineIndent, int hangingIndent); |
||||
int measureMultilineText(const char *text, int x, int y, int w, int h, const Style *style, int firstLineIndent, int hangingIndent); |
||||
|
||||
void drawBitmap(Image *image, int x, int y, int w, int h, const Style *style, bool active); |
||||
void drawRectangle(int x, int y, int w, int h, const Style *style, bool active = false, bool ignoreLuminocity = false, bool invertColors = true); |
||||
|
||||
void drawShadow(int x1, int y1, int x2, int y2); |
||||
void expandRectWithShadow(int &x1, int &y1, int &x2, int &y2); |
||||
|
||||
void drawLine(int x1, int y1, int x2, int y2); |
||||
void drawAntialiasedLine(int x1, int y1, int x2, int y2); |
||||
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,273 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include <eez/conf.h> |
||||
#include <eez/core/os.h> |
||||
#include <eez/core/hmi.h> |
||||
|
||||
#if OPTION_MOUSE |
||||
#include <eez/core/mouse.h> |
||||
#endif |
||||
|
||||
#include <eez/core/util.h> |
||||
|
||||
#include <eez/gui/gui.h> |
||||
#include <eez/gui/thread.h> |
||||
|
||||
#define CONF_GUI_LONG_TOUCH_TIMEOUT_MS 1000 |
||||
#define CONF_GUI_KEYPAD_FIRST_AUTO_REPEAT_DELAY_MS 300 |
||||
#define CONF_GUI_KEYPAD_NEXT_AUTO_REPEAT_DELAY_MS 50 |
||||
#define CONF_GUI_EXTRA_LONG_TOUCH_TIMEOUT_MS 15000 |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WidgetCursor g_activeWidget; |
||||
bool g_isLongTouch; |
||||
|
||||
static WidgetCursor g_foundWidgetAtDown; |
||||
|
||||
static bool g_touchActionExecuted; |
||||
static bool g_touchActionExecutedAtDown; |
||||
|
||||
static OnTouchFunctionType g_onTouchFunction; |
||||
|
||||
static bool g_longTouchGenerated; |
||||
static bool g_extraLongTouchGenerated; |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void processTouchEvent(EventType type, Event &touchEvent); |
||||
static void onPageTouch(const WidgetCursor &foundWidget, Event &touchEvent); |
||||
static void onWidgetDefaultTouch(const WidgetCursor &widgetCursor, Event &touchEvent); |
||||
static void onWidgetTouch(const WidgetCursor &widgetCursor, Event &touchEvent); |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void onTouchEvent(bool pressed, int x, int y, Event &lastEvent) { |
||||
auto eventType = lastEvent.type; |
||||
if (pressed) { |
||||
if (lastEvent.type == EVENT_TYPE_TOUCH_NONE || lastEvent.type == EVENT_TYPE_TOUCH_UP) { |
||||
eventType = EVENT_TYPE_TOUCH_DOWN; |
||||
} else { |
||||
if (lastEvent.type == EVENT_TYPE_TOUCH_DOWN) { |
||||
eventType = EVENT_TYPE_TOUCH_MOVE; |
||||
} |
||||
} |
||||
} else { |
||||
if (lastEvent.type == EVENT_TYPE_TOUCH_DOWN || lastEvent.type == EVENT_TYPE_TOUCH_MOVE) { |
||||
eventType = EVENT_TYPE_TOUCH_UP; |
||||
} else if (lastEvent.type == EVENT_TYPE_TOUCH_UP) { |
||||
eventType = EVENT_TYPE_TOUCH_NONE; |
||||
} |
||||
} |
||||
|
||||
if (eventType != lastEvent.type || x != lastEvent.x || y != lastEvent.y) { |
||||
lastEvent.type = eventType; |
||||
lastEvent.x = x; |
||||
lastEvent.y = y; |
||||
if (lastEvent.type != EVENT_TYPE_TOUCH_NONE) { |
||||
sendTouchEventToGuiThread(lastEvent); |
||||
} |
||||
} else { |
||||
static const uint32_t SEND_TOUC_MOVE_EVENT_EVERY_MS = 20; |
||||
if (lastEvent.type == EVENT_TYPE_TOUCH_MOVE) { |
||||
auto time = millis(); |
||||
if (time - lastEvent.time > SEND_TOUC_MOVE_EVENT_EVERY_MS) { |
||||
sendTouchEventToGuiThread(lastEvent); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
void processTouchEvent(Event &touchEvent) { |
||||
if (g_hooks.isEventHandlingDisabled()) { |
||||
return; |
||||
} |
||||
|
||||
static uint32_t m_lastAutoRepeatEventTimeMs; |
||||
static uint32_t m_touchDownTimeMs; |
||||
|
||||
if (touchEvent.type != EVENT_TYPE_TOUCH_NONE) { |
||||
uint32_t tickCountMs = millis(); |
||||
|
||||
eez::hmi::noteActivity(); |
||||
|
||||
if (touchEvent.type == EVENT_TYPE_TOUCH_DOWN) { |
||||
m_touchDownTimeMs = tickCountMs; |
||||
m_lastAutoRepeatEventTimeMs = tickCountMs; |
||||
g_longTouchGenerated = false; |
||||
g_extraLongTouchGenerated = false; |
||||
processTouchEvent(EVENT_TYPE_TOUCH_DOWN, touchEvent); |
||||
} else if (touchEvent.type == EVENT_TYPE_TOUCH_MOVE) { |
||||
processTouchEvent(EVENT_TYPE_TOUCH_MOVE, touchEvent); |
||||
|
||||
if (!g_longTouchGenerated && int32_t(tickCountMs - m_touchDownTimeMs) >= CONF_GUI_LONG_TOUCH_TIMEOUT_MS) { |
||||
g_longTouchGenerated = true; |
||||
processTouchEvent(EVENT_TYPE_LONG_TOUCH, touchEvent); |
||||
} |
||||
|
||||
if (g_longTouchGenerated && !g_extraLongTouchGenerated && int32_t(tickCountMs - m_touchDownTimeMs) >= CONF_GUI_EXTRA_LONG_TOUCH_TIMEOUT_MS) { |
||||
g_extraLongTouchGenerated = true; |
||||
g_touchActionExecuted = true; |
||||
int action = g_hooks.getExtraLongTouchAction(); |
||||
if (action != ACTION_ID_NONE) { |
||||
executeAction(WidgetCursor(), action); |
||||
} |
||||
} |
||||
|
||||
if (int32_t(tickCountMs - m_lastAutoRepeatEventTimeMs) >= (m_lastAutoRepeatEventTimeMs == m_touchDownTimeMs ? CONF_GUI_KEYPAD_FIRST_AUTO_REPEAT_DELAY_MS : CONF_GUI_KEYPAD_NEXT_AUTO_REPEAT_DELAY_MS)) { |
||||
processTouchEvent(EVENT_TYPE_AUTO_REPEAT, touchEvent); |
||||
m_lastAutoRepeatEventTimeMs = tickCountMs; |
||||
} |
||||
} else if (touchEvent.type == EVENT_TYPE_TOUCH_UP) { |
||||
processTouchEvent(EVENT_TYPE_TOUCH_UP, touchEvent); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void processTouchEvent(EventType type, Event &touchEvent) { |
||||
if (type == EVENT_TYPE_TOUCH_DOWN) { |
||||
g_foundWidgetAtDown = findWidget(touchEvent.x, touchEvent.y); |
||||
g_onTouchFunction = getWidgetTouchFunction(g_foundWidgetAtDown); |
||||
if (!g_onTouchFunction) { |
||||
g_onTouchFunction = onPageTouch; |
||||
} |
||||
} else if (type == EVENT_TYPE_TOUCH_UP) { |
||||
g_activeWidget = 0; |
||||
} |
||||
|
||||
if (g_onTouchFunction) { |
||||
Event event = touchEvent; |
||||
event.type = type; |
||||
g_onTouchFunction(g_foundWidgetAtDown, event); |
||||
} |
||||
} |
||||
|
||||
OnTouchFunctionType getWidgetTouchFunction(const WidgetCursor &widgetCursor) { |
||||
if (widgetCursor) { |
||||
auto action = getWidgetAction(widgetCursor); |
||||
if (action && !widgetCursor.appContext->isWidgetActionEnabled(widgetCursor)) { |
||||
return nullptr; |
||||
} |
||||
|
||||
if (widgetCursor.currentState->hasOnTouch()) { |
||||
return onWidgetTouch; |
||||
} |
||||
|
||||
if (widgetCursor.appContext->isWidgetActionEnabled(widgetCursor)) { |
||||
return onWidgetDefaultTouch; |
||||
} |
||||
|
||||
return g_hooks.getWidgetTouchFunction(widgetCursor); |
||||
} |
||||
|
||||
return nullptr; |
||||
} |
||||
|
||||
static void onPageTouch(const WidgetCursor &foundWidget, Event &touchEvent) { |
||||
if (foundWidget.appContext) { |
||||
foundWidget.appContext->onPageTouch(foundWidget, touchEvent); |
||||
} else { |
||||
getRootAppContext()->onPageTouch(foundWidget, touchEvent); |
||||
} |
||||
} |
||||
|
||||
static void onWidgetDefaultTouch(const WidgetCursor &widgetCursor, Event &touchEvent) { |
||||
if (!widgetCursor.widget) { |
||||
return; |
||||
} |
||||
|
||||
auto action = getWidgetAction(widgetCursor);
|
||||
|
||||
if (touchEvent.type == EVENT_TYPE_TOUCH_DOWN) { |
||||
g_touchActionExecuted = false; |
||||
g_touchActionExecutedAtDown = false; |
||||
|
||||
if (action == ACTION_ID_DRAG_OVERLAY) { |
||||
dragOverlay(touchEvent); |
||||
g_activeWidget = widgetCursor; |
||||
} else if (widgetCursor.appContext->testExecuteActionOnTouchDown(action)) { |
||||
executeAction(widgetCursor, action); |
||||
g_touchActionExecutedAtDown = true; |
||||
if (widgetCursor.appContext->isAutoRepeatAction(action)) { |
||||
g_activeWidget = widgetCursor; |
||||
} |
||||
} else { |
||||
g_activeWidget = widgetCursor; |
||||
} |
||||
} else if (touchEvent.type == EVENT_TYPE_TOUCH_MOVE) { |
||||
if (action == ACTION_ID_DRAG_OVERLAY) { |
||||
dragOverlay(touchEvent); |
||||
} |
||||
} else if (touchEvent.type == EVENT_TYPE_AUTO_REPEAT) { |
||||
if (widgetCursor.appContext->isWidgetActionEnabled(widgetCursor) && widgetCursor.appContext->isAutoRepeatAction(action)) { |
||||
g_touchActionExecuted = true; |
||||
executeAction(widgetCursor, action); |
||||
} |
||||
} else if (touchEvent.type == EVENT_TYPE_LONG_TOUCH) { |
||||
g_touchActionExecuted = true; |
||||
int action = widgetCursor.appContext->getLongTouchActionHook(widgetCursor); |
||||
if (action != ACTION_ID_NONE) { |
||||
g_isLongTouch = true; |
||||
executeAction(widgetCursor, action); |
||||
g_isLongTouch = false; |
||||
} |
||||
} else if (touchEvent.type == EVENT_TYPE_TOUCH_UP) { |
||||
if (!g_touchActionExecutedAtDown) { |
||||
if (!g_touchActionExecuted) { |
||||
if (action == ACTION_ID_DRAG_OVERLAY) { |
||||
dragOverlay(touchEvent); |
||||
} else { |
||||
executeAction(widgetCursor, action); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void onWidgetTouch(const WidgetCursor &widgetCursor, Event &touchEvent) { |
||||
if (widgetCursor) { |
||||
if (touchEvent.type == EVENT_TYPE_TOUCH_DOWN) { |
||||
g_activeWidget = g_foundWidgetAtDown; |
||||
} |
||||
widgetCursor.currentState->onTouch(widgetCursor, touchEvent); |
||||
} |
||||
} |
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WidgetCursor &getFoundWidgetAtDown() { |
||||
return g_foundWidgetAtDown; |
||||
} |
||||
|
||||
void setFoundWidgetAtDown(WidgetCursor &widgetCursor) { |
||||
g_foundWidgetAtDown = widgetCursor; |
||||
} |
||||
|
||||
void clearFoundWidgetAtDown() { |
||||
g_foundWidgetAtDown = 0; |
||||
} |
||||
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
|
||||
enum EventType { |
||||
EVENT_TYPE_TOUCH_NONE, |
||||
EVENT_TYPE_TOUCH_DOWN, |
||||
EVENT_TYPE_TOUCH_MOVE, |
||||
EVENT_TYPE_TOUCH_UP, |
||||
|
||||
EVENT_TYPE_LONG_TOUCH, |
||||
EVENT_TYPE_EXTRA_LONG_TOUCH, |
||||
EVENT_TYPE_AUTO_REPEAT |
||||
}; |
||||
|
||||
struct Event { |
||||
uint32_t time; |
||||
EventType type; |
||||
int x; |
||||
int y; |
||||
}; |
||||
|
||||
void onTouchEvent(bool pressed, int x, int y, Event &lastEvent); |
||||
void processTouchEvent(Event &event); |
||||
|
||||
extern bool g_isLongTouch; |
||||
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <eez/gui/font.h> |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
namespace font { |
||||
|
||||
Font::Font() |
||||
: fontData(0) |
||||
{ |
||||
} |
||||
|
||||
Font::Font(const FontData *fontData_) |
||||
: fontData(fontData_) |
||||
{ |
||||
} |
||||
|
||||
uint8_t Font::getAscent() { |
||||
return fontData->ascent; |
||||
} |
||||
|
||||
uint8_t Font::getDescent() { |
||||
return fontData->descent; |
||||
} |
||||
|
||||
uint8_t Font::getHeight() { |
||||
return fontData->ascent + fontData->descent; |
||||
} |
||||
|
||||
const GlyphData *Font::getGlyph(int32_t encoding) { |
||||
auto start = fontData->encodingStart; |
||||
auto end = fontData->encodingEnd; |
||||
|
||||
uint32_t glyphIndex = 0; |
||||
if ((uint32_t)encoding < start || (uint32_t)encoding > end) { |
||||
// TODO use binary search
|
||||
uint32_t i; |
||||
for (i = 0; i < fontData->groups.count; i++) { |
||||
auto group = fontData->groups[i]; |
||||
if ((uint32_t)encoding >= group->encoding && (uint32_t)encoding < group->encoding + group->length) { |
||||
glyphIndex = group->glyphIndex + (encoding - group->encoding); |
||||
break; |
||||
} |
||||
} |
||||
if (i == fontData->groups.count) { |
||||
return nullptr; |
||||
} |
||||
} else { |
||||
glyphIndex = encoding - start; |
||||
} |
||||
|
||||
auto glyphData = fontData->glyphs[glyphIndex]; |
||||
|
||||
if (glyphData->dx == -128) { |
||||
// empty glyph
|
||||
return nullptr; |
||||
} |
||||
|
||||
return glyphData; |
||||
} |
||||
|
||||
} // namespace font
|
||||
} // namespace gui
|
||||
} // namespace eez
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* EEZ Modular Firmware |
||||
* Copyright (C) 2015-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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include <eez/gui/assets.h> |
||||
|
||||
namespace eez { |
||||
namespace gui { |
||||
namespace font { |
||||
|
||||
struct Font { |
||||
const FontData *fontData; |
||||
|
||||
Font(); |
||||
Font(const FontData *fontData_); |
||||
|
||||
explicit operator bool() const { |
||||
return fontData != nullptr; |
||||
} |
||||
|
||||
const GlyphData *getGlyph(int32_t encoding); |
||||
|
||||
uint8_t getAscent(); |
||||
uint8_t getDescent(); |
||||
uint8_t getHeight(); |
||||
}; |
||||
|
||||
} // namespace font
|
||||
} // namespace gui
|
||||
} // namespace eez
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue