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.
 
 
 
 
 
 

760 lines
21 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/>.
*/
#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