diff --git a/packages/xod-arduino/src/formatTweakMessage.js b/packages/xod-arduino/src/formatTweakMessage.js new file mode 100644 index 00000000..f1363736 --- /dev/null +++ b/packages/xod-arduino/src/formatTweakMessage.js @@ -0,0 +1,34 @@ +import * as R from 'ramda'; + +import { unquote } from 'xod-func-tools'; +import * as XP from 'xod-project'; + +import { def } from './types'; + +import { byteLiteralToDecimal } from './templates'; + +export default def( + 'formatTweakMessage :: PatchPath -> NodeId -> DataValue -> String', + (nodeType, nodeId, value) => { + const prefix = `+XOD:${nodeId}`; + + switch (XP.getTweakType(nodeType)) { + case XP.PIN_TYPE.NUMBER: + return `${prefix}:${value}\r\n`; + case XP.PIN_TYPE.BOOLEAN: + return `${prefix}:${value === 'True' ? '1' : '0'}\r\n`; + case XP.PIN_TYPE.BYTE: + return `${prefix}:${byteLiteralToDecimal(value)}\r\n`; + case XP.PIN_TYPE.PULSE: + return `${prefix}\r\n`; + case XP.PIN_TYPE.STRING: + return R.compose( + s => `${prefix}:${s}\r\n`, + R.slice(0, XP.getStringTweakLength(nodeType)), + unquote + )(value); + default: + return ''; + } + } +); diff --git a/packages/xod-arduino/src/index.js b/packages/xod-arduino/src/index.js index e6658989..4bffc708 100644 --- a/packages/xod-arduino/src/index.js +++ b/packages/xod-arduino/src/index.js @@ -8,3 +8,5 @@ export { export { default as messages } from './messages'; export { LIVENESS } from './constants'; + +export { default as formatTweakMessage } from './formatTweakMessage'; diff --git a/packages/xod-arduino/src/templates.js b/packages/xod-arduino/src/templates.js index a3709e59..727441eb 100644 --- a/packages/xod-arduino/src/templates.js +++ b/packages/xod-arduino/src/templates.js @@ -100,6 +100,22 @@ const cppStringLiteral = def( ) ); +export const byteLiteralToDecimal = R.ifElse( + R.test(/(b|h|d)$/), + R.converge(parseInt, [ + R.init, + R.compose( + R.prop(R.__, { + b: 2, + h: 16, + d: 10, + }), + R.last + ), + ]), + plainDecimal => parseInt(plainDecimal, 10) +); + // Formats XOD byte literal into C++ byte literal // E.G. // 00011101b -> 0x1D @@ -117,21 +133,7 @@ const cppByteLiteral = def( R.concat('0x'), R.toUpper, x => x.toString(16), - R.ifElse( - R.test(/(b|h|d)$/), - R.converge(parseInt, [ - R.init, - R.compose( - R.prop(R.__, { - b: 2, - h: 16, - d: 10, - }), - R.last - ), - ]), - plainDecimal => parseInt(plainDecimal, 10) - ) + byteLiteralToDecimal ) ) ); diff --git a/packages/xod-client-electron/src/debugger/sendTweakValuesMiddleware.js b/packages/xod-client-electron/src/debugger/sendTweakValuesMiddleware.js new file mode 100644 index 00000000..9b537a6f --- /dev/null +++ b/packages/xod-client-electron/src/debugger/sendTweakValuesMiddleware.js @@ -0,0 +1,39 @@ +import * as R from 'ramda'; +import * as XP from 'xod-project'; +import client from 'xod-client'; +import { formatTweakMessage } from 'xod-arduino'; +import { ipcRenderer } from 'electron'; + +import { DEBUG_SERIAL_SEND } from '../shared/events'; + +export default ({ getState }) => next => action => { + const state = getState(); + const result = next(action); + + if ( + action.type === client.NODE_UPDATE_PROPERTY && + client.isSerialDebugRunning(state) + ) { + const { id: nodeId, value, patchPath } = action.payload; + const nodeType = R.compose( + XP.getNodeType, + XP.getNodeByIdUnsafe(nodeId), + XP.getPatchByPathUnsafe(patchPath), + client.getProject + )(state); + + if (XP.isTweakPath(nodeType)) { + const debuggerNodeId = R.compose( + R.prop(nodeId), + client.getInvertedDebuggerNodeIdsMap + )(state); + + ipcRenderer.send( + DEBUG_SERIAL_SEND, + formatTweakMessage(nodeType, debuggerNodeId, value) + ); + } + } + + return result; +}; diff --git a/packages/xod-client-electron/src/index.jsx b/packages/xod-client-electron/src/index.jsx index 0cf4ae4a..b623ccfa 100644 --- a/packages/xod-client-electron/src/index.jsx +++ b/packages/xod-client-electron/src/index.jsx @@ -8,6 +8,7 @@ import popupsReducer from './popups/reducer'; import uploadReducer from './upload/reducer'; import stopDebuggerOnTabCloseMiddleware from './debugger/stopDebuggerOnTabCloseMiddleware'; +import sendTweakValuesMiddleware from './debugger/sendTweakValuesMiddleware'; import autoupdateMiddleware from './view/autoupdateMiddleware'; import installLibMiddleware from './view/installLibMiddleware'; import arduinoDependenciesMiddleware from './arduinoDependencies/middleware'; @@ -18,6 +19,7 @@ const extraReducers = { }; const extraMiddlewares = [ + sendTweakValuesMiddleware, stopDebuggerOnTabCloseMiddleware, installLibMiddleware, autoupdateMiddleware, diff --git a/packages/xod-client/src/debugger/selectors.js b/packages/xod-client/src/debugger/selectors.js index 29e40116..c7656ee2 100644 --- a/packages/xod-client/src/debugger/selectors.js +++ b/packages/xod-client/src/debugger/selectors.js @@ -1,6 +1,6 @@ import * as R from 'ramda'; import { Maybe } from 'ramda-fantasy'; -import { foldMaybe, isAmong } from 'xod-func-tools'; +import { foldMaybe, isAmong, memoizeOnlyLast } from 'xod-func-tools'; import { createSelector } from 'reselect'; import { getCurrentTabId, @@ -90,6 +90,11 @@ export const getDebuggerNodeIdsMap = R.compose( getDebuggerState ); +export const getInvertedDebuggerNodeIdsMap = R.compose( + memoizeOnlyLast(R.invertObj), + getDebuggerNodeIdsMap +); + export const getWatchNodeValues = R.compose( R.prop('watchNodeValues'), getDebuggerState diff --git a/packages/xod-client/src/editor/containers/Patch/modes/debugging.jsx b/packages/xod-client/src/editor/containers/Patch/modes/debugging.jsx index a9dd1172..acac7050 100644 --- a/packages/xod-client/src/editor/containers/Patch/modes/debugging.jsx +++ b/packages/xod-client/src/editor/containers/Patch/modes/debugging.jsx @@ -16,6 +16,9 @@ const debuggingMode = R.merge(selectingMode, { onNodeDoubleClick(api, nodeId, patchPath) { if (patchPath === XP.NOT_IMPLEMENTED_IN_XOD_PATH) { api.props.actions.openImplementationEditor(); + } else if (XP.isConstantNodeType(patchPath) || XP.isTweakPath(patchPath)) { + // TODO: rename this action to something more suitable? + api.props.actions.selectConstantNodeValue(nodeId, api.props.patchPath); } else { api.props.actions.drillDown(patchPath, nodeId); } diff --git a/packages/xod-client/src/editor/containers/Patch/modes/selecting.jsx b/packages/xod-client/src/editor/containers/Patch/modes/selecting.jsx index 7589af50..b2cd484c 100644 --- a/packages/xod-client/src/editor/containers/Patch/modes/selecting.jsx +++ b/packages/xod-client/src/editor/containers/Patch/modes/selecting.jsx @@ -227,7 +227,8 @@ const selectingMode = { onNodeDoubleClick(api, nodeId, patchPath) { if (R.contains(patchPath, R.keys(XP.MANAGED_ATTACHMENT_FILENAMES))) { api.props.actions.openAttachmentEditor(patchPath); - } else if (XP.isConstantNodeType(patchPath)) { + } else if (XP.isConstantNodeType(patchPath) || XP.isTweakPath(patchPath)) { + // TODO: rename this action to something more suitable? api.props.actions.selectConstantNodeValue(nodeId, api.props.patchPath); } else { api.props.actions.switchPatch(patchPath); diff --git a/packages/xod-client/src/index.js b/packages/xod-client/src/index.js index 5bf991e2..26c75674 100644 --- a/packages/xod-client/src/index.js +++ b/packages/xod-client/src/index.js @@ -25,7 +25,7 @@ import { LOG_TAB_TYPE } from './debugger/constants'; import { MESSAGE_BUTTON_CLICKED } from './messages/actionTypes'; import { TAB_CLOSE, INSTALL_LIBRARIES_COMPLETE } from './editor/actionTypes'; -import { SAVE_ALL } from './project/actionTypes'; +import { SAVE_ALL, NODE_UPDATE_PROPERTY } from './project/actionTypes'; import * as EditorConstants from './editor/constants'; import * as UtilsConstants from './utils/constants'; @@ -82,7 +82,7 @@ export { LOG_TAB_TYPE } from './debugger/constants'; export { MESSAGE_BUTTON_CLICKED } from './messages/actionTypes'; export { TAB_CLOSE, INSTALL_LIBRARIES_COMPLETE } from './editor/actionTypes'; -export { SAVE_ALL } from './project/actionTypes'; +export { SAVE_ALL, NODE_UPDATE_PROPERTY } from './project/actionTypes'; export { SERIAL_SESSION_STARTED } from './debugger/actionTypes'; export * from './editor/selectors'; @@ -166,6 +166,7 @@ export default Object.assign( parseDebuggerMessage, TAB_CLOSE, SAVE_ALL, + NODE_UPDATE_PROPERTY, INSTALL_LIBRARIES_COMPLETE, MESSAGE_BUTTON_CLICKED, Messages: coreMessages, diff --git a/packages/xod-project/src/patchPathUtils.js b/packages/xod-project/src/patchPathUtils.js index 11833efc..36fe23c5 100644 --- a/packages/xod-project/src/patchPathUtils.js +++ b/packages/xod-project/src/patchPathUtils.js @@ -295,7 +295,15 @@ export const getSpecializationPatchPath = R.curry( // utils for tweak nodes // -const tweakPathRegExp = new RegExp('^xod/debug/tweak-'); +const tweakPathRegExp = new RegExp(`^xod/debug/tweak-(${dataTypes.join('|')})`); // :: PatchPath -> Boolean export const isTweakPath = R.test(tweakPathRegExp); + +export const getTweakType = R.pipe(R.match(tweakPathRegExp), R.nth(1)); + +export const getStringTweakLength = R.pipe( + R.match(/^xod\/debug\/tweak-string-(\d+)/), + R.nth(1), + n => parseInt(n, 10) +);