Fix city hub bootloader compatibility

The city hub requires that certain messages are write with response and
others are write without response, otherwise it will cause BlueZ to
disconnect because it does not follow proper BLE protocol.
This commit is contained in:
David Lechner
2020-05-22 19:54:48 -05:00
committed by David Lechner
parent 21208344be
commit ac6c798148
4 changed files with 33 additions and 4 deletions
+1 -1
View File
@@ -84,7 +84,7 @@ export interface BootloaderConnectionSendAction
export function send(
data: ArrayBuffer,
withResponse = false,
withResponse = true,
): BootloaderConnectionSendAction {
return { type: BootloaderConnectionActionType.Send, data, withResponse };
}
+3 -2
View File
@@ -146,7 +146,8 @@ describe('message encoder', () => {
expect(dispatched[0]).toEqual({
type: BootloaderConnectionActionType.Send,
data: message,
withResponse: false,
// Program is write without response, all others are write with response
withResponse: request.type !== BootloaderRequestActionType.Program,
});
});
@@ -185,7 +186,7 @@ describe('message encoder', () => {
expect(dispatched[i]).toEqual({
type: BootloaderConnectionActionType.Send,
data: message,
withResponse: false,
withResponse: true,
});
}
+25 -1
View File
@@ -38,6 +38,7 @@ import {
checksumResponse,
connect,
didRequest,
disconnectRequest,
eraseRequest,
eraseResponse,
errorResponse,
@@ -53,6 +54,7 @@ import {
stateResponse,
} from '../actions/bootloader';
import { MpyCompiledAction, compile } from '../actions/mpy';
import * as notification from '../actions/notification';
import {
Command,
ErrorBytecode,
@@ -92,13 +94,23 @@ function* encodeRequest(): Generator {
while (true) {
const action = (yield take(chan)) as BootloaderRequestAction;
// NB: Commands other than program on city hub will cause BlueZ to
// disconnect because they will send a response even if we write without
// response, so we always write with response on those commands. The
// program command needs to be write without response for performance
// reasons (and also the city hub will disconnect if write with response
// is used on this command).
switch (action.type) {
case BootloaderRequestActionType.Erase:
yield put(send(createEraseFlashRequest()));
break;
case BootloaderRequestActionType.Program:
yield put(
send(createProgramFlashRequest(action.address, action.payload)),
send(
createProgramFlashRequest(action.address, action.payload),
/* withResponse */ false,
),
);
break;
case BootloaderRequestActionType.Reboot:
@@ -294,6 +306,18 @@ function* flashFirmware(action: BootloaderFlashFirmwareAction): Generator {
);
}
// City hub bootloader is buggy. See note in encodeRequest().
if (info[0].hubType === HubType.CityHub && !didConnect.canWriteWithoutResponse) {
yield put(
notification.add(
'error',
'City Hub is not compatible with this web browser.',
),
);
yield put(disconnectRequest());
return;
}
yield put(eraseRequest());
const erase = (yield wait(
BootloaderResponseActionType.Erase,
+4
View File
@@ -86,6 +86,10 @@ async function connect(action: Action, dispatch: Dispatch): Promise<void> {
!char.writeValueWithoutResponse &&
!/Android/i.test(navigator.userAgent)
) {
// TODO: this needs to be an error if connected to city hub
// however it is not currently possible to get mfg-specific
// advertising data, so we don't know what type of hub it is
// until after we connect
dispatch(
notification.add(
'warning',