From 7909d33aead191fb84afe8b19ee72b015552d86c Mon Sep 17 00:00:00 2001 From: Joost Wooning Date: Mon, 14 Feb 2022 16:01:11 +0100 Subject: [PATCH] CAN FD support (#85) * variable length AddSignal matrix * nicer matrix rendering * fix selecting signal * correct size of new frame * MessageBytes canvas wider * multi line MessageBytes * fix tests * can log multirow * rebase fixes --- src/CanExplorer.js | 6 ++- src/__tests__/utils/dbc.test.js | 2 +- src/components/AddSignals.js | 31 +++++++++------ src/components/CanLog.js | 14 ++++--- src/components/MessageBytes.js | 50 ++++++++++++++++--------- src/components/Meta/meta.scss | 1 - src/components/SignalLog/signalLog.scss | 2 + src/models/can/dbc.js | 11 +++--- src/utils/dbc.js | 18 +++++++-- 9 files changed, 87 insertions(+), 48 deletions(-) diff --git a/src/CanExplorer.js b/src/CanExplorer.js index 3a68055..ffbed4e 100644 --- a/src/CanExplorer.js +++ b/src/CanExplorer.js @@ -966,7 +966,8 @@ export default class CanExplorer extends Component { onConfirmedSignalChange(message, signals) { const { dbc, dbcFilename } = this.state; - dbc.setSignals(message.address, { ...signals }); + const frameSize = DbcUtils.maxMessageSize(message); + dbc.setSignals(message.address, { ...signals }, frameSize); this.persistDbc({ dbcFilename, dbc }); @@ -1015,8 +1016,9 @@ export default class CanExplorer extends Component { showEditMessageModal(msgKey) { const msg = this.state.messages[msgKey]; + console.log(msg); if (!msg.frame) { - msg.frame = this.state.dbc.createFrame(msg.address); + msg.frame = this.state.dbc.createFrame(msg.address); // TODO frameSize } this.setState({ diff --git a/src/__tests__/utils/dbc.test.js b/src/__tests__/utils/dbc.test.js index 1832784..a6391ad 100644 --- a/src/__tests__/utils/dbc.test.js +++ b/src/__tests__/utils/dbc.test.js @@ -59,7 +59,7 @@ test('addCanMessage should add parsed can message with dbc containing message sp const messages = {}; // create dbc with message spec and signal for sample_message const dbc = new DBC(); - dbc.createFrame(SAMPLE_MESSAGE.address); + dbc.createFrame(SAMPLE_MESSAGE.address, 8); const signal = new Signal({ name: 'NEW_SIGNAL', startBit: 0, size: 8 }); dbc.addSignal(SAMPLE_MESSAGE.address, signal); diff --git a/src/components/AddSignals.js b/src/components/AddSignals.js index 50de3b9..07e4308 100644 --- a/src/components/AddSignals.js +++ b/src/components/AddSignals.js @@ -67,7 +67,8 @@ export default class AddSignals extends Component { highlightedSignal: null, dragStartBit: null, dragSignal: null, - dragCurrentBit: null + dragCurrentBit: null, + maxMessageBytes: 8, }; } @@ -81,6 +82,22 @@ export default class AddSignals extends Component { ); } + componentDidUpdate(prevProps) { + if (prevProps.message !== this.props.message) { + this.setState({ + maxMessageBytes: DbcUtils.maxMessageSize(this.props.message), + }); + } + + if (prevProps.message.address !== this.props.message.address || + prevProps.selectedMessageKey !== this.props.selectedMessageKey) + { + const signals = this.props.message.frame ? this.props.message.frame.signals : {}; + + this.setState({ signals: this.copySignals(signals) }, this.updateSignalStyles); + } + } + shouldComponentUpdate(nextProps, nextState) { return ( nextProps.message.hexData !== this.props.message.hexData @@ -131,16 +148,6 @@ export default class AddSignals extends Component { return signalStyles; } - componentDidUpdate(prevProps) { - if (prevProps.message.address !== this.props.message.address || - prevProps.selectedMessageKey !== this.props.selectedMessageKey) - { - const signals = this.props.message.frame ? this.props.message.frame.signals : {}; - - this.setState({ signals: this.copySignals(signals) }, this.updateSignalStyles); - } - } - signalForBit(bitIdx) { // bitIdx in [0,64) // returns instance of Signal @@ -426,7 +433,7 @@ export default class AddSignals extends Component { if (message.frame && message.frame.size) { rowCount = Math.floor((message.frame.size * 8) / 8); } else { - rowCount = 8; + rowCount = this.state.maxMessageBytes; } for (let i = 0; i < rowCount; i++) { diff --git a/src/components/CanLog.js b/src/components/CanLog.js index 0c65715..c5a12c9 100644 --- a/src/components/CanLog.js +++ b/src/components/CanLog.js @@ -191,6 +191,12 @@ export default class CanLog extends Component { const msgHasSignals = Object.keys(msgEntry.signals).length > 0; const hasSignalsClass = msgHasSignals ? 'has-signals' : null; const expandedClass = msgIsExpanded ? 'is-expanded' : null; + + const msgHexs = []; + for (let i = 0; i < msgEntry.data.length; i += 8) { + msgHexs.push(msgEntry.hexData.substring(i, Math.min(i + 8, msgEntry.data.length))); + } + const row = (
- -[ - {msgEntry.relTime.toFixed(3)} -] - + [{msgEntry.relTime.toFixed(3)}]
- {msgEntry.hexData} + { msgHexs.map((hx, i) => { hx } )}
diff --git a/src/components/MessageBytes.js b/src/components/MessageBytes.js index dd6daf1..9d88c60 100644 --- a/src/components/MessageBytes.js +++ b/src/components/MessageBytes.js @@ -1,6 +1,8 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import DbcUtils from '../utils/dbc'; + export default class MessageBytes extends Component { static propTypes = { seekTime: PropTypes.number.isRequired, @@ -14,7 +16,8 @@ export default class MessageBytes extends Component { this.state = { isVisible: true, lastMessageIndex: 0, - lastSeekTime: 0 + lastSeekTime: 0, + maxMessageBytes: 8, }; this.onVisibilityChange = this.onVisibilityChange.bind(this); @@ -22,8 +25,28 @@ export default class MessageBytes extends Component { this.updateCanvas = this.updateCanvas.bind(this); } + componentDidMount() { + this.componentDidUpdate({}, {}); + } + + componentDidUpdate(prevProps) { + if (prevProps.message !== this.props.message) { + const maxMessageBytes = DbcUtils.maxMessageSize(this.props.message, this.state.maxMessageBytes); + this.setState({ maxMessageBytes: maxMessageBytes }); + if (this.canvas) { + this.canvas.height = Math.ceil(maxMessageBytes / 8) * 15 * window.devicePixelRatio; + } + } + + if (prevProps.seekIndex !== this.props.seekIndex || + Math.floor(prevProps.seekTime * 60) !== Math.floor(this.props.seekTime * 60)) + { + this.updateCanvas(); + } + } + shouldComponentUpdate(nextProps, nextState) { - if (nextProps.live) { + if (nextProps.live && nextProps.message.entries.length) { const nextLastEntry = nextProps.message.entries[nextProps.message.entries.length - 1]; const curLastEntry = this.props.message.entries[ this.props.message.entries.length - 1 @@ -34,14 +57,6 @@ export default class MessageBytes extends Component { return nextProps.seekTime !== this.props.seekTime; } - componentDidUpdate(prevProps) { - if (prevProps.seekIndex !== this.props.seekIndex || - Math.floor(prevProps.seekTime * 60) !== Math.floor(this.props.seekTime * 60)) - { - this.updateCanvas(); - } - } - findMostRecentMessage(seekTime) { const { message } = this.props; const { lastMessageIndex, lastSeekTime } = this.state; @@ -91,17 +106,16 @@ export default class MessageBytes extends Component { for (let i = 0; i < message.byteStateChangeCounts.length; ++i) { const hexData = mostRecentMsg.hexData.substr(i * 2, 2); - ctx.fillStyle = message.byteColors[i]; - ctx.fillRect(i * 20, 0, 20, 15); + const x = (i % 8) * 20; + const y = Math.floor(i / 8) * 15; + + ctx.fillStyle = message.byteColors[i]; + ctx.fillRect(x, y, 20, 15); ctx.font = '12px Courier'; ctx.fillStyle = 'white'; - if (hexData) { - ctx.fillText(hexData, i * 20 + 2, 12); - } else { - ctx.fillText('-', i * 20 + 7, 12); - } + ctx.fillText(hexData ? hexData : '-', x + 2, y + 12); } } @@ -116,7 +130,7 @@ export default class MessageBytes extends Component { this.canvas = ref; this.canvas.width = 160 * window.devicePixelRatio; - this.canvas.height = 15 * window.devicePixelRatio; + this.canvas.height = Math.ceil(this.state.maxMessageBytes / 8) * 15 * window.devicePixelRatio; const ctx = this.canvas.getContext('2d'); ctx.scale(window.devicePixelRatio, window.devicePixelRatio); } diff --git a/src/components/Meta/meta.scss b/src/components/Meta/meta.scss index de46be1..a852122 100644 --- a/src/components/Meta/meta.scss +++ b/src/components/Meta/meta.scss @@ -90,7 +90,6 @@ width: 160px; &-canvas { width: 160px; - height: 15px; } } &:not(.is-selected):hover { diff --git a/src/components/SignalLog/signalLog.scss b/src/components/SignalLog/signalLog.scss index ee682ec..ffba27f 100644 --- a/src/components/SignalLog/signalLog.scss +++ b/src/components/SignalLog/signalLog.scss @@ -19,6 +19,8 @@ } &-bytes { flex: 2; + display: flex; + flex-wrap: wrap; } &-header { border-bottom: 1px solid rgba(0, 0, 0, 0.1); diff --git a/src/models/can/dbc.js b/src/models/can/dbc.js index 9bca846..5ad5820 100644 --- a/src/models/can/dbc.js +++ b/src/models/can/dbc.js @@ -174,25 +174,26 @@ export default class DBC { return {}; } - createFrame(msgId) { + createFrame(msgId, size=64) { + console.log(this.messages, msgId); const msg = new Frame({ name: this.nextNewFrameName(), id: msgId, - size: 8 + size: size, }); this.messages.set(msgId, msg); return msg; } - setSignals(msgId, signals) { - const msg = this.getMessageFrame(msgId); + setSignals(msgId, signals, frameSize) { + const msg = this.getMessageFrame(msgId); // TODO conform frameSize if (msg) { const newMsg = Object.assign(Object.create(msg), msg); newMsg.signals = signals; this.messages.set(msgId, newMsg); } else { - const msg = this.createFrame(msgId); + const msg = this.createFrame(msgId, frameSize); msg.signals = signals; this.messages.set(msgId, msg); diff --git a/src/utils/dbc.js b/src/utils/dbc.js index 66f0f46..b6762b4 100644 --- a/src/utils/dbc.js +++ b/src/utils/dbc.js @@ -146,7 +146,7 @@ function parseMessage(dbc, time, address, data, timeStart, lastParsedMessage) { hexData = Buffer.from(data).toString('hex'); } const msgSpec = dbc.getMessageFrame(address); - const msgSize = msgSpec ? msgSpec.size : 8; + const msgSize = msgSpec ? msgSpec.size : Math.max(8, data.length); const relTime = time - timeStart; const { @@ -171,7 +171,7 @@ function parseMessage(dbc, time, address, data, timeStart, lastParsedMessage) { } const BIG_ENDIAN_START_BITS = []; -for (let i = 0; i < 64; i += 8) { +for (let i = 0; i < 8 * 64; i += 8) { for (let j = 7; j > -1; j--) { BIG_ENDIAN_START_BITS.push(i + j); } @@ -195,6 +195,17 @@ function setMessageByteColors(message, maxByteStateChangeCount) { return message; } +function maxMessageSize(message, initial = 8) { + let max = initial; + for (const entry of message.entries) { + const data = Buffer.from(entry.hexData, 'hex'); + if (data.length > max) { + max = data.length; + } + } + return max; +} + export default { bigEndianBitIndex, addCanMessage, @@ -204,5 +215,6 @@ export default { reparseMessage, findMaxByteStateChangeCount, setMessageByteColors, - createMessageEntry + createMessageEntry, + maxMessageSize, };