can explorer progress; chffr free space check + build fix
commit
a40e982666
|
@ -0,0 +1,18 @@
|
|||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "can-explorer",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"aphrodite": "^1.2.1",
|
||||
"create-react-class": "^15.5.3",
|
||||
"int64-buffer": "^0.1.9",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^15.5.4",
|
||||
"react-dom": "^15.5.4",
|
||||
"react-infinite": "^0.11.0",
|
||||
"react-list": "^0.8.6",
|
||||
"react-measure": "^1.4.7",
|
||||
"react-vega": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"react-scripts": "0.9.5"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "python simple-cors-http-server.py & react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"esLintConfig": {
|
||||
"rules": {
|
||||
"no-use-before-define": "off"
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -0,0 +1,31 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tag above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start`.
|
||||
To create a production bundle, use `npm run build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env python2
|
||||
from SimpleHTTPServer import SimpleHTTPRequestHandler
|
||||
import BaseHTTPServer
|
||||
|
||||
class CORSRequestHandler (SimpleHTTPRequestHandler):
|
||||
def end_headers (self):
|
||||
self.send_header('Access-Control-Allow-Origin', '*')
|
||||
SimpleHTTPRequestHandler.end_headers(self)
|
||||
|
||||
if __name__ == '__main__':
|
||||
BaseHTTPServer.test(CORSRequestHandler, BaseHTTPServer.HTTPServer)
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
import { css, StyleSheet } from 'aphrodite/no-important';
|
||||
|
||||
import Meta from './components/meta';
|
||||
import Explorer from './components/explorer';
|
||||
import NumpyLoader from './utils/loadnpy';
|
||||
import CivicDbc from './civic-dbc'
|
||||
import {uint64BEToHex} from './models/can-msg-fmt';
|
||||
|
||||
const Int64LE = require('int64-buffer').Int64LE
|
||||
|
||||
export default class CanExplorer extends Component {
|
||||
static propTypes = {
|
||||
url: React.PropTypes.string,
|
||||
max: React.PropTypes.number,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
messages: {},
|
||||
selectedMessage: null,
|
||||
};
|
||||
|
||||
this.loadCanPart = this.loadCanPart.bind(this);
|
||||
}
|
||||
|
||||
parseMessage(time, address, data) {
|
||||
return {time: time,
|
||||
hexData: Buffer.from(data).toString('hex'),
|
||||
signals: CivicDbc.getSignalValues(address, data)}
|
||||
}
|
||||
|
||||
createMessageSpec(address, id, bus) {
|
||||
return {name: CivicDbc.getMessageName(address),
|
||||
address: address,
|
||||
id: id,
|
||||
bus: bus,
|
||||
signalSpecs: CivicDbc.getSignalSpecs(address),
|
||||
entries: []}
|
||||
}
|
||||
|
||||
loadCanPart(base, num, messages) {
|
||||
var urls = [ base+"/Log/"+num+"/can/t",
|
||||
base+"/Log/"+num+"/can/src",
|
||||
base+"/Log/"+num+"/can/address",
|
||||
base+"/Log/"+num+"/can/data"];
|
||||
|
||||
return new Promise((resolve) => {
|
||||
Promise.all(urls.map(NumpyLoader.promise)).then((da) => {
|
||||
for (var i = 0; i < da[0].data.length; i++) {
|
||||
var t = da[0].data[i];
|
||||
var src = Int64LE(da[1].data, i*8).toString(10);
|
||||
var address = Int64LE(da[2].data, i*8);
|
||||
var addressHexStr = address.toString(16);
|
||||
var id = src + ":" + addressHexStr;
|
||||
|
||||
var addressNum = address.toNumber();
|
||||
var data = da[3].data.slice(i*8, (i+1)*8);
|
||||
if (messages[id] === undefined) messages[id] = this.createMessageSpec(address.toNumber(), id, src);
|
||||
const msg = this.parseMessage(t, address.toNumber(), data);
|
||||
|
||||
messages[id].entries.push(msg);
|
||||
}
|
||||
resolve(messages)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fetchLocalMessages() {
|
||||
fetch('http://127.0.0.1:8000/src/dev-data/civic-messages.json').then((resp) => {
|
||||
resp.json().then((messages) => {
|
||||
Object.keys(messages).forEach((key) => {
|
||||
const msg = messages[key];
|
||||
|
||||
msg['id'] = msg.bus + ':' + msg.address.toString(16)
|
||||
messages[key] = msg;
|
||||
});
|
||||
this.setState({messages});
|
||||
})
|
||||
})
|
||||
}
|
||||
componentWillMount() {
|
||||
this.fetchLocalMessages();
|
||||
// This is currently way too slow. working with pre-processed CAN (see above)
|
||||
// to build out frontend before handling perf issues.
|
||||
|
||||
// const messages = {};
|
||||
// let promise = new Promise((resolve, reject) => {resolve({})});
|
||||
// for(var i = 2; i <= 3; i++) {
|
||||
// console.log(i);
|
||||
// promise = promise.then((partialMessages) => {
|
||||
// for(var id in partialMessages) {
|
||||
// if(messages[id] === undefined) messages[id] = partialMessages[id];
|
||||
// messages[id].entries = messages[id].entries.concat(partialMessages[id].entries);
|
||||
// }
|
||||
|
||||
// this.setState({messages})
|
||||
// console.log(messages)
|
||||
// return this.loadCanPart(this.props.url, i, messages)
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<div className={css(Styles.root)}>
|
||||
<Meta url={this.props.url}
|
||||
messages={this.state.messages}
|
||||
onMessageSelected={(msg) => {this.setState({selectedMessage: msg})}} />
|
||||
<Explorer
|
||||
url={this.props.url}
|
||||
messages={this.state.messages}
|
||||
selectedMessage={this.state.selectedMessage} />
|
||||
</div>)
|
||||
}
|
||||
}
|
||||
|
||||
const Styles = StyleSheet.create({
|
||||
root: {
|
||||
flexDirection: 'row',
|
||||
display: 'flex',
|
||||
}
|
||||
});
|
|
@ -0,0 +1,50 @@
|
|||
import DBC, {swapOrder} from '../../models/can/dbc';
|
||||
import Signal from '../../models/can/signal';
|
||||
const Uint64BE = require('int64-buffer').Uint64BE
|
||||
|
||||
const DBC_MESSAGE_DEF = `BO_ 228 STEERING_CONTROL: 5 ADAS
|
||||
SG_ STEER_TORQUE : 7|16@0- (1,0) [-3840|3840] "" EPS
|
||||
SG_ STEER_TORQUE_REQUEST : 23|1@0+ (1,0) [0|1] "" EPS
|
||||
SG_ SET_ME_X00 : 22|7@0+ (1,0) [0|127] "" EPS
|
||||
SG_ SET_ME_X00_2 : 31|8@0+ (1,0) [0|0] "" EPS
|
||||
SG_ CHECKSUM : 39|4@0+ (1,0) [0|15] "" EPS
|
||||
SG_ COUNTER : 33|2@0+ (1,0) [0|3] "" EPS`;
|
||||
|
||||
const steerTorqueSignal = new Signal({
|
||||
name: 'STEER_TORQUE',
|
||||
startBit: 7,
|
||||
size: 16,
|
||||
isLittleEndian: false,
|
||||
isSigned: true,
|
||||
factor: 1,
|
||||
offset: 0,
|
||||
min: -3840,
|
||||
max: 3840,
|
||||
unit: ""});
|
||||
|
||||
test('DBC parses steering control message', () => {
|
||||
const dbcParsed = new DBC(DBC_MESSAGE_DEF);
|
||||
const {signals} = dbcParsed.messages.get(228);
|
||||
|
||||
expect(Object.keys(signals).length).toBe(6);
|
||||
expect(signals['STEER_TORQUE'].equals(steerTorqueSignal)).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
test('swapOrder properly converts little endian to big endian', () => {
|
||||
const littleEndianHex = 'e2d62a0bd0d3b5e5';
|
||||
const bigEndianHex = 'e5b5d3d00b2ad6e2';
|
||||
|
||||
const littleEndianHexSwapped = swapOrder(littleEndianHex, 16, 2);
|
||||
|
||||
expect(littleEndianHexSwapped == bigEndianHex).toBe(true);
|
||||
});
|
||||
|
||||
test('DBC parses steer torque field from hex', () => {
|
||||
const dbc = new DBC(DBC_MESSAGE_DEF);
|
||||
|
||||
const hex = 'e2d62a0bd0d3b5e5';
|
||||
const value = dbc.valueForSignal(steerTorqueSignal, hex);
|
||||
|
||||
expect(value).toBe(-7466);
|
||||
});
|
|
@ -0,0 +1,37 @@
|
|||
import Signal from '../../models/can/signal';
|
||||
|
||||
const someSignalParams = {
|
||||
name: 'STEER_TORQUE',
|
||||
startBit: 7,
|
||||
size: 16,
|
||||
isLittleEndian: false,
|
||||
isSigned: true,
|
||||
factor: 1,
|
||||
offset: 0,
|
||||
min: -3840,
|
||||
max: 3840,
|
||||
unit: ""};
|
||||
|
||||
const someOtherSignalParams = {
|
||||
name: 'DIFFERENT_NAME',
|
||||
startBit: 0,
|
||||
size: 16,
|
||||
isLittleEndian: false,
|
||||
isSigned: true,
|
||||
factor: 1,
|
||||
offset: 0,
|
||||
min: -3840,
|
||||
max: 3840,
|
||||
unit: ""};
|
||||
|
||||
test('Signal.equals returns true for signals with identical properties', () => {
|
||||
const someSignal = new Signal(someSignalParams);
|
||||
const someEquivalentSignal = new Signal(someSignalParams);
|
||||
expect(someSignal.equals(someEquivalentSignal)).toBe(true);
|
||||
});
|
||||
|
||||
test('Signal.equals returns false for signals with different properties', () => {
|
||||
const someSignal = new Signal(someSignalParams);
|
||||
const differentSignal = new Signal(someOtherSignalParams);
|
||||
expect(someSignal.equals(differentSignal)).toBe(false);
|
||||
});
|
|
@ -0,0 +1,348 @@
|
|||
import DBC from './models/can/dbc';
|
||||
|
||||
const CivicDbc = new DBC(`
|
||||
VERSION ""
|
||||
|
||||
|
||||
NS_ :
|
||||
NS_DESC_
|
||||
CM_
|
||||
BA_DEF_
|
||||
BA_
|
||||
VAL_
|
||||
CAT_DEF_
|
||||
CAT_
|
||||
FILTER
|
||||
BA_DEF_DEF_
|
||||
EV_DATA_
|
||||
ENVVAR_DATA_
|
||||
SGTYPE_
|
||||
SGTYPE_VAL_
|
||||
BA_DEF_SGTYPE_
|
||||
BA_SGTYPE_
|
||||
SIG_TYPE_REF_
|
||||
VAL_TABLE_
|
||||
SIG_GROUP_
|
||||
SIG_VALTYPE_
|
||||
SIGTYPE_VALTYPE_
|
||||
BO_TX_BU_
|
||||
BA_DEF_REL_
|
||||
BA_REL_
|
||||
BA_DEF_DEF_REL_
|
||||
BU_SG_REL_
|
||||
BU_EV_REL_
|
||||
BU_BO_REL_
|
||||
SG_MUL_VAL_
|
||||
|
||||
BS_:
|
||||
|
||||
BU_: INTERCEPTOR EBCM NEO ADAS PCM EPS VSA SCM BDY XXX EPB
|
||||
|
||||
|
||||
BO_ 57 XXX_1: 3 XXX
|
||||
|
||||
BO_ 148 XXX_2: 8 XXX
|
||||
SG_ LAT_ACCEL : 7|10@0+ (0.02,-512) [-20|20] "m/s2" NEO
|
||||
SG_ LONG_ACCEL : 24|9@0- (-0.02,0) [-20|20] "m/s2" NEO
|
||||
|
||||
BO_ 228 STEERING_CONTROL: 5 ADAS
|
||||
SG_ STEER_TORQUE : 7|16@0- (1,0) [-3840|3840] "" EPS
|
||||
SG_ STEER_TORQUE_REQUEST : 23|1@0+ (1,0) [0|1] "" EPS
|
||||
SG_ SET_ME_X00 : 22|7@0+ (1,0) [0|127] "" EPS
|
||||
SG_ SET_ME_X00_2 : 31|8@0+ (1,0) [0|0] "" EPS
|
||||
SG_ CHECKSUM : 39|4@0+ (1,0) [0|15] "" EPS
|
||||
SG_ COUNTER : 33|2@0+ (1,0) [0|3] "" EPS
|
||||
|
||||
BO_ 304 GAS_PEDAL2: 8 PCM
|
||||
SG_ ENGINE_TORQUE_ESTIMATE : 7|16@0- (1,0) [-1000|1000] "Nm" NEO
|
||||
SG_ ENGINE_TORQUE_REQUEST : 23|16@0- (1,0) [-1000|1000] "Nm" NEO
|
||||
SG_ CAR_GAS : 39|8@0+ (1,0) [0|255] "" NEO
|
||||
|
||||
BO_ 330 STEERING_SENSORS: 8 EPS
|
||||
SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" NEO
|
||||
SG_ STEER_ANGLE_RATE : 23|16@0- (-1,0) [-3000|3000] "deg/s" NEO
|
||||
SG_ STEER_ANGLE_OFFSET : 39|8@0- (-0.1,0) [-128|127] "deg" NEO
|
||||
SG_ STEER_WHEEL_ANGLE : 47|16@0- (-0.1,0) [-500|500] "deg" NEO
|
||||
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 344 POWERTRAIN_DATA: 8 PCM
|
||||
SG_ XMISSION_SPEED : 7|16@0+ (0.002759506,0) [0|70] "m/s" NEO
|
||||
SG_ ENGINE_RPM : 23|16@0+ (1,0) [0|15000] "rpm" NEO
|
||||
SG_ XMISSION_SPEED2 : 39|16@0+ (0.002759506,0) [0|70] "m/s" NEO
|
||||
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 380 POWERTRAIN_DATA2: 8 PCM
|
||||
SG_ PEDAL_GAS : 7|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ ENGINE_RPM : 23|16@0+ (1,0) [0|15000] "rpm" NEO
|
||||
SG_ GAS_PRESSED : 39|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ ACC_STATUS : 38|1@0+ (1,0) [0|1] "rpm" NEO
|
||||
SG_ BOH_17C : 37|5@0+ (1,0) [0|1] "rpm" NEO
|
||||
SG_ BRAKE_LIGHTS_ON : 32|1@0+ (1,0) [0|1] "rpm" NEO
|
||||
SG_ BOH2_17C : 47|10@0+ (1,0) [0|1] "rpm" NEO
|
||||
SG_ BRAKE_PRESSED : 53|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ BOH3_17C : 52|5@0+ (1,0) [0|1] "rpm" NEO
|
||||
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 399 STEER_STATUS: 7 EPS
|
||||
SG_ STEER_TORQUE_SENSOR : 7|16@0- (1,0) [-31000|31000] "tbd" NEO
|
||||
SG_ STEER_TORQUE_MOTOR : 23|16@0- (1,0) [-31000|31000] "tbd" NEO
|
||||
SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" NEO
|
||||
SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 401 GEARBOX: 8 PCM
|
||||
SG_ GEAR_SHIFTER : 5|6@0+ (1,0) [0|63] "" NEO
|
||||
SG_ GEAR : 35|4@0+ (1,0) [0|15] "" NEO
|
||||
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 420 VSA_STATUS: 8 VSA
|
||||
SG_ USER_BRAKE : 7|16@0+ (0.015625,-1.609375) [0|1000] "" NEO
|
||||
SG_ ESP_DISABLED : 28|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 427 XXX_3: 3 VSA
|
||||
|
||||
BO_ 428 XXX_4: 8 XXX
|
||||
|
||||
BO_ 432 STANDSTILL: 7 VSA
|
||||
SG_ WHEELS_MOVING : 12|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ BRAKE_ERROR_1 : 11|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ BRAKE_ERROR_2 : 9|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 450 XXX_5: 8 EPB
|
||||
SG_ EPB_ACTIVE : 3|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ EPB_STATE : 29|2@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 464 WHEEL_SPEEDS: 8 VSA
|
||||
SG_ WHEEL_SPEED_FL : 7|15@0+ (0.002759506,0) [0|70] "m/s" NEO
|
||||
SG_ WHEEL_SPEED_FR : 8|15@0+ (0.002759506,0) [0|70] "m/s" NEO
|
||||
SG_ WHEEL_SPEED_RL : 25|15@0+ (0.002759506,0) [0|70] "m/s" NEO
|
||||
SG_ WHEEL_SPEED_RR : 42|15@0+ (0.002759506,0) [0|70] "m/s" NEO
|
||||
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 470 XXX_6: 2 VSA
|
||||
|
||||
BO_ 476 XXX_7: 7 XXX
|
||||
|
||||
BO_ 487 XXX_8: 4 VSA
|
||||
SG_ BRAKE_PRESSURE1 : 7|10@0+ (0.015625,-103) [0|1000] "" NEO
|
||||
SG_ BRAKE_PRESSURE2 : 9|10@0+ (0.015625,-103) [0|1000] "" NEO
|
||||
|
||||
BO_ 490 VEHICLE_DYNAMICS: 8 VSA
|
||||
SG_ LONG_ACCEL : 23|16@0- (0.0015384,0) [-20|20] "m/s2" NEO
|
||||
|
||||
BO_ 493 XXX_9: 5 VSA
|
||||
|
||||
BO_ 506 BRAKE_COMMAND: 8 ADAS
|
||||
SG_ COMPUTER_BRAKE : 7|10@0+ (0.003906248,0) [0|1] "" EBCM
|
||||
SG_ ZEROS_BOH : 13|5@0+ (1,0) [0|1] "" EBCM
|
||||
SG_ COMPUTER_BRAKE_REQUEST : 8|1@0+ (1,0) [0|1] "" EBCM
|
||||
SG_ CRUISE_BOH2 : 23|3@0+ (1,0) [0|1] "" EBCM
|
||||
SG_ CRUISE_OVERRIDE : 20|1@0+ (1,0) [0|1] "" EBCM
|
||||
SG_ CRUISE_BOH3 : 19|1@0+ (1,0) [0|1] "" EBCM
|
||||
SG_ CRUISE_FAULT_CMD : 18|1@0+ (1,0) [0|1] "" EBCM
|
||||
SG_ CRUISE_CANCEL_CMD : 17|1@0+ (1,0) [0|1] "" EBCM
|
||||
SG_ COMPUTER_BRAKE_REQUEST_2 : 16|1@0+ (1,0) [0|1] "" EBCM
|
||||
SG_ SET_ME_0X80 : 31|8@0+ (1,0) [0|1] "" EBCM
|
||||
SG_ BRAKE_LIGHTS : 39|1@0+ (1,0) [0|1] "" EBCM
|
||||
SG_ CRUISE_STATES : 38|7@0+ (1,0) [0|1] "" EBCM
|
||||
SG_ CHIME : 47|3@0+ (1,0) [0|7] "" EBCM
|
||||
SG_ ZEROS_BOH6 : 44|1@0+ (1,0) [0|1] "" EBCM
|
||||
SG_ FCW : 43|1@0+ (1,0) [0|3] "" EBCM
|
||||
SG_ ZEROS_BOH3 : 42|2@0+ (1,0) [0|0] "" EBCM
|
||||
SG_ FCW2 : 40|1@0+ (1,0) [0|0] "" EBCM
|
||||
SG_ ZEROS_BOH4 : 55|8@0+ (1,0) [0|0] "" EBCM
|
||||
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EBCM
|
||||
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" EBCM
|
||||
|
||||
BO_ 512 GAS_COMMAND: 3 NEO
|
||||
SG_ GAS_COMMAND : 7|16@0+ (0.253984064,-328) [0|1] "" INTERCEPTOR
|
||||
SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" INTERCEPTOR
|
||||
SG_ CHECKSUM : 19|4@0+ (1,0) [0|3] "" INTERCEPTOR
|
||||
|
||||
BO_ 513 GAS_SENSOR: 5 INTERCEPTOR
|
||||
SG_ INTERCEPTOR_GAS : 7|16@0+ (0.253984064,-328) [0|1] "" NEO
|
||||
SG_ INTERCEPTOR_GAS2 : 23|16@0+ (0.126992032,-656) [0|1] "" NEO
|
||||
SG_ COUNTER : 37|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ CHECKSUM : 35|4@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 545 XXX_10: 6 XXX
|
||||
|
||||
BO_ 597 ROUGH_WHEEL_SPEED: 8 VSA
|
||||
SG_ WHEEL_SPEED_FL : 7|8@0+ (1,0) [0|255] "mph" NEO
|
||||
SG_ WHEEL_SPEED_FR : 15|8@0+ (1,0) [0|255] "mph" NEO
|
||||
SG_ WHEEL_SPEED_RL : 23|8@0+ (1,0) [0|255] "mph" NEO
|
||||
SG_ WHEEL_SPEED_RR : 31|8@0+ (1,0) [0|255] "mph" NEO
|
||||
SG_ SET_TO_X55 : 39|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ SET_TO_X55 : 47|8@0+ (1,0) [0|255] "" NEO
|
||||
|
||||
BO_ 662 CRUISE_BUTTONS: 4 SCM
|
||||
SG_ CRUISE_BUTTONS : 7|3@0+ (1,0) [0|7] "" NEO
|
||||
SG_ CRUISE_SETTING : 3|2@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 773 SEATBELT_STATUS: 7 BDY
|
||||
SG_ SEATBELT_DRIVER_LAMP : 7|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ SEATBELT_DRIVER_LATCHED : 13|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 777 XXX_11: 8 XXX
|
||||
|
||||
BO_ 780 ACC_HUD: 8 ADAS
|
||||
SG_ PCM_SPEED : 7|16@0+ (0.002759506,0) [0|100] "m/s" BDY
|
||||
SG_ PCM_GAS : 23|7@0+ (1,0) [0|127] "" BDY
|
||||
SG_ ZEROS_BOH : 16|1@0+ (1,0) [0|255] "" BDY
|
||||
SG_ CRUISE_SPEED : 31|8@0+ (1,0) [0|255] "" BDY
|
||||
SG_ DTC_MODE : 39|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ BOH : 38|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ ACC_PROBLEM : 37|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ FCM_OFF : 36|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ BOH_2 : 35|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ FCM_PROBLEM : 34|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ RADAR_OBSTRUCTED : 33|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ ENABLE_MINI_CAR : 32|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ HUD_DISTANCE : 47|2@0+ (1,0) [0|3] "" BDY
|
||||
SG_ HUD_LEAD : 45|2@0+ (1,0) [0|3] "" BDY
|
||||
SG_ BOH_3 : 43|1@0+ (1,0) [0|3] "" BDY
|
||||
SG_ BOH_4 : 42|1@0+ (1,0) [0|3] "" BDY
|
||||
SG_ BOH_5 : 41|1@0+ (1,0) [0|3] "" BDY
|
||||
SG_ CRUISE_CONTROL_LABEL : 40|1@0+ (1,0) [0|3] "" BDY
|
||||
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" BDY
|
||||
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" BDY
|
||||
|
||||
BO_ 795 XXX_12: 8 XXX
|
||||
|
||||
BO_ 800 XXX_13: 8 XXX
|
||||
|
||||
BO_ 804 CRUISE: 8 PCM
|
||||
SG_ ENGINE_TEMPERATURE : 7|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ BOH : 15|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ TRIP_FUEL_CONSUMED : 23|16@0+ (1,0) [0|255] "" NEO
|
||||
SG_ CRUISE_SPEED_PCM : 39|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ BOH2 : 47|8@0- (1,0) [0|255] "" NEO
|
||||
SG_ BOH3 : 55|8@0+ (1,0) [0|255] "" NEO
|
||||
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 806 SCM_FEEDBACK: 8 SCM
|
||||
SG_ CMBS_BUTTON : 22|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ MAIN_ON : 28|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ RIGHT_BLINKER : 27|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ LEFT_BLINKER : 26|1@0+ (1,0) [0|1] "" NEO
|
||||
|
||||
BO_ 808 XXX_14: 8 XXX
|
||||
|
||||
BO_ 829 LKAS_HUD_2: 5 ADAS
|
||||
SG_ CAM_TEMP_HIGH : 7|1@0+ (1,0) [0|255] "" BDY
|
||||
SG_ BOH : 6|7@0+ (1,0) [0|127] "" BDY
|
||||
SG_ DASHED_LANES : 14|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ DTC : 13|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ LKAS_PROBLEM : 12|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ LKAS_OFF : 11|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ SOLID_LANES : 10|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ LDW_RIGHT : 9|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ STEERING_REQUIRED : 8|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ BOH : 23|2@0+ (1,0) [0|4] "" BDY
|
||||
SG_ LDW_PROBLEM : 21|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ BEEP : 17|2@0+ (1,0) [0|1] "" BDY
|
||||
SG_ LDW_ON : 28|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ LDW_OFF : 27|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ CLEAN_WINDSHIELD : 26|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ SET_ME_X48 : 31|8@0+ (1,0) [0|255] "" BDY
|
||||
SG_ COUNTER : 37|2@0+ (1,0) [0|3] "" BDY
|
||||
SG_ CHECKSUM : 35|4@0+ (1,0) [0|3] "" BDY
|
||||
|
||||
BO_ 862 XXX_15: 8 ADAS
|
||||
SG_ UI_ALERTS : 7|56@0+ (1,0) [0|127] "" BDY
|
||||
|
||||
BO_ 884 XXX_16: 8 XXX
|
||||
|
||||
BO_ 891 XXX_17: 8 XXX
|
||||
|
||||
BO_ 892 XXX_18: 8 XXX
|
||||
|
||||
BO_ 927 XXX_19: 8 ADAS
|
||||
SG_ ZEROS_BOH : 7|17@0+ (1,0) [0|127] "" BDY
|
||||
SG_ APPLY_BRAKES_FOR_CANC : 23|1@0+ (1,0) [0|15] "" BDY
|
||||
SG_ ZEROS_BOH2 : 22|1@0+ (1,0) [0|1] "" BDY
|
||||
SG_ RESUME_INSTRUCTION : 21|1@0+ (1,0) [0|15] "" BDY
|
||||
SG_ ACC_ALERTS : 20|5@0+ (1,0) [0|15] "" BDY
|
||||
SG_ ZEROS_BOH2 : 31|8@0+ (1,0) [0|127] "" BDY
|
||||
SG_ LEAD_SPEED : 39|9@0+ (1,0) [0|127] "" BDY
|
||||
SG_ LEAD_STATE : 46|3@0+ (1,0) [0|127] "" BDY
|
||||
SG_ LEAD_DISTANCE : 43|5@0+ (1,0) [0|31] "" BDY
|
||||
SG_ ZEROS_BOH3 : 54|7@0+ (1,0) [0|127] "" BDY
|
||||
|
||||
BO_ 929 XXX_20: 8 XXX
|
||||
|
||||
BO_ 985 XXX_21: 3 XXX
|
||||
|
||||
BO_ 1024 XXX_22: 5 XXX
|
||||
|
||||
BO_ 1027 XXX_23: 5 XXX
|
||||
|
||||
BO_ 1029 DOORS_STATUS: 8 BDY
|
||||
SG_ DOOR_OPEN_FL : 37|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ DOOR_OPEN_FR : 38|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ DOOR_OPEN_RL : 39|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ DOOR_OPEN_RR : 40|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" NEO
|
||||
|
||||
BO_ 1036 XXX_24: 8 XXX
|
||||
|
||||
BO_ 1039 XXX_25: 8 XXX
|
||||
|
||||
BO_ 1108 XXX_26: 8 XXX
|
||||
|
||||
BO_ 1302 XXX_27: 8 XXX
|
||||
|
||||
BO_ 1322 XXX_28: 5 XXX
|
||||
|
||||
BO_ 1361 XXX_29: 5 XXX
|
||||
|
||||
BO_ 1365 XXX_30: 5 XXX
|
||||
|
||||
BO_ 1424 XXX_31: 5 XXX
|
||||
|
||||
BO_ 1600 XXX_32: 5 XXX
|
||||
|
||||
BO_ 1601 XXX_33: 8 XXX
|
||||
|
||||
BO_ 1633 XXX_34: 8 XXX
|
||||
|
||||
BO_TX_BU_ 228 : NEO,ADAS;
|
||||
BO_TX_BU_ 506 : NEO,ADAS;
|
||||
BO_TX_BU_ 780 : NEO,ADAS;
|
||||
BO_TX_BU_ 829 : NEO,ADAS;
|
||||
BO_TX_BU_ 862 : NEO,ADAS;
|
||||
BO_TX_BU_ 927 : NEO,ADAS;
|
||||
|
||||
|
||||
CM_ SG_ 401 GEAR "10 = reverse, 11 = transition";
|
||||
CM_ SG_ 490 LONG_ACCEL "wheel speed derivative, noisy and zero snapping";
|
||||
CM_ SG_ 780 CRUISE_SPEED "255 = no speed";
|
||||
CM_ SG_ 804 CRUISE_SPEED_PCM "255 = no speed";
|
||||
CM_ SG_ 829 BEEP "beeps are pleasant, chimes are for warnngs etc...";
|
||||
VAL_ 399 STEER_STATUS 5 "fault" 4 "no_torque_alert_2" 2 "no_torque_alert_1" 0 "normal" ;
|
||||
VAL_ 401 GEAR_SHIFTER 32 "L" 16 "S" 8 "D" 4 "N" 2 "R" 1 "P" ;
|
||||
VAL_ 450 EPB_STATE 3 "engaged" 2 "disengaging" 1 "engaging" 0 "disengaged" ;
|
||||
VAL_ 506 CHIME 4 "double_chime" 3 "single_chime" 2 "continuous_chime" 1 "repeating_chime" 0 "no_chime" ;
|
||||
VAL_ 662 CRUISE_BUTTONS 7 "tbd" 6 "tbd" 5 "tbd" 4 "accel_res" 3 "decel_set" 2 "cancel" 1 "main" 0 "none" ;
|
||||
VAL_ 662 CRUISE_SETTING 3 "distance_adj" 2 "tbd" 1 "lkas_button" 0 "none" ;
|
||||
VAL_ 780 CRUISE_SPEED 255 "no_speed" 252 "stopped" ;
|
||||
VAL_ 780 HUD_LEAD 3 "acc_off" 2 "solid_car" 1 "dashed_car" 0 "no_car" ;
|
||||
VAL_ 806 CMBS_BUTTON 3 "pressed" 0 "released" ;
|
||||
VAL_ 829 BEEP 3 "single_beep" 2 "triple_beep" 1 "repeated_beep" 0 "no_beep" ;
|
||||
VAL_ 927 ACC_ALERTS 29 "esp_active_acc_canceled" 10 "b_pedal_applied" 9 "speed_too_low" 8 "speed_too_high" 7 "p_brake_applied" 6 "gear_no_d" 5 "seatbelt" 4 "too_steep_downhill" 3 "too_steep_uphill" 2 "too_close" 1 "no_vehicle_ahead" ;
|
||||
|
||||
`);
|
||||
export default CivicDbc;
|
|
@ -0,0 +1,135 @@
|
|||
import React, {Component} from 'react';
|
||||
import { StyleSheet, css } from 'aphrodite/no-important';
|
||||
import Vega from 'react-vega';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Signal from '../models/can/signal';
|
||||
import CanPlot from '../vega/CanPlot';
|
||||
|
||||
const spec = {
|
||||
"$schema": "https://vega.github.io/schema/vega/v3.0.json",
|
||||
"width": 500,
|
||||
"height": 200,
|
||||
"padding": 5,
|
||||
|
||||
|
||||
"data": [
|
||||
{
|
||||
"name": "table"
|
||||
}
|
||||
],
|
||||
|
||||
"scales": [
|
||||
{
|
||||
"name": "xscale",
|
||||
"type": "linear",
|
||||
"range": "width",
|
||||
"zero": false,
|
||||
"domain": {"data": "table", "field": "x"}
|
||||
},
|
||||
{
|
||||
"name": "yscale",
|
||||
"type": "linear",
|
||||
"range": "height",
|
||||
"zero": true,
|
||||
"domain": {"data": "table", "field": "y"}
|
||||
}
|
||||
],
|
||||
|
||||
"axes": [
|
||||
{"orient": "bottom", "scale": "xscale"},
|
||||
{"orient": "left", "scale": "yscale"}
|
||||
],
|
||||
|
||||
"marks": [
|
||||
{
|
||||
"type": "line",
|
||||
"from": {"data": "table"},
|
||||
"encode": {
|
||||
"enter": {
|
||||
"x": {"scale": "xscale", "field": "x"},
|
||||
"y": {"scale": "yscale", "field": "y"},
|
||||
},
|
||||
"hover": {
|
||||
"fillOpacity": {"value": 0.5}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
export default class CanGraph extends Component {
|
||||
static propTypes = {
|
||||
data: PropTypes.array,
|
||||
messageName: PropTypes.string,
|
||||
signalSpec: PropTypes.instanceOf(Signal),
|
||||
segment: PropTypes.array
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onNewView = this.onNewView.bind(this);
|
||||
}
|
||||
|
||||
segmentIsNew(newSegment) {
|
||||
return newSegment.length != this.props.segment.length
|
||||
|| !(newSegment.every((val, idx) => this.props.segment[idx] == val));
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
if(this.view) {
|
||||
// only update if segment is new
|
||||
if(this.segmentIsNew(nextProps.segment)) {
|
||||
if(nextProps.segment.length > 0) {
|
||||
// Set segmented domain
|
||||
this.view.signal('segment', nextProps.segment)
|
||||
} else {
|
||||
// Reset segment to full domain
|
||||
const xVals = this.props.data.map((d) => d.x);
|
||||
const min = Math.min.apply(null, xVals);
|
||||
const max = Math.max.apply(null, xVals);
|
||||
this.view.signal('segment', [min, max]);
|
||||
}
|
||||
this.view.run();
|
||||
}
|
||||
}
|
||||
|
||||
return nextProps.data.length != this.props.data.length;
|
||||
}
|
||||
|
||||
onNewView(view) {
|
||||
this.view = view;
|
||||
if(this.props.segment.length > 0) {
|
||||
view.signal('segment', this.props.segment);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<div className={css(Styles.root)}>
|
||||
<p className={css(Styles.messageName)}>{this.props.messageName}</p>
|
||||
<p className={css(Styles.signalName)}>{this.props.signalSpec.name}</p>
|
||||
<CanPlot logLevel={0}
|
||||
data={{table: this.props.data}}
|
||||
onNewView={this.onNewView}
|
||||
/>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
||||
const Styles = StyleSheet.create({
|
||||
root: {
|
||||
borderBottomWidth: '1px',
|
||||
borderColor: 'gray',
|
||||
},
|
||||
messageName: {
|
||||
fontSize: 12,
|
||||
color: 'rgba(0,0,0,0.5)',
|
||||
margin: 0
|
||||
},
|
||||
signalName: {
|
||||
fontSize: 16,
|
||||
margin: 0
|
||||
}
|
||||
});
|
|
@ -0,0 +1,44 @@
|
|||
import React, {Component} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StyleSheet, css } from 'aphrodite/no-important';
|
||||
|
||||
import CanHistogramPlot from '../vega/CanHistogramPlot';
|
||||
|
||||
export default class CanHistogram extends Component {
|
||||
static propTypes = {
|
||||
message: PropTypes.object,
|
||||
onSegmentChanged: PropTypes.func
|
||||
};
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<div className={css(Styles.root)}>
|
||||
{this.props.message ?
|
||||
(<div>
|
||||
<CanHistogramPlot
|
||||
logLevel={0}
|
||||
data={{points: this.props.message.entries}}
|
||||
onSignalSegment={(signal, segment) => {this.props.onSegmentChanged(segment)}}
|
||||
/>
|
||||
<p className={css(Styles.label)}>{this.props.message.name} per time</p>
|
||||
</div>)
|
||||
: null}
|
||||
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
||||
const Styles = StyleSheet.create({
|
||||
root: {
|
||||
borderBottom: '1px solid rgba(0,0,0,0.9)',
|
||||
borderColor: 'gray',
|
||||
width: '1000px'
|
||||
},
|
||||
label: {
|
||||
textAlign: 'center',
|
||||
color: 'rgba(0,0,0,0.9)',
|
||||
margin: 0
|
||||
}
|
||||
});
|
|
@ -0,0 +1,236 @@
|
|||
import React, {Component} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactList from 'react-list';
|
||||
import Measure from 'react-measure';
|
||||
|
||||
import { StyleSheet, css } from 'aphrodite/no-important';
|
||||
import { formatMsgDec, formatMsgHex } from '../models/can-msg-fmt';
|
||||
|
||||
export default class CanLog extends Component {
|
||||
static ITEMS_PER_PAGE = 50;
|
||||
|
||||
static propTypes = {
|
||||
plottedSignals: PropTypes.array,
|
||||
onSignalUnplotPressed: PropTypes.func,
|
||||
onSignalPlotPressed: PropTypes.func
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
// only want to display up to length elements at a time
|
||||
// offset, length
|
||||
|
||||
this.state = {
|
||||
offset: 0,
|
||||
length: 0,
|
||||
msgDisplayFormat: 'name',
|
||||
expandedMessages: [],
|
||||
messageHeights: []
|
||||
}
|
||||
|
||||
this.onChoicePress = this.onChoicePress.bind(this);
|
||||
this.messageRow = this.messageRow.bind(this);
|
||||
this.addDisplayedMessages = this.addDisplayedMessages.bind(this);
|
||||
this.renderMessage = this.renderMessage.bind(this);
|
||||
this.renderTable = this.renderTable.bind(this);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if(nextProps.data) {
|
||||
this.addDisplayedMessages();
|
||||
}
|
||||
}
|
||||
|
||||
addDisplayedMessages() {
|
||||
const {length, messageHeights} = this.state;
|
||||
const newLength = length + CanLog.ITEMS_PER_PAGE;
|
||||
for(let i = length; i < newLength; i++) {
|
||||
messageHeights.push(Styles.dataRow.height);
|
||||
}
|
||||
|
||||
this.setState({length: newLength, messageHeights});
|
||||
}
|
||||
|
||||
onChoicePress(fmt) {
|
||||
this.setState({msgDisplayFormat: fmt})
|
||||
}
|
||||
|
||||
expandMessage(msg, msgIdx) {
|
||||
// const {messageHeights} = this.state;
|
||||
// messageHeights[msgIdx] = TODO dynamic height calc if message expanded.
|
||||
// Also could pre-compute height of each message Id instead of row (as signals are consistent), which would be cheaper.
|
||||
this.setState({expandedMessages: this.state.expandedMessages.concat([msg.time])})
|
||||
}
|
||||
|
||||
collapseMessage(msg, msgIdx) {
|
||||
this.setState({expandedMessages: this.state.expandedMessages
|
||||
.filter((expMsgTime) => expMsgTime !== msg.time)})
|
||||
}
|
||||
|
||||
isSignalPlotted(msgId, signalName) {
|
||||
const plottedSignal = this.props.plottedSignals.find((signal) => signal.messageId == msgId && signal.name == signalName);
|
||||
return plottedSignal !== undefined;
|
||||
}
|
||||
|
||||
expandedMessage(msg) {
|
||||
return (<div className={css(Styles.row, Styles.signalRow)} key={msg.time + '-expanded'}>
|
||||
<div className={css(Styles.col)}>
|
||||
<div className={css(Styles.signalCol)}>
|
||||
<table>
|
||||
<tbody>
|
||||
{Object.entries(msg.signals).map(([name, value]) => {
|
||||
return [name, value, this.isSignalPlotted(this.props.data.id, name)]
|
||||
}).sort(([name1, value1, isPlotted1], [name2, value2, isPlotted2]) => {
|
||||
// Display plotted signals first
|
||||
if(isPlotted1 && !isPlotted2) {
|
||||
return -1;
|
||||
} else if(isPlotted1 && isPlotted2) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}).map(([name, value, isPlotted]) => {
|
||||
const {unit} = this.props.data.signalSpecs[name];
|
||||
return (<tr key={name}>
|
||||
<td>{name}</td>
|
||||
<td>{value} {unit}</td>
|
||||
{isPlotted ?
|
||||
<td className={css(Styles.plotSignal)}
|
||||
onClick={() => {this.props.onSignalUnplotPressed(this.props.data.id, name)}}>[unplot]</td>
|
||||
:
|
||||
<td className={css(Styles.plotSignal)}
|
||||
onClick={() => {this.props.onSignalPlotPressed(this.props.data.id, name)}}>[plot]</td>
|
||||
}
|
||||
</tr>);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>)
|
||||
}
|
||||
|
||||
isMessageExpanded(msg) {
|
||||
return this.state.expandedMessages.indexOf(msg.time) !== -1;
|
||||
}
|
||||
|
||||
messageRow(msg, key) {
|
||||
const msgIsExpanded = this.isMessageExpanded(msg);
|
||||
|
||||
const row = [<div key={key}
|
||||
className={css(Styles.dataRow, Styles.row)}
|
||||
onClick={() => {
|
||||
if(msgIsExpanded) {
|
||||
this.collapseMessage(msg);
|
||||
} else {
|
||||
this.expandMessage(msg);
|
||||
}
|
||||
}}>
|
||||
{msgIsExpanded ? <div className={css(Styles.col)}>↑</div>
|
||||
:
|
||||
<div className={css(Styles.col)}>↓</div>}
|
||||
<div className={css(Styles.col, Styles.timefieldCol)}>{msg.time}</div>
|
||||
<div className={css(Styles.col, Styles.dataCol)}>{this.state.msgDisplayFormat == 'name' ? this.props.data.name : msg.hexData}</div>
|
||||
</div>];
|
||||
|
||||
if(msgIsExpanded) {
|
||||
row.push(this.expandedMessage(msg));
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
renderMessage(index, key) {
|
||||
return this.messageRow(this.props.data.entries[this.state.offset + index], key);
|
||||
}
|
||||
|
||||
renderTable(items, ref) {
|
||||
return (<div className={css(Styles.root)}>
|
||||
<div className={css(Styles.row)}>
|
||||
<div className={css(Styles.col, Styles.dropdownCol)}> </div>
|
||||
<div className={css(Styles.col, Styles.timefieldCol)}>Time</div>
|
||||
<div className={css(Styles.dataCol)}>
|
||||
Message
|
||||
(<span className={css(Styles.messageFormatChoice,
|
||||
(this.state.msgDisplayFormat == 'name' ? Styles.messageFormatChoiceSelected
|
||||
: Styles.messageFormatChoiceUnselected))}
|
||||
onClick={() => {this.onChoicePress('name')}}>Name</span>
|
||||
<span> / </span>
|
||||
<span className={css(Styles.messageFormatChoice,
|
||||
(this.state.msgDisplayFormat == 'hex' ? Styles.messageFormatChoiceSelected
|
||||
: Styles.messageFormatChoiceUnselected))}
|
||||
onClick={() => {this.onChoicePress('hex')}}>Hex</span>)
|
||||
</div>
|
||||
</div>
|
||||
<div className={css(Styles.tableRowGroup)}
|
||||
ref={ref}>
|
||||
{items}
|
||||
</div>
|
||||
</div>)
|
||||
}
|
||||
|
||||
render() {
|
||||
return <ReactList
|
||||
itemRenderer={this.renderMessage}
|
||||
itemsRenderer={this.renderTable}
|
||||
length={this.props.data ? this.props.data.entries.length : 0}
|
||||
pageSize={50}
|
||||
type='variable' />;
|
||||
}
|
||||
}
|
||||
|
||||
const Styles = StyleSheet.create({
|
||||
root: {
|
||||
borderBottomWidth: '1px',
|
||||
borderColor: 'gray',
|
||||
width: '100%',
|
||||
display: 'table',
|
||||
tableLayout: 'fixed'
|
||||
},
|
||||
row: {
|
||||
display: 'table-row',
|
||||
width: 'auto',
|
||||
clear: 'both',
|
||||
},
|
||||
dataRow: {
|
||||
cursor: 'pointer',
|
||||
},
|
||||
tableRowGroup: {
|
||||
display: 'table-row-group'
|
||||
},
|
||||
signalCol: {
|
||||
width: '1px'
|
||||
},
|
||||
col: {
|
||||
display: 'table-cell',
|
||||
},
|
||||
dropdownCol: {
|
||||
width: '10px',
|
||||
padding: 0,
|
||||
margin: 0
|
||||
},
|
||||
timefieldCol: {
|
||||
|
||||
},
|
||||
dataCol: {
|
||||
|
||||
},
|
||||
messageFormatHeader: {
|
||||
|
||||
},
|
||||
messageFormatChoice: {
|
||||
cursor: 'pointer',
|
||||
},
|
||||
messageFormatChoiceSelected: {
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
messageFormatChoiceUnselected: {
|
||||
color: 'gray'
|
||||
},
|
||||
plotSignal: {
|
||||
cursor: 'pointer',
|
||||
':hover': {
|
||||
textDecoration: 'underline'
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,17 @@
|
|||
import React, {Component} from 'react';
|
||||
|
||||
import { StyleSheet, css } from 'aphrodite/no-important';
|
||||
|
||||
export default class NearestFrame extends Component {
|
||||
render() {
|
||||
return (<div className={css(Styles.root)}>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
||||
const Styles = StyleSheet.create({
|
||||
root: {
|
||||
borderBottomWidth: '1px',
|
||||
borderColor: 'gray',
|
||||
}
|
||||
});
|
|
@ -0,0 +1,111 @@
|
|||
import React, {Component} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { StyleSheet, css } from 'aphrodite/no-important';
|
||||
|
||||
import CanHistogram from './CanHistogram';
|
||||
import CanGraph from './CanGraph';
|
||||
import NearestFrame from './NearestFrame';
|
||||
import CanLog from './CanLog';
|
||||
|
||||
export default class Explorer extends Component {
|
||||
static propTypes = {
|
||||
selectedMessage: PropTypes.string,
|
||||
url: PropTypes.string,
|
||||
messages: PropTypes.objectOf(PropTypes.object)
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
plottedSignals: [],
|
||||
segment: []
|
||||
}
|
||||
this.onSignalPlotPressed = this.onSignalPlotPressed.bind(this);
|
||||
this.onSignalUnplotPressed = this.onSignalUnplotPressed.bind(this);
|
||||
this.onSegmentChanged = this.onSegmentChanged.bind(this);
|
||||
}
|
||||
|
||||
graphData(msg, signalName) {
|
||||
if(!msg) return null;
|
||||
|
||||
return msg.entries.map((entry) => {
|
||||
return {x: entry.time,
|
||||
y: entry.signals[signalName],
|
||||
unit: msg.signalSpecs[signalName].unit}
|
||||
});
|
||||
}
|
||||
|
||||
onSignalPlotPressed(messageId, name) {
|
||||
const {plottedSignals} = this.state;
|
||||
this.setState({plottedSignals: plottedSignals.concat([{messageId, name}])})
|
||||
}
|
||||
|
||||
onSignalUnplotPressed(messageId, name) {
|
||||
const {plottedSignals} = this.state;
|
||||
const newPlottedSignals = plottedSignals.filter((signal) => !(signal.messageId == messageId && signal.name == name));
|
||||
|
||||
this.setState({plottedSignals: newPlottedSignals})
|
||||
}
|
||||
|
||||
onSegmentChanged(segment) {
|
||||
if(Array.isArray(segment)) {
|
||||
this.setState({segment})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<div className={css(Styles.root)}>
|
||||
<CanHistogram
|
||||
message={this.props.messages[this.props.selectedMessage]}
|
||||
onSegmentChanged={this.onSegmentChanged}
|
||||
/>
|
||||
<div className={css(Styles.dataContainer)}>
|
||||
<div className={css(Styles.left)}>
|
||||
<CanLog data={this.props.messages[this.props.selectedMessage]}
|
||||
plottedSignals={this.state.plottedSignals}
|
||||
onSignalPlotPressed={this.onSignalPlotPressed}
|
||||
onSignalUnplotPressed={this.onSignalUnplotPressed} />
|
||||
</div>
|
||||
<div className={css(Styles.right)}>
|
||||
{this.state.plottedSignals.map(({messageId, name}) => {
|
||||
const msg = this.props.messages[messageId];
|
||||
return <CanGraph key={messageId + '_' + name}
|
||||
messageName={msg.name}
|
||||
signalSpec={msg.signalSpecs[name]}
|
||||
segment={this.state.segment}
|
||||
data={this.graphData(msg, name)} />
|
||||
})}
|
||||
<NearestFrame messages={this.props.messages}
|
||||
selectedMessage={this.props.selectedMessage}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
||||
const Styles = StyleSheet.create({
|
||||
root: {
|
||||
flexDirection: 'column',
|
||||
flex: 4,
|
||||
width: '100%',
|
||||
},
|
||||
dataContainer: {
|
||||
paddingTop: '10px',
|
||||
paddingLeft: '10px',
|
||||
flexDirection: 'row',
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
height: '100vh'
|
||||
},
|
||||
left: {
|
||||
flex: '2 3 auto',
|
||||
overflow: 'auto'
|
||||
},
|
||||
right: {
|
||||
flex: '4 1',
|
||||
}
|
||||
})
|
|
@ -0,0 +1,112 @@
|
|||
import React, {Component} from 'react';
|
||||
|
||||
import { StyleSheet, css } from 'aphrodite/no-important';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class Meta extends Component {
|
||||
static propTypes = {
|
||||
onMessageSelected: PropTypes.func,
|
||||
url: PropTypes.string,
|
||||
messages: PropTypes.objectOf(PropTypes.object)
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
filterText: 'Filter'
|
||||
};
|
||||
this.onFilterChanged = this.onFilterChanged.bind(this);
|
||||
this.onFilterFocus = this.onFilterFocus.bind(this);
|
||||
this.msgKeyFilter = this.msgKeyFilter.bind(this);
|
||||
}
|
||||
|
||||
onFilterChanged(e) {
|
||||
this.setState({filterText: e.target.value})
|
||||
}
|
||||
|
||||
onFilterFocus(e) {
|
||||
if(this.state.filterText == 'Filter') {
|
||||
this.setState({filterText: ''})
|
||||
}
|
||||
}
|
||||
|
||||
msgKeyFilter(key) {
|
||||
const {filterText} = this.state;
|
||||
const msgName = this.props.messages[key].name || '';
|
||||
|
||||
return (filterText == 'Filter'
|
||||
|| filterText == ''
|
||||
|| key.toLowerCase().indexOf(filterText.toLowerCase()) !== -1
|
||||
|| msgName.toLowerCase().indexOf(filterText.toLowerCase()) !== -1);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={css(Styles.root)}>
|
||||
<div>
|
||||
<span className={css(Styles.titleText)}>
|
||||
comma cabana
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<img src="http://www.westingrandcayman.com/wp-content/uploads/2017/01/westin-grand-cayman-cabana-luxury.jpg" height="133" />
|
||||
</div>
|
||||
<div className={css(Styles.routeMeta)}>
|
||||
<p>{this.props.url.match(/comma-([a-zA-Z0-9]+)/)[1]}</p>
|
||||
<p>{this.props.url.match(/_(.+)/)[1]}</p>
|
||||
</div>
|
||||
<div>
|
||||
<input type="text"
|
||||
defaultValue="Filter"
|
||||
value={this.state.filterText}
|
||||
onFocus={this.onFilterFocus}
|
||||
onChange={this.onFilterChanged} />
|
||||
<ul className={css(Styles.messageList)}>
|
||||
{Object.keys(this.props.messages)
|
||||
.filter(this.msgKeyFilter)
|
||||
.sort()
|
||||
.map((key) => (
|
||||
<li onClick={() => {this.props.onMessageSelected(key)}}
|
||||
key={key}
|
||||
className={css(Styles.message)}>{this.props.messages[key].name} ({key})</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const Styles = StyleSheet.create({
|
||||
root: {
|
||||
maxWidth: 225,
|
||||
padding: 10,
|
||||
flex: 1,
|
||||
borderColor: 'gray',
|
||||
borderRight: 'solid',
|
||||
borderRightWidth: 2,
|
||||
},
|
||||
titleText: {
|
||||
fontFamily: 'monospace',
|
||||
paddingRight: 10,
|
||||
fontSize: 24
|
||||
},
|
||||
routeMeta: {
|
||||
borderBottomWidth: '1px',
|
||||
borderColor: 'grey',
|
||||
'*': {
|
||||
display: 'inline-block'
|
||||
}
|
||||
},
|
||||
message: {
|
||||
cursor: 'pointer',
|
||||
':hover' : {
|
||||
backgroundColor: 'rgba(0,0,0,0.1)'
|
||||
},
|
||||
marginTop: 5
|
||||
},
|
||||
messageList: {
|
||||
margin: 0,
|
||||
padding: 0
|
||||
},
|
||||
});
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,16 @@
|
|||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
#root {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import CanExplorer from './CanExplorer';
|
||||
import './index.css';
|
||||
|
||||
ReactDOM.render(
|
||||
<CanExplorer
|
||||
url={"https://s3-us-west-2.amazonaws.com/chffrprivate2/v1/comma-2d7526b1faf1a2ca/586e2db5b03b3d653b1bec7e521459f1_2017-05-14--18-25-39"}
|
||||
max={53} />,
|
||||
document.getElementById('root')
|
||||
);
|
|
@ -0,0 +1,7 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
|
||||
<g fill="#61DAFB">
|
||||
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
|
||||
<circle cx="420.9" cy="296.5" r="45.7"/>
|
||||
<path d="M520.5 78.1z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1,36 @@
|
|||
const Uint64BE = require('int64-buffer').Uint64BE
|
||||
|
||||
export function formatForMsg(msg) {
|
||||
return {bstart: 0, bend: 15}
|
||||
}
|
||||
|
||||
export function formatMsgDec(msg) {
|
||||
const {bstart, bend} = formatForMsg(msg)
|
||||
const uint = Uint64BE(msg[1])
|
||||
var tt = "0"+uint.toString(2);
|
||||
tt = tt.substring(0, tt.length - (63-bend))
|
||||
tt = tt.substring(tt.length - (bend-bstart) - 1)
|
||||
return [msg[0], parseInt(tt, 2)];
|
||||
}
|
||||
|
||||
export function uint64BEToHex(int64) {
|
||||
return Uint64BE(int64).toString(16);
|
||||
}
|
||||
|
||||
export function int64BufferToPrettyHexStr(buffer) {
|
||||
const uint = Uint64BE(buffer);
|
||||
let hex = uint.toString(16);
|
||||
if(hex.length == 1) hex = '0' + hex;
|
||||
let hexParts = hex.match(/.{1,2}/g);
|
||||
|
||||
return hexParts.join(" ")
|
||||
}
|
||||
|
||||
export function formatMsgHex(msg) {
|
||||
const uint = Uint64BE(msg[1]);
|
||||
let hex = uint.toString(16);
|
||||
if(hex.length == 1) hex = '0' + hex;
|
||||
let hexParts = hex.match(/.{1,2}/g);
|
||||
|
||||
return [msg[0], hexParts.join(" ")]
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
const Uint64BE = require('int64-buffer').Uint64BE
|
||||
const UINT64 = require('cuint').UINT64
|
||||
import Signal from './signal';
|
||||
|
||||
const BO_RE = /^BO\_ (\w+) (\w+) *: (\w+) (\w+)/
|
||||
// normal signal
|
||||
const SG_RE = /^SG\_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*)/
|
||||
// Multiplexed signal
|
||||
const SGM_RE = /^SG\_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*)/
|
||||
|
||||
function floatOrInt(numericStr) {
|
||||
if(Number.isInteger(numericStr)) {
|
||||
return parseInt(numericStr);
|
||||
} else {
|
||||
return parseFloat(numericStr);
|
||||
}
|
||||
}
|
||||
|
||||
export function swapOrder(arr, wordSize, gSize) {
|
||||
const swappedWords = [];
|
||||
|
||||
for(let i = 0; i < arr.length; i += wordSize) {
|
||||
const word = arr.slice(i, i + wordSize);
|
||||
for(let j = wordSize - gSize; j > -gSize; j -= gSize) {
|
||||
swappedWords.push(word.slice(j, j + gSize));
|
||||
}
|
||||
}
|
||||
|
||||
return swappedWords.join("");
|
||||
}
|
||||
|
||||
export default class DBC {
|
||||
constructor(dbcString) {
|
||||
this.importDbcString(dbcString);
|
||||
this.bits = [];
|
||||
for(let i = 0; i < 64; i += 8) {
|
||||
for(let j = 7; j > -1; j--) {
|
||||
this.bits.push(i + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getMessageName(msgId) {
|
||||
const msg = this.messages.get(msgId);
|
||||
if(msg) return msg.name;
|
||||
return null;
|
||||
}
|
||||
|
||||
getSignalSpecs(msgId) {
|
||||
const msg = this.messages.get(msgId);
|
||||
if(msg) return msg.signals;
|
||||
return null;
|
||||
}
|
||||
|
||||
importDbcString(dbcString) {
|
||||
const messages = new Map();
|
||||
let ids = 0;
|
||||
|
||||
dbcString.split('\n').forEach((line, idx) => {
|
||||
line = line.trim();
|
||||
if(line.indexOf("BO_") === 0) {
|
||||
let matches = line.match(BO_RE)
|
||||
if (matches === null) {
|
||||
console.log('Bad BO', line)
|
||||
return
|
||||
}
|
||||
let [idString, name, size] = matches.slice(1);
|
||||
ids = parseInt(idString, 0); // 0 radix parses hex or dec
|
||||
|
||||
messages.set(ids, {name, size, signals: {}});
|
||||
|
||||
} else if(line.indexOf("SG_") === 0) {
|
||||
let matches = line.match(SG_RE);
|
||||
|
||||
if(matches === null) {
|
||||
matches = line.match(SGM_RE);
|
||||
if(matches === null) {
|
||||
return;
|
||||
}
|
||||
// for now, ignore multiplex which is matches[1]
|
||||
matches = matches[1] + matches.slice(3);
|
||||
} else {
|
||||
matches = matches.slice(1)
|
||||
}
|
||||
|
||||
let [name, startBit, size, isLittleEndian, isSigned,
|
||||
factor, offset, min, max, unit] = matches;
|
||||
startBit = parseInt(startBit);
|
||||
size = parseInt(size);
|
||||
isLittleEndian = parseInt(isLittleEndian) === 1
|
||||
isSigned = isSigned === '-'
|
||||
factor = floatOrInt(factor);
|
||||
offset = floatOrInt(offset);
|
||||
min = floatOrInt(min);
|
||||
max = floatOrInt(max);
|
||||
|
||||
const signalProperties= {name, startBit, size, isLittleEndian,
|
||||
isSigned, factor, offset, unit, min, max};
|
||||
const signal = new Signal(signalProperties);
|
||||
|
||||
messages.get(ids).signals[name] = signal;
|
||||
}
|
||||
});
|
||||
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
valueForSignal(signalSpec, hexData) {
|
||||
const blen = hexData.length * 4;
|
||||
let value, startBit, dataBitPos;
|
||||
|
||||
if (signalSpec.isLittleEndian) {
|
||||
value = UINT64(swapOrder(hexData, 16, 2), 16);
|
||||
startBit = signalSpec.startBit;
|
||||
dataBitPos = UINT64.fromNumber(startBit);
|
||||
} else {
|
||||
// big endian
|
||||
value = UINT64(hexData, 16);
|
||||
|
||||
startBit = this.bits.indexOf(signalSpec.startBit);
|
||||
dataBitPos = UINT64(blen - (startBit + signalSpec.size));
|
||||
}
|
||||
// console.log('startBit', startBit)
|
||||
// console.log('dataBitPos', dataBitPos)
|
||||
if(dataBitPos < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let rightHandAnd = UINT64((1 << signalSpec.size) - 1);
|
||||
let ival = (value.shiftr(dataBitPos)).and(rightHandAnd).toNumber();
|
||||
|
||||
if(signalSpec.isSigned && (ival & (1<<(signalSpec.size - 1)))) {
|
||||
ival -= 1<<signalSpec.size
|
||||
}
|
||||
ival = (ival * signalSpec.factor) + signalSpec.offset;
|
||||
return ival;
|
||||
}
|
||||
|
||||
getSignalValues(messageId, data) {
|
||||
const hexData = Buffer.from(data).toString('hex');
|
||||
if(!this.messages.has(messageId)) {
|
||||
return [];
|
||||
}
|
||||
const {signals} = this.messages.get(messageId);
|
||||
|
||||
const signalValuesByName = {};
|
||||
Object.values(signals).forEach((signalSpec) => {
|
||||
signalValuesByName[signalSpec.name] = this.valueForSignal(signalSpec, hexData);
|
||||
});
|
||||
|
||||
return signalValuesByName;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
export default class Frame {
|
||||
constructor({name,
|
||||
id = 0,
|
||||
dlc = 0,
|
||||
transmitter = [],
|
||||
extended = 0,
|
||||
comment = null,
|
||||
signals = []}) {
|
||||
Object.assign(this, {name,
|
||||
id,
|
||||
dlc,
|
||||
transmitter,
|
||||
extended,
|
||||
comment,
|
||||
signals})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
export default class Signal {
|
||||
constructor({name,
|
||||
startBit = 0,
|
||||
size = 0,
|
||||
isLittleEndian = true,
|
||||
isSigned = true,
|
||||
isFloat = false,
|
||||
factor = 1,
|
||||
offset = 0,
|
||||
unit = "",
|
||||
receiver = [],
|
||||
comment = null,
|
||||
multiplex = null,
|
||||
min = null,
|
||||
max = null
|
||||
}) {
|
||||
Object.assign(this,
|
||||
{name,
|
||||
startBit,
|
||||
size,
|
||||
isLittleEndian,
|
||||
isSigned,
|
||||
isFloat,
|
||||
factor,
|
||||
offset,
|
||||
unit,
|
||||
receiver,
|
||||
comment,
|
||||
multiplex});
|
||||
|
||||
if(min == null) {
|
||||
min = this.calculateMin();
|
||||
}
|
||||
if(max == null) {
|
||||
max = this.calculateMax();
|
||||
}
|
||||
|
||||
Object.assign(this, {min, max});
|
||||
}
|
||||
|
||||
calculateRawRange() {
|
||||
let rawRange = Math.pow(2, this.size);
|
||||
if (this.isSigned) {
|
||||
rawRange /= 2;
|
||||
}
|
||||
return [(this.isSigned ? -1 * rawRange : 0),
|
||||
rawRange - 1]
|
||||
}
|
||||
|
||||
calculateMin() {
|
||||
const rawMin = this.calculateRawRange()[0];
|
||||
return this.offset + (rawMin * this.factor);
|
||||
}
|
||||
|
||||
calculateMax() {
|
||||
const rawMax = this.calculateRawRange()[1];
|
||||
return this.offset + (rawMax * this.factor);
|
||||
}
|
||||
|
||||
equals(otherSignal) {
|
||||
return (otherSignal.name == this.name
|
||||
&& otherSignal.startBit == this.startBit
|
||||
&& otherSignal.size == this.size
|
||||
&& otherSignal.isLittleEndian == this.isLittleEndian
|
||||
&& otherSignal.isSigned == this.isSigned
|
||||
&& otherSignal.isFloat == this.isFloat
|
||||
&& otherSignal.factor == this.factor
|
||||
&& otherSignal.offset == this.offset
|
||||
&& otherSignal.unit == this.unit
|
||||
&& otherSignal.receiver.length==this.receiver.length
|
||||
&& otherSignal.receiver.every((v,i)=> v === this.receiver[i])
|
||||
&& otherSignal.comment == this.comment
|
||||
&& otherSignal.multiplex == this.multiplex);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
export const Styles = StyleSheet.create({
|
||||
root: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
});
|
|
@ -0,0 +1,122 @@
|
|||
// Client-side parser for .npy files
|
||||
// See the specification: http://docs.scipy.org/doc/numpy-dev/neps/npy-format.html
|
||||
|
||||
const NumpyLoader = (function NumpyLoader() {
|
||||
function asciiDecode(buf) {
|
||||
return String.fromCharCode.apply(null, new Uint8Array(buf));
|
||||
}
|
||||
|
||||
function readUint16LE(buffer) {
|
||||
var view = new DataView(buffer);
|
||||
var val = view.getUint8(0);
|
||||
val |= view.getUint8(1) << 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
function fromArrayBuffer(buf) {
|
||||
// Check the magic number
|
||||
var magic = asciiDecode(buf.slice(0,6));
|
||||
if (magic !== "\x93NUMPY") {
|
||||
throw new Error("Bad magic number");
|
||||
}
|
||||
|
||||
var version = new Uint8Array(buf.slice(6,8)),
|
||||
headerLength = readUint16LE(buf.slice(8,10)),
|
||||
headerStr = asciiDecode(buf.slice(10, 10+headerLength));
|
||||
const offsetBytes = 10 + headerLength;
|
||||
//rest = buf.slice(10+headerLength); XXX -- This makes a copy!!! https://www.khronos.org/registry/typedarray/specs/latest/#5
|
||||
|
||||
// Hacky conversion of dict literal string to JS Object
|
||||
const info = JSON.parse(headerStr.toLowerCase()
|
||||
.replace('(','[')
|
||||
.replace('),',']')
|
||||
.replace(/'/g, '"')
|
||||
.replace(',]', ']'));
|
||||
|
||||
// Intepret the bytes according to the specified dtype
|
||||
var data;
|
||||
if (info.descr === "|u1") {
|
||||
data = new Uint8Array(buf, offsetBytes);
|
||||
} else if (info.descr === "|i1") {
|
||||
data = new Int8Array(buf, offsetBytes);
|
||||
} else if (info.descr === "<u2") {
|
||||
data = new Uint16Array(buf, offsetBytes);
|
||||
} else if (info.descr === "<i2") {
|
||||
data = new Int16Array(buf, offsetBytes);
|
||||
} else if (info.descr === "<u4") {
|
||||
data = new Uint32Array(buf, offsetBytes);
|
||||
} else if (info.descr === "<i4") {
|
||||
data = new Int32Array(buf, offsetBytes);
|
||||
} else if (info.descr === "<f4") {
|
||||
data = new Float32Array(buf, offsetBytes);
|
||||
} else if (info.descr === "<f8") {
|
||||
data = new Float64Array(buf, offsetBytes);
|
||||
} else if (info.descr === "<u8") {
|
||||
// 8 byte uint64s
|
||||
data = new Uint8Array(buf, offsetBytes);
|
||||
} else if (info.descr === "<i8") {
|
||||
// 8 byte int64s
|
||||
data = new Uint8Array(buf, offsetBytes);
|
||||
} else if (info.descr === "|s8") {
|
||||
// 8 byte strings
|
||||
data = new Uint8Array(buf, offsetBytes);
|
||||
} else {
|
||||
throw new Error('unknown numeric dtype '+info.descr)
|
||||
}
|
||||
|
||||
return {
|
||||
shape: info.shape,
|
||||
fortran_order: info.fortran_order,
|
||||
data: data
|
||||
};
|
||||
}
|
||||
|
||||
function open(file, callback) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function() {
|
||||
// the file contents have been read as an array buffer
|
||||
var buf = reader.result;
|
||||
var ndarray = fromArrayBuffer(buf);
|
||||
callback(ndarray);
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function promise(url) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
// Do the usual XHR stuff
|
||||
var req = new XMLHttpRequest();
|
||||
req.onload = function() {
|
||||
// This is called even on 404 etc
|
||||
// so check the status
|
||||
if (req.status == 200) {
|
||||
var buf = req.response; // not responseText
|
||||
var ndarray = fromArrayBuffer(buf);
|
||||
resolve(ndarray);
|
||||
} else {
|
||||
// Otherwise reject with the status text
|
||||
// which will hopefully be a meaningful error
|
||||
reject(Error(req.statusText));
|
||||
}
|
||||
};
|
||||
|
||||
// Handle network errors
|
||||
req.onerror = function() {
|
||||
reject(Error("Network Error"));
|
||||
};
|
||||
|
||||
// Make the request
|
||||
req.open('GET', url, true);
|
||||
req.responseType = "arraybuffer";
|
||||
req.send(null);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
open: open,
|
||||
promise: promise,
|
||||
fromArrayBuffer: fromArrayBuffer,
|
||||
};
|
||||
})();
|
||||
|
||||
module.exports = NumpyLoader;
|
|
@ -0,0 +1,200 @@
|
|||
import {createClassFromSpec} from 'react-vega';
|
||||
|
||||
const canHistogramSpec = {
|
||||
"$schema": "https://vega.github.io/schema/vega/v3.0.json",
|
||||
"width": 1000,
|
||||
"height": 100,
|
||||
"padding": 5,
|
||||
|
||||
"signals": [
|
||||
{
|
||||
"name": "segment"
|
||||
}
|
||||
],
|
||||
"data": [
|
||||
{
|
||||
"name": "points"
|
||||
},
|
||||
{
|
||||
"name": "binned",
|
||||
"source": "points",
|
||||
"transform": [
|
||||
{
|
||||
"type": "extent",
|
||||
"field": "time",
|
||||
"signal": "extent"
|
||||
},
|
||||
{
|
||||
"type": "bin", "field": "time",
|
||||
"extent": {"signal": "extent"},
|
||||
"nice": false
|
||||
},
|
||||
{
|
||||
"type": "aggregate",
|
||||
"key": "bin0", "groupby": ["bin0", "bin1"],
|
||||
"fields": ["bin0"], "ops": ["count"], "as": ["count"]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
"scales": [
|
||||
{
|
||||
"name": "xscale",
|
||||
"type": "linear",
|
||||
"zero": false,
|
||||
"range": "width",
|
||||
"domain": {"data": "points", "field": "time"}
|
||||
},
|
||||
{
|
||||
"name": "yscale",
|
||||
"type": "linear",
|
||||
"range": "height", "round": true,
|
||||
"domain": {"data": "binned", "field": "count"},
|
||||
"zero": true, "nice": true
|
||||
}
|
||||
],
|
||||
|
||||
"axes": [
|
||||
{"orient": "bottom", "scale": "xscale", "zindex": 1},
|
||||
{"orient": "left", "scale": "yscale", "tickCount": 5, "zindex": 1}
|
||||
],
|
||||
|
||||
"marks": [
|
||||
{"type": "group",
|
||||
"name": "histogram",
|
||||
"encode": {
|
||||
"enter": {
|
||||
"height": {"value": 75},
|
||||
"width": {"value": 1000},
|
||||
"fill": {"value": "transparent"}
|
||||
}
|
||||
},
|
||||
"signals": [
|
||||
{
|
||||
"name": "brush", "value": 0,
|
||||
"on": [
|
||||
{
|
||||
"events": "@histogram:mousedown",
|
||||
"update": "[x(), x()]"
|
||||
},
|
||||
{
|
||||
"events": "[@histogram:mousedown, window:mouseup] > window:mousemove!",
|
||||
"update": "[brush[0], clamp(x(), 0, width)]"
|
||||
},
|
||||
{
|
||||
"events": {"signal": "delta"},
|
||||
"update": "clampRange([anchor[0] + delta, anchor[1] + delta], 0, width)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "anchor", "value": null,
|
||||
"on": [{"events": "@brush:mousedown", "update": "slice(brush)"}]
|
||||
},
|
||||
{
|
||||
"name": "xdown", "value": 0,
|
||||
"on": [{"events": "@brush:mousedown", "update": "x()"}]
|
||||
},
|
||||
{
|
||||
"name": "delta", "value": 0,
|
||||
"on": [
|
||||
{
|
||||
"events": "[@brush:mousedown, window:mouseup] > window:mousemove!",
|
||||
"update": "x() - xdown"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "segment",
|
||||
"push": "outer",
|
||||
"on": [
|
||||
{
|
||||
"events": {"signal": "brush"},
|
||||
"update": "span(brush) ? invert('xscale', brush) : null"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"marks": [
|
||||
{
|
||||
"type": "rect",
|
||||
"from": {"data": "binned"},
|
||||
"interactive": false,
|
||||
"encode": {
|
||||
"update": {
|
||||
"x": {"scale": "xscale", "field": "bin0"},
|
||||
"x2": {"scale": "xscale", "field": "bin1",
|
||||
"offset": 0},
|
||||
"y": {"scale": "yscale", "field": "count"},
|
||||
"y2": {"scale": "yscale", "value": 0},
|
||||
"fill": {"value": "steelblue"}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "rect",
|
||||
"from": {"data": "points"},
|
||||
"encode": {
|
||||
"enter": {
|
||||
"x": {"scale": "xscale", "field": "time"},
|
||||
"width": {"value": 1},
|
||||
"y": {"value": 25, "offset": {"signal": "height"}},
|
||||
"height": {"value": 5},
|
||||
"fill": {"value": "steelblue"},
|
||||
"fillOpacity": {"value": 0.4}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "rect",
|
||||
"name": "brush",
|
||||
"encode": {
|
||||
"enter": {
|
||||
"y": {"value": 0},
|
||||
"height": {"value": 100},
|
||||
"fill": {"value": "#333"},
|
||||
"fillOpacity": {"value": 0.2}
|
||||
},
|
||||
"update": {
|
||||
"x": {"signal": "brush[0]"},
|
||||
"x2": {"signal": "brush[1]"}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "rect",
|
||||
"interactive": false,
|
||||
"encode": {
|
||||
"enter": {
|
||||
"y": {"value": 0},
|
||||
"height": {"value": 100},
|
||||
"width": {"value": 2},
|
||||
"fill": {"value": "firebrick"}
|
||||
},
|
||||
"update": {
|
||||
"x": {"signal": "brush[0]"}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "rect",
|
||||
"interactive": false,
|
||||
"encode": {
|
||||
"enter": {
|
||||
"y": {"value": 0},
|
||||
"height": {"value": 100},
|
||||
"width": {"value": 2},
|
||||
"fill": {"value": "firebrick"}
|
||||
},
|
||||
"update": {
|
||||
"x": {"signal": "brush[1]"}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default createClassFromSpec(canHistogramSpec);
|
|
@ -0,0 +1,122 @@
|
|||
import {createClassFromSpec} from 'react-vega';
|
||||
|
||||
export default createClassFromSpec('CanPlot', {
|
||||
"$schema": "https://vega.github.io/schema/vega/v3.0.json",
|
||||
"width": 500,
|
||||
"height": 200,
|
||||
"padding": 5,
|
||||
|
||||
"signals": [
|
||||
{
|
||||
"name": "tipTime",
|
||||
"on": [{
|
||||
"events": "mousemove",
|
||||
"update": "invert('xscale', x())"
|
||||
}]
|
||||
},
|
||||
{"name": "segment", "value": {"data": "table", "field": "x"}}
|
||||
],
|
||||
"data": [
|
||||
{
|
||||
"name": "table"
|
||||
},
|
||||
{
|
||||
"name": "tooltip",
|
||||
"source": "table",
|
||||
"transform": [
|
||||
{
|
||||
"type": "filter",
|
||||
"expr": "abs(datum.x - tipTime) <= 0.1"
|
||||
},
|
||||
{
|
||||
"type": "aggregate",
|
||||
"fields": ["x", "y", "unit"],
|
||||
"ops": ["min", "argmin", "argmin"],
|
||||
"as": ["min", "argmin", "argmin"]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
"scales": [
|
||||
{
|
||||
"name": "xscale",
|
||||
"type": "linear",
|
||||
"range": "width",
|
||||
"zero": false,
|
||||
"domain": {"data": "table", "field": "x"},
|
||||
"domainRaw": {"signal": "segment"}
|
||||
},
|
||||
{
|
||||
"name": "yscale",
|
||||
"type": "linear",
|
||||
"range": "height",
|
||||
"zero": true,
|
||||
"domain": {"data": "table", "field": "y"}
|
||||
}
|
||||
],
|
||||
|
||||
"axes": [
|
||||
{"orient": "bottom", "scale": "xscale"},
|
||||
{"orient": "left", "scale": "yscale"}
|
||||
],
|
||||
|
||||
"marks": [
|
||||
{
|
||||
"type": "line",
|
||||
"from": {"data": "table"},
|
||||
"interactive": true,
|
||||
"encode": {
|
||||
"update": {
|
||||
"x": {"scale": "xscale", "field": "x"},
|
||||
"y": {"scale": "yscale", "field": "y"}
|
||||
},
|
||||
"hover": {
|
||||
"fillOpacity": {"value": 0.5}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "symbol",
|
||||
"from": {"data": "tooltip"},
|
||||
"encode": {
|
||||
"update": {
|
||||
"x": {"scale": "xscale", "field": "argmin.x"},
|
||||
"y": {"scale": "yscale", "field": "argmin.y"},
|
||||
"size": {"value": 50},
|
||||
"fill": {"value": "black"}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "group",
|
||||
"from": {"data": "tooltip"},
|
||||
"interactive": false,
|
||||
"encode": {
|
||||
"update": {
|
||||
"x": {"scale": "xscale", "field": "argmin.x"},
|
||||
"y": {"scale": "yscale", "field": "argmin.y"},
|
||||
"height": {"value": 20},
|
||||
"width": {"value": 150},
|
||||
"fill": {"value": "#fff"},
|
||||
"fillOpacity": {"value": 0.85},
|
||||
"stroke": {"value": "#aaa"},
|
||||
"strokeWidth": {"value": 0.5}
|
||||
}
|
||||
},
|
||||
"marks": [
|
||||
{
|
||||
"type": "text",
|
||||
"interactive": false,
|
||||
"encode": {
|
||||
"update": {
|
||||
"text": {"signal": "parent.argmin.x + ': ' + parent.argmin.y + ' ' + parent.argmin.unit"},
|
||||
"fill": {"value": "black"},
|
||||
"fontWeight": {"value": "bold"}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
Loading…
Reference in New Issue