Add eslint with explorer configuration (#26)
* Add eslint and run --fix * Remove precommit prettiermain
parent
8bcda7c579
commit
1be5544df3
|
@ -0,0 +1,5 @@
|
||||||
|
node_modules/
|
||||||
|
public/
|
||||||
|
build/
|
||||||
|
.storybook
|
||||||
|
src/registerServiceWorker.js
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"parser": "babel-eslint",
|
||||||
|
"extends": [
|
||||||
|
"airbnb"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"import/prefer-default-export": 0,
|
||||||
|
"import/no-named-as-default": 0,
|
||||||
|
"comma-dangle": 0,
|
||||||
|
"react/jsx-filename-extension": 0, // .jsx should be better? But git diff will be crazy
|
||||||
|
"react/forbid-prop-types": 0, // Too time consuming to map out types for now
|
||||||
|
"react/require-default-props": 0,
|
||||||
|
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }]
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"browser": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "react-app",
|
|
||||||
"rules": {
|
|
||||||
"no-undef": 1
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"browser": true
|
|
||||||
},
|
|
||||||
"globals": {
|
|
||||||
"window": false
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +1,25 @@
|
||||||
const WorkerLoaderPlugin = require("craco-worker-loader");
|
const WorkerLoaderPlugin = require('craco-worker-loader');
|
||||||
const SentryPlugin = require("craco-sentry-plugin");
|
const SentryPlugin = require('craco-sentry-plugin');
|
||||||
|
|
||||||
module.exports = function({ env }) {
|
module.exports = function ({ env }) {
|
||||||
var plugins = [
|
const plugins = [
|
||||||
{
|
{
|
||||||
plugin: WorkerLoaderPlugin
|
plugin: WorkerLoaderPlugin
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
if (env === "production") {
|
if (env === 'production') {
|
||||||
// plugins.push({
|
// plugins.push({
|
||||||
// plugin: SentryPlugin
|
// plugin: SentryPlugin
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
plugins: plugins,
|
plugins,
|
||||||
webpack: {
|
webpack: {
|
||||||
configure: (webpackConfig, { env, paths }) => {
|
configure: (webpackConfig, { env, paths }) => {
|
||||||
webpackConfig.output.globalObject = "this";
|
webpackConfig.output.globalObject = 'this';
|
||||||
webpackConfig.optimization.minimizer = webpackConfig.optimization.minimizer.map(
|
webpackConfig.optimization.minimizer = webpackConfig.optimization.minimizer.map(
|
||||||
function(plugin) {
|
(plugin) => {
|
||||||
if (plugin.constructor.name !== "TerserPlugin") {
|
if (plugin.constructor.name !== 'TerserPlugin') {
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
plugin.options.terserOptions.keep_fnames = true;
|
plugin.options.terserOptions.keep_fnames = true;
|
||||||
|
|
10
package.json
10
package.json
|
@ -11,6 +11,7 @@
|
||||||
"@craco/craco": "^5.5.0",
|
"@craco/craco": "^5.5.0",
|
||||||
"ap": "^0.2.0",
|
"ap": "^0.2.0",
|
||||||
"aphrodite": "^1.2.1",
|
"aphrodite": "^1.2.1",
|
||||||
|
"babel-eslint": "^10.0.3",
|
||||||
"base64-inline-loader": "^1.1.0",
|
"base64-inline-loader": "^1.1.0",
|
||||||
"classnames": "^2.2.5",
|
"classnames": "^2.2.5",
|
||||||
"clipboard": "^1.7.1",
|
"clipboard": "^1.7.1",
|
||||||
|
@ -22,6 +23,12 @@
|
||||||
"emotion": "^8.0.12",
|
"emotion": "^8.0.12",
|
||||||
"enzyme": "^3.2.0",
|
"enzyme": "^3.2.0",
|
||||||
"enzyme-adapter-react-16": "^1.1.0",
|
"enzyme-adapter-react-16": "^1.1.0",
|
||||||
|
"eslint": "^6.5.1",
|
||||||
|
"eslint-config-airbnb": "^18.0.1",
|
||||||
|
"eslint-plugin-import": "^2.18.2",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.2.3",
|
||||||
|
"eslint-plugin-react": "^7.16.0",
|
||||||
|
"eslint-plugin-react-hooks": "^2.1.2",
|
||||||
"file-saver": "^1.3.3",
|
"file-saver": "^1.3.3",
|
||||||
"font-awesome": "^4.7.0",
|
"font-awesome": "^4.7.0",
|
||||||
"github-api": "^3.0.0",
|
"github-api": "^3.0.0",
|
||||||
|
@ -86,11 +93,10 @@
|
||||||
"test-ci": "CI=true craco test --env=jsdom",
|
"test-ci": "CI=true craco test --env=jsdom",
|
||||||
"netlify-sass": "node-sass src/index.scss > src/index.css",
|
"netlify-sass": "node-sass src/index.scss > src/index.css",
|
||||||
"sass": "node-sass src/index.scss -o src && node-sass -w src/index.scss -o src",
|
"sass": "node-sass src/index.scss -o src && node-sass -w src/index.scss -o src",
|
||||||
"precommit": "lint-staged",
|
|
||||||
"deploy": "npm run build && gh-pages -d build"
|
"deploy": "npm run build && gh-pages -d build"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{js,jsx}": ["prettier --parser flow --write", "git add"],
|
"*.{js,jsx}": ["eslint --fix", "git add"],
|
||||||
"*.json": ["prettier --parser json --write", "git add"],
|
"*.json": ["prettier --parser json --write", "git add"],
|
||||||
"*.{graphql,gql}": ["prettier --parser graphql --write", "git add"],
|
"*.{graphql,gql}": ["prettier --parser graphql --write", "git add"],
|
||||||
"*.{md,markdown}": ["prettier --parser markdown --write", "git add"],
|
"*.{md,markdown}": ["prettier --parser markdown --write", "git add"],
|
||||||
|
|
|
@ -1,43 +1,43 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import Moment from "moment";
|
import Moment from 'moment';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import cx from "classnames";
|
import cx from 'classnames';
|
||||||
import { createWriteStream } from "streamsaver";
|
import { createWriteStream } from 'streamsaver';
|
||||||
import Panda from "@commaai/pandajs";
|
import Panda from '@commaai/pandajs';
|
||||||
import CommaAuth from "@commaai/my-comma-auth";
|
import CommaAuth from '@commaai/my-comma-auth';
|
||||||
import { raw as RawDataApi, drives as DrivesApi } from "@commaai/comma-api";
|
import { raw as RawDataApi, drives as DrivesApi } from '@commaai/comma-api';
|
||||||
import {
|
import {
|
||||||
USE_UNLOGGER,
|
USE_UNLOGGER,
|
||||||
PART_SEGMENT_LENGTH,
|
PART_SEGMENT_LENGTH,
|
||||||
STREAMING_WINDOW,
|
STREAMING_WINDOW,
|
||||||
GITHUB_AUTH_TOKEN_KEY
|
GITHUB_AUTH_TOKEN_KEY
|
||||||
} from "./config";
|
} from './config';
|
||||||
import * as GithubAuth from "./api/github-auth";
|
import * as GithubAuth from './api/github-auth';
|
||||||
|
|
||||||
import DBC from "./models/can/dbc";
|
import DBC from './models/can/dbc';
|
||||||
import Meta from "./components/Meta";
|
import Meta from './components/Meta';
|
||||||
import Explorer from "./components/Explorer";
|
import Explorer from './components/Explorer';
|
||||||
import OnboardingModal from "./components/Modals/OnboardingModal";
|
import OnboardingModal from './components/Modals/OnboardingModal';
|
||||||
import SaveDbcModal from "./components/SaveDbcModal";
|
import SaveDbcModal from './components/SaveDbcModal';
|
||||||
import LoadDbcModal from "./components/LoadDbcModal";
|
import LoadDbcModal from './components/LoadDbcModal';
|
||||||
import debounce from "./utils/debounce";
|
import debounce from './utils/debounce';
|
||||||
import EditMessageModal from "./components/EditMessageModal";
|
import EditMessageModal from './components/EditMessageModal';
|
||||||
import LoadingBar from "./components/LoadingBar";
|
import LoadingBar from './components/LoadingBar';
|
||||||
import {
|
import {
|
||||||
persistDbc,
|
persistDbc,
|
||||||
fetchPersistedDbc,
|
fetchPersistedDbc,
|
||||||
unpersistGithubAuthToken
|
unpersistGithubAuthToken
|
||||||
} from "./api/localstorage";
|
} from './api/localstorage';
|
||||||
import OpenDbc from "./api/OpenDbc";
|
import OpenDbc from './api/OpenDbc';
|
||||||
import UnloggerClient from "./api/unlogger";
|
import UnloggerClient from './api/unlogger';
|
||||||
import * as ObjectUtils from "./utils/object";
|
import * as ObjectUtils from './utils/object';
|
||||||
import { hash } from "./utils/string";
|
import { hash } from './utils/string';
|
||||||
import { modifyQueryParameters } from "./utils/url";
|
import { modifyQueryParameters } from './utils/url';
|
||||||
|
|
||||||
const RLogDownloader = require("./workers/rlog-downloader.worker.js");
|
const RLogDownloader = require('./workers/rlog-downloader.worker.js');
|
||||||
const LogCSVDownloader = require("./workers/dbc-csv-downloader.worker.js");
|
const LogCSVDownloader = require('./workers/dbc-csv-downloader.worker.js');
|
||||||
const MessageParser = require("./workers/message-parser.worker.js");
|
const MessageParser = require('./workers/message-parser.worker.js');
|
||||||
const CanStreamerWorker = require("./workers/CanStreamerWorker.worker.js");
|
const CanStreamerWorker = require('./workers/CanStreamerWorker.worker.js');
|
||||||
|
|
||||||
export default class CanExplorer extends Component {
|
export default class CanExplorer extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -73,7 +73,7 @@ export default class CanExplorer extends Component {
|
||||||
editMessageModalMessage: null,
|
editMessageModalMessage: null,
|
||||||
dbc: props.dbc ? props.dbc : new DBC(),
|
dbc: props.dbc ? props.dbc : new DBC(),
|
||||||
dbcText: props.dbc ? props.dbc.text() : new DBC().text(),
|
dbcText: props.dbc ? props.dbc.text() : new DBC().text(),
|
||||||
dbcFilename: props.dbcFilename ? props.dbcFilename : "New_DBC",
|
dbcFilename: props.dbcFilename ? props.dbcFilename : 'New_DBC',
|
||||||
dbcLastSaved: null,
|
dbcLastSaved: null,
|
||||||
seekTime: 0,
|
seekTime: 0,
|
||||||
seekIndex: 0,
|
seekIndex: 0,
|
||||||
|
@ -135,19 +135,19 @@ export default class CanExplorer extends Component {
|
||||||
if (CommaAuth.isAuthenticated() && !name) {
|
if (CommaAuth.isAuthenticated() && !name) {
|
||||||
this.showOnboarding();
|
this.showOnboarding();
|
||||||
} else if (
|
} else if (
|
||||||
this.props.max &&
|
this.props.max
|
||||||
this.props.url &&
|
&& this.props.url
|
||||||
!this.props.exp &&
|
&& !this.props.exp
|
||||||
!this.props.sig
|
&& !this.props.sig
|
||||||
) {
|
) {
|
||||||
// probably the demo!
|
// probably the demo!
|
||||||
const { max, url } = this.props;
|
const { max, url } = this.props;
|
||||||
const startTime = Moment(name, "YYYY-MM-DD--H-m-s");
|
const startTime = Moment(name, 'YYYY-MM-DD--H-m-s');
|
||||||
|
|
||||||
const route = {
|
const route = {
|
||||||
fullname: dongleId + "|" + name,
|
fullname: `${dongleId}|${name}`,
|
||||||
proclog: max,
|
proclog: max,
|
||||||
url: url,
|
url,
|
||||||
start_time: startTime
|
start_time: startTime
|
||||||
};
|
};
|
||||||
this.setState(
|
this.setState(
|
||||||
|
@ -158,15 +158,14 @@ export default class CanExplorer extends Component {
|
||||||
this.initCanData
|
this.initCanData
|
||||||
);
|
);
|
||||||
} else if (dongleId && name) {
|
} else if (dongleId && name) {
|
||||||
const routeName = dongleId + "|" + name;
|
const routeName = `${dongleId}|${name}`;
|
||||||
let urlPromise, logUrlsPromise;
|
let urlPromise;
|
||||||
|
let logUrlsPromise;
|
||||||
|
|
||||||
if (this.props.url) {
|
if (this.props.url) {
|
||||||
urlPromise = Promise.resolve(this.props.url);
|
urlPromise = Promise.resolve(this.props.url);
|
||||||
} else {
|
} else {
|
||||||
urlPromise = DrivesApi.getRouteInfo(routeName).then(function(route) {
|
urlPromise = DrivesApi.getRouteInfo(routeName).then((route) => route.url);
|
||||||
return route.url;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.sig && this.props.exp) {
|
if (this.props.sig && this.props.exp) {
|
||||||
|
@ -178,13 +177,13 @@ export default class CanExplorer extends Component {
|
||||||
logUrlsPromise = RawDataApi.getLogUrls(routeName);
|
logUrlsPromise = RawDataApi.getLogUrls(routeName);
|
||||||
}
|
}
|
||||||
Promise.all([urlPromise, logUrlsPromise])
|
Promise.all([urlPromise, logUrlsPromise])
|
||||||
.then(initData => {
|
.then((initData) => {
|
||||||
let [url, logUrls] = initData;
|
const [url, logUrls] = initData;
|
||||||
const newState = {
|
const newState = {
|
||||||
route: {
|
route: {
|
||||||
fullname: routeName,
|
fullname: routeName,
|
||||||
proclog: logUrls.length - 1,
|
proclog: logUrls.length - 1,
|
||||||
start_time: Moment(name, "YYYY-MM-DD--H-m-s"),
|
start_time: Moment(name, 'YYYY-MM-DD--H-m-s'),
|
||||||
url
|
url
|
||||||
},
|
},
|
||||||
currentParts: [
|
currentParts: [
|
||||||
|
@ -195,21 +194,19 @@ export default class CanExplorer extends Component {
|
||||||
};
|
};
|
||||||
this.setState(newState, this.initCanData);
|
this.setState(newState, this.initCanData);
|
||||||
|
|
||||||
DrivesApi.getShareSignature(routeName).then(shareSignature =>
|
DrivesApi.getShareSignature(routeName).then((shareSignature) => this.setState({
|
||||||
this.setState({
|
shareUrl: modifyQueryParameters({
|
||||||
shareUrl: modifyQueryParameters({
|
add: {
|
||||||
add: {
|
exp: shareSignature.exp,
|
||||||
exp: shareSignature.exp,
|
sig: shareSignature.sig,
|
||||||
sig: shareSignature.sig,
|
max: logUrls.length - 1,
|
||||||
max: logUrls.length - 1,
|
url
|
||||||
url
|
},
|
||||||
},
|
remove: [GITHUB_AUTH_TOKEN_KEY]
|
||||||
remove: [GITHUB_AUTH_TOKEN_KEY]
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
);
|
}));
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch((err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
this.showOnboarding();
|
this.showOnboarding();
|
||||||
});
|
});
|
||||||
|
@ -245,7 +242,12 @@ export default class CanExplorer extends Component {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.setState({ dbc, dbcFilename, dbcText: dbc.text(), messages: {} });
|
this.setState({
|
||||||
|
dbc,
|
||||||
|
dbcFilename,
|
||||||
|
dbcText: dbc.text(),
|
||||||
|
messages: {}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,10 +264,10 @@ export default class CanExplorer extends Component {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
downloadLogAsCSV() {
|
downloadLogAsCSV() {
|
||||||
console.log("downloadLogAsCSV:start");
|
console.log('downloadLogAsCSV:start');
|
||||||
const { dbcFilename } = this.state;
|
const { dbcFilename } = this.state;
|
||||||
const fileStream = createWriteStream(
|
const fileStream = createWriteStream(
|
||||||
`${dbcFilename.replace(/\.dbc/g, "-")}${+new Date()}.csv`
|
`${dbcFilename.replace(/\.dbc/g, '-')}${+new Date()}.csv`
|
||||||
);
|
);
|
||||||
const writer = fileStream.getWriter();
|
const writer = fileStream.getWriter();
|
||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
|
@ -278,15 +280,16 @@ export default class CanExplorer extends Component {
|
||||||
function dataHandler(e) {
|
function dataHandler(e) {
|
||||||
const { logData, shouldClose, progress } = e.data;
|
const { logData, shouldClose, progress } = e.data;
|
||||||
if (shouldClose) {
|
if (shouldClose) {
|
||||||
console.log("downloadLogAsCSV:close");
|
console.log('downloadLogAsCSV:close');
|
||||||
writer.close();
|
writer.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("CSV export progress:", progress);
|
console.log('CSV export progress:', progress);
|
||||||
const uint8array = encoder.encode(logData + "\n");
|
const uint8array = encoder.encode(`${logData}\n`);
|
||||||
writer.write(uint8array);
|
writer.write(uint8array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadRawLogAsCSV(handler) {
|
downloadRawLogAsCSV(handler) {
|
||||||
return this.downloadLiveLogAsCSV(handler);
|
return this.downloadLiveLogAsCSV(handler);
|
||||||
}
|
}
|
||||||
|
@ -301,8 +304,8 @@ export default class CanExplorer extends Component {
|
||||||
worker.onmessage = handler;
|
worker.onmessage = handler;
|
||||||
|
|
||||||
worker.postMessage({
|
worker.postMessage({
|
||||||
data: Object.keys(this.state.messages).map(sourceId => {
|
data: Object.keys(this.state.messages).map((sourceId) => {
|
||||||
var source = this.state.messages[sourceId];
|
const source = this.state.messages[sourceId];
|
||||||
return {
|
return {
|
||||||
id: source.id,
|
id: source.id,
|
||||||
bus: source.bus,
|
bus: source.bus,
|
||||||
|
@ -321,16 +324,16 @@ export default class CanExplorer extends Component {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
const messages = { ...this.state.messages };
|
const messages = { ...this.state.messages };
|
||||||
for (var key in newMessages) {
|
for (const key in newMessages) {
|
||||||
// add message
|
// add message
|
||||||
if (options.replace !== true && key in messages) {
|
if (options.replace !== true && key in messages) {
|
||||||
// should merge here instead of concat
|
// should merge here instead of concat
|
||||||
// assumes messages are always sequential
|
// assumes messages are always sequential
|
||||||
let msgEntries = messages[key].entries;
|
const msgEntries = messages[key].entries;
|
||||||
let newMsgEntries = newMessages[key].entries;
|
const newMsgEntries = newMessages[key].entries;
|
||||||
let msgLength = msgEntries.length;
|
const msgLength = msgEntries.length;
|
||||||
let newMsgLength = newMsgEntries.length;
|
const newMsgLength = newMsgEntries.length;
|
||||||
let entryLength = msgLength + newMsgLength;
|
const entryLength = msgLength + newMsgLength;
|
||||||
messages[key].entries = Array(entryLength);
|
messages[key].entries = Array(entryLength);
|
||||||
|
|
||||||
let msgIndex = 0;
|
let msgIndex = 0;
|
||||||
|
@ -351,8 +354,7 @@ export default class CanExplorer extends Component {
|
||||||
messages[key].entries[i] = newMsgEntries[newMsgIndex++];
|
messages[key].entries[i] = newMsgEntries[newMsgIndex++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
messages[key].byteStateChangeCounts =
|
messages[key].byteStateChangeCounts = newMessages[key].byteStateChangeCounts;
|
||||||
newMessages[key].byteStateChangeCounts;
|
|
||||||
} else {
|
} else {
|
||||||
messages[key] = newMessages[key];
|
messages[key] = newMessages[key];
|
||||||
messages[key].frame = this.state.dbc.getMessageFrame(
|
messages[key].frame = this.state.dbc.getMessageFrame(
|
||||||
|
@ -365,15 +367,15 @@ export default class CanExplorer extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelWorker(workerHash) {
|
cancelWorker(workerHash) {
|
||||||
let currentWorkers = { ...this.state.currentWorkers };
|
const currentWorkers = { ...this.state.currentWorkers };
|
||||||
let { worker, part } = currentWorkers[workerHash];
|
const { worker, part } = currentWorkers[workerHash];
|
||||||
let loadingParts = this.state.loadingParts.filter(p => p !== part);
|
const loadingParts = this.state.loadingParts.filter((p) => p !== part);
|
||||||
let loadedParts = this.state.loadedParts.filter(p => p !== part);
|
const loadedParts = this.state.loadedParts.filter((p) => p !== part);
|
||||||
delete currentWorkers[workerHash];
|
delete currentWorkers[workerHash];
|
||||||
|
|
||||||
console.log("Stoping worker", workerHash, "for part", part);
|
console.log('Stoping worker', workerHash, 'for part', part);
|
||||||
worker.postMessage({
|
worker.postMessage({
|
||||||
action: "terminate"
|
action: 'terminate'
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -385,16 +387,16 @@ export default class CanExplorer extends Component {
|
||||||
|
|
||||||
spawnWorker(options) {
|
spawnWorker(options) {
|
||||||
let { currentParts, currentWorkers } = this.state;
|
let { currentParts, currentWorkers } = this.state;
|
||||||
console.log("Checking worker for", currentParts);
|
console.log('Checking worker for', currentParts);
|
||||||
if (!this.state.isLoading) {
|
if (!this.state.isLoading) {
|
||||||
this.setState({ isLoading: true });
|
this.setState({ isLoading: true });
|
||||||
}
|
}
|
||||||
const [minPart, maxPart] = currentParts;
|
const [minPart, maxPart] = currentParts;
|
||||||
// cancel old workers that are still loading data no longer inside the window
|
// cancel old workers that are still loading data no longer inside the window
|
||||||
Object.keys(currentWorkers).forEach(workerHash => {
|
Object.keys(currentWorkers).forEach((workerHash) => {
|
||||||
if (
|
if (
|
||||||
currentWorkers[workerHash].part < minPart ||
|
currentWorkers[workerHash].part < minPart
|
||||||
currentWorkers[workerHash].part > maxPart
|
|| currentWorkers[workerHash].part > maxPart
|
||||||
) {
|
) {
|
||||||
this.cancelWorker(workerHash);
|
this.cancelWorker(workerHash);
|
||||||
}
|
}
|
||||||
|
@ -406,12 +408,12 @@ export default class CanExplorer extends Component {
|
||||||
|
|
||||||
// clean this up just in case, the cancel process above *should* have already done this
|
// clean this up just in case, the cancel process above *should* have already done this
|
||||||
// they have at most 4 entries so it's trivial
|
// they have at most 4 entries so it's trivial
|
||||||
loadingParts = loadingParts.filter(p => p >= minPart && p <= maxPart);
|
loadingParts = loadingParts.filter((p) => p >= minPart && p <= maxPart);
|
||||||
loadedParts = loadedParts.filter(p => p >= minPart && p <= maxPart);
|
loadedParts = loadedParts.filter((p) => p >= minPart && p <= maxPart);
|
||||||
|
|
||||||
let part = -1;
|
let part = -1;
|
||||||
let allWorkerParts = Object.keys(currentWorkers).map(
|
const allWorkerParts = Object.keys(currentWorkers).map(
|
||||||
i => currentWorkers[i].part
|
(i) => currentWorkers[i].part
|
||||||
);
|
);
|
||||||
|
|
||||||
for (let partOffset = 0; partOffset <= maxPart - minPart; ++partOffset) {
|
for (let partOffset = 0; partOffset <= maxPart - minPart; ++partOffset) {
|
||||||
|
@ -425,15 +427,15 @@ export default class CanExplorer extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (part === -1) {
|
if (part === -1) {
|
||||||
console.log("Loading complete");
|
console.log('Loading complete');
|
||||||
this.setState({ isLoading: false });
|
this.setState({ isLoading: false });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("Starting worker for part", part);
|
console.log('Starting worker for part', part);
|
||||||
// options is object of {part, prevMsgEntries, spawnWorkerHash, prepend}
|
// options is object of {part, prevMsgEntries, spawnWorkerHash, prepend}
|
||||||
options = options || {};
|
options = options || {};
|
||||||
let prevMsgEntries = options.prevMsgEntries;
|
let { prevMsgEntries } = options;
|
||||||
let prepend = false;
|
const prepend = false;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
dbc,
|
dbc,
|
||||||
|
@ -446,19 +448,19 @@ export default class CanExplorer extends Component {
|
||||||
|
|
||||||
if (!prevMsgEntries) {
|
if (!prevMsgEntries) {
|
||||||
// we have previous messages loaded
|
// we have previous messages loaded
|
||||||
let { messages } = this.state;
|
const { messages } = this.state;
|
||||||
let canStartTime = firstCanTime - canFrameOffset;
|
const canStartTime = firstCanTime - canFrameOffset;
|
||||||
prevMsgEntries = {};
|
prevMsgEntries = {};
|
||||||
Object.keys(messages).forEach(function(key) {
|
Object.keys(messages).forEach((key) => {
|
||||||
let entries = messages[key].entries;
|
const { entries } = messages[key];
|
||||||
prevMsgEntries[key] = entries[entries.length - 1];
|
prevMsgEntries[key] = entries[entries.length - 1];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// var worker = new CanFetcher();
|
// var worker = new CanFetcher();
|
||||||
var worker = new RLogDownloader();
|
const worker = new RLogDownloader();
|
||||||
|
|
||||||
let spawnWorkerHash = hash(Math.random().toString(16));
|
const spawnWorkerHash = hash(Math.random().toString(16));
|
||||||
currentWorkers[spawnWorkerHash] = {
|
currentWorkers[spawnWorkerHash] = {
|
||||||
part,
|
part,
|
||||||
worker
|
worker
|
||||||
|
@ -471,9 +473,9 @@ export default class CanExplorer extends Component {
|
||||||
loadingParts
|
loadingParts
|
||||||
});
|
});
|
||||||
|
|
||||||
worker.onmessage = e => {
|
worker.onmessage = (e) => {
|
||||||
if (this.state.currentWorkers[spawnWorkerHash] === undefined) {
|
if (this.state.currentWorkers[spawnWorkerHash] === undefined) {
|
||||||
console.log("Worker was canceled");
|
console.log('Worker was canceled');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,16 +497,15 @@ export default class CanExplorer extends Component {
|
||||||
maxByteStateChangeCount
|
maxByteStateChangeCount
|
||||||
);
|
);
|
||||||
const prevMsgEntries = {};
|
const prevMsgEntries = {};
|
||||||
for (let key in newMessages) {
|
for (const key in newMessages) {
|
||||||
prevMsgEntries[key] =
|
prevMsgEntries[key] = newMessages[key].entries[newMessages[key].entries.length - 1];
|
||||||
newMessages[key].entries[newMessages[key].entries.length - 1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isFinished) {
|
if (!isFinished) {
|
||||||
this.setState({ messages });
|
this.setState({ messages });
|
||||||
} else {
|
} else {
|
||||||
let loadingParts = this.state.loadingParts.filter(p => p !== part);
|
const loadingParts = this.state.loadingParts.filter((p) => p !== part);
|
||||||
let loadedParts = [part, ...this.state.loadedParts];
|
const loadedParts = [part, ...this.state.loadedParts];
|
||||||
|
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
|
@ -537,7 +538,7 @@ export default class CanExplorer extends Component {
|
||||||
// data that is used
|
// data that is used
|
||||||
dbcText: dbc.text(),
|
dbcText: dbc.text(),
|
||||||
route: route.fullname,
|
route: route.fullname,
|
||||||
part: part,
|
part,
|
||||||
canStartTime: firstCanTime != null ? firstCanTime - canFrameOffset : null,
|
canStartTime: firstCanTime != null ? firstCanTime - canFrameOffset : null,
|
||||||
prevMsgEntries,
|
prevMsgEntries,
|
||||||
maxByteStateChangeCount
|
maxByteStateChangeCount
|
||||||
|
@ -553,11 +554,11 @@ export default class CanExplorer extends Component {
|
||||||
showEditMessageModal
|
showEditMessageModal
|
||||||
} = this.state;
|
} = this.state;
|
||||||
return (
|
return (
|
||||||
showOnboarding ||
|
showOnboarding
|
||||||
showLoadDbc ||
|
|| showLoadDbc
|
||||||
showSaveDbc ||
|
|| showSaveDbc
|
||||||
showAddSignal ||
|
|| showAddSignal
|
||||||
showEditMessageModal
|
|| showEditMessageModal
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -589,8 +590,8 @@ export default class CanExplorer extends Component {
|
||||||
this.setState({ isLoading: true });
|
this.setState({ isLoading: true });
|
||||||
|
|
||||||
const { dbc } = this.state;
|
const { dbc } = this.state;
|
||||||
var worker = new MessageParser();
|
const worker = new MessageParser();
|
||||||
worker.onmessage = e => {
|
worker.onmessage = (e) => {
|
||||||
let messages = e.data;
|
let messages = e.data;
|
||||||
messages = this.addAndRehydrateMessages(messages, { replace: true });
|
messages = this.addAndRehydrateMessages(messages, { replace: true });
|
||||||
|
|
||||||
|
@ -616,7 +617,7 @@ export default class CanExplorer extends Component {
|
||||||
if (route) {
|
if (route) {
|
||||||
persistDbc(route.fullname, { dbcFilename, dbc });
|
persistDbc(route.fullname, { dbcFilename, dbc });
|
||||||
} else {
|
} else {
|
||||||
persistDbc("live", { dbcFilename, dbc });
|
persistDbc('live', { dbcFilename, dbc });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,19 +636,17 @@ export default class CanExplorer extends Component {
|
||||||
|
|
||||||
messages[message.id] = newMessage;
|
messages[message.id] = newMessage;
|
||||||
|
|
||||||
this.setState({ dbc, dbcText: dbc.text() }, () =>
|
this.setState({ dbc, dbcText: dbc.text() }, () => this.reparseMessages(messages));
|
||||||
this.reparseMessages(messages)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
partChangeDebounced = debounce(() => {
|
partChangeDebounced = debounce(() => {
|
||||||
let [minPart, maxPart] = this.state.currentParts;
|
const [minPart, maxPart] = this.state.currentParts;
|
||||||
let messages = { ...this.state.messages };
|
const messages = { ...this.state.messages };
|
||||||
// update messages to only preserve entries in new part range
|
// update messages to only preserve entries in new part range
|
||||||
let minTime = minPart * 60;
|
const minTime = minPart * 60;
|
||||||
let maxTime = maxPart * 60 + 60;
|
const maxTime = maxPart * 60 + 60;
|
||||||
Object.keys(messages).forEach(key => {
|
Object.keys(messages).forEach((key) => {
|
||||||
let entries = messages[key].entries;
|
const { entries } = messages[key];
|
||||||
let minIndex = 0;
|
let minIndex = 0;
|
||||||
let maxIndex = entries.length - 1;
|
let maxIndex = entries.length - 1;
|
||||||
while (minIndex < entries.length && entries[minIndex].relTime < minTime) {
|
while (minIndex < entries.length && entries[minIndex].relTime < minTime) {
|
||||||
|
@ -669,14 +668,16 @@ export default class CanExplorer extends Component {
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
onPartChange(part) {
|
onPartChange(part) {
|
||||||
let { currentParts, currentPart, canFrameOffset, route } = this.state;
|
let {
|
||||||
|
currentParts, currentPart, canFrameOffset, route
|
||||||
|
} = this.state;
|
||||||
if (canFrameOffset === -1 || part === currentPart) {
|
if (canFrameOffset === -1 || part === currentPart) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine new parts to load, whether to prepend or append
|
// determine new parts to load, whether to prepend or append
|
||||||
let maxPart = Math.min(route.proclog, part + 1);
|
let maxPart = Math.min(route.proclog, part + 1);
|
||||||
let minPart = Math.max(0, maxPart - PART_SEGMENT_LENGTH + 1);
|
const minPart = Math.max(0, maxPart - PART_SEGMENT_LENGTH + 1);
|
||||||
if (minPart === 0) {
|
if (minPart === 0) {
|
||||||
maxPart = Math.min(route.proclog, 2);
|
maxPart = Math.min(route.proclog, 2);
|
||||||
}
|
}
|
||||||
|
@ -687,9 +688,9 @@ export default class CanExplorer extends Component {
|
||||||
currentPart = part;
|
currentPart = part;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
currentPart !== this.state.currentPart ||
|
currentPart !== this.state.currentPart
|
||||||
currentParts[0] !== this.state.currentParts[0] ||
|
|| currentParts[0] !== this.state.currentParts[0]
|
||||||
currentParts[1] !== this.state.currentParts[1]
|
|| currentParts[1] !== this.state.currentParts[1]
|
||||||
) {
|
) {
|
||||||
// update state then load new parts
|
// update state then load new parts
|
||||||
this.setState({ currentParts, currentPart }, this.partChangeDebounced);
|
this.setState({ currentParts, currentPart }, this.partChangeDebounced);
|
||||||
|
@ -715,9 +716,11 @@ export default class CanExplorer extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessageFrameEdited(messageFrame) {
|
onMessageFrameEdited(messageFrame) {
|
||||||
const { messages, dbcFilename, dbc, editMessageModalMessage } = this.state;
|
const {
|
||||||
|
messages, dbcFilename, dbc, editMessageModalMessage
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
const message = Object.assign({}, messages[editMessageModalMessage]);
|
const message = { ...messages[editMessageModalMessage] };
|
||||||
message.frame = messageFrame;
|
message.frame = messageFrame;
|
||||||
dbc.messages.set(messageFrame.id, messageFrame);
|
dbc.messages.set(messageFrame.id, messageFrame);
|
||||||
this.persistDbc({ dbcFilename, dbc });
|
this.persistDbc({ dbcFilename, dbc });
|
||||||
|
@ -730,8 +733,8 @@ export default class CanExplorer extends Component {
|
||||||
onSeek(seekIndex, seekTime) {
|
onSeek(seekIndex, seekTime) {
|
||||||
this.setState({ seekIndex, seekTime });
|
this.setState({ seekIndex, seekTime });
|
||||||
|
|
||||||
let { currentPart } = this.state;
|
const { currentPart } = this.state;
|
||||||
let part = ~~(seekTime / 60);
|
const part = ~~(seekTime / 60);
|
||||||
if (part !== currentPart) {
|
if (part !== currentPart) {
|
||||||
this.onPartChange(part);
|
this.onPartChange(part);
|
||||||
}
|
}
|
||||||
|
@ -745,7 +748,7 @@ export default class CanExplorer extends Component {
|
||||||
const msg = this.state.messages[this.state.selectedMessage];
|
const msg = this.state.messages[this.state.selectedMessage];
|
||||||
let seekIndex;
|
let seekIndex;
|
||||||
if (msg) {
|
if (msg) {
|
||||||
seekIndex = msg.entries.findIndex(e => e.relTime >= seekTime);
|
seekIndex = msg.entries.findIndex((e) => e.relTime >= seekTime);
|
||||||
if (seekIndex === -1) {
|
if (seekIndex === -1) {
|
||||||
seekIndex = 0;
|
seekIndex = 0;
|
||||||
}
|
}
|
||||||
|
@ -761,7 +764,7 @@ export default class CanExplorer extends Component {
|
||||||
const msg = messages[msgKey];
|
const msg = messages[msgKey];
|
||||||
|
|
||||||
if (seekTime > 0 && msg.entries.length > 0) {
|
if (seekTime > 0 && msg.entries.length > 0) {
|
||||||
seekIndex = msg.entries.findIndex(e => e.relTime >= seekTime);
|
seekIndex = msg.entries.findIndex((e) => e.relTime >= seekTime);
|
||||||
if (seekIndex === -1) {
|
if (seekIndex === -1) {
|
||||||
seekIndex = 0;
|
seekIndex = 0;
|
||||||
}
|
}
|
||||||
|
@ -785,7 +788,7 @@ export default class CanExplorer extends Component {
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
href={GithubAuth.authorizeUrl(
|
href={GithubAuth.authorizeUrl(
|
||||||
route && route.fullname ? route.fullname : ""
|
route && route.fullname ? route.fullname : ''
|
||||||
)}
|
)}
|
||||||
className="button button--dark button--inline"
|
className="button button--dark button--inline"
|
||||||
>
|
>
|
||||||
|
@ -847,7 +850,7 @@ export default class CanExplorer extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
enforceStreamingMessageWindow(messages) {
|
enforceStreamingMessageWindow(messages) {
|
||||||
let messageIds = Object.keys(messages);
|
const messageIds = Object.keys(messages);
|
||||||
for (let i = 0; i < messageIds.length; i++) {
|
for (let i = 0; i < messageIds.length; i++) {
|
||||||
const messageId = messageIds[i];
|
const messageId = messageIds[i];
|
||||||
const message = messages[messageId];
|
const message = messages[messageId];
|
||||||
|
@ -886,8 +889,8 @@ export default class CanExplorer extends Component {
|
||||||
messages = this.enforceStreamingMessageWindow(messages);
|
messages = this.enforceStreamingMessageWindow(messages);
|
||||||
let { seekIndex, selectedMessages } = this.state;
|
let { seekIndex, selectedMessages } = this.state;
|
||||||
if (
|
if (
|
||||||
selectedMessages.length > 0 &&
|
selectedMessages.length > 0
|
||||||
messages[selectedMessages[0]] !== undefined
|
&& messages[selectedMessages[0]] !== undefined
|
||||||
) {
|
) {
|
||||||
seekIndex = Math.max(0, messages[selectedMessages[0]].entries.length - 1);
|
seekIndex = Math.max(0, messages[selectedMessages[0]].entries.length - 1);
|
||||||
}
|
}
|
||||||
|
@ -908,16 +911,16 @@ export default class CanExplorer extends Component {
|
||||||
async handlePandaConnect(e) {
|
async handlePandaConnect(e) {
|
||||||
this.setState({ attemptingPandaConnection: true, live: true });
|
this.setState({ attemptingPandaConnection: true, live: true });
|
||||||
|
|
||||||
const persistedDbc = fetchPersistedDbc("live");
|
const persistedDbc = fetchPersistedDbc('live');
|
||||||
if (persistedDbc) {
|
if (persistedDbc) {
|
||||||
let { dbc, dbcText } = persistedDbc;
|
const { dbc, dbcText } = persistedDbc;
|
||||||
this.setState({ dbc, dbcText });
|
this.setState({ dbc, dbcText });
|
||||||
}
|
}
|
||||||
this.canStreamerWorker = new CanStreamerWorker();
|
this.canStreamerWorker = new CanStreamerWorker();
|
||||||
this.canStreamerWorker.onmessage = this.onStreamedCanMessagesProcessed;
|
this.canStreamerWorker.onmessage = this.onStreamedCanMessagesProcessed;
|
||||||
|
|
||||||
// if any errors go off during connection, mark as not trying to connect anymore...
|
// if any errors go off during connection, mark as not trying to connect anymore...
|
||||||
let unlisten = this.pandaReader.onError(err => {
|
const unlisten = this.pandaReader.onError((err) => {
|
||||||
console.error(err.stack || err);
|
console.error(err.stack || err);
|
||||||
this.setState({ attemptingPandaConnection: false });
|
this.setState({ attemptingPandaConnection: false });
|
||||||
});
|
});
|
||||||
|
@ -943,7 +946,7 @@ export default class CanExplorer extends Component {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id="cabana"
|
id="cabana"
|
||||||
className={cx({ "is-showing-modal": this.showingModal() })}
|
className={cx({ 'is-showing-modal': this.showingModal() })}
|
||||||
>
|
>
|
||||||
{this.state.isLoading ? (
|
{this.state.isLoading ? (
|
||||||
<LoadingBar isLoading={this.state.isLoading} />
|
<LoadingBar isLoading={this.state.isLoading} />
|
||||||
|
|
|
@ -1,27 +1,28 @@
|
||||||
global.__JEST__ = 1;
|
import DBC from '../../models/can/dbc';
|
||||||
import DBC from "../../models/can/dbc";
|
import Signal from '../../models/can/signal';
|
||||||
import Signal from "../../models/can/signal";
|
|
||||||
|
|
||||||
test("setting signals should create a message", () => {
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
|
test('setting signals should create a message', () => {
|
||||||
const dbc = new DBC();
|
const dbc = new DBC();
|
||||||
dbc.setSignals(100, { "My Signal": new Signal({ name: "My Signal" }) });
|
dbc.setSignals(100, { 'My Signal': new Signal({ name: 'My Signal' }) });
|
||||||
|
|
||||||
expect(dbc.messages.has(100)).toBe(true);
|
expect(dbc.messages.has(100)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("setting signals should update DBC.boardUnits", () => {
|
test('setting signals should update DBC.boardUnits', () => {
|
||||||
const dbc = new DBC();
|
const dbc = new DBC();
|
||||||
dbc.setSignals(100, {
|
dbc.setSignals(100, {
|
||||||
"My Signal": new Signal({ name: "My Signal", receiver: ["NEO"] })
|
'My Signal': new Signal({ name: 'My Signal', receiver: ['NEO'] })
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(dbc.boardUnits.map(bu => bu.name).indexOf("NEO")).toBe(0);
|
expect(dbc.boardUnits.map((bu) => bu.name).indexOf('NEO')).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("adding a signal should update DBC.boardUnits", () => {
|
test('adding a signal should update DBC.boardUnits', () => {
|
||||||
const dbc = new DBC();
|
const dbc = new DBC();
|
||||||
dbc.createFrame(100);
|
dbc.createFrame(100);
|
||||||
dbc.addSignal(100, new Signal({ name: "My Signal", receiver: ["NEO"] }));
|
dbc.addSignal(100, new Signal({ name: 'My Signal', receiver: ['NEO'] }));
|
||||||
|
|
||||||
expect(dbc.boardUnits.map(bu => bu.name).indexOf("NEO")).toBe(0);
|
expect(dbc.boardUnits.map((bu) => bu.name).indexOf('NEO')).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
import DBC, { swapOrder } from '../../models/can/dbc';
|
||||||
|
import Signal from '../../models/can/signal';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
import DBC, { swapOrder } from "../../models/can/dbc";
|
|
||||||
import Signal from "../../models/can/signal";
|
|
||||||
|
|
||||||
const DBC_MESSAGE_DEF = `BO_ 228 STEERING_CONTROL: 5 ADAS
|
const DBC_MESSAGE_DEF = `BO_ 228 STEERING_CONTROL: 5 ADAS
|
||||||
SG_ STEER_TORQUE : 7|16@0- (1,0) [-3840|3840] "" EPS
|
SG_ STEER_TORQUE : 7|16@0- (1,0) [-3840|3840] "" EPS
|
||||||
|
@ -145,7 +146,7 @@ BO_ 464 WHEEL_SPEEDS: 8 VSA
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const steerTorqueSignal = new Signal({
|
const steerTorqueSignal = new Signal({
|
||||||
name: "STEER_TORQUE",
|
name: 'STEER_TORQUE',
|
||||||
startBit: 7,
|
startBit: 7,
|
||||||
size: 16,
|
size: 16,
|
||||||
isLittleEndian: false,
|
isLittleEndian: false,
|
||||||
|
@ -154,165 +155,165 @@ const steerTorqueSignal = new Signal({
|
||||||
offset: 0,
|
offset: 0,
|
||||||
min: -3840,
|
min: -3840,
|
||||||
max: 3840,
|
max: 3840,
|
||||||
receiver: ["EPS"],
|
receiver: ['EPS'],
|
||||||
unit: ""
|
unit: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
function dbcInt32SignalValue(dbc, signalSpec, hex) {
|
function dbcInt32SignalValue(dbc, signalSpec, hex) {
|
||||||
// expects hex string to represent 8 bytes, left-justified with zeroes if frame size is smaller
|
// expects hex string to represent 8 bytes, left-justified with zeroes if frame size is smaller
|
||||||
const buffer = Buffer.from(hex, "hex");
|
const buffer = Buffer.from(hex, 'hex');
|
||||||
|
|
||||||
return dbc.valueForInt32Signal(signalSpec, buffer);
|
return dbc.valueForInt32Signal(signalSpec, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
test("DBC parses steering control message", () => {
|
test('DBC parses steering control message', () => {
|
||||||
const dbcParsed = new DBC(DBC_MESSAGE_DEF);
|
const dbcParsed = new DBC(DBC_MESSAGE_DEF);
|
||||||
const { signals } = dbcParsed.getMessageFrame(228);
|
const { signals } = dbcParsed.getMessageFrame(228);
|
||||||
|
|
||||||
expect(Object.keys(signals).length).toBe(6);
|
expect(Object.keys(signals).length).toBe(6);
|
||||||
expect(signals["STEER_TORQUE"].equals(steerTorqueSignal)).toBe(true);
|
expect(signals.STEER_TORQUE.equals(steerTorqueSignal)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("DBC parses signal comment", () => {
|
test('DBC parses signal comment', () => {
|
||||||
const dbcParsed = new DBC(DBC_SIGNAL_WITH_COMMENT);
|
const dbcParsed = new DBC(DBC_SIGNAL_WITH_COMMENT);
|
||||||
const { signals } = dbcParsed.getMessageFrame(228);
|
const { signals } = dbcParsed.getMessageFrame(228);
|
||||||
|
|
||||||
expect(signals.STEER_TORQUE.comment).toEqual(
|
expect(signals.STEER_TORQUE.comment).toEqual(
|
||||||
"steer torque is the amount of torque in Nm applied"
|
'steer torque is the amount of torque in Nm applied'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("DBC parses multi-line signal comment", () => {
|
test('DBC parses multi-line signal comment', () => {
|
||||||
const dbcParsed = new DBC(DBC_SIGNAL_WITH_MULTI_LINE_COMMENT);
|
const dbcParsed = new DBC(DBC_SIGNAL_WITH_MULTI_LINE_COMMENT);
|
||||||
const { signals } = dbcParsed.getMessageFrame(228);
|
const { signals } = dbcParsed.getMessageFrame(228);
|
||||||
|
|
||||||
expect(signals.STEER_TORQUE.comment).toEqual(
|
expect(signals.STEER_TORQUE.comment).toEqual(
|
||||||
"steer torque is the\namount of torque in Nm applied"
|
'steer torque is the\namount of torque in Nm applied'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("DBC parses message comment", () => {
|
test('DBC parses message comment', () => {
|
||||||
const dbcParsed = new DBC(DBC_MESSAGE_WITH_COMMENT);
|
const dbcParsed = new DBC(DBC_MESSAGE_WITH_COMMENT);
|
||||||
const msg = dbcParsed.getMessageFrame(228);
|
const msg = dbcParsed.getMessageFrame(228);
|
||||||
|
|
||||||
expect(msg.comment).toEqual("this message contains steer torque information");
|
expect(msg.comment).toEqual('this message contains steer torque information');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("DBC parses multi-line message comment", () => {
|
test('DBC parses multi-line message comment', () => {
|
||||||
const dbcParsed = new DBC(DBC_MESSAGE_WITH_MULTI_LINE_COMMENT);
|
const dbcParsed = new DBC(DBC_MESSAGE_WITH_MULTI_LINE_COMMENT);
|
||||||
const msg = dbcParsed.getMessageFrame(228);
|
const msg = dbcParsed.getMessageFrame(228);
|
||||||
|
|
||||||
expect(msg.comment).toEqual(
|
expect(msg.comment).toEqual(
|
||||||
"this message contains\nsteer torque information"
|
'this message contains\nsteer torque information'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("DBC parses board unit names", () => {
|
test('DBC parses board unit names', () => {
|
||||||
const dbcParsed = new DBC(DBC_BOARD_UNITS);
|
const dbcParsed = new DBC(DBC_BOARD_UNITS);
|
||||||
expect(dbcParsed.boardUnits[0].name).toEqual("first_board_unit");
|
expect(dbcParsed.boardUnits[0].name).toEqual('first_board_unit');
|
||||||
expect(dbcParsed.boardUnits[1].name).toEqual("second_board_unit");
|
expect(dbcParsed.boardUnits[1].name).toEqual('second_board_unit');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("DBC parses board unit comments", () => {
|
test('DBC parses board unit comments', () => {
|
||||||
const dbcParsed = new DBC(DBC_BOARD_UNITS_WITH_COMMENT);
|
const dbcParsed = new DBC(DBC_BOARD_UNITS_WITH_COMMENT);
|
||||||
expect(dbcParsed.boardUnits[0].comment).toEqual("first board unit comment");
|
expect(dbcParsed.boardUnits[0].comment).toEqual('first board unit comment');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("DBC parses multi-line board unit comments", () => {
|
test('DBC parses multi-line board unit comments', () => {
|
||||||
const dbcParsed = new DBC(DBC_BOARD_UNITS_WITH_COMMENT_LINES);
|
const dbcParsed = new DBC(DBC_BOARD_UNITS_WITH_COMMENT_LINES);
|
||||||
expect(dbcParsed.boardUnits[0].comment).toEqual("first board unit\ncomment");
|
expect(dbcParsed.boardUnits[0].comment).toEqual('first board unit\ncomment');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("DBC parses signal value descriptions", () => {
|
test('DBC parses signal value descriptions', () => {
|
||||||
const dbcParsed = new DBC(DBC_SIGNALS_WITH_VAL);
|
const dbcParsed = new DBC(DBC_SIGNALS_WITH_VAL);
|
||||||
const { signals } = dbcParsed.getMessageFrame(228);
|
const { signals } = dbcParsed.getMessageFrame(228);
|
||||||
|
|
||||||
const expectedTorqueRequestVals = new Map([
|
const expectedTorqueRequestVals = new Map([
|
||||||
["1", "requesting torque"],
|
['1', 'requesting torque'],
|
||||||
["0", "not requesting torque"]
|
['0', 'not requesting torque']
|
||||||
]);
|
]);
|
||||||
expect(signals.STEER_TORQUE_REQUEST.valueDescriptions).toEqual(
|
expect(signals.STEER_TORQUE_REQUEST.valueDescriptions).toEqual(
|
||||||
expectedTorqueRequestVals
|
expectedTorqueRequestVals
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("DBC parses value tables", () => {
|
test('DBC parses value tables', () => {
|
||||||
const dbcParsed = new DBC(DBC_VALUE_TABLE);
|
const dbcParsed = new DBC(DBC_VALUE_TABLE);
|
||||||
const stateTableEntries = [
|
const stateTableEntries = [
|
||||||
["4", "DI_STATE_ENABLE"],
|
['4', 'DI_STATE_ENABLE'],
|
||||||
["3", "DI_STATE_FAULT"],
|
['3', 'DI_STATE_FAULT'],
|
||||||
["2", "DI_STATE_CLEAR_FAULT"],
|
['2', 'DI_STATE_CLEAR_FAULT'],
|
||||||
["1", "DI_STATE_STANDBY"],
|
['1', 'DI_STATE_STANDBY'],
|
||||||
["0", "DI_STATE_PREAUTH"]
|
['0', 'DI_STATE_PREAUTH']
|
||||||
];
|
];
|
||||||
const stateTable = new Map(stateTableEntries);
|
const stateTable = new Map(stateTableEntries);
|
||||||
const speedUnitsEntries = [["1", "DI_SPEED_KPH"], ["0", "DI_SPEED_MPH"]];
|
const speedUnitsEntries = [['1', 'DI_SPEED_KPH'], ['0', 'DI_SPEED_MPH']];
|
||||||
const speedUnitsTable = new Map(speedUnitsEntries);
|
const speedUnitsTable = new Map(speedUnitsEntries);
|
||||||
|
|
||||||
const valueTableEntries = Array.from(dbcParsed.valueTables.entries());
|
const valueTableEntries = Array.from(dbcParsed.valueTables.entries());
|
||||||
expect(valueTableEntries[0]).toEqual(["DI_state", stateTable]);
|
expect(valueTableEntries[0]).toEqual(['DI_state', stateTable]);
|
||||||
expect(valueTableEntries[1]).toEqual(["DI_speedUnits", speedUnitsTable]);
|
expect(valueTableEntries[1]).toEqual(['DI_speedUnits', speedUnitsTable]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("swapOrder properly converts little endian to big endian", () => {
|
test('swapOrder properly converts little endian to big endian', () => {
|
||||||
const littleEndianHex = "e2d62a0bd0d3b5e5";
|
const littleEndianHex = 'e2d62a0bd0d3b5e5';
|
||||||
const bigEndianHex = "e5b5d3d00b2ad6e2";
|
const bigEndianHex = 'e5b5d3d00b2ad6e2';
|
||||||
|
|
||||||
const littleEndianHexSwapped = swapOrder(littleEndianHex, 16, 2);
|
const littleEndianHexSwapped = swapOrder(littleEndianHex, 16, 2);
|
||||||
|
|
||||||
expect(littleEndianHexSwapped == bigEndianHex).toBe(true);
|
expect(littleEndianHexSwapped == bigEndianHex).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("int32 parser produces correct value for steer torque signal", () => {
|
test('int32 parser produces correct value for steer torque signal', () => {
|
||||||
const dbc = new DBC(DBC_MESSAGE_DEF);
|
const dbc = new DBC(DBC_MESSAGE_DEF);
|
||||||
|
|
||||||
const hex = "e2d62a0bd0d3b5e5";
|
const hex = 'e2d62a0bd0d3b5e5';
|
||||||
const value = dbcInt32SignalValue(
|
const value = dbcInt32SignalValue(
|
||||||
dbc,
|
dbc,
|
||||||
dbc.getMessageFrame(228).signals["STEER_TORQUE"],
|
dbc.getMessageFrame(228).signals.STEER_TORQUE,
|
||||||
hex
|
hex
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(value).toBe(-7466);
|
expect(value).toBe(-7466);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("int64 parser produces correct value for steer torque signal", () => {
|
test('int64 parser produces correct value for steer torque signal', () => {
|
||||||
const dbc = new DBC(DBC_MESSAGE_DEF);
|
const dbc = new DBC(DBC_MESSAGE_DEF);
|
||||||
|
|
||||||
const hex = "e2d62a0bd0d3b5e5";
|
const hex = 'e2d62a0bd0d3b5e5';
|
||||||
const value = dbc.valueForInt64Signal(steerTorqueSignal, hex);
|
const value = dbc.valueForInt64Signal(steerTorqueSignal, hex);
|
||||||
|
|
||||||
expect(value).toBe(-7466);
|
expect(value).toBe(-7466);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("int32 parser produces correct value for wheel speeds", () => {
|
test('int32 parser produces correct value for wheel speeds', () => {
|
||||||
const dbc = new DBC(DBC_WHEEL_SPEEDS);
|
const dbc = new DBC(DBC_WHEEL_SPEEDS);
|
||||||
|
|
||||||
const hex = "36806cd8d8f1b0b7";
|
const hex = '36806cd8d8f1b0b7';
|
||||||
const rearRight = dbcInt32SignalValue(
|
const rearRight = dbcInt32SignalValue(
|
||||||
dbc,
|
dbc,
|
||||||
dbc.getMessageFrame(464).signals["WHEEL_SPEED_RR"],
|
dbc.getMessageFrame(464).signals.WHEEL_SPEED_RR,
|
||||||
hex
|
hex
|
||||||
);
|
);
|
||||||
expect(rearRight).toBe(69.23);
|
expect(rearRight).toBe(69.23);
|
||||||
|
|
||||||
const rearLeft = dbcInt32SignalValue(
|
const rearLeft = dbcInt32SignalValue(
|
||||||
dbc,
|
dbc,
|
||||||
dbc.getMessageFrame(464).signals["WHEEL_SPEED_RL"],
|
dbc.getMessageFrame(464).signals.WHEEL_SPEED_RL,
|
||||||
hex
|
hex
|
||||||
);
|
);
|
||||||
expect(rearLeft).toBe(69.42);
|
expect(rearLeft).toBe(69.42);
|
||||||
|
|
||||||
const frontLeft = dbcInt32SignalValue(
|
const frontLeft = dbcInt32SignalValue(
|
||||||
dbc,
|
dbc,
|
||||||
dbc.getMessageFrame(464).signals["WHEEL_SPEED_FL"],
|
dbc.getMessageFrame(464).signals.WHEEL_SPEED_FL,
|
||||||
hex
|
hex
|
||||||
);
|
);
|
||||||
expect(frontLeft).toBe(69.76);
|
expect(frontLeft).toBe(69.76);
|
||||||
|
|
||||||
const frontRight = dbcInt32SignalValue(
|
const frontRight = dbcInt32SignalValue(
|
||||||
dbc,
|
dbc,
|
||||||
dbc.getMessageFrame(464).signals["WHEEL_SPEED_FR"],
|
dbc.getMessageFrame(464).signals.WHEEL_SPEED_FR,
|
||||||
hex
|
hex
|
||||||
);
|
);
|
||||||
expect(frontRight).toBe(69.66);
|
expect(frontRight).toBe(69.66);
|
||||||
|
@ -323,12 +324,12 @@ BO_ 768 NEW_MSG_1: 8 XXX
|
||||||
SG_ NEW_SIGNAL_1 : 37|1@1+ (1,0) [0|1] "" XXX
|
SG_ NEW_SIGNAL_1 : 37|1@1+ (1,0) [0|1] "" XXX
|
||||||
`;
|
`;
|
||||||
|
|
||||||
test("int32 parsers produces correct value for binary little endian signal", () => {
|
test('int32 parsers produces correct value for binary little endian signal', () => {
|
||||||
const dbc = new DBC(DBC_BINARY_LE_SIGNAL);
|
const dbc = new DBC(DBC_BINARY_LE_SIGNAL);
|
||||||
const signalSpec = dbc.getMessageFrame(768).signals["NEW_SIGNAL_1"];
|
const signalSpec = dbc.getMessageFrame(768).signals.NEW_SIGNAL_1;
|
||||||
|
|
||||||
const hexDataSet = "0000000020000000";
|
const hexDataSet = '0000000020000000';
|
||||||
const hexDataNotSet = "0000000000000000";
|
const hexDataNotSet = '0000000000000000';
|
||||||
|
|
||||||
const setValue = dbcInt32SignalValue(dbc, signalSpec, hexDataSet, 8);
|
const setValue = dbcInt32SignalValue(dbc, signalSpec, hexDataSet, 8);
|
||||||
const notSetValue = dbcInt32SignalValue(dbc, signalSpec, hexDataNotSet, 8);
|
const notSetValue = dbcInt32SignalValue(dbc, signalSpec, hexDataNotSet, 8);
|
||||||
|
@ -341,11 +342,11 @@ const DBC_TWO_BIT_LE_SIGNAL = `
|
||||||
BO_ 768 NEW_MSG_1: 8 XXX
|
BO_ 768 NEW_MSG_1: 8 XXX
|
||||||
SG_ NEW_SIGNAL_1 : 35|2@1+ (1,0) [0|3] "" XXX
|
SG_ NEW_SIGNAL_1 : 35|2@1+ (1,0) [0|3] "" XXX
|
||||||
`;
|
`;
|
||||||
test("int32 parser produces correct value for 2-bit little endian signal spanning words", () => {
|
test('int32 parser produces correct value for 2-bit little endian signal spanning words', () => {
|
||||||
const dbc = new DBC(DBC_TWO_BIT_LE_SIGNAL);
|
const dbc = new DBC(DBC_TWO_BIT_LE_SIGNAL);
|
||||||
const signalSpec = dbc.getMessageFrame(768).signals["NEW_SIGNAL_1"];
|
const signalSpec = dbc.getMessageFrame(768).signals.NEW_SIGNAL_1;
|
||||||
|
|
||||||
const hexData = "00000001f8000000";
|
const hexData = '00000001f8000000';
|
||||||
|
|
||||||
const value = dbcInt32SignalValue(dbc, signalSpec, hexData, 8);
|
const value = dbcInt32SignalValue(dbc, signalSpec, hexData, 8);
|
||||||
expect(value).toEqual(3);
|
expect(value).toEqual(3);
|
||||||
|
@ -355,17 +356,17 @@ const DBC_FOUR_BIT_LE_SIGNAL = `
|
||||||
BO_ 768 NEW_MSG_1: 8 XXX
|
BO_ 768 NEW_MSG_1: 8 XXX
|
||||||
SG_ NEW_SIGNAL_1 : 6|4@1+ (1,0) [0|15] "" XXX
|
SG_ NEW_SIGNAL_1 : 6|4@1+ (1,0) [0|15] "" XXX
|
||||||
`;
|
`;
|
||||||
test("int32 parser produces correct value for 4-bit little endian signal", () => {
|
test('int32 parser produces correct value for 4-bit little endian signal', () => {
|
||||||
const dbc = new DBC(DBC_FOUR_BIT_LE_SIGNAL);
|
const dbc = new DBC(DBC_FOUR_BIT_LE_SIGNAL);
|
||||||
const signalSpec = dbc.getMessageFrame(768).signals["NEW_SIGNAL_1"];
|
const signalSpec = dbc.getMessageFrame(768).signals.NEW_SIGNAL_1;
|
||||||
|
|
||||||
// this data is symmetric, the data bits are 1111
|
// this data is symmetric, the data bits are 1111
|
||||||
const hexDataSymmetric = "f00f000000000000";
|
const hexDataSymmetric = 'f00f000000000000';
|
||||||
const symValue = dbcInt32SignalValue(dbc, signalSpec, hexDataSymmetric, 8);
|
const symValue = dbcInt32SignalValue(dbc, signalSpec, hexDataSymmetric, 8);
|
||||||
expect(symValue).toEqual(15);
|
expect(symValue).toEqual(15);
|
||||||
|
|
||||||
// this data is asymmetric, the data bits are 1101
|
// this data is asymmetric, the data bits are 1101
|
||||||
const hexDataAsymmetric = "f002000000000000";
|
const hexDataAsymmetric = 'f002000000000000';
|
||||||
const aSymValue = dbcInt32SignalValue(dbc, signalSpec, hexDataAsymmetric, 8);
|
const aSymValue = dbcInt32SignalValue(dbc, signalSpec, hexDataAsymmetric, 8);
|
||||||
expect(aSymValue).toEqual(11);
|
expect(aSymValue).toEqual(11);
|
||||||
});
|
});
|
||||||
|
@ -385,12 +386,12 @@ BO_ 1265 CLU11: 4 CLU
|
||||||
SG_ CF_Clu_AmpInfo : 25|1@1+ (1.0,0.0) [0.0|1.0] "" BCM
|
SG_ CF_Clu_AmpInfo : 25|1@1+ (1.0,0.0) [0.0|1.0] "" BCM
|
||||||
SG_ CF_Clu_AliveCnt1 : 28|4@1+ (1.0,0.0) [0.0|15.0] "" AHLS,EMS,EPB,LDWS_LKAS,MDPS,SCC
|
SG_ CF_Clu_AliveCnt1 : 28|4@1+ (1.0,0.0) [0.0|15.0] "" AHLS,EMS,EPB,LDWS_LKAS,MDPS,SCC
|
||||||
`;
|
`;
|
||||||
test("int32 parser produces correct value for 4-bit little endian signal within a 4-byte message", () => {
|
test('int32 parser produces correct value for 4-bit little endian signal within a 4-byte message', () => {
|
||||||
const dbc = new DBC(DBC_FOUR_BIT_LE_SIGNAL_FOUR_BYTE_MESSAGE);
|
const dbc = new DBC(DBC_FOUR_BIT_LE_SIGNAL_FOUR_BYTE_MESSAGE);
|
||||||
const frame = dbc.getMessageFrame(1265);
|
const frame = dbc.getMessageFrame(1265);
|
||||||
const signalSpec = frame.signals["CF_Clu_AliveCnt1"];
|
const signalSpec = frame.signals.CF_Clu_AliveCnt1;
|
||||||
|
|
||||||
const hexData = "2000662000000000";
|
const hexData = '2000662000000000';
|
||||||
const value = dbcInt32SignalValue(dbc, signalSpec, hexData, frame.size);
|
const value = dbcInt32SignalValue(dbc, signalSpec, hexData, frame.size);
|
||||||
expect(value).toEqual(2);
|
expect(value).toEqual(2);
|
||||||
});
|
});
|
||||||
|
@ -403,16 +404,16 @@ BO_ 688 SAS11: 5 MDPS
|
||||||
SG_ MsgCount : 32|4@1+ (1.0,0.0) [0.0|15.0] "" ECS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS,ECS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS
|
SG_ MsgCount : 32|4@1+ (1.0,0.0) [0.0|15.0] "" ECS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS,ECS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS
|
||||||
SG_ CheckSum : 36|4@1+ (1.0,0.0) [0.0|15.0] "" ECS,EMS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS,ECS,EMS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS
|
SG_ CheckSum : 36|4@1+ (1.0,0.0) [0.0|15.0] "" ECS,EMS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS,ECS,EMS,ESC,IBOX,LDWS_LKAS,PSB,SCC,SPAS
|
||||||
`;
|
`;
|
||||||
test("int32 parser produces correct value for 2-byte signed little endian signal within a 5-byte message", () => {
|
test('int32 parser produces correct value for 2-byte signed little endian signal within a 5-byte message', () => {
|
||||||
const dbc = new DBC(DBC_MESSAGE_WITH_LE_SIGNED_SIGNAL);
|
const dbc = new DBC(DBC_MESSAGE_WITH_LE_SIGNED_SIGNAL);
|
||||||
const frame = dbc.getMessageFrame(688);
|
const frame = dbc.getMessageFrame(688);
|
||||||
const signalSpec = frame.signals["SAS_Angle"];
|
const signalSpec = frame.signals.SAS_Angle;
|
||||||
|
|
||||||
const hexData = "000000fafe000700";
|
const hexData = '000000fafe000700';
|
||||||
const value = dbcInt32SignalValue(dbc, signalSpec, hexData, frame.size);
|
const value = dbcInt32SignalValue(dbc, signalSpec, hexData, frame.size);
|
||||||
expect(value).toEqual(0.0);
|
expect(value).toEqual(0.0);
|
||||||
|
|
||||||
const hexData2 = "0b000907d8b30000";
|
const hexData2 = '0b000907d8b30000';
|
||||||
const value2 = dbcInt32SignalValue(dbc, signalSpec, hexData2, frame.size);
|
const value2 = dbcInt32SignalValue(dbc, signalSpec, hexData2, frame.size);
|
||||||
expect(value2).toEqual(1.1);
|
expect(value2).toEqual(1.1);
|
||||||
});
|
});
|
||||||
|
@ -424,12 +425,12 @@ BO_ 37 STEERING_CONTROL: 8 XXX
|
||||||
CM_ "CHFFR_METRIC 37 STEER_ANGLE STEER_ANGLE 0.36 180";
|
CM_ "CHFFR_METRIC 37 STEER_ANGLE STEER_ANGLE 0.36 180";
|
||||||
`;
|
`;
|
||||||
|
|
||||||
test("dbc parser parses top-level comment with chffr metric", () => {
|
test('dbc parser parses top-level comment with chffr metric', () => {
|
||||||
const dbc = new DBC(DBC_CHFFR_METRIC_COMMENT);
|
const dbc = new DBC(DBC_CHFFR_METRIC_COMMENT);
|
||||||
const { comments } = dbc;
|
const { comments } = dbc;
|
||||||
|
|
||||||
expect(comments.length).toEqual(1);
|
expect(comments.length).toEqual(1);
|
||||||
expect(comments[0]).toEqual(
|
expect(comments[0]).toEqual(
|
||||||
"CHFFR_METRIC 37 STEER_ANGLE STEER_ANGLE 0.36 180"
|
'CHFFR_METRIC 37 STEER_ANGLE STEER_ANGLE 0.36 180'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import DBC, { swapOrder } from "../../models/can/dbc";
|
import fs from 'fs';
|
||||||
import fs from "fs";
|
import path from 'path';
|
||||||
import path from "path";
|
import DBC, { swapOrder } from '../../models/can/dbc';
|
||||||
|
|
||||||
const ACURA_DBC = fs.readFileSync("src/__tests__/res/acura.dbc", "utf-8");
|
const ACURA_DBC = fs.readFileSync('src/__tests__/res/acura.dbc', 'utf-8');
|
||||||
//import { TESLA_DBC } from "../res/tesla.dbc";
|
// import { TESLA_DBC } from "../res/tesla.dbc";
|
||||||
|
|
||||||
test("DBC.text() for acura DBC should be equivalent to its original text", () => {
|
test('DBC.text() for acura DBC should be equivalent to its original text', () => {
|
||||||
const dbc = new DBC(ACURA_DBC);
|
const dbc = new DBC(ACURA_DBC);
|
||||||
|
|
||||||
expect(dbc.text()).toBe(ACURA_DBC);
|
expect(dbc.text()).toBe(ACURA_DBC);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Entries from "../../models/can/entries";
|
import Entries from '../../models/can/entries';
|
||||||
|
|
||||||
test("segment index low is inclusive and index high is exclusive", () => {
|
test('segment index low is inclusive and index high is exclusive', () => {
|
||||||
const entries = [
|
const entries = [
|
||||||
{ time: 1.0 },
|
{ time: 1.0 },
|
||||||
{ time: 3.45 },
|
{ time: 3.45 },
|
||||||
|
@ -16,8 +16,8 @@ test("segment index low is inclusive and index high is exclusive", () => {
|
||||||
expect(segmentIdxHi).toBe(entries.length - 1);
|
expect(segmentIdxHi).toBe(entries.length - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("segment index cant return negative indexes", () => {
|
test('segment index cant return negative indexes', () => {
|
||||||
var indices = Entries.findSegmentIndices([], [123, 321], true);
|
const indices = Entries.findSegmentIndices([], [123, 321], true);
|
||||||
expect(indices[0]).toBe(0);
|
expect(indices[0]).toBe(0);
|
||||||
expect(indices[1]).toBe(0);
|
expect(indices[1]).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import Frame from "../../models/can/frame";
|
import Frame from '../../models/can/frame';
|
||||||
|
|
||||||
const FRAME_HEADER = "BO_ 255 SOME_FRAME: 5 ADAS";
|
const FRAME_HEADER = 'BO_ 255 SOME_FRAME: 5 ADAS';
|
||||||
|
|
||||||
test("Frame.header() returns spec compliant representation", () => {
|
test('Frame.header() returns spec compliant representation', () => {
|
||||||
const frame = new Frame({
|
const frame = new Frame({
|
||||||
name: "SOME_FRAME",
|
name: 'SOME_FRAME',
|
||||||
id: 255,
|
id: 255,
|
||||||
size: 5,
|
size: 5,
|
||||||
transmitters: ["ADAS"]
|
transmitters: ['ADAS']
|
||||||
});
|
});
|
||||||
expect(frame.header()).toEqual(FRAME_HEADER);
|
expect(frame.header()).toEqual(FRAME_HEADER);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Signal from "../../models/can/signal";
|
import Signal from '../../models/can/signal';
|
||||||
|
|
||||||
const someSignalParams = {
|
const someSignalParams = {
|
||||||
name: "STEER_TORQUE",
|
name: 'STEER_TORQUE',
|
||||||
startBit: 7,
|
startBit: 7,
|
||||||
size: 16,
|
size: 16,
|
||||||
isLittleEndian: false,
|
isLittleEndian: false,
|
||||||
|
@ -10,11 +10,11 @@ const someSignalParams = {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
min: -3840,
|
min: -3840,
|
||||||
max: 3840,
|
max: 3840,
|
||||||
unit: ""
|
unit: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
const someOtherSignalParams = {
|
const someOtherSignalParams = {
|
||||||
name: "DIFFERENT_NAME",
|
name: 'DIFFERENT_NAME',
|
||||||
startBit: 0,
|
startBit: 0,
|
||||||
size: 16,
|
size: 16,
|
||||||
isLittleEndian: false,
|
isLittleEndian: false,
|
||||||
|
@ -23,24 +23,24 @@ const someOtherSignalParams = {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
min: -3840,
|
min: -3840,
|
||||||
max: 3840,
|
max: 3840,
|
||||||
unit: ""
|
unit: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
test("Signal.equals returns true for signals with identical properties", () => {
|
test('Signal.equals returns true for signals with identical properties', () => {
|
||||||
const someSignal = new Signal(someSignalParams);
|
const someSignal = new Signal(someSignalParams);
|
||||||
const someEquivalentSignal = new Signal(someSignalParams);
|
const someEquivalentSignal = new Signal(someSignalParams);
|
||||||
expect(someSignal.equals(someEquivalentSignal)).toBe(true);
|
expect(someSignal.equals(someEquivalentSignal)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Signal.equals returns false for signals with different properties", () => {
|
test('Signal.equals returns false for signals with different properties', () => {
|
||||||
const someSignal = new Signal(someSignalParams);
|
const someSignal = new Signal(someSignalParams);
|
||||||
const differentSignal = new Signal(someOtherSignalParams);
|
const differentSignal = new Signal(someOtherSignalParams);
|
||||||
expect(someSignal.equals(differentSignal)).toBe(false);
|
expect(someSignal.equals(differentSignal)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Signal.bitDescription returns proper description for a little endian signal", () => {
|
test('Signal.bitDescription returns proper description for a little endian signal', () => {
|
||||||
const littleEndianSignal = new Signal({
|
const littleEndianSignal = new Signal({
|
||||||
name: "little endian signal",
|
name: 'little endian signal',
|
||||||
startBit: 20,
|
startBit: 20,
|
||||||
size: 4,
|
size: 4,
|
||||||
isLittleEndian: true
|
isLittleEndian: true
|
||||||
|
@ -52,9 +52,9 @@ test("Signal.bitDescription returns proper description for a little endian signa
|
||||||
expect(littleEndianSignal.bitDescription(23).bitNumber).toBe(3);
|
expect(littleEndianSignal.bitDescription(23).bitNumber).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Signal.bitDescription returns proper description for a big endian signal", () => {
|
test('Signal.bitDescription returns proper description for a big endian signal', () => {
|
||||||
const bigEndianSignal = new Signal({
|
const bigEndianSignal = new Signal({
|
||||||
name: "big endian signal",
|
name: 'big endian signal',
|
||||||
startBit: 7,
|
startBit: 7,
|
||||||
size: 16,
|
size: 16,
|
||||||
isLittleEndian: false
|
isLittleEndian: false
|
||||||
|
@ -91,9 +91,9 @@ test("Signal.bitDescription returns proper description for a big endian signal",
|
||||||
expect(bigEndianSignal.bitDescription(7)).toEqual(bitSevenDescription);
|
expect(bigEndianSignal.bitDescription(7)).toEqual(bitSevenDescription);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Signal.bitDescription returns null for bit index that is not in its range", () => {
|
test('Signal.bitDescription returns null for bit index that is not in its range', () => {
|
||||||
const someSignal = new Signal({
|
const someSignal = new Signal({
|
||||||
name: "some signal",
|
name: 'some signal',
|
||||||
startBit: 20,
|
startBit: 20,
|
||||||
size: 4,
|
size: 4,
|
||||||
isLittleEndian: false
|
isLittleEndian: false
|
||||||
|
|
|
@ -5,10 +5,10 @@ note: 'right' and 'left' in test descriptions
|
||||||
refer to the sides of the bit matrix
|
refer to the sides of the bit matrix
|
||||||
as displayed to the user.
|
as displayed to the user.
|
||||||
*/
|
*/
|
||||||
import AddSignals from "../../components/AddSignals";
|
import React from 'react';
|
||||||
import React from "react";
|
import { shallow, mount, render } from 'enzyme';
|
||||||
import { shallow, mount, render } from "enzyme";
|
import { StyleSheetTestUtils } from 'aphrodite';
|
||||||
import { StyleSheetTestUtils } from "aphrodite";
|
import AddSignals from '../../components/AddSignals';
|
||||||
|
|
||||||
// Prevents style injection from firing after test finishes
|
// Prevents style injection from firing after test finishes
|
||||||
// and jsdom is torn down.
|
// and jsdom is torn down.
|
||||||
|
@ -31,7 +31,7 @@ function createAddSignals(signals) {
|
||||||
entries: [
|
entries: [
|
||||||
{
|
{
|
||||||
relTime: 0,
|
relTime: 0,
|
||||||
hexData: "0000000000000000"
|
hexData: '0000000000000000'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
@ -46,99 +46,99 @@ function createAddSignals(signals) {
|
||||||
|
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
test("double clicking adds a signal", () => {
|
test('double clicking adds a signal', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
|
|
||||||
const firstBit = component.find(".bit").first();
|
const firstBit = component.find('.bit').first();
|
||||||
|
|
||||||
firstBit.simulate("dblclick");
|
firstBit.simulate('dblclick');
|
||||||
const newSignal = Object.values(component.state("signals"))[0];
|
const newSignal = Object.values(component.state('signals'))[0];
|
||||||
|
|
||||||
expect(newSignal).toBeDefined();
|
expect(newSignal).toBeDefined();
|
||||||
expect(newSignal.size).toBe(1);
|
expect(newSignal.size).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("dragging right to left across a byte creates a little endian signal", () => {
|
test('dragging right to left across a byte creates a little endian signal', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
const leftBitInByte = component.find(".bit").first();
|
const leftBitInByte = component.find('.bit').first();
|
||||||
const rightBitInByte = component.find(".bit").at(7);
|
const rightBitInByte = component.find('.bit').at(7);
|
||||||
rightBitInByte.simulate("mousedown");
|
rightBitInByte.simulate('mousedown');
|
||||||
leftBitInByte.simulate("mouseup");
|
leftBitInByte.simulate('mouseup');
|
||||||
|
|
||||||
const newSignal = Object.values(component.state("signals"))[0];
|
const newSignal = Object.values(component.state('signals'))[0];
|
||||||
expect(newSignal).toBeDefined();
|
expect(newSignal).toBeDefined();
|
||||||
expect(newSignal.size).toBe(8);
|
expect(newSignal.size).toBe(8);
|
||||||
expect(newSignal.isLittleEndian).toBe(true);
|
expect(newSignal.isLittleEndian).toBe(true);
|
||||||
expect(newSignal.startBit).toBe(0);
|
expect(newSignal.startBit).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("dragging left to right across a byte creates a big endian signal", () => {
|
test('dragging left to right across a byte creates a big endian signal', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
const leftBitInByte = component.find(".bit").first();
|
const leftBitInByte = component.find('.bit').first();
|
||||||
const rightBitInByte = component.find(".bit").at(7);
|
const rightBitInByte = component.find('.bit').at(7);
|
||||||
leftBitInByte.simulate("mousedown");
|
leftBitInByte.simulate('mousedown');
|
||||||
rightBitInByte.simulate("mouseup");
|
rightBitInByte.simulate('mouseup');
|
||||||
|
|
||||||
const newSignal = Object.values(component.state("signals"))[0];
|
const newSignal = Object.values(component.state('signals'))[0];
|
||||||
expect(newSignal).toBeDefined();
|
expect(newSignal).toBeDefined();
|
||||||
expect(newSignal.size).toBe(8);
|
expect(newSignal.size).toBe(8);
|
||||||
expect(newSignal.isLittleEndian).toBe(false);
|
expect(newSignal.isLittleEndian).toBe(false);
|
||||||
expect(newSignal.startBit).toBe(7);
|
expect(newSignal.startBit).toBe(7);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("dragging from the left of byte 0 to right of byte 1 creates a big endian signal spanning both bytes", () => {
|
test('dragging from the left of byte 0 to right of byte 1 creates a big endian signal spanning both bytes', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
const leftBitInByte = component.find(".bit").first();
|
const leftBitInByte = component.find('.bit').first();
|
||||||
const rightBitInByte = component.find(".bit").at(15);
|
const rightBitInByte = component.find('.bit').at(15);
|
||||||
leftBitInByte.simulate("mousedown");
|
leftBitInByte.simulate('mousedown');
|
||||||
rightBitInByte.simulate("mouseup");
|
rightBitInByte.simulate('mouseup');
|
||||||
|
|
||||||
const newSignal = Object.values(component.state("signals"))[0];
|
const newSignal = Object.values(component.state('signals'))[0];
|
||||||
expect(newSignal).toBeDefined();
|
expect(newSignal).toBeDefined();
|
||||||
expect(newSignal.size).toBe(16);
|
expect(newSignal.size).toBe(16);
|
||||||
expect(newSignal.isLittleEndian).toBe(false);
|
expect(newSignal.isLittleEndian).toBe(false);
|
||||||
expect(newSignal.startBit).toBe(7);
|
expect(newSignal.startBit).toBe(7);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("dragging from the right of byte 0 to the left of byte 1 creates a little endian signal spanning both bytes", () => {
|
test('dragging from the right of byte 0 to the left of byte 1 creates a little endian signal spanning both bytes', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
const leftBitInByteOne = component.find(".bit").at(8); // left of byte 1
|
const leftBitInByteOne = component.find('.bit').at(8); // left of byte 1
|
||||||
const rightBitInByteZero = component.find(".bit").at(7); // right of byte 0
|
const rightBitInByteZero = component.find('.bit').at(7); // right of byte 0
|
||||||
|
|
||||||
rightBitInByteZero.simulate("mousedown");
|
rightBitInByteZero.simulate('mousedown');
|
||||||
leftBitInByteOne.simulate("mouseup");
|
leftBitInByteOne.simulate('mouseup');
|
||||||
|
|
||||||
const newSignal = Object.values(component.state("signals"))[0];
|
const newSignal = Object.values(component.state('signals'))[0];
|
||||||
expect(newSignal).toBeDefined();
|
expect(newSignal).toBeDefined();
|
||||||
expect(newSignal.size).toBe(16);
|
expect(newSignal.size).toBe(16);
|
||||||
expect(newSignal.isLittleEndian).toBe(true);
|
expect(newSignal.isLittleEndian).toBe(true);
|
||||||
expect(newSignal.startBit).toBe(0);
|
expect(newSignal.startBit).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("dragging from the left of byte 1 to the right of byte 0 creates a little endian signal spanning both bytes", () => {
|
test('dragging from the left of byte 1 to the right of byte 0 creates a little endian signal spanning both bytes', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
const leftBitInByteOne = component.find(".bit").at(8);
|
const leftBitInByteOne = component.find('.bit').at(8);
|
||||||
const rightBitInByteZero = component.find(".bit").at(7);
|
const rightBitInByteZero = component.find('.bit').at(7);
|
||||||
|
|
||||||
leftBitInByteOne.simulate("mousedown");
|
leftBitInByteOne.simulate('mousedown');
|
||||||
rightBitInByteZero.simulate("mouseup");
|
rightBitInByteZero.simulate('mouseup');
|
||||||
|
|
||||||
const signal = Object.values(component.state("signals"))[0];
|
const signal = Object.values(component.state('signals'))[0];
|
||||||
expect(signal).toBeDefined();
|
expect(signal).toBeDefined();
|
||||||
expect(signal.size).toBe(16);
|
expect(signal.size).toBe(16);
|
||||||
expect(signal.isLittleEndian).toBe(true);
|
expect(signal.isLittleEndian).toBe(true);
|
||||||
expect(signal.startBit).toBe(0);
|
expect(signal.startBit).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("dragging from the right of byte 1 to the left of byte 0 creates a big endian signal spanning both bytes", () => {
|
test('dragging from the right of byte 1 to the left of byte 0 creates a big endian signal spanning both bytes', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
const leftBitInByteZero = component.find(".bit").at(0);
|
const leftBitInByteZero = component.find('.bit').at(0);
|
||||||
const rightBitInByteOne = component.find(".bit").at(15);
|
const rightBitInByteOne = component.find('.bit').at(15);
|
||||||
|
|
||||||
rightBitInByteOne.simulate("mousedown");
|
rightBitInByteOne.simulate('mousedown');
|
||||||
leftBitInByteZero.simulate("mouseup");
|
leftBitInByteZero.simulate('mouseup');
|
||||||
|
|
||||||
const signal = Object.values(component.state("signals"))[0];
|
const signal = Object.values(component.state('signals'))[0];
|
||||||
expect(signal).toBeDefined();
|
expect(signal).toBeDefined();
|
||||||
expect(signal.size).toBe(16);
|
expect(signal.size).toBe(16);
|
||||||
expect(signal.isLittleEndian).toBe(false);
|
expect(signal.isLittleEndian).toBe(false);
|
||||||
|
@ -147,205 +147,205 @@ test("dragging from the right of byte 1 to the left of byte 0 creates a big endi
|
||||||
|
|
||||||
// signal mutation
|
// signal mutation
|
||||||
|
|
||||||
test.skip("dragging a one-bit big-endian signal to the right should extend it to the right of the byte", () => {
|
test.skip('dragging a one-bit big-endian signal to the right should extend it to the right of the byte', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
component
|
component
|
||||||
.instance()
|
.instance()
|
||||||
.createSignal({ startBit: 7, size: 1, isLittleEndian: false });
|
.createSignal({ startBit: 7, size: 1, isLittleEndian: false });
|
||||||
|
|
||||||
const signalBit = component.find(".bit").at(0);
|
const signalBit = component.find('.bit').at(0);
|
||||||
signalBit.simulate("mousedown");
|
signalBit.simulate('mousedown');
|
||||||
for (let i = 1; i < 8; i++) {
|
for (let i = 1; i < 8; i++) {
|
||||||
component
|
component
|
||||||
.find(".bit")
|
.find('.bit')
|
||||||
.at(i)
|
.at(i)
|
||||||
.simulate("mouseenter");
|
.simulate('mouseenter');
|
||||||
}
|
}
|
||||||
const bitAtRightOfFirstByte = component.find(".bit").at(7);
|
const bitAtRightOfFirstByte = component.find('.bit').at(7);
|
||||||
bitAtRightOfFirstByte.simulate("mouseup");
|
bitAtRightOfFirstByte.simulate('mouseup');
|
||||||
|
|
||||||
const signal = Object.values(component.state("signals"))[0];
|
const signal = Object.values(component.state('signals'))[0];
|
||||||
expect(signal).toBeDefined();
|
expect(signal).toBeDefined();
|
||||||
expect(signal.size).toBe(8);
|
expect(signal.size).toBe(8);
|
||||||
expect(signal.isLittleEndian).toBe(false);
|
expect(signal.isLittleEndian).toBe(false);
|
||||||
expect(signal.startBit).toBe(7);
|
expect(signal.startBit).toBe(7);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip("dragging a one-bit little-endian signal to the right should extend it to the right of the byte", () => {
|
test.skip('dragging a one-bit little-endian signal to the right should extend it to the right of the byte', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
component
|
component
|
||||||
.instance()
|
.instance()
|
||||||
.createSignal({ startBit: 7, size: 1, isLittleEndian: true });
|
.createSignal({ startBit: 7, size: 1, isLittleEndian: true });
|
||||||
|
|
||||||
const signalBit = component.find(".bit").at(0);
|
const signalBit = component.find('.bit').at(0);
|
||||||
signalBit.simulate("mousedown");
|
signalBit.simulate('mousedown');
|
||||||
for (let i = 1; i < 8; i++) {
|
for (let i = 1; i < 8; i++) {
|
||||||
component
|
component
|
||||||
.find(".bit")
|
.find('.bit')
|
||||||
.at(i)
|
.at(i)
|
||||||
.simulate("mouseenter");
|
.simulate('mouseenter');
|
||||||
}
|
}
|
||||||
const bitAtRightOfFirstByte = component.find(".bit").at(7);
|
const bitAtRightOfFirstByte = component.find('.bit').at(7);
|
||||||
bitAtRightOfFirstByte.simulate("mouseup");
|
bitAtRightOfFirstByte.simulate('mouseup');
|
||||||
|
|
||||||
const signal = Object.values(component.state("signals"))[0];
|
const signal = Object.values(component.state('signals'))[0];
|
||||||
expect(signal).toBeDefined();
|
expect(signal).toBeDefined();
|
||||||
expect(signal.size).toBe(8);
|
expect(signal.size).toBe(8);
|
||||||
expect(signal.isLittleEndian).toBe(true);
|
expect(signal.isLittleEndian).toBe(true);
|
||||||
expect(signal.startBit).toBe(0);
|
expect(signal.startBit).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip("dragging a one-bit big-endian signal to the left should extend it to the left of the byte", () => {
|
test.skip('dragging a one-bit big-endian signal to the left should extend it to the left of the byte', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
component
|
component
|
||||||
.instance()
|
.instance()
|
||||||
.createSignal({ startBit: 0, size: 1, isLittleEndian: false });
|
.createSignal({ startBit: 0, size: 1, isLittleEndian: false });
|
||||||
|
|
||||||
const signalBit = component.find(".bit").at(7);
|
const signalBit = component.find('.bit').at(7);
|
||||||
signalBit.simulate("mousedown");
|
signalBit.simulate('mousedown');
|
||||||
for (let i = 6; i > -1; i--) {
|
for (let i = 6; i > -1; i--) {
|
||||||
component
|
component
|
||||||
.find(".bit")
|
.find('.bit')
|
||||||
.at(i)
|
.at(i)
|
||||||
.simulate("mouseenter");
|
.simulate('mouseenter');
|
||||||
}
|
}
|
||||||
const bitAtRightOfFirstByte = component.find(".bit").at(0);
|
const bitAtRightOfFirstByte = component.find('.bit').at(0);
|
||||||
bitAtRightOfFirstByte.simulate("mouseup");
|
bitAtRightOfFirstByte.simulate('mouseup');
|
||||||
|
|
||||||
const signal = Object.values(component.state("signals"))[0];
|
const signal = Object.values(component.state('signals'))[0];
|
||||||
expect(signal).toBeDefined();
|
expect(signal).toBeDefined();
|
||||||
expect(signal.size).toBe(8);
|
expect(signal.size).toBe(8);
|
||||||
expect(signal.isLittleEndian).toBe(false);
|
expect(signal.isLittleEndian).toBe(false);
|
||||||
expect(signal.startBit).toBe(7);
|
expect(signal.startBit).toBe(7);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip("extending a two-bit big-endian signal by its LSB should extend it to the right of the byte", () => {
|
test.skip('extending a two-bit big-endian signal by its LSB should extend it to the right of the byte', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
component
|
component
|
||||||
.instance()
|
.instance()
|
||||||
.createSignal({ startBit: 7, size: 2, isLittleEndian: false });
|
.createSignal({ startBit: 7, size: 2, isLittleEndian: false });
|
||||||
|
|
||||||
const lsb = component.find(".bit").at(1);
|
const lsb = component.find('.bit').at(1);
|
||||||
lsb.simulate("mousedown");
|
lsb.simulate('mousedown');
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
component
|
component
|
||||||
.find(".bit")
|
.find('.bit')
|
||||||
.at(i)
|
.at(i)
|
||||||
.simulate("mouseenter");
|
.simulate('mouseenter');
|
||||||
}
|
}
|
||||||
const bitAtRightOfFirstByte = component.find(".bit").at(7);
|
const bitAtRightOfFirstByte = component.find('.bit').at(7);
|
||||||
bitAtRightOfFirstByte.simulate("mouseup");
|
bitAtRightOfFirstByte.simulate('mouseup');
|
||||||
|
|
||||||
const signal = Object.values(component.state("signals"))[0];
|
const signal = Object.values(component.state('signals'))[0];
|
||||||
expect(signal).toBeDefined();
|
expect(signal).toBeDefined();
|
||||||
expect(signal.size).toBe(8);
|
expect(signal.size).toBe(8);
|
||||||
expect(signal.isLittleEndian).toBe(false);
|
expect(signal.isLittleEndian).toBe(false);
|
||||||
expect(signal.startBit).toBe(7);
|
expect(signal.startBit).toBe(7);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip("a two-bit little-endian signal should extend by its LSB to the end of the byte", () => {
|
test.skip('a two-bit little-endian signal should extend by its LSB to the end of the byte', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
component
|
component
|
||||||
.instance()
|
.instance()
|
||||||
.createSignal({ startBit: 6, size: 2, isLittleEndian: true });
|
.createSignal({ startBit: 6, size: 2, isLittleEndian: true });
|
||||||
|
|
||||||
const lsb = component.find(".bit").at(1);
|
const lsb = component.find('.bit').at(1);
|
||||||
lsb.simulate("mousedown");
|
lsb.simulate('mousedown');
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
component
|
component
|
||||||
.find(".bit")
|
.find('.bit')
|
||||||
.at(i)
|
.at(i)
|
||||||
.simulate("mouseenter");
|
.simulate('mouseenter');
|
||||||
}
|
}
|
||||||
const bitAtRightOfFirstByte = component.find(".bit").at(7);
|
const bitAtRightOfFirstByte = component.find('.bit').at(7);
|
||||||
bitAtRightOfFirstByte.simulate("mouseup");
|
bitAtRightOfFirstByte.simulate('mouseup');
|
||||||
|
|
||||||
const signal = Object.values(component.state("signals"))[0];
|
const signal = Object.values(component.state('signals'))[0];
|
||||||
expect(signal).toBeDefined();
|
expect(signal).toBeDefined();
|
||||||
expect(signal.size).toBe(8);
|
expect(signal.size).toBe(8);
|
||||||
expect(signal.isLittleEndian).toBe(true);
|
expect(signal.isLittleEndian).toBe(true);
|
||||||
expect(signal.startBit).toBe(0);
|
expect(signal.startBit).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("dragging the lsb of a little-endian signal spanning an entire byte should not be allowed to pass the MSB", () => {
|
test('dragging the lsb of a little-endian signal spanning an entire byte should not be allowed to pass the MSB', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
component
|
component
|
||||||
.instance()
|
.instance()
|
||||||
.createSignal({ startBit: 0, size: 8, isLittleEndian: true });
|
.createSignal({ startBit: 0, size: 8, isLittleEndian: true });
|
||||||
|
|
||||||
const lsb = component.find(".bit").at(7);
|
const lsb = component.find('.bit').at(7);
|
||||||
lsb.simulate("mousedown");
|
lsb.simulate('mousedown');
|
||||||
|
|
||||||
const bitPastMsb = component.find(".bit").at(15);
|
const bitPastMsb = component.find('.bit').at(15);
|
||||||
bitPastMsb.simulate("mouseenter");
|
bitPastMsb.simulate('mouseenter');
|
||||||
bitPastMsb.simulate("mouseup");
|
bitPastMsb.simulate('mouseup');
|
||||||
|
|
||||||
const signal = Object.values(component.state("signals"))[0];
|
const signal = Object.values(component.state('signals'))[0];
|
||||||
expect(signal).toBeDefined();
|
expect(signal).toBeDefined();
|
||||||
expect(signal.size).toBe(8);
|
expect(signal.size).toBe(8);
|
||||||
expect(signal.isLittleEndian).toBe(true);
|
expect(signal.isLittleEndian).toBe(true);
|
||||||
expect(signal.startBit).toBe(0);
|
expect(signal.startBit).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip("dragging the lsb of a big-endian signal towards the msb in the same byte should contract the signal", () => {
|
test.skip('dragging the lsb of a big-endian signal towards the msb in the same byte should contract the signal', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
component
|
component
|
||||||
.instance()
|
.instance()
|
||||||
.createSignal({ startBit: 7, size: 8, isLittleEndian: false });
|
.createSignal({ startBit: 7, size: 8, isLittleEndian: false });
|
||||||
|
|
||||||
const lsb = component.find(".bit").at(7);
|
const lsb = component.find('.bit').at(7);
|
||||||
lsb.simulate("mousedown");
|
lsb.simulate('mousedown');
|
||||||
for (let i = 6; i > 0; i--) {
|
for (let i = 6; i > 0; i--) {
|
||||||
component
|
component
|
||||||
.find(".bit")
|
.find('.bit')
|
||||||
.at(i)
|
.at(i)
|
||||||
.simulate("mouseenter");
|
.simulate('mouseenter');
|
||||||
}
|
}
|
||||||
component
|
component
|
||||||
.find(".bit")
|
.find('.bit')
|
||||||
.at(1)
|
.at(1)
|
||||||
.simulate("mouseup");
|
.simulate('mouseup');
|
||||||
|
|
||||||
const signal = Object.values(component.state("signals"))[0];
|
const signal = Object.values(component.state('signals'))[0];
|
||||||
expect(signal).toBeDefined();
|
expect(signal).toBeDefined();
|
||||||
expect(signal.size).toBe(2);
|
expect(signal.size).toBe(2);
|
||||||
expect(signal.isLittleEndian).toBe(false);
|
expect(signal.isLittleEndian).toBe(false);
|
||||||
expect(signal.startBit).toBe(7);
|
expect(signal.startBit).toBe(7);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("a big endian signal spanning one byte should switch to little endian preserving its bit coverage", () => {
|
test('a big endian signal spanning one byte should switch to little endian preserving its bit coverage', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
component
|
component
|
||||||
.instance()
|
.instance()
|
||||||
.createSignal({ startBit: 0, size: 8, isLittleEndian: true });
|
.createSignal({ startBit: 0, size: 8, isLittleEndian: true });
|
||||||
|
|
||||||
const lsb = component.find(".bit").at(7);
|
const lsb = component.find('.bit').at(7);
|
||||||
lsb.simulate("mousedown");
|
lsb.simulate('mousedown');
|
||||||
|
|
||||||
const bitPastMsb = component.find(".bit").at(15);
|
const bitPastMsb = component.find('.bit').at(15);
|
||||||
bitPastMsb.simulate("mouseenter");
|
bitPastMsb.simulate('mouseenter');
|
||||||
bitPastMsb.simulate("mouseup");
|
bitPastMsb.simulate('mouseup');
|
||||||
|
|
||||||
const signal = Object.values(component.state("signals"))[0];
|
const signal = Object.values(component.state('signals'))[0];
|
||||||
expect(signal).toBeDefined();
|
expect(signal).toBeDefined();
|
||||||
expect(signal.size).toBe(8);
|
expect(signal.size).toBe(8);
|
||||||
expect(signal.isLittleEndian).toBe(true);
|
expect(signal.isLittleEndian).toBe(true);
|
||||||
expect(signal.startBit).toBe(0);
|
expect(signal.startBit).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("dragging the msb of a 2-bit little endian signal to a lower byte should not change the signal", () => {
|
test('dragging the msb of a 2-bit little endian signal to a lower byte should not change the signal', () => {
|
||||||
const component = createAddSignals();
|
const component = createAddSignals();
|
||||||
component
|
component
|
||||||
.instance()
|
.instance()
|
||||||
.createSignal({ startBit: 14, size: 2, isLittleEndian: true });
|
.createSignal({ startBit: 14, size: 2, isLittleEndian: true });
|
||||||
|
|
||||||
const msb = component.find(".bit").at(8);
|
const msb = component.find('.bit').at(8);
|
||||||
msb.simulate("mousedown");
|
msb.simulate('mousedown');
|
||||||
const bitOutOfBounds = component.find(".bit").at(0);
|
const bitOutOfBounds = component.find('.bit').at(0);
|
||||||
bitOutOfBounds.simulate("mouseenter");
|
bitOutOfBounds.simulate('mouseenter');
|
||||||
bitOutOfBounds.simulate("mouseup");
|
bitOutOfBounds.simulate('mouseup');
|
||||||
|
|
||||||
const signal = Object.values(component.state("signals"))[0];
|
const signal = Object.values(component.state('signals'))[0];
|
||||||
expect(signal).toBeDefined();
|
expect(signal).toBeDefined();
|
||||||
expect(signal.size).toBe(2);
|
expect(signal.size).toBe(2);
|
||||||
expect(signal.isLittleEndian).toBe(true);
|
expect(signal.isLittleEndian).toBe(true);
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
global.__JEST__ = 1;
|
import React from 'react';
|
||||||
import CanExplorer from "../../CanExplorer";
|
import { shallow, mount, render } from 'enzyme';
|
||||||
import React from "react";
|
import { StyleSheetTestUtils } from 'aphrodite';
|
||||||
import { shallow, mount, render } from "enzyme";
|
import CanExplorer from '../../CanExplorer';
|
||||||
import { StyleSheetTestUtils } from "aphrodite";
|
|
||||||
|
|
||||||
test("CanExplorer renders", () => {
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
|
test('CanExplorer renders', () => {
|
||||||
const canExplorer = shallow(<CanExplorer />);
|
const canExplorer = shallow(<CanExplorer />);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
import CanGraph from '../../components/CanGraph';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import CanGraph from "../../components/CanGraph";
|
test('CanGraph successfully mounts with minimal default props', () => {
|
||||||
import React from "react";
|
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
|
|
||||||
test("CanGraph successfully mounts with minimal default props", () => {
|
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<CanGraph
|
<CanGraph
|
||||||
onGraphRefAvailable={() => {}}
|
onGraphRefAvailable={() => {}}
|
||||||
|
@ -24,7 +24,7 @@ test("CanGraph successfully mounts with minimal default props", () => {
|
||||||
dragPos={null}
|
dragPos={null}
|
||||||
canReceiveGraphDrop={false}
|
canReceiveGraphDrop={false}
|
||||||
plottedSignals={[]}
|
plottedSignals={[]}
|
||||||
live={true}
|
live
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
expect(component.exists()).toBe(true);
|
expect(component.exists()).toBe(true);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
import CanGraphList from '../../components/CanGraphList';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import CanGraphList from "../../components/CanGraphList";
|
test('CanGraphList successfully mounts with minimal default props', () => {
|
||||||
import React from "react";
|
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
|
|
||||||
test("CanGraphList successfully mounts with minimal default props", () => {
|
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<CanGraphList
|
<CanGraphList
|
||||||
plottedSignals={[]}
|
plottedSignals={[]}
|
||||||
|
@ -16,7 +16,7 @@ test("CanGraphList successfully mounts with minimal default props", () => {
|
||||||
onSignalUnplotPressed={() => {}}
|
onSignalUnplotPressed={() => {}}
|
||||||
segment={[]}
|
segment={[]}
|
||||||
mergePlots={() => {}}
|
mergePlots={() => {}}
|
||||||
live={true}
|
live
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
expect(component.exists()).toBe(true);
|
expect(component.exists()).toBe(true);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
import CanLog from '../../components/CanLog';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import CanLog from "../../components/CanLog";
|
test('CanLog successfully mounts with minimal default props', () => {
|
||||||
import React from "react";
|
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
|
|
||||||
test("CanLog successfully mounts with minimal default props", () => {
|
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<CanLog
|
<CanLog
|
||||||
message={null}
|
message={null}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
import DbcUpload from '../../components/DbcUpload';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import DbcUpload from "../../components/DbcUpload";
|
test('DbcUpload successfully mounts with minimal default props', () => {
|
||||||
import React from "react";
|
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
|
|
||||||
test("DbcUpload successfully mounts with minimal default props", () => {
|
|
||||||
const component = shallow(<DbcUpload />);
|
const component = shallow(<DbcUpload />);
|
||||||
expect(component.exists()).toBe(true);
|
expect(component.exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
import EditMessageModal from '../../components/EditMessageModal';
|
||||||
|
import DbcUtils from '../../utils/dbc';
|
||||||
|
import DBC from '../../models/can/dbc';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import EditMessageModal from "../../components/EditMessageModal";
|
test('EditMessageModal successfully mounts with minimal default props', () => {
|
||||||
import React from "react";
|
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
import DbcUtils from "../../utils/dbc";
|
|
||||||
import DBC from "../../models/can/dbc";
|
|
||||||
|
|
||||||
test("EditMessageModal successfully mounts with minimal default props", () => {
|
|
||||||
const dbc = new DBC();
|
const dbc = new DBC();
|
||||||
const frame = dbc.createFrame(0);
|
const frame = dbc.createFrame(0);
|
||||||
const message = DbcUtils.createMessageSpec(dbc, 0, "0", 1);
|
const message = DbcUtils.createMessageSpec(dbc, 0, '0', 1);
|
||||||
|
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<EditMessageModal
|
<EditMessageModal
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Moment from 'moment';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
import Explorer from '../../components/Explorer';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import Explorer from "../../components/Explorer";
|
test('Explorer successfully mounts with minimal default props', () => {
|
||||||
import React from "react";
|
|
||||||
import Moment from "moment";
|
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
|
|
||||||
test("Explorer successfully mounts with minimal default props", () => {
|
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<Explorer
|
<Explorer
|
||||||
url={null}
|
url={null}
|
||||||
live={true}
|
live
|
||||||
messages={{}}
|
messages={{}}
|
||||||
selectedMessage={null}
|
selectedMessage={null}
|
||||||
onConfirmedSignalChange={() => {}}
|
onConfirmedSignalChange={() => {}}
|
||||||
|
@ -21,7 +21,7 @@ test("Explorer successfully mounts with minimal default props", () => {
|
||||||
seekIndex={0}
|
seekIndex={0}
|
||||||
currentParts={[0, 0]}
|
currentParts={[0, 0]}
|
||||||
partsLoaded={0}
|
partsLoaded={0}
|
||||||
autoplay={true}
|
autoplay
|
||||||
showEditMessageModal={() => {}}
|
showEditMessageModal={() => {}}
|
||||||
onPartChange={() => {}}
|
onPartChange={() => {}}
|
||||||
routeStartTime={Moment()}
|
routeStartTime={Moment()}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
import GithubDbcList from '../../components/GithubDbcList';
|
||||||
|
|
||||||
|
import OpenDbc from '../../api/OpenDbc';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import GithubDbcList from "../../components/GithubDbcList";
|
test('GithubDbcList successfully mounts with minimal default props', () => {
|
||||||
import React from "react";
|
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
|
|
||||||
import OpenDbc from "../../api/OpenDbc";
|
|
||||||
|
|
||||||
test("GithubDbcList successfully mounts with minimal default props", () => {
|
|
||||||
const openDbcClient = new OpenDbc(null);
|
const openDbcClient = new OpenDbc(null);
|
||||||
|
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import HLS from "../../components/HLS";
|
import React from 'react';
|
||||||
import React from "react";
|
import { shallow, mount, render } from 'enzyme';
|
||||||
import { shallow, mount, render } from "enzyme";
|
import HLS from '../../components/HLS';
|
||||||
|
|
||||||
test("HLS successfully mounts with minimal default props", () => {
|
test('HLS successfully mounts with minimal default props', () => {
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<HLS
|
<HLS
|
||||||
source={"http://comma.ai"}
|
source="http://comma.ai"
|
||||||
startTime={0}
|
startTime={0}
|
||||||
playbackSpeed={1}
|
playbackSpeed={1}
|
||||||
onVideoElementAvailable={() => {}}
|
onVideoElementAvailable={() => {}}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
|
||||||
|
import LoadDbcModal from '../../components/LoadDbcModal';
|
||||||
|
import OpenDbc from '../../api/OpenDbc';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import React from "react";
|
test('LoadDbcModal successfully mounts with minimal default props', () => {
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
|
|
||||||
import LoadDbcModal from "../../components/LoadDbcModal";
|
|
||||||
import OpenDbc from "../../api/OpenDbc";
|
|
||||||
|
|
||||||
test("LoadDbcModal successfully mounts with minimal default props", () => {
|
|
||||||
const openDbcClient = new OpenDbc(null);
|
const openDbcClient = new OpenDbc(null);
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<LoadDbcModal
|
<LoadDbcModal
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import LoadingBar from "../../components/LoadingBar";
|
import React from 'react';
|
||||||
import React from "react";
|
import { shallow, mount, render } from 'enzyme';
|
||||||
import { shallow, mount, render } from "enzyme";
|
import LoadingBar from '../../components/LoadingBar';
|
||||||
|
|
||||||
test("LoadingBar successfully mounts with minimal default props", () => {
|
test('LoadingBar successfully mounts with minimal default props', () => {
|
||||||
const component = shallow(<LoadingBar />);
|
const component = shallow(<LoadingBar />);
|
||||||
expect(component.exists()).toBe(true);
|
expect(component.exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
|
||||||
|
import MessageBytes from '../../components/MessageBytes';
|
||||||
|
import DbcUtils from '../../utils/dbc';
|
||||||
|
import DBC from '../../models/can/dbc';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import React from "react";
|
test('MessageBytes successfully mounts with minimal default props', () => {
|
||||||
import { shallow, mount, render } from "enzyme";
|
const message = DbcUtils.createMessageSpec(new DBC(), 0, '0', 1);
|
||||||
|
|
||||||
import MessageBytes from "../../components/MessageBytes";
|
|
||||||
import DbcUtils from "../../utils/dbc";
|
|
||||||
import DBC from "../../models/can/dbc";
|
|
||||||
|
|
||||||
test("MessageBytes successfully mounts with minimal default props", () => {
|
|
||||||
const message = DbcUtils.createMessageSpec(new DBC(), 0, "0", 1);
|
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<MessageBytes seekTime={0} message={message} live={true} />
|
<MessageBytes seekTime={0} message={message} live />
|
||||||
);
|
);
|
||||||
expect(component.exists()).toBe(true);
|
expect(component.exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
import Meta from '../../components/Meta';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import Meta from "../../components/Meta";
|
test('Meta successfully mounts with minimal default props', () => {
|
||||||
import React from "react";
|
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
|
|
||||||
test("Meta successfully mounts with minimal default props", () => {
|
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<Meta
|
<Meta
|
||||||
url={null}
|
url={null}
|
||||||
|
@ -26,7 +26,7 @@ test("Meta successfully mounts with minimal default props", () => {
|
||||||
seekIndex={0}
|
seekIndex={0}
|
||||||
maxByteStateChangeCount={0}
|
maxByteStateChangeCount={0}
|
||||||
isDemo={false}
|
isDemo={false}
|
||||||
live={true}
|
live
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
expect(component.exists()).toBe(true);
|
expect(component.exists()).toBe(true);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
import PartSelector from '../../components/PartSelector';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import PartSelector from "../../components/PartSelector";
|
test('PartSelector successfully mounts with minimal default props', () => {
|
||||||
import React from "react";
|
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
|
|
||||||
test("PartSelector successfully mounts with minimal default props", () => {
|
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<PartSelector onPartChange={() => {}} partsCount={0} selectedPart={0} />
|
<PartSelector onPartChange={() => {}} partsCount={0} selectedPart={0} />
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
import PlayButton from '../../components/PlayButton';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import PlayButton from "../../components/PlayButton";
|
test('PlayButton successfully mounts with minimal default props', () => {
|
||||||
import React from "react";
|
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
|
|
||||||
test("PlayButton successfully mounts with minimal default props", () => {
|
|
||||||
const component = shallow(<PlayButton />);
|
const component = shallow(<PlayButton />);
|
||||||
expect(component.exists()).toBe(true);
|
expect(component.exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
import RouteSeeker from '../../components/RouteSeeker';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import RouteSeeker from "../../components/RouteSeeker";
|
test('RouteSeeker successfully mounts with minimal default props', () => {
|
||||||
import React from "react";
|
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
|
|
||||||
test("RouteSeeker successfully mounts with minimal default props", () => {
|
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<RouteSeeker
|
<RouteSeeker
|
||||||
nearestFrameTime={0}
|
nearestFrameTime={0}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
global.__JEST__ = 1;
|
import API from '@commaai/comma-api';
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
import { StyleSheetTestUtils } from 'aphrodite';
|
||||||
|
import RouteVideoSync from '../../components/RouteVideoSync';
|
||||||
|
|
||||||
import API from "@commaai/comma-api";
|
global.__JEST__ = 1;
|
||||||
import RouteVideoSync from "../../components/RouteVideoSync";
|
|
||||||
import React from "react";
|
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
import { StyleSheetTestUtils } from "aphrodite";
|
|
||||||
|
|
||||||
// Prevents style injection from firing after test finishes
|
// Prevents style injection from firing after test finishes
|
||||||
// and jsdom is torn down.
|
// and jsdom is torn down.
|
||||||
|
@ -15,7 +15,7 @@ afterEach(() => {
|
||||||
StyleSheetTestUtils.clearBufferAndResumeStyleInjection();
|
StyleSheetTestUtils.clearBufferAndResumeStyleInjection();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("RouteVideoSync successfully mounts with minimal default props", () => {
|
test('RouteVideoSync successfully mounts with minimal default props', () => {
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<RouteVideoSync
|
<RouteVideoSync
|
||||||
message={null}
|
message={null}
|
||||||
|
@ -26,7 +26,7 @@ test("RouteVideoSync successfully mounts with minimal default props", () => {
|
||||||
userSeekIndex={0}
|
userSeekIndex={0}
|
||||||
playing={false}
|
playing={false}
|
||||||
playSpeed={1}
|
playSpeed={1}
|
||||||
url={"http://comma.ai"}
|
url="http://comma.ai"
|
||||||
canFrameOffset={0}
|
canFrameOffset={0}
|
||||||
firstCanTime={0}
|
firstCanTime={0}
|
||||||
onVideoClick={() => {}}
|
onVideoClick={() => {}}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
|
||||||
|
import SaveDbcModal from '../../components/SaveDbcModal';
|
||||||
|
import OpenDbc from '../../api/OpenDbc';
|
||||||
|
import DBC from '../../models/can/dbc';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import React from "react";
|
test('SaveDbcModal successfully mounts with minimal default props', () => {
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
|
|
||||||
import SaveDbcModal from "../../components/SaveDbcModal";
|
|
||||||
import OpenDbc from "../../api/OpenDbc";
|
|
||||||
import DBC from "../../models/can/dbc";
|
|
||||||
|
|
||||||
test("SaveDbcModal successfully mounts with minimal default props", () => {
|
|
||||||
const openDbcClient = new OpenDbc(null);
|
const openDbcClient = new OpenDbc(null);
|
||||||
const dbc = new DBC();
|
const dbc = new DBC();
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<SaveDbcModal
|
<SaveDbcModal
|
||||||
dbc={dbc}
|
dbc={dbc}
|
||||||
sourceDbcFilename={""}
|
sourceDbcFilename=""
|
||||||
onDbcSaved={() => {}}
|
onDbcSaved={() => {}}
|
||||||
handleClose={() => {}}
|
handleClose={() => {}}
|
||||||
openDbcClient={openDbcClient}
|
openDbcClient={openDbcClient}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { shallow, mount, render } from 'enzyme';
|
||||||
|
import SignalLegend from '../../components/SignalLegend';
|
||||||
|
|
||||||
global.__JEST__ = 1;
|
global.__JEST__ = 1;
|
||||||
|
|
||||||
import SignalLegend from "../../components/SignalLegend";
|
test('SignalLegend successfully mounts with minimal default props', () => {
|
||||||
import React from "react";
|
|
||||||
import { shallow, mount, render } from "enzyme";
|
|
||||||
|
|
||||||
test("SignalLegend successfully mounts with minimal default props", () => {
|
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<SignalLegend
|
<SignalLegend
|
||||||
signals={{}}
|
signals={{}}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { shade } from "../../utils/color";
|
import { shade } from '../../utils/color';
|
||||||
|
|
||||||
test("Shade darkens rgb white (255,255,255)", () => {
|
test('Shade darkens rgb white (255,255,255)', () => {
|
||||||
const rgb = [255, 255, 255];
|
const rgb = [255, 255, 255];
|
||||||
const darkenRgb = shade(rgb, -0.5);
|
const darkenRgb = shade(rgb, -0.5);
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
global.__JEST__ = 1;
|
import extend from 'xtend';
|
||||||
|
import DbcUtils from '../../utils/dbc';
|
||||||
|
import DBC from '../../models/can/dbc';
|
||||||
|
import Signal from '../../models/can/signal';
|
||||||
|
|
||||||
import DbcUtils from "../../utils/dbc";
|
global.__JEST__ = 1;
|
||||||
import DBC from "../../models/can/dbc";
|
|
||||||
import Signal from "../../models/can/signal";
|
|
||||||
import extend from "xtend";
|
|
||||||
|
|
||||||
// want to mock pandareader and test processStreamedCanMessages
|
// want to mock pandareader and test processStreamedCanMessages
|
||||||
const SAMPLE_MESSAGE = {
|
const SAMPLE_MESSAGE = {
|
||||||
address: 0x10,
|
address: 0x10,
|
||||||
busTime: 0,
|
busTime: 0,
|
||||||
data: Buffer.from("abababababababab", "hex"),
|
data: Buffer.from('abababababababab', 'hex'),
|
||||||
bus: 1
|
bus: 1
|
||||||
};
|
};
|
||||||
const SAMPLE_MESSAGE_ID = "1:10";
|
const SAMPLE_MESSAGE_ID = '1:10';
|
||||||
|
|
||||||
function expectSampleMessageFieldsPreserved(messages, frame) {
|
function expectSampleMessageFieldsPreserved(messages, frame) {
|
||||||
const { address, busTime, data, bus } = SAMPLE_MESSAGE;
|
const {
|
||||||
|
address, busTime, data, bus
|
||||||
|
} = SAMPLE_MESSAGE;
|
||||||
expect(messages[SAMPLE_MESSAGE_ID].address).toEqual(address);
|
expect(messages[SAMPLE_MESSAGE_ID].address).toEqual(address);
|
||||||
expect(messages[SAMPLE_MESSAGE_ID].id).toEqual(SAMPLE_MESSAGE_ID);
|
expect(messages[SAMPLE_MESSAGE_ID].id).toEqual(SAMPLE_MESSAGE_ID);
|
||||||
expect(messages[SAMPLE_MESSAGE_ID].bus).toEqual(bus);
|
expect(messages[SAMPLE_MESSAGE_ID].bus).toEqual(bus);
|
||||||
|
@ -28,7 +30,7 @@ function expectSampleMessageFieldsPreserved(messages, frame) {
|
||||||
// function addCanMessage([address, busTime, data, bus], dbc, canStartTime, messages, prevMsgEntries, byteStateChangeCountsByMessage) {
|
// function addCanMessage([address, busTime, data, bus], dbc, canStartTime, messages, prevMsgEntries, byteStateChangeCountsByMessage) {
|
||||||
function addMessages(messages, message, dbc, n) {
|
function addMessages(messages, message, dbc, n) {
|
||||||
const firstCanTime = 0;
|
const firstCanTime = 0;
|
||||||
let nextMessage = () => {
|
const nextMessage = () => {
|
||||||
message = extend(message);
|
message = extend(message);
|
||||||
message.busTime += 1;
|
message.busTime += 1;
|
||||||
return message;
|
return message;
|
||||||
|
@ -38,7 +40,7 @@ function addMessages(messages, message, dbc, n) {
|
||||||
DbcUtils.addCanMessage(nextMessage(), dbc, firstCanTime, messages, {}, {});
|
DbcUtils.addCanMessage(nextMessage(), dbc, firstCanTime, messages, {}, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
test("addCanMessage should add raw can message with empty dbc", () => {
|
test('addCanMessage should add raw can message with empty dbc', () => {
|
||||||
const messages = {};
|
const messages = {};
|
||||||
addMessages(messages, SAMPLE_MESSAGE, new DBC(), 1);
|
addMessages(messages, SAMPLE_MESSAGE, new DBC(), 1);
|
||||||
|
|
||||||
|
@ -46,7 +48,7 @@ test("addCanMessage should add raw can message with empty dbc", () => {
|
||||||
expectSampleMessageFieldsPreserved(messages);
|
expectSampleMessageFieldsPreserved(messages);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("addCanMessage should add multiple raw can messages with empty dbc", () => {
|
test('addCanMessage should add multiple raw can messages with empty dbc', () => {
|
||||||
const messages = {};
|
const messages = {};
|
||||||
addMessages(messages, SAMPLE_MESSAGE, new DBC(), 3);
|
addMessages(messages, SAMPLE_MESSAGE, new DBC(), 3);
|
||||||
|
|
||||||
|
@ -54,12 +56,12 @@ test("addCanMessage should add multiple raw can messages with empty dbc", () =>
|
||||||
expectSampleMessageFieldsPreserved(messages);
|
expectSampleMessageFieldsPreserved(messages);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("addCanMessage should add parsed can message with dbc containing message spec", () => {
|
test('addCanMessage should add parsed can message with dbc containing message spec', () => {
|
||||||
const messages = {};
|
const messages = {};
|
||||||
// create dbc with message spec and signal for sample_message
|
// create dbc with message spec and signal for sample_message
|
||||||
const dbc = new DBC();
|
const dbc = new DBC();
|
||||||
dbc.createFrame(SAMPLE_MESSAGE.address);
|
dbc.createFrame(SAMPLE_MESSAGE.address);
|
||||||
const signal = new Signal({ name: "NEW_SIGNAL", startBit: 0, size: 8 });
|
const signal = new Signal({ name: 'NEW_SIGNAL', startBit: 0, size: 8 });
|
||||||
dbc.addSignal(SAMPLE_MESSAGE.address, signal);
|
dbc.addSignal(SAMPLE_MESSAGE.address, signal);
|
||||||
|
|
||||||
// add 1 sample_message
|
// add 1 sample_message
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import DBC from "./models/can/dbc";
|
import DBC from './models/can/dbc';
|
||||||
|
|
||||||
const AcuraDbc = new DBC(`
|
const AcuraDbc = new DBC(`
|
||||||
VERSION ""
|
VERSION ""
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import GitHub from "github-api";
|
import GitHub from 'github-api';
|
||||||
|
|
||||||
import { OPENDBC_SOURCE_REPO } from "../config";
|
import { OPENDBC_SOURCE_REPO } from '../config';
|
||||||
|
|
||||||
export default class OpenDBC {
|
export default class OpenDBC {
|
||||||
constructor(token) {
|
constructor(token) {
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.github = new GitHub({ token });
|
this.github = new GitHub({ token });
|
||||||
this.sourceRepo = this.github.getRepo("commaai", "opendbc");
|
this.sourceRepo = this.github.getRepo('commaai', 'opendbc');
|
||||||
this.githubUsername = null;
|
this.githubUsername = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,11 +17,10 @@ export default class OpenDBC {
|
||||||
async getGithubUsername() {
|
async getGithubUsername() {
|
||||||
if (this.githubUsername) {
|
if (this.githubUsername) {
|
||||||
return this.githubUsername;
|
return this.githubUsername;
|
||||||
} else {
|
}
|
||||||
const githubUsername = await this.fetchGithubUsername();
|
const githubUsername = await this.fetchGithubUsername();
|
||||||
if (githubUsername) {
|
if (githubUsername) {
|
||||||
return githubUsername;
|
return githubUsername;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,13 +49,13 @@ export default class OpenDBC {
|
||||||
if (repoFullName === undefined) {
|
if (repoFullName === undefined) {
|
||||||
repo = this.sourceRepo;
|
repo = this.sourceRepo;
|
||||||
} else {
|
} else {
|
||||||
const [username, repoName] = repoFullName.split("/");
|
const [username, repoName] = repoFullName.split('/');
|
||||||
repo = this.github.getRepo(username, repoName);
|
repo = this.github.getRepo(username, repoName);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const response = await repo.getContents("master", "");
|
const response = await repo.getContents('master', '');
|
||||||
|
|
||||||
return response.data.map(content => content.path);
|
return response.data.map((content) => content.path);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -67,15 +66,15 @@ export default class OpenDBC {
|
||||||
if (repoFullName === undefined) {
|
if (repoFullName === undefined) {
|
||||||
repo = this.sourceRepo;
|
repo = this.sourceRepo;
|
||||||
} else {
|
} else {
|
||||||
const [username, repoName] = repoFullName.split("/");
|
const [username, repoName] = repoFullName.split('/');
|
||||||
repo = this.github.getRepo(username, repoName);
|
repo = this.github.getRepo(username, repoName);
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileContents = await repo.getContents("master", dbcPath);
|
const fileContents = await repo.getContents('master', dbcPath);
|
||||||
|
|
||||||
const rawContentsUrl = fileContents.data.download_url;
|
const rawContentsUrl = fileContents.data.download_url;
|
||||||
|
|
||||||
const resp = await fetch(rawContentsUrl, { cache: "no-cache" });
|
const resp = await fetch(rawContentsUrl, { cache: 'no-cache' });
|
||||||
|
|
||||||
return resp.text();
|
return resp.text();
|
||||||
}
|
}
|
||||||
|
@ -90,24 +89,22 @@ export default class OpenDBC {
|
||||||
const githubUsername = await this.getGithubUsername();
|
const githubUsername = await this.getGithubUsername();
|
||||||
if (!githubUsername) return null;
|
if (!githubUsername) return null;
|
||||||
|
|
||||||
const openDbcFork = this.github.getRepo(githubUsername, "opendbc");
|
const openDbcFork = this.github.getRepo(githubUsername, 'opendbc');
|
||||||
const repoDetailResp = await openDbcFork.getDetails();
|
const repoDetailResp = await openDbcFork.getDetails();
|
||||||
const repoDetails = repoDetailResp.data;
|
const repoDetails = repoDetailResp.data;
|
||||||
|
|
||||||
if (this.repoSourceIsOpenDbc(repoDetails)) {
|
if (this.repoSourceIsOpenDbc(repoDetails)) {
|
||||||
return repoDetails.full_name;
|
return repoDetails.full_name;
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fork() {
|
async fork() {
|
||||||
const forkResponse = await this.sourceRepo.fork();
|
const forkResponse = await this.sourceRepo.fork();
|
||||||
if (forkResponse.status === 202) {
|
if (forkResponse.status === 202) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async commitFile(repoFullName, path, contents, commitMessage) {
|
async commitFile(repoFullName, path, contents, commitMessage) {
|
||||||
|
@ -115,11 +112,11 @@ export default class OpenDBC {
|
||||||
repo is of format username/reponame
|
repo is of format username/reponame
|
||||||
authenciated user must have write access to repo
|
authenciated user must have write access to repo
|
||||||
*/
|
*/
|
||||||
const [user, repoName] = repoFullName.split("/");
|
const [user, repoName] = repoFullName.split('/');
|
||||||
const repo = this.github.getRepo(user, repoName);
|
const repo = this.github.getRepo(user, repoName);
|
||||||
|
|
||||||
// get HEAD reference
|
// get HEAD reference
|
||||||
const refResp = await repo.getRef("heads/master");
|
const refResp = await repo.getRef('heads/master');
|
||||||
const ref = refResp.data;
|
const ref = refResp.data;
|
||||||
|
|
||||||
// get HEAD commit sha
|
// get HEAD commit sha
|
||||||
|
@ -133,9 +130,9 @@ export default class OpenDBC {
|
||||||
// create new tree
|
// create new tree
|
||||||
const tree = [
|
const tree = [
|
||||||
{
|
{
|
||||||
mode: "100644",
|
mode: '100644',
|
||||||
path: path,
|
path,
|
||||||
type: "blob",
|
type: 'blob',
|
||||||
content: contents
|
content: contents
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -147,13 +144,13 @@ export default class OpenDBC {
|
||||||
const commitResp = await repo.commit(
|
const commitResp = await repo.commit(
|
||||||
headCommit.sha,
|
headCommit.sha,
|
||||||
createdTree.sha,
|
createdTree.sha,
|
||||||
commitMessage || "OpenDBC updates"
|
commitMessage || 'OpenDBC updates'
|
||||||
);
|
);
|
||||||
const commit = commitResp.data;
|
const commit = commitResp.data;
|
||||||
|
|
||||||
// update HEAD
|
// update HEAD
|
||||||
const updateHeadResp = await repo.updateHead(
|
const updateHeadResp = await repo.updateHead(
|
||||||
"heads/master",
|
'heads/master',
|
||||||
commit.sha,
|
commit.sha,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { GITHUB_CLIENT_ID, GITHUB_REDIRECT_URL } from "../config";
|
import { GITHUB_CLIENT_ID, GITHUB_REDIRECT_URL } from '../config';
|
||||||
import { objToQuery } from "../utils/url";
|
import { objToQuery } from '../utils/url';
|
||||||
|
|
||||||
export function authorizeUrl(route) {
|
export function authorizeUrl(route) {
|
||||||
const params = {
|
const params = {
|
||||||
client_id: GITHUB_CLIENT_ID,
|
client_id: GITHUB_CLIENT_ID,
|
||||||
redirect_uri: GITHUB_REDIRECT_URL,
|
redirect_uri: GITHUB_REDIRECT_URL,
|
||||||
scope: "user:email public_repo",
|
scope: 'user:email public_repo',
|
||||||
state: JSON.stringify({ route })
|
state: JSON.stringify({ route })
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import DBC from "../models/can/dbc";
|
import DBC from '../models/can/dbc';
|
||||||
|
|
||||||
export function fetchPersistedDbc(routeName) {
|
export function fetchPersistedDbc(routeName) {
|
||||||
const maybeDbc = window.localStorage.getItem(routeName);
|
const maybeDbc = window.localStorage.getItem(routeName);
|
||||||
|
@ -7,7 +7,8 @@ export function fetchPersistedDbc(routeName) {
|
||||||
const dbc = new DBC(dbcText);
|
const dbc = new DBC(dbcText);
|
||||||
|
|
||||||
return { dbc, dbcText, dbcFilename };
|
return { dbc, dbcText, dbcFilename };
|
||||||
} else return null;
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function persistDbc(routeName, { dbcFilename, dbc }) {
|
export function persistDbc(routeName, { dbcFilename, dbc }) {
|
||||||
|
@ -18,7 +19,7 @@ export function persistDbc(routeName, { dbcFilename, dbc }) {
|
||||||
window.localStorage.setItem(routeName, dbcJson);
|
window.localStorage.setItem(routeName, dbcJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
const GITHUB_AUTH_TOKEN_LOCALSTORAGE_KEY = "gh_auth_token";
|
const GITHUB_AUTH_TOKEN_LOCALSTORAGE_KEY = 'gh_auth_token';
|
||||||
export function fetchPersistedGithubAuthToken() {
|
export function fetchPersistedGithubAuthToken() {
|
||||||
return window.localStorage.getItem(GITHUB_AUTH_TOKEN_LOCALSTORAGE_KEY);
|
return window.localStorage.getItem(GITHUB_AUTH_TOKEN_LOCALSTORAGE_KEY);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { raw as RawDataApi, request as Request } from "@commaai/comma-api";
|
import { raw as RawDataApi, request as Request } from '@commaai/comma-api';
|
||||||
import CommaAuth from "@commaai/my-comma-auth";
|
import CommaAuth from '@commaai/my-comma-auth';
|
||||||
import request from "simple-get";
|
import request from 'simple-get';
|
||||||
|
|
||||||
const urlStore = {};
|
const urlStore = {};
|
||||||
|
|
||||||
var initPromise;
|
let initPromise;
|
||||||
function ensureInit() {
|
function ensureInit() {
|
||||||
if (!initPromise) {
|
if (!initPromise) {
|
||||||
initPromise = CommaAuth.init().then(function(token) {
|
initPromise = CommaAuth.init().then((token) => {
|
||||||
Request.configure(token);
|
Request.configure(token);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
});
|
});
|
||||||
|
@ -16,8 +16,8 @@ function ensureInit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLogPart(logUrl) {
|
export async function getLogPart(logUrl) {
|
||||||
return new Promise(async function(resolve, reject) {
|
return new Promise(async (resolve, reject) => {
|
||||||
request(logUrl, function(err, res) {
|
request(logUrl, (err, res) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return reject(err);
|
return reject(err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import SocketIO from "socket.io-client";
|
import SocketIO from 'socket.io-client';
|
||||||
import { UNLOGGER_HOST } from "../config";
|
import { UNLOGGER_HOST } from '../config';
|
||||||
|
|
||||||
export default class UnloggerClient {
|
export default class UnloggerClient {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -7,6 +7,6 @@ export default class UnloggerClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
seek(dongleId, baseTime, seekSeconds) {
|
seek(dongleId, baseTime, seekSeconds) {
|
||||||
this.socket.emit("seek", dongleId, baseTime, seekSeconds);
|
this.socket.emit('seek', dongleId, baseTime, seekSeconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import DBC from "./models/can/dbc";
|
import DBC from './models/can/dbc';
|
||||||
|
|
||||||
const CivicDbc = new DBC(`
|
const CivicDbc = new DBC(`
|
||||||
VERSION ""
|
VERSION ""
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import { StyleSheet } from "aphrodite/no-important";
|
import { StyleSheet } from 'aphrodite/no-important';
|
||||||
import css from "../utils/css";
|
import css from '../utils/css';
|
||||||
|
|
||||||
import SignalLegend from "./SignalLegend";
|
import SignalLegend from './SignalLegend';
|
||||||
import Signal from "../models/can/signal";
|
import Signal from '../models/can/signal';
|
||||||
import { shade } from "../utils/color";
|
import { shade } from '../utils/color';
|
||||||
import DbcUtils from "../utils/dbc";
|
import DbcUtils from '../utils/dbc';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
AddSignals component draws an 8x8 matrix
|
AddSignals component draws an 8x8 matrix
|
||||||
|
@ -20,25 +20,25 @@ const Styles = StyleSheet.create({
|
||||||
bit: {
|
bit: {
|
||||||
margin: 0,
|
margin: 0,
|
||||||
padding: 12,
|
padding: 12,
|
||||||
userSelect: "none",
|
userSelect: 'none',
|
||||||
cursor: "pointer",
|
cursor: 'pointer',
|
||||||
textAlign: "center",
|
textAlign: 'center',
|
||||||
position: "relative"
|
position: 'relative'
|
||||||
},
|
},
|
||||||
bitSelectedStyle: {
|
bitSelectedStyle: {
|
||||||
backgroundColor: "rgba(0,119,158,0.5)"
|
backgroundColor: 'rgba(0,119,158,0.5)'
|
||||||
},
|
},
|
||||||
bitSignificance: {
|
bitSignificance: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
display: "block",
|
display: 'block',
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
margin: "0 auto"
|
margin: '0 auto'
|
||||||
},
|
},
|
||||||
highlightedSignalTitle: {
|
highlightedSignalTitle: {
|
||||||
backgroundColor: "rgba(0,0,0,0.2)"
|
backgroundColor: 'rgba(0,0,0,0.2)'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ export default class AddSignals extends Component {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
bits: [],
|
bits: [],
|
||||||
signals: signals,
|
signals,
|
||||||
signalStyles: this.calcSignalStyles(signals),
|
signalStyles: this.calcSignalStyles(signals),
|
||||||
highlightedSignal: null,
|
highlightedSignal: null,
|
||||||
dragStartBit: null,
|
dragStartBit: null,
|
||||||
|
@ -82,28 +82,29 @@ export default class AddSignals extends Component {
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
return (
|
return (
|
||||||
nextProps.message.hexData !== this.props.message.hexData ||
|
nextProps.message.hexData !== this.props.message.hexData
|
||||||
nextProps.messageIndex !== this.props.messageIndex ||
|
|| nextProps.messageIndex !== this.props.messageIndex
|
||||||
JSON.stringify(nextProps.plottedSignalUids) !==
|
|| JSON.stringify(nextProps.plottedSignalUids)
|
||||||
JSON.stringify(this.props.plottedSignalUids) ||
|
!== JSON.stringify(this.props.plottedSignalUids)
|
||||||
JSON.stringify(this.state) !== JSON.stringify(nextState)
|
|| JSON.stringify(this.state) !== JSON.stringify(nextState)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
signalColorStyle(signal) {
|
signalColorStyle(signal) {
|
||||||
const { colors } = signal;
|
const { colors } = signal;
|
||||||
|
|
||||||
let colorRgbStr, backgroundColor;
|
let colorRgbStr;
|
||||||
|
let backgroundColor;
|
||||||
if (this.state && this.state.highlightedSignal === signal.name) {
|
if (this.state && this.state.highlightedSignal === signal.name) {
|
||||||
// when signal highlighted,
|
// when signal highlighted,
|
||||||
// darkened background and lightened text.
|
// darkened background and lightened text.
|
||||||
|
|
||||||
const darkenedColors = shade(colors, -0.5);
|
const darkenedColors = shade(colors, -0.5);
|
||||||
const lightenedColors = shade(colors, 0.9);
|
const lightenedColors = shade(colors, 0.9);
|
||||||
colorRgbStr = `rgb(${lightenedColors.join(",")})`;
|
colorRgbStr = `rgb(${lightenedColors.join(',')})`;
|
||||||
backgroundColor = `rgba(${darkenedColors.join(",")},0.5)`;
|
backgroundColor = `rgba(${darkenedColors.join(',')},0.5)`;
|
||||||
} else {
|
} else {
|
||||||
const colorsCommaSep = colors.join(",");
|
const colorsCommaSep = colors.join(',');
|
||||||
colorRgbStr = `rgb(${colorsCommaSep})`;
|
colorRgbStr = `rgb(${colorsCommaSep})`;
|
||||||
backgroundColor = `rgba(${colorsCommaSep},0.2)`;
|
backgroundColor = `rgba(${colorsCommaSep},0.2)`;
|
||||||
}
|
}
|
||||||
|
@ -122,7 +123,7 @@ export default class AddSignals extends Component {
|
||||||
|
|
||||||
calcSignalStyles(signals) {
|
calcSignalStyles(signals) {
|
||||||
const signalStyles = {};
|
const signalStyles = {};
|
||||||
Object.values(signals).forEach(signal => {
|
Object.values(signals).forEach((signal) => {
|
||||||
signalStyles[signal.name] = this.signalColorStyle(signal);
|
signalStyles[signal.name] = this.signalColorStyle(signal);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -145,12 +146,12 @@ export default class AddSignals extends Component {
|
||||||
// bitIdx in [0,64)
|
// bitIdx in [0,64)
|
||||||
// returns instance of Signal
|
// returns instance of Signal
|
||||||
|
|
||||||
return Object.values(this.state.signals).filter(signal => {
|
return Object.values(this.state.signals).filter(
|
||||||
return signal.bitDescription(bitIdx) !== null;
|
(signal) => signal.bitDescription(bitIdx) !== null
|
||||||
})[0];
|
)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignalHover = signal => {
|
onSignalHover = (signal) => {
|
||||||
if (!signal) return;
|
if (!signal) return;
|
||||||
|
|
||||||
this.setState({ highlightedSignal: signal.name }, this.updateSignalStyles);
|
this.setState({ highlightedSignal: signal.name }, this.updateSignalStyles);
|
||||||
|
@ -214,22 +215,20 @@ export default class AddSignals extends Component {
|
||||||
dragSignal.size = bitIdx - dragStartBit + 1;
|
dragSignal.size = bitIdx - dragStartBit + 1;
|
||||||
dragStartBit = bitIdx;
|
dragStartBit = bitIdx;
|
||||||
}
|
}
|
||||||
|
} else if (dragSignal.isLittleEndian) {
|
||||||
|
dragSignal.startBit = bitIdx;
|
||||||
|
dragSignal.size = dragStartBit - bitIdx + 1;
|
||||||
|
dragStartBit = bitIdx;
|
||||||
} else {
|
} else {
|
||||||
if (dragSignal.isLittleEndian) {
|
dragSignal.size = dragStartBit - bitIdx + 1;
|
||||||
dragSignal.startBit = bitIdx;
|
dragStartBit = bitIdx;
|
||||||
dragSignal.size = dragStartBit - bitIdx + 1;
|
|
||||||
dragStartBit = bitIdx;
|
|
||||||
} else {
|
|
||||||
dragSignal.size = dragStartBit - bitIdx + 1;
|
|
||||||
dragStartBit = bitIdx;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signals[dragSignal.name] = dragSignal;
|
signals[dragSignal.name] = dragSignal;
|
||||||
} else if (
|
} else if (
|
||||||
dragSignal.isLittleEndian &&
|
dragSignal.isLittleEndian
|
||||||
dragStartBit === dragSignal.msbBitIndex()
|
&& dragStartBit === dragSignal.msbBitIndex()
|
||||||
) {
|
) {
|
||||||
if (bitIdx < dragSignal.startBit) {
|
if (bitIdx < dragSignal.startBit) {
|
||||||
// should not be able to drag the MSB past the LSB
|
// should not be able to drag the MSB past the LSB
|
||||||
|
@ -244,8 +243,8 @@ export default class AddSignals extends Component {
|
||||||
signals[dragSignal.name] = dragSignal;
|
signals[dragSignal.name] = dragSignal;
|
||||||
dragStartBit = dragSignal.msbBitIndex();
|
dragStartBit = dragSignal.msbBitIndex();
|
||||||
} else if (
|
} else if (
|
||||||
!dragSignal.isLittleEndian &&
|
!dragSignal.isLittleEndian
|
||||||
dragStartBit === dragSignal.lsbBitIndex()
|
&& dragStartBit === dragSignal.lsbBitIndex()
|
||||||
) {
|
) {
|
||||||
const diff = bitIdx - dragStartBit;
|
const diff = bitIdx - dragStartBit;
|
||||||
if (dragSignal.bitDescription(bitIdx) === null) {
|
if (dragSignal.bitDescription(bitIdx) === null) {
|
||||||
|
@ -271,7 +270,7 @@ export default class AddSignals extends Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onSignalHoverEnd = signal => {
|
onSignalHoverEnd = (signal) => {
|
||||||
if (!signal) return;
|
if (!signal) return;
|
||||||
|
|
||||||
this.setState({ highlightedSignal: null }, this.updateSignalStyles);
|
this.setState({ highlightedSignal: null }, this.updateSignalStyles);
|
||||||
|
@ -279,10 +278,10 @@ export default class AddSignals extends Component {
|
||||||
|
|
||||||
nextNewSignalName() {
|
nextNewSignalName() {
|
||||||
const existingNames = Object.keys(this.state.signals);
|
const existingNames = Object.keys(this.state.signals);
|
||||||
let signalNum = 1,
|
let signalNum = 1;
|
||||||
signalName;
|
let signalName;
|
||||||
do {
|
do {
|
||||||
signalName = "NEW_SIGNAL_" + signalNum;
|
signalName = `NEW_SIGNAL_${signalNum}`;
|
||||||
signalNum++;
|
signalNum++;
|
||||||
} while (existingNames.indexOf(signalName) !== -1);
|
} while (existingNames.indexOf(signalName) !== -1);
|
||||||
|
|
||||||
|
@ -300,7 +299,7 @@ export default class AddSignals extends Component {
|
||||||
const signal = new Signal({
|
const signal = new Signal({
|
||||||
name: this.nextNewSignalName(),
|
name: this.nextNewSignalName(),
|
||||||
startBit,
|
startBit,
|
||||||
size: size,
|
size,
|
||||||
isLittleEndian
|
isLittleEndian
|
||||||
});
|
});
|
||||||
let { signals } = this.state;
|
let { signals } = this.state;
|
||||||
|
@ -319,10 +318,8 @@ export default class AddSignals extends Component {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const isDragAcrossSingleByte =
|
const isDragAcrossSingleByte = Math.floor(dragEndBit / 8) === Math.floor(dragStartBit / 8);
|
||||||
Math.floor(dragEndBit / 8) === Math.floor(dragStartBit / 8);
|
const isDragDirectionUp = !isDragAcrossSingleByte && dragEndBit < dragStartBit;
|
||||||
const isDragDirectionUp =
|
|
||||||
!isDragAcrossSingleByte && dragEndBit < dragStartBit;
|
|
||||||
|
|
||||||
let isLittleEndian;
|
let isLittleEndian;
|
||||||
if (isDragAcrossSingleByte || !isDragDirectionUp) {
|
if (isDragAcrossSingleByte || !isDragDirectionUp) {
|
||||||
|
@ -330,30 +327,27 @@ export default class AddSignals extends Component {
|
||||||
} else {
|
} else {
|
||||||
isLittleEndian = dragStartBit % 8 >= 4;
|
isLittleEndian = dragStartBit % 8 >= 4;
|
||||||
}
|
}
|
||||||
let size,
|
let size;
|
||||||
startBit = dragStartBit;
|
let startBit = dragStartBit;
|
||||||
|
|
||||||
if (isDragAcrossSingleByte) {
|
if (isDragAcrossSingleByte) {
|
||||||
size = Math.abs(dragEndBit - dragStartBit) + 1;
|
size = Math.abs(dragEndBit - dragStartBit) + 1;
|
||||||
} else {
|
} else if (isLittleEndian) {
|
||||||
if (isLittleEndian) {
|
if (dragEndBit > dragStartBit) {
|
||||||
if (dragEndBit > dragStartBit) {
|
startBit = dragStartBit;
|
||||||
startBit = dragStartBit;
|
size = dragEndBit - dragStartBit + 1;
|
||||||
size = dragEndBit - dragStartBit + 1;
|
|
||||||
} else {
|
|
||||||
startBit = dragEndBit;
|
|
||||||
size = dragStartBit - dragEndBit + 1;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (dragEndBit < dragStartBit) {
|
startBit = dragEndBit;
|
||||||
startBit = dragEndBit;
|
size = dragStartBit - dragEndBit + 1;
|
||||||
}
|
|
||||||
size =
|
|
||||||
Math.abs(
|
|
||||||
DbcUtils.bigEndianBitIndex(dragEndBit) -
|
|
||||||
DbcUtils.bigEndianBitIndex(dragStartBit)
|
|
||||||
) + 1;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (dragEndBit < dragStartBit) {
|
||||||
|
startBit = dragEndBit;
|
||||||
|
}
|
||||||
|
size = Math.abs(
|
||||||
|
DbcUtils.bigEndianBitIndex(dragEndBit)
|
||||||
|
- DbcUtils.bigEndianBitIndex(dragStartBit)
|
||||||
|
) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.createSignal({ startBit, size, isLittleEndian });
|
this.createSignal({ startBit, size, isLittleEndian });
|
||||||
|
@ -362,7 +356,7 @@ export default class AddSignals extends Component {
|
||||||
|
|
||||||
onBitMouseUp(dragEndBit, signal) {
|
onBitMouseUp(dragEndBit, signal) {
|
||||||
if (this.state.dragStartBit !== null) {
|
if (this.state.dragStartBit !== null) {
|
||||||
let { dragStartBit } = this.state;
|
const { dragStartBit } = this.state;
|
||||||
|
|
||||||
if (dragEndBit !== dragStartBit) {
|
if (dragEndBit !== dragStartBit) {
|
||||||
// one-bit signal requires double click
|
// one-bit signal requires double click
|
||||||
|
@ -380,24 +374,22 @@ export default class AddSignals extends Component {
|
||||||
const entry = entries[this.props.messageIndex];
|
const entry = entries[this.props.messageIndex];
|
||||||
|
|
||||||
return entry.hexData.substr(byteIdx * 2, 2);
|
return entry.hexData.substr(byteIdx * 2, 2);
|
||||||
} else {
|
|
||||||
return "--";
|
|
||||||
}
|
}
|
||||||
|
return '--';
|
||||||
}
|
}
|
||||||
|
|
||||||
bitValue(byteIdx, byteBitIdx) {
|
bitValue(byteIdx, byteBitIdx) {
|
||||||
const { entries } = this.props.message;
|
const { entries } = this.props.message;
|
||||||
if (this.props.messageIndex < entries.length) {
|
if (this.props.messageIndex < entries.length) {
|
||||||
const entry = entries[this.props.messageIndex];
|
const entry = entries[this.props.messageIndex];
|
||||||
const data = Buffer.from(entry.hexData, "hex");
|
const data = Buffer.from(entry.hexData, 'hex');
|
||||||
if (byteIdx >= data.length) {
|
if (byteIdx >= data.length) {
|
||||||
return "-";
|
return '-';
|
||||||
}
|
}
|
||||||
const byte = data.readInt8(byteIdx);
|
const byte = data.readInt8(byteIdx);
|
||||||
return (byte >> byteBitIdx) & 1;
|
return (byte >> byteBitIdx) & 1;
|
||||||
} else {
|
|
||||||
return "-";
|
|
||||||
}
|
}
|
||||||
|
return '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
bitIsContainedInSelection(bitIdx, isLittleEndian = false) {
|
bitIsContainedInSelection(bitIdx, isLittleEndian = false) {
|
||||||
|
@ -405,22 +397,21 @@ export default class AddSignals extends Component {
|
||||||
|
|
||||||
if (isLittleEndian || dragStartBit % 8 < 4) {
|
if (isLittleEndian || dragStartBit % 8 < 4) {
|
||||||
return (
|
return (
|
||||||
dragStartBit !== null &&
|
dragStartBit !== null
|
||||||
dragCurrentBit !== null &&
|
&& dragCurrentBit !== null
|
||||||
bitIdx >= dragStartBit &&
|
&& bitIdx >= dragStartBit
|
||||||
bitIdx <= dragCurrentBit
|
&& bitIdx <= dragCurrentBit
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const bigEndianStartBit = DbcUtils.bigEndianBitIndex(dragStartBit);
|
|
||||||
const bigEndianCurrentBit = DbcUtils.bigEndianBitIndex(dragCurrentBit);
|
|
||||||
const bigEndianBitIdx = DbcUtils.bigEndianBitIndex(bitIdx);
|
|
||||||
return (
|
|
||||||
dragStartBit !== null &&
|
|
||||||
dragCurrentBit !== null &&
|
|
||||||
bigEndianBitIdx >= bigEndianStartBit &&
|
|
||||||
bigEndianBitIdx <= bigEndianCurrentBit
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const bigEndianStartBit = DbcUtils.bigEndianBitIndex(dragStartBit);
|
||||||
|
const bigEndianCurrentBit = DbcUtils.bigEndianBitIndex(dragCurrentBit);
|
||||||
|
const bigEndianBitIdx = DbcUtils.bigEndianBitIndex(bitIdx);
|
||||||
|
return (
|
||||||
|
dragStartBit !== null
|
||||||
|
&& dragCurrentBit !== null
|
||||||
|
&& bigEndianBitIdx >= bigEndianStartBit
|
||||||
|
&& bigEndianBitIdx <= bigEndianCurrentBit
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onBitDoubleClick(startBit, signal) {
|
onBitDoubleClick(startBit, signal) {
|
||||||
|
@ -434,26 +425,26 @@ export default class AddSignals extends Component {
|
||||||
const rows = [];
|
const rows = [];
|
||||||
let rowCount;
|
let rowCount;
|
||||||
if (message.frame && message.frame.size) {
|
if (message.frame && message.frame.size) {
|
||||||
rowCount = Math.floor(message.frame.size * 8 / 8);
|
rowCount = Math.floor((message.frame.size * 8) / 8);
|
||||||
} else {
|
} else {
|
||||||
rowCount = 8;
|
rowCount = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < rowCount; i++) {
|
for (let i = 0; i < rowCount; i++) {
|
||||||
const rowBits = [];
|
const rowBits = [];
|
||||||
for (var j = 7; j >= 0; j--) {
|
for (let j = 7; j >= 0; j--) {
|
||||||
const bitIdx = i * 8 + j;
|
const bitIdx = i * 8 + j;
|
||||||
const signal = this.signalForBit(bitIdx);
|
const signal = this.signalForBit(bitIdx);
|
||||||
let bitStyle = null,
|
let bitStyle = null;
|
||||||
bitSignificance = "";
|
let bitSignificance = '';
|
||||||
if (signal) {
|
if (signal) {
|
||||||
bitStyle = this.state.signalStyles[signal.name] || null;
|
bitStyle = this.state.signalStyles[signal.name] || null;
|
||||||
const bitDesc = signal.bitDescription(bitIdx);
|
const bitDesc = signal.bitDescription(bitIdx);
|
||||||
bitSignificance = bitDesc.isMsb ? "msb" : bitDesc.isLsb ? "lsb" : "";
|
bitSignificance = bitDesc.isMsb ? 'msb' : bitDesc.isLsb ? 'lsb' : '';
|
||||||
} else if (this.bitIsContainedInSelection(bitIdx)) {
|
} else if (this.bitIsContainedInSelection(bitIdx)) {
|
||||||
bitStyle = Styles.bitSelectedStyle;
|
bitStyle = Styles.bitSelectedStyle;
|
||||||
}
|
}
|
||||||
const className = css("bit", Styles.bit, bitStyle);
|
const className = css('bit', Styles.bit, bitStyle);
|
||||||
const bitValue = this.bitValue(i, j);
|
const bitValue = this.bitValue(i, j);
|
||||||
|
|
||||||
rowBits.push(
|
rowBits.push(
|
||||||
|
@ -474,7 +465,7 @@ export default class AddSignals extends Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
rowBits.push(<td key={"hex-repr"}>{this.byteValueHex(i)}</td>);
|
rowBits.push(<td key="hex-repr">{this.byteValueHex(i)}</td>);
|
||||||
rows.push(<tr key={i.toString()}>{rowBits}</tr>);
|
rows.push(<tr key={i.toString()}>{rowBits}</tr>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,7 +486,7 @@ export default class AddSignals extends Component {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onTentativeSignalChange = signal => {
|
onTentativeSignalChange = (signal) => {
|
||||||
// Tentative signal changes are not propagated up
|
// Tentative signal changes are not propagated up
|
||||||
// but their effects are displayed in the bitmatrix
|
// but their effects are displayed in the bitmatrix
|
||||||
const { signals } = this.state;
|
const { signals } = this.state;
|
||||||
|
@ -506,7 +497,7 @@ export default class AddSignals extends Component {
|
||||||
onSignalChange = (signal, oldSignal) => {
|
onSignalChange = (signal, oldSignal) => {
|
||||||
const { signals } = this.state;
|
const { signals } = this.state;
|
||||||
|
|
||||||
for (let signalName in signals) {
|
for (const signalName in signals) {
|
||||||
if (signals[signalName].uid === signal.uid) {
|
if (signals[signalName].uid === signal.uid) {
|
||||||
delete signals[signalName];
|
delete signals[signalName];
|
||||||
}
|
}
|
||||||
|
@ -516,7 +507,7 @@ export default class AddSignals extends Component {
|
||||||
this.setState({ signals }, this.propagateUpSignalChange);
|
this.setState({ signals }, this.propagateUpSignalChange);
|
||||||
};
|
};
|
||||||
|
|
||||||
onSignalRemove = signal => {
|
onSignalRemove = (signal) => {
|
||||||
const { signals } = this.state;
|
const { signals } = this.state;
|
||||||
delete signals[signal.name];
|
delete signals[signal.name];
|
||||||
this.setState({ signals }, this.propagateUpSignalChange);
|
this.setState({ signals }, this.propagateUpSignalChange);
|
||||||
|
@ -546,7 +537,8 @@ export default class AddSignals extends Component {
|
||||||
{this.props.message.entries[this.props.messageIndex] ? (
|
{this.props.message.entries[this.props.messageIndex] ? (
|
||||||
<div className="cabana-explorer-signals-time">
|
<div className="cabana-explorer-signals-time">
|
||||||
<p>
|
<p>
|
||||||
time:{" "}
|
time:
|
||||||
|
{' '}
|
||||||
{this.props.message.entries[
|
{this.props.message.entries[
|
||||||
this.props.messageIndex
|
this.props.messageIndex
|
||||||
].relTime.toFixed(3)}
|
].relTime.toFixed(3)}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import Measure from "react-measure";
|
import Measure from 'react-measure';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import cx from "classnames";
|
import cx from 'classnames';
|
||||||
import { Vega } from "react-vega";
|
import { Vega } from 'react-vega';
|
||||||
|
|
||||||
import Signal from "../models/can/signal";
|
import Signal from '../models/can/signal';
|
||||||
import GraphData from "../models/graph-data";
|
import GraphData from '../models/graph-data';
|
||||||
import CanPlotSpec from "../vega/CanPlot";
|
import CanPlotSpec from '../vega/CanPlot';
|
||||||
import debounce from "../utils/debounce";
|
import debounce from '../utils/debounce';
|
||||||
|
|
||||||
const DefaultPlotInnerStyle = {
|
const DefaultPlotInnerStyle = {
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0
|
left: 0
|
||||||
};
|
};
|
||||||
|
@ -63,10 +63,10 @@ export default class CanGraph extends Component {
|
||||||
getGraphData(props) {
|
getGraphData(props) {
|
||||||
let firstRelTime = -1;
|
let firstRelTime = -1;
|
||||||
let lastRelTime = -1;
|
let lastRelTime = -1;
|
||||||
let series = props.plottedSignals
|
const series = props.plottedSignals
|
||||||
.map(signals => {
|
.map((signals) => {
|
||||||
const { messageId, signalUid } = signals;
|
const { messageId, signalUid } = signals;
|
||||||
let entries = props.messages[messageId].entries;
|
const { entries } = props.messages[messageId];
|
||||||
if (entries.length) {
|
if (entries.length) {
|
||||||
let messageRelTime = entries[0].relTime;
|
let messageRelTime = entries[0].relTime;
|
||||||
if (firstRelTime === -1) {
|
if (firstRelTime === -1) {
|
||||||
|
@ -109,15 +109,15 @@ export default class CanGraph extends Component {
|
||||||
|
|
||||||
segmentIsNew(newSegment) {
|
segmentIsNew(newSegment) {
|
||||||
return (
|
return (
|
||||||
newSegment.length !== this.props.segment.length ||
|
newSegment.length !== this.props.segment.length
|
||||||
!newSegment.every((val, idx) => this.props.segment[idx] === val)
|
|| !newSegment.every((val, idx) => this.props.segment[idx] === val)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
visualChanged(prevProps, nextProps) {
|
visualChanged(prevProps, nextProps) {
|
||||||
return (
|
return (
|
||||||
prevProps.canReceiveGraphDrop !== nextProps.canReceiveGraphDrop ||
|
prevProps.canReceiveGraphDrop !== nextProps.canReceiveGraphDrop
|
||||||
JSON.stringify(prevProps.dragPos) !== JSON.stringify(nextProps.dragPos)
|
|| JSON.stringify(prevProps.dragPos) !== JSON.stringify(nextProps.dragPos)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,46 +138,46 @@ export default class CanGraph extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBounds = debounce(() => {
|
updateBounds = debounce(() => {
|
||||||
this.view.signal("width", this.state.bounds.width - 70);
|
this.view.signal('width', this.state.bounds.width - 70);
|
||||||
this.view.signal("height", 0.4 * (this.state.bounds.width - 70)); // 5:2 aspect ratio
|
this.view.signal('height', 0.4 * (this.state.bounds.width - 70)); // 5:2 aspect ratio
|
||||||
this.view.run();
|
this.view.run();
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
insertData = debounce(() => {
|
insertData = debounce(() => {
|
||||||
if (!this.view) {
|
if (!this.view) {
|
||||||
console.log("Cannot insertData");
|
console.log('Cannot insertData');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// adding plot points by diff isn't faster since it basically has to be n^2
|
// adding plot points by diff isn't faster since it basically has to be n^2
|
||||||
// out-of-order events make it so that you can't just check the bounds
|
// out-of-order events make it so that you can't just check the bounds
|
||||||
let { series } = this.state.data;
|
const { series } = this.state.data;
|
||||||
let changeset = this.view
|
const changeset = this.view
|
||||||
.changeset()
|
.changeset()
|
||||||
.remove(v => true)
|
.remove((v) => true)
|
||||||
.insert(series);
|
.insert(series);
|
||||||
this.view.change("table", changeset);
|
this.view.change('table', changeset);
|
||||||
this.view.run();
|
this.view.run();
|
||||||
}, 250);
|
}, 250);
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (
|
if (
|
||||||
nextProps.dragPos &&
|
nextProps.dragPos
|
||||||
JSON.stringify(nextProps.dragPos) !== JSON.stringify(this.props.dragPos)
|
&& JSON.stringify(nextProps.dragPos) !== JSON.stringify(this.props.dragPos)
|
||||||
) {
|
) {
|
||||||
this.updateStyleFromDragPos(nextProps.dragPos);
|
this.updateStyleFromDragPos(nextProps.dragPos);
|
||||||
} else if (!nextProps.dragPos && this.state.plotInnerStyle !== null) {
|
} else if (!nextProps.dragPos && this.state.plotInnerStyle !== null) {
|
||||||
this.setState({ plotInnerStyle: null });
|
this.setState({ plotInnerStyle: null });
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
this.props.messages !== nextProps.messages ||
|
this.props.messages !== nextProps.messages
|
||||||
this.props.plottedSignal !== nextProps.plottedSignal
|
|| this.props.plottedSignal !== nextProps.plottedSignal
|
||||||
) {
|
) {
|
||||||
let data = this.getGraphData(nextProps);
|
const data = this.getGraphData(nextProps);
|
||||||
if (
|
if (
|
||||||
data.series.length === this.state.data.series.length &&
|
data.series.length === this.state.data.series.length
|
||||||
data.firstRelTime === this.state.data.firstRelTime &&
|
&& data.firstRelTime === this.state.data.firstRelTime
|
||||||
data.lastRelTime === this.state.data.lastRelTime
|
&& data.lastRelTime === this.state.data.lastRelTime
|
||||||
) {
|
) {
|
||||||
// do nothing, the data didn't *actually* change
|
// do nothing, the data didn't *actually* change
|
||||||
} else {
|
} else {
|
||||||
|
@ -188,6 +188,7 @@ export default class CanGraph extends Component {
|
||||||
this.setState({ spec: this.getGraphSpec(nextProps) });
|
this.setState({ spec: this.getGraphSpec(nextProps) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
if (!this.view) {
|
if (!this.view) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -199,30 +200,31 @@ export default class CanGraph extends Component {
|
||||||
this.insertData();
|
this.insertData();
|
||||||
}
|
}
|
||||||
if (this.props.currentTime !== nextProps.currentTime) {
|
if (this.props.currentTime !== nextProps.currentTime) {
|
||||||
this.view.signal("videoTime", nextProps.currentTime);
|
this.view.signal('videoTime', nextProps.currentTime);
|
||||||
}
|
}
|
||||||
if (this.segmentIsNew(nextProps.segment)) {
|
if (this.segmentIsNew(nextProps.segment)) {
|
||||||
if (nextProps.segment.length > 0) {
|
if (nextProps.segment.length > 0) {
|
||||||
// Set segmented domain
|
// Set segmented domain
|
||||||
this.view.signal("segment", nextProps.segment);
|
this.view.signal('segment', nextProps.segment);
|
||||||
} else {
|
} else {
|
||||||
// Reset segment to full domain
|
// Reset segment to full domain
|
||||||
this.view.signal("segment", 0);
|
this.view.signal('segment', 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.view.runAsync();
|
this.view.runAsync();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(oldProps, oldState) {
|
componentDidUpdate(oldProps, oldState) {
|
||||||
if (this.view) {
|
if (this.view) {
|
||||||
if (this.props.segment.length > 0) {
|
if (this.props.segment.length > 0) {
|
||||||
// Set segmented domain
|
// Set segmented domain
|
||||||
this.view.signal("segment", this.props.segment);
|
this.view.signal('segment', this.props.segment);
|
||||||
} else {
|
} else {
|
||||||
// Reset segment to full domain
|
// Reset segment to full domain
|
||||||
this.view.signal("segment", 0);
|
this.view.signal('segment', 0);
|
||||||
}
|
}
|
||||||
this.view.signal("videoTime", this.props.currentTime);
|
this.view.signal('videoTime', this.props.currentTime);
|
||||||
this.view.runAsync();
|
this.view.runAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,9 +243,9 @@ export default class CanGraph extends Component {
|
||||||
this.onPlotResize();
|
this.onPlotResize();
|
||||||
}
|
}
|
||||||
if (this.props.segment.length > 0) {
|
if (this.props.segment.length > 0) {
|
||||||
view.signal("segment", this.props.segment);
|
view.signal('segment', this.props.segment);
|
||||||
}
|
}
|
||||||
view.signal("videoTime", this.props.currentTime);
|
view.signal('videoTime', this.props.currentTime);
|
||||||
|
|
||||||
this.insertData();
|
this.insertData();
|
||||||
}
|
}
|
||||||
|
@ -319,7 +321,7 @@ export default class CanGraph extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { plotInnerStyle } = this.state;
|
const { plotInnerStyle } = this.state;
|
||||||
const canReceiveDropClass = this.props.canReceiveGraphDrop
|
const canReceiveDropClass = this.props.canReceiveGraphDrop
|
||||||
? "is-droppable"
|
? 'is-droppable'
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -329,7 +331,7 @@ export default class CanGraph extends Component {
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
"cabana-explorer-visuals-plot-inner",
|
'cabana-explorer-visuals-plot-inner',
|
||||||
canReceiveDropClass
|
canReceiveDropClass
|
||||||
)}
|
)}
|
||||||
style={plotInnerStyle || null}
|
style={plotInnerStyle || null}
|
||||||
|
@ -344,13 +346,13 @@ export default class CanGraph extends Component {
|
||||||
({ messageId, signalUid, messageName }) => {
|
({ messageId, signalUid, messageName }) => {
|
||||||
const signal = Object.values(
|
const signal = Object.values(
|
||||||
this.props.messages[messageId].frame.signals
|
this.props.messages[messageId].frame.signals
|
||||||
).find(s => s.uid === signalUid);
|
).find((s) => s.uid === signalUid);
|
||||||
const { colors } = signal;
|
const { colors } = signal;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="cabana-explorer-visuals-plot-header"
|
className="cabana-explorer-visuals-plot-header"
|
||||||
key={messageId + "_" + signal.uid}
|
key={`${messageId}_${signal.uid}`}
|
||||||
>
|
>
|
||||||
<div className="cabana-explorer-visuals-plot-header-toggle">
|
<div className="cabana-explorer-visuals-plot-header-toggle">
|
||||||
<button
|
<button
|
||||||
|
@ -377,29 +379,27 @@ export default class CanGraph extends Component {
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
<Measure bounds onResize={this.onPlotResize}>
|
<Measure bounds onResize={this.onPlotResize}>
|
||||||
{({ measureRef }) => {
|
{({ measureRef }) => (
|
||||||
return (
|
<div
|
||||||
<div
|
ref={measureRef}
|
||||||
ref={measureRef}
|
className="cabana-explorer-visuals-plot-container"
|
||||||
className="cabana-explorer-visuals-plot-container"
|
>
|
||||||
>
|
<Vega
|
||||||
<Vega
|
onNewView={this.onNewView}
|
||||||
onNewView={this.onNewView}
|
logLevel={1}
|
||||||
logLevel={1}
|
signalListeners={{
|
||||||
signalListeners={{
|
clickTime: this.onSignalClickTime,
|
||||||
clickTime: this.onSignalClickTime,
|
segment: this.onSignalSegment
|
||||||
segment: this.onSignalSegment
|
}}
|
||||||
}}
|
renderer="canvas"
|
||||||
renderer={"canvas"}
|
spec={this.state.spec}
|
||||||
spec={this.state.spec}
|
actions={false}
|
||||||
actions={false}
|
data={{
|
||||||
data={{
|
table: this.state.data.series
|
||||||
table: this.state.data.series
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
)}
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Measure>
|
</Measure>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import CanGraph from "./CanGraph";
|
import CanGraph from './CanGraph';
|
||||||
|
|
||||||
require("element-closest");
|
require('element-closest');
|
||||||
|
|
||||||
export default class CanGraphList extends Component {
|
export default class CanGraphList extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -46,9 +46,8 @@ export default class CanGraphList extends Component {
|
||||||
determineDraggingGraph() {
|
determineDraggingGraph() {
|
||||||
const { draggingSignal } = this.state;
|
const { draggingSignal } = this.state;
|
||||||
return this.plotRefs.find(
|
return this.plotRefs.find(
|
||||||
({ messageId, signalUid }) =>
|
({ messageId, signalUid }) => draggingSignal.messageId === messageId
|
||||||
draggingSignal.messageId === messageId &&
|
&& draggingSignal.signalUid === signalUid
|
||||||
draggingSignal.signalUid === signalUid
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,13 +65,12 @@ export default class CanGraphList extends Component {
|
||||||
draggingGraph.ref.hidden = true;
|
draggingGraph.ref.hidden = true;
|
||||||
const ele = document.elementFromPoint(e.clientX, e.clientY);
|
const ele = document.elementFromPoint(e.clientX, e.clientY);
|
||||||
draggingGraph.ref.hidden = false;
|
draggingGraph.ref.hidden = false;
|
||||||
const closestPlot = ele.closest(".cabana-explorer-visuals-plot");
|
const closestPlot = ele.closest('.cabana-explorer-visuals-plot');
|
||||||
const closestPlotRef = this.plotRefs.find(
|
const closestPlotRef = this.plotRefs.find(
|
||||||
({ ref, messageId, signalUid }) =>
|
({ ref, messageId, signalUid }) => !(
|
||||||
!(
|
messageId === draggingGraph.messageId
|
||||||
messageId === draggingGraph.messageId &&
|
&& signalUid === draggingGraph.signalUid
|
||||||
signalUid === draggingGraph.signalUid
|
) && ref.isEqualNode(closestPlot)
|
||||||
) && ref.isEqualNode(closestPlot)
|
|
||||||
);
|
);
|
||||||
if (closestPlotRef) {
|
if (closestPlotRef) {
|
||||||
this.setState({ graphToReceiveDrop: closestPlotRef });
|
this.setState({ graphToReceiveDrop: closestPlotRef });
|
||||||
|
@ -107,7 +105,7 @@ export default class CanGraphList extends Component {
|
||||||
let { plotRefs } = this;
|
let { plotRefs } = this;
|
||||||
plotRefs = plotRefs
|
plotRefs = plotRefs
|
||||||
.filter(
|
.filter(
|
||||||
ref => !(ref.messageId === messageId && ref.signalUid === signalUid)
|
(ref) => !(ref.messageId === messageId && ref.signalUid === signalUid)
|
||||||
)
|
)
|
||||||
.concat([{ messageId, signalUid, ref }]);
|
.concat([{ messageId, signalUid, ref }]);
|
||||||
this.plotRefs = plotRefs;
|
this.plotRefs = plotRefs;
|
||||||
|
@ -119,33 +117,29 @@ export default class CanGraphList extends Component {
|
||||||
const { messageId, signalUid } = plottedSignals[0];
|
const { messageId, signalUid } = plottedSignals[0];
|
||||||
const msg = this.props.messages[messageId];
|
const msg = this.props.messages[messageId];
|
||||||
const signal = Object.values(msg.frame.signals).find(
|
const signal = Object.values(msg.frame.signals).find(
|
||||||
s => s.uid === signalUid
|
(s) => s.uid === signalUid
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!this.plotListRef) {
|
if (!this.plotListRef) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const isDragging =
|
const isDragging = draggingSignal.signalUid === signalUid
|
||||||
draggingSignal.signalUid === signalUid &&
|
&& draggingSignal.messageId === messageId;
|
||||||
draggingSignal.messageId === messageId;
|
const canReceiveGraphDrop = graphToReceiveDrop
|
||||||
const canReceiveGraphDrop =
|
&& graphToReceiveDrop.signalUid === signalUid
|
||||||
graphToReceiveDrop &&
|
&& graphToReceiveDrop.messageId === messageId;
|
||||||
graphToReceiveDrop.signalUid === signalUid &&
|
plottedSignals = plottedSignals.map((plottedSignal) => ({
|
||||||
graphToReceiveDrop.messageId === messageId;
|
messageName: this.props.messages[plottedSignal.messageId].frame.name,
|
||||||
plottedSignals = plottedSignals.map(plottedSignal => {
|
...plottedSignal
|
||||||
return {
|
}));
|
||||||
messageName: this.props.messages[plottedSignal.messageId].frame.name,
|
|
||||||
...plottedSignal
|
|
||||||
};
|
|
||||||
});
|
|
||||||
const key = plottedSignals.reduce(
|
const key = plottedSignals.reduce(
|
||||||
(key, { messageId, signalUid }) => key + messageId + "_" + signalUid,
|
(key, { messageId, signalUid }) => `${key + messageId}_${signalUid}`,
|
||||||
""
|
''
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<CanGraph
|
<CanGraph
|
||||||
onGraphRefAvailable={ref => {
|
onGraphRefAvailable={(ref) => {
|
||||||
this.addCanGraphRef(ref, messageId, signalUid);
|
this.addCanGraphRef(ref, messageId, signalUid);
|
||||||
}}
|
}}
|
||||||
key={key}
|
key={key}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import ReactList from "react-list";
|
import ReactList from 'react-list';
|
||||||
|
|
||||||
import cx from "classnames";
|
import cx from 'classnames';
|
||||||
|
|
||||||
export default class CanLog extends Component {
|
export default class CanLog extends Component {
|
||||||
static ITEMS_PER_PAGE = 50;
|
static ITEMS_PER_PAGE = 50;
|
||||||
|
@ -52,21 +52,20 @@ export default class CanLog extends Component {
|
||||||
? nextProps.message.entries.length
|
? nextProps.message.entries.length
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
const shouldUpdate =
|
const shouldUpdate = this.props.message !== nextProps.message
|
||||||
this.props.message !== nextProps.message ||
|
|| nextMessageLength !== curMessageLength
|
||||||
nextMessageLength !== curMessageLength ||
|
|| nextProps.messageIndex !== this.props.messageIndex
|
||||||
nextProps.messageIndex !== this.props.messageIndex ||
|
|| nextProps.plottedSignals.length !== this.props.plottedSignals.length
|
||||||
nextProps.plottedSignals.length !== this.props.plottedSignals.length ||
|
|| JSON.stringify(nextProps.segmentIndices)
|
||||||
JSON.stringify(nextProps.segmentIndices) !==
|
!== JSON.stringify(this.props.segmentIndices)
|
||||||
JSON.stringify(this.props.segmentIndices) ||
|
|| JSON.stringify(nextState) !== JSON.stringify(this.state)
|
||||||
JSON.stringify(nextState) !== JSON.stringify(this.state) ||
|
|| this.props.message !== nextProps.message
|
||||||
this.props.message !== nextProps.message ||
|
|| (this.props.message !== undefined
|
||||||
(this.props.message !== undefined &&
|
&& nextProps.message !== undefined
|
||||||
nextProps.message !== undefined &&
|
&& this.props.message.frame !== undefined
|
||||||
this.props.message.frame !== undefined &&
|
&& nextProps.message.frame !== undefined
|
||||||
nextProps.message.frame !== undefined &&
|
&& JSON.stringify(this.props.message.frame)
|
||||||
JSON.stringify(this.props.message.frame) !==
|
!== JSON.stringify(nextProps.message.frame));
|
||||||
JSON.stringify(nextProps.message.frame));
|
|
||||||
|
|
||||||
return shouldUpdate;
|
return shouldUpdate;
|
||||||
}
|
}
|
||||||
|
@ -88,24 +87,23 @@ export default class CanLog extends Component {
|
||||||
collapseMessage(msg, msgIdx) {
|
collapseMessage(msg, msgIdx) {
|
||||||
this.setState({
|
this.setState({
|
||||||
expandedMessages: this.state.expandedMessages.filter(
|
expandedMessages: this.state.expandedMessages.filter(
|
||||||
expMsgTime => expMsgTime !== msg.time
|
(expMsgTime) => expMsgTime !== msg.time
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
isSignalPlotted(msgId, signalUid) {
|
isSignalPlotted(msgId, signalUid) {
|
||||||
const plottedSignal = this.props.plottedSignals.find(plot =>
|
const plottedSignal = this.props.plottedSignals.find((plot) => plot.some(
|
||||||
plot.some(
|
(signal) => signal.messageId === msgId && signal.signalUid === signalUid
|
||||||
signal => signal.messageId === msgId && signal.signalUid === signalUid
|
));
|
||||||
)
|
|
||||||
);
|
|
||||||
return plottedSignal !== undefined;
|
return plottedSignal !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
signalValuePretty(signal, value) {
|
signalValuePretty(signal, value) {
|
||||||
if (signal.isFloat) {
|
if (signal.isFloat) {
|
||||||
return value.toFixed(3);
|
return value.toFixed(3);
|
||||||
} else return value;
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
isMessageExpanded(msg) {
|
isMessageExpanded(msg) {
|
||||||
|
@ -124,15 +122,13 @@ export default class CanLog extends Component {
|
||||||
if (!this.props.message.frame) {
|
if (!this.props.message.frame) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const msgIsExpanded =
|
const msgIsExpanded = this.state.allPacketsExpanded || this.isMessageExpanded(msgEntry);
|
||||||
this.state.allPacketsExpanded || this.isMessageExpanded(msgEntry);
|
|
||||||
|
|
||||||
const msgHasSignals =
|
const msgHasSignals = Object.keys(this.props.message.frame.signals).length > 0;
|
||||||
Object.keys(this.props.message.frame.signals).length > 0;
|
|
||||||
if (msgIsExpanded && msgHasSignals) {
|
if (msgIsExpanded && msgHasSignals) {
|
||||||
this.setState({
|
this.setState({
|
||||||
expandedMessages: this.state.expandedMessages.filter(
|
expandedMessages: this.state.expandedMessages.filter(
|
||||||
expMsgTime => expMsgTime !== msgEntry.time
|
(expMsgTime) => expMsgTime !== msgEntry.time
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
} else if (msgHasSignals) {
|
} else if (msgHasSignals) {
|
||||||
|
@ -141,7 +137,6 @@ export default class CanLog extends Component {
|
||||||
});
|
});
|
||||||
this.props.onMessageExpanded();
|
this.props.onMessageExpanded();
|
||||||
} else {
|
} else {
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,10 +150,10 @@ export default class CanLog extends Component {
|
||||||
// Signal removed?
|
// Signal removed?
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const unit = signal.unit.length > 0 ? signal.unit : "units";
|
const unit = signal.unit.length > 0 ? signal.unit : 'units';
|
||||||
const isPlotted = this.isSignalPlotted(message.id, signal.uid);
|
const isPlotted = this.isSignalPlotted(message.id, signal.uid);
|
||||||
const plottedButtonClass = isPlotted ? null : "button--alpha";
|
const plottedButtonClass = isPlotted ? null : 'button--alpha';
|
||||||
const plottedButtonText = isPlotted ? "Hide Plot" : "Show Plot";
|
const plottedButtonText = isPlotted ? 'Hide Plot' : 'Show Plot';
|
||||||
return (
|
return (
|
||||||
<div key={name} className="signals-log-list-signal">
|
<div key={name} className="signals-log-list-signal">
|
||||||
<div className="signals-log-list-signal-message">
|
<div className="signals-log-list-signal-message">
|
||||||
|
@ -166,8 +161,11 @@ export default class CanLog extends Component {
|
||||||
</div>
|
</div>
|
||||||
<div className="signals-log-list-signal-value">
|
<div className="signals-log-list-signal-value">
|
||||||
<span>
|
<span>
|
||||||
(<strong>{this.signalValuePretty(signal, value)}</strong>{" "}
|
(
|
||||||
{unit})
|
<strong>{this.signalValuePretty(signal, value)}</strong>
|
||||||
|
{' '}
|
||||||
|
{unit}
|
||||||
|
)
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
@ -176,7 +174,7 @@ export default class CanLog extends Component {
|
||||||
this.toggleSignalPlot(message.id, signal.uid, isPlotted);
|
this.toggleSignalPlot(message.id, signal.uid, isPlotted);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<button className={cx("button--tiny", plottedButtonClass)}>
|
<button className={cx('button--tiny', plottedButtonClass)}>
|
||||||
<span>{plottedButtonText}</span>
|
<span>{plottedButtonText}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -189,15 +187,14 @@ export default class CanLog extends Component {
|
||||||
|
|
||||||
renderLogListItemMessage(msgEntry, key) {
|
renderLogListItemMessage(msgEntry, key) {
|
||||||
const { message } = this.props;
|
const { message } = this.props;
|
||||||
const msgIsExpanded =
|
const msgIsExpanded = this.state.allPacketsExpanded || this.isMessageExpanded(msgEntry);
|
||||||
this.state.allPacketsExpanded || this.isMessageExpanded(msgEntry);
|
|
||||||
const msgHasSignals = Object.keys(msgEntry.signals).length > 0;
|
const msgHasSignals = Object.keys(msgEntry.signals).length > 0;
|
||||||
const hasSignalsClass = msgHasSignals ? "has-signals" : null;
|
const hasSignalsClass = msgHasSignals ? 'has-signals' : null;
|
||||||
const expandedClass = msgIsExpanded ? "is-expanded" : null;
|
const expandedClass = msgIsExpanded ? 'is-expanded' : null;
|
||||||
const row = (
|
const row = (
|
||||||
<div
|
<div
|
||||||
key={key}
|
key={key}
|
||||||
className={cx("signals-log-list-item", hasSignalsClass, expandedClass)}
|
className={cx('signals-log-list-item', hasSignalsClass, expandedClass)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="signals-log-list-item-header"
|
className="signals-log-list-item-header"
|
||||||
|
@ -211,7 +208,11 @@ export default class CanLog extends Component {
|
||||||
</strong>
|
</strong>
|
||||||
</div>
|
</div>
|
||||||
<div className="signals-log-list-time">
|
<div className="signals-log-list-time">
|
||||||
<span>[{msgEntry.relTime.toFixed(3)}]</span>
|
<span>
|
||||||
|
[
|
||||||
|
{msgEntry.relTime.toFixed(3)}
|
||||||
|
]
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="signals-log-list-bytes">
|
<div className="signals-log-list-bytes">
|
||||||
<span className="t-mono">{msgEntry.hexData}</span>
|
<span className="t-mono">{msgEntry.hexData}</span>
|
||||||
|
@ -239,9 +240,8 @@ export default class CanLog extends Component {
|
||||||
this.props.message.entries[offset + index],
|
this.props.message.entries[offset + index],
|
||||||
key
|
key
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLogList(items, ref) {
|
renderLogList(items, ref) {
|
||||||
|
@ -263,14 +263,15 @@ export default class CanLog extends Component {
|
||||||
const { segmentIndices, messageIndex } = this.props;
|
const { segmentIndices, messageIndex } = this.props;
|
||||||
if (messageIndex > 0) {
|
if (messageIndex > 0) {
|
||||||
return this.props.message.entries.length - messageIndex;
|
return this.props.message.entries.length - messageIndex;
|
||||||
} else if (segmentIndices.length === 2) {
|
|
||||||
return segmentIndices[1] - segmentIndices[0];
|
|
||||||
} else if (this.props.message) {
|
|
||||||
return this.props.message.entries.length;
|
|
||||||
} else {
|
|
||||||
// no message yet
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
if (segmentIndices.length === 2) {
|
||||||
|
return segmentIndices[1] - segmentIndices[0];
|
||||||
|
}
|
||||||
|
if (this.props.message) {
|
||||||
|
return this.props.message.entries.length;
|
||||||
|
}
|
||||||
|
// no message yet
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
onExpandAllChanged(e) {
|
onExpandAllChanged(e) {
|
||||||
|
@ -282,16 +283,18 @@ export default class CanLog extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let expandAllText = this.state.allPacketsExpanded
|
const expandAllText = this.state.allPacketsExpanded
|
||||||
? "Collapse All"
|
? 'Collapse All'
|
||||||
: "Expand All";
|
: 'Expand All';
|
||||||
let expandAllClass = this.state.allPacketsExpanded ? null : "button--alpha";
|
const expandAllClass = this.state.allPacketsExpanded
|
||||||
|
? null
|
||||||
|
: 'button--alpha';
|
||||||
return (
|
return (
|
||||||
<div className="cabana-explorer-signals-log">
|
<div className="cabana-explorer-signals-log">
|
||||||
<div className="cabana-explorer-signals-log-header">
|
<div className="cabana-explorer-signals-log-header">
|
||||||
<strong>Message Packets</strong>
|
<strong>Message Packets</strong>
|
||||||
<button
|
<button
|
||||||
className={cx("button--tiny", expandAllClass)}
|
className={cx('button--tiny', expandAllClass)}
|
||||||
onClick={this.toggleExpandAllPackets}
|
onClick={this.toggleExpandAllPackets}
|
||||||
>
|
>
|
||||||
{expandAllText}
|
{expandAllText}
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
export default class DbcUpload extends Component {
|
export default class DbcUpload extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
onDbcLoaded: PropTypes.func
|
onDbcLoaded: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
dbcText: ""
|
dbcText: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
this.onTextChanged = this.onTextChanged.bind(this);
|
this.onTextChanged = this.onTextChanged.bind(this);
|
||||||
|
@ -17,7 +18,7 @@ export default class DbcUpload extends Component {
|
||||||
onTextChanged(e) {
|
onTextChanged(e) {
|
||||||
const dbcText = e.target.value;
|
const dbcText = e.target.value;
|
||||||
this.setState({ dbcText });
|
this.setState({ dbcText });
|
||||||
this.props.onDbcLoaded("from paste", dbcText);
|
this.props.onDbcLoaded('from paste', dbcText);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import Modal from "./Modals/baseModal";
|
import Modal from './Modals/baseModal';
|
||||||
|
|
||||||
export default class EditMessageModal extends Component {
|
export default class EditMessageModal extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -32,9 +32,7 @@ export default class EditMessageModal extends Component {
|
||||||
this.setState({ messageFrame });
|
this.setState({ messageFrame });
|
||||||
}
|
}
|
||||||
|
|
||||||
editTransmitter(transmitter) {
|
editTransmitter(transmitter) {}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderActions() {
|
renderActions() {
|
||||||
return (
|
return (
|
||||||
|
@ -67,7 +65,7 @@ export default class EditMessageModal extends Component {
|
||||||
type="text"
|
type="text"
|
||||||
id="message_name"
|
id="message_name"
|
||||||
value={this.state.messageFrame.name}
|
value={this.state.messageFrame.name}
|
||||||
onChange={e => {
|
onChange={(e) => {
|
||||||
const { messageFrame } = this.state;
|
const { messageFrame } = this.state;
|
||||||
messageFrame.name = e.target.value;
|
messageFrame.name = e.target.value;
|
||||||
this.setState({ messageFrame });
|
this.setState({ messageFrame });
|
||||||
|
@ -83,7 +81,7 @@ export default class EditMessageModal extends Component {
|
||||||
type="number"
|
type="number"
|
||||||
id="message_size"
|
id="message_size"
|
||||||
value={this.state.messageFrame.size}
|
value={this.state.messageFrame.size}
|
||||||
onChange={e => {
|
onChange={(e) => {
|
||||||
const { messageFrame } = this.state;
|
const { messageFrame } = this.state;
|
||||||
if (e.target.value > 8) {
|
if (e.target.value > 8) {
|
||||||
return;
|
return;
|
||||||
|
@ -102,23 +100,21 @@ export default class EditMessageModal extends Component {
|
||||||
</label>
|
</label>
|
||||||
<div className="form-field-inset">
|
<div className="form-field-inset">
|
||||||
<ul className="form-field-inset-list">
|
<ul className="form-field-inset-list">
|
||||||
{this.state.messageFrame.transmitters.map(transmitter => {
|
{this.state.messageFrame.transmitters.map((transmitter) => (
|
||||||
return (
|
<li className="form-field-inset-list-item" key={transmitter}>
|
||||||
<li className="form-field-inset-list-item" key={transmitter}>
|
<div className="form-field-inset-list-item-title">
|
||||||
<div className="form-field-inset-list-item-title">
|
<span>{transmitter}</span>
|
||||||
<span>{transmitter}</span>
|
</div>
|
||||||
</div>
|
<div className="form-field-inset-list-item-action">
|
||||||
<div className="form-field-inset-list-item-action">
|
<button className="button--tiny button--alpha">Edit</button>
|
||||||
<button className="button--tiny button--alpha">
|
</div>
|
||||||
Edit
|
</li>
|
||||||
</button>
|
))}
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<button className="button--tiny button--alpha">
|
<button className="button--tiny button--alpha">
|
||||||
<span>
|
<span>
|
||||||
<i className="fa fa-plus" /> Add Transmitter
|
<i className="fa fa-plus" />
|
||||||
|
{' '}
|
||||||
|
Add Transmitter
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import cx from "classnames";
|
import cx from 'classnames';
|
||||||
|
|
||||||
import AddSignals from "./AddSignals";
|
import AddSignals from './AddSignals';
|
||||||
import CanGraphList from "./CanGraphList";
|
import CanGraphList from './CanGraphList';
|
||||||
import RouteVideoSync from "./RouteVideoSync";
|
import RouteVideoSync from './RouteVideoSync';
|
||||||
import CanLog from "./CanLog";
|
import CanLog from './CanLog';
|
||||||
import Entries from "../models/can/entries";
|
import Entries from '../models/can/entries';
|
||||||
import debounce from "../utils/debounce";
|
import debounce from '../utils/debounce';
|
||||||
import PartSelector from "./PartSelector";
|
import PartSelector from './PartSelector';
|
||||||
import PlaySpeedSelector from "./PlaySpeedSelector";
|
import PlaySpeedSelector from './PlaySpeedSelector';
|
||||||
|
|
||||||
export default class Explorer extends Component {
|
export default class Explorer extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -66,20 +66,20 @@ export default class Explorer extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
document.addEventListener("keydown", this._onKeyDown);
|
document.addEventListener('keydown', this._onKeyDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
document.removeEventListener("keydown", this._onKeyDown);
|
document.removeEventListener('keydown', this._onKeyDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
clipSegment(segment, segmentIndices, nextMessage) {
|
clipSegment(segment, segmentIndices, nextMessage) {
|
||||||
if (segment.length === 2) {
|
if (segment.length === 2) {
|
||||||
const segmentStartIdx = nextMessage.entries.findIndex(
|
const segmentStartIdx = nextMessage.entries.findIndex(
|
||||||
e => e.relTime >= segment[0]
|
(e) => e.relTime >= segment[0]
|
||||||
);
|
);
|
||||||
let segmentEndIdx = nextMessage.entries.findIndex(
|
let segmentEndIdx = nextMessage.entries.findIndex(
|
||||||
e => e.relTime >= segment[1]
|
(e) => e.relTime >= segment[1]
|
||||||
);
|
);
|
||||||
if (segmentStartIdx !== -1) {
|
if (segmentStartIdx !== -1) {
|
||||||
if (segmentEndIdx === -1) {
|
if (segmentEndIdx === -1) {
|
||||||
|
@ -119,32 +119,30 @@ export default class Explorer extends Component {
|
||||||
|
|
||||||
// remove plottedSignals that no longer exist
|
// remove plottedSignals that no longer exist
|
||||||
plottedSignals = plottedSignals
|
plottedSignals = plottedSignals
|
||||||
.map(plot =>
|
.map((plot) => plot.filter(({ messageId, signalUid }, index) => {
|
||||||
plot.filter(({ messageId, signalUid }, index) => {
|
const messageExists = !!nextProps.messages[messageId];
|
||||||
const messageExists = !!nextProps.messages[messageId];
|
let signalExists = true;
|
||||||
let signalExists = true;
|
if (messageExists) {
|
||||||
if (messageExists) {
|
signalExists = Object.values(
|
||||||
signalExists = Object.values(
|
nextProps.messages[messageId].frame.signals
|
||||||
nextProps.messages[messageId].frame.signals
|
).some((signal) => signal.uid === signalUid);
|
||||||
).some(signal => signal.uid === signalUid);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return messageExists && signalExists;
|
return messageExists && signalExists;
|
||||||
})
|
}))
|
||||||
)
|
.filter((plot) => plot.length > 0);
|
||||||
.filter(plot => plot.length > 0);
|
|
||||||
|
|
||||||
this.setState({ plottedSignals });
|
this.setState({ plottedSignals });
|
||||||
|
|
||||||
if (
|
if (
|
||||||
nextProps.selectedMessage &&
|
nextProps.selectedMessage
|
||||||
nextProps.selectedMessage !== this.props.selectedMessage
|
&& nextProps.selectedMessage !== this.props.selectedMessage
|
||||||
) {
|
) {
|
||||||
// Update segment and seek state
|
// Update segment and seek state
|
||||||
// by finding a entry indices
|
// by finding a entry indices
|
||||||
// corresponding to old message segment/seek times.
|
// corresponding to old message segment/seek times.
|
||||||
|
|
||||||
let { segment, segmentIndices } = this.clipSegment(
|
const { segment, segmentIndices } = this.clipSegment(
|
||||||
this.state.segment,
|
this.state.segment,
|
||||||
this.state.segmentIndices,
|
this.state.segmentIndices,
|
||||||
nextMessage
|
nextMessage
|
||||||
|
@ -169,11 +167,11 @@ export default class Explorer extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
nextMessage &&
|
nextMessage
|
||||||
curMessage &&
|
&& curMessage
|
||||||
nextMessage.entries.length !== curMessage.entries.length
|
&& nextMessage.entries.length !== curMessage.entries.length
|
||||||
) {
|
) {
|
||||||
let { segment, segmentIndices } = this.clipSegment(
|
const { segment, segmentIndices } = this.clipSegment(
|
||||||
this.state.segment,
|
this.state.segment,
|
||||||
this.state.segmentIndices,
|
this.state.segmentIndices,
|
||||||
nextMessage
|
nextMessage
|
||||||
|
@ -193,20 +191,21 @@ export default class Explorer extends Component {
|
||||||
const { routeStartTime, currentParts } = this.props;
|
const { routeStartTime, currentParts } = this.props;
|
||||||
|
|
||||||
if (routeStartTime) {
|
if (routeStartTime) {
|
||||||
const partStartOffset = currentParts[0] * 60,
|
const partStartOffset = currentParts[0] * 60;
|
||||||
partEndOffset = (currentParts[1] + 1) * 60;
|
const partEndOffset = (currentParts[1] + 1) * 60;
|
||||||
|
|
||||||
const windowStartTime = routeStartTime
|
const windowStartTime = routeStartTime
|
||||||
.clone()
|
.clone()
|
||||||
.add(partStartOffset, "s")
|
.add(partStartOffset, 's')
|
||||||
.format("HH:mm:ss");
|
.format('HH:mm:ss');
|
||||||
const windowEndTime = routeStartTime
|
const windowEndTime = routeStartTime
|
||||||
.clone()
|
.clone()
|
||||||
.add(partEndOffset, "s")
|
.add(partEndOffset, 's')
|
||||||
.format("HH:mm:ss");
|
.format('HH:mm:ss');
|
||||||
|
|
||||||
return `${windowStartTime} - ${windowEndTime}`;
|
return `${windowStartTime} - ${windowEndTime}`;
|
||||||
} else return "";
|
}
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignalPlotPressed(messageId, signalUid) {
|
onSignalPlotPressed(messageId, signalUid) {
|
||||||
|
@ -220,13 +219,10 @@ export default class Explorer extends Component {
|
||||||
onSignalUnplotPressed(messageId, signalUid) {
|
onSignalUnplotPressed(messageId, signalUid) {
|
||||||
const { plottedSignals } = this.state;
|
const { plottedSignals } = this.state;
|
||||||
const newPlottedSignals = plottedSignals
|
const newPlottedSignals = plottedSignals
|
||||||
.map(plot =>
|
.map((plot) => plot.filter(
|
||||||
plot.filter(
|
(signal) => !(signal.messageId === messageId && signal.signalUid === signalUid)
|
||||||
signal =>
|
))
|
||||||
!(signal.messageId === messageId && signal.signalUid === signalUid)
|
.filter((plot) => plot.length > 0);
|
||||||
)
|
|
||||||
)
|
|
||||||
.filter(plot => plot.length > 0);
|
|
||||||
|
|
||||||
this.setState({ plottedSignals: newPlottedSignals });
|
this.setState({ plottedSignals: newPlottedSignals });
|
||||||
}
|
}
|
||||||
|
@ -237,8 +233,8 @@ export default class Explorer extends Component {
|
||||||
|
|
||||||
// console.log(this.state.segment, '->', segment, segmentIndices);
|
// console.log(this.state.segment, '->', segment, segmentIndices);
|
||||||
if (
|
if (
|
||||||
segment[0] === this.props.currentParts[0] * 60 &&
|
segment[0] === this.props.currentParts[0] * 60
|
||||||
segment[1] === (this.props.currentParts[1] + 1) * 60
|
&& segment[1] === (this.props.currentParts[1] + 1) * 60
|
||||||
) {
|
) {
|
||||||
segment = [];
|
segment = [];
|
||||||
segmentIndices = [];
|
segmentIndices = [];
|
||||||
|
@ -297,14 +293,13 @@ export default class Explorer extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return segmentIndices[1];
|
return segmentIndices[1];
|
||||||
} else {
|
|
||||||
for (let i = 0; i < entries.length; i++) {
|
|
||||||
if (entries[i].relTime >= time) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return entries.length - 1;
|
|
||||||
}
|
}
|
||||||
|
for (let i = 0; i < entries.length; i++) {
|
||||||
|
if (entries[i].relTime >= time) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entries.length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
onUserSeek(time) {
|
onUserSeek(time) {
|
||||||
|
@ -377,24 +372,20 @@ export default class Explorer extends Component {
|
||||||
selectedMessagePlottedSignalUids() {
|
selectedMessagePlottedSignalUids() {
|
||||||
const { plottedSignals } = this.state;
|
const { plottedSignals } = this.state;
|
||||||
return plottedSignals
|
return plottedSignals
|
||||||
.map(plot =>
|
.map((plot) => plot
|
||||||
plot
|
.filter(
|
||||||
.filter(
|
({ messageId, signalUid }) => messageId === this.props.selectedMessage
|
||||||
({ messageId, signalUid }) =>
|
)
|
||||||
messageId === this.props.selectedMessage
|
.map(({ signalUid }) => signalUid))
|
||||||
)
|
|
||||||
.map(({ signalUid }) => signalUid)
|
|
||||||
)
|
|
||||||
.reduce((arr, signalUid) => arr.concat(signalUid), []);
|
.reduce((arr, signalUid) => arr.concat(signalUid), []);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderExplorerSignals() {
|
renderExplorerSignals() {
|
||||||
const selectedMessageKey = this.props.selectedMessage;
|
const selectedMessageKey = this.props.selectedMessage;
|
||||||
const selectedMessage = this.props.messages[selectedMessageKey];
|
const selectedMessage = this.props.messages[selectedMessageKey];
|
||||||
const selectedMessageName =
|
const selectedMessageName = selectedMessage.frame !== undefined
|
||||||
selectedMessage.frame !== undefined
|
? selectedMessage.frame.name
|
||||||
? selectedMessage.frame.name
|
: 'undefined';
|
||||||
: "undefined";
|
|
||||||
return (
|
return (
|
||||||
<div className="cabana-explorer-signals-wrapper">
|
<div className="cabana-explorer-signals-wrapper">
|
||||||
<div className="cabana-explorer-signals-header">
|
<div className="cabana-explorer-signals-header">
|
||||||
|
@ -405,9 +396,7 @@ export default class Explorer extends Component {
|
||||||
<div className="cabana-explorer-signals-header-action">
|
<div className="cabana-explorer-signals-header-action">
|
||||||
<button
|
<button
|
||||||
className="button--small"
|
className="button--small"
|
||||||
onClick={() =>
|
onClick={() => this.props.showEditMessageModal(selectedMessageKey)}
|
||||||
this.props.showEditMessageModal(selectedMessageKey)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
Edit
|
Edit
|
||||||
</button>
|
</button>
|
||||||
|
@ -448,25 +437,19 @@ export default class Explorer extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
mergePlots({ fromPlot, toPlot }) {
|
mergePlots({ fromPlot, toPlot }) {
|
||||||
let { plottedSignals } = this.state;
|
const { plottedSignals } = this.state;
|
||||||
|
|
||||||
// remove fromPlot from plottedSignals
|
// remove fromPlot from plottedSignals
|
||||||
const fromPlotIdx = plottedSignals.findIndex(plot =>
|
const fromPlotIdx = plottedSignals.findIndex((plot) => plot.some(
|
||||||
plot.some(
|
(signal) => signal.signalUid === fromPlot.signalUid
|
||||||
signal =>
|
&& signal.messageId === fromPlot.messageId
|
||||||
signal.signalUid === fromPlot.signalUid &&
|
));
|
||||||
signal.messageId === fromPlot.messageId
|
|
||||||
)
|
|
||||||
);
|
|
||||||
plottedSignals.splice(fromPlotIdx, 1);
|
plottedSignals.splice(fromPlotIdx, 1);
|
||||||
|
|
||||||
const toPlotIdx = plottedSignals.findIndex(plot =>
|
const toPlotIdx = plottedSignals.findIndex((plot) => plot.some(
|
||||||
plot.some(
|
(signal) => signal.signalUid === toPlot.signalUid
|
||||||
signal =>
|
&& signal.messageId === toPlot.messageId
|
||||||
signal.signalUid === toPlot.signalUid &&
|
));
|
||||||
signal.messageId === toPlot.messageId
|
|
||||||
)
|
|
||||||
);
|
|
||||||
plottedSignals[toPlotIdx] = [fromPlot, toPlot];
|
plottedSignals[toPlotIdx] = [fromPlot, toPlot];
|
||||||
|
|
||||||
this.setState({ plottedSignals });
|
this.setState({ plottedSignals });
|
||||||
|
@ -474,7 +457,7 @@ export default class Explorer extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const signalsExpandedClass = this.state.shouldShowAddSignal
|
const signalsExpandedClass = this.state.shouldShowAddSignal
|
||||||
? "is-expanded"
|
? 'is-expanded'
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
let graphSegment = this.state.segment;
|
let graphSegment = this.state.segment;
|
||||||
|
@ -487,7 +470,7 @@ export default class Explorer extends Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="cabana-explorer">
|
<div className="cabana-explorer">
|
||||||
<div className={cx("cabana-explorer-signals", signalsExpandedClass)}>
|
<div className={cx('cabana-explorer-signals', signalsExpandedClass)}>
|
||||||
{this.props.messages[this.props.selectedMessage]
|
{this.props.messages[this.props.selectedMessage]
|
||||||
? this.renderExplorerSignals()
|
? this.renderExplorerSignals()
|
||||||
: this.renderSelectMessagePrompt()}
|
: this.renderSelectMessagePrompt()}
|
||||||
|
@ -522,7 +505,7 @@ export default class Explorer extends Component {
|
||||||
) : null}
|
) : null}
|
||||||
{this.state.segment.length > 0 ? (
|
{this.state.segment.length > 0 ? (
|
||||||
<div
|
<div
|
||||||
className={"cabana-explorer-visuals-segmentreset"}
|
className="cabana-explorer-visuals-segmentreset"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.resetSegment();
|
this.resetSegment();
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import cx from "classnames";
|
import cx from 'classnames';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import OpenDbc from "../api/OpenDbc";
|
import OpenDbc from '../api/OpenDbc';
|
||||||
|
|
||||||
export default class GithubDbcList extends Component {
|
export default class GithubDbcList extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -17,7 +17,7 @@ export default class GithubDbcList extends Component {
|
||||||
this.state = {
|
this.state = {
|
||||||
paths: [],
|
paths: [],
|
||||||
selectedPath: null,
|
selectedPath: null,
|
||||||
pathQuery: ""
|
pathQuery: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updatePathQuery = this.updatePathQuery.bind(this);
|
this.updatePathQuery = this.updatePathQuery.bind(this);
|
||||||
|
@ -25,15 +25,15 @@ export default class GithubDbcList extends Component {
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (nextProps.repo !== this.props.repo) {
|
if (nextProps.repo !== this.props.repo) {
|
||||||
this.props.openDbcClient.list(nextProps.repo).then(paths => {
|
this.props.openDbcClient.list(nextProps.repo).then((paths) => {
|
||||||
this.setState({ paths, selectedPath: null });
|
this.setState({ paths, selectedPath: null });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.openDbcClient.list(this.props.repo).then(paths => {
|
this.props.openDbcClient.list(this.props.repo).then((paths) => {
|
||||||
paths = paths.filter(path => path.indexOf(".dbc") !== -1);
|
paths = paths.filter((path) => path.indexOf('.dbc') !== -1);
|
||||||
this.setState({ paths });
|
this.setState({ paths });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ export default class GithubDbcList extends Component {
|
||||||
this.setState({ selectedPath: path });
|
this.setState({ selectedPath: path });
|
||||||
this.props.openDbcClient
|
this.props.openDbcClient
|
||||||
.getDbcContents(path, this.props.repo)
|
.getDbcContents(path, this.props.repo)
|
||||||
.then(dbcContents => {
|
.then((dbcContents) => {
|
||||||
this.props.onDbcLoaded(path, dbcContents);
|
this.props.onDbcLoaded(path, dbcContents);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -72,24 +72,21 @@ export default class GithubDbcList extends Component {
|
||||||
<div className="cabana-dbc-list-files">
|
<div className="cabana-dbc-list-files">
|
||||||
{this.state.paths
|
{this.state.paths
|
||||||
.filter(
|
.filter(
|
||||||
p =>
|
(p) => (this.state.pathQuery === '') | p.includes(this.state.pathQuery)
|
||||||
(this.state.pathQuery === "") | p.includes(this.state.pathQuery)
|
|
||||||
)
|
)
|
||||||
.map(path => {
|
.map((path) => (
|
||||||
return (
|
<div
|
||||||
<div
|
className={cx('cabana-dbc-list-file', {
|
||||||
className={cx("cabana-dbc-list-file", {
|
'is-selected': this.state.selectedPath === path
|
||||||
"is-selected": this.state.selectedPath === path
|
})}
|
||||||
})}
|
onClick={() => {
|
||||||
onClick={() => {
|
this.selectPath(path);
|
||||||
this.selectPath(path);
|
}}
|
||||||
}}
|
key={path}
|
||||||
key={path}
|
>
|
||||||
>
|
<span>{path}</span>
|
||||||
<span>{path}</span>
|
</div>
|
||||||
</div>
|
))}
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import Hls from "hls.js";
|
import Hls from 'hls.js';
|
||||||
|
|
||||||
export default class HLS extends Component {
|
export default class HLS extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -26,8 +26,8 @@ export default class HLS extends Component {
|
||||||
}
|
}
|
||||||
if (nextProps.playing) {
|
if (nextProps.playing) {
|
||||||
if (
|
if (
|
||||||
this.videoElement &&
|
this.videoElement
|
||||||
(this.videoElement.paused || this.videoElement.currentTime < 0.01)
|
&& (this.videoElement.paused || this.videoElement.currentTime < 0.01)
|
||||||
) {
|
) {
|
||||||
this.videoElement.play();
|
this.videoElement.play();
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ export default class HLS extends Component {
|
||||||
// legacy outer scope variable. Revisit this to see if putting in state
|
// legacy outer scope variable. Revisit this to see if putting in state
|
||||||
// makes more sense
|
// makes more sense
|
||||||
shouldInitVideoTime = true;
|
shouldInitVideoTime = true;
|
||||||
|
|
||||||
onSeeked = () => {
|
onSeeked = () => {
|
||||||
if (!this.props.playing) {
|
if (!this.props.playing) {
|
||||||
if (this.shouldInitVideoTime) {
|
if (this.shouldInitVideoTime) {
|
||||||
|
@ -84,7 +85,7 @@ export default class HLS extends Component {
|
||||||
onClick={this.props.onClick}
|
onClick={this.props.onClick}
|
||||||
>
|
>
|
||||||
<video
|
<video
|
||||||
ref={video => {
|
ref={(video) => {
|
||||||
this.videoElement = video;
|
this.videoElement = video;
|
||||||
}}
|
}}
|
||||||
autoPlay={this.props.playing}
|
autoPlay={this.props.playing}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import cx from "classnames";
|
import cx from 'classnames';
|
||||||
|
|
||||||
import DBC from "../models/can/dbc";
|
import DBC from '../models/can/dbc';
|
||||||
import OpenDbc from "../api/OpenDbc";
|
import OpenDbc from '../api/OpenDbc';
|
||||||
import Modal from "./Modals/baseModal";
|
import Modal from './Modals/baseModal';
|
||||||
import GithubDbcList from "./GithubDbcList";
|
import GithubDbcList from './GithubDbcList';
|
||||||
import DbcUpload from "./DbcUpload";
|
import DbcUpload from './DbcUpload';
|
||||||
|
|
||||||
export default class LoadDbcModal extends Component {
|
export default class LoadDbcModal extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -19,8 +19,8 @@ export default class LoadDbcModal extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
tab: "OpenDBC",
|
tab: 'OpenDBC',
|
||||||
tabs: ["OpenDBC", "GitHub", "Upload"],
|
tabs: ['OpenDBC', 'GitHub', 'Upload'],
|
||||||
dbc: null,
|
dbc: null,
|
||||||
dbcSource: null,
|
dbcSource: null,
|
||||||
userOpenDbcRepo: null
|
userOpenDbcRepo: null
|
||||||
|
@ -34,7 +34,7 @@ export default class LoadDbcModal extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.openDbcClient.getUserOpenDbcFork().then(userOpenDbcRepo => {
|
this.props.openDbcClient.getUserOpenDbcFork().then((userOpenDbcRepo) => {
|
||||||
this.setState({ userOpenDbcRepo });
|
this.setState({ userOpenDbcRepo });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -54,26 +54,24 @@ export default class LoadDbcModal extends Component {
|
||||||
renderTabNavigation() {
|
renderTabNavigation() {
|
||||||
return (
|
return (
|
||||||
<div className="cabana-tabs-navigation">
|
<div className="cabana-tabs-navigation">
|
||||||
{this.state.tabs.map(tab => {
|
{this.state.tabs.map((tab) => (
|
||||||
return (
|
<a
|
||||||
<a
|
className={cx({ 'is-active': this.state.tab === tab })}
|
||||||
className={cx({ "is-active": this.state.tab === tab })}
|
onClick={() => {
|
||||||
onClick={() => {
|
this.setState({ tab });
|
||||||
this.setState({ tab });
|
}}
|
||||||
}}
|
key={tab}
|
||||||
key={tab}
|
>
|
||||||
>
|
<span>{tab}</span>
|
||||||
<span>{tab}</span>
|
</a>
|
||||||
</a>
|
))}
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTabContent() {
|
renderTabContent() {
|
||||||
const { tab } = this.state;
|
const { tab } = this.state;
|
||||||
if (tab === "OpenDBC") {
|
if (tab === 'OpenDBC') {
|
||||||
return (
|
return (
|
||||||
<GithubDbcList
|
<GithubDbcList
|
||||||
onDbcLoaded={this.onDbcLoaded}
|
onDbcLoaded={this.onDbcLoaded}
|
||||||
|
@ -81,21 +79,23 @@ export default class LoadDbcModal extends Component {
|
||||||
openDbcClient={this.props.openDbcClient}
|
openDbcClient={this.props.openDbcClient}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (tab === "GitHub") {
|
}
|
||||||
|
if (tab === 'GitHub') {
|
||||||
if (!this.props.openDbcClient.hasAuth()) {
|
if (!this.props.openDbcClient.hasAuth()) {
|
||||||
return this.props.loginWithGithub;
|
return this.props.loginWithGithub;
|
||||||
} else if (this.state.userOpenDbcRepo === null) {
|
|
||||||
return <div>Fork it</div>;
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<GithubDbcList
|
|
||||||
onDbcLoaded={this.onDbcLoaded}
|
|
||||||
repo={this.state.userOpenDbcRepo}
|
|
||||||
openDbcClient={this.props.openDbcClient}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else if (tab === "Upload") {
|
if (this.state.userOpenDbcRepo === null) {
|
||||||
|
return <div>Fork it</div>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<GithubDbcList
|
||||||
|
onDbcLoaded={this.onDbcLoaded}
|
||||||
|
repo={this.state.userOpenDbcRepo}
|
||||||
|
openDbcClient={this.props.openDbcClient}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (tab === 'Upload') {
|
||||||
return <DbcUpload onDbcLoaded={this.onDbcLoaded} />;
|
return <DbcUpload onDbcLoaded={this.onDbcLoaded} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import styled, { keyframes } from "react-emotion";
|
import styled, { keyframes } from 'react-emotion';
|
||||||
|
|
||||||
const frames = keyframes`
|
const frames = keyframes`
|
||||||
0% {
|
0% {
|
||||||
|
@ -8,10 +8,10 @@ const frames = keyframes`
|
||||||
transform: translateX(-400px)
|
transform: translateX(-400px)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
const animationColor1 = "rgba(74, 242, 161, 1.00)";
|
const animationColor1 = 'rgba(74, 242, 161, 1.00)';
|
||||||
const animationColor2 = "rgba(140, 169, 197, 1.00)";
|
const animationColor2 = 'rgba(140, 169, 197, 1.00)';
|
||||||
|
|
||||||
export default styled("div")`
|
export default styled('div')`
|
||||||
display: block;
|
display: block;
|
||||||
animation-name: ${frames};
|
animation-name: ${frames};
|
||||||
animation-duration: 2s;
|
animation-duration: 2s;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
export default class MessageBytes extends Component {
|
export default class MessageBytes extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -23,22 +23,20 @@ export default class MessageBytes extends Component {
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
if (nextProps.live) {
|
if (nextProps.live) {
|
||||||
const nextLastEntry =
|
const nextLastEntry = nextProps.message.entries[nextProps.message.entries.length - 1];
|
||||||
nextProps.message.entries[nextProps.message.entries.length - 1];
|
|
||||||
const curLastEntry = this.props.message.entries[
|
const curLastEntry = this.props.message.entries[
|
||||||
this.props.message.entries.length - 1
|
this.props.message.entries.length - 1
|
||||||
];
|
];
|
||||||
|
|
||||||
return nextLastEntry.hexData !== curLastEntry.hexData;
|
return nextLastEntry.hexData !== curLastEntry.hexData;
|
||||||
} else {
|
|
||||||
return nextProps.seekTime !== this.props.seekTime;
|
|
||||||
}
|
}
|
||||||
|
return nextProps.seekTime !== this.props.seekTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (
|
if (
|
||||||
this.props.seekIndex !== nextProps.seekIndex ||
|
this.props.seekIndex !== nextProps.seekIndex
|
||||||
frameForTime(this.props.seekTime) !== frameForTime(nextProps.seekTime)
|
|| frameForTime(this.props.seekTime) !== frameForTime(nextProps.seekTime)
|
||||||
) {
|
) {
|
||||||
this.updateCanvas(nextProps);
|
this.updateCanvas(nextProps);
|
||||||
}
|
}
|
||||||
|
@ -66,7 +64,7 @@ export default class MessageBytes extends Component {
|
||||||
// TODO this can be faster with binary search, not currently a bottleneck though.
|
// TODO this can be faster with binary search, not currently a bottleneck though.
|
||||||
|
|
||||||
mostRecentMessageIndex = message.entries.findIndex(
|
mostRecentMessageIndex = message.entries.findIndex(
|
||||||
e => e.relTime >= seekTime
|
(e) => e.relTime >= seekTime
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +90,7 @@ export default class MessageBytes extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ctx = this.canvas.getContext("2d");
|
const ctx = this.canvas.getContext('2d');
|
||||||
// ctx.clearRect(0, 0, 180, 15);
|
// ctx.clearRect(0, 0, 180, 15);
|
||||||
|
|
||||||
for (let i = 0; i < message.byteStateChangeCounts.length; ++i) {
|
for (let i = 0; i < message.byteStateChangeCounts.length; ++i) {
|
||||||
|
@ -101,12 +99,12 @@ export default class MessageBytes extends Component {
|
||||||
|
|
||||||
ctx.fillRect(i * 20, 0, 20, 15);
|
ctx.fillRect(i * 20, 0, 20, 15);
|
||||||
|
|
||||||
ctx.font = "12px Courier";
|
ctx.font = '12px Courier';
|
||||||
ctx.fillStyle = "white";
|
ctx.fillStyle = 'white';
|
||||||
if (hexData) {
|
if (hexData) {
|
||||||
ctx.fillText(hexData, i * 20 + 2, 12);
|
ctx.fillText(hexData, i * 20 + 2, 12);
|
||||||
} else {
|
} else {
|
||||||
ctx.fillText("-", i * 20 + 7, 12);
|
ctx.fillText('-', i * 20 + 7, 12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,7 +121,7 @@ export default class MessageBytes extends Component {
|
||||||
this.canvas = ref;
|
this.canvas = ref;
|
||||||
this.canvas.width = 160 * window.devicePixelRatio;
|
this.canvas.width = 160 * window.devicePixelRatio;
|
||||||
this.canvas.height = 15 * window.devicePixelRatio;
|
this.canvas.height = 15 * window.devicePixelRatio;
|
||||||
const ctx = this.canvas.getContext("2d");
|
const ctx = this.canvas.getContext('2d');
|
||||||
ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
|
ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import cx from "classnames";
|
import cx from 'classnames';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import Clipboard from "clipboard";
|
import Clipboard from 'clipboard';
|
||||||
|
|
||||||
import MessageBytes from "./MessageBytes";
|
import MessageBytes from './MessageBytes';
|
||||||
const { ckmeans } = require("simple-statistics");
|
|
||||||
|
const { ckmeans } = require('simple-statistics');
|
||||||
|
|
||||||
export default class Meta extends Component {
|
export default class Meta extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -44,7 +45,7 @@ export default class Meta extends Component {
|
||||||
const { dbcLastSaved } = props;
|
const { dbcLastSaved } = props;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
filterText: "Filter",
|
filterText: 'Filter',
|
||||||
lastSaved:
|
lastSaved:
|
||||||
dbcLastSaved !== null ? this.props.dbcLastSaved.fromNow() : null,
|
dbcLastSaved !== null ? this.props.dbcLastSaved.fromNow() : null,
|
||||||
hoveredMessages: [],
|
hoveredMessages: [],
|
||||||
|
@ -67,25 +68,25 @@ export default class Meta extends Component {
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (
|
if (
|
||||||
nextProps.lastSaved !== this.props.lastSaved &&
|
nextProps.lastSaved !== this.props.lastSaved
|
||||||
typeof nextProps === "object"
|
&& typeof nextProps === 'object'
|
||||||
) {
|
) {
|
||||||
this.setState({ lastSaved: nextProps.dbcLastSaved.fromNow() });
|
this.setState({ lastSaved: nextProps.dbcLastSaved.fromNow() });
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextMsgKeys = Object.keys(nextProps.messages);
|
const nextMsgKeys = Object.keys(nextProps.messages);
|
||||||
if (
|
if (
|
||||||
JSON.stringify(nextMsgKeys) !==
|
JSON.stringify(nextMsgKeys)
|
||||||
JSON.stringify(Object.keys(this.props.messages))
|
!== JSON.stringify(Object.keys(this.props.messages))
|
||||||
) {
|
) {
|
||||||
const orderedMessageKeys = this.sortMessages(nextProps.messages);
|
const orderedMessageKeys = this.sortMessages(nextProps.messages);
|
||||||
this.setState({ hoveredMessages: [], orderedMessageKeys });
|
this.setState({ hoveredMessages: [], orderedMessageKeys });
|
||||||
} else if (
|
} else if (
|
||||||
this.state.orderedMessageKeys.length === 0 ||
|
this.state.orderedMessageKeys.length === 0
|
||||||
(!this.props.live &&
|
|| (!this.props.live
|
||||||
this.props.messages &&
|
&& this.props.messages
|
||||||
nextProps.messages &&
|
&& nextProps.messages
|
||||||
this.byteCountsDidUpdate(this.props.messages, nextProps.messages))
|
&& this.byteCountsDidUpdate(this.props.messages, nextProps.messages))
|
||||||
) {
|
) {
|
||||||
const orderedMessageKeys = this.sortMessages(nextProps.messages);
|
const orderedMessageKeys = this.sortMessages(nextProps.messages);
|
||||||
this.setState({ orderedMessageKeys });
|
this.setState({ orderedMessageKeys });
|
||||||
|
@ -94,9 +95,8 @@ export default class Meta extends Component {
|
||||||
|
|
||||||
byteCountsDidUpdate(prevMessages, nextMessages) {
|
byteCountsDidUpdate(prevMessages, nextMessages) {
|
||||||
return Object.entries(nextMessages).some(
|
return Object.entries(nextMessages).some(
|
||||||
([msgId, msg]) =>
|
([msgId, msg]) => JSON.stringify(msg.byteStateChangeCounts)
|
||||||
JSON.stringify(msg.byteStateChangeCounts) !==
|
!== JSON.stringify(prevMessages[msgId].byteStateChangeCounts)
|
||||||
JSON.stringify(prevMessages[msgId].byteStateChangeCounts)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,27 +121,22 @@ export default class Meta extends Component {
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
|
||||||
const entryCounts = Object.keys(messagesByEntryCount).map(count =>
|
const entryCounts = Object.keys(messagesByEntryCount).map((count) => parseInt(count, 10));
|
||||||
parseInt(count, 10)
|
|
||||||
);
|
|
||||||
const binnedEntryCounts = ckmeans(
|
const binnedEntryCounts = ckmeans(
|
||||||
entryCounts,
|
entryCounts,
|
||||||
Math.min(entryCounts.length, 10)
|
Math.min(entryCounts.length, 10)
|
||||||
);
|
);
|
||||||
const sortedKeys = binnedEntryCounts
|
const sortedKeys = binnedEntryCounts
|
||||||
.map(bin =>
|
.map((bin) => bin
|
||||||
bin
|
.map((entryCount) => messagesByEntryCount[entryCount.toString()])
|
||||||
.map(entryCount => messagesByEntryCount[entryCount.toString()])
|
.reduce((messages, partial) => messages.concat(partial), [])
|
||||||
.reduce((messages, partial) => messages.concat(partial), [])
|
.sort((msg1, msg2) => {
|
||||||
.sort((msg1, msg2) => {
|
if (msg1.address < msg2.address) {
|
||||||
if (msg1.address < msg2.address) {
|
return 1;
|
||||||
return 1;
|
}
|
||||||
} else {
|
return -1;
|
||||||
return -1;
|
})
|
||||||
}
|
.map((msg) => msg.id))
|
||||||
})
|
|
||||||
.map(msg => msg.id)
|
|
||||||
)
|
|
||||||
.reduce((keys, bin) => keys.concat(bin), [])
|
.reduce((keys, bin) => keys.concat(bin), [])
|
||||||
.reverse();
|
.reverse();
|
||||||
|
|
||||||
|
@ -156,20 +151,20 @@ export default class Meta extends Component {
|
||||||
|
|
||||||
onFilterChanged(e) {
|
onFilterChanged(e) {
|
||||||
let val = e.target.value;
|
let val = e.target.value;
|
||||||
if (val.trim() === "Filter") val = "";
|
if (val.trim() === 'Filter') val = '';
|
||||||
|
|
||||||
this.setState({ filterText: val });
|
this.setState({ filterText: val });
|
||||||
}
|
}
|
||||||
|
|
||||||
onFilterFocus(e) {
|
onFilterFocus(e) {
|
||||||
if (this.state.filterText.trim() === "Filter") {
|
if (this.state.filterText.trim() === 'Filter') {
|
||||||
this.setState({ filterText: "" });
|
this.setState({ filterText: '' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onFilterUnfocus(e) {
|
onFilterUnfocus(e) {
|
||||||
if (this.state.filterText.trim() === "") {
|
if (this.state.filterText.trim() === '') {
|
||||||
this.setState({ filterText: "Filter" });
|
this.setState({ filterText: 'Filter' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,13 +173,13 @@ export default class Meta extends Component {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { filterText } = this.state;
|
const { filterText } = this.state;
|
||||||
const msgName = msg.frame ? msg.frame.name : "";
|
const msgName = msg.frame ? msg.frame.name : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
filterText === "Filter" ||
|
filterText === 'Filter'
|
||||||
filterText === "" ||
|
|| filterText === ''
|
||||||
msg.id.toLowerCase().indexOf(filterText.toLowerCase()) !== -1 ||
|
|| msg.id.toLowerCase().indexOf(filterText.toLowerCase()) !== -1
|
||||||
msgName.toLowerCase().indexOf(filterText.toLowerCase()) !== -1
|
|| msgName.toLowerCase().indexOf(filterText.toLowerCase()) !== -1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,13 +188,13 @@ export default class Meta extends Component {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { filterText } = this.state;
|
const { filterText } = this.state;
|
||||||
const msgName = msg.frame ? msg.frame.name : "";
|
const msgName = msg.frame ? msg.frame.name : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
filterText === "Filter" ||
|
filterText === 'Filter'
|
||||||
filterText === "" ||
|
|| filterText === ''
|
||||||
msg.id.toLowerCase().indexOf(filterText.toLowerCase()) !== -1 ||
|
|| msg.id.toLowerCase().indexOf(filterText.toLowerCase()) !== -1
|
||||||
msgName.toLowerCase().indexOf(filterText.toLowerCase()) !== -1
|
|| msgName.toLowerCase().indexOf(filterText.toLowerCase()) !== -1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +204,7 @@ export default class Meta extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessageHover(key) {
|
onMessageHover(key) {
|
||||||
let { hoveredMessages } = this.state;
|
const { hoveredMessages } = this.state;
|
||||||
if (hoveredMessages.indexOf(key) !== -1) return;
|
if (hoveredMessages.indexOf(key) !== -1) return;
|
||||||
|
|
||||||
hoveredMessages.push(key);
|
hoveredMessages.push(key);
|
||||||
|
@ -218,13 +213,13 @@ export default class Meta extends Component {
|
||||||
|
|
||||||
onMessageHoverEnd(key) {
|
onMessageHoverEnd(key) {
|
||||||
let { hoveredMessages } = this.state;
|
let { hoveredMessages } = this.state;
|
||||||
hoveredMessages = hoveredMessages.filter(m => m !== key);
|
hoveredMessages = hoveredMessages.filter((m) => m !== key);
|
||||||
this.setState({ hoveredMessages });
|
this.setState({ hoveredMessages });
|
||||||
}
|
}
|
||||||
|
|
||||||
onMsgRemoveClick(key) {
|
onMsgRemoveClick(key) {
|
||||||
let { selectedMessages } = this.state;
|
let { selectedMessages } = this.state;
|
||||||
selectedMessages = selectedMessages.filter(m => m !== key);
|
selectedMessages = selectedMessages.filter((m) => m !== key);
|
||||||
this.props.onMessageUnselected(key);
|
this.props.onMessageUnselected(key);
|
||||||
this.setState({ selectedMessages });
|
this.setState({ selectedMessages });
|
||||||
}
|
}
|
||||||
|
@ -241,12 +236,12 @@ export default class Meta extends Component {
|
||||||
orderedMessages() {
|
orderedMessages() {
|
||||||
const { orderedMessageKeys } = this.state;
|
const { orderedMessageKeys } = this.state;
|
||||||
const { messages } = this.props;
|
const { messages } = this.props;
|
||||||
return orderedMessageKeys.map(key => messages[key]);
|
return orderedMessageKeys.map((key) => messages[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedMessageClass(messageId) {
|
selectedMessageClass(messageId) {
|
||||||
return this.props.selectedMessages.includes(messageId)
|
return this.props.selectedMessages.includes(messageId)
|
||||||
? "is-selected"
|
? 'is-selected'
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,17 +253,17 @@ export default class Meta extends Component {
|
||||||
}}
|
}}
|
||||||
key={msg.id}
|
key={msg.id}
|
||||||
className={cx(
|
className={cx(
|
||||||
"cabana-meta-messages-list-item",
|
'cabana-meta-messages-list-item',
|
||||||
this.selectedMessageClass(msg.id)
|
this.selectedMessageClass(msg.id)
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{msg.isLogEvent ? (
|
{msg.isLogEvent ? (
|
||||||
<td colSpan="2">{msg.id}</td>
|
<td colSpan="2">{msg.id}</td>
|
||||||
) : (
|
) : (
|
||||||
<React.Fragment>
|
<>
|
||||||
<td>{msg.frame ? msg.frame.name : "untitled"}</td>
|
<td>{msg.frame ? msg.frame.name : 'untitled'}</td>
|
||||||
<td>{msg.id}</td>
|
<td>{msg.id}</td>
|
||||||
</React.Fragment>
|
</>
|
||||||
)}
|
)}
|
||||||
<td>{msg.entries.length}</td>
|
<td>{msg.entries.length}</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -303,10 +298,10 @@ export default class Meta extends Component {
|
||||||
return <p>Loading messages...</p>;
|
return <p>Loading messages...</p>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<>
|
||||||
<table cellPadding="5">
|
<table cellPadding="5">
|
||||||
{this.state.showLogEvents && (
|
{this.state.showLogEvents && (
|
||||||
<React.Fragment>
|
<>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan="2">Name</td>
|
<td colSpan="2">Name</td>
|
||||||
|
@ -322,7 +317,7 @@ export default class Meta extends Component {
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</React.Fragment>
|
</>
|
||||||
)}
|
)}
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -334,7 +329,7 @@ export default class Meta extends Component {
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>{this.renderCanMessages()}</tbody>
|
<tbody>{this.renderCanMessages()}</tbody>
|
||||||
</table>
|
</table>
|
||||||
</React.Fragment>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,13 +337,14 @@ export default class Meta extends Component {
|
||||||
try {
|
try {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
"serviceWorker" in navigator &&
|
"serviceWorker" in navigator &&
|
||||||
!!new ReadableStream() &&
|
!!new ReadableStream()
|
||||||
!!new WritableStream(); // eslint-disable-line no-undef
|
&& !!new WritableStream(); // eslint-disable-line no-undef
|
||||||
return "saveable";
|
return 'saveable';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="cabana-meta">
|
<div className="cabana-meta">
|
||||||
|
@ -361,7 +357,10 @@ export default class Meta extends Component {
|
||||||
</strong>
|
</strong>
|
||||||
{this.props.dbcLastSaved !== null ? (
|
{this.props.dbcLastSaved !== null ? (
|
||||||
<div className="cabana-meta-header-last-saved">
|
<div className="cabana-meta-header-last-saved">
|
||||||
<p>Last saved: {this.lastSavedPretty()}</p>
|
<p>
|
||||||
|
Last saved:
|
||||||
|
{this.lastSavedPretty()}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div className={`cabana-meta-header-actions ${this.saveable()}`}>
|
<div className={`cabana-meta-header-actions ${this.saveable()}`}>
|
||||||
|
@ -378,12 +377,12 @@ export default class Meta extends Component {
|
||||||
className="cabana-meta-header-action special-wide"
|
className="cabana-meta-header-action special-wide"
|
||||||
data-clipboard-text={this.props.shareUrl}
|
data-clipboard-text={this.props.shareUrl}
|
||||||
data-clipboard-action="copy"
|
data-clipboard-action="copy"
|
||||||
ref={ref => (ref ? new Clipboard(ref) : null)}
|
ref={(ref) => (ref ? new Clipboard(ref) : null)}
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
className="button"
|
className="button"
|
||||||
href={this.props.shareUrl}
|
href={this.props.shareUrl}
|
||||||
onClick={e => e.preventDefault()}
|
onClick={(e) => e.preventDefault()}
|
||||||
>
|
>
|
||||||
Copy Share Link
|
Copy Share Link
|
||||||
</a>
|
</a>
|
||||||
|
@ -398,8 +397,8 @@ export default class Meta extends Component {
|
||||||
<div className="cabana-meta-messages-header">
|
<div className="cabana-meta-messages-header">
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "inline-block",
|
display: 'inline-block',
|
||||||
float: "right"
|
float: 'right'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<h5 className="t-capline">
|
<h5 className="t-capline">
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import Moment from "moment";
|
import Moment from 'moment';
|
||||||
import _ from "lodash";
|
import _ from 'lodash';
|
||||||
import cx from "classnames";
|
import cx from 'classnames';
|
||||||
import CommaAuth from "@commaai/my-comma-auth";
|
import CommaAuth from '@commaai/my-comma-auth';
|
||||||
|
|
||||||
import { EXPLORER_URL } from "../../config";
|
import { EXPLORER_URL } from '../../config';
|
||||||
import Modal from "../Modals/baseModal";
|
import Modal from './baseModal';
|
||||||
|
|
||||||
export default class OnboardingModal extends Component {
|
export default class OnboardingModal extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -15,8 +15,8 @@ export default class OnboardingModal extends Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
static instructionalImages = {
|
static instructionalImages = {
|
||||||
step2: require("../../images/webusb-enable-experimental-features.png"),
|
step2: require('../../images/webusb-enable-experimental-features.png'),
|
||||||
step3: require("../../images/webusb-enable-webusb.png")
|
step3: require('../../images/webusb-enable-webusb.png')
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -66,7 +66,8 @@ export default class OnboardingModal extends Component {
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
} else if (!pandaConnected && attemptingPandaConnection) {
|
}
|
||||||
|
if (!pandaConnected && attemptingPandaConnection) {
|
||||||
return (
|
return (
|
||||||
<p>
|
<p>
|
||||||
<i className="fa fa-spinner animate-spin" />
|
<i className="fa fa-spinner animate-spin" />
|
||||||
|
@ -87,8 +88,8 @@ export default class OnboardingModal extends Component {
|
||||||
<i className="fa fa-video-camera" />
|
<i className="fa fa-video-camera" />
|
||||||
<strong>
|
<strong>
|
||||||
{CommaAuth.isAuthenticated()
|
{CommaAuth.isAuthenticated()
|
||||||
? "Find a drive in Explorer"
|
? 'Find a drive in Explorer'
|
||||||
: "Log in with Explorer"}
|
: 'Log in with Explorer'}
|
||||||
</strong>
|
</strong>
|
||||||
<sup>Click "View CAN Data" while replaying a drive</sup>
|
<sup>Click "View CAN Data" while replaying a drive</sup>
|
||||||
</button>
|
</button>
|
||||||
|
@ -101,17 +102,19 @@ export default class OnboardingModal extends Component {
|
||||||
<div className="cabana-onboarding-mode">{this.renderLogin()}</div>
|
<div className="cabana-onboarding-mode">{this.renderLogin()}</div>
|
||||||
<div className="cabana-onboarding-mode">
|
<div className="cabana-onboarding-mode">
|
||||||
<button
|
<button
|
||||||
className={cx("button--secondary button--kiosk", {
|
className={cx('button--secondary button--kiosk', {
|
||||||
"is-disabled":
|
'is-disabled':
|
||||||
!this.state.webUsbEnabled ||
|
!this.state.webUsbEnabled
|
||||||
this.props.attemptingPandaConnection
|
|| this.props.attemptingPandaConnection
|
||||||
})}
|
})}
|
||||||
onClick={this.attemptPandaConnection}
|
onClick={this.attemptPandaConnection}
|
||||||
>
|
>
|
||||||
<i className="fa fa-bolt" />
|
<i className="fa fa-bolt" />
|
||||||
<strong>Launch Realtime Streaming</strong>
|
<strong>Launch Realtime Streaming</strong>
|
||||||
<sup>
|
<sup>
|
||||||
Interactively stream car data over USB with <em>panda</em>
|
Interactively stream car data over USB with
|
||||||
|
{' '}
|
||||||
|
<em>panda</em>
|
||||||
</sup>
|
</sup>
|
||||||
{this.renderPandaEligibility()}
|
{this.renderPandaEligibility()}
|
||||||
</button>
|
</button>
|
||||||
|
@ -147,7 +150,7 @@ export default class OnboardingModal extends Component {
|
||||||
<strong>Enable Experimental Platform features:</strong>
|
<strong>Enable Experimental Platform features:</strong>
|
||||||
</p>
|
</p>
|
||||||
<img
|
<img
|
||||||
alt={"Screenshot of Google Chrome Experimental Platform features"}
|
alt="Screenshot of Google Chrome Experimental Platform features"
|
||||||
src={OnboardingModal.instructionalImages.step2}
|
src={OnboardingModal.instructionalImages.step2}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
|
@ -156,7 +159,7 @@ export default class OnboardingModal extends Component {
|
||||||
<strong>Enable WebUSB:</strong>
|
<strong>Enable WebUSB:</strong>
|
||||||
</p>
|
</p>
|
||||||
<img
|
<img
|
||||||
alt={"Screenshot of Google Chrome enable WebUSB"}
|
alt="Screenshot of Google Chrome enable WebUSB"
|
||||||
src={OnboardingModal.instructionalImages.step3}
|
src={OnboardingModal.instructionalImages.step3}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
|
@ -175,23 +178,25 @@ export default class OnboardingModal extends Component {
|
||||||
renderModalContent() {
|
renderModalContent() {
|
||||||
if (this.state.viewingUsbInstructions) {
|
if (this.state.viewingUsbInstructions) {
|
||||||
return this.renderUsbInstructions();
|
return this.renderUsbInstructions();
|
||||||
} else {
|
|
||||||
return this.renderOnboardingOptions();
|
|
||||||
}
|
}
|
||||||
|
return this.renderOnboardingOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderModalFooter() {
|
renderModalFooter() {
|
||||||
return (
|
return (
|
||||||
<p>
|
<p>
|
||||||
<span>
|
<span>
|
||||||
Don't have a{" "}
|
Don't have a
|
||||||
|
{' '}
|
||||||
<a
|
<a
|
||||||
href="https://panda.comma.ai"
|
href="https://panda.comma.ai"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
panda
|
panda
|
||||||
</a>?{" "}
|
</a>
|
||||||
|
?
|
||||||
|
{' '}
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<a
|
<a
|
||||||
|
@ -200,10 +205,14 @@ export default class OnboardingModal extends Component {
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
Get one here
|
Get one here
|
||||||
</a>{" "}
|
</a>
|
||||||
|
{' '}
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
or <a href={`${window.location.href}?demo=1`}>try the demo</a>.
|
or
|
||||||
|
{' '}
|
||||||
|
<a href={`${window.location.href}?demo=1`}>try the demo</a>
|
||||||
|
.
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
|
@ -215,8 +224,8 @@ export default class OnboardingModal extends Component {
|
||||||
title="Welcome to Cabana"
|
title="Welcome to Cabana"
|
||||||
subtitle="Get started by selecting a drive from Explorer or enabling live mode"
|
subtitle="Get started by selecting a drive from Explorer or enabling live mode"
|
||||||
footer={this.renderModalFooter()}
|
footer={this.renderModalFooter()}
|
||||||
disableClose={true}
|
disableClose
|
||||||
variations={["wide", "dark"]}
|
variations={['wide', 'dark']}
|
||||||
>
|
>
|
||||||
{this.renderModalContent()}
|
{this.renderModalContent()}
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import cx from "classnames";
|
import cx from 'classnames';
|
||||||
import Measure from "react-measure";
|
import Measure from 'react-measure';
|
||||||
|
|
||||||
export default class Modal extends Component {
|
export default class Modal extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -36,8 +36,8 @@ export default class Modal extends Component {
|
||||||
if (this.props.variations) {
|
if (this.props.variations) {
|
||||||
const { variations } = this.props;
|
const { variations } = this.props;
|
||||||
const classes = variations.reduce(
|
const classes = variations.reduce(
|
||||||
(classes, variation) => classes + `cabana-modal--${variation} `,
|
(classes, variation) => `${classes}cabana-modal--${variation} `,
|
||||||
""
|
''
|
||||||
);
|
);
|
||||||
return classes;
|
return classes;
|
||||||
}
|
}
|
||||||
|
@ -54,14 +54,14 @@ export default class Modal extends Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cx("cabana-modal", this.readVariationClasses(), {
|
className={cx('cabana-modal', this.readVariationClasses(), {
|
||||||
"cabana-modal--not-closable": this.checkClosability(),
|
'cabana-modal--not-closable': this.checkClosability(),
|
||||||
"cabana-modal--scrollable-y": this.checkYScrollability()
|
'cabana-modal--scrollable-y': this.checkYScrollability()
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Measure
|
<Measure
|
||||||
bounds
|
bounds
|
||||||
onResize={contentRect => {
|
onResize={(contentRect) => {
|
||||||
this.updateHeights(contentRect);
|
this.updateHeights(contentRect);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { PART_SEGMENT_LENGTH } from "../config";
|
import { PART_SEGMENT_LENGTH } from '../config';
|
||||||
|
|
||||||
export default class PartSelector extends Component {
|
export default class PartSelector extends Component {
|
||||||
static selectorWidth = 150;
|
static selectorWidth = 150;
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
onPartChange: PropTypes.func.isRequired,
|
onPartChange: PropTypes.func.isRequired,
|
||||||
partsCount: PropTypes.number.isRequired,
|
partsCount: PropTypes.number.isRequired,
|
||||||
|
@ -29,14 +30,14 @@ export default class PartSelector extends Component {
|
||||||
|
|
||||||
makePartStyle(partsCount, selectedPart) {
|
makePartStyle(partsCount, selectedPart) {
|
||||||
return {
|
return {
|
||||||
left: selectedPart / partsCount * PartSelector.selectorWidth,
|
left: (selectedPart / partsCount) * PartSelector.selectorWidth,
|
||||||
width: PART_SEGMENT_LENGTH / partsCount * PartSelector.selectorWidth
|
width: (PART_SEGMENT_LENGTH / partsCount) * PartSelector.selectorWidth
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUpdate(nextProps, nextState) {
|
componentWillUpdate(nextProps, nextState) {
|
||||||
if (nextProps.selectedPart !== this.props.selectedPart) {
|
if (nextProps.selectedPart !== this.props.selectedPart) {
|
||||||
console.log("updating styles for part picker");
|
console.log('updating styles for part picker');
|
||||||
const selectedPartStyle = this.makePartStyle(
|
const selectedPartStyle = this.makePartStyle(
|
||||||
nextProps.partsCount,
|
nextProps.partsCount,
|
||||||
nextProps.selectedPart
|
nextProps.selectedPart
|
||||||
|
@ -80,12 +81,12 @@ export default class PartSelector extends Component {
|
||||||
partAtClientX(clientX) {
|
partAtClientX(clientX) {
|
||||||
const rect = this.selectorRect.getBoundingClientRect();
|
const rect = this.selectorRect.getBoundingClientRect();
|
||||||
const x = clientX - rect.left;
|
const x = clientX - rect.left;
|
||||||
return Math.floor(x * this.props.partsCount / PartSelector.selectorWidth);
|
return Math.floor((x * this.props.partsCount) / PartSelector.selectorWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelectedPartDragStart(e) {
|
onSelectedPartDragStart(e) {
|
||||||
this.setState({ isDragging: true });
|
this.setState({ isDragging: true });
|
||||||
document.addEventListener("mouseup", this.onSelectedPartDragEnd);
|
document.addEventListener('mouseup', this.onSelectedPartDragEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelectedPartMouseMove(e) {
|
onSelectedPartMouseMove(e) {
|
||||||
|
@ -97,7 +98,7 @@ export default class PartSelector extends Component {
|
||||||
|
|
||||||
onSelectedPartDragEnd(e) {
|
onSelectedPartDragEnd(e) {
|
||||||
this.setState({ isDragging: false });
|
this.setState({ isDragging: false });
|
||||||
document.removeEventListener("mouseup", this.onSelectedPartDragEnd);
|
document.removeEventListener('mouseup', this.onSelectedPartDragEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
onClick(e) {
|
onClick(e) {
|
||||||
|
@ -116,7 +117,7 @@ export default class PartSelector extends Component {
|
||||||
<div className="cabana-explorer-part-selector">
|
<div className="cabana-explorer-part-selector">
|
||||||
<div
|
<div
|
||||||
className="cabana-explorer-part-selector-track"
|
className="cabana-explorer-part-selector-track"
|
||||||
ref={selector => (this.selectorRect = selector)}
|
ref={(selector) => (this.selectorRect = selector)}
|
||||||
style={{ width: PartSelector.selectorWidth }}
|
style={{ width: PartSelector.selectorWidth }}
|
||||||
onMouseMove={this.onSelectedPartMouseMove}
|
onMouseMove={this.onSelectedPartMouseMove}
|
||||||
onClick={this.onClick}
|
onClick={this.onClick}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
export default class PlayButton extends Component {
|
export default class PlayButton extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -21,29 +21,18 @@ export default class PlayButton extends Component {
|
||||||
const { isPlaying } = this.props;
|
const { isPlaying } = this.props;
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
if (hover) {
|
if (hover) {
|
||||||
return (
|
return `${process.env.PUBLIC_URL}/img/ic_pause_circle_filled_white_24px.svg`;
|
||||||
process.env.PUBLIC_URL + "/img/ic_pause_circle_filled_white_24px.svg"
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
process.env.PUBLIC_URL + "/img/ic_pause_circle_outline_white_24px.svg"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (hover) {
|
|
||||||
return (
|
|
||||||
process.env.PUBLIC_URL + "/img/ic_play_circle_filled_white_24px.svg"
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
process.env.PUBLIC_URL + "/img/ic_play_circle_outline_white_24px.svg"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
return `${process.env.PUBLIC_URL}/img/ic_pause_circle_outline_white_24px.svg`;
|
||||||
}
|
}
|
||||||
|
if (hover) {
|
||||||
|
return `${process.env.PUBLIC_URL}/img/ic_play_circle_filled_white_24px.svg`;
|
||||||
|
}
|
||||||
|
return `${process.env.PUBLIC_URL}/img/ic_play_circle_outline_white_24px.svg`;
|
||||||
}
|
}
|
||||||
|
|
||||||
onClick(e) {
|
onClick(e) {
|
||||||
let { isPlaying } = this.props;
|
const { isPlaying } = this.props;
|
||||||
|
|
||||||
if (!isPlaying) {
|
if (!isPlaying) {
|
||||||
this.props.onPlay();
|
this.props.onPlay();
|
||||||
|
@ -56,7 +45,7 @@ export default class PlayButton extends Component {
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
src={this.imageSource()}
|
src={this.imageSource()}
|
||||||
alt={this.props.isPlaying ? "Pause" : "Play"}
|
alt={this.props.isPlaying ? 'Pause' : 'Play'}
|
||||||
className={this.props.className}
|
className={this.props.className}
|
||||||
onClick={this.onClick}
|
onClick={this.onClick}
|
||||||
onMouseOver={() => this.setState({ hover: true })}
|
onMouseOver={() => this.setState({ hover: true })}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
export default class PlaySpeedSelector extends Component {
|
export default class PlaySpeedSelector extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -16,8 +16,8 @@ export default class PlaySpeedSelector extends Component {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "inline-block",
|
display: 'inline-block',
|
||||||
float: "right",
|
float: 'right',
|
||||||
margin: 10
|
margin: 10
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import PlayButton from "../PlayButton";
|
import PlayButton from '../PlayButton';
|
||||||
import debounce from "../../utils/debounce";
|
import debounce from '../../utils/debounce';
|
||||||
|
|
||||||
export default class RouteSeeker extends Component {
|
export default class RouteSeeker extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -18,10 +18,14 @@ export default class RouteSeeker extends Component {
|
||||||
nearestFrameTime: PropTypes.number
|
nearestFrameTime: PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
||||||
static hiddenMarkerStyle = { display: "none", left: 0 };
|
static hiddenMarkerStyle = { display: 'none', left: 0 };
|
||||||
|
|
||||||
static zeroSeekedBarStyle = { width: 0 };
|
static zeroSeekedBarStyle = { width: 0 };
|
||||||
static hiddenTooltipStyle = { display: "none", left: 0 };
|
|
||||||
|
static hiddenTooltipStyle = { display: 'none', left: 0 };
|
||||||
|
|
||||||
static markerWidth = 20;
|
static markerWidth = 20;
|
||||||
|
|
||||||
static tooltipWidth = 50;
|
static tooltipWidth = 50;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -31,7 +35,7 @@ export default class RouteSeeker extends Component {
|
||||||
markerStyle: RouteSeeker.hiddenMarkerStyle,
|
markerStyle: RouteSeeker.hiddenMarkerStyle,
|
||||||
tooltipStyle: RouteSeeker.hiddenTooltipStyle,
|
tooltipStyle: RouteSeeker.hiddenTooltipStyle,
|
||||||
ratio: 0,
|
ratio: 0,
|
||||||
tooltipTime: "0:00",
|
tooltipTime: '0:00',
|
||||||
isPlaying: false,
|
isPlaying: false,
|
||||||
isDragging: false
|
isDragging: false
|
||||||
};
|
};
|
||||||
|
@ -50,8 +54,8 @@ export default class RouteSeeker extends Component {
|
||||||
const { ratio } = this.state;
|
const { ratio } = this.state;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
JSON.stringify(this.props.segmentIndices) !==
|
JSON.stringify(this.props.segmentIndices)
|
||||||
JSON.stringify(nextProps.segmentIndices)
|
!== JSON.stringify(nextProps.segmentIndices)
|
||||||
) {
|
) {
|
||||||
this.setState({
|
this.setState({
|
||||||
seekedBarStyle: RouteSeeker.zeroSeekedBarStyle,
|
seekedBarStyle: RouteSeeker.zeroSeekedBarStyle,
|
||||||
|
@ -88,7 +92,7 @@ export default class RouteSeeker extends Component {
|
||||||
return 100 * (x / this.progressBar.offsetWidth);
|
return 100 * (x / this.progressBar.offsetWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDraggingSeek = debounce(ratio => this.props.onUserSeek(ratio), 250);
|
updateDraggingSeek = debounce((ratio) => this.props.onUserSeek(ratio), 250);
|
||||||
|
|
||||||
onMouseMove(e) {
|
onMouseMove(e) {
|
||||||
const markerOffsetPct = this.mouseEventXOffsetPercent(e);
|
const markerOffsetPct = this.mouseEventXOffsetPercent(e);
|
||||||
|
@ -96,18 +100,18 @@ export default class RouteSeeker extends Component {
|
||||||
this.onMouseLeave();
|
this.onMouseLeave();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const markerWidth = RouteSeeker.markerWidth;
|
const { markerWidth } = RouteSeeker;
|
||||||
|
|
||||||
const markerLeft = `calc(${markerOffsetPct + "%"} - ${markerWidth / 2}px)`;
|
const markerLeft = `calc(${`${markerOffsetPct}%`} - ${markerWidth / 2}px)`;
|
||||||
const markerStyle = {
|
const markerStyle = {
|
||||||
display: "",
|
display: '',
|
||||||
left: markerLeft
|
left: markerLeft
|
||||||
};
|
};
|
||||||
const tooltipWidth = RouteSeeker.tooltipWidth;
|
const { tooltipWidth } = RouteSeeker;
|
||||||
const tooltipLeft = `calc(${markerOffsetPct + "%"} - ${tooltipWidth /
|
const tooltipLeft = `calc(${`${markerOffsetPct}%`} - ${tooltipWidth
|
||||||
2}px)`;
|
/ 2}px)`;
|
||||||
|
|
||||||
const tooltipStyle = { display: "flex", left: tooltipLeft };
|
const tooltipStyle = { display: 'flex', left: tooltipLeft };
|
||||||
const ratio = Math.max(0, markerOffsetPct / 100);
|
const ratio = Math.max(0, markerOffsetPct / 100);
|
||||||
if (this.state.isDragging) {
|
if (this.state.isDragging) {
|
||||||
this.updateSeekedBar(ratio);
|
this.updateSeekedBar(ratio);
|
||||||
|
@ -130,7 +134,7 @@ export default class RouteSeeker extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSeekedBar(ratio) {
|
updateSeekedBar(ratio) {
|
||||||
const seekedBarStyle = { width: 100 * ratio + "%" };
|
const seekedBarStyle = { width: `${100 * ratio}%` };
|
||||||
this.setState({ seekedBarStyle, ratio });
|
this.setState({ seekedBarStyle, ratio });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,32 +214,32 @@ export default class RouteSeeker extends Component {
|
||||||
return (
|
return (
|
||||||
<div className="cabana-explorer-visuals-camera-seeker">
|
<div className="cabana-explorer-visuals-camera-seeker">
|
||||||
<PlayButton
|
<PlayButton
|
||||||
className={"cabana-explorer-visuals-camera-seeker-playbutton"}
|
className="cabana-explorer-visuals-camera-seeker-playbutton"
|
||||||
onPlay={this.onPlay}
|
onPlay={this.onPlay}
|
||||||
onPause={this.onPause}
|
onPause={this.onPause}
|
||||||
isPlaying={this.state.isPlaying}
|
isPlaying={this.state.isPlaying}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className={"cabana-explorer-visuals-camera-seeker-progress"}
|
className="cabana-explorer-visuals-camera-seeker-progress"
|
||||||
onMouseMove={this.onMouseMove}
|
onMouseMove={this.onMouseMove}
|
||||||
onMouseLeave={this.onMouseLeave}
|
onMouseLeave={this.onMouseLeave}
|
||||||
onMouseDown={this.onMouseDown}
|
onMouseDown={this.onMouseDown}
|
||||||
onMouseUp={this.onMouseUp}
|
onMouseUp={this.onMouseUp}
|
||||||
onClick={this.onClick}
|
onClick={this.onClick}
|
||||||
ref={ref => (this.progressBar = ref)}
|
ref={(ref) => (this.progressBar = ref)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={"cabana-explorer-visuals-camera-seeker-progress-tooltip"}
|
className="cabana-explorer-visuals-camera-seeker-progress-tooltip"
|
||||||
style={tooltipStyle}
|
style={tooltipStyle}
|
||||||
>
|
>
|
||||||
{this.state.tooltipTime}
|
{this.state.tooltipTime}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={"cabana-explorer-visuals-camera-seeker-progress-marker"}
|
className="cabana-explorer-visuals-camera-seeker-progress-marker"
|
||||||
style={markerStyle}
|
style={markerStyle}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className={"cabana-explorer-visuals-camera-seeker-progress-inner"}
|
className="cabana-explorer-visuals-camera-seeker-progress-inner"
|
||||||
style={seekedBarStyle}
|
style={seekedBarStyle}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
import RouteSeeker from "./RouteSeeker";
|
import RouteSeeker from './RouteSeeker';
|
||||||
|
|
||||||
export default RouteSeeker;
|
export default RouteSeeker;
|
||||||
|
|
|
@ -1,44 +1,44 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import { StyleSheet, css } from "aphrodite/no-important";
|
import { StyleSheet, css } from 'aphrodite/no-important';
|
||||||
import { derived as RouteApi, video as VideoApi } from "@commaai/comma-api";
|
import { derived as RouteApi, video as VideoApi } from '@commaai/comma-api';
|
||||||
|
|
||||||
import HLS from "./HLS";
|
import HLS from './HLS';
|
||||||
import RouteSeeker from "./RouteSeeker/RouteSeeker";
|
import RouteSeeker from './RouteSeeker/RouteSeeker';
|
||||||
|
|
||||||
const Styles = StyleSheet.create({
|
const Styles = StyleSheet.create({
|
||||||
loadingOverlay: {
|
loadingOverlay: {
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
width: "100%",
|
width: '100%',
|
||||||
height: "100%",
|
height: '100%',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
zIndex: 3
|
zIndex: 3
|
||||||
},
|
},
|
||||||
loadingSpinner: {
|
loadingSpinner: {
|
||||||
width: "25%",
|
width: '25%',
|
||||||
height: "25%",
|
height: '25%',
|
||||||
display: "block"
|
display: 'block'
|
||||||
},
|
},
|
||||||
img: {
|
img: {
|
||||||
height: 480,
|
height: 480,
|
||||||
display: "block",
|
display: 'block',
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
zIndex: 2
|
zIndex: 2
|
||||||
},
|
},
|
||||||
hls: {
|
hls: {
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
height: 480,
|
height: 480,
|
||||||
backgroundColor: "rgba(0,0,0,0.9)"
|
backgroundColor: 'rgba(0,0,0,0.9)'
|
||||||
},
|
},
|
||||||
seekBar: {
|
seekBar: {
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
width: "100%",
|
width: '100%',
|
||||||
zIndex: 4
|
zIndex: 4
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -79,17 +79,17 @@ export default class RouteVideoSync extends Component {
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (
|
if (
|
||||||
this.props.userSeekIndex !== nextProps.userSeekIndex ||
|
this.props.userSeekIndex !== nextProps.userSeekIndex
|
||||||
this.props.canFrameOffset !== nextProps.canFrameOffset ||
|
|| this.props.canFrameOffset !== nextProps.canFrameOffset
|
||||||
(this.props.message &&
|
|| (this.props.message
|
||||||
nextProps.message &&
|
&& nextProps.message
|
||||||
this.props.message.entries.length !== nextProps.message.entries.length)
|
&& this.props.message.entries.length !== nextProps.message.entries.length)
|
||||||
) {
|
) {
|
||||||
this.setState({ shouldRestartHls: true });
|
this.setState({ shouldRestartHls: true });
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
nextProps.userSeekTime &&
|
nextProps.userSeekTime
|
||||||
this.props.userSeekTime !== nextProps.userSeekTime
|
&& this.props.userSeekTime !== nextProps.userSeekTime
|
||||||
) {
|
) {
|
||||||
if (this.state.videoElement) {
|
if (this.state.videoElement) {
|
||||||
this.state.videoElement.currentTime = nextProps.userSeekTime;
|
this.state.videoElement.currentTime = nextProps.userSeekTime;
|
||||||
|
@ -111,8 +111,8 @@ export default class RouteVideoSync extends Component {
|
||||||
<div className={css(Styles.loadingOverlay)}>
|
<div className={css(Styles.loadingOverlay)}>
|
||||||
<img
|
<img
|
||||||
className={css(Styles.loadingSpinner)}
|
className={css(Styles.loadingSpinner)}
|
||||||
src={process.env.PUBLIC_URL + "/img/loading.svg"}
|
src={`${process.env.PUBLIC_URL}/img/loading.svg`}
|
||||||
alt={"Loading video"}
|
alt="Loading video"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -154,7 +154,7 @@ export default class RouteVideoSync extends Component {
|
||||||
|
|
||||||
segmentProgress(currentTime) {
|
segmentProgress(currentTime) {
|
||||||
// returns progress as number in [0,1]
|
// returns progress as number in [0,1]
|
||||||
let startTime = this.startTime();
|
const startTime = this.startTime();
|
||||||
|
|
||||||
if (currentTime < startTime) {
|
if (currentTime < startTime) {
|
||||||
currentTime = startTime;
|
currentTime = startTime;
|
||||||
|
@ -175,12 +175,12 @@ export default class RouteVideoSync extends Component {
|
||||||
onUserSeek(ratio) {
|
onUserSeek(ratio) {
|
||||||
/* ratio in [0,1] */
|
/* ratio in [0,1] */
|
||||||
|
|
||||||
let { videoElement } = this.state;
|
const { videoElement } = this.state;
|
||||||
if (isNaN(videoElement.duration)) {
|
if (isNaN(videoElement.duration)) {
|
||||||
this.setState({ shouldRestartHls: true }, funcSeekToRatio);
|
this.setState({ shouldRestartHls: true }, funcSeekToRatio);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let seekTime = this.ratioTime(ratio);
|
const seekTime = this.ratioTime(ratio);
|
||||||
videoElement.currentTime = seekTime;
|
videoElement.currentTime = seekTime;
|
||||||
|
|
||||||
const funcSeekToRatio = () => this.props.onUserSeek(seekTime);
|
const funcSeekToRatio = () => this.props.onUserSeek(seekTime);
|
||||||
|
@ -203,7 +203,7 @@ export default class RouteVideoSync extends Component {
|
||||||
<img
|
<img
|
||||||
src={this.nearestFrameUrl()}
|
src={this.nearestFrameUrl()}
|
||||||
className={css(Styles.img)}
|
className={css(Styles.img)}
|
||||||
alt={"Camera preview at t = " + Math.round(this.props.userSeekTime)}
|
alt={`Camera preview at t = ${Math.round(this.props.userSeekTime)}`}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<HLS
|
<HLS
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import cx from "classnames";
|
import cx from 'classnames';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import FileSaver from "file-saver";
|
import FileSaver from 'file-saver';
|
||||||
|
|
||||||
import OpenDbc from "../api/OpenDbc";
|
import OpenDbc from '../api/OpenDbc';
|
||||||
import DBC from "../models/can/dbc";
|
import DBC from '../models/can/dbc';
|
||||||
import Modal from "./Modals/baseModal";
|
import Modal from './Modals/baseModal';
|
||||||
// import TabStyles from '../styles/modal-tabs';
|
// import TabStyles from '../styles/modal-tabs';
|
||||||
|
|
||||||
export default class SaveDbcModal extends Component {
|
export default class SaveDbcModal extends Component {
|
||||||
|
@ -22,11 +22,11 @@ export default class SaveDbcModal extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
tab: "GitHub",
|
tab: 'GitHub',
|
||||||
openDbcFork: null,
|
openDbcFork: null,
|
||||||
dbcFilename: this.props.sourceDbcFilename,
|
dbcFilename: this.props.sourceDbcFilename,
|
||||||
tabs: ["GitHub", "Download"],
|
tabs: ['GitHub', 'Download'],
|
||||||
commitMessage: "OpenDBC updates"
|
commitMessage: 'OpenDBC updates'
|
||||||
};
|
};
|
||||||
|
|
||||||
this.commitToGitHub = this.commitToGitHub.bind(this);
|
this.commitToGitHub = this.commitToGitHub.bind(this);
|
||||||
|
@ -44,7 +44,7 @@ export default class SaveDbcModal extends Component {
|
||||||
|
|
||||||
async commitToGitHub() {
|
async commitToGitHub() {
|
||||||
const { openDbcFork, dbcFilename } = this.state;
|
const { openDbcFork, dbcFilename } = this.state;
|
||||||
const filename = dbcFilename.replace(/\.dbc/g, "") + ".dbc";
|
const filename = `${dbcFilename.replace(/\.dbc/g, '')}.dbc`;
|
||||||
const success = await this.props.openDbcClient.commitFile(
|
const success = await this.props.openDbcClient.commitFile(
|
||||||
openDbcFork,
|
openDbcFork,
|
||||||
filename,
|
filename,
|
||||||
|
@ -58,9 +58,9 @@ export default class SaveDbcModal extends Component {
|
||||||
|
|
||||||
async downloadDbcFile() {
|
async downloadDbcFile() {
|
||||||
const blob = new Blob([this.props.dbc.text()], {
|
const blob = new Blob([this.props.dbc.text()], {
|
||||||
type: "text/plain;charset=utf-8"
|
type: 'text/plain;charset=utf-8'
|
||||||
});
|
});
|
||||||
const filename = this.state.dbcFilename.replace(/\.dbc/g, "") + ".dbc";
|
const filename = `${this.state.dbcFilename.replace(/\.dbc/g, '')}.dbc`;
|
||||||
FileSaver.saveAs(blob, filename, true);
|
FileSaver.saveAs(blob, filename, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ export default class SaveDbcModal extends Component {
|
||||||
|
|
||||||
const interval = window.setInterval(() => {
|
const interval = window.setInterval(() => {
|
||||||
if (!isTimedOut) {
|
if (!isTimedOut) {
|
||||||
this.props.openDbcClient.getUserOpenDbcFork().then(openDbcFork => {
|
this.props.openDbcClient.getUserOpenDbcFork().then((openDbcFork) => {
|
||||||
if (openDbcFork !== null) {
|
if (openDbcFork !== null) {
|
||||||
this.setState({ openDbcFork });
|
this.setState({ openDbcFork });
|
||||||
window.clearInterval(interval);
|
window.clearInterval(interval);
|
||||||
|
@ -92,11 +92,12 @@ export default class SaveDbcModal extends Component {
|
||||||
|
|
||||||
primaryActionDisabled() {
|
primaryActionDisabled() {
|
||||||
const { tab } = this.state;
|
const { tab } = this.state;
|
||||||
if (tab === "GitHub") {
|
if (tab === 'GitHub') {
|
||||||
return (
|
return (
|
||||||
this.state.openDbcFork != null && this.state.dbcFilename.length > 0
|
this.state.openDbcFork != null && this.state.dbcFilename.length > 0
|
||||||
);
|
);
|
||||||
} else if (tab === "Download") {
|
}
|
||||||
|
if (tab === 'Download') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,7 +118,11 @@ export default class SaveDbcModal extends Component {
|
||||||
content = (
|
content = (
|
||||||
<button disabled>
|
<button disabled>
|
||||||
<i className="fa fa-code-fork" />
|
<i className="fa fa-code-fork" />
|
||||||
<span> Forked: {openDbcFork}</span>
|
<span>
|
||||||
|
{' '}
|
||||||
|
Forked:
|
||||||
|
{openDbcFork}
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
} else if (this.props.hasGithubAuth) {
|
} else if (this.props.hasGithubAuth) {
|
||||||
|
@ -144,9 +149,9 @@ export default class SaveDbcModal extends Component {
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="filename"
|
id="filename"
|
||||||
value={this.state.dbcFilename.replace(/\.dbc/g, "")}
|
value={this.state.dbcFilename.replace(/\.dbc/g, '')}
|
||||||
size={this.state.dbcFilename.length + 2}
|
size={this.state.dbcFilename.length + 2}
|
||||||
onChange={e => this.setState({ dbcFilename: e.target.value })}
|
onChange={(e) => this.setState({ dbcFilename: e.target.value })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -155,19 +160,17 @@ export default class SaveDbcModal extends Component {
|
||||||
renderTabNavigation() {
|
renderTabNavigation() {
|
||||||
return (
|
return (
|
||||||
<div className="cabana-tabs-navigation">
|
<div className="cabana-tabs-navigation">
|
||||||
{this.state.tabs.map(tab => {
|
{this.state.tabs.map((tab) => (
|
||||||
return (
|
<a
|
||||||
<a
|
className={cx({ 'is-active': this.state.tab === tab })}
|
||||||
className={cx({ "is-active": this.state.tab === tab })}
|
onClick={() => {
|
||||||
onClick={() => {
|
this.setState({ tab });
|
||||||
this.setState({ tab });
|
}}
|
||||||
}}
|
key={tab}
|
||||||
key={tab}
|
>
|
||||||
>
|
<span>{tab}</span>
|
||||||
<span>{tab}</span>
|
</a>
|
||||||
</a>
|
))}
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -183,7 +186,7 @@ export default class SaveDbcModal extends Component {
|
||||||
type="text"
|
type="text"
|
||||||
id="commit-message"
|
id="commit-message"
|
||||||
value={this.state.commitMessage}
|
value={this.state.commitMessage}
|
||||||
onChange={e => this.setState({ commitMessage: e.target.value })}
|
onChange={(e) => this.setState({ commitMessage: e.target.value })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -191,7 +194,7 @@ export default class SaveDbcModal extends Component {
|
||||||
|
|
||||||
renderTabContent() {
|
renderTabContent() {
|
||||||
const { tab } = this.state;
|
const { tab } = this.state;
|
||||||
if (tab === "GitHub") {
|
if (tab === 'GitHub') {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{this.renderForkStep()}
|
{this.renderForkStep()}
|
||||||
|
@ -199,14 +202,15 @@ export default class SaveDbcModal extends Component {
|
||||||
{this.renderCommitMessage()}
|
{this.renderCommitMessage()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (tab === "Download") {
|
}
|
||||||
|
if (tab === 'Download') {
|
||||||
return <div>{this.renderFilenameField()}</div>;
|
return <div>{this.renderFilenameField()}</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderActions() {
|
renderActions() {
|
||||||
const { tab } = this.state;
|
const { tab } = this.state;
|
||||||
if (tab === "GitHub") {
|
if (tab === 'GitHub') {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<button className="button--inverted" onClick={this.props.handleClose}>
|
<button className="button--inverted" onClick={this.props.handleClose}>
|
||||||
|
@ -217,7 +221,8 @@ export default class SaveDbcModal extends Component {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (tab === "Download") {
|
}
|
||||||
|
if (tab === 'Download') {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<button className="button--inverted" onClick={this.props.handleClose}>
|
<button className="button--inverted" onClick={this.props.handleClose}>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// SignalLegend.js
|
// SignalLegend.js
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import SignalLegendEntry from "./SignalLegendEntry";
|
import SignalLegendEntry from './SignalLegendEntry';
|
||||||
|
|
||||||
export default class SignalLegend extends Component {
|
export default class SignalLegend extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -23,13 +23,13 @@ export default class SignalLegend extends Component {
|
||||||
expandedSignals: []
|
expandedSignals: []
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleExpandSignal = s => {
|
toggleExpandSignal = (s) => {
|
||||||
const { expandedSignals } = this.state;
|
const { expandedSignals } = this.state;
|
||||||
if (!expandedSignals.includes(s.uid)) {
|
if (!expandedSignals.includes(s.uid)) {
|
||||||
const updatedExpandedSignals = [...expandedSignals, s.uid];
|
const updatedExpandedSignals = [...expandedSignals, s.uid];
|
||||||
this.setState({ expandedSignals: updatedExpandedSignals });
|
this.setState({ expandedSignals: updatedExpandedSignals });
|
||||||
} else {
|
} else {
|
||||||
const updatedExpandedSignals = expandedSignals.filter(i => i !== s.uid);
|
const updatedExpandedSignals = expandedSignals.filter((i) => i !== s.uid);
|
||||||
this.setState({ expandedSignals: updatedExpandedSignals });
|
this.setState({ expandedSignals: updatedExpandedSignals });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -44,9 +44,8 @@ export default class SignalLegend extends Component {
|
||||||
.sort(([_, signal1], [__, signal2]) => {
|
.sort(([_, signal1], [__, signal2]) => {
|
||||||
if (signal1.startBit < signal2.startBit) {
|
if (signal1.startBit < signal2.startBit) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
return 1;
|
||||||
})
|
})
|
||||||
.map(([signalName, signal]) => {
|
.map(([signalName, signal]) => {
|
||||||
const { colors } = signals[signalName];
|
const { colors } = signals[signalName];
|
||||||
|
@ -73,10 +72,8 @@ export default class SignalLegend extends Component {
|
||||||
});
|
});
|
||||||
|
|
||||||
const signalRows = signalRowsNested
|
const signalRows = signalRowsNested
|
||||||
.filter(row => row != null)
|
.filter((row) => row != null)
|
||||||
.reduce((a, b) => {
|
.reduce((a, b) => a.concat(b), []);
|
||||||
return a.concat(b);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return <div className="cabana-explorer-signals-legend">{signalRows}</div>;
|
return <div className="cabana-explorer-signals-legend">{signalRows}</div>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import styled from "react-emotion";
|
import styled from 'react-emotion';
|
||||||
|
|
||||||
// color bar on the left side of the signals legend
|
// color bar on the left side of the signals legend
|
||||||
export default styled("div")`
|
export default styled('div')`
|
||||||
display: block;
|
display: block;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
left: 0;
|
left: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 1.5%;
|
width: 1.5%;
|
||||||
opacity: ${({ isHighlighted }) => (isHighlighted ? 0.5 : 0.3)};
|
opacity: ${({ isHighlighted }) => (isHighlighted ? 0.5 : 0.3)};
|
||||||
background-color: rgb(${({ rgb }) => rgb.join(",")});
|
background-color: rgb(${({ rgb }) => rgb.join(',')});
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -1,44 +1,41 @@
|
||||||
import DbcUtils from "../../utils/dbc";
|
import DbcUtils from '../../utils/dbc';
|
||||||
|
|
||||||
const unsignedTransformation = field => {
|
const unsignedTransformation = (field) => (value, signal) => {
|
||||||
return (value, signal) => {
|
if (value !== '') {
|
||||||
if (value !== "") {
|
value = Number(value) || 0;
|
||||||
value = Number(value) || 0;
|
|
||||||
|
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
value = 0;
|
value = 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
signal[field] = value;
|
}
|
||||||
return signal;
|
signal[field] = value;
|
||||||
};
|
return signal;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
field: "name",
|
field: 'name',
|
||||||
title: "Name",
|
title: 'Name',
|
||||||
type: "string"
|
type: 'string'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "size",
|
field: 'size',
|
||||||
title: "Size",
|
title: 'Size',
|
||||||
type: "number",
|
type: 'number',
|
||||||
transform: unsignedTransformation("size")
|
transform: unsignedTransformation('size')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "startBit",
|
field: 'startBit',
|
||||||
title: signal =>
|
title: (signal) => (signal.isLittleEndian ? 'Least significant bit' : 'Most significant bit'),
|
||||||
signal.isLittleEndian ? "Least significant bit" : "Most significant bit",
|
type: 'number',
|
||||||
type: "number",
|
transform: unsignedTransformation('startBit')
|
||||||
transform: unsignedTransformation("startBit")
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "isLittleEndian",
|
field: 'isLittleEndian',
|
||||||
title: "Endianness",
|
title: 'Endianness',
|
||||||
type: "option",
|
type: 'option',
|
||||||
options: {
|
options: {
|
||||||
options: ["Little", "Big"],
|
options: ['Little', 'Big'],
|
||||||
optionValues: { Little: true, Big: false }
|
optionValues: { Little: true, Big: false }
|
||||||
},
|
},
|
||||||
transform: (isLittleEndian, signal) => {
|
transform: (isLittleEndian, signal) => {
|
||||||
|
@ -47,8 +44,8 @@ export default [
|
||||||
|
|
||||||
if (isLittleEndian) {
|
if (isLittleEndian) {
|
||||||
// big endian -> little endian
|
// big endian -> little endian
|
||||||
const startByte = Math.floor(signal.startBit / 8),
|
const startByte = Math.floor(signal.startBit / 8);
|
||||||
endByte = Math.floor((signal.startBit - signal.size + 1) / 8);
|
const endByte = Math.floor((signal.startBit - signal.size + 1) / 8);
|
||||||
|
|
||||||
if (startByte === endByte) {
|
if (startByte === endByte) {
|
||||||
signal.startBit = signal.startBit - signal.size + 1;
|
signal.startBit = signal.startBit - signal.size + 1;
|
||||||
|
@ -57,8 +54,8 @@ export default [
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// little endian -> big endian
|
// little endian -> big endian
|
||||||
const startByte = Math.floor(signal.startBit / 8),
|
const startByte = Math.floor(signal.startBit / 8);
|
||||||
endByte = Math.floor((signal.startBit + signal.size - 1) / 8);
|
const endByte = Math.floor((signal.startBit + signal.size - 1) / 8);
|
||||||
|
|
||||||
if (startByte === endByte) {
|
if (startByte === endByte) {
|
||||||
signal.startBit = signal.startBit + signal.size - 1;
|
signal.startBit = signal.startBit + signal.size - 1;
|
||||||
|
@ -72,42 +69,42 @@ export default [
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "isSigned",
|
field: 'isSigned',
|
||||||
title: "Sign",
|
title: 'Sign',
|
||||||
type: "option",
|
type: 'option',
|
||||||
options: {
|
options: {
|
||||||
options: ["Signed", "Unsigned"],
|
options: ['Signed', 'Unsigned'],
|
||||||
optionValues: { Signed: true, Unsigned: false }
|
optionValues: { Signed: true, Unsigned: false }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "factor",
|
field: 'factor',
|
||||||
title: "Factor",
|
title: 'Factor',
|
||||||
type: "number"
|
type: 'number'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "offset",
|
field: 'offset',
|
||||||
title: "Offset",
|
title: 'Offset',
|
||||||
type: "number"
|
type: 'number'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "unit",
|
field: 'unit',
|
||||||
title: "Unit",
|
title: 'Unit',
|
||||||
type: "string"
|
type: 'string'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "comment",
|
field: 'comment',
|
||||||
title: "Comment",
|
title: 'Comment',
|
||||||
type: "string"
|
type: 'string'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "min",
|
field: 'min',
|
||||||
title: "Minimum value",
|
title: 'Minimum value',
|
||||||
type: "number"
|
type: 'number'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "max",
|
field: 'max',
|
||||||
title: "Maximum value",
|
title: 'Maximum value',
|
||||||
type: "number"
|
type: 'number'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
export default class Field extends Component {
|
export default class Field extends Component {
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import Field from "./Field";
|
import Field from './Field';
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
fieldSpec,
|
fieldSpec,
|
||||||
|
@ -14,27 +14,27 @@ export default ({
|
||||||
|
|
||||||
if (isExpanded) {
|
if (isExpanded) {
|
||||||
let value = signalEdited;
|
let value = signalEdited;
|
||||||
if (value !== "") {
|
if (value !== '') {
|
||||||
let num = Number(value);
|
const num = Number(value);
|
||||||
value = isNaN(num) ? "" : num;
|
value = isNaN(num) ? '' : num;
|
||||||
}
|
}
|
||||||
valueCol = (
|
valueCol = (
|
||||||
<input
|
<input
|
||||||
id={htmlFor}
|
id={htmlFor}
|
||||||
type="number"
|
type="number"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={e => {
|
onChange={(e) => {
|
||||||
updateField(fieldSpec, e.target.value);
|
updateField(fieldSpec, e.target.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let value = signal[field];
|
const value = signal[field];
|
||||||
valueCol = <span>{value}</span>;
|
valueCol = <span>{value}</span>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Field
|
<Field
|
||||||
title={typeof title === "function" ? title(signal) : title}
|
title={typeof title === 'function' ? title(signal) : title}
|
||||||
htmlFor={htmlFor}
|
htmlFor={htmlFor}
|
||||||
>
|
>
|
||||||
{valueCol}
|
{valueCol}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import Field from "./Field";
|
import Field from './Field';
|
||||||
|
|
||||||
import { swapKeysAndValues } from "../../utils/object";
|
import { swapKeysAndValues } from '../../utils/object';
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
fieldSpec,
|
fieldSpec,
|
||||||
|
@ -14,10 +14,10 @@ export default ({
|
||||||
const { field, title } = fieldSpec;
|
const { field, title } = fieldSpec;
|
||||||
const htmlFor = `${signal.name}_${field}`;
|
const htmlFor = `${signal.name}_${field}`;
|
||||||
const { options, optionValues } = fieldSpec.options;
|
const { options, optionValues } = fieldSpec.options;
|
||||||
let valueOptions = swapKeysAndValues(optionValues);
|
const valueOptions = swapKeysAndValues(optionValues);
|
||||||
|
|
||||||
if (isExpanded) {
|
if (isExpanded) {
|
||||||
const optionEles = options.map(opt => (
|
const optionEles = options.map((opt) => (
|
||||||
<option key={opt} value={optionValues[opt]}>
|
<option key={opt} value={optionValues[opt]}>
|
||||||
{opt}
|
{opt}
|
||||||
</option>
|
</option>
|
||||||
|
@ -26,8 +26,8 @@ export default ({
|
||||||
<select
|
<select
|
||||||
id={htmlFor}
|
id={htmlFor}
|
||||||
defaultValue={signalEdited}
|
defaultValue={signalEdited}
|
||||||
onChange={e => {
|
onChange={(e) => {
|
||||||
updateField(fieldSpec, e.target.value === "true");
|
updateField(fieldSpec, e.target.value === 'true');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{optionEles}
|
{optionEles}
|
||||||
|
@ -39,7 +39,7 @@ export default ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Field
|
<Field
|
||||||
title={typeof title === "function" ? title(signal) : title}
|
title={typeof title === 'function' ? title(signal) : title}
|
||||||
htmlFor={htmlFor}
|
htmlFor={htmlFor}
|
||||||
>
|
>
|
||||||
{valueCol}
|
{valueCol}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
|
|
||||||
import FIELDS from "./FIELDS";
|
import FIELDS from './FIELDS';
|
||||||
import NumberField from "./NumberField";
|
import NumberField from './NumberField';
|
||||||
import StringField from "./StringField";
|
import StringField from './StringField';
|
||||||
import OptionField from "./OptionField";
|
import OptionField from './OptionField';
|
||||||
|
|
||||||
const FieldMap = {
|
const FieldMap = {
|
||||||
number: NumberField,
|
number: NumberField,
|
||||||
|
@ -17,31 +17,29 @@ export default ({
|
||||||
isExpanded,
|
isExpanded,
|
||||||
getSignalEdited,
|
getSignalEdited,
|
||||||
update
|
update
|
||||||
}) => {
|
}) => (
|
||||||
return (
|
<div className="signals-legend-entry-form">
|
||||||
<div className="signals-legend-entry-form">
|
{FIELDS.map((field) => {
|
||||||
{FIELDS.map(field => {
|
const Node = FieldMap[field.type];
|
||||||
const Node = FieldMap[field.type];
|
return (
|
||||||
return (
|
<div className="signals-legend-entry-form-field" key={field.field}>
|
||||||
<div className="signals-legend-entry-form-field" key={field.field}>
|
<Node
|
||||||
<Node
|
fieldSpec={field}
|
||||||
fieldSpec={field}
|
signal={signal}
|
||||||
signal={signal}
|
isExpanded={isExpanded}
|
||||||
isExpanded={isExpanded}
|
signalEdited={getSignalEdited(field.field)}
|
||||||
signalEdited={getSignalEdited(field.field)}
|
updateField={update}
|
||||||
updateField={update}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
})}
|
||||||
})}
|
<div className="signals-legend-entry-form-remove">
|
||||||
<div className="signals-legend-entry-form-remove">
|
<button
|
||||||
<button
|
className="button--tiny button--alpha"
|
||||||
className="button--tiny button--alpha"
|
onClick={() => onSignalRemove(signal)}
|
||||||
onClick={() => onSignalRemove(signal)}
|
>
|
||||||
>
|
Remove Signal
|
||||||
Remove Signal
|
</button>
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
};
|
);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import Field from "./Field";
|
import Field from './Field';
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
fieldSpec,
|
fieldSpec,
|
||||||
|
@ -16,8 +16,8 @@ export default ({
|
||||||
<input
|
<input
|
||||||
id={htmlFor}
|
id={htmlFor}
|
||||||
type="text"
|
type="text"
|
||||||
value={signalEdited || ""}
|
value={signalEdited || ''}
|
||||||
onChange={e => {
|
onChange={(e) => {
|
||||||
updateField(fieldSpec, e.target.value);
|
updateField(fieldSpec, e.target.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -28,7 +28,7 @@ export default ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Field
|
<Field
|
||||||
title={typeof title === "function" ? title(signal) : title}
|
title={typeof title === 'function' ? title(signal) : title}
|
||||||
htmlFor={htmlFor}
|
htmlFor={htmlFor}
|
||||||
>
|
>
|
||||||
{valueCol}
|
{valueCol}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// SignalLegendEntry.js
|
// SignalLegendEntry.js
|
||||||
|
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from 'prop-types';
|
||||||
import cx from "classnames";
|
import cx from 'classnames';
|
||||||
|
|
||||||
import Signal from "../../models/can/signal";
|
import Signal from '../../models/can/signal';
|
||||||
import SignalForm from "./SignalForm";
|
import SignalForm from './SignalForm';
|
||||||
import ColorBar from "./ColorBar";
|
import ColorBar from './ColorBar';
|
||||||
import FIELDS from "./FIELDS";
|
import FIELDS from './FIELDS';
|
||||||
|
|
||||||
export default class SignalLegendEntry extends Component {
|
export default class SignalLegendEntry extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -25,9 +25,7 @@ export default class SignalLegendEntry extends Component {
|
||||||
isExpanded: PropTypes.bool
|
isExpanded: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
||||||
static fieldSpecForName = name => {
|
static fieldSpecForName = (name) => FIELDS.find((field) => field.field === name);
|
||||||
return FIELDS.find(field => field.field === name);
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -66,7 +64,7 @@ export default class SignalLegendEntry extends Component {
|
||||||
this.props.onSignalChange(signalCopy, signal);
|
this.props.onSignalChange(signalCopy, signal);
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleEditing = e => {
|
toggleEditing = (e) => {
|
||||||
if (this.props.isLogEvent) {
|
if (this.props.isLogEvent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -81,9 +79,9 @@ export default class SignalLegendEntry extends Component {
|
||||||
const fieldSpec = SignalLegendEntry.fieldSpecForName(field);
|
const fieldSpec = SignalLegendEntry.fieldSpecForName(field);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
fieldSpec &&
|
fieldSpec
|
||||||
fieldSpec.type === "number" &&
|
&& fieldSpec.type === 'number'
|
||||||
isNaN(parseInt(value, 10))
|
&& isNaN(parseInt(value, 10))
|
||||||
) {
|
) {
|
||||||
value = 0;
|
value = 0;
|
||||||
}
|
}
|
||||||
|
@ -103,22 +101,23 @@ export default class SignalLegendEntry extends Component {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleSignalPlot = e => {
|
toggleSignalPlot = (e) => {
|
||||||
const { signal, isPlotted } = this.props;
|
const { signal, isPlotted } = this.props;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.onSignalPlotChange(!isPlotted, signal.uid);
|
this.props.onSignalPlotChange(!isPlotted, signal.uid);
|
||||||
};
|
};
|
||||||
|
|
||||||
getSignalEdited = field => {
|
getSignalEdited = (field) => this.state.signalEdited[field];
|
||||||
return this.state.signalEdited[field];
|
|
||||||
};
|
|
||||||
render() {
|
render() {
|
||||||
const { signal, isHighlighted, color, isPlotted, isExpanded } = this.props;
|
const {
|
||||||
const expandedEntryClass = isExpanded ? "is-expanded" : null;
|
signal, isHighlighted, color, isPlotted, isExpanded
|
||||||
const plottedButtonClass = isPlotted ? "button" : "button--alpha";
|
} = this.props;
|
||||||
|
const expandedEntryClass = isExpanded ? 'is-expanded' : null;
|
||||||
|
const plottedButtonClass = isPlotted ? 'button' : 'button--alpha';
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cx("signals-legend-entry", expandedEntryClass)}
|
className={cx('signals-legend-entry', expandedEntryClass)}
|
||||||
onMouseEnter={() => this.props.onSignalHover(signal)}
|
onMouseEnter={() => this.props.onSignalHover(signal)}
|
||||||
onMouseLeave={() => this.props.onSignalHoverEnd(signal)}
|
onMouseLeave={() => this.props.onSignalHoverEnd(signal)}
|
||||||
>
|
>
|
||||||
|
@ -134,8 +133,8 @@ export default class SignalLegendEntry extends Component {
|
||||||
className="signals-legend-entry-header-action"
|
className="signals-legend-entry-header-action"
|
||||||
onClick={this.toggleSignalPlot}
|
onClick={this.toggleSignalPlot}
|
||||||
>
|
>
|
||||||
<button className={cx("button--tiny", plottedButtonClass)}>
|
<button className={cx('button--tiny', plottedButtonClass)}>
|
||||||
{isPlotted ? "Hide Plot" : "Show Plot"}
|
{isPlotted ? 'Hide Plot' : 'Show Plot'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import SignalLegendEntry from ".";
|
import React from 'react';
|
||||||
import Signal from "../../models/can/signal";
|
import { shallow, mount, render } from 'enzyme';
|
||||||
import React from "react";
|
import { StyleSheetTestUtils } from 'aphrodite';
|
||||||
import { shallow, mount, render } from "enzyme";
|
import Signal from '../../models/can/signal';
|
||||||
import { StyleSheetTestUtils } from "aphrodite";
|
import SignalLegendEntry from '.';
|
||||||
|
|
||||||
// Prevents style injection from firing after test finishes
|
// Prevents style injection from firing after test finishes
|
||||||
// and jsdom is torn down.
|
// and jsdom is torn down.
|
||||||
|
@ -14,11 +14,11 @@ afterEach(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function createSignalLegendEntry(props) {
|
function createSignalLegendEntry(props) {
|
||||||
let signal = props.signal,
|
let { signal } = props;
|
||||||
onSignalChange = props.onSignalChange,
|
let { onSignalChange } = props;
|
||||||
onTentativeSignalChange = props.onTentativeSignalChange;
|
let { onTentativeSignalChange } = props;
|
||||||
if (signal === undefined) {
|
if (signal === undefined) {
|
||||||
signal = new Signal({ name: "NEW_SIGNAL" });
|
signal = new Signal({ name: 'NEW_SIGNAL' });
|
||||||
}
|
}
|
||||||
if (onSignalChange === undefined) {
|
if (onSignalChange === undefined) {
|
||||||
onSignalChange = () => {};
|
onSignalChange = () => {};
|
||||||
|
@ -37,9 +37,9 @@ function createSignalLegendEntry(props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
test("a little endian signal spanning one byte should adjust its startBit switching to big endian, preserving its bit coverage", () => {
|
test('a little endian signal spanning one byte should adjust its startBit switching to big endian, preserving its bit coverage', () => {
|
||||||
const signal = new Signal({
|
const signal = new Signal({
|
||||||
name: "signal",
|
name: 'signal',
|
||||||
startBit: 0,
|
startBit: 0,
|
||||||
size: 8,
|
size: 8,
|
||||||
isLittleEndian: true
|
isLittleEndian: true
|
||||||
|
@ -47,30 +47,30 @@ test("a little endian signal spanning one byte should adjust its startBit switch
|
||||||
|
|
||||||
const component = createSignalLegendEntry({ signal });
|
const component = createSignalLegendEntry({ signal });
|
||||||
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
|
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
|
||||||
"isLittleEndian"
|
'isLittleEndian'
|
||||||
);
|
);
|
||||||
component.instance().updateField(endiannessFieldSpec, false);
|
component.instance().updateField(endiannessFieldSpec, false);
|
||||||
|
|
||||||
const signalEdited = component.state("signalEdited");
|
const signalEdited = component.state('signalEdited');
|
||||||
expect(signalEdited.isLittleEndian).toBe(false);
|
expect(signalEdited.isLittleEndian).toBe(false);
|
||||||
expect(signalEdited.startBit).toBe(7);
|
expect(signalEdited.startBit).toBe(7);
|
||||||
expect(signalEdited.size).toBe(8);
|
expect(signalEdited.size).toBe(8);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("a big endian signal spanning two bytes should should adjust its startBit switching to little endian, preserving its bit coverage", () => {
|
test('a big endian signal spanning two bytes should should adjust its startBit switching to little endian, preserving its bit coverage', () => {
|
||||||
const signal = new Signal({
|
const signal = new Signal({
|
||||||
name: "signal",
|
name: 'signal',
|
||||||
startBit: 7,
|
startBit: 7,
|
||||||
size: 8,
|
size: 8,
|
||||||
isLittleEndian: false
|
isLittleEndian: false
|
||||||
});
|
});
|
||||||
const component = createSignalLegendEntry({ signal });
|
const component = createSignalLegendEntry({ signal });
|
||||||
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
|
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
|
||||||
"isLittleEndian"
|
'isLittleEndian'
|
||||||
);
|
);
|
||||||
component.instance().updateField(endiannessFieldSpec, true);
|
component.instance().updateField(endiannessFieldSpec, true);
|
||||||
|
|
||||||
const signalEdited = component.state("signalEdited");
|
const signalEdited = component.state('signalEdited');
|
||||||
expect(signalEdited.isLittleEndian).toBe(true);
|
expect(signalEdited.isLittleEndian).toBe(true);
|
||||||
expect(signalEdited.startBit).toBe(0);
|
expect(signalEdited.startBit).toBe(0);
|
||||||
expect(signalEdited.size).toBe(8);
|
expect(signalEdited.size).toBe(8);
|
||||||
|
@ -78,7 +78,7 @@ test("a big endian signal spanning two bytes should should adjust its startBit s
|
||||||
|
|
||||||
test("a big endian signal spanning one and a half bytes should adjust its startBit switching to little endian, preserving the first byte's coverage", () => {
|
test("a big endian signal spanning one and a half bytes should adjust its startBit switching to little endian, preserving the first byte's coverage", () => {
|
||||||
const signal = new Signal({
|
const signal = new Signal({
|
||||||
name: "signal",
|
name: 'signal',
|
||||||
startBit: 7,
|
startBit: 7,
|
||||||
size: 12,
|
size: 12,
|
||||||
isLittleEndian: false
|
isLittleEndian: false
|
||||||
|
@ -86,49 +86,49 @@ test("a big endian signal spanning one and a half bytes should adjust its startB
|
||||||
|
|
||||||
const component = createSignalLegendEntry({ signal });
|
const component = createSignalLegendEntry({ signal });
|
||||||
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
|
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
|
||||||
"isLittleEndian"
|
'isLittleEndian'
|
||||||
);
|
);
|
||||||
component.instance().updateField(endiannessFieldSpec, true);
|
component.instance().updateField(endiannessFieldSpec, true);
|
||||||
|
|
||||||
const signalEdited = component.state("signalEdited");
|
const signalEdited = component.state('signalEdited');
|
||||||
expect(signalEdited.isLittleEndian).toBe(true);
|
expect(signalEdited.isLittleEndian).toBe(true);
|
||||||
expect(signalEdited.startBit).toBe(0);
|
expect(signalEdited.startBit).toBe(0);
|
||||||
expect(signalEdited.size).toBe(12);
|
expect(signalEdited.size).toBe(12);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("a little endian signal spanning 3 bits on one byte should adjust its startBit switching to big endian, preserving its bit coverage", () => {
|
test('a little endian signal spanning 3 bits on one byte should adjust its startBit switching to big endian, preserving its bit coverage', () => {
|
||||||
const signal = new Signal({
|
const signal = new Signal({
|
||||||
name: "signal",
|
name: 'signal',
|
||||||
startBit: 13,
|
startBit: 13,
|
||||||
size: 3,
|
size: 3,
|
||||||
isLittleEndian: true
|
isLittleEndian: true
|
||||||
});
|
});
|
||||||
const component = createSignalLegendEntry({ signal });
|
const component = createSignalLegendEntry({ signal });
|
||||||
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
|
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
|
||||||
"isLittleEndian"
|
'isLittleEndian'
|
||||||
);
|
);
|
||||||
component.instance().updateField(endiannessFieldSpec, false);
|
component.instance().updateField(endiannessFieldSpec, false);
|
||||||
|
|
||||||
const signalEdited = component.state("signalEdited");
|
const signalEdited = component.state('signalEdited');
|
||||||
expect(signalEdited.isLittleEndian).toBe(false);
|
expect(signalEdited.isLittleEndian).toBe(false);
|
||||||
expect(signalEdited.startBit).toBe(15);
|
expect(signalEdited.startBit).toBe(15);
|
||||||
expect(signalEdited.size).toBe(3);
|
expect(signalEdited.size).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("a big endian signal spanning 3 bytes on one byte should adjust its startBit switching to little endian, preserving its bit coverage", () => {
|
test('a big endian signal spanning 3 bytes on one byte should adjust its startBit switching to little endian, preserving its bit coverage', () => {
|
||||||
const signal = new Signal({
|
const signal = new Signal({
|
||||||
name: "signal",
|
name: 'signal',
|
||||||
startBit: 15,
|
startBit: 15,
|
||||||
size: 3,
|
size: 3,
|
||||||
isLittleEndian: false
|
isLittleEndian: false
|
||||||
});
|
});
|
||||||
const component = createSignalLegendEntry({ signal });
|
const component = createSignalLegendEntry({ signal });
|
||||||
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
|
const endiannessFieldSpec = SignalLegendEntry.fieldSpecForName(
|
||||||
"isLittleEndian"
|
'isLittleEndian'
|
||||||
);
|
);
|
||||||
component.instance().updateField(endiannessFieldSpec, true);
|
component.instance().updateField(endiannessFieldSpec, true);
|
||||||
|
|
||||||
const signalEdited = component.state("signalEdited");
|
const signalEdited = component.state('signalEdited');
|
||||||
expect(signalEdited.isLittleEndian).toBe(true);
|
expect(signalEdited.isLittleEndian).toBe(true);
|
||||||
expect(signalEdited.startBit).toBe(13);
|
expect(signalEdited.startBit).toBe(13);
|
||||||
expect(signalEdited.size).toBe(3);
|
expect(signalEdited.size).toBe(3);
|
||||||
|
|
|
@ -1,26 +1,25 @@
|
||||||
import { getUrlParameter } from "./utils/url";
|
import { getUrlParameter } from './utils/url';
|
||||||
|
|
||||||
const ENV = process.env.NODE_ENV === "production" ? "prod" : "debug";
|
const ENV = process.env.NODE_ENV === 'production' ? 'prod' : 'debug';
|
||||||
|
|
||||||
const ENV_GITHUB_CLIENT_ID = {
|
const ENV_GITHUB_CLIENT_ID = {
|
||||||
debug: "f1e42d14f45491f9ca34",
|
debug: 'f1e42d14f45491f9ca34',
|
||||||
prod: "4b43250e7499a97d62a5"
|
prod: '4b43250e7499a97d62a5'
|
||||||
};
|
};
|
||||||
export const GITHUB_CLIENT_ID = ENV_GITHUB_CLIENT_ID[ENV];
|
export const GITHUB_CLIENT_ID = ENV_GITHUB_CLIENT_ID[ENV];
|
||||||
|
|
||||||
const ENV_GITHUB_REDIRECT_URL = {
|
const ENV_GITHUB_REDIRECT_URL = {
|
||||||
debug: "http://127.0.0.1:1235/callback",
|
debug: 'http://127.0.0.1:1235/callback',
|
||||||
prod: "https://api.comma.ai/cabana/ghcallback"
|
prod: 'https://api.comma.ai/cabana/ghcallback'
|
||||||
};
|
};
|
||||||
export const GITHUB_REDIRECT_URL = ENV_GITHUB_REDIRECT_URL[ENV];
|
export const GITHUB_REDIRECT_URL = ENV_GITHUB_REDIRECT_URL[ENV];
|
||||||
export const GITHUB_AUTH_TOKEN_KEY = "gh_access_token";
|
export const GITHUB_AUTH_TOKEN_KEY = 'gh_access_token';
|
||||||
export const OPENDBC_SOURCE_REPO = "commaai/opendbc";
|
export const OPENDBC_SOURCE_REPO = 'commaai/opendbc';
|
||||||
|
|
||||||
export const USE_UNLOGGER =
|
export const USE_UNLOGGER = typeof window !== 'undefined' && getUrlParameter('unlogger') !== null;
|
||||||
typeof window !== "undefined" && getUrlParameter("unlogger") !== null;
|
export const UNLOGGER_HOST = 'http://localhost:8080/unlogger';
|
||||||
export const UNLOGGER_HOST = "http://localhost:8080/unlogger";
|
|
||||||
|
|
||||||
export const LOGENTRIES_TOKEN = "4bc98019-8277-4fe0-867c-ed21ea843cc5";
|
export const LOGENTRIES_TOKEN = '4bc98019-8277-4fe0-867c-ed21ea843cc5';
|
||||||
|
|
||||||
export const PART_SEGMENT_LENGTH = 3;
|
export const PART_SEGMENT_LENGTH = 3;
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ export const CAN_GRAPH_MAX_POINTS = 5000;
|
||||||
export const STREAMING_WINDOW = 60;
|
export const STREAMING_WINDOW = 60;
|
||||||
|
|
||||||
const ENV_EXPLORER_URL = {
|
const ENV_EXPLORER_URL = {
|
||||||
debug: "http://127.0.0.1:3000/",
|
debug: 'http://127.0.0.1:3000/',
|
||||||
prod: "https://my.comma.ai/"
|
prod: 'https://my.comma.ai/'
|
||||||
};
|
};
|
||||||
export const EXPLORER_URL = ENV_EXPLORER_URL[ENV];
|
export const EXPLORER_URL = ENV_EXPLORER_URL[ENV];
|
||||||
|
|
63
src/index.js
63
src/index.js
|
@ -1,37 +1,37 @@
|
||||||
import Sentry from "./logging/Sentry";
|
import React from 'react';
|
||||||
import React from "react";
|
import ReactDOM from 'react-dom';
|
||||||
import ReactDOM from "react-dom";
|
import CommaAuth from '@commaai/my-comma-auth';
|
||||||
import CommaAuth from "@commaai/my-comma-auth";
|
import { request as Request } from '@commaai/comma-api';
|
||||||
import { request as Request } from "@commaai/comma-api";
|
import Sentry from './logging/Sentry';
|
||||||
import CanExplorer from "./CanExplorer";
|
import CanExplorer from './CanExplorer';
|
||||||
import AcuraDbc from "./acura-dbc";
|
import AcuraDbc from './acura-dbc';
|
||||||
import { getUrlParameter, modifyQueryParameters } from "./utils/url";
|
import { getUrlParameter, modifyQueryParameters } from './utils/url';
|
||||||
import { GITHUB_AUTH_TOKEN_KEY } from "./config";
|
import { GITHUB_AUTH_TOKEN_KEY } from './config';
|
||||||
import {
|
import {
|
||||||
fetchPersistedDbc,
|
fetchPersistedDbc,
|
||||||
fetchPersistedGithubAuthToken,
|
fetchPersistedGithubAuthToken,
|
||||||
persistGithubAuthToken
|
persistGithubAuthToken
|
||||||
} from "./api/localstorage";
|
} from './api/localstorage';
|
||||||
import "./index.css";
|
import './index.css';
|
||||||
|
|
||||||
Sentry.init();
|
Sentry.init();
|
||||||
|
|
||||||
const routeFullName = getUrlParameter("route");
|
const routeFullName = getUrlParameter('route');
|
||||||
let isDemo = !routeFullName;
|
const isDemo = !routeFullName;
|
||||||
let props = { autoplay: true, isDemo };
|
const props = { autoplay: true, isDemo };
|
||||||
let persistedDbc = null;
|
let persistedDbc = null;
|
||||||
|
|
||||||
if (routeFullName) {
|
if (routeFullName) {
|
||||||
const [dongleId, route] = routeFullName.split("|");
|
const [dongleId, route] = routeFullName.split('|');
|
||||||
props.dongleId = dongleId;
|
props.dongleId = dongleId;
|
||||||
props.name = route;
|
props.name = route;
|
||||||
|
|
||||||
persistedDbc = fetchPersistedDbc(routeFullName);
|
persistedDbc = fetchPersistedDbc(routeFullName);
|
||||||
|
|
||||||
let max = getUrlParameter("max"),
|
const max = getUrlParameter('max');
|
||||||
url = getUrlParameter("url"),
|
const url = getUrlParameter('url');
|
||||||
exp = getUrlParameter("exp"),
|
const exp = getUrlParameter('exp');
|
||||||
sig = getUrlParameter("sig");
|
const sig = getUrlParameter('sig');
|
||||||
|
|
||||||
if (max) {
|
if (max) {
|
||||||
props.max = max;
|
props.max = max;
|
||||||
|
@ -47,15 +47,14 @@ if (routeFullName) {
|
||||||
}
|
}
|
||||||
props.isLegacyShare = max && url && !exp && !sig;
|
props.isLegacyShare = max && url && !exp && !sig;
|
||||||
props.isShare = max && url && exp && sig;
|
props.isShare = max && url && exp && sig;
|
||||||
} else if (getUrlParameter("demo")) {
|
} else if (getUrlParameter('demo')) {
|
||||||
props.max = 12;
|
props.max = 12;
|
||||||
props.url =
|
props.url = 'https://chffrprivate.blob.core.windows.net/chffrprivate3-permanent/v2/cb38263377b873ee/78392b99580c5920227cc5b43dff8a70_2017-06-12--18-51-47';
|
||||||
"https://chffrprivate.blob.core.windows.net/chffrprivate3-permanent/v2/cb38263377b873ee/78392b99580c5920227cc5b43dff8a70_2017-06-12--18-51-47";
|
props.name = '2017-06-12--18-51-47';
|
||||||
props.name = "2017-06-12--18-51-47";
|
props.dongleId = 'cb38263377b873ee';
|
||||||
props.dongleId = "cb38263377b873ee";
|
|
||||||
props.dbc = AcuraDbc;
|
props.dbc = AcuraDbc;
|
||||||
props.isDemo = true;
|
props.isDemo = true;
|
||||||
props.dbcFilename = "acura_ilx_2016_can.dbc";
|
props.dbcFilename = 'acura_ilx_2016_can.dbc';
|
||||||
|
|
||||||
// lots of 404s on this one
|
// lots of 404s on this one
|
||||||
// props.max = 752;
|
// props.max = 752;
|
||||||
|
@ -97,17 +96,17 @@ async function init() {
|
||||||
if (token) {
|
if (token) {
|
||||||
Request.configure(token);
|
Request.configure(token);
|
||||||
}
|
}
|
||||||
ReactDOM.render(<CanExplorer {...props} />, document.getElementById("root"));
|
ReactDOM.render(<CanExplorer {...props} />, document.getElementById('root'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (routeFullName || isDemo) {
|
if (routeFullName || isDemo) {
|
||||||
init();
|
init();
|
||||||
} else {
|
} else {
|
||||||
const img = document.createElement("img");
|
const img = document.createElement('img');
|
||||||
img.src = process.env.PUBLIC_URL + "/img/cabana.jpg";
|
img.src = `${process.env.PUBLIC_URL}/img/cabana.jpg`;
|
||||||
img.style.width = "100%";
|
img.style.width = '100%';
|
||||||
const comment = document.createComment("7/6/17");
|
const comment = document.createComment('7/6/17');
|
||||||
|
|
||||||
document.getElementById("root").appendChild(img);
|
document.getElementById('root').appendChild(img);
|
||||||
document.getElementById("root").appendChild(comment);
|
document.getElementById('root').appendChild(comment);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import LogEntries from "./LogEntries";
|
import LogEntries from './LogEntries';
|
||||||
import { LOGENTRIES_TOKEN } from "../config";
|
import { LOGENTRIES_TOKEN } from '../config';
|
||||||
|
|
||||||
class CloudLog {
|
class CloudLog {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -15,8 +15,8 @@ class CloudLog {
|
||||||
this.context.update(obj);
|
this.context.update(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(message, level = "log") {
|
emit(message, level = 'log') {
|
||||||
if (typeof global.__JEST__ !== "undefined") {
|
if (typeof global.__JEST__ !== 'undefined') {
|
||||||
// Don't log in testing environment
|
// Don't log in testing environment
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -25,14 +25,14 @@ class CloudLog {
|
||||||
ctx: this.context,
|
ctx: this.context,
|
||||||
created: new Date().getTime() / 1000,
|
created: new Date().getTime() / 1000,
|
||||||
msg: message,
|
msg: message,
|
||||||
src: "JSCloudLog"
|
src: 'JSCloudLog'
|
||||||
};
|
};
|
||||||
|
|
||||||
if (level === "log") {
|
if (level === 'log') {
|
||||||
LogEntries.log(entry);
|
LogEntries.log(entry);
|
||||||
} else if (level === "warn") {
|
} else if (level === 'warn') {
|
||||||
LogEntries.warn(entry);
|
LogEntries.warn(entry);
|
||||||
} else if (level === "error") {
|
} else if (level === 'error') {
|
||||||
LogEntries.error(entry);
|
LogEntries.error(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,11 +42,11 @@ class CloudLog {
|
||||||
}
|
}
|
||||||
|
|
||||||
warn(message) {
|
warn(message) {
|
||||||
this.emit(message, "warn");
|
this.emit(message, 'warn');
|
||||||
}
|
}
|
||||||
|
|
||||||
error(message) {
|
error(message) {
|
||||||
this.emit(message, "error");
|
this.emit(message, 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import Raven from "raven-js";
|
import Raven from 'raven-js';
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
if (process.env.NODE_ENV === "production") {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
const opts = {};
|
const opts = {};
|
||||||
|
|
||||||
if (typeof __webpack_hash__ !== "undefined") {
|
if (typeof __webpack_hash__ !== 'undefined') {
|
||||||
opts["release"] = __webpack_hash__; // eslint-disable-line no-undef
|
opts.release = __webpack_hash__; // eslint-disable-line no-undef
|
||||||
}
|
}
|
||||||
|
|
||||||
Raven.config(
|
Raven.config(
|
||||||
"https://50006e5d91894f508dd288bbbf4585a6@sentry.io/185303",
|
'https://50006e5d91894f508dd288bbbf4585a6@sentry.io/185303',
|
||||||
opts
|
opts
|
||||||
).install();
|
).install();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const Uint64BE = require("int64-buffer").Uint64BE;
|
const { Uint64BE } = require('int64-buffer');
|
||||||
|
|
||||||
export function formatForMsg(msg) {
|
export function formatForMsg(msg) {
|
||||||
return { bstart: 0, bend: 15 };
|
return { bstart: 0, bend: 15 };
|
||||||
|
@ -7,7 +7,7 @@ export function formatForMsg(msg) {
|
||||||
export function formatMsgDec(msg) {
|
export function formatMsgDec(msg) {
|
||||||
const { bstart, bend } = formatForMsg(msg);
|
const { bstart, bend } = formatForMsg(msg);
|
||||||
const uint = Uint64BE(msg[1]);
|
const uint = Uint64BE(msg[1]);
|
||||||
var tt = "0" + uint.toString(2);
|
let tt = `0${uint.toString(2)}`;
|
||||||
tt = tt.substring(0, tt.length - (63 - bend));
|
tt = tt.substring(0, tt.length - (63 - bend));
|
||||||
tt = tt.substring(tt.length - (bend - bstart) - 1);
|
tt = tt.substring(tt.length - (bend - bstart) - 1);
|
||||||
return [msg[0], parseInt(tt, 2)];
|
return [msg[0], parseInt(tt, 2)];
|
||||||
|
@ -20,17 +20,17 @@ export function uint64BEToHex(int64) {
|
||||||
export function int64BufferToPrettyHexStr(buffer) {
|
export function int64BufferToPrettyHexStr(buffer) {
|
||||||
const uint = Uint64BE(buffer);
|
const uint = Uint64BE(buffer);
|
||||||
let hex = uint.toString(16);
|
let hex = uint.toString(16);
|
||||||
if (hex.length === 1) hex = "0" + hex;
|
if (hex.length === 1) hex = `0${hex}`;
|
||||||
let hexParts = hex.match(/.{1,2}/g);
|
const hexParts = hex.match(/.{1,2}/g);
|
||||||
|
|
||||||
return hexParts.join(" ");
|
return hexParts.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatMsgHex(msg) {
|
export function formatMsgHex(msg) {
|
||||||
const uint = Uint64BE(msg[1]);
|
const uint = Uint64BE(msg[1]);
|
||||||
let hex = uint.toString(16);
|
let hex = uint.toString(16);
|
||||||
if (hex.length === 1) hex = "0" + hex;
|
if (hex.length === 1) hex = `0${hex}`;
|
||||||
let hexParts = hex.match(/.{1,2}/g);
|
const hexParts = hex.match(/.{1,2}/g);
|
||||||
|
|
||||||
return [msg[0], hexParts.join(" ")];
|
return [msg[0], hexParts.join(' ')];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import rightPad from "right-pad";
|
import rightPad from 'right-pad';
|
||||||
import CloudLog from "../../logging/CloudLog";
|
import CloudLog from '../../logging/CloudLog';
|
||||||
import Signal from "./signal";
|
import Signal from './signal';
|
||||||
import Frame from "./frame";
|
import Frame from './frame';
|
||||||
import BoardUnit from "./BoardUnit";
|
import BoardUnit from './BoardUnit';
|
||||||
import DbcUtils from "../../utils/dbc";
|
import DbcUtils from '../../utils/dbc';
|
||||||
import * as LogSignals from "./logSignals";
|
import * as LogSignals from './logSignals';
|
||||||
|
|
||||||
const UINT64 = require("cuint").UINT64;
|
const { UINT64 } = require('cuint');
|
||||||
|
|
||||||
const DBC_COMMENT_RE = /^CM_ *"(.*)";/;
|
const DBC_COMMENT_RE = /^CM_ *"(.*)";/;
|
||||||
const DBC_COMMENT_MULTI_LINE_RE = /^CM_ *"(.*)/;
|
const DBC_COMMENT_MULTI_LINE_RE = /^CM_ *"(.*)/;
|
||||||
|
@ -34,17 +34,16 @@ const BOARD_UNIT_COMMENT_RE = /^CM_ BU_ *(\w+) *"(.*)";/;
|
||||||
const BOARD_UNIT_COMMENT_MULTI_LINE_RE = /^CM_ BU_ *(\w+) *"(.*)/;
|
const BOARD_UNIT_COMMENT_MULTI_LINE_RE = /^CM_ BU_ *(\w+) *"(.*)/;
|
||||||
|
|
||||||
// Follow ups are used to parse multi-line comment definitions
|
// Follow ups are used to parse multi-line comment definitions
|
||||||
const FOLLOW_UP_DBC_COMMENT = "FollowUpDbcComment";
|
const FOLLOW_UP_DBC_COMMENT = 'FollowUpDbcComment';
|
||||||
const FOLLOW_UP_SIGNAL_COMMENT = "FollowUpSignalComment";
|
const FOLLOW_UP_SIGNAL_COMMENT = 'FollowUpSignalComment';
|
||||||
const FOLLOW_UP_MSG_COMMENT = "FollowUpMsgComment";
|
const FOLLOW_UP_MSG_COMMENT = 'FollowUpMsgComment';
|
||||||
const FOLLOW_UP_BOARD_UNIT_COMMENT = "FollowUpBoardUnitComment";
|
const FOLLOW_UP_BOARD_UNIT_COMMENT = 'FollowUpBoardUnitComment';
|
||||||
|
|
||||||
function floatOrInt(numericStr) {
|
function floatOrInt(numericStr) {
|
||||||
if (Number.isInteger(numericStr)) {
|
if (Number.isInteger(numericStr)) {
|
||||||
return parseInt(numericStr, 10);
|
return parseInt(numericStr, 10);
|
||||||
} else {
|
|
||||||
return parseFloat(numericStr);
|
|
||||||
}
|
}
|
||||||
|
return parseFloat(numericStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function swapOrder(arr, wordSize, gSize) {
|
export function swapOrder(arr, wordSize, gSize) {
|
||||||
|
@ -57,7 +56,7 @@ export function swapOrder(arr, wordSize, gSize) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return swappedWords.join("");
|
return swappedWords.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class DBC {
|
export default class DBC {
|
||||||
|
@ -82,14 +81,14 @@ export default class DBC {
|
||||||
nextNewFrameName() {
|
nextNewFrameName() {
|
||||||
const messageNames = [];
|
const messageNames = [];
|
||||||
|
|
||||||
for (let msg of this.messages.values()) {
|
for (const msg of this.messages.values()) {
|
||||||
messageNames.push(msg.name);
|
messageNames.push(msg.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
let msgNum = 1,
|
let msgNum = 1;
|
||||||
msgName;
|
let msgName;
|
||||||
do {
|
do {
|
||||||
msgName = "NEW_MSG_" + msgNum;
|
msgName = `NEW_MSG_${msgNum}`;
|
||||||
msgNum++;
|
msgNum++;
|
||||||
} while (messageNames.indexOf(msgName) !== -1);
|
} while (messageNames.indexOf(msgName) !== -1);
|
||||||
|
|
||||||
|
@ -97,15 +96,15 @@ export default class DBC {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBoardUnits() {
|
updateBoardUnits() {
|
||||||
const boardUnitNames = this.boardUnits.map(bu => bu.name);
|
const boardUnitNames = this.boardUnits.map((bu) => bu.name);
|
||||||
const missingBoardUnits = Array.from(this.messages.entries())
|
const missingBoardUnits = Array.from(this.messages.entries())
|
||||||
.map(([msgId, frame]) => Object.values(frame.signals))
|
.map(([msgId, frame]) => Object.values(frame.signals))
|
||||||
.reduce((arr, signals) => arr.concat(signals), [])
|
.reduce((arr, signals) => arr.concat(signals), [])
|
||||||
.map(signal => signal.receiver)
|
.map((signal) => signal.receiver)
|
||||||
.reduce((arr, receivers) => arr.concat(receivers), [])
|
.reduce((arr, receivers) => arr.concat(receivers), [])
|
||||||
.filter((recv, idx, array) => array.indexOf(recv) === idx)
|
.filter((recv, idx, array) => array.indexOf(recv) === idx)
|
||||||
.filter(recv => boardUnitNames.indexOf(recv) === -1)
|
.filter((recv) => boardUnitNames.indexOf(recv) === -1)
|
||||||
.map(recv => new BoardUnit(recv));
|
.map((recv) => new BoardUnit(recv));
|
||||||
|
|
||||||
this.boardUnits = this.boardUnits.concat(missingBoardUnits);
|
this.boardUnits = this.boardUnits.concat(missingBoardUnits);
|
||||||
}
|
}
|
||||||
|
@ -114,57 +113,54 @@ export default class DBC {
|
||||||
this.updateBoardUnits();
|
this.updateBoardUnits();
|
||||||
|
|
||||||
let txt = 'VERSION ""\n\n\n';
|
let txt = 'VERSION ""\n\n\n';
|
||||||
txt += "NS_ :" + this._newSymbols();
|
txt += `NS_ :${this._newSymbols()}`;
|
||||||
txt += "\n\nBS_:\n";
|
txt += '\n\nBS_:\n';
|
||||||
|
|
||||||
const boardUnitsText = this.boardUnits.map(bu => bu.text()).join(" ");
|
const boardUnitsText = this.boardUnits.map((bu) => bu.text()).join(' ');
|
||||||
txt += "\nBU_: " + boardUnitsText + "\n\n\n";
|
txt += `\nBU_: ${boardUnitsText}\n\n\n`;
|
||||||
|
|
||||||
const frames = [];
|
const frames = [];
|
||||||
for (let frame of this.messages.values()) {
|
for (const frame of this.messages.values()) {
|
||||||
frames.push(frame);
|
frames.push(frame);
|
||||||
}
|
}
|
||||||
txt += frames.map(f => f.text()).join("\n\n") + "\n\n";
|
txt += `${frames.map((f) => f.text()).join('\n\n')}\n\n`;
|
||||||
|
|
||||||
const messageTxs = frames
|
const messageTxs = frames
|
||||||
.map(f => [f.id, f.transmitters.slice(1)])
|
.map((f) => [f.id, f.transmitters.slice(1)])
|
||||||
.filter(([addr, txs]) => txs.length > 0);
|
.filter(([addr, txs]) => txs.length > 0);
|
||||||
txt +=
|
txt += `${messageTxs
|
||||||
messageTxs
|
.map(([addr, txs]) => `BO_TX_BU_ ${addr} : ${txs.join(',')};`)
|
||||||
.map(([addr, txs]) => `BO_TX_BU_ ${addr} : ${txs.join(",")};`)
|
.join('\n')}\n\n\n`;
|
||||||
.join("\n") + "\n\n\n";
|
|
||||||
|
|
||||||
txt += this.boardUnits
|
txt += this.boardUnits
|
||||||
.filter(bu => bu.comment !== null)
|
.filter((bu) => bu.comment !== null)
|
||||||
.map(bu => `CM_ BU_ ${bu.name} "${bu.comment}";`)
|
.map((bu) => `CM_ BU_ ${bu.name} "${bu.comment}";`)
|
||||||
.join("\n");
|
.join('\n');
|
||||||
|
|
||||||
txt += frames
|
txt += frames
|
||||||
.filter(f => f.comment !== null)
|
.filter((f) => f.comment !== null)
|
||||||
.map(msg => `CM_ BO_ ${msg.address} "${msg.comment}";`)
|
.map((msg) => `CM_ BO_ ${msg.address} "${msg.comment}";`)
|
||||||
.join("\n");
|
.join('\n');
|
||||||
|
|
||||||
const signalsByMsgId = frames
|
const signalsByMsgId = frames
|
||||||
.map(f => Object.values(f.signals).map(sig => [f.id, sig]))
|
.map((f) => Object.values(f.signals).map((sig) => [f.id, sig]))
|
||||||
.reduce((s1, s2) => s1.concat(s2), []);
|
.reduce((s1, s2) => s1.concat(s2), []);
|
||||||
|
|
||||||
txt +=
|
txt += `${signalsByMsgId
|
||||||
signalsByMsgId
|
.filter(([msgAddr, sig]) => sig.comment !== null)
|
||||||
.filter(([msgAddr, sig]) => sig.comment !== null)
|
.map(
|
||||||
.map(
|
([msgAddr, sig]) => `CM_ SG_ ${msgAddr} ${sig.name} "${sig.comment}";`
|
||||||
([msgAddr, sig]) => `CM_ SG_ ${msgAddr} ${sig.name} "${sig.comment}";`
|
)
|
||||||
)
|
.join('\n')}\n`;
|
||||||
.join("\n") + "\n";
|
|
||||||
|
|
||||||
txt +=
|
txt += `${signalsByMsgId
|
||||||
signalsByMsgId
|
.filter(([msgAddr, sig]) => sig.valueDescriptions.size > 0)
|
||||||
.filter(([msgAddr, sig]) => sig.valueDescriptions.size > 0)
|
.map(([msgAddr, sig]) => sig.valueDescriptionText(msgAddr))
|
||||||
.map(([msgAddr, sig]) => sig.valueDescriptionText(msgAddr))
|
.join('\n')}\n`;
|
||||||
.join("\n") + "\n";
|
|
||||||
|
|
||||||
txt += this.comments.map(comment => `CM_ "${comment}";`).join("\n");
|
txt += this.comments.map((comment) => `CM_ "${comment}";`).join('\n');
|
||||||
|
|
||||||
return txt.trim() + "\n";
|
return `${txt.trim()}\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMessageName(msgId) {
|
getMessageName(msgId) {
|
||||||
|
@ -218,11 +214,11 @@ export default class DBC {
|
||||||
const warnings = [];
|
const warnings = [];
|
||||||
const messages = new Map();
|
const messages = new Map();
|
||||||
let boardUnits = [];
|
let boardUnits = [];
|
||||||
let valueTables = new Map();
|
const valueTables = new Map();
|
||||||
let id = 0;
|
let id = 0;
|
||||||
let followUp = null;
|
let followUp = null;
|
||||||
|
|
||||||
const lines = dbcString.split("\n");
|
const lines = dbcString.split('\n');
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
let line = lines[i].trim();
|
let line = lines[i].trim();
|
||||||
|
|
||||||
|
@ -230,7 +226,7 @@ export default class DBC {
|
||||||
|
|
||||||
if (followUp != null) {
|
if (followUp != null) {
|
||||||
const { type, data } = followUp;
|
const { type, data } = followUp;
|
||||||
line = line.replace(/" *;/, "");
|
line = line.replace(/" *;/, '');
|
||||||
let followUpLine = `\n${line.substr(0, line.length)}`;
|
let followUpLine = `\n${line.substr(0, line.length)}`;
|
||||||
if (line.indexOf('"') !== -1) {
|
if (line.indexOf('"') !== -1) {
|
||||||
followUp = null;
|
followUp = null;
|
||||||
|
@ -248,13 +244,12 @@ export default class DBC {
|
||||||
} else if (type === FOLLOW_UP_DBC_COMMENT) {
|
} else if (type === FOLLOW_UP_DBC_COMMENT) {
|
||||||
// const comment = data;
|
// const comment = data;
|
||||||
const partialComment = this.comments[this.comments.length - 1];
|
const partialComment = this.comments[this.comments.length - 1];
|
||||||
this.comments[this.comments.length - 1] =
|
this.comments[this.comments.length - 1] = partialComment + followUpLine;
|
||||||
partialComment + followUpLine;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line.indexOf("BO_ ") === 0) {
|
if (line.indexOf('BO_ ') === 0) {
|
||||||
let matches = line.match(MSG_RE);
|
const matches = line.match(MSG_RE);
|
||||||
if (matches === null) {
|
if (matches === null) {
|
||||||
warnings.push(
|
warnings.push(
|
||||||
`failed to parse message definition on line ${i + 1} -- ${line}`
|
`failed to parse message definition on line ${i + 1} -- ${line}`
|
||||||
|
@ -271,7 +266,7 @@ export default class DBC {
|
||||||
transmitters: [transmitter]
|
transmitters: [transmitter]
|
||||||
});
|
});
|
||||||
messages.set(id, frame);
|
messages.set(id, frame);
|
||||||
} else if (line.indexOf("SG_") === 0) {
|
} else if (line.indexOf('SG_') === 0) {
|
||||||
let matches = line.match(SIGNAL_RE);
|
let matches = line.match(SIGNAL_RE);
|
||||||
|
|
||||||
if (matches === null) {
|
if (matches === null) {
|
||||||
|
@ -304,12 +299,12 @@ export default class DBC {
|
||||||
startBit = parseInt(startBit, 10);
|
startBit = parseInt(startBit, 10);
|
||||||
size = parseInt(size, 10);
|
size = parseInt(size, 10);
|
||||||
isLittleEndian = parseInt(isLittleEndian, 10) === 1;
|
isLittleEndian = parseInt(isLittleEndian, 10) === 1;
|
||||||
isSigned = isSigned === "-";
|
isSigned = isSigned === '-';
|
||||||
factor = floatOrInt(factor);
|
factor = floatOrInt(factor);
|
||||||
offset = floatOrInt(offset);
|
offset = floatOrInt(offset);
|
||||||
min = floatOrInt(min);
|
min = floatOrInt(min);
|
||||||
max = floatOrInt(max);
|
max = floatOrInt(max);
|
||||||
const receiver = receiverStr.split(",").map(s => s.trim());
|
const receiver = receiverStr.split(',').map((s) => s.trim());
|
||||||
|
|
||||||
const signalProperties = {
|
const signalProperties = {
|
||||||
name,
|
name,
|
||||||
|
@ -330,35 +325,32 @@ export default class DBC {
|
||||||
messages.get(id).signals[name] = signal;
|
messages.get(id).signals[name] = signal;
|
||||||
} else {
|
} else {
|
||||||
CloudLog.warn(
|
CloudLog.warn(
|
||||||
"importDbcString: could not add signal: " +
|
`importDbcString: could not add signal: ${name} due to missing message: ${id}`
|
||||||
name +
|
|
||||||
" due to missing message: " +
|
|
||||||
id
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (line.indexOf("VAL_ ") === 0) {
|
} else if (line.indexOf('VAL_ ') === 0) {
|
||||||
let matches = line.match(VAL_RE);
|
const matches = line.match(VAL_RE);
|
||||||
|
|
||||||
if (matches !== null) {
|
if (matches !== null) {
|
||||||
let [messageId, signalName, vals] = matches.slice(1);
|
let [messageId, signalName, vals] = matches.slice(1);
|
||||||
vals = vals
|
vals = vals
|
||||||
.split('"')
|
.split('"')
|
||||||
.map(s => s.trim())
|
.map((s) => s.trim())
|
||||||
.filter(s => s.length > 0);
|
.filter((s) => s.length > 0);
|
||||||
|
|
||||||
messageId = parseInt(messageId, 10);
|
messageId = parseInt(messageId, 10);
|
||||||
const msg = messages.get(messageId);
|
const msg = messages.get(messageId);
|
||||||
const signal = msg.signals[signalName];
|
const signal = msg.signals[signalName];
|
||||||
if (signal === undefined) {
|
if (signal === undefined) {
|
||||||
warnings.push(
|
warnings.push(
|
||||||
`could not find signal for value description on line ${i +
|
`could not find signal for value description on line ${i
|
||||||
1} -- ${line}`
|
+ 1} -- ${line}`
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < vals.length; i += 2) {
|
for (let i = 0; i < vals.length; i += 2) {
|
||||||
const value = vals[i].trim(),
|
const value = vals[i].trim();
|
||||||
description = vals[i + 1].trim();
|
const description = vals[i + 1].trim();
|
||||||
signal.valueDescriptions.set(value, description);
|
signal.valueDescriptions.set(value, description);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -366,20 +358,20 @@ export default class DBC {
|
||||||
`failed to parse value description on line ${i + 1} -- ${line}`
|
`failed to parse value description on line ${i + 1} -- ${line}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (line.indexOf("VAL_TABLE_ ") === 0) {
|
} else if (line.indexOf('VAL_TABLE_ ') === 0) {
|
||||||
let matches = line.match(VAL_TABLE_RE);
|
const matches = line.match(VAL_TABLE_RE);
|
||||||
|
|
||||||
if (matches !== null) {
|
if (matches !== null) {
|
||||||
const table = new Map();
|
const table = new Map();
|
||||||
let [tableName, items] = matches.slice(1);
|
let [tableName, items] = matches.slice(1);
|
||||||
items = items
|
items = items
|
||||||
.split('"')
|
.split('"')
|
||||||
.map(s => s.trim())
|
.map((s) => s.trim())
|
||||||
.filter(s => s.length > 0);
|
.filter((s) => s.length > 0);
|
||||||
|
|
||||||
for (let i = 0; i < items.length; i += 2) {
|
for (let i = 0; i < items.length; i += 2) {
|
||||||
const key = items[i],
|
const key = items[i];
|
||||||
value = items[i + 1];
|
const value = items[i + 1];
|
||||||
table.set(key, value);
|
table.set(key, value);
|
||||||
}
|
}
|
||||||
valueTables.set(tableName, table);
|
valueTables.set(tableName, table);
|
||||||
|
@ -388,8 +380,8 @@ export default class DBC {
|
||||||
`failed to parse value table on line ${i + 1} -- ${line}`
|
`failed to parse value table on line ${i + 1} -- ${line}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (line.indexOf("BO_TX_BU_ ") === 0) {
|
} else if (line.indexOf('BO_TX_BU_ ') === 0) {
|
||||||
let matches = line.match(MSG_TRANSMITTER_RE);
|
const matches = line.match(MSG_TRANSMITTER_RE);
|
||||||
|
|
||||||
if (matches !== null) {
|
if (matches !== null) {
|
||||||
let [messageId, transmitter] = matches.slice(1);
|
let [messageId, transmitter] = matches.slice(1);
|
||||||
|
@ -400,11 +392,11 @@ export default class DBC {
|
||||||
messages.set(messageId, msg);
|
messages.set(messageId, msg);
|
||||||
} else {
|
} else {
|
||||||
warnings.push(
|
warnings.push(
|
||||||
`failed to parse message transmitter definition on line ${i +
|
`failed to parse message transmitter definition on line ${i
|
||||||
1} -- ${line}`
|
+ 1} -- ${line}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (line.indexOf("CM_ SG_ ") === 0) {
|
} else if (line.indexOf('CM_ SG_ ') === 0) {
|
||||||
let matches = line.match(SIGNAL_COMMENT_RE);
|
let matches = line.match(SIGNAL_COMMENT_RE);
|
||||||
let hasFollowUp = false;
|
let hasFollowUp = false;
|
||||||
if (matches === null) {
|
if (matches === null) {
|
||||||
|
@ -423,8 +415,8 @@ export default class DBC {
|
||||||
messageId = parseInt(messageId, 10);
|
messageId = parseInt(messageId, 10);
|
||||||
const msg = messages.get(messageId);
|
const msg = messages.get(messageId);
|
||||||
if (msg === undefined) {
|
if (msg === undefined) {
|
||||||
warnings.push(`failed to parse signal comment on line ${i +
|
warnings.push(`failed to parse signal comment on line ${i
|
||||||
1} -- ${line}:
|
+ 1} -- ${line}:
|
||||||
message id ${messageId} does not exist prior to this line`);
|
message id ${messageId} does not exist prior to this line`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -442,7 +434,7 @@ export default class DBC {
|
||||||
if (hasFollowUp) {
|
if (hasFollowUp) {
|
||||||
followUp = { type: FOLLOW_UP_SIGNAL_COMMENT, data: signal };
|
followUp = { type: FOLLOW_UP_SIGNAL_COMMENT, data: signal };
|
||||||
}
|
}
|
||||||
} else if (line.indexOf("CM_ BO_ ") === 0) {
|
} else if (line.indexOf('CM_ BO_ ') === 0) {
|
||||||
let matches = line.match(MESSAGE_COMMENT_RE);
|
let matches = line.match(MESSAGE_COMMENT_RE);
|
||||||
let hasFollowUp = false;
|
let hasFollowUp = false;
|
||||||
if (matches === null) {
|
if (matches === null) {
|
||||||
|
@ -464,16 +456,16 @@ export default class DBC {
|
||||||
if (hasFollowUp) {
|
if (hasFollowUp) {
|
||||||
followUp = { type: FOLLOW_UP_MSG_COMMENT, data: msg };
|
followUp = { type: FOLLOW_UP_MSG_COMMENT, data: msg };
|
||||||
}
|
}
|
||||||
} else if (line.indexOf("BU_: ") === 0) {
|
} else if (line.indexOf('BU_: ') === 0) {
|
||||||
let matches = line.match(BOARD_UNIT_RE);
|
const matches = line.match(BOARD_UNIT_RE);
|
||||||
|
|
||||||
if (matches !== null) {
|
if (matches !== null) {
|
||||||
const [boardUnitNameStr] = matches.slice(1);
|
const [boardUnitNameStr] = matches.slice(1);
|
||||||
const newBoardUnits = boardUnitNameStr
|
const newBoardUnits = boardUnitNameStr
|
||||||
.split(" ")
|
.split(' ')
|
||||||
.map(s => s.trim())
|
.map((s) => s.trim())
|
||||||
.filter(s => s.length > 0)
|
.filter((s) => s.length > 0)
|
||||||
.map(name => new BoardUnit(name));
|
.map((name) => new BoardUnit(name));
|
||||||
|
|
||||||
boardUnits = boardUnits.concat(newBoardUnits);
|
boardUnits = boardUnits.concat(newBoardUnits);
|
||||||
} else {
|
} else {
|
||||||
|
@ -482,7 +474,7 @@ export default class DBC {
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (line.indexOf("CM_ BU_ ") === 0) {
|
} else if (line.indexOf('CM_ BU_ ') === 0) {
|
||||||
let matches = line.match(BOARD_UNIT_COMMENT_RE);
|
let matches = line.match(BOARD_UNIT_COMMENT_RE);
|
||||||
let hasFollowUp = false;
|
let hasFollowUp = false;
|
||||||
if (matches === null) {
|
if (matches === null) {
|
||||||
|
@ -496,8 +488,8 @@ export default class DBC {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let [boardUnitName, comment] = matches.slice(1);
|
const [boardUnitName, comment] = matches.slice(1);
|
||||||
let boardUnit = boardUnits.find(bu => bu.name === boardUnitName);
|
const boardUnit = boardUnits.find((bu) => bu.name === boardUnitName);
|
||||||
if (boardUnit) {
|
if (boardUnit) {
|
||||||
boardUnit.comment = comment;
|
boardUnit.comment = comment;
|
||||||
}
|
}
|
||||||
|
@ -505,7 +497,7 @@ export default class DBC {
|
||||||
if (hasFollowUp) {
|
if (hasFollowUp) {
|
||||||
followUp = { type: FOLLOW_UP_BOARD_UNIT_COMMENT, data: boardUnit };
|
followUp = { type: FOLLOW_UP_BOARD_UNIT_COMMENT, data: boardUnit };
|
||||||
}
|
}
|
||||||
} else if (line.indexOf("CM_ ") === 0) {
|
} else if (line.indexOf('CM_ ') === 0) {
|
||||||
let matches = line.match(DBC_COMMENT_RE);
|
let matches = line.match(DBC_COMMENT_RE);
|
||||||
let hasFollowUp = false;
|
let hasFollowUp = false;
|
||||||
if (matches === null) {
|
if (matches === null) {
|
||||||
|
@ -520,7 +512,7 @@ export default class DBC {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let [comment] = matches.slice(1);
|
const [comment] = matches.slice(1);
|
||||||
this.comments.push(comment);
|
this.comments.push(comment);
|
||||||
if (hasFollowUp) {
|
if (hasFollowUp) {
|
||||||
followUp = { type: FOLLOW_UP_DBC_COMMENT, data: comment };
|
followUp = { type: FOLLOW_UP_DBC_COMMENT, data: comment };
|
||||||
|
@ -542,7 +534,9 @@ export default class DBC {
|
||||||
|
|
||||||
valueForInt64Signal(signalSpec, hexData) {
|
valueForInt64Signal(signalSpec, hexData) {
|
||||||
const blen = hexData.length * 4;
|
const blen = hexData.length * 4;
|
||||||
let value, startBit, dataBitPos;
|
let value;
|
||||||
|
let startBit;
|
||||||
|
let dataBitPos;
|
||||||
|
|
||||||
if (signalSpec.isLittleEndian) {
|
if (signalSpec.isLittleEndian) {
|
||||||
value = UINT64(swapOrder(hexData, 16, 2), 16);
|
value = UINT64(swapOrder(hexData, 16, 2), 16);
|
||||||
|
@ -559,7 +553,7 @@ export default class DBC {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let rightHandAnd = UINT64(Math.pow(2, signalSpec.size) - 1);
|
const rightHandAnd = UINT64(Math.pow(2, signalSpec.size) - 1);
|
||||||
let ival = value
|
let ival = value
|
||||||
.shiftr(dataBitPos)
|
.shiftr(dataBitPos)
|
||||||
.and(rightHandAnd)
|
.and(rightHandAnd)
|
||||||
|
@ -573,11 +567,11 @@ export default class DBC {
|
||||||
}
|
}
|
||||||
|
|
||||||
valueForInt32Signal(signalSpec, buf) {
|
valueForInt32Signal(signalSpec, buf) {
|
||||||
var startBit;
|
let startBit;
|
||||||
if (signalSpec.isLittleEndian) {
|
if (signalSpec.isLittleEndian) {
|
||||||
startBit = 64 - signalSpec.startBit - signalSpec.size;
|
startBit = 64 - signalSpec.startBit - signalSpec.size;
|
||||||
} else {
|
} else {
|
||||||
var bitPos = (-signalSpec.startBit - 1) % 8;
|
let bitPos = (-signalSpec.startBit - 1) % 8;
|
||||||
if (bitPos < 0) {
|
if (bitPos < 0) {
|
||||||
bitPos += 8; // mimic python modulo behavior
|
bitPos += 8; // mimic python modulo behavior
|
||||||
}
|
}
|
||||||
|
@ -585,8 +579,9 @@ export default class DBC {
|
||||||
startBit = Math.floor(signalSpec.startBit / 8) * 8 + bitPos;
|
startBit = Math.floor(signalSpec.startBit / 8) * 8 + bitPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
var shiftAmount, signalValue;
|
let shiftAmount;
|
||||||
let byteOffset = Math.min(4, Math.floor(signalSpec.startBit / 8));
|
let signalValue;
|
||||||
|
const byteOffset = Math.min(4, Math.floor(signalSpec.startBit / 8));
|
||||||
if (signalSpec.isLittleEndian) {
|
if (signalSpec.isLittleEndian) {
|
||||||
signalValue = buf.readUInt32LE(byteOffset);
|
signalValue = buf.readUInt32LE(byteOffset);
|
||||||
shiftAmount = signalSpec.startBit - 8 * byteOffset;
|
shiftAmount = signalSpec.startBit - 8 * byteOffset;
|
||||||
|
@ -609,17 +604,17 @@ export default class DBC {
|
||||||
}
|
}
|
||||||
const frame = this.getMessageFrame(messageId);
|
const frame = this.getMessageFrame(messageId);
|
||||||
|
|
||||||
let buffer = Buffer.from(data);
|
const buffer = Buffer.from(data);
|
||||||
let paddedBuffer = buffer;
|
let paddedBuffer = buffer;
|
||||||
if (buffer.length !== 8) {
|
if (buffer.length !== 8) {
|
||||||
// pad data it's 64 bits long
|
// pad data it's 64 bits long
|
||||||
const paddedDataHex = rightPad(buffer.toString("hex"), 16, "0");
|
const paddedDataHex = rightPad(buffer.toString('hex'), 16, '0');
|
||||||
paddedBuffer = Buffer.from(paddedDataHex, "hex");
|
paddedBuffer = Buffer.from(paddedDataHex, 'hex');
|
||||||
}
|
}
|
||||||
const hexData = paddedBuffer.toString("hex");
|
const hexData = paddedBuffer.toString('hex');
|
||||||
|
|
||||||
const signalValuesByName = {};
|
const signalValuesByName = {};
|
||||||
Object.values(frame.signals).forEach(signalSpec => {
|
Object.values(frame.signals).forEach((signalSpec) => {
|
||||||
let value;
|
let value;
|
||||||
if (signalSpec.size > 32) {
|
if (signalSpec.size > 32) {
|
||||||
value = this.valueForInt64Signal(signalSpec, hexData);
|
value = this.valueForInt64Signal(signalSpec, hexData);
|
||||||
|
@ -634,15 +629,15 @@ export default class DBC {
|
||||||
|
|
||||||
getChffrMetricMappings() {
|
getChffrMetricMappings() {
|
||||||
const metricComment = this.comments.find(
|
const metricComment = this.comments.find(
|
||||||
comment => comment.indexOf("CHFFR_METRIC") === 0
|
(comment) => comment.indexOf('CHFFR_METRIC') === 0
|
||||||
);
|
);
|
||||||
if (!metricComment) {
|
if (!metricComment) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return metricComment
|
return metricComment
|
||||||
.split(";")
|
.split(';')
|
||||||
.map(metric => metric.trim().split(" "))
|
.map((metric) => metric.trim().split(' '))
|
||||||
.reduce(
|
.reduce(
|
||||||
(metrics, [_, messageId, signalName, metricName, factor, offset]) => {
|
(metrics, [_, messageId, signalName, metricName, factor, offset]) => {
|
||||||
metrics[metricName] = {
|
metrics[metricName] = {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
function findTimeIndex(entries, time) {
|
function findTimeIndex(entries, time) {
|
||||||
return entries.findIndex(e => e.time >= time);
|
return entries.findIndex((e) => e.time >= time);
|
||||||
}
|
}
|
||||||
|
|
||||||
function findRelativeTimeIndex(entries, relTime) {
|
function findRelativeTimeIndex(entries, relTime) {
|
||||||
return entries.findIndex(e => e.relTime >= relTime);
|
return entries.findIndex((e) => e.relTime >= relTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
function findSegmentIndices(
|
function findSegmentIndices(
|
||||||
|
@ -20,17 +20,15 @@ function findSegmentIndices(
|
||||||
Returns `[segmentIdxLow, segmentIdxHigh]`
|
Returns `[segmentIdxLow, segmentIdxHigh]`
|
||||||
(inclusive, exclusive)
|
(inclusive, exclusive)
|
||||||
*/
|
*/
|
||||||
let timeIndexFunc =
|
const timeIndexFunc = isRelative === true ? findRelativeTimeIndex : findTimeIndex;
|
||||||
isRelative === true ? findRelativeTimeIndex : findTimeIndex;
|
|
||||||
|
|
||||||
const segmentIdxLow = Math.max(0, timeIndexFunc(entries, segmentTimeLow));
|
const segmentIdxLow = Math.max(0, timeIndexFunc(entries, segmentTimeLow));
|
||||||
|
|
||||||
const upperSegments = entries.slice(segmentIdxLow);
|
const upperSegments = entries.slice(segmentIdxLow);
|
||||||
let upperSegmentIdxHi = timeIndexFunc(upperSegments, segmentTimeHi);
|
const upperSegmentIdxHi = timeIndexFunc(upperSegments, segmentTimeHi);
|
||||||
const segmentIdxHi =
|
const segmentIdxHi = upperSegmentIdxHi >= 0
|
||||||
upperSegmentIdxHi >= 0
|
? upperSegmentIdxHi + segmentIdxLow + 1
|
||||||
? upperSegmentIdxHi + segmentIdxLow + 1
|
: entries.length - 1;
|
||||||
: entries.length - 1;
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
segmentIdxLow,
|
segmentIdxLow,
|
||||||
|
|
|
@ -20,10 +20,10 @@ export default class Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
nextNewTransmitterName() {
|
nextNewTransmitterName() {
|
||||||
let txNum = 1,
|
let txNum = 1;
|
||||||
txName;
|
let txName;
|
||||||
do {
|
do {
|
||||||
txName = "NEW_TRANSMITTER_" + txNum;
|
txName = `NEW_TRANSMITTER_${txNum}`;
|
||||||
txNum++;
|
txNum++;
|
||||||
} while (this.transmitters.indexOf(txName) !== -1);
|
} while (this.transmitters.indexOf(txName) !== -1);
|
||||||
|
|
||||||
|
@ -38,21 +38,20 @@ export default class Frame {
|
||||||
|
|
||||||
header() {
|
header() {
|
||||||
return (
|
return (
|
||||||
`BO_ ${this.id} ${this.name}: ${this.size} ` +
|
`BO_ ${this.id} ${this.name}: ${this.size} `
|
||||||
`${this.transmitters[0] || "XXX"}`
|
+ `${this.transmitters[0] || 'XXX'}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
text() {
|
text() {
|
||||||
const signals = Object.values(this.signals)
|
const signals = Object.values(this.signals)
|
||||||
.map(signal => " " + signal.text()) // indent
|
.map((signal) => ` ${signal.text()}`) // indent
|
||||||
.join("\n");
|
.join('\n');
|
||||||
|
|
||||||
if (signals.length > 0) {
|
if (signals.length > 0) {
|
||||||
return this.header() + "\n" + signals;
|
return `${this.header()}\n${signals}`;
|
||||||
} else {
|
|
||||||
return this.header();
|
|
||||||
}
|
}
|
||||||
|
return this.header();
|
||||||
}
|
}
|
||||||
|
|
||||||
copy() {
|
copy() {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import Frame from "./frame";
|
import Frame from './frame';
|
||||||
import Signal from "./signal";
|
import Signal from './signal';
|
||||||
|
|
||||||
export const wheelSpeeds = {
|
export const wheelSpeeds = {
|
||||||
FrontLeftWheel: shortSignal({
|
FrontLeftWheel: shortSignal({
|
||||||
|
@ -82,13 +82,13 @@ export const flags = {
|
||||||
Standstill: boolSignal({
|
Standstill: boolSignal({
|
||||||
index: 8
|
index: 8
|
||||||
}),
|
}),
|
||||||
"CruiseState.Enabled": boolSignal({
|
'CruiseState.Enabled': boolSignal({
|
||||||
index: 9
|
index: 9
|
||||||
}),
|
}),
|
||||||
"CruiseState.Available": boolSignal({
|
'CruiseState.Available': boolSignal({
|
||||||
index: 10
|
index: 10
|
||||||
}),
|
}),
|
||||||
"CruiseState.Standstill": boolSignal({
|
'CruiseState.Standstill': boolSignal({
|
||||||
index: 11
|
index: 11
|
||||||
}),
|
}),
|
||||||
GearShifter: {
|
GearShifter: {
|
||||||
|
@ -96,7 +96,7 @@ export const flags = {
|
||||||
size: 4,
|
size: 4,
|
||||||
unsigned: true
|
unsigned: true
|
||||||
},
|
},
|
||||||
"CruiseState.Speed": charSignal({
|
'CruiseState.Speed': charSignal({
|
||||||
index: 2
|
index: 2
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
@ -192,21 +192,21 @@ export const thermalFreeSpace = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const signalMap = {
|
export const signalMap = {
|
||||||
"CarState:WheelSpeeds": wheelSpeeds,
|
'CarState:WheelSpeeds': wheelSpeeds,
|
||||||
"CarState:Ego": ego,
|
'CarState:Ego': ego,
|
||||||
"CarState:Controls": controls,
|
'CarState:Controls': controls,
|
||||||
"CarState:Flags": flags,
|
'CarState:Flags': flags,
|
||||||
"UbloxGnss:MeasurementReport": ubloxGnss,
|
'UbloxGnss:MeasurementReport': ubloxGnss,
|
||||||
"Health:Data": health,
|
'Health:Data': health,
|
||||||
"Thermal:CPU": thermalCPU,
|
'Thermal:CPU': thermalCPU,
|
||||||
"Thermal:Data": thermalData,
|
'Thermal:Data': thermalData,
|
||||||
"Thermal:FreeSpace": thermalFreeSpace
|
'Thermal:FreeSpace': thermalFreeSpace
|
||||||
};
|
};
|
||||||
|
|
||||||
const ADDRESS_LIST = [];
|
const ADDRESS_LIST = [];
|
||||||
|
|
||||||
Object.keys(signalMap).forEach(function(name) {
|
Object.keys(signalMap).forEach((name) => {
|
||||||
Object.keys(signalMap[name]).forEach(function(signal) {
|
Object.keys(signalMap[name]).forEach((signal) => {
|
||||||
signalMap[name][signal] = createSignalEntry({
|
signalMap[name][signal] = createSignalEntry({
|
||||||
name: signal,
|
name: signal,
|
||||||
...signalMap[name][signal]
|
...signalMap[name][signal]
|
||||||
|
@ -224,7 +224,7 @@ function createSignalEntry(options) {
|
||||||
isSigned: !options.unsigned,
|
isSigned: !options.unsigned,
|
||||||
factor: options.factor || 1,
|
factor: options.factor || 1,
|
||||||
offset: options.offset || 0,
|
offset: options.offset || 0,
|
||||||
unit: options.unit || ""
|
unit: options.unit || ''
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +262,7 @@ function boolSignal(options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addressForName(name) {
|
export function addressForName(name) {
|
||||||
var i = ADDRESS_LIST.indexOf(name);
|
const i = ADDRESS_LIST.indexOf(name);
|
||||||
if (i === -1) {
|
if (i === -1) {
|
||||||
ADDRESS_LIST.push(name);
|
ADDRESS_LIST.push(name);
|
||||||
return ADDRESS_LIST.indexOf(name) + 0x1000;
|
return ADDRESS_LIST.indexOf(name) + 0x1000;
|
||||||
|
@ -282,10 +282,10 @@ export function isLogAddress(address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function frameForAddress(address) {
|
export function frameForAddress(address) {
|
||||||
let name = nameForAddress(address);
|
const name = nameForAddress(address);
|
||||||
return new Frame({
|
return new Frame({
|
||||||
id: name,
|
id: name,
|
||||||
name: name,
|
name,
|
||||||
size: 8,
|
size: 8,
|
||||||
signals: signalMap[name]
|
signals: signalMap[name]
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import DbcUtils from "../../utils/dbc";
|
import DbcUtils from '../../utils/dbc';
|
||||||
|
|
||||||
export default class Signal {
|
export default class Signal {
|
||||||
constructor({
|
constructor({
|
||||||
|
@ -10,8 +10,8 @@ export default class Signal {
|
||||||
isFloat = false,
|
isFloat = false,
|
||||||
factor = 1,
|
factor = 1,
|
||||||
offset = 0,
|
offset = 0,
|
||||||
unit = "",
|
unit = '',
|
||||||
receiver = ["XXX"],
|
receiver = ['XXX'],
|
||||||
comment = null,
|
comment = null,
|
||||||
multiplex = null,
|
multiplex = null,
|
||||||
min = null,
|
min = null,
|
||||||
|
@ -45,28 +45,33 @@ export default class Signal {
|
||||||
|
|
||||||
const colors = this.generateColors();
|
const colors = this.generateColors();
|
||||||
|
|
||||||
Object.assign(this, { min, max, uid, colors });
|
Object.assign(this, {
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
uid,
|
||||||
|
colors
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
text() {
|
text() {
|
||||||
const multiplex = this.multiplex ? " " + this.multiplex : "";
|
const multiplex = this.multiplex ? ` ${this.multiplex}` : '';
|
||||||
const byteOrder = this.isLittleEndian ? 1 : 0;
|
const byteOrder = this.isLittleEndian ? 1 : 0;
|
||||||
const signedChar = this.isSigned ? "-" : "+";
|
const signedChar = this.isSigned ? '-' : '+';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
`SG_ ${this.name}${multiplex} : ` +
|
`SG_ ${this.name}${multiplex} : `
|
||||||
`${this.startBit}|${this.size}@${byteOrder}${signedChar}` +
|
+ `${this.startBit}|${this.size}@${byteOrder}${signedChar}`
|
||||||
` (${this.factor},${this.offset})` +
|
+ ` (${this.factor},${this.offset})`
|
||||||
` [${this.min}|${this.max}]` +
|
+ ` [${this.min}|${this.max}]`
|
||||||
` "${this.unit}" ${this.receiver}`
|
+ ` "${this.unit}" ${this.receiver}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
valueDescriptionText(msgId) {
|
valueDescriptionText(msgId) {
|
||||||
const entryPairs = Array.from(this.valueDescriptions.entries());
|
const entryPairs = Array.from(this.valueDescriptions.entries());
|
||||||
const values = entryPairs.reduce(
|
const values = entryPairs.reduce(
|
||||||
(str, [value, desc]) => str + value + ` "${desc}" `,
|
(str, [value, desc]) => `${str + value} "${desc}" `,
|
||||||
""
|
''
|
||||||
);
|
);
|
||||||
return `VAL_ ${msgId} ${this.name} ${values};`;
|
return `VAL_ ${msgId} ${this.name} ${values};`;
|
||||||
}
|
}
|
||||||
|
@ -76,11 +81,10 @@ export default class Signal {
|
||||||
|
|
||||||
if (this.isLittleEndian) {
|
if (this.isLittleEndian) {
|
||||||
return this.startBit;
|
return this.startBit;
|
||||||
} else {
|
|
||||||
const lsbBitNumber = this.lsbBitNumber();
|
|
||||||
|
|
||||||
return DbcUtils.matrixBitNumber(lsbBitNumber);
|
|
||||||
}
|
}
|
||||||
|
const lsbBitNumber = this.lsbBitNumber();
|
||||||
|
|
||||||
|
return DbcUtils.matrixBitNumber(lsbBitNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
lsbBitNumber() {
|
lsbBitNumber() {
|
||||||
|
@ -92,21 +96,19 @@ export default class Signal {
|
||||||
msbBitIndex() {
|
msbBitIndex() {
|
||||||
if (this.isLittleEndian) {
|
if (this.isLittleEndian) {
|
||||||
return this.startBit + this.size - 1;
|
return this.startBit + this.size - 1;
|
||||||
} else {
|
|
||||||
return this.startBit;
|
|
||||||
}
|
}
|
||||||
|
return this.startBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
littleEndianBitDescription(bitIndex) {
|
littleEndianBitDescription(bitIndex) {
|
||||||
const bitRange = [this.startBit, this.startBit + this.size - 1];
|
const bitRange = [this.startBit, this.startBit + this.size - 1];
|
||||||
if (bitIndex < bitRange[0] || bitIndex > bitRange[1]) {
|
if (bitIndex < bitRange[0] || bitIndex > bitRange[1]) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
|
||||||
const bitNumber = bitIndex - bitRange[0];
|
|
||||||
const isLsb = bitIndex === bitRange[0];
|
|
||||||
const isMsb = bitIndex === bitRange[1];
|
|
||||||
return { bitNumber, isLsb, isMsb };
|
|
||||||
}
|
}
|
||||||
|
const bitNumber = bitIndex - bitRange[0];
|
||||||
|
const isLsb = bitIndex === bitRange[0];
|
||||||
|
const isMsb = bitIndex === bitRange[1];
|
||||||
|
return { bitNumber, isLsb, isMsb };
|
||||||
}
|
}
|
||||||
|
|
||||||
bigEndianBitDescription(bitIndex) {
|
bigEndianBitDescription(bitIndex) {
|
||||||
|
@ -120,15 +122,19 @@ export default class Signal {
|
||||||
|
|
||||||
const isLsb = bitNumber === range[1];
|
const isLsb = bitNumber === range[1];
|
||||||
const isMsb = bitIndex === this.startBit;
|
const isMsb = bitIndex === this.startBit;
|
||||||
return { bitNumber, isLsb, isMsb, range };
|
return {
|
||||||
|
bitNumber,
|
||||||
|
isLsb,
|
||||||
|
isMsb,
|
||||||
|
range
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bitDescription(bitIndex) {
|
bitDescription(bitIndex) {
|
||||||
if (this.isLittleEndian) {
|
if (this.isLittleEndian) {
|
||||||
return this.littleEndianBitDescription(bitIndex);
|
return this.littleEndianBitDescription(bitIndex);
|
||||||
} else {
|
|
||||||
return this.bigEndianBitDescription(bitIndex);
|
|
||||||
}
|
}
|
||||||
|
return this.bigEndianBitDescription(bitIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateRawRange() {
|
calculateRawRange() {
|
||||||
|
@ -150,7 +156,7 @@ export default class Signal {
|
||||||
}
|
}
|
||||||
|
|
||||||
generateColors() {
|
generateColors() {
|
||||||
let colors = Array(3);
|
const colors = Array(3);
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
colors[i] = Math.floor(Math.random() * 211);
|
colors[i] = Math.floor(Math.random() * 211);
|
||||||
}
|
}
|
||||||
|
@ -160,19 +166,19 @@ export default class Signal {
|
||||||
|
|
||||||
equals(otherSignal) {
|
equals(otherSignal) {
|
||||||
return (
|
return (
|
||||||
otherSignal.name === this.name &&
|
otherSignal.name === this.name
|
||||||
otherSignal.startBit === this.startBit &&
|
&& otherSignal.startBit === this.startBit
|
||||||
otherSignal.size === this.size &&
|
&& otherSignal.size === this.size
|
||||||
otherSignal.isLittleEndian === this.isLittleEndian &&
|
&& otherSignal.isLittleEndian === this.isLittleEndian
|
||||||
otherSignal.isSigned === this.isSigned &&
|
&& otherSignal.isSigned === this.isSigned
|
||||||
otherSignal.isFloat === this.isFloat &&
|
&& otherSignal.isFloat === this.isFloat
|
||||||
otherSignal.factor === this.factor &&
|
&& otherSignal.factor === this.factor
|
||||||
otherSignal.offset === this.offset &&
|
&& otherSignal.offset === this.offset
|
||||||
otherSignal.unit === this.unit &&
|
&& otherSignal.unit === this.unit
|
||||||
otherSignal.receiver.length === this.receiver.length &&
|
&& otherSignal.receiver.length === this.receiver.length
|
||||||
otherSignal.receiver.every((v, i) => v === this.receiver[i]) &&
|
&& otherSignal.receiver.every((v, i) => v === this.receiver[i])
|
||||||
otherSignal.comment === this.comment &&
|
&& otherSignal.comment === this.comment
|
||||||
otherSignal.multiplex === this.multiplex
|
&& otherSignal.multiplex === this.multiplex
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import ArrayUtils from "../utils/array";
|
import ArrayUtils from '../utils/array';
|
||||||
import { CAN_GRAPH_MAX_POINTS } from "../config";
|
import { CAN_GRAPH_MAX_POINTS } from '../config';
|
||||||
|
|
||||||
function _calcGraphData(msg, signalUid, firstCanTime) {
|
function _calcGraphData(msg, signalUid, firstCanTime) {
|
||||||
if (!msg) return null;
|
if (!msg) return null;
|
||||||
|
|
||||||
const signal = Object.values(msg.frame.signals).find(
|
const signal = Object.values(msg.frame.signals).find(
|
||||||
s => s.uid === signalUid
|
(s) => s.uid === signalUid
|
||||||
);
|
);
|
||||||
if (!signal) {
|
if (!signal) {
|
||||||
console.warn("_calcGraphData: no signal", signalUid, msg);
|
console.warn('_calcGraphData: no signal', signalUid, msg);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let samples = [];
|
let samples = [];
|
||||||
let skip = Math.floor(msg.entries.length / CAN_GRAPH_MAX_POINTS);
|
const skip = Math.floor(msg.entries.length / CAN_GRAPH_MAX_POINTS);
|
||||||
|
|
||||||
if (skip === 0) {
|
if (skip === 0) {
|
||||||
samples = msg.entries;
|
samples = msg.entries;
|
||||||
|
@ -29,8 +29,8 @@ function _calcGraphData(msg, signalUid, firstCanTime) {
|
||||||
// sorting these doesn't fix the phantom lines
|
// sorting these doesn't fix the phantom lines
|
||||||
let lastEntry = samples[0].relTime;
|
let lastEntry = samples[0].relTime;
|
||||||
return samples
|
return samples
|
||||||
.filter(e => e.signals[signal.name] !== undefined)
|
.filter((e) => e.signals[signal.name] !== undefined)
|
||||||
.map(entry => {
|
.map((entry) => {
|
||||||
if (entry.relTime - lastEntry > 2) {
|
if (entry.relTime - lastEntry > 2) {
|
||||||
signalUid = Math.random().toString(36);
|
signalUid = Math.random().toString(36);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ function _calcGraphData(msg, signalUid, firstCanTime) {
|
||||||
relTime: entry.relTime,
|
relTime: entry.relTime,
|
||||||
y: entry.signals[signal.name],
|
y: entry.signals[signal.name],
|
||||||
unit: signal.unit,
|
unit: signal.unit,
|
||||||
color: `rgba(${signal.colors.join(",")}, 0.5)`,
|
color: `rgba(${signal.colors.join(',')}, 0.5)`,
|
||||||
signalName: signal.name,
|
signalName: signal.name,
|
||||||
signalUid
|
signalUid
|
||||||
};
|
};
|
||||||
|
@ -49,17 +49,13 @@ function _calcGraphData(msg, signalUid, firstCanTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) {
|
function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) {
|
||||||
const messagesPerPlot = plottedSignals.map(plottedMessages =>
|
const messagesPerPlot = plottedSignals.map((plottedMessages) => plottedMessages.reduce((messages, { messageId, signalUid }) => {
|
||||||
plottedMessages.reduce((messages, { messageId, signalUid }) => {
|
messages.push(messageId);
|
||||||
messages.push(messageId);
|
return messages;
|
||||||
return messages;
|
}, []));
|
||||||
}, [])
|
|
||||||
);
|
|
||||||
|
|
||||||
const extendedPlots = messagesPerPlot
|
const extendedPlots = messagesPerPlot
|
||||||
.map((plottedMessageIds, index) => {
|
.map((plottedMessageIds, index) => ({ plottedMessageIds, index })) // preserve index so we can look up graphData
|
||||||
return { plottedMessageIds, index };
|
|
||||||
}) // preserve index so we can look up graphData
|
|
||||||
.filter(({ plottedMessageIds, index }) => {
|
.filter(({ plottedMessageIds, index }) => {
|
||||||
if (index < graphData.length) {
|
if (index < graphData.length) {
|
||||||
let maxGraphTime = 0;
|
let maxGraphTime = 0;
|
||||||
|
@ -69,13 +65,11 @@ function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return plottedMessageIds.some(
|
return plottedMessageIds.some(
|
||||||
messageId =>
|
(messageId) => (messages[messageId].entries.length > 0 && series.length === 0)
|
||||||
(messages[messageId].entries.length > 0 && series.length === 0) ||
|
|| messages[messageId].entries.some((e) => e.relTime > maxGraphTime)
|
||||||
messages[messageId].entries.some(e => e.relTime > maxGraphTime)
|
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
})
|
})
|
||||||
.map(({ plottedMessageIds, index }) => {
|
.map(({ plottedMessageIds, index }) => {
|
||||||
plottedMessageIds = plottedMessageIds.reduce((arr, messageId) => {
|
plottedMessageIds = plottedMessageIds.reduce((arr, messageId) => {
|
||||||
|
@ -102,9 +96,10 @@ function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) {
|
||||||
const graphDataMaxMessageTimes = plottedMessageIds.reduce(
|
const graphDataMaxMessageTimes = plottedMessageIds.reduce(
|
||||||
(obj, messageId) => {
|
(obj, messageId) => {
|
||||||
const signalUids = signalUidsByMessageId[messageId];
|
const signalUids = signalUidsByMessageId[messageId];
|
||||||
const maxIndex = ArrayUtils.findIndexRight(series, entry => {
|
const maxIndex = ArrayUtils.findIndexRight(
|
||||||
return signalUids.indexOf(entry.signalUid) !== -1;
|
series,
|
||||||
});
|
(entry) => signalUids.indexOf(entry.signalUid) !== -1
|
||||||
|
);
|
||||||
if (maxIndex) {
|
if (maxIndex) {
|
||||||
obj[messageId] = series[maxIndex].relTime;
|
obj[messageId] = series[maxIndex].relTime;
|
||||||
} else if (series.length > 0) {
|
} else if (series.length > 0) {
|
||||||
|
@ -121,24 +116,21 @@ function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) {
|
||||||
|
|
||||||
let newGraphData = [];
|
let newGraphData = [];
|
||||||
plottedMessageIds
|
plottedMessageIds
|
||||||
.map(messageId => {
|
.map((messageId) => ({ messageId, entries: messages[messageId].entries }))
|
||||||
return { messageId, entries: messages[messageId].entries };
|
|
||||||
})
|
|
||||||
.filter(
|
.filter(
|
||||||
(
|
(
|
||||||
{ messageId, entries } // Filter to only messages with stale graphData
|
{ messageId, entries } // Filter to only messages with stale graphData
|
||||||
) =>
|
) => entries[entries.length - 1].relTime
|
||||||
entries[entries.length - 1].relTime >
|
> graphDataMaxMessageTimes[messageId]
|
||||||
graphDataMaxMessageTimes[messageId]
|
|
||||||
)
|
)
|
||||||
.forEach(({ messageId, entries }) => {
|
.forEach(({ messageId, entries }) => {
|
||||||
// Compute and append new graphData
|
// Compute and append new graphData
|
||||||
let firstNewEntryIdx = entries.findIndex(
|
const firstNewEntryIdx = entries.findIndex(
|
||||||
entry => entry.relTime > graphDataMaxMessageTimes[messageId]
|
(entry) => entry.relTime > graphDataMaxMessageTimes[messageId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const newEntries = entries.slice(firstNewEntryIdx);
|
const newEntries = entries.slice(firstNewEntryIdx);
|
||||||
signalUidsByMessageId[messageId].forEach(signalUid => {
|
signalUidsByMessageId[messageId].forEach((signalUid) => {
|
||||||
const signalGraphData = _calcGraphData(
|
const signalGraphData = _calcGraphData(
|
||||||
{
|
{
|
||||||
...messages[messageId],
|
...messages[messageId],
|
||||||
|
@ -152,12 +144,10 @@ function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const messageIdOutOfBounds =
|
const messageIdOutOfBounds = series.length > 0
|
||||||
series.length > 0 &&
|
&& plottedMessageIds.find(
|
||||||
plottedMessageIds.find(
|
(messageId) => messages[messageId].entries.length > 0
|
||||||
messageId =>
|
&& series[0].relTime < messages[messageId].entries[0].relTime
|
||||||
messages[messageId].entries.length > 0 &&
|
|
||||||
series[0].relTime < messages[messageId].entries[0].relTime
|
|
||||||
);
|
);
|
||||||
graphData[index] = {
|
graphData[index] = {
|
||||||
series: graphData[index].series.concat(newGraphData),
|
series: graphData[index].series.concat(newGraphData),
|
||||||
|
@ -166,7 +156,7 @@ function appendNewGraphData(plottedSignals, graphData, messages, firstCanTime) {
|
||||||
|
|
||||||
if (messageIdOutOfBounds) {
|
if (messageIdOutOfBounds) {
|
||||||
const graphDataLowerBound = graphData[index].series.findIndex(
|
const graphDataLowerBound = graphData[index].series.findIndex(
|
||||||
e => e.relTime > messages[messageIdOutOfBounds].entries[0].relTime
|
(e) => e.relTime > messages[messageIdOutOfBounds].entries[0].relTime
|
||||||
);
|
);
|
||||||
|
|
||||||
if (graphDataLowerBound) {
|
if (graphDataLowerBound) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { configure } from "enzyme";
|
import { configure } from 'enzyme';
|
||||||
import Adapter from "enzyme-adapter-react-16";
|
import Adapter from 'enzyme-adapter-react-16';
|
||||||
|
|
||||||
configure({ adapter: new Adapter() });
|
configure({ adapter: new Adapter() });
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import { StyleSheet, css } from "aphrodite/no-important";
|
import { StyleSheet, css } from 'aphrodite/no-important';
|
||||||
|
|
||||||
import * as ObjectUtils from "../utils/object";
|
import * as ObjectUtils from '../utils/object';
|
||||||
|
|
||||||
function createImageComponent(source, alt, styles) {
|
function createImageComponent(source, alt, styles) {
|
||||||
if (styles === undefined) {
|
if (styles === undefined) {
|
||||||
|
@ -10,13 +10,13 @@ function createImageComponent(source, alt, styles) {
|
||||||
styles = [styles];
|
styles = [styles];
|
||||||
}
|
}
|
||||||
|
|
||||||
return props => {
|
return (props) => {
|
||||||
let localStyles = styles.slice();
|
let localStyles = styles.slice();
|
||||||
if (Array.isArray(props.styles)) {
|
if (Array.isArray(props.styles)) {
|
||||||
localStyles = localStyles.concat(props.styles);
|
localStyles = localStyles.concat(props.styles);
|
||||||
// filter 'styles' from props, which is passed via spread to <img> tag.
|
// filter 'styles' from props, which is passed via spread to <img> tag.
|
||||||
props = ObjectUtils.fromArray(
|
props = ObjectUtils.fromArray(
|
||||||
Object.entries(props).filter(([k, v]) => k !== "styles")
|
Object.entries(props).filter(([k, v]) => k !== 'styles')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,36 +32,42 @@ const Styles = StyleSheet.create({
|
||||||
height: 24
|
height: 24
|
||||||
},
|
},
|
||||||
pointer: {
|
pointer: {
|
||||||
cursor: "pointer"
|
cursor: 'pointer'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const leftArrow = createImageComponent(
|
const leftArrow = createImageComponent(
|
||||||
process.env.PUBLIC_URL + "/img/ic_arrow_left_black_24dp.png",
|
`${process.env.PUBLIC_URL}/img/ic_arrow_left_black_24dp.png`,
|
||||||
"Left arrow",
|
'Left arrow',
|
||||||
Styles.materialIcon
|
Styles.materialIcon
|
||||||
);
|
);
|
||||||
const rightArrow = createImageComponent(
|
const rightArrow = createImageComponent(
|
||||||
process.env.PUBLIC_URL + "/img/ic_arrow_right_black_24dp.png",
|
`${process.env.PUBLIC_URL}/img/ic_arrow_right_black_24dp.png`,
|
||||||
"Right arrow",
|
'Right arrow',
|
||||||
Styles.materialIcon
|
Styles.materialIcon
|
||||||
);
|
);
|
||||||
|
|
||||||
const downArrow = createImageComponent(
|
const downArrow = createImageComponent(
|
||||||
process.env.PUBLIC_URL + "/img/ic_arrow_drop_down_black_24dp.png",
|
`${process.env.PUBLIC_URL}/img/ic_arrow_drop_down_black_24dp.png`,
|
||||||
"Down arrow",
|
'Down arrow',
|
||||||
Styles.materialIcon
|
Styles.materialIcon
|
||||||
);
|
);
|
||||||
|
|
||||||
const clear = createImageComponent(
|
const clear = createImageComponent(
|
||||||
process.env.PUBLIC_URL + "/img/ic_clear_black_24dp.png",
|
`${process.env.PUBLIC_URL}/img/ic_clear_black_24dp.png`,
|
||||||
"Clear",
|
'Clear',
|
||||||
[Styles.materialIcon, Styles.pointer]
|
[Styles.materialIcon, Styles.pointer]
|
||||||
);
|
);
|
||||||
|
|
||||||
const panda = createImageComponent(
|
const panda = createImageComponent(
|
||||||
process.env.PUBLIC_URL + "/img/panda.png",
|
`${process.env.PUBLIC_URL}/img/panda.png`,
|
||||||
"Panda",
|
'Panda',
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
export default { rightArrow, leftArrow, downArrow, clear, panda };
|
export default {
|
||||||
|
rightArrow,
|
||||||
|
leftArrow,
|
||||||
|
downArrow,
|
||||||
|
clear,
|
||||||
|
panda
|
||||||
|
};
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { StyleSheet } from "aphrodite/no-important";
|
import { StyleSheet } from 'aphrodite/no-important';
|
||||||
|
|
||||||
export default StyleSheet.create({
|
export default StyleSheet.create({
|
||||||
tab: {
|
tab: {
|
||||||
display: "inline",
|
display: 'inline',
|
||||||
marginRight: 20,
|
marginRight: 20,
|
||||||
cursor: "pointer"
|
cursor: 'pointer'
|
||||||
},
|
},
|
||||||
selectedTab: {
|
selectedTab: {
|
||||||
borderBottom: "2px solid #000",
|
borderBottom: '2px solid #000',
|
||||||
fontWeight: "bold"
|
fontWeight: 'bold'
|
||||||
},
|
},
|
||||||
tabContent: {
|
tabContent: {
|
||||||
paddingTop: 20
|
paddingTop: 20
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import { StyleSheet } from "aphrodite/no-important";
|
import { StyleSheet } from 'aphrodite/no-important';
|
||||||
|
|
||||||
export default StyleSheet.create({
|
export default StyleSheet.create({
|
||||||
root: {
|
root: {
|
||||||
flexDirection: "row"
|
flexDirection: 'row'
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
cursor: "pointer",
|
cursor: 'pointer',
|
||||||
backgroundColor: "RGB(63, 135, 255)",
|
backgroundColor: 'RGB(63, 135, 255)',
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
minWidth: 80,
|
minWidth: 80,
|
||||||
paddingLeft: 20,
|
paddingLeft: 20,
|
||||||
paddingRight: 20,
|
paddingRight: 20,
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
color: "white",
|
color: 'white',
|
||||||
":hover": {
|
':hover': {
|
||||||
backgroundColor: "RGBA(63, 135, 255, 0.5)"
|
backgroundColor: 'RGBA(63, 135, 255, 0.5)'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,14 +4,14 @@
|
||||||
|
|
||||||
// Useful for component testing
|
// Useful for component testing
|
||||||
|
|
||||||
import { css } from "aphrodite";
|
import { css } from 'aphrodite';
|
||||||
import classNames from "classnames";
|
import classNames from 'classnames';
|
||||||
|
|
||||||
export default function() {
|
export default function () {
|
||||||
const styles = [];
|
const styles = [];
|
||||||
const classes = [];
|
const classes = [];
|
||||||
|
|
||||||
[].forEach.call(arguments, it => {
|
[].forEach.call(arguments, (it) => {
|
||||||
if (it && it._definition && it._name) styles.push(it);
|
if (it && it._definition && it._name) styles.push(it);
|
||||||
else classes.push(it);
|
else classes.push(it);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
function findMaxByteStateChangeCount(messages) {
|
function findMaxByteStateChangeCount(messages) {
|
||||||
return Object.values(messages)
|
return Object.values(messages)
|
||||||
.map(m => m.byteStateChangeCounts)
|
.map((m) => m.byteStateChangeCounts)
|
||||||
.reduce((counts, countArr) => counts.concat(countArr), []) // flatten arrays
|
.reduce((counts, countArr) => counts.concat(countArr), []) // flatten arrays
|
||||||
.reduce((count1, count2) => (count1 > count2 ? count1 : count2), 0); // find max
|
.reduce((count1, count2) => (count1 > count2 ? count1 : count2), 0); // find max
|
||||||
}
|
}
|
||||||
|
@ -13,20 +13,20 @@ function addCanMessage(
|
||||||
prevMsgEntries,
|
prevMsgEntries,
|
||||||
byteStateChangeCountsByMessage
|
byteStateChangeCountsByMessage
|
||||||
) {
|
) {
|
||||||
var { address, busTime, data, bus } = canMessage;
|
const {
|
||||||
var id = bus + ":" + address.toString(16);
|
address, busTime, data, bus
|
||||||
|
} = canMessage;
|
||||||
|
const id = `${bus}:${address.toString(16)}`;
|
||||||
|
|
||||||
if (messages[id] === undefined)
|
if (messages[id] === undefined) messages[id] = createMessageSpec(dbc, address, id, bus);
|
||||||
messages[id] = createMessageSpec(dbc, address, id, bus);
|
|
||||||
|
|
||||||
const prevMsgEntry =
|
const prevMsgEntry = messages[id].entries.length > 0
|
||||||
messages[id].entries.length > 0
|
? messages[id].entries[messages[id].entries.length - 1]
|
||||||
? messages[id].entries[messages[id].entries.length - 1]
|
: prevMsgEntries[id] || null;
|
||||||
: prevMsgEntries[id] || null;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
byteStateChangeCountsByMessage[id] &&
|
byteStateChangeCountsByMessage[id]
|
||||||
messages[id].byteStateChangeCounts.every(c => c === 0)
|
&& messages[id].byteStateChangeCounts.every((c) => c === 0)
|
||||||
) {
|
) {
|
||||||
messages[id].byteStateChangeCounts = byteStateChangeCountsByMessage[id];
|
messages[id].byteStateChangeCounts = byteStateChangeCountsByMessage[id];
|
||||||
}
|
}
|
||||||
|
@ -54,11 +54,11 @@ function createMessageSpec(dbc, address, id, bus) {
|
||||||
const size = frame ? frame.size : 8;
|
const size = frame ? frame.size : 8;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
address: address,
|
address,
|
||||||
id: id,
|
id,
|
||||||
bus: bus,
|
bus,
|
||||||
entries: [],
|
entries: [],
|
||||||
frame: frame,
|
frame,
|
||||||
byteColors: Array(size).fill(0),
|
byteColors: Array(size).fill(0),
|
||||||
byteStateChangeCounts: Array(size).fill(0)
|
byteStateChangeCounts: Array(size).fill(0)
|
||||||
};
|
};
|
||||||
|
@ -79,8 +79,8 @@ function determineByteStateChangeTimes(
|
||||||
byteStateChangeTimes = Array.from(lastParsedMessage.byteStateChangeTimes);
|
byteStateChangeTimes = Array.from(lastParsedMessage.byteStateChangeTimes);
|
||||||
|
|
||||||
for (let i = 0; i < byteStateChangeTimes.length; i++) {
|
for (let i = 0; i < byteStateChangeTimes.length; i++) {
|
||||||
const currentData = hexData.substr(i * 2, 2),
|
const currentData = hexData.substr(i * 2, 2);
|
||||||
prevData = lastParsedMessage.hexData.substr(i * 2, 2);
|
const prevData = lastParsedMessage.hexData.substr(i * 2, 2);
|
||||||
|
|
||||||
if (currentData !== prevData) {
|
if (currentData !== prevData) {
|
||||||
byteStateChangeTimes[i] = time;
|
byteStateChangeTimes[i] = time;
|
||||||
|
@ -104,7 +104,7 @@ function createMessageEntry(
|
||||||
signals: dbc.getSignalValues(address, data),
|
signals: dbc.getSignalValues(address, data),
|
||||||
time,
|
time,
|
||||||
relTime,
|
relTime,
|
||||||
hexData: Buffer.from(data).toString("hex"),
|
hexData: Buffer.from(data).toString('hex'),
|
||||||
byteStateChangeTimes,
|
byteStateChangeTimes,
|
||||||
updated: Date.now()
|
updated: Date.now()
|
||||||
};
|
};
|
||||||
|
@ -112,11 +112,11 @@ function createMessageEntry(
|
||||||
|
|
||||||
function parseMessage(dbc, time, address, data, timeStart, lastParsedMessage) {
|
function parseMessage(dbc, time, address, data, timeStart, lastParsedMessage) {
|
||||||
let hexData;
|
let hexData;
|
||||||
if (typeof data === "string") {
|
if (typeof data === 'string') {
|
||||||
hexData = data;
|
hexData = data;
|
||||||
data = Buffer.from(data, "hex");
|
data = Buffer.from(data, 'hex');
|
||||||
} else {
|
} else {
|
||||||
hexData = Buffer.from(data).toString("hex");
|
hexData = Buffer.from(data).toString('hex');
|
||||||
}
|
}
|
||||||
const msgSpec = dbc.getMessageFrame(address);
|
const msgSpec = dbc.getMessageFrame(address);
|
||||||
const msgSize = msgSpec ? msgSpec.size : 8;
|
const msgSize = msgSpec ? msgSpec.size : 8;
|
||||||
|
@ -160,13 +160,10 @@ function matrixBitNumber(bigEndianIndex) {
|
||||||
|
|
||||||
function setMessageByteColors(message, maxByteStateChangeCount) {
|
function setMessageByteColors(message, maxByteStateChangeCount) {
|
||||||
message.byteColors = message.byteStateChangeCounts
|
message.byteColors = message.byteStateChangeCounts
|
||||||
.map(
|
.map((count) => (isNaN(count)
|
||||||
count =>
|
? 0
|
||||||
isNaN(count)
|
: Math.min(255, 75 + 180 * (count / maxByteStateChangeCount))))
|
||||||
? 0
|
.map((red) => `rgb(${Math.round(red)},0,0)`);
|
||||||
: Math.min(255, 75 + 180 * (count / maxByteStateChangeCount))
|
|
||||||
)
|
|
||||||
.map(red => "rgb(" + Math.round(red) + ",0,0)");
|
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
export default function debounce(func, wait, immediate) {
|
export default function debounce(func, wait, immediate) {
|
||||||
var timeout;
|
let timeout;
|
||||||
return function() {
|
return function () {
|
||||||
var context = this,
|
const context = this;
|
||||||
args = arguments;
|
const args = arguments;
|
||||||
var later = function() {
|
const later = function () {
|
||||||
timeout = null;
|
timeout = null;
|
||||||
if (!immediate) func.apply(context, args);
|
if (!immediate) func.apply(context, args);
|
||||||
};
|
};
|
||||||
var callNow = immediate && !timeout;
|
const callNow = immediate && !timeout;
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
timeout = setTimeout(later, wait);
|
timeout = setTimeout(later, wait);
|
||||||
if (callNow) func.apply(context, args);
|
if (callNow) func.apply(context, args);
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
const binTimeIntervals = [
|
const binTimeIntervals = [
|
||||||
{
|
{
|
||||||
seconds: 1,
|
seconds: 1,
|
||||||
title: "second"
|
title: 'second'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
seconds: 60,
|
seconds: 60,
|
||||||
title: "minute"
|
title: 'minute'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
seconds: 300,
|
seconds: 300,
|
||||||
title: "5 minutes"
|
title: '5 minutes'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
seconds: 3600,
|
seconds: 3600,
|
||||||
title: "hour"
|
title: 'hour'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -33,13 +33,13 @@ function prettyBinDuration(samplesDurationSeconds, maxBinCount = 100) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function binMessages(messageEntries, segmentIndices) {
|
export function binMessages(messageEntries, segmentIndices) {
|
||||||
let startIdx = 0,
|
let startIdx = 0;
|
||||||
endIdx = messageEntries.length - 1;
|
let endIdx = messageEntries.length - 1;
|
||||||
if (segmentIndices && segmentIndices.length === 2) {
|
if (segmentIndices && segmentIndices.length === 2) {
|
||||||
[startIdx, endIdx] = segmentIndices;
|
[startIdx, endIdx] = segmentIndices;
|
||||||
}
|
}
|
||||||
const first = messageEntries[startIdx],
|
const first = messageEntries[startIdx];
|
||||||
last = messageEntries[endIdx];
|
const last = messageEntries[endIdx];
|
||||||
const binDuration = prettyBinDuration(last.time - first.time);
|
const binDuration = prettyBinDuration(last.time - first.time);
|
||||||
|
|
||||||
const bins = [];
|
const bins = [];
|
||||||
|
@ -63,5 +63,5 @@ export function binMessages(messageEntries, segmentIndices) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return { bins: bins, binDuration };
|
return { bins, binDuration };
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,103 +7,103 @@ const NumpyLoader = (function NumpyLoader() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function readUint16LE(buffer) {
|
function readUint16LE(buffer) {
|
||||||
var view = new DataView(buffer);
|
const view = new DataView(buffer);
|
||||||
var val = view.getUint8(0);
|
let val = view.getUint8(0);
|
||||||
val |= view.getUint8(1) << 8;
|
val |= view.getUint8(1) << 8;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fromArrayBuffer(buf) {
|
function fromArrayBuffer(buf) {
|
||||||
// Check the magic number
|
// Check the magic number
|
||||||
var magic = asciiDecode(buf.slice(0, 6));
|
const magic = asciiDecode(buf.slice(0, 6));
|
||||||
if (magic !== "\x93NUMPY") {
|
if (magic !== '\x93NUMPY') {
|
||||||
throw new Error("Bad magic number");
|
throw new Error('Bad magic number');
|
||||||
}
|
}
|
||||||
|
|
||||||
var version = new Uint8Array(buf.slice(6, 8)),
|
const version = new Uint8Array(buf.slice(6, 8));
|
||||||
headerLength = readUint16LE(buf.slice(8, 10)),
|
const headerLength = readUint16LE(buf.slice(8, 10));
|
||||||
headerStr = asciiDecode(buf.slice(10, 10 + headerLength));
|
const headerStr = asciiDecode(buf.slice(10, 10 + headerLength));
|
||||||
const offsetBytes = 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
|
// 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
|
// Hacky conversion of dict literal string to JS Object
|
||||||
const info = JSON.parse(
|
const info = JSON.parse(
|
||||||
headerStr
|
headerStr
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replace("(", "[")
|
.replace('(', '[')
|
||||||
.replace("),", "]")
|
.replace('),', ']')
|
||||||
.replace(/'/g, '"')
|
.replace(/'/g, '"')
|
||||||
.replace(",]", "]")
|
.replace(',]', ']')
|
||||||
);
|
);
|
||||||
|
|
||||||
// Intepret the bytes according to the specified dtype
|
// Intepret the bytes according to the specified dtype
|
||||||
var data;
|
let data;
|
||||||
if (info.descr === "|u1") {
|
if (info.descr === '|u1') {
|
||||||
data = new Uint8Array(buf, offsetBytes);
|
data = new Uint8Array(buf, offsetBytes);
|
||||||
} else if (info.descr === "|i1") {
|
} else if (info.descr === '|i1') {
|
||||||
data = new Int8Array(buf, offsetBytes);
|
data = new Int8Array(buf, offsetBytes);
|
||||||
} else if (info.descr === "<u2") {
|
} else if (info.descr === '<u2') {
|
||||||
data = new Uint16Array(buf, offsetBytes);
|
data = new Uint16Array(buf, offsetBytes);
|
||||||
} else if (info.descr === "<i2") {
|
} else if (info.descr === '<i2') {
|
||||||
data = new Int16Array(buf, offsetBytes);
|
data = new Int16Array(buf, offsetBytes);
|
||||||
} else if (info.descr === "<u4") {
|
} else if (info.descr === '<u4') {
|
||||||
data = new Uint32Array(buf, offsetBytes);
|
data = new Uint32Array(buf, offsetBytes);
|
||||||
} else if (info.descr === "<i4") {
|
} else if (info.descr === '<i4') {
|
||||||
data = new Int32Array(buf, offsetBytes);
|
data = new Int32Array(buf, offsetBytes);
|
||||||
} else if (info.descr === "<f4") {
|
} else if (info.descr === '<f4') {
|
||||||
data = new Float32Array(buf, offsetBytes);
|
data = new Float32Array(buf, offsetBytes);
|
||||||
} else if (info.descr === "<f8") {
|
} else if (info.descr === '<f8') {
|
||||||
data = new Float64Array(buf, offsetBytes);
|
data = new Float64Array(buf, offsetBytes);
|
||||||
} else if (info.descr === "<u8") {
|
} else if (info.descr === '<u8') {
|
||||||
// 8 byte uint64s
|
// 8 byte uint64s
|
||||||
data = new Uint8Array(buf, offsetBytes);
|
data = new Uint8Array(buf, offsetBytes);
|
||||||
} else if (info.descr === "<i8") {
|
} else if (info.descr === '<i8') {
|
||||||
// 8 byte int64s
|
// 8 byte int64s
|
||||||
data = new Uint8Array(buf, offsetBytes);
|
data = new Uint8Array(buf, offsetBytes);
|
||||||
} else if (info.descr === "|s5") {
|
} else if (info.descr === '|s5') {
|
||||||
// 5 byte string
|
// 5 byte string
|
||||||
data = new Uint8Array(buf, offsetBytes);
|
data = new Uint8Array(buf, offsetBytes);
|
||||||
} else if (info.descr === "|s8") {
|
} else if (info.descr === '|s8') {
|
||||||
// 8 byte strings
|
// 8 byte strings
|
||||||
data = new Uint8Array(buf, offsetBytes);
|
data = new Uint8Array(buf, offsetBytes);
|
||||||
} else if (info.descr === "|s15") {
|
} else if (info.descr === '|s15') {
|
||||||
// 15 byte strings?
|
// 15 byte strings?
|
||||||
data = new Uint8Array(buf, offsetBytes);
|
data = new Uint8Array(buf, offsetBytes);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("unknown numeric dtype " + info.descr);
|
throw new Error(`unknown numeric dtype ${info.descr}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
shape: info.shape,
|
shape: info.shape,
|
||||||
fortran_order: info.fortran_order,
|
fortran_order: info.fortran_order,
|
||||||
data: data
|
data
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function open(file, callback) {
|
function open(file, callback) {
|
||||||
var reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = function() {
|
reader.onload = function () {
|
||||||
// the file contents have been read as an array buffer
|
// the file contents have been read as an array buffer
|
||||||
var buf = reader.result;
|
const buf = reader.result;
|
||||||
var ndarray = fromArrayBuffer(buf);
|
const ndarray = fromArrayBuffer(buf);
|
||||||
callback(ndarray);
|
callback(ndarray);
|
||||||
};
|
};
|
||||||
reader.readAsArrayBuffer(file);
|
reader.readAsArrayBuffer(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
function promise(url) {
|
function promise(url) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise((resolve, reject) => {
|
||||||
// Do the usual XHR stuff
|
// Do the usual XHR stuff
|
||||||
var req = new XMLHttpRequest();
|
const req = new XMLHttpRequest();
|
||||||
req.onload = function() {
|
req.onload = function () {
|
||||||
// This is called even on 404 etc
|
// This is called even on 404 etc
|
||||||
// so check the status
|
// so check the status
|
||||||
if (req.status == 200) {
|
if (req.status == 200) {
|
||||||
var buf = req.response; // not responseText
|
const buf = req.response; // not responseText
|
||||||
var ndarray = fromArrayBuffer(buf);
|
const ndarray = fromArrayBuffer(buf);
|
||||||
resolve(ndarray);
|
resolve(ndarray);
|
||||||
} else if (req.status == 404) {
|
} else if (req.status == 404) {
|
||||||
console.log("yup");
|
console.log('yup');
|
||||||
reject({ is404: true });
|
reject({ is404: true });
|
||||||
} else {
|
} else {
|
||||||
// Otherwise reject with the status text
|
// Otherwise reject with the status text
|
||||||
|
@ -113,22 +113,22 @@ const NumpyLoader = (function NumpyLoader() {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle network errors
|
// Handle network errors
|
||||||
req.onerror = function() {
|
req.onerror = function () {
|
||||||
reject(Error("Network Error"));
|
reject(Error('Network Error'));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make the request
|
// Make the request
|
||||||
req.open("GET", url, true);
|
req.open('GET', url, true);
|
||||||
req.responseType = "arraybuffer";
|
req.responseType = 'arraybuffer';
|
||||||
req.send(null);
|
req.send(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
open: open,
|
open,
|
||||||
promise: promise,
|
promise,
|
||||||
fromArrayBuffer: fromArrayBuffer
|
fromArrayBuffer
|
||||||
};
|
};
|
||||||
})();
|
}());
|
||||||
|
|
||||||
module.exports = NumpyLoader;
|
module.exports = NumpyLoader;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export function swapKeysAndValues(obj, f) {
|
export function swapKeysAndValues(obj, f) {
|
||||||
return Object.keys(obj).reduce(function(acc, k) {
|
return Object.keys(obj).reduce((acc, k) => {
|
||||||
acc[obj[k]] = k;
|
acc[obj[k]] = k;
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
@ -12,7 +12,6 @@ export function fromArray(arr) {
|
||||||
const pairs = arr.map(([k, v]) => ({ [k]: v }));
|
const pairs = arr.map(([k, v]) => ({ [k]: v }));
|
||||||
if (pairs.length > 0) {
|
if (pairs.length > 0) {
|
||||||
return Object.assign(...pairs);
|
return Object.assign(...pairs);
|
||||||
} else {
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export function hash(str) {
|
export function hash(str) {
|
||||||
var hash = 5381,
|
let hash = 5381;
|
||||||
i = str.length;
|
let i = str.length;
|
||||||
|
|
||||||
while (i) {
|
while (i) {
|
||||||
hash = (hash * 33) ^ str.charCodeAt(--i);
|
hash = (hash * 33) ^ str.charCodeAt(--i);
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
/* eslint-disable no-restricted-globals*/
|
/* eslint-disable no-restricted-globals */
|
||||||
export function objToQuery(obj) {
|
export function objToQuery(obj) {
|
||||||
return Object.keys(obj)
|
return Object.keys(obj)
|
||||||
.map(k => k + "=" + encodeURIComponent(decodeURIComponent(obj[k])))
|
.map((k) => `${k}=${encodeURIComponent(decodeURIComponent(obj[k]))}`)
|
||||||
.join("&");
|
.join('&');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUrlParameter(name) {
|
export function getUrlParameter(name) {
|
||||||
var location = window.location;
|
const { location } = window;
|
||||||
name = name.replace(/[[]/, "\\[").replace(/[\]]/, "\\]");
|
name = name.replace(/[[]/, '\\[').replace(/[\]]/, '\\]');
|
||||||
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
|
const regex = new RegExp(`[\\?&]${name}=([^&#]*)`);
|
||||||
var results = regex.exec(location.search);
|
const results = regex.exec(location.search);
|
||||||
|
|
||||||
return results === null
|
return results === null
|
||||||
? null
|
? null
|
||||||
: decodeURIComponent(results[1].replace(/\+/g, " "));
|
: decodeURIComponent(results[1].replace(/\+/g, ' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function modifyQueryParameters({ add, remove = [] }) {
|
export function modifyQueryParameters({ add, remove = [] }) {
|
||||||
var regex = new RegExp("[\\?&]([^&#]+)=([^&#]*)");
|
const regex = new RegExp('[\\?&]([^&#]+)=([^&#]*)');
|
||||||
var results = regex.exec(location.search);
|
const results = regex.exec(location.search);
|
||||||
|
|
||||||
let params = {};
|
let params = {};
|
||||||
if (results != null) {
|
if (results != null) {
|
||||||
for (let i = 1; i < results.length - 1; i += 2) {
|
for (let i = 1; i < results.length - 1; i += 2) {
|
||||||
let key = results[i],
|
const key = results[i];
|
||||||
value = results[i + 1];
|
const value = results[i + 1];
|
||||||
params[key] = value;
|
params[key] = value;
|
||||||
}
|
}
|
||||||
for (let key in params) {
|
for (const key in params) {
|
||||||
if (remove.indexOf(key) !== -1) {
|
if (remove.indexOf(key) !== -1) {
|
||||||
delete params[key];
|
delete params[key];
|
||||||
}
|
}
|
||||||
|
@ -37,5 +37,5 @@ export function modifyQueryParameters({ add, remove = [] }) {
|
||||||
params = add;
|
params = add;
|
||||||
}
|
}
|
||||||
|
|
||||||
return location.origin + location.pathname + "?" + objToQuery(params);
|
return `${location.origin + location.pathname}?${objToQuery(params)}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,111 +1,121 @@
|
||||||
import { createClassFromSpec } from "react-vega";
|
import { createClassFromSpec } from 'react-vega';
|
||||||
|
|
||||||
const canHistogramSpec = {
|
const canHistogramSpec = {
|
||||||
$schema: "https://vega.github.io/schema/vega/v3.0.json",
|
$schema: 'https://vega.github.io/schema/vega/v3.0.json',
|
||||||
width: 1000,
|
width: 1000,
|
||||||
height: 100,
|
height: 100,
|
||||||
padding: 5,
|
padding: 5,
|
||||||
|
|
||||||
signals: [
|
signals: [
|
||||||
{
|
{
|
||||||
name: "segment"
|
name: 'segment'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
name: "binned"
|
name: 'binned'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
scales: [
|
scales: [
|
||||||
{
|
{
|
||||||
name: "xscale",
|
name: 'xscale',
|
||||||
type: "linear",
|
type: 'linear',
|
||||||
zero: false,
|
zero: false,
|
||||||
range: "width",
|
range: 'width',
|
||||||
domain: { data: "binned", field: "startTime" }
|
domain: { data: 'binned', field: 'startTime' }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "xrelscale",
|
name: 'xrelscale',
|
||||||
type: "linear",
|
type: 'linear',
|
||||||
zero: false,
|
zero: false,
|
||||||
range: "width",
|
range: 'width',
|
||||||
domain: { data: "binned", field: "relStartTime" }
|
domain: { data: 'binned', field: 'relStartTime' }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "yscale",
|
name: 'yscale',
|
||||||
type: "linear",
|
type: 'linear',
|
||||||
range: "height",
|
range: 'height',
|
||||||
round: true,
|
round: true,
|
||||||
domain: { data: "binned", field: "count" },
|
domain: { data: 'binned', field: 'count' },
|
||||||
zero: true,
|
zero: true,
|
||||||
nice: true
|
nice: true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
axes: [
|
axes: [
|
||||||
{ orient: "bottom", scale: "xrelscale", zindex: 1, tickCount: 10 },
|
{
|
||||||
{ orient: "left", scale: "yscale", tickCount: 5, zindex: 1 }
|
orient: 'bottom',
|
||||||
|
scale: 'xrelscale',
|
||||||
|
zindex: 1,
|
||||||
|
tickCount: 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
orient: 'left',
|
||||||
|
scale: 'yscale',
|
||||||
|
tickCount: 5,
|
||||||
|
zindex: 1
|
||||||
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
marks: [
|
marks: [
|
||||||
{
|
{
|
||||||
type: "group",
|
type: 'group',
|
||||||
name: "histogram",
|
name: 'histogram',
|
||||||
interactive: true,
|
interactive: true,
|
||||||
encode: {
|
encode: {
|
||||||
enter: {
|
enter: {
|
||||||
height: { value: 75 },
|
height: { value: 75 },
|
||||||
width: { value: 1000 },
|
width: { value: 1000 },
|
||||||
fill: { value: "transparent" }
|
fill: { value: 'transparent' }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
signals: [
|
signals: [
|
||||||
{
|
{
|
||||||
name: "brush",
|
name: 'brush',
|
||||||
value: 0,
|
value: 0,
|
||||||
on: [
|
on: [
|
||||||
{
|
{
|
||||||
events: "@bins:mousedown",
|
events: '@bins:mousedown',
|
||||||
update: "[x(), x()]"
|
update: '[x(), x()]'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
events: "[@bins:mousedown, window:mouseup] > window:mousemove!",
|
events: '[@bins:mousedown, window:mouseup] > window:mousemove!',
|
||||||
update: "[brush[0], clamp(x(), 0, width)]"
|
update: '[brush[0], clamp(x(), 0, width)]'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
events: { signal: "delta" },
|
events: { signal: 'delta' },
|
||||||
update:
|
update:
|
||||||
"clampRange([anchor[0] + delta, anchor[1] + delta], 0, width)"
|
'clampRange([anchor[0] + delta, anchor[1] + delta], 0, width)'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "anchor",
|
name: 'anchor',
|
||||||
value: null,
|
value: null,
|
||||||
on: [{ events: "@brush:mousedown", update: "slice(brush)" }]
|
on: [{ events: '@brush:mousedown', update: 'slice(brush)' }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "xdown",
|
name: 'xdown',
|
||||||
value: 0,
|
value: 0,
|
||||||
on: [{ events: "@brush:mousedown", update: "x()" }]
|
on: [{ events: '@brush:mousedown', update: 'x()' }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "delta",
|
name: 'delta',
|
||||||
value: 0,
|
value: 0,
|
||||||
on: [
|
on: [
|
||||||
{
|
{
|
||||||
events: "[@brush:mousedown, window:mouseup] > window:mousemove!",
|
events: '[@brush:mousedown, window:mouseup] > window:mousemove!',
|
||||||
update: "x() - xdown"
|
update: 'x() - xdown'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "segment",
|
name: 'segment',
|
||||||
push: "outer",
|
push: 'outer',
|
||||||
on: [
|
on: [
|
||||||
{
|
{
|
||||||
events: { signal: "brush" },
|
events: { signal: 'brush' },
|
||||||
update: "span(brush) ? invert('xscale', brush) : null"
|
update: "span(brush) ? invert('xscale', brush) : null"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -113,72 +123,72 @@ const canHistogramSpec = {
|
||||||
],
|
],
|
||||||
marks: [
|
marks: [
|
||||||
{
|
{
|
||||||
type: "rect",
|
type: 'rect',
|
||||||
interactive: true,
|
interactive: true,
|
||||||
from: { data: "binned" },
|
from: { data: 'binned' },
|
||||||
name: "bins",
|
name: 'bins',
|
||||||
encode: {
|
encode: {
|
||||||
update: {
|
update: {
|
||||||
x: { scale: "xscale", field: "startTime" },
|
x: { scale: 'xscale', field: 'startTime' },
|
||||||
x2: {
|
x2: {
|
||||||
scale: "xscale",
|
scale: 'xscale',
|
||||||
field: "endTime",
|
field: 'endTime',
|
||||||
offset: 0
|
offset: 0
|
||||||
},
|
},
|
||||||
y: { scale: "yscale", field: "count" },
|
y: { scale: 'yscale', field: 'count' },
|
||||||
y2: { scale: "yscale", value: 0 },
|
y2: { scale: 'yscale', value: 0 },
|
||||||
fill: { value: "steelblue" }
|
fill: { value: 'steelblue' }
|
||||||
},
|
},
|
||||||
hover: {
|
hover: {
|
||||||
fill: { value: "goldenrod" },
|
fill: { value: 'goldenrod' },
|
||||||
cursor: { value: "ew-resize" }
|
cursor: { value: 'ew-resize' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "rect",
|
type: 'rect',
|
||||||
interactive: true,
|
interactive: true,
|
||||||
name: "brush",
|
name: 'brush',
|
||||||
encode: {
|
encode: {
|
||||||
enter: {
|
enter: {
|
||||||
y: { value: 0 },
|
y: { value: 0 },
|
||||||
height: { value: 100 },
|
height: { value: 100 },
|
||||||
fill: { value: "#333" },
|
fill: { value: '#333' },
|
||||||
fillOpacity: { value: 0.2 }
|
fillOpacity: { value: 0.2 }
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
x: { signal: "brush[0]" },
|
x: { signal: 'brush[0]' },
|
||||||
x2: { signal: "brush[1]" }
|
x2: { signal: 'brush[1]' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "rect",
|
type: 'rect',
|
||||||
interactive: false,
|
interactive: false,
|
||||||
encode: {
|
encode: {
|
||||||
enter: {
|
enter: {
|
||||||
y: { value: 0 },
|
y: { value: 0 },
|
||||||
height: { value: 100 },
|
height: { value: 100 },
|
||||||
width: { value: 2 },
|
width: { value: 2 },
|
||||||
fill: { value: "firebrick" }
|
fill: { value: 'firebrick' }
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
x: { signal: "brush[0]" }
|
x: { signal: 'brush[0]' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "rect",
|
type: 'rect',
|
||||||
interactive: false,
|
interactive: false,
|
||||||
encode: {
|
encode: {
|
||||||
enter: {
|
enter: {
|
||||||
y: { value: 0 },
|
y: { value: 0 },
|
||||||
height: { value: 100 },
|
height: { value: 100 },
|
||||||
width: { value: 2 },
|
width: { value: 2 },
|
||||||
fill: { value: "firebrick" }
|
fill: { value: 'firebrick' }
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
x: { signal: "brush[1]" }
|
x: { signal: 'brush[1]' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export default {
|
export default {
|
||||||
$schema: "https://vega.github.io/schema/vega/v5.6.json",
|
$schema: 'https://vega.github.io/schema/vega/v5.6.json',
|
||||||
width: 400,
|
width: 400,
|
||||||
height: 200,
|
height: 200,
|
||||||
padding: {
|
padding: {
|
||||||
|
@ -10,166 +10,166 @@ export default {
|
||||||
},
|
},
|
||||||
signals: [
|
signals: [
|
||||||
{
|
{
|
||||||
name: "tipTime",
|
name: 'tipTime',
|
||||||
on: [
|
on: [
|
||||||
{
|
{
|
||||||
events: "mousemove",
|
events: 'mousemove',
|
||||||
update: "invert('xrelscale', x())"
|
update: "invert('xrelscale', x())"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "clickTime",
|
name: 'clickTime',
|
||||||
on: [
|
on: [
|
||||||
{
|
{
|
||||||
events: "click",
|
events: 'click',
|
||||||
update: "invert('xrelscale', x())"
|
update: "invert('xrelscale', x())"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ name: "videoTime" },
|
{ name: 'videoTime' },
|
||||||
{
|
{
|
||||||
name: "segment",
|
name: 'segment',
|
||||||
value: { data: "table", field: "relTime" }
|
value: { data: 'table', field: 'relTime' }
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
name: "table"
|
name: 'table'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "segment"
|
name: 'segment'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "tooltip",
|
name: 'tooltip',
|
||||||
source: "table",
|
source: 'table',
|
||||||
transform: [
|
transform: [
|
||||||
{
|
{
|
||||||
type: "filter",
|
type: 'filter',
|
||||||
expr: "abs(datum.relTime - tipTime) <= 0.01"
|
expr: 'abs(datum.relTime - tipTime) <= 0.01'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "aggregate",
|
type: 'aggregate',
|
||||||
fields: ["relTime", "y", "unit"],
|
fields: ['relTime', 'y', 'unit'],
|
||||||
ops: ["min", "argmin", "argmin"],
|
ops: ['min', 'argmin', 'argmin'],
|
||||||
as: ["min", "argmin", "argmin"]
|
as: ['min', 'argmin', 'argmin']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ySegmentScale",
|
name: 'ySegmentScale',
|
||||||
source: "table",
|
source: 'table',
|
||||||
transform: [
|
transform: [
|
||||||
{
|
{
|
||||||
type: "filter",
|
type: 'filter',
|
||||||
expr:
|
expr:
|
||||||
"length(segment) != 2 || (datum.relTime >= segment[0] && datum.relTime <= segment[1])"
|
'length(segment) != 2 || (datum.relTime >= segment[0] && datum.relTime <= segment[1])'
|
||||||
},
|
},
|
||||||
{ type: "extent", field: "y", signal: "ySegment" }
|
{ type: 'extent', field: 'y', signal: 'ySegment' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
scales: [
|
scales: [
|
||||||
{
|
{
|
||||||
name: "xscale",
|
name: 'xscale',
|
||||||
type: "linear",
|
type: 'linear',
|
||||||
range: "width",
|
range: 'width',
|
||||||
domain: { data: "table", field: "x" },
|
domain: { data: 'table', field: 'x' },
|
||||||
zero: false
|
zero: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "xrelscale",
|
name: 'xrelscale',
|
||||||
type: "linear",
|
type: 'linear',
|
||||||
range: "width",
|
range: 'width',
|
||||||
domain: { data: "table", field: "relTime" },
|
domain: { data: 'table', field: 'relTime' },
|
||||||
zero: false,
|
zero: false,
|
||||||
clamp: true,
|
clamp: true,
|
||||||
domainRaw: { signal: "segment" }
|
domainRaw: { signal: 'segment' }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "yscale",
|
name: 'yscale',
|
||||||
type: "linear",
|
type: 'linear',
|
||||||
range: "height",
|
range: 'height',
|
||||||
clamp: true,
|
clamp: true,
|
||||||
zero: false,
|
zero: false,
|
||||||
domain: { signal: "ySegment" }
|
domain: { signal: 'ySegment' }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "color",
|
name: 'color',
|
||||||
type: "ordinal",
|
type: 'ordinal',
|
||||||
domain: { data: "table", field: "color" },
|
domain: { data: 'table', field: 'color' },
|
||||||
range: { data: "table", field: "color" }
|
range: { data: 'table', field: 'color' }
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
axes: [
|
axes: [
|
||||||
{ orient: "bottom", scale: "xrelscale", labelOverlap: true },
|
{ orient: 'bottom', scale: 'xrelscale', labelOverlap: true },
|
||||||
{ orient: "left", scale: "yscale" }
|
{ orient: 'left', scale: 'yscale' }
|
||||||
],
|
],
|
||||||
marks: [
|
marks: [
|
||||||
{
|
{
|
||||||
type: "group",
|
type: 'group',
|
||||||
name: "plot",
|
name: 'plot',
|
||||||
interactive: true,
|
interactive: true,
|
||||||
encode: {
|
encode: {
|
||||||
enter: {
|
enter: {
|
||||||
width: { signal: "width" },
|
width: { signal: 'width' },
|
||||||
height: { signal: "height" },
|
height: { signal: 'height' },
|
||||||
fill: { value: "transparent" }
|
fill: { value: 'transparent' }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
signals: [
|
signals: [
|
||||||
{
|
{
|
||||||
name: "brush",
|
name: 'brush',
|
||||||
value: 0,
|
value: 0,
|
||||||
on: [
|
on: [
|
||||||
{
|
{
|
||||||
events: "@boundingRect:mousedown",
|
events: '@boundingRect:mousedown',
|
||||||
update: "[x(), x()]"
|
update: '[x(), x()]'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
events:
|
events:
|
||||||
"[@boundingRect:mousedown, window:mouseup] > window:mousemove!",
|
'[@boundingRect:mousedown, window:mouseup] > window:mousemove!',
|
||||||
update: "[brush[0], clamp(x(), 0, width)]"
|
update: '[brush[0], clamp(x(), 0, width)]'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
events: { signal: "delta" },
|
events: { signal: 'delta' },
|
||||||
update:
|
update:
|
||||||
"clampRange([anchor[0] + delta, anchor[1] + delta], 0, width)"
|
'clampRange([anchor[0] + delta, anchor[1] + delta], 0, width)'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "anchor",
|
name: 'anchor',
|
||||||
value: null,
|
value: null,
|
||||||
on: [{ events: "@brush:mousedown", update: "slice(brush)" }]
|
on: [{ events: '@brush:mousedown', update: 'slice(brush)' }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "xdown",
|
name: 'xdown',
|
||||||
value: 0,
|
value: 0,
|
||||||
on: [{ events: "@brush:mousedown", update: "x()" }]
|
on: [{ events: '@brush:mousedown', update: 'x()' }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "xup",
|
name: 'xup',
|
||||||
value: 0,
|
value: 0,
|
||||||
on: [{ events: "@brush:mouseup", update: "x()" }]
|
on: [{ events: '@brush:mouseup', update: 'x()' }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "delta",
|
name: 'delta',
|
||||||
value: 0,
|
value: 0,
|
||||||
on: [
|
on: [
|
||||||
{
|
{
|
||||||
events: "[@brush:mousedown, window:mouseup] > window:mousemove!",
|
events: '[@brush:mousedown, window:mouseup] > window:mousemove!',
|
||||||
update: "x() - xdown"
|
update: 'x() - xdown'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "segment",
|
name: 'segment',
|
||||||
push: "outer",
|
push: 'outer',
|
||||||
on: [
|
on: [
|
||||||
{
|
{
|
||||||
events: "window:mouseup",
|
events: 'window:mouseup',
|
||||||
update:
|
update:
|
||||||
"span(brush) && span(brush) > 15 ? invert('xrelscale', brush) : segment"
|
"span(brush) && span(brush) > 15 ? invert('xrelscale', brush) : segment"
|
||||||
}
|
}
|
||||||
|
@ -178,50 +178,50 @@ export default {
|
||||||
],
|
],
|
||||||
marks: [
|
marks: [
|
||||||
{
|
{
|
||||||
type: "group",
|
type: 'group',
|
||||||
from: {
|
from: {
|
||||||
facet: {
|
facet: {
|
||||||
name: "series",
|
name: 'series',
|
||||||
data: "table",
|
data: 'table',
|
||||||
groupby: "signalUid"
|
groupby: 'signalUid'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
marks: {
|
marks: {
|
||||||
type: "line",
|
type: 'line',
|
||||||
name: "lineMark",
|
name: 'lineMark',
|
||||||
from: { data: "series" },
|
from: { data: 'series' },
|
||||||
interactive: true,
|
interactive: true,
|
||||||
encode: {
|
encode: {
|
||||||
update: {
|
update: {
|
||||||
interpolate: { value: "step" },
|
interpolate: { value: 'step' },
|
||||||
x: { scale: "xrelscale", field: "relTime" },
|
x: { scale: 'xrelscale', field: 'relTime' },
|
||||||
y: { scale: "yscale", field: "y" }
|
y: { scale: 'yscale', field: 'y' }
|
||||||
},
|
},
|
||||||
hover: {
|
hover: {
|
||||||
fillOpacity: { value: 0.5 }
|
fillOpacity: { value: 0.5 }
|
||||||
},
|
},
|
||||||
enter: {
|
enter: {
|
||||||
clip: { value: true },
|
clip: { value: true },
|
||||||
stroke: { scale: "color", field: "color" },
|
stroke: { scale: 'color', field: 'color' },
|
||||||
strokeWidth: { value: 2 }
|
strokeWidth: { value: 2 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "rect",
|
type: 'rect',
|
||||||
interactive: true,
|
interactive: true,
|
||||||
name: "brush",
|
name: 'brush',
|
||||||
encode: {
|
encode: {
|
||||||
enter: {
|
enter: {
|
||||||
y: { value: 0 },
|
y: { value: 0 },
|
||||||
height: { signal: "height" },
|
height: { signal: 'height' },
|
||||||
fill: { value: "#333" },
|
fill: { value: '#333' },
|
||||||
fillOpacity: { value: 0.2 }
|
fillOpacity: { value: 0.2 }
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
x: { signal: "brush[0]" },
|
x: { signal: 'brush[0]' },
|
||||||
x2: { signal: "brush[1]" }
|
x2: { signal: 'brush[1]' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -256,61 +256,61 @@ export default {
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
type: "rule",
|
type: 'rule',
|
||||||
encode: {
|
encode: {
|
||||||
update: {
|
update: {
|
||||||
y: { value: 0 },
|
y: { value: 0 },
|
||||||
y2: { field: { group: "height" } },
|
y2: { field: { group: 'height' } },
|
||||||
stroke: { value: "#000" },
|
stroke: { value: '#000' },
|
||||||
strokeWidth: { value: 2 },
|
strokeWidth: { value: 2 },
|
||||||
x: {
|
x: {
|
||||||
scale: "xrelscale",
|
scale: 'xrelscale',
|
||||||
signal: "videoTime",
|
signal: 'videoTime',
|
||||||
offset: 0.5
|
offset: 0.5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "symbol",
|
type: 'symbol',
|
||||||
from: { data: "tooltip" },
|
from: { data: 'tooltip' },
|
||||||
encode: {
|
encode: {
|
||||||
update: {
|
update: {
|
||||||
x: { scale: "xrelscale", field: "argmin.relTime" },
|
x: { scale: 'xrelscale', field: 'argmin.relTime' },
|
||||||
y: { scale: "yscale", field: "argmin.y" },
|
y: { scale: 'yscale', field: 'argmin.y' },
|
||||||
size: { value: 50 },
|
size: { value: 50 },
|
||||||
fill: { value: "black" }
|
fill: { value: 'black' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "group",
|
type: 'group',
|
||||||
from: { data: "tooltip" },
|
from: { data: 'tooltip' },
|
||||||
interactive: false,
|
interactive: false,
|
||||||
name: "tooltipGroup",
|
name: 'tooltipGroup',
|
||||||
encode: {
|
encode: {
|
||||||
update: {
|
update: {
|
||||||
x: [
|
x: [
|
||||||
{
|
{
|
||||||
test:
|
test:
|
||||||
"inrange(datum.argmin.relTime + 80, domain('xrelscale'))",
|
"inrange(datum.argmin.relTime + 80, domain('xrelscale'))",
|
||||||
scale: "xrelscale",
|
scale: 'xrelscale',
|
||||||
field: "argmin.relTime"
|
field: 'argmin.relTime'
|
||||||
},
|
},
|
||||||
{ scale: "xrelscale", field: "argmin.relTime", offset: -80 }
|
{ scale: 'xrelscale', field: 'argmin.relTime', offset: -80 }
|
||||||
],
|
],
|
||||||
y: { scale: "yscale", field: "argmin.y" },
|
y: { scale: 'yscale', field: 'argmin.y' },
|
||||||
height: { value: 20 },
|
height: { value: 20 },
|
||||||
width: { value: 80 },
|
width: { value: 80 },
|
||||||
fill: { value: "#fff" },
|
fill: { value: '#fff' },
|
||||||
fillOpacity: { value: 0.85 },
|
fillOpacity: { value: 0.85 },
|
||||||
stroke: { value: "#aaa" },
|
stroke: { value: '#aaa' },
|
||||||
strokeWidth: { value: 0.5 }
|
strokeWidth: { value: 0.5 }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
marks: [
|
marks: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: 'text',
|
||||||
interactive: false,
|
interactive: false,
|
||||||
encode: {
|
encode: {
|
||||||
update: {
|
update: {
|
||||||
|
@ -318,8 +318,8 @@ export default {
|
||||||
signal:
|
signal:
|
||||||
"format(parent.argmin.relTime, ',.2f') + ': ' + format(parent.argmin.y, ',.2f') + ' ' + parent.argmin.unit"
|
"format(parent.argmin.relTime, ',.2f') + ': ' + format(parent.argmin.y, ',.2f') + ' ' + parent.argmin.unit"
|
||||||
},
|
},
|
||||||
fill: { value: "black" },
|
fill: { value: 'black' },
|
||||||
fontWeight: { value: "bold" },
|
fontWeight: { value: 'bold' },
|
||||||
y: { value: 20 }
|
y: { value: 20 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,14 +327,14 @@ export default {
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "rect",
|
type: 'rect',
|
||||||
name: "boundingRect",
|
name: 'boundingRect',
|
||||||
interactive: true,
|
interactive: true,
|
||||||
encode: {
|
encode: {
|
||||||
enter: {
|
enter: {
|
||||||
width: { signal: "width" },
|
width: { signal: 'width' },
|
||||||
height: { signal: "height" },
|
height: { signal: 'height' },
|
||||||
fill: { value: "transparent" }
|
fill: { value: 'transparent' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/* eslint-env worker */
|
/* eslint-env worker */
|
||||||
/* eslint-disable no-restricted-globals */
|
/* eslint-disable no-restricted-globals */
|
||||||
import DBC from "../models/can/dbc";
|
import extend from 'xtend';
|
||||||
import DbcUtils from "../utils/dbc";
|
import DBC from '../models/can/dbc';
|
||||||
import extend from "xtend";
|
import DbcUtils from '../utils/dbc';
|
||||||
|
|
||||||
function processStreamedCanMessages(
|
function processStreamedCanMessages(
|
||||||
newCanMessages,
|
newCanMessages,
|
||||||
|
@ -21,17 +21,19 @@ function processStreamedCanMessages(
|
||||||
canMessages = canMessages.sort((msg1, msg2) => {
|
canMessages = canMessages.sort((msg1, msg2) => {
|
||||||
if (msg1[1] < msg2[1]) {
|
if (msg1[1] < msg2[1]) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (msg1[1] > msg2[1]) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
if (msg1[1] > msg2[1]) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
let busTimeSum = 0;
|
let busTimeSum = 0;
|
||||||
|
|
||||||
for (let i = 0; i < canMessages.length; i++) {
|
for (let i = 0; i < canMessages.length; i++) {
|
||||||
let { address, busTime, data, bus } = canMessages[i];
|
const {
|
||||||
|
address, busTime, data, bus
|
||||||
|
} = canMessages[i];
|
||||||
|
|
||||||
let prevBusTime;
|
let prevBusTime;
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
|
@ -78,7 +80,7 @@ function processStreamedCanMessages(
|
||||||
maxByteStateChangeCount = newMaxByteStateChangeCount;
|
maxByteStateChangeCount = newMaxByteStateChangeCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(messages).forEach(key => {
|
Object.keys(messages).forEach((key) => {
|
||||||
messages[key] = DbcUtils.setMessageByteColors(
|
messages[key] = DbcUtils.setMessageByteColors(
|
||||||
messages[key],
|
messages[key],
|
||||||
maxByteStateChangeCount
|
maxByteStateChangeCount
|
||||||
|
@ -95,7 +97,7 @@ function processStreamedCanMessages(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.onmessage = function(e) {
|
self.onmessage = function (e) {
|
||||||
const {
|
const {
|
||||||
newCanMessages,
|
newCanMessages,
|
||||||
prevMsgEntries,
|
prevMsgEntries,
|
||||||
|
|
|
@ -2,19 +2,19 @@
|
||||||
/* eslint-disable no-restricted-globals */
|
/* eslint-disable no-restricted-globals */
|
||||||
// import Sentry from '../logging/Sentry';
|
// import Sentry from '../logging/Sentry';
|
||||||
|
|
||||||
import NumpyLoader from "../utils/loadnpy";
|
import NumpyLoader from '../utils/loadnpy';
|
||||||
|
|
||||||
const MAX_CONNECTIONS = 8;
|
const MAX_CONNECTIONS = 8;
|
||||||
|
|
||||||
var window = self;
|
const window = self;
|
||||||
|
|
||||||
const Int64LE = require("int64-buffer").Int64LE;
|
const { Int64LE } = require('int64-buffer');
|
||||||
|
|
||||||
function transformAndSend(rawData) {
|
function transformAndSend(rawData) {
|
||||||
var totalSize = 0;
|
let totalSize = 0;
|
||||||
var maxTime = rawData.reduce(function(memo, sourceData) {
|
const maxTime = rawData.reduce((memo, sourceData) => {
|
||||||
totalSize += sourceData.entries.length;
|
totalSize += sourceData.entries.length;
|
||||||
sourceData.entries = sourceData.entries.sort(function(a, b) {
|
sourceData.entries = sourceData.entries.sort((a, b) => {
|
||||||
if (a.relTime > b.relTime) {
|
if (a.relTime > b.relTime) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -26,14 +26,14 @@ function transformAndSend(rawData) {
|
||||||
return Math.max(memo, getLastTimeFromEntries(sourceData.entries));
|
return Math.max(memo, getLastTimeFromEntries(sourceData.entries));
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
var minTime = Math.max(0, maxTime - 30);
|
const minTime = Math.max(0, maxTime - 30);
|
||||||
console.log("Time span from", minTime, maxTime);
|
console.log('Time span from', minTime, maxTime);
|
||||||
var curIndexes = {};
|
const curIndexes = {};
|
||||||
rawData.forEach(function(sourceData) {
|
rawData.forEach((sourceData) => {
|
||||||
if (!sourceData.entries.length) {
|
if (!sourceData.entries.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var sourceId = sourceData.id;
|
const sourceId = sourceData.id;
|
||||||
if (minTime === 0 || sourceData.entries[0].relTime > minTime) {
|
if (minTime === 0 || sourceData.entries[0].relTime > minTime) {
|
||||||
curIndexes[sourceId] = 0;
|
curIndexes[sourceId] = 0;
|
||||||
return;
|
return;
|
||||||
|
@ -41,12 +41,12 @@ function transformAndSend(rawData) {
|
||||||
curIndexes[sourceId] = findFirstEntryIndex(sourceData.entries, minTime);
|
curIndexes[sourceId] = findFirstEntryIndex(sourceData.entries, minTime);
|
||||||
});
|
});
|
||||||
|
|
||||||
var entryBuffer = [];
|
let entryBuffer = [];
|
||||||
var totalEntries = 0;
|
let totalEntries = 0;
|
||||||
|
|
||||||
while (!isAtEnd()) {
|
while (!isAtEnd()) {
|
||||||
let nextSource = rawData.reduce(function(memo, sourceData) {
|
const nextSource = rawData.reduce((memo, sourceData) => {
|
||||||
let curEntry = sourceData.entries[curIndexes[sourceData.id]];
|
const curEntry = sourceData.entries[curIndexes[sourceData.id]];
|
||||||
if (!curEntry) {
|
if (!curEntry) {
|
||||||
return memo;
|
return memo;
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ function transformAndSend(rawData) {
|
||||||
if (entryBuffer.length > 5000) {
|
if (entryBuffer.length > 5000) {
|
||||||
self.postMessage({
|
self.postMessage({
|
||||||
progress: 100 * (totalEntries / totalSize),
|
progress: 100 * (totalEntries / totalSize),
|
||||||
logData: entryBuffer.join("\n"),
|
logData: entryBuffer.join('\n'),
|
||||||
shouldClose: false
|
shouldClose: false
|
||||||
});
|
});
|
||||||
entryBuffer = [];
|
entryBuffer = [];
|
||||||
|
@ -88,13 +88,13 @@ function transformAndSend(rawData) {
|
||||||
if (entryBuffer.length > 0) {
|
if (entryBuffer.length > 0) {
|
||||||
self.postMessage({
|
self.postMessage({
|
||||||
progress: 99,
|
progress: 99,
|
||||||
logData: entryBuffer.join("\n"),
|
logData: entryBuffer.join('\n'),
|
||||||
shouldClose: false
|
shouldClose: false
|
||||||
});
|
});
|
||||||
entryBuffer = [];
|
entryBuffer = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Wrote", totalEntries, "lines of CSV");
|
console.log('Wrote', totalEntries, 'lines of CSV');
|
||||||
self.postMessage({
|
self.postMessage({
|
||||||
progress: 100,
|
progress: 100,
|
||||||
shouldClose: true
|
shouldClose: true
|
||||||
|
@ -102,8 +102,7 @@ function transformAndSend(rawData) {
|
||||||
|
|
||||||
function isAtEnd() {
|
function isAtEnd() {
|
||||||
return rawData.reduce(
|
return rawData.reduce(
|
||||||
(memo, sourceData) =>
|
(memo, sourceData) => memo && curIndexes[sourceData.id] >= sourceData.entries.length
|
||||||
memo && curIndexes[sourceData.id] >= sourceData.entries.length
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,7 +113,7 @@ function makeEntry(nextSource) {
|
||||||
nextSource.address,
|
nextSource.address,
|
||||||
nextSource.bus,
|
nextSource.bus,
|
||||||
nextSource.entry.hexData
|
nextSource.entry.hexData
|
||||||
].join(",");
|
].join(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
function findFirstEntryIndex(entries, minTime, start, length) {
|
function findFirstEntryIndex(entries, minTime, start, length) {
|
||||||
|
@ -160,11 +159,11 @@ function getLastTimeFromEntries(entries) {
|
||||||
return entries[entries.length - 1].relTime;
|
return entries[entries.length - 1].relTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.onmessage = function(e) {
|
self.onmessage = function (e) {
|
||||||
console.log("onmessage worker");
|
console.log('onmessage worker');
|
||||||
self.postMessage({
|
self.postMessage({
|
||||||
progress: 0,
|
progress: 0,
|
||||||
logData: "time,addr,bus,data",
|
logData: 'time,addr,bus,data',
|
||||||
shouldClose: false
|
shouldClose: false
|
||||||
});
|
});
|
||||||
const {
|
const {
|
||||||
|
@ -180,7 +179,7 @@ self.onmessage = function(e) {
|
||||||
// saveDBC(dbc, base, num, canStartTime);
|
// saveDBC(dbc, base, num, canStartTime);
|
||||||
if (data) {
|
if (data) {
|
||||||
// has raw data from live mode, process this instead
|
// has raw data from live mode, process this instead
|
||||||
console.log("Using raw data from memory", canStartTime);
|
console.log('Using raw data from memory', canStartTime);
|
||||||
transformAndSend(data, canStartTime);
|
transformAndSend(data, canStartTime);
|
||||||
} else {
|
} else {
|
||||||
self.postMessage({
|
self.postMessage({
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue