Browse Source

Removing eez adding eez-framework as submodule

dev-g
Goran Mahovlić 1 year ago
parent
commit
ceada3cc60
  1. 3
      .gitmodules
  2. 1
      Middlewares/eez-framework
  3. 0
      Middlewares/eez/README.md
  4. 202
      Middlewares/eez/core/alloc.cpp
  5. 53
      Middlewares/eez/core/alloc.h
  6. 58
      Middlewares/eez/core/debug.cpp
  7. 54
      Middlewares/eez/core/debug.h
  8. 211
      Middlewares/eez/core/eeprom.cpp
  9. 39
      Middlewares/eez/core/eeprom.h
  10. 32
      Middlewares/eez/core/encoder.h
  11. 61
      Middlewares/eez/core/hmi.cpp
  12. 33
      Middlewares/eez/core/hmi.h
  13. 285
      Middlewares/eez/core/keyboard.h
  14. 99
      Middlewares/eez/core/memory.cpp
  15. 84
      Middlewares/eez/core/memory.h
  16. 38
      Middlewares/eez/core/mouse.h
  17. 37
      Middlewares/eez/core/os.cpp
  18. 102
      Middlewares/eez/core/os.h
  19. 51
      Middlewares/eez/core/sound.h
  20. 30
      Middlewares/eez/core/step_values.h
  21. 309
      Middlewares/eez/core/unit.cpp
  22. 94
      Middlewares/eez/core/unit.h
  23. 43
      Middlewares/eez/core/utf8.h
  24. 921
      Middlewares/eez/core/util.cpp
  25. 209
      Middlewares/eez/core/util.h
  26. 66
      Middlewares/eez/core/value_types.h
  27. 142
      Middlewares/eez/flow/components.cpp
  28. 35
      Middlewares/eez/flow/components.h
  29. 110
      Middlewares/eez/flow/components/animate.cpp
  30. 77
      Middlewares/eez/flow/components/call_action.cpp
  31. 41
      Middlewares/eez/flow/components/call_action.h
  32. 36
      Middlewares/eez/flow/components/catch_error.cpp
  33. 57
      Middlewares/eez/flow/components/compare.cpp
  34. 41
      Middlewares/eez/flow/components/constant.cpp
  35. 57
      Middlewares/eez/flow/components/counter.cpp
  36. 72
      Middlewares/eez/flow/components/delay.cpp
  37. 37
      Middlewares/eez/flow/components/end.cpp
  38. 38
      Middlewares/eez/flow/components/error.cpp
  39. 40
      Middlewares/eez/flow/components/expr_eval.cpp
  40. 84
      Middlewares/eez/flow/components/input.cpp
  41. 38
      Middlewares/eez/flow/components/input.h
  42. 51
      Middlewares/eez/flow/components/is_true.cpp
  43. 100
      Middlewares/eez/flow/components/layout_view_widget.cpp
  44. 47
      Middlewares/eez/flow/components/log.cpp
  45. 102
      Middlewares/eez/flow/components/loop.cpp
  46. 36
      Middlewares/eez/flow/components/noop.cpp
  47. 31
      Middlewares/eez/flow/components/on_event.cpp
  48. 64
      Middlewares/eez/flow/components/output.cpp
  49. 43
      Middlewares/eez/flow/components/roller_widget.cpp
  50. 31
      Middlewares/eez/flow/components/roller_widget.h
  51. 53
      Middlewares/eez/flow/components/select_language.cpp
  52. 49
      Middlewares/eez/flow/components/set_page_direction.cpp
  53. 57
      Middlewares/eez/flow/components/set_variable.cpp
  54. 36
      Middlewares/eez/flow/components/set_variable.h
  55. 88
      Middlewares/eez/flow/components/show_keyboard.cpp
  56. 109
      Middlewares/eez/flow/components/show_keypad.cpp
  57. 52
      Middlewares/eez/flow/components/show_message_box.cpp
  58. 40
      Middlewares/eez/flow/components/show_page.cpp
  59. 31
      Middlewares/eez/flow/components/start.cpp
  60. 61
      Middlewares/eez/flow/components/switch.cpp
  61. 36
      Middlewares/eez/flow/components/switch.h
  62. 74
      Middlewares/eez/flow/components/watch_variable.cpp
  63. 378
      Middlewares/eez/flow/dashboard_api.cpp
  64. 29
      Middlewares/eez/flow/dashboard_api.h
  65. 760
      Middlewares/eez/flow/debugger.cpp
  66. 62
      Middlewares/eez/flow/debugger.h
  67. 221
      Middlewares/eez/flow/expression.cpp
  68. 66
      Middlewares/eez/flow/expression.h
  69. 331
      Middlewares/eez/flow/flow.cpp
  70. 58
      Middlewares/eez/flow/flow.h
  71. 444
      Middlewares/eez/flow/flow_defs_v3.h
  72. 77
      Middlewares/eez/flow/hooks.cpp
  73. 47
      Middlewares/eez/flow/hooks.h
  74. 1413
      Middlewares/eez/flow/operations.cpp
  75. 50
      Middlewares/eez/flow/operations.h
  76. 525
      Middlewares/eez/flow/private.cpp
  77. 117
      Middlewares/eez/flow/private.h
  78. 126
      Middlewares/eez/flow/queue.cpp
  79. 37
      Middlewares/eez/flow/queue.h
  80. 162
      Middlewares/eez/fs/fs.h
  81. 411
      Middlewares/eez/fs/stm32/fs.cpp
  82. 71
      Middlewares/eez/gui/action_impl.cpp
  83. 369
      Middlewares/eez/gui/animation.cpp
  84. 78
      Middlewares/eez/gui/animation.h
  85. 543
      Middlewares/eez/gui/app_context.cpp
  86. 146
      Middlewares/eez/gui/app_context.h
  87. 256
      Middlewares/eez/gui/assets.cpp
  88. 493
      Middlewares/eez/gui/assets.h
  89. 275
      Middlewares/eez/gui/assets_fix_offsets.cpp
  90. 1697
      Middlewares/eez/gui/data.cpp
  91. 761
      Middlewares/eez/gui/data.h
  92. 94
      Middlewares/eez/gui/display-private.h
  93. 987
      Middlewares/eez/gui/display.cpp
  94. 180
      Middlewares/eez/gui/display.h
  95. 856
      Middlewares/eez/gui/draw.cpp
  96. 60
      Middlewares/eez/gui/draw.h
  97. 273
      Middlewares/eez/gui/event.cpp
  98. 48
      Middlewares/eez/gui/event.h
  99. 81
      Middlewares/eez/gui/font.cpp
  100. 48
      Middlewares/eez/gui/font.h
  101. Some files were not shown because too many files have changed in this diff Show More

