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
main
Joost Wooning 2022-02-14 16:01:11 +01:00 committed by GitHub
parent 976c1652ce
commit 7909d33aea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 87 additions and 48 deletions

View File

@ -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({

View File

@ -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);

View File

@ -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++) {

View File

@ -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 = (
<div
key={key}
@ -208,14 +214,10 @@ export default class CanLog extends Component {
</strong>
</div>
<div className="signals-log-list-time">
<span>
[
{msgEntry.relTime.toFixed(3)}
]
</span>
<span>[{msgEntry.relTime.toFixed(3)}]</span>
</div>
<div className="signals-log-list-bytes">
<span className="t-mono">{msgEntry.hexData}</span>
{ msgHexs.map((hx, i) => <span key={ i } className="t-mono">{ hx }</span> )}
</div>
</div>
<div className="signals-log-list-item-body">

View File

@ -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);
}

View File

@ -90,7 +90,6 @@
width: 160px;
&-canvas {
width: 160px;
height: 15px;
}
}
&:not(.is-selected):hover {

View File

@ -19,6 +19,8 @@
}
&-bytes {
flex: 2;
display: flex;
flex-wrap: wrap;
}
&-header {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);

View File

@ -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);

View File

@ -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,
};