You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
378 lines
12 KiB
378 lines
12 KiB
|
|
/* |
|
* 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__
|
|
|