3
.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "Middlewares/eez-framework"]
path = Middlewares/eez-framework
url = https://github.com/eez-open/eez-framework.git

1
Middlewares/eez-framework

@ -0,0 +1 @@
Subproject commit d317ba7f91a27ac03b20dedb4d2584c61d2f11ae

0
Middlewares/eez/README.md

202
Middlewares/eez/core/alloc.cpp

@ -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

53
Middlewares/eez/core/alloc.h

@ -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

58
Middlewares/eez/core/debug.cpp

@ -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

54
Middlewares/eez/core/debug.h

@ -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

211
Middlewares/eez/core/eeprom.cpp

@ -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

39
Middlewares/eez/core/eeprom.h

@ -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

32
Middlewares/eez/core/encoder.h

@ -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

61
Middlewares/eez/core/hmi.cpp

@ -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

33
Middlewares/eez/core/hmi.h

@ -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

285
Middlewares/eez/core/keyboard.h

@ -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

99
Middlewares/eez/core/memory.cpp

@ -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

84
Middlewares/eez/core/memory.h

@ -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

38
Middlewares/eez/core/mouse.h

@ -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

37
Middlewares/eez/core/os.cpp

@ -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

102
Middlewares/eez/core/os.h

@ -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

51
Middlewares/eez/core/sound.h

@ -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

30
Middlewares/eez/core/step_values.h

@ -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

309
Middlewares/eez/core/unit.cpp

@ -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

94
Middlewares/eez/core/unit.h

@ -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

43
Middlewares/eez/core/utf8.h

@ -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

921
Middlewares/eez/core/util.cpp

@ -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

209
Middlewares/eez/core/util.h

@ -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

66
Middlewares/eez/core/value_types.h

@ -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
}

142
Middlewares/eez/flow/components.cpp

@ -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

35
Middlewares/eez/flow/components.h

@ -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

110
Middlewares/eez/flow/components/animate.cpp

@ -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

77
Middlewares/eez/flow/components/call_action.cpp

@ -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

41
Middlewares/eez/flow/components/call_action.h

@ -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

36
Middlewares/eez/flow/components/catch_error.cpp

@ -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

57
Middlewares/eez/flow/components/compare.cpp

@ -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

41
Middlewares/eez/flow/components/constant.cpp

@ -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

57
Middlewares/eez/flow/components/counter.cpp

@ -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

72
Middlewares/eez/flow/components/delay.cpp

@ -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

37
Middlewares/eez/flow/components/end.cpp

@ -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

38
Middlewares/eez/flow/components/error.cpp

@ -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

40
Middlewares/eez/flow/components/expr_eval.cpp

@ -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

84
Middlewares/eez/flow/components/input.cpp

@ -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

38
Middlewares/eez/flow/components/input.h

@ -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

51
Middlewares/eez/flow/components/is_true.cpp

@ -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

100
Middlewares/eez/flow/components/layout_view_widget.cpp

@ -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

47
Middlewares/eez/flow/components/log.cpp

@ -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

102
Middlewares/eez/flow/components/loop.cpp

@ -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

36
Middlewares/eez/flow/components/noop.cpp

@ -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

31
Middlewares/eez/flow/components/on_event.cpp

@ -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

64
Middlewares/eez/flow/components/output.cpp

@ -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

43
Middlewares/eez/flow/components/roller_widget.cpp

@ -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

31
Middlewares/eez/flow/components/roller_widget.h

@ -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

53
Middlewares/eez/flow/components/select_language.cpp

@ -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

49
Middlewares/eez/flow/components/set_page_direction.cpp

@ -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

57
Middlewares/eez/flow/components/set_variable.cpp

@ -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

36
Middlewares/eez/flow/components/set_variable.h

@ -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

88
Middlewares/eez/flow/components/show_keyboard.cpp

@ -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

109
Middlewares/eez/flow/components/show_keypad.cpp

@ -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

52
Middlewares/eez/flow/components/show_message_box.cpp

@ -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

40
Middlewares/eez/flow/components/show_page.cpp

@ -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

31
Middlewares/eez/flow/components/start.cpp

@ -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

61
Middlewares/eez/flow/components/switch.cpp

@ -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

36
Middlewares/eez/flow/components/switch.h

@ -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

74
Middlewares/eez/flow/components/watch_variable.cpp

@ -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

378
Middlewares/eez/flow/dashboard_api.cpp

@ -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__

29
Middlewares/eez/flow/dashboard_api.h

@ -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

760
Middlewares/eez/flow/debugger.cpp

@ -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

62
Middlewares/eez/flow/debugger.h

@ -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

221
Middlewares/eez/flow/expression.cpp

@ -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

66
Middlewares/eez/flow/expression.h

@ -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

331
Middlewares/eez/flow/flow.cpp

@ -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

58
Middlewares/eez/flow/flow.h

@ -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

444
Middlewares/eez/flow/flow_defs_v3.h

@ -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

77
Middlewares/eez/flow/hooks.cpp

@ -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

47
Middlewares/eez/flow/hooks.h

@ -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

1413
Middlewares/eez/flow/operations.cpp

File diff suppressed because it is too large Load Diff

50
Middlewares/eez/flow/operations.h

@ -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

525
Middlewares/eez/flow/private.cpp

@ -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

117
Middlewares/eez/flow/private.h

@ -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

126
Middlewares/eez/flow/queue.cpp

@ -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

37
Middlewares/eez/flow/queue.h

@ -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

162
Middlewares/eez/fs/fs.h

@ -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

411
Middlewares/eez/fs/stm32/fs.cpp

@ -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

71
Middlewares/eez/gui/action_impl.cpp

@ -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

369
Middlewares/eez/gui/animation.cpp

@ -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

78
Middlewares/eez/gui/animation.h

@ -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

543
Middlewares/eez/gui/app_context.cpp

@ -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

146
Middlewares/eez/gui/app_context.h

@ -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

256
Middlewares/eez/gui/assets.cpp

@ -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

493
Middlewares/eez/gui/assets.h

@ -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

275
Middlewares/eez/gui/assets_fix_offsets.cpp

@ -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

1697
Middlewares/eez/gui/data.cpp

File diff suppressed because it is too large Load Diff

761
Middlewares/eez/gui/data.h

@ -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

94
Middlewares/eez/gui/display-private.h

@ -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

987
Middlewares/eez/gui/display.cpp

@ -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

180
Middlewares/eez/gui/display.h

@ -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

856
Middlewares/eez/gui/draw.cpp

@ -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

60
Middlewares/eez/gui/draw.h

@ -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

273
Middlewares/eez/gui/event.cpp

@ -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

48
Middlewares/eez/gui/event.h

@ -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

81
Middlewares/eez/gui/font.cpp

@ -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

48
Middlewares/eez/gui/font.h

@ -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…
Cancel
Save