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.
761 lines
21 KiB
761 lines
21 KiB
2 years ago
|
/*
|
||
|
* 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
|