Read thumbnails from rlog files when video isn't working (#28)
* Add rlog thumbnails to cabana * Fixing more linting errorsmain
parent
1be5544df3
commit
5c83305260
34
package.json
34
package.json
|
@ -5,7 +5,7 @@
|
||||||
"homepage": "https://community.comma.ai/cabana",
|
"homepage": "https://community.comma.ai/cabana",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@commaai/comma-api": "1.1.6",
|
"@commaai/comma-api": "1.1.6",
|
||||||
"@commaai/log_reader": "^0.3.1",
|
"@commaai/log_reader": "^0.5.3",
|
||||||
"@commaai/my-comma-auth": "^1.1.0",
|
"@commaai/my-comma-auth": "^1.1.0",
|
||||||
"@commaai/pandajs": "^0.3.4",
|
"@commaai/pandajs": "^0.3.4",
|
||||||
"@craco/craco": "^5.5.0",
|
"@craco/craco": "^5.5.0",
|
||||||
|
@ -60,6 +60,7 @@
|
||||||
"socket.io-client": "^2.0.3",
|
"socket.io-client": "^2.0.3",
|
||||||
"stream-selector": "^0.1.1",
|
"stream-selector": "^0.1.1",
|
||||||
"streamsaver": "^1.0.1",
|
"streamsaver": "^1.0.1",
|
||||||
|
"thyming": "^0.1.1",
|
||||||
"vega": "^5.3.4",
|
"vega": "^5.3.4",
|
||||||
"vega-lite": "^3.0.0",
|
"vega-lite": "^3.0.0",
|
||||||
"vega-tooltip": "^0.4.0"
|
"vega-tooltip": "^0.4.0"
|
||||||
|
@ -96,11 +97,26 @@
|
||||||
"deploy": "npm run build && gh-pages -d build"
|
"deploy": "npm run build && gh-pages -d build"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{js,jsx}": ["eslint --fix", "git add"],
|
"*.{js,jsx}": [
|
||||||
"*.json": ["prettier --parser json --write", "git add"],
|
"eslint --fix",
|
||||||
"*.{graphql,gql}": ["prettier --parser graphql --write", "git add"],
|
"git add"
|
||||||
"*.{md,markdown}": ["prettier --parser markdown --write", "git add"],
|
],
|
||||||
"*.scss": ["prettier --parser postcss --write", "git add"]
|
"*.json": [
|
||||||
|
"prettier --parser json --write",
|
||||||
|
"git add"
|
||||||
|
],
|
||||||
|
"*.{graphql,gql}": [
|
||||||
|
"prettier --parser graphql --write",
|
||||||
|
"git add"
|
||||||
|
],
|
||||||
|
"*.{md,markdown}": [
|
||||||
|
"prettier --parser markdown --write",
|
||||||
|
"git add"
|
||||||
|
],
|
||||||
|
"*.scss": [
|
||||||
|
"prettier --parser postcss --write",
|
||||||
|
"git add"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"moduleNameMapper": {
|
"moduleNameMapper": {
|
||||||
|
@ -111,7 +127,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [">0.2%", "not dead", "not op_mini all"],
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
],
|
||||||
"development": [
|
"development": [
|
||||||
"last 1 chrome version",
|
"last 1 chrome version",
|
||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
|
|
|
@ -40,21 +40,11 @@ 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 = {
|
|
||||||
dongleId: PropTypes.string,
|
|
||||||
name: PropTypes.string,
|
|
||||||
dbc: PropTypes.instanceOf(DBC),
|
|
||||||
dbcFilename: PropTypes.string,
|
|
||||||
githubAuthToken: PropTypes.string,
|
|
||||||
autoplay: PropTypes.bool,
|
|
||||||
max: PropTypes.number,
|
|
||||||
url: PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
messages: {},
|
messages: {},
|
||||||
|
thumbnails: [],
|
||||||
selectedMessages: [],
|
selectedMessages: [],
|
||||||
route: null,
|
route: null,
|
||||||
canFrameOffset: 0,
|
canFrameOffset: 0,
|
||||||
|
@ -317,6 +307,45 @@ export default class CanExplorer extends Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mergeThumbnails(newThumbnails) {
|
||||||
|
const { thumbnails } = this.state;
|
||||||
|
if (!newThumbnails || !newThumbnails.length) {
|
||||||
|
return thumbnails;
|
||||||
|
}
|
||||||
|
if (!thumbnails.length) {
|
||||||
|
return newThumbnails;
|
||||||
|
}
|
||||||
|
|
||||||
|
let oldIndex = 0;
|
||||||
|
let newIndex = 0;
|
||||||
|
|
||||||
|
// is old immediately after new?
|
||||||
|
if (newThumbnails[0].monoTime > thumbnails[thumbnails.length - 1]) {
|
||||||
|
return thumbnails.concat(newThumbnails);
|
||||||
|
}
|
||||||
|
// is new immediately after old?
|
||||||
|
if (newThumbnails[newThumbnails.length - 1] < thumbnails[0]) {
|
||||||
|
return newThumbnails.concat(thumbnails);
|
||||||
|
}
|
||||||
|
let result = [];
|
||||||
|
while (oldIndex < thumbnails.length && newIndex < newThumbnails.length) {
|
||||||
|
if (thumbnails[oldIndex].monoTime < newThumbnails[newIndex].monoTime) {
|
||||||
|
result.push(thumbnails[oldIndex]);
|
||||||
|
oldIndex += 1;
|
||||||
|
} else {
|
||||||
|
result.push(newThumbnails[newIndex]);
|
||||||
|
newIndex += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oldIndex < thumbnails.length) {
|
||||||
|
result = result.concat(thumbnails.slice(oldIndex));
|
||||||
|
} else if (newIndex < newThumbnails.length) {
|
||||||
|
result = result.concat(newThumbnails.slice(newIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
addAndRehydrateMessages(newMessages, options) {
|
addAndRehydrateMessages(newMessages, options) {
|
||||||
// Adds new message entries to messages state
|
// Adds new message entries to messages state
|
||||||
// and "rehydrates" ES6 classes (message frame)
|
// and "rehydrates" ES6 classes (message frame)
|
||||||
|
@ -442,14 +471,13 @@ export default class CanExplorer extends Component {
|
||||||
dbcFilename,
|
dbcFilename,
|
||||||
route,
|
route,
|
||||||
firstCanTime,
|
firstCanTime,
|
||||||
canFrameOffset,
|
canFrameOffset
|
||||||
maxByteStateChangeCount
|
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
let { maxByteStateChangeCount } = this.state;
|
||||||
|
|
||||||
if (!prevMsgEntries) {
|
if (!prevMsgEntries) {
|
||||||
// we have previous messages loaded
|
// we have previous messages loaded
|
||||||
const { messages } = this.state;
|
const { messages } = this.state;
|
||||||
const canStartTime = firstCanTime - canFrameOffset;
|
|
||||||
prevMsgEntries = {};
|
prevMsgEntries = {};
|
||||||
Object.keys(messages).forEach((key) => {
|
Object.keys(messages).forEach((key) => {
|
||||||
const { entries } = messages[key];
|
const { entries } = messages[key];
|
||||||
|
@ -485,7 +513,8 @@ export default class CanExplorer extends Component {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { newMessages, maxByteStateChangeCount, isFinished } = e.data;
|
maxByteStateChangeCount = e.data.maxByteStateChangeCount;
|
||||||
|
const { newMessages, newThumbnails, isFinished } = e.data;
|
||||||
if (maxByteStateChangeCount > this.state.maxByteStateChangeCount) {
|
if (maxByteStateChangeCount > this.state.maxByteStateChangeCount) {
|
||||||
this.setState({ maxByteStateChangeCount });
|
this.setState({ maxByteStateChangeCount });
|
||||||
} else {
|
} else {
|
||||||
|
@ -497,12 +526,14 @@ export default class CanExplorer extends Component {
|
||||||
maxByteStateChangeCount
|
maxByteStateChangeCount
|
||||||
);
|
);
|
||||||
const prevMsgEntries = {};
|
const prevMsgEntries = {};
|
||||||
for (const key in newMessages) {
|
Object.keys(newMessages).forEach((key) => {
|
||||||
prevMsgEntries[key] = newMessages[key].entries[newMessages[key].entries.length - 1];
|
prevMsgEntries[key] = newMessages[key].entries[newMessages[key].entries.length - 1];
|
||||||
}
|
});
|
||||||
|
|
||||||
|
const thumbnails = this.mergeThumbnails(newThumbnails);
|
||||||
|
|
||||||
if (!isFinished) {
|
if (!isFinished) {
|
||||||
this.setState({ messages });
|
this.setState({ messages, thumbnails });
|
||||||
} else {
|
} else {
|
||||||
const loadingParts = this.state.loadingParts.filter((p) => p !== part);
|
const loadingParts = this.state.loadingParts.filter((p) => p !== part);
|
||||||
const loadedParts = [part, ...this.state.loadedParts];
|
const loadedParts = [part, ...this.state.loadedParts];
|
||||||
|
@ -510,6 +541,7 @@ export default class CanExplorer extends Component {
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
messages,
|
messages,
|
||||||
|
thumbnails,
|
||||||
partsLoaded: this.state.partsLoaded + 1,
|
partsLoaded: this.state.partsLoaded + 1,
|
||||||
loadingParts,
|
loadingParts,
|
||||||
loadedParts
|
loadedParts
|
||||||
|
@ -943,6 +975,26 @@ export default class CanExplorer extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const {
|
||||||
|
route,
|
||||||
|
messages,
|
||||||
|
selectedMessages,
|
||||||
|
currentParts,
|
||||||
|
dbcFilename,
|
||||||
|
dbcLastSaved,
|
||||||
|
seekTime,
|
||||||
|
seekIndex,
|
||||||
|
shareUrl,
|
||||||
|
maxByteStateChangeCount,
|
||||||
|
live,
|
||||||
|
thumbnails,
|
||||||
|
selectedMessage,
|
||||||
|
canFrameOffset,
|
||||||
|
firstCanTime,
|
||||||
|
currentPart,
|
||||||
|
partsLoaded
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id="cabana"
|
id="cabana"
|
||||||
|
@ -973,52 +1025,53 @@ export default class CanExplorer extends Component {
|
||||||
</div>
|
</div>
|
||||||
<div className="cabana-window">
|
<div className="cabana-window">
|
||||||
<Meta
|
<Meta
|
||||||
url={this.state.route ? this.state.route.url : null}
|
url={this.state.route ? route.url : null}
|
||||||
messages={this.state.messages}
|
messages={messages}
|
||||||
selectedMessages={this.state.selectedMessages}
|
selectedMessages={selectedMessages}
|
||||||
updateSelectedMessages={this.updateSelectedMessages}
|
updateSelectedMessages={this.updateSelectedMessages}
|
||||||
showEditMessageModal={this.showEditMessageModal}
|
showEditMessageModal={this.showEditMessageModal}
|
||||||
currentParts={this.state.currentParts}
|
currentParts={currentParts}
|
||||||
onMessageSelected={this.onMessageSelected}
|
onMessageSelected={this.onMessageSelected}
|
||||||
onMessageUnselected={this.onMessageUnselected}
|
onMessageUnselected={this.onMessageUnselected}
|
||||||
showLoadDbc={this.showLoadDbc}
|
showLoadDbc={this.showLoadDbc}
|
||||||
showSaveDbc={this.showSaveDbc}
|
showSaveDbc={this.showSaveDbc}
|
||||||
dbcFilename={this.state.dbcFilename}
|
dbcFilename={dbcFilename}
|
||||||
dbcLastSaved={this.state.dbcLastSaved}
|
dbcLastSaved={dbcLastSaved}
|
||||||
dongleId={this.props.dongleId}
|
dongleId={this.props.dongleId}
|
||||||
name={this.props.name}
|
name={this.props.name}
|
||||||
route={this.state.route}
|
route={route}
|
||||||
seekTime={this.state.seekTime}
|
seekTime={seekTime}
|
||||||
seekIndex={this.state.seekIndex}
|
seekIndex={seekIndex}
|
||||||
shareUrl={this.state.shareUrl}
|
shareUrl={shareUrl}
|
||||||
maxByteStateChangeCount={this.state.maxByteStateChangeCount}
|
maxByteStateChangeCount={maxByteStateChangeCount}
|
||||||
isDemo={this.props.isDemo}
|
isDemo={this.props.isDemo}
|
||||||
live={this.state.live}
|
live={live}
|
||||||
saveLog={debounce(this.downloadLogAsCSV, 500)}
|
saveLog={debounce(this.downloadLogAsCSV, 500)}
|
||||||
/>
|
/>
|
||||||
{this.state.route || this.state.live ? (
|
{route || live ? (
|
||||||
<Explorer
|
<Explorer
|
||||||
url={this.state.route ? this.state.route.url : null}
|
url={route ? route.url : null}
|
||||||
live={this.state.live}
|
live={live}
|
||||||
messages={this.state.messages}
|
messages={messages}
|
||||||
selectedMessage={this.state.selectedMessage}
|
thumbnails={thumbnails}
|
||||||
|
selectedMessage={selectedMessage}
|
||||||
onConfirmedSignalChange={this.onConfirmedSignalChange}
|
onConfirmedSignalChange={this.onConfirmedSignalChange}
|
||||||
onSeek={this.onSeek}
|
onSeek={this.onSeek}
|
||||||
onUserSeek={this.onUserSeek}
|
onUserSeek={this.onUserSeek}
|
||||||
canFrameOffset={this.state.canFrameOffset}
|
canFrameOffset={canFrameOffset}
|
||||||
firstCanTime={this.state.firstCanTime}
|
firstCanTime={firstCanTime}
|
||||||
seekTime={this.state.seekTime}
|
seekTime={seekTime}
|
||||||
seekIndex={this.state.seekIndex}
|
seekIndex={seekIndex}
|
||||||
currentParts={this.state.currentParts}
|
currentParts={currentParts}
|
||||||
selectedPart={this.state.currentPart}
|
selectedPart={currentPart}
|
||||||
partsLoaded={this.state.partsLoaded}
|
partsLoaded={partsLoaded}
|
||||||
autoplay={this.props.autoplay}
|
autoplay={this.props.autoplay}
|
||||||
showEditMessageModal={this.showEditMessageModal}
|
showEditMessageModal={this.showEditMessageModal}
|
||||||
onPartChange={this.onPartChange}
|
onPartChange={this.onPartChange}
|
||||||
routeStartTime={
|
routeStartTime={
|
||||||
this.state.route ? this.state.route.start_time : Moment()
|
route ? route.start_time : Moment()
|
||||||
}
|
}
|
||||||
partsCount={this.state.route ? this.state.route.proclog : 0}
|
partsCount={route ? route.proclog : 0}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1063,3 +1116,14 @@ export default class CanExplorer extends Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CanExplorer.propTypes = {
|
||||||
|
dongleId: PropTypes.string,
|
||||||
|
name: PropTypes.string,
|
||||||
|
dbc: PropTypes.instanceOf(DBC),
|
||||||
|
dbcFilename: PropTypes.string,
|
||||||
|
githubAuthToken: PropTypes.string,
|
||||||
|
autoplay: PropTypes.bool,
|
||||||
|
max: PropTypes.number,
|
||||||
|
url: PropTypes.string
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/* eslint-env jest */
|
||||||
|
import {
|
||||||
|
signedShortToByteArray,
|
||||||
|
shortToByteArray,
|
||||||
|
longToByteArray,
|
||||||
|
signedLongToByteArray,
|
||||||
|
getThermalFlags,
|
||||||
|
// getHealthFlags,
|
||||||
|
// getFlags,
|
||||||
|
// getUbloxGnss,
|
||||||
|
// getEgoData,
|
||||||
|
// getCarStateControls,
|
||||||
|
// getWheelSpeeds,
|
||||||
|
// getThermalFreeSpace,
|
||||||
|
// getThermalData,
|
||||||
|
// getThermalCPU,
|
||||||
|
// getHealth
|
||||||
|
} from '../../workers/rlog-utils';
|
||||||
|
|
||||||
|
describe('byte array methods', () => {
|
||||||
|
test('signedShortToByteArray', () => {
|
||||||
|
expect(signedShortToByteArray(123)).toMatchObject([0, 123]);
|
||||||
|
expect(signedShortToByteArray(-123)).toMatchObject([255, 133]);
|
||||||
|
});
|
||||||
|
test('shortToByteArray', () => {
|
||||||
|
expect(shortToByteArray(123)).toMatchObject([0, 123]);
|
||||||
|
expect(shortToByteArray(-123)).toMatchObject([255, 133]);
|
||||||
|
});
|
||||||
|
test('longToByteArray', () => {
|
||||||
|
expect(longToByteArray(123)).toMatchObject([0, 0, 0, 123]);
|
||||||
|
expect(longToByteArray(-123)).toMatchObject([255, 255, 255, 133]);
|
||||||
|
});
|
||||||
|
test('signedLongToByteArray', () => {
|
||||||
|
expect(signedLongToByteArray(123)).toMatchObject([0, 0, 0, 123]);
|
||||||
|
expect(signedLongToByteArray(-123)).toMatchObject([255, 255, 255, 133]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('flags', () => {
|
||||||
|
test('getThermalFlags', () => {
|
||||||
|
expect(getThermalFlags({
|
||||||
|
UsbOnline: false,
|
||||||
|
Started: false
|
||||||
|
})).toBe(0x00);
|
||||||
|
|
||||||
|
expect(getThermalFlags({
|
||||||
|
UsbOnline: true,
|
||||||
|
Started: false
|
||||||
|
})).toBe(0x01);
|
||||||
|
|
||||||
|
expect(getThermalFlags({
|
||||||
|
UsbOnline: false,
|
||||||
|
Started: true
|
||||||
|
})).toBe(0x02);
|
||||||
|
|
||||||
|
expect(getThermalFlags({
|
||||||
|
UsbOnline: true,
|
||||||
|
Started: true
|
||||||
|
})).toBe(0x03);
|
||||||
|
});
|
||||||
|
});
|
|
@ -460,6 +460,8 @@ export default class Explorer extends Component {
|
||||||
? 'is-expanded'
|
? 'is-expanded'
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
const { thumbnails, messages } = this.props;
|
||||||
|
|
||||||
let graphSegment = this.state.segment;
|
let graphSegment = this.state.segment;
|
||||||
if (!graphSegment.length && this.props.currentParts) {
|
if (!graphSegment.length && this.props.currentParts) {
|
||||||
graphSegment = [
|
graphSegment = [
|
||||||
|
@ -471,7 +473,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]
|
{messages[this.props.selectedMessage]
|
||||||
? this.renderExplorerSignals()
|
? this.renderExplorerSignals()
|
||||||
: this.renderSelectMessagePrompt()}
|
: this.renderSelectMessagePrompt()}
|
||||||
</div>
|
</div>
|
||||||
|
@ -485,7 +487,7 @@ export default class Explorer extends Component {
|
||||||
<div className="cabana-explorer-visuals-header g-row" />
|
<div className="cabana-explorer-visuals-header g-row" />
|
||||||
<br />
|
<br />
|
||||||
<RouteVideoSync
|
<RouteVideoSync
|
||||||
message={this.props.messages[this.props.selectedMessage]}
|
message={messages[this.props.selectedMessage]}
|
||||||
segment={this.state.segment}
|
segment={this.state.segment}
|
||||||
seekIndex={this.props.seekIndex}
|
seekIndex={this.props.seekIndex}
|
||||||
userSeekIndex={this.state.userSeekIndex}
|
userSeekIndex={this.state.userSeekIndex}
|
||||||
|
@ -500,6 +502,7 @@ export default class Explorer extends Component {
|
||||||
onPause={this.onPause}
|
onPause={this.onPause}
|
||||||
userSeekTime={this.state.userSeekTime}
|
userSeekTime={this.state.userSeekTime}
|
||||||
playSpeed={this.state.playSpeed}
|
playSpeed={this.state.playSpeed}
|
||||||
|
thumbnails={thumbnails}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -515,7 +518,7 @@ export default class Explorer extends Component {
|
||||||
) : null}
|
) : null}
|
||||||
<CanGraphList
|
<CanGraphList
|
||||||
plottedSignals={this.state.plottedSignals}
|
plottedSignals={this.state.plottedSignals}
|
||||||
messages={this.props.messages}
|
messages={messages}
|
||||||
onGraphTimeClick={this.onGraphTimeClick}
|
onGraphTimeClick={this.onGraphTimeClick}
|
||||||
seekTime={this.props.seekTime}
|
seekTime={this.props.seekTime}
|
||||||
onSegmentChanged={this.onSegmentChanged}
|
onSegmentChanged={this.onSegmentChanged}
|
||||||
|
|
|
@ -44,21 +44,6 @@ const Styles = StyleSheet.create({
|
||||||
});
|
});
|
||||||
|
|
||||||
export default class RouteVideoSync extends Component {
|
export default class RouteVideoSync extends Component {
|
||||||
static propTypes = {
|
|
||||||
userSeekIndex: PropTypes.number.isRequired,
|
|
||||||
segment: PropTypes.array.isRequired,
|
|
||||||
message: PropTypes.object,
|
|
||||||
canFrameOffset: PropTypes.number.isRequired,
|
|
||||||
url: PropTypes.string.isRequired,
|
|
||||||
playing: PropTypes.bool.isRequired,
|
|
||||||
onPlaySeek: PropTypes.func.isRequired,
|
|
||||||
onUserSeek: PropTypes.func.isRequired,
|
|
||||||
onPlay: PropTypes.func.isRequired,
|
|
||||||
onPause: PropTypes.func.isRequired,
|
|
||||||
userSeekTime: PropTypes.number.isRequired,
|
|
||||||
playSpeed: PropTypes.number.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -73,49 +58,71 @@ export default class RouteVideoSync extends Component {
|
||||||
this.segmentProgress = this.segmentProgress.bind(this);
|
this.segmentProgress = this.segmentProgress.bind(this);
|
||||||
this.onVideoElementAvailable = this.onVideoElementAvailable.bind(this);
|
this.onVideoElementAvailable = this.onVideoElementAvailable.bind(this);
|
||||||
this.onUserSeek = this.onUserSeek.bind(this);
|
this.onUserSeek = this.onUserSeek.bind(this);
|
||||||
|
this.onPlaySeek = this.onPlaySeek.bind(this);
|
||||||
this.onHlsRestart = this.onHlsRestart.bind(this);
|
this.onHlsRestart = this.onHlsRestart.bind(this);
|
||||||
this.ratioTime = this.ratioTime.bind(this);
|
this.ratioTime = this.ratioTime.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentDidUpdate(nextProps) {
|
||||||
|
const {
|
||||||
|
userSeekIndex,
|
||||||
|
message,
|
||||||
|
canFrameOffset,
|
||||||
|
userSeekTime
|
||||||
|
} = this.props;
|
||||||
|
const { videoElement } = this.state;
|
||||||
if (
|
if (
|
||||||
this.props.userSeekIndex !== nextProps.userSeekIndex
|
userSeekIndex !== nextProps.userSeekIndex
|
||||||
|| this.props.canFrameOffset !== nextProps.canFrameOffset
|
|| canFrameOffset !== nextProps.canFrameOffset
|
||||||
|| (this.props.message
|
|| (message
|
||||||
&& nextProps.message
|
&& nextProps.message
|
||||||
&& this.props.message.entries.length !== nextProps.message.entries.length)
|
&& 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
|
&& userSeekTime !== nextProps.userSeekTime
|
||||||
) {
|
) {
|
||||||
if (this.state.videoElement) {
|
if (videoElement) {
|
||||||
this.state.videoElement.currentTime = nextProps.userSeekTime;
|
videoElement.currentTime = nextProps.userSeekTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nearestFrameUrl() {
|
onVideoElementAvailable(videoElement) {
|
||||||
const { url } = this.props;
|
this.setState({ videoElement });
|
||||||
const sec = Math.round(this.props.userSeekTime);
|
|
||||||
if (isNaN(sec)) {
|
|
||||||
debugger;
|
|
||||||
}
|
|
||||||
return RouteApi(url).getJpegUrl(sec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadingOverlay() {
|
onUserSeek(ratio) {
|
||||||
return (
|
/* ratio in [0,1] */
|
||||||
<div className={css(Styles.loadingOverlay)}>
|
|
||||||
<img
|
const { videoElement } = this.state;
|
||||||
className={css(Styles.loadingSpinner)}
|
const { onUserSeek } = this.props;
|
||||||
src={`${process.env.PUBLIC_URL}/img/loading.svg`}
|
const seekTime = this.ratioTime(ratio);
|
||||||
alt="Loading video"
|
const funcSeekToRatio = () => onUserSeek(seekTime);
|
||||||
/>
|
|
||||||
</div>
|
if (Number.isNaN(videoElement.duration)) {
|
||||||
);
|
this.setState({ shouldRestartHls: true }, funcSeekToRatio);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
videoElement.currentTime = seekTime;
|
||||||
|
|
||||||
|
if (ratio === 0) {
|
||||||
|
this.setState({ shouldRestartHls: true }, funcSeekToRatio);
|
||||||
|
} else {
|
||||||
|
funcSeekToRatio();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onHlsRestart() {
|
||||||
|
this.setState({ shouldRestartHls: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
onPlaySeek(offset) {
|
||||||
|
const { onPlaySeek } = this.props;
|
||||||
|
this.seekTime = offset;
|
||||||
|
onPlaySeek(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoadStart() {
|
onLoadStart() {
|
||||||
|
@ -132,6 +139,18 @@ export default class RouteVideoSync extends Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadingOverlay() {
|
||||||
|
return (
|
||||||
|
<div className={css(Styles.loadingOverlay)}>
|
||||||
|
<img
|
||||||
|
className={css(Styles.loadingSpinner)}
|
||||||
|
src={`${process.env.PUBLIC_URL}/img/loading.svg`}
|
||||||
|
alt="Loading video"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
videoLength() {
|
videoLength() {
|
||||||
if (this.props.segment.length) {
|
if (this.props.segment.length) {
|
||||||
return this.props.segment[1] - this.props.segment[0];
|
return this.props.segment[1] - this.props.segment[0];
|
||||||
|
@ -168,73 +187,73 @@ export default class RouteVideoSync extends Component {
|
||||||
return ratio * this.videoLength() + this.startTime();
|
return ratio * this.videoLength() + this.startTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
onVideoElementAvailable(videoElement) {
|
nearestFrameUrl() {
|
||||||
this.setState({ videoElement });
|
const { thumbnails } = this.props;
|
||||||
}
|
if (!this.seekTime) {
|
||||||
|
return '';
|
||||||
onUserSeek(ratio) {
|
|
||||||
/* ratio in [0,1] */
|
|
||||||
|
|
||||||
const { videoElement } = this.state;
|
|
||||||
if (isNaN(videoElement.duration)) {
|
|
||||||
this.setState({ shouldRestartHls: true }, funcSeekToRatio);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
const seekTime = this.ratioTime(ratio);
|
for (let i = 0, l = thumbnails.length; i < l; ++i) {
|
||||||
videoElement.currentTime = seekTime;
|
if (Math.abs(thumbnails[i].monoTime - this.seekTime) < 5) {
|
||||||
|
const data = btoa(String.fromCharCode(...thumbnails[i].data));
|
||||||
const funcSeekToRatio = () => this.props.onUserSeek(seekTime);
|
return `data:image/jpeg;base64,${data}`;
|
||||||
if (ratio === 0) {
|
}
|
||||||
this.setState({ shouldRestartHls: true }, funcSeekToRatio);
|
|
||||||
} else {
|
|
||||||
funcSeekToRatio();
|
|
||||||
}
|
}
|
||||||
}
|
return '';
|
||||||
|
|
||||||
onHlsRestart() {
|
|
||||||
this.setState({ shouldRestartHls: false });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const {
|
||||||
|
isLoading,
|
||||||
|
shouldRestartHls,
|
||||||
|
shouldShowJpeg
|
||||||
|
} = this.state;
|
||||||
|
const {
|
||||||
|
userSeekTime,
|
||||||
|
url,
|
||||||
|
playSpeed,
|
||||||
|
playing,
|
||||||
|
onVideoClick,
|
||||||
|
segmentIndices
|
||||||
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
<div className="cabana-explorer-visuals-camera">
|
<div className="cabana-explorer-visuals-camera">
|
||||||
{this.state.isLoading ? this.loadingOverlay() : null}
|
{isLoading ? this.loadingOverlay() : null}
|
||||||
{this.state.shouldShowJpeg ? (
|
{shouldShowJpeg ? (
|
||||||
<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(userSeekTime)}`}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<HLS
|
<HLS
|
||||||
className={css(Styles.hls)}
|
className={css(Styles.hls)}
|
||||||
source={VideoApi(
|
source={VideoApi(
|
||||||
this.props.url,
|
url,
|
||||||
process.env.REACT_APP_VIDEO_CDN
|
process.env.REACT_APP_VIDEO_CDN
|
||||||
).getRearCameraStreamIndexUrl()}
|
).getRearCameraStreamIndexUrl()}
|
||||||
startTime={this.startTime()}
|
startTime={this.startTime()}
|
||||||
videoLength={this.videoLength()}
|
videoLength={this.videoLength()}
|
||||||
playbackSpeed={this.props.playSpeed}
|
playbackSpeed={playSpeed}
|
||||||
onVideoElementAvailable={this.onVideoElementAvailable}
|
onVideoElementAvailable={this.onVideoElementAvailable}
|
||||||
playing={this.props.playing}
|
playing={playing}
|
||||||
onClick={this.props.onVideoClick}
|
onClick={onVideoClick}
|
||||||
onLoadStart={this.onLoadStart}
|
onLoadStart={this.onLoadStart}
|
||||||
onLoadEnd={this.onLoadEnd}
|
onLoadEnd={this.onLoadEnd}
|
||||||
onUserSeek={this.onUserSeek}
|
onUserSeek={this.onUserSeek}
|
||||||
onPlaySeek={this.props.onPlaySeek}
|
onPlaySeek={this.onPlaySeek}
|
||||||
segmentProgress={this.segmentProgress}
|
segmentProgress={this.segmentProgress}
|
||||||
shouldRestart={this.state.shouldRestartHls}
|
shouldRestart={shouldRestartHls}
|
||||||
onRestart={this.onHlsRestart}
|
onRestart={this.onHlsRestart}
|
||||||
/>
|
/>
|
||||||
<RouteSeeker
|
<RouteSeeker
|
||||||
className={css(Styles.seekBar)}
|
className={css(Styles.seekBar)}
|
||||||
nearestFrameTime={this.props.userSeekTime}
|
nearestFrameTime={userSeekTime}
|
||||||
segmentProgress={this.segmentProgress}
|
segmentProgress={this.segmentProgress}
|
||||||
startTime={this.startTime()}
|
startTime={this.startTime()}
|
||||||
videoLength={this.videoLength()}
|
videoLength={this.videoLength()}
|
||||||
segmentIndices={this.props.segmentIndices}
|
segmentIndices={segmentIndices}
|
||||||
onUserSeek={this.onUserSeek}
|
onUserSeek={this.onUserSeek}
|
||||||
onPlaySeek={this.props.onPlaySeek}
|
onPlaySeek={this.onPlaySeek}
|
||||||
videoElement={this.state.videoElement}
|
videoElement={this.state.videoElement}
|
||||||
onPlay={this.props.onPlay}
|
onPlay={this.props.onPlay}
|
||||||
onPause={this.props.onPause}
|
onPause={this.props.onPause}
|
||||||
|
@ -245,3 +264,21 @@ export default class RouteVideoSync extends Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RouteVideoSync.propTypes = {
|
||||||
|
userSeekIndex: PropTypes.number.isRequired,
|
||||||
|
segment: PropTypes.array.isRequired,
|
||||||
|
message: PropTypes.object,
|
||||||
|
thumbnails: PropTypes.array,
|
||||||
|
canFrameOffset: PropTypes.number.isRequired,
|
||||||
|
url: PropTypes.string.isRequired,
|
||||||
|
playing: PropTypes.bool.isRequired,
|
||||||
|
onPlaySeek: PropTypes.func.isRequired,
|
||||||
|
onUserSeek: PropTypes.func.isRequired,
|
||||||
|
onPlay: PropTypes.func.isRequired,
|
||||||
|
onPause: PropTypes.func.isRequired,
|
||||||
|
userSeekTime: PropTypes.number.isRequired,
|
||||||
|
playSpeed: PropTypes.number.isRequired,
|
||||||
|
onVideoClick: PropTypes.func,
|
||||||
|
segmentIndices: PropTypes.array,
|
||||||
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* eslint-env worker */
|
/* eslint-env worker */
|
||||||
/* eslint-disable no-restricted-globals */
|
/* eslint-disable no-restricted-globals, no-param-reassign */
|
||||||
import LogStream from '@commaai/log_reader';
|
import LogStream from '@commaai/log_reader';
|
||||||
import { timeout } from 'thyming';
|
import { timeout } from 'thyming';
|
||||||
import { partial } from 'ap';
|
import { partial } from 'ap';
|
||||||
|
@ -8,47 +8,25 @@ import { getLogPart } from '../api/rlog';
|
||||||
import DbcUtils from '../utils/dbc';
|
import DbcUtils from '../utils/dbc';
|
||||||
import DBC from '../models/can/dbc';
|
import DBC from '../models/can/dbc';
|
||||||
import { addressForName } from '../models/can/logSignals';
|
import { addressForName } from '../models/can/logSignals';
|
||||||
|
import {
|
||||||
|
getFlags,
|
||||||
|
getUbloxGnss,
|
||||||
|
getEgoData,
|
||||||
|
getCarStateControls,
|
||||||
|
getWheelSpeeds,
|
||||||
|
getThermalFreeSpace,
|
||||||
|
getThermalData,
|
||||||
|
getThermalCPU,
|
||||||
|
getHealth
|
||||||
|
} from './rlog-utils';
|
||||||
|
|
||||||
const DEBOUNCE_DELAY = 100;
|
const DEBOUNCE_DELAY = 100;
|
||||||
|
|
||||||
self.onmessage = handleMessage;
|
|
||||||
|
|
||||||
function handleMessage(msg) {
|
|
||||||
const options = msg.data;
|
|
||||||
|
|
||||||
if (options.action === 'terminate') {
|
|
||||||
close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
options.dbc = new DBC(options.dbcText);
|
|
||||||
|
|
||||||
const entry = new CacheEntry(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
function CacheEntry(options) {
|
|
||||||
options = options || {};
|
|
||||||
this.options = options;
|
|
||||||
|
|
||||||
const {
|
|
||||||
route, part, dbc, logUrls
|
|
||||||
} = options;
|
|
||||||
|
|
||||||
this.messages = {};
|
|
||||||
this.route = route;
|
|
||||||
this.part = part;
|
|
||||||
this.dbc = dbc;
|
|
||||||
this.logUrls = logUrls;
|
|
||||||
this.sendBatch = partial(sendBatch, this);
|
|
||||||
|
|
||||||
// load in the data!
|
|
||||||
loadData(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendBatch(entry) {
|
function sendBatch(entry) {
|
||||||
delete entry.batching;
|
delete entry.batching;
|
||||||
const { messages } = entry;
|
const { messages, thumbnails } = entry;
|
||||||
entry.messages = {};
|
entry.messages = {};
|
||||||
|
entry.thumbnails = [];
|
||||||
|
|
||||||
let { maxByteStateChangeCount } = entry.options;
|
let { maxByteStateChangeCount } = entry.options;
|
||||||
const newMaxByteStateChangeCount = DbcUtils.findMaxByteStateChangeCount(
|
const newMaxByteStateChangeCount = DbcUtils.findMaxByteStateChangeCount(
|
||||||
|
@ -67,8 +45,9 @@ function sendBatch(entry) {
|
||||||
|
|
||||||
self.postMessage({
|
self.postMessage({
|
||||||
newMessages: messages,
|
newMessages: messages,
|
||||||
maxByteStateChangeCount,
|
newThumbnails: thumbnails,
|
||||||
isFinished: entry.ended
|
isFinished: entry.ended,
|
||||||
|
maxByteStateChangeCount
|
||||||
});
|
});
|
||||||
|
|
||||||
if (entry.ended) {
|
if (entry.ended) {
|
||||||
|
@ -77,6 +56,93 @@ function sendBatch(entry) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function queueBatch(entry) {
|
||||||
|
if (!entry.batching) {
|
||||||
|
entry.batching = timeout(entry.sendBatch, DEBOUNCE_DELAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPrevMsgEntry(messages, prevMsgEntries, id) {
|
||||||
|
if (messages[id].entries.length) {
|
||||||
|
return messages[id].entries[messages[id].entries.length - 1];
|
||||||
|
}
|
||||||
|
return prevMsgEntries[id] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertEventData(src, part, entry, logTime, getData) {
|
||||||
|
const id = `${src}:${part}`;
|
||||||
|
const address = addressForName(id);
|
||||||
|
|
||||||
|
if (!entry.messages[id]) {
|
||||||
|
entry.messages[id] = DbcUtils.createMessageSpec(
|
||||||
|
entry.dbc,
|
||||||
|
address,
|
||||||
|
id,
|
||||||
|
src
|
||||||
|
);
|
||||||
|
entry.messages[id].isLogEvent = true;
|
||||||
|
}
|
||||||
|
const prevMsgEntry = getPrevMsgEntry(
|
||||||
|
entry.messages,
|
||||||
|
entry.options.prevMsgEntries,
|
||||||
|
id
|
||||||
|
);
|
||||||
|
|
||||||
|
const { msgEntry, byteStateChangeCounts } = DbcUtils.parseMessage(
|
||||||
|
entry.dbc,
|
||||||
|
logTime,
|
||||||
|
address,
|
||||||
|
getData(),
|
||||||
|
entry.options.canStartTime,
|
||||||
|
prevMsgEntry
|
||||||
|
);
|
||||||
|
|
||||||
|
entry.messages[id].byteStateChangeCounts = byteStateChangeCounts.map(
|
||||||
|
(count, idx) => entry.messages[id].byteStateChangeCounts[idx] + count
|
||||||
|
);
|
||||||
|
|
||||||
|
entry.messages[id].entries.push(msgEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertCanMessage(entry, logTime, msg) {
|
||||||
|
const src = msg.Src;
|
||||||
|
const address = Number(msg.Address);
|
||||||
|
const addressHexStr = address.toString(16);
|
||||||
|
const id = `${src}:${addressHexStr}`;
|
||||||
|
|
||||||
|
if (!entry.messages[id]) {
|
||||||
|
entry.messages[id] = DbcUtils.createMessageSpec(
|
||||||
|
entry.dbc,
|
||||||
|
address,
|
||||||
|
id,
|
||||||
|
src
|
||||||
|
);
|
||||||
|
entry.messages[id].isLogEvent = false;
|
||||||
|
}
|
||||||
|
const prevMsgEntry = getPrevMsgEntry(
|
||||||
|
entry.messages,
|
||||||
|
entry.options.prevMsgEntries,
|
||||||
|
id
|
||||||
|
);
|
||||||
|
|
||||||
|
const { msgEntry, byteStateChangeCounts } = DbcUtils.parseMessage(
|
||||||
|
entry.dbc,
|
||||||
|
logTime,
|
||||||
|
address,
|
||||||
|
msg.Dat,
|
||||||
|
entry.options.canStartTime,
|
||||||
|
prevMsgEntry
|
||||||
|
);
|
||||||
|
|
||||||
|
entry.messages[id].byteStateChangeCounts = byteStateChangeCounts.map(
|
||||||
|
(count, idx) => entry.messages[id].byteStateChangeCounts[idx] + count
|
||||||
|
);
|
||||||
|
|
||||||
|
entry.messages[id].entries.push(msgEntry);
|
||||||
|
|
||||||
|
// console.log(id);
|
||||||
|
}
|
||||||
|
|
||||||
async function loadData(entry) {
|
async function loadData(entry) {
|
||||||
let url = null;
|
let url = null;
|
||||||
|
|
||||||
|
@ -85,9 +151,10 @@ async function loadData(entry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!url || url.indexOf('.7z') !== -1) {
|
if (!url || url.indexOf('.7z') !== -1) {
|
||||||
return self.postMessage({
|
self.postMessage({
|
||||||
error: 'Invalid or missing log files'
|
error: 'Invalid or missing log files'
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const res = await getLogPart(entry.logUrls[entry.part]);
|
const res = await getLogPart(entry.logUrls[entry.part]);
|
||||||
const logReader = new LogStream(res);
|
const logReader = new LogStream(res);
|
||||||
|
@ -102,10 +169,6 @@ async function loadData(entry) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const msgArr = [];
|
|
||||||
const startTime = Date.now();
|
|
||||||
const i = 0;
|
|
||||||
|
|
||||||
logReader((msg) => {
|
logReader((msg) => {
|
||||||
if (entry.ended) {
|
if (entry.ended) {
|
||||||
console.log('You can get msgs after end', msg);
|
console.log('You can get msgs after end', msg);
|
||||||
|
@ -191,290 +254,49 @@ async function loadData(entry) {
|
||||||
monoTime,
|
monoTime,
|
||||||
partial(getThermalFreeSpace, msg.Thermal)
|
partial(getThermalFreeSpace, msg.Thermal)
|
||||||
);
|
);
|
||||||
|
} else if ('Thumbnail' in msg) {
|
||||||
|
const monoTime = msg.LogMonoTime / 1000000000 - entry.options.canStartTime;
|
||||||
|
const data = new Uint8Array(msg.Thumbnail.Thumbnail);
|
||||||
|
entry.thumbnails.push({ data, monoTime });
|
||||||
} else {
|
} else {
|
||||||
|
// console.log(Object.keys(msg));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
queueBatch(entry);
|
queueBatch(entry);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function queueBatch(entry) {
|
function CacheEntry(options) {
|
||||||
if (!entry.batching) {
|
options = options || {};
|
||||||
entry.batching = timeout(entry.sendBatch, DEBOUNCE_DELAY);
|
this.options = options;
|
||||||
}
|
|
||||||
|
const {
|
||||||
|
route, part, dbc, logUrls
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
this.messages = {};
|
||||||
|
this.thumbnails = [];
|
||||||
|
this.route = route;
|
||||||
|
this.part = part;
|
||||||
|
this.dbc = dbc;
|
||||||
|
this.logUrls = logUrls;
|
||||||
|
this.sendBatch = partial(sendBatch, this);
|
||||||
|
this.loadData = partial(loadData, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertEventData(src, part, entry, logTime, getData) {
|
function handleMessage(msg) {
|
||||||
const id = `${src}:${part}`;
|
const options = msg.data;
|
||||||
const address = addressForName(id);
|
|
||||||
|
|
||||||
if (!entry.messages[id]) {
|
if (options.action === 'terminate') {
|
||||||
entry.messages[id] = DbcUtils.createMessageSpec(
|
close();
|
||||||
entry.dbc,
|
return;
|
||||||
address,
|
|
||||||
id,
|
|
||||||
src
|
|
||||||
);
|
|
||||||
entry.messages[id].isLogEvent = true;
|
|
||||||
}
|
}
|
||||||
const prevMsgEntry = getPrevMsgEntry(
|
|
||||||
entry.messages,
|
|
||||||
entry.options.prevMsgEntries,
|
|
||||||
id
|
|
||||||
);
|
|
||||||
|
|
||||||
const { msgEntry, byteStateChangeCounts } = DbcUtils.parseMessage(
|
options.dbc = new DBC(options.dbcText);
|
||||||
entry.dbc,
|
|
||||||
logTime,
|
|
||||||
address,
|
|
||||||
getData(),
|
|
||||||
entry.options.canStartTime,
|
|
||||||
prevMsgEntry
|
|
||||||
);
|
|
||||||
|
|
||||||
entry.messages[id].byteStateChangeCounts = byteStateChangeCounts.map(
|
const entry = new CacheEntry(options);
|
||||||
(count, idx) => entry.messages[id].byteStateChangeCounts[idx] + count
|
// load in the data!
|
||||||
);
|
entry.loadData();
|
||||||
|
|
||||||
entry.messages[id].entries.push(msgEntry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getThermalFlags(state) {
|
self.onmessage = handleMessage;
|
||||||
let flags = 0x00;
|
|
||||||
|
|
||||||
if (state.UsbOnline) {
|
|
||||||
flags |= 0x01;
|
|
||||||
}
|
|
||||||
if (state.Started) {
|
|
||||||
flags |= 0x02;
|
|
||||||
}
|
|
||||||
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getThermalFreeSpace(state) {
|
|
||||||
return longToByteArray(state.FreeSpace * 1000000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getThermalData(state) {
|
|
||||||
return shortToByteArray(state.Mem)
|
|
||||||
.concat(shortToByteArray(state.Gpu))
|
|
||||||
.concat(shortToByteArray(state.FanSpeed))
|
|
||||||
.concat(state.BatteryPercent)
|
|
||||||
.concat(getThermalFlags(state));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getThermalCPU(state) {
|
|
||||||
return shortToByteArray(state.Cpu0)
|
|
||||||
.concat(shortToByteArray(state.Cpu1))
|
|
||||||
.concat(shortToByteArray(state.Cpu2))
|
|
||||||
.concat(shortToByteArray(state.Cpu3));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHealth(state) {
|
|
||||||
return signedShortToByteArray(state.Voltage)
|
|
||||||
.concat(state.Current)
|
|
||||||
.concat(getHealthFlags(state));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHealthFlags(state) {
|
|
||||||
let flags = 0x00;
|
|
||||||
|
|
||||||
if (state.Started) {
|
|
||||||
flags |= 0x01;
|
|
||||||
}
|
|
||||||
if (state.ControlsAllowed) {
|
|
||||||
flags |= 0x02;
|
|
||||||
}
|
|
||||||
if (state.GasInterceptorDetected) {
|
|
||||||
flags |= 0x04;
|
|
||||||
}
|
|
||||||
if (state.StartedSignalDetected) {
|
|
||||||
flags |= 0x08;
|
|
||||||
}
|
|
||||||
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUbloxGnss(state) {
|
|
||||||
return signedLongToByteArray(state.RcvTow / 1000)
|
|
||||||
.concat(signedShortToByteArray(state.GpsWeek))
|
|
||||||
.concat([state.LeapSeconds])
|
|
||||||
.concat([state.NumMeas]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getEgoData(state) {
|
|
||||||
return signedShortToByteArray(state.VEgo * 1000)
|
|
||||||
.concat(signedShortToByteArray(state.AEgo * 1000))
|
|
||||||
.concat(signedShortToByteArray(state.VEgoRaw * 1000))
|
|
||||||
.concat(signedShortToByteArray(state.YawRate * 1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCarStateControls(state) {
|
|
||||||
return signedLongToByteArray(state.SteeringAngle * 1000)
|
|
||||||
.concat(signedShortToByteArray(state.Brake * 1000))
|
|
||||||
.concat(signedShortToByteArray(state.Gas * 1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getWheelSpeeds(state) {
|
|
||||||
return signedShortToByteArray(state.WheelSpeeds.Fl * 100)
|
|
||||||
.concat(signedShortToByteArray(state.WheelSpeeds.Fr * 100))
|
|
||||||
.concat(signedShortToByteArray(state.WheelSpeeds.Rl * 100))
|
|
||||||
.concat(signedShortToByteArray(state.WheelSpeeds.Rr * 100));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFlags(state) {
|
|
||||||
let flags = 0x00;
|
|
||||||
const arr = [0, 0, 0];
|
|
||||||
|
|
||||||
if (state.LeftBlinker) {
|
|
||||||
flags |= 0x01;
|
|
||||||
}
|
|
||||||
if (state.RightBlinker) {
|
|
||||||
flags |= 0x02;
|
|
||||||
}
|
|
||||||
if (state.GenericToggle) {
|
|
||||||
flags |= 0x04;
|
|
||||||
}
|
|
||||||
if (state.DoorOpen) {
|
|
||||||
flags |= 0x08;
|
|
||||||
}
|
|
||||||
if (state.SeatbeltUnlatched) {
|
|
||||||
flags |= 0x10;
|
|
||||||
}
|
|
||||||
if (state.GasPressed) {
|
|
||||||
flags |= 0x20;
|
|
||||||
}
|
|
||||||
if (state.BrakeLights) {
|
|
||||||
flags |= 0x40;
|
|
||||||
}
|
|
||||||
if (state.SteeringPressed) {
|
|
||||||
flags |= 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
arr[0] = flags;
|
|
||||||
flags = 0x00;
|
|
||||||
|
|
||||||
if (state.Standstill) {
|
|
||||||
flags |= 0x01;
|
|
||||||
}
|
|
||||||
if (state.CruiseState.Enabled) {
|
|
||||||
flags |= 0x02;
|
|
||||||
}
|
|
||||||
if (state.CruiseState.Available) {
|
|
||||||
flags |= 0x04;
|
|
||||||
}
|
|
||||||
if (state.CruiseState.Standstill) {
|
|
||||||
flags |= 0x08;
|
|
||||||
}
|
|
||||||
if (state.GearShifter) {
|
|
||||||
flags |= state.GearShifter << 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
arr[1] = flags;
|
|
||||||
arr[2] = state.CruiseState.Speed;
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertCanMessage(entry, logTime, msg) {
|
|
||||||
const src = msg.Src;
|
|
||||||
const address = Number(msg.Address);
|
|
||||||
const busTime = msg.BusTime;
|
|
||||||
const addressHexStr = address.toString(16);
|
|
||||||
const id = `${src}:${addressHexStr}`;
|
|
||||||
|
|
||||||
if (!entry.messages[id]) {
|
|
||||||
entry.messages[id] = DbcUtils.createMessageSpec(
|
|
||||||
entry.dbc,
|
|
||||||
address,
|
|
||||||
id,
|
|
||||||
src
|
|
||||||
);
|
|
||||||
entry.messages[id].isLogEvent = false;
|
|
||||||
}
|
|
||||||
const prevMsgEntry = getPrevMsgEntry(
|
|
||||||
entry.messages,
|
|
||||||
entry.options.prevMsgEntries,
|
|
||||||
id
|
|
||||||
);
|
|
||||||
|
|
||||||
const { msgEntry, byteStateChangeCounts } = DbcUtils.parseMessage(
|
|
||||||
entry.dbc,
|
|
||||||
logTime,
|
|
||||||
address,
|
|
||||||
msg.Dat,
|
|
||||||
entry.options.canStartTime,
|
|
||||||
prevMsgEntry
|
|
||||||
);
|
|
||||||
|
|
||||||
entry.messages[id].byteStateChangeCounts = byteStateChangeCounts.map(
|
|
||||||
(count, idx) => entry.messages[id].byteStateChangeCounts[idx] + count
|
|
||||||
);
|
|
||||||
|
|
||||||
entry.messages[id].entries.push(msgEntry);
|
|
||||||
|
|
||||||
// console.log(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPrevMsgEntry(messages, prevMsgEntries, id) {
|
|
||||||
if (messages[id].entries.length) {
|
|
||||||
return messages[id].entries[messages[id].entries.length - 1];
|
|
||||||
}
|
|
||||||
return prevMsgEntries[id] || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function signedShortToByteArray(short) {
|
|
||||||
const byteArray = [0, 0];
|
|
||||||
const isNegative = short < 0;
|
|
||||||
if (isNegative) {
|
|
||||||
short += Math.pow(2, 8 * byteArray.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let index = byteArray.length - 1; index >= 0; --index) {
|
|
||||||
const byte = short & 0xff;
|
|
||||||
byteArray[index] = byte;
|
|
||||||
short >>= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
return byteArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
function shortToByteArray(short) {
|
|
||||||
const byteArray = [0, 0];
|
|
||||||
|
|
||||||
for (let index = byteArray.length - 1; index >= 0; --index) {
|
|
||||||
const byte = short & 0xff;
|
|
||||||
byteArray[index] = byte;
|
|
||||||
short >>= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
return byteArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
function longToByteArray(long) {
|
|
||||||
const byteArray = [0, 0, 0, 0];
|
|
||||||
|
|
||||||
for (let index = byteArray.length - 1; index >= 0; --index) {
|
|
||||||
const byte = long & 0xff;
|
|
||||||
byteArray[index] = byte;
|
|
||||||
long >>= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
return byteArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
function signedLongToByteArray(long) {
|
|
||||||
const byteArray = [0, 0, 0, 0];
|
|
||||||
const isNegative = long < 0;
|
|
||||||
if (isNegative) {
|
|
||||||
long += Math.pow(2, 8 * byteArray.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let index = byteArray.length - 1; index >= 0; --index) {
|
|
||||||
const byte = long & 0xff;
|
|
||||||
byteArray[index] = byte;
|
|
||||||
long >>= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
return byteArray;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,194 @@
|
||||||
|
/* eslint-disable no-param-reassign, no-bitwise */
|
||||||
|
|
||||||
|
export function signedShortToByteArray(short) {
|
||||||
|
const byteArray = [0, 0];
|
||||||
|
const isNegative = short < 0;
|
||||||
|
if (isNegative) {
|
||||||
|
short += 2 ** (8 * byteArray.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let index = byteArray.length - 1; index >= 0; --index) {
|
||||||
|
const byte = short & 0xff;
|
||||||
|
byteArray[index] = byte;
|
||||||
|
short >>= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return byteArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shortToByteArray(short) {
|
||||||
|
const byteArray = [0, 0];
|
||||||
|
|
||||||
|
for (let index = byteArray.length - 1; index >= 0; --index) {
|
||||||
|
const byte = short & 0xff;
|
||||||
|
byteArray[index] = byte;
|
||||||
|
short >>= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return byteArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function longToByteArray(long) {
|
||||||
|
const byteArray = [0, 0, 0, 0];
|
||||||
|
|
||||||
|
for (let index = byteArray.length - 1; index >= 0; --index) {
|
||||||
|
const byte = long & 0xff;
|
||||||
|
byteArray[index] = byte;
|
||||||
|
long >>= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return byteArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function signedLongToByteArray(long) {
|
||||||
|
const byteArray = [0, 0, 0, 0];
|
||||||
|
const isNegative = long < 0;
|
||||||
|
if (isNegative) {
|
||||||
|
long += 2 ** (8 * byteArray.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let index = byteArray.length - 1; index >= 0; --index) {
|
||||||
|
const byte = long & 0xff;
|
||||||
|
byteArray[index] = byte;
|
||||||
|
long >>= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return byteArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getThermalFlags(state) {
|
||||||
|
let flags = 0x00;
|
||||||
|
|
||||||
|
if (state.UsbOnline) {
|
||||||
|
flags |= 0x01;
|
||||||
|
}
|
||||||
|
if (state.Started) {
|
||||||
|
flags |= 0x02;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getHealthFlags(state) {
|
||||||
|
let flags = 0x00;
|
||||||
|
|
||||||
|
if (state.Started) {
|
||||||
|
flags |= 0x01;
|
||||||
|
}
|
||||||
|
if (state.ControlsAllowed) {
|
||||||
|
flags |= 0x02;
|
||||||
|
}
|
||||||
|
if (state.GasInterceptorDetected) {
|
||||||
|
flags |= 0x04;
|
||||||
|
}
|
||||||
|
if (state.StartedSignalDetected) {
|
||||||
|
flags |= 0x08;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFlags(state) {
|
||||||
|
let flags = 0x00;
|
||||||
|
const arr = [0, 0, 0];
|
||||||
|
|
||||||
|
if (state.LeftBlinker) {
|
||||||
|
flags |= 0x01;
|
||||||
|
}
|
||||||
|
if (state.RightBlinker) {
|
||||||
|
flags |= 0x02;
|
||||||
|
}
|
||||||
|
if (state.GenericToggle) {
|
||||||
|
flags |= 0x04;
|
||||||
|
}
|
||||||
|
if (state.DoorOpen) {
|
||||||
|
flags |= 0x08;
|
||||||
|
}
|
||||||
|
if (state.SeatbeltUnlatched) {
|
||||||
|
flags |= 0x10;
|
||||||
|
}
|
||||||
|
if (state.GasPressed) {
|
||||||
|
flags |= 0x20;
|
||||||
|
}
|
||||||
|
if (state.BrakeLights) {
|
||||||
|
flags |= 0x40;
|
||||||
|
}
|
||||||
|
if (state.SteeringPressed) {
|
||||||
|
flags |= 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr[0] = flags;
|
||||||
|
flags = 0x00;
|
||||||
|
|
||||||
|
if (state.Standstill) {
|
||||||
|
flags |= 0x01;
|
||||||
|
}
|
||||||
|
if (state.CruiseState.Enabled) {
|
||||||
|
flags |= 0x02;
|
||||||
|
}
|
||||||
|
if (state.CruiseState.Available) {
|
||||||
|
flags |= 0x04;
|
||||||
|
}
|
||||||
|
if (state.CruiseState.Standstill) {
|
||||||
|
flags |= 0x08;
|
||||||
|
}
|
||||||
|
if (state.GearShifter) {
|
||||||
|
flags |= state.GearShifter << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr[1] = flags;
|
||||||
|
arr[2] = state.CruiseState.Speed;
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUbloxGnss(state) {
|
||||||
|
return signedLongToByteArray(state.RcvTow / 1000)
|
||||||
|
.concat(signedShortToByteArray(state.GpsWeek))
|
||||||
|
.concat([state.LeapSeconds])
|
||||||
|
.concat([state.NumMeas]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getEgoData(state) {
|
||||||
|
return signedShortToByteArray(state.VEgo * 1000)
|
||||||
|
.concat(signedShortToByteArray(state.AEgo * 1000))
|
||||||
|
.concat(signedShortToByteArray(state.VEgoRaw * 1000))
|
||||||
|
.concat(signedShortToByteArray(state.YawRate * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCarStateControls(state) {
|
||||||
|
return signedLongToByteArray(state.SteeringAngle * 1000)
|
||||||
|
.concat(signedShortToByteArray(state.Brake * 1000))
|
||||||
|
.concat(signedShortToByteArray(state.Gas * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getWheelSpeeds(state) {
|
||||||
|
return signedShortToByteArray(state.WheelSpeeds.Fl * 100)
|
||||||
|
.concat(signedShortToByteArray(state.WheelSpeeds.Fr * 100))
|
||||||
|
.concat(signedShortToByteArray(state.WheelSpeeds.Rl * 100))
|
||||||
|
.concat(signedShortToByteArray(state.WheelSpeeds.Rr * 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getThermalFreeSpace(state) {
|
||||||
|
return longToByteArray(state.FreeSpace * 1000000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getThermalData(state) {
|
||||||
|
return shortToByteArray(state.Mem)
|
||||||
|
.concat(shortToByteArray(state.Gpu))
|
||||||
|
.concat(shortToByteArray(state.FanSpeed))
|
||||||
|
.concat(state.BatteryPercent)
|
||||||
|
.concat(getThermalFlags(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getThermalCPU(state) {
|
||||||
|
return shortToByteArray(state.Cpu0)
|
||||||
|
.concat(shortToByteArray(state.Cpu1))
|
||||||
|
.concat(shortToByteArray(state.Cpu2))
|
||||||
|
.concat(shortToByteArray(state.Cpu3));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getHealth(state) {
|
||||||
|
return signedShortToByteArray(state.Voltage)
|
||||||
|
.concat(state.Current)
|
||||||
|
.concat(getHealthFlags(state));
|
||||||
|
}
|
39
yarn.lock
39
yarn.lock
|
@ -911,6 +911,13 @@
|
||||||
exec-sh "^0.3.2"
|
exec-sh "^0.3.2"
|
||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
|
|
||||||
|
"@commaai/capnp-json@^0.2.0":
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@commaai/capnp-json/-/capnp-json-0.2.0.tgz#866bba39274b02f899803dc7968a7fe79fb02321"
|
||||||
|
integrity sha512-PXqEjvoLkb7VPaeMlFV7NspHAUMfTGhd6plQ72rilrjagf1os73fdItdlhk/q2XELx+l/Vq1xRSLJT1Os0DVqQ==
|
||||||
|
dependencies:
|
||||||
|
capnp-ts "0.2.4"
|
||||||
|
|
||||||
"@commaai/comma-api@1.1.6":
|
"@commaai/comma-api@1.1.6":
|
||||||
version "1.1.6"
|
version "1.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/@commaai/comma-api/-/comma-api-1.1.6.tgz#be486443a8d8843c74a811cdd406b85694b5d526"
|
resolved "https://registry.yarnpkg.com/@commaai/comma-api/-/comma-api-1.1.6.tgz#be486443a8d8843c74a811cdd406b85694b5d526"
|
||||||
|
@ -931,21 +938,21 @@
|
||||||
joi-browser "^13.4.0"
|
joi-browser "^13.4.0"
|
||||||
querystringify "^2.1.1"
|
querystringify "^2.1.1"
|
||||||
|
|
||||||
"@commaai/log_reader@^0.3.1":
|
"@commaai/log_reader@^0.5.3":
|
||||||
version "0.3.1"
|
version "0.5.3"
|
||||||
resolved "https://registry.yarnpkg.com/@commaai/log_reader/-/log_reader-0.3.1.tgz#0e2b47b621ac9b852ccf5137787e17952a34170c"
|
resolved "https://registry.yarnpkg.com/@commaai/log_reader/-/log_reader-0.5.3.tgz#c3dd2c6f3b911198c32bbebd34d0e9cc862e0672"
|
||||||
integrity sha512-WMV6BiSBOfPFOld3KKuuEHRSAPv95cpeDes4LWwy4cONYZHnnuVu91v5nYzQVbB3F6eQaCvkakmwLSzR2UQkow==
|
integrity sha512-/962u7s7uXPMGLz2AH+L57w+CSXCX1uZmh0OLSwGZXzyxO/dGvimaVspYe9N78Q0BYa1B5ctv986zliaAblrmg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@commaai/unbzip2-stream" "^2.0.0"
|
"@commaai/capnp-json" "^0.2.0"
|
||||||
JSONStream "^1.3.2"
|
JSONStream "^1.3.2"
|
||||||
ap "^0.2.0"
|
ap "^0.2.0"
|
||||||
capnp-json "^0.1.2"
|
|
||||||
capnp-split "^0.1.1"
|
capnp-split "^0.1.1"
|
||||||
capnp-ts "^0.2.4"
|
capnp-ts "^0.2.4"
|
||||||
commander "^2.15.1"
|
commander "^2.15.1"
|
||||||
file-type "^7.6.0"
|
file-type "^7.6.0"
|
||||||
geval "^2.2.0"
|
geval "^2.2.0"
|
||||||
stream-selector "^0.4.0"
|
stream-selector "^0.4.0"
|
||||||
|
wasm-bz2 "^0.0.2"
|
||||||
|
|
||||||
"@commaai/my-comma-auth@^1.1.0":
|
"@commaai/my-comma-auth@^1.1.0":
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
|
@ -978,11 +985,6 @@
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
usb "^1.3.1"
|
usb "^1.3.1"
|
||||||
|
|
||||||
"@commaai/unbzip2-stream@^2.0.0":
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@commaai/unbzip2-stream/-/unbzip2-stream-2.0.0.tgz#93821dc5e72f04ec5eedef5ed4e6ff57412019e0"
|
|
||||||
integrity sha512-Dqzzmos7r2OsvpJ9YtID1n50GpVwB4dw7ft41XJZM2V7bJ0L68ygeK4WktaT1ZslgWz5NzqHEn0t9nWFuopixg==
|
|
||||||
|
|
||||||
"@craco/craco@^5.5.0":
|
"@craco/craco@^5.5.0":
|
||||||
version "5.5.0"
|
version "5.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/@craco/craco/-/craco-5.5.0.tgz#081b25522d866fbc14b80fe61517f2f10e3e4499"
|
resolved "https://registry.yarnpkg.com/@craco/craco/-/craco-5.5.0.tgz#081b25522d866fbc14b80fe61517f2f10e3e4499"
|
||||||
|
@ -2830,11 +2832,6 @@ canvas@^1.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
nan "^2.10.0"
|
nan "^2.10.0"
|
||||||
|
|
||||||
capnp-json@^0.1.2:
|
|
||||||
version "0.1.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/capnp-json/-/capnp-json-0.1.3.tgz#e305dd690b9fcf53e2e19278eb6a99d187ea8047"
|
|
||||||
integrity sha512-S1bRHkHECsFVjETOZKnxIeab00ozGb7wyS7HEkNhOLUo1/9oDvcURdttp7AbOPDUSIUWM9HoPKdnnH/SSHNBWA==
|
|
||||||
|
|
||||||
capnp-split@^0.1.1:
|
capnp-split@^0.1.1:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/capnp-split/-/capnp-split-0.1.4.tgz#c3f86890645cd203c5ce23ff1ccb4fe6642ea4a3"
|
resolved "https://registry.yarnpkg.com/capnp-split/-/capnp-split-0.1.4.tgz#c3f86890645cd203c5ce23ff1ccb4fe6642ea4a3"
|
||||||
|
@ -2842,7 +2839,7 @@ capnp-split@^0.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
through2 "^2.0.3"
|
through2 "^2.0.3"
|
||||||
|
|
||||||
capnp-ts@^0.2.4:
|
capnp-ts@0.2.4, capnp-ts@^0.2.4:
|
||||||
version "0.2.4"
|
version "0.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/capnp-ts/-/capnp-ts-0.2.4.tgz#da729493311f384d65d480d9afe979ceab9f41bb"
|
resolved "https://registry.yarnpkg.com/capnp-ts/-/capnp-ts-0.2.4.tgz#da729493311f384d65d480d9afe979ceab9f41bb"
|
||||||
integrity sha512-A9+Awl2WQDhg0fpEoyDpIF7RUQp27gpYBLRGV2zKA37a0IBEutdgIKDI7pO44C9AhzxvCfR6Ooj5W14D3TKaQA==
|
integrity sha512-A9+Awl2WQDhg0fpEoyDpIF7RUQp27gpYBLRGV2zKA37a0IBEutdgIKDI7pO44C9AhzxvCfR6Ooj5W14D3TKaQA==
|
||||||
|
@ -13330,6 +13327,14 @@ walker@^1.0.7, walker@~1.0.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
makeerror "1.0.x"
|
makeerror "1.0.x"
|
||||||
|
|
||||||
|
wasm-bz2@^0.0.2:
|
||||||
|
version "0.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/wasm-bz2/-/wasm-bz2-0.0.2.tgz#ff5c4e3ed660169ec14f00bd9f4650c43c142a13"
|
||||||
|
integrity sha512-OjWSwiIvz8yacBBqajiZTSVI9Yom1nHFjBuXJFTOwa9rkHIQFNmFaEG65kmnUlFMUNU6mxmGGKAwF8BGMesZ6g==
|
||||||
|
dependencies:
|
||||||
|
ap "^0.2.0"
|
||||||
|
weakmap-event "^2.0.7"
|
||||||
|
|
||||||
watchpack@^1.6.0:
|
watchpack@^1.6.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
|
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
|
||||||
|
|
Loading…
Reference in New Issue