From 3ae2fb2eefbd912dcbe2cc48cd5864b44cbc15bc Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 20 May 2020 19:51:34 -0500 Subject: [PATCH] wire up firmware flash progress Also turn off logging and longer checksum interval to improve performance 94K movehub fw flashes in about 1:45 --- src/actions/bootloader.ts | 27 +++++++++++++++++++++++++++ src/components/App.tsx | 2 +- src/components/StatusBar.tsx | 24 ++++++++++++++++++++++++ src/components/Statusbar.tsx | 33 --------------------------------- src/index.tsx | 3 ++- src/reducers/index.ts | 4 +++- src/reducers/status.ts | 18 ++++++++++++++++++ src/sagas/bootloader.ts | 9 ++++++--- 8 files changed, 81 insertions(+), 39 deletions(-) create mode 100644 src/components/StatusBar.tsx delete mode 100644 src/components/Statusbar.tsx create mode 100644 src/reducers/status.ts diff --git a/src/actions/bootloader.ts b/src/actions/bootloader.ts index 9ef6747a..8a061065 100644 --- a/src/actions/bootloader.ts +++ b/src/actions/bootloader.ts @@ -299,6 +299,10 @@ export enum BootloaderActionType { * Flash new firmware to the device. */ FlashFirmware = 'bootloader.action.flash', + /** + * Firmware flash progress. + */ + FlashProgress = 'bootloader.action.flash.progress', } export interface BootloaderFlashFirmwareAction @@ -309,3 +313,26 @@ export interface BootloaderFlashFirmwareAction export function flashFirmware(data: ArrayBuffer): BootloaderFlashFirmwareAction { return { type: BootloaderActionType.FlashFirmware, data }; } + +export interface BootloaderFlashProgressAction + extends Action { + /** + * The number of bytes that have been flashed so far. + */ + complete: number; + /** + * The total number of bytes to be flashed. + */ + total: number; +} + +export function progress( + complete: number, + total: number, +): BootloaderFlashProgressAction { + return { type: BootloaderActionType.FlashProgress, complete, total }; +} + +export type BootloaderAction = + | BootloaderFlashFirmwareAction + | BootloaderFlashProgressAction; diff --git a/src/components/App.tsx b/src/components/App.tsx index ee3efef5..032175d6 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Col, Row } from 'react-bootstrap'; import Container from 'react-bootstrap/Container'; import Editor from './Editor'; -import StatusBar from './Statusbar'; +import StatusBar from './StatusBar'; import Terminal from './Terminal'; import Toolbar from './Toolbar'; diff --git a/src/components/StatusBar.tsx b/src/components/StatusBar.tsx new file mode 100644 index 00000000..5e2dcf03 --- /dev/null +++ b/src/components/StatusBar.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import ProgressBar from 'react-bootstrap/ProgressBar'; +import { connect } from 'react-redux'; +import { RootState } from '../reducers'; + +type StateProps = { progress: number }; + +type StatusProps = StateProps; + +class StatusBar extends React.Component { + render(): JSX.Element { + return ( +
+ +
+ ); + } +} + +const mapStateToProps = (state: RootState): StateProps => ({ + progress: state.status.progress, +}); + +export default connect(mapStateToProps)(StatusBar); diff --git a/src/components/Statusbar.tsx b/src/components/Statusbar.tsx deleted file mode 100644 index 2f56f878..00000000 --- a/src/components/Statusbar.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import ProgressBar from 'react-bootstrap/ProgressBar'; -import { BLEConnectionState } from '../reducers/ble'; - -interface StatusBarState { - bleState: BLEConnectionState; -} - -class StatusBar extends React.Component<{}, StatusBarState> { - constructor(props: {}) { - super(props); - this.state = { bleState: BLEConnectionState.Disconnected }; - this.onAction = this.onAction.bind(this); - } - - private onAction(action: string): void { - console.log(action); - } - - setBLEState(state: BLEConnectionState): void { - this.setState({ bleState: state }); - } - - render(): JSX.Element { - return ( -
- -
- ); - } -} - -export default StatusBar; diff --git a/src/index.tsx b/src/index.tsx index 7a240949..658e335d 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -17,7 +17,8 @@ import serviceMiddleware from './services'; const sagaMiddleware = createSagaMiddleware(); const epicMiddleware = createEpicMiddleware(); -const loggerMiddleware = createLogger(); +// TODO: add runtime option or filter - logger affects firmware flash performance +const loggerMiddleware = createLogger({ predicate: () => false }); const store = createStore( rootReducer, diff --git a/src/reducers/index.ts b/src/reducers/index.ts index ec658841..5183237b 100644 --- a/src/reducers/index.ts +++ b/src/reducers/index.ts @@ -4,6 +4,7 @@ import bootloader, { BootloaderState } from './bootloader'; import editor, { EditorState } from './editor'; import hub, { HubState } from './hub'; import notification, { NotificationState } from './notification'; +import status, { StatusState } from './status'; /** * Root state for redux store. @@ -14,6 +15,7 @@ export interface RootState { readonly editor: EditorState; readonly hub: HubState; readonly notification: NotificationState; + readonly status: StatusState; } -export default combineReducers({ bootloader, ble, editor, hub, notification }); +export default combineReducers({ bootloader, ble, editor, hub, notification, status }); diff --git a/src/reducers/status.ts b/src/reducers/status.ts new file mode 100644 index 00000000..efe8cc1f --- /dev/null +++ b/src/reducers/status.ts @@ -0,0 +1,18 @@ +import { Reducer } from 'react'; +import { combineReducers } from 'redux'; +import { BootloaderAction, BootloaderActionType } from '../actions/bootloader'; + +const progress: Reducer = (state = -1, action) => { + switch (action.type) { + case BootloaderActionType.FlashProgress: + return (action.complete / action.total) * 100; + default: + return state; + } +}; + +export interface StatusState { + readonly progress: number; +} + +export default combineReducers({ progress }); diff --git a/src/sagas/bootloader.ts b/src/sagas/bootloader.ts index cd3fa740..e11d76ce 100644 --- a/src/sagas/bootloader.ts +++ b/src/sagas/bootloader.ts @@ -41,6 +41,7 @@ import { initResponse, programRequest, programResponse, + progress, rebootRequest, send, stateResponse, @@ -305,11 +306,11 @@ function* flashFirmware(action: BootloaderFlashFirmwareAction): Generator { const payload = firmware.slice(offset, offset + MaxProgramFlashSize); yield put(programRequest(info[0].startAddress + offset, payload.buffer)); - // TODO: dispatch progress action + yield put(progress(offset, firmware.length)); - // request checksum every so often to prevent buffer overrun on the hub + // request checksum every 8K to prevent buffer overrun on the hub // because of sending too much data at once - if (++count % 10 === 0) { + if (++count % 585 === 0) { yield put(checksumRequest()); const checksum = (yield wait( BootloaderResponseActionType.Checksum, @@ -334,6 +335,8 @@ function* flashFirmware(action: BootloaderFlashFirmwareAction): Generator { throw Error("Didn't flash all bytes"); } + yield put(progress(firmware.length, firmware.length)); + // this will cause the remote device to disconnect and reboot yield put(rebootRequest()); }