rename BLEData to BleUart

These actions all relate specifically to the nRF UART GATT service
This commit is contained in:
David Lechner
2020-06-11 22:53:38 -05:00
committed by David Lechner
parent 802f2bc05d
commit f3425e2f0f
10 changed files with 146 additions and 135 deletions
+73
View File
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
// actions/ble-uart.ts: Actions for Bluetooth Low Energy nRF UART service
import { Action } from 'redux';
import { assert } from '../utils';
import { createCountFunc } from '../utils/iter';
/**
* BLE nRF UART service actions types.
*/
export enum BleUartActionType {
/**
* Write data.
*/
Write = 'ble.data.action.write',
/**
* Writing completed successfully.
*/
DidWrite = 'ble.data.didWrite',
/**
* Writing failed.
*/
DidFailToWrite = 'ble.data.action.didFailToWrite',
/**
* Notify that data was received.
*/
Notify = 'ble.data.action.receive',
}
const nextId = createCountFunc();
export type BleUartWriteAction = Action<BleUartActionType.Write> & {
id: number;
value: Uint8Array;
};
export function write(value: Uint8Array): BleUartWriteAction {
assert(value.length <= 20, 'value can be at most 20 bytes');
return { type: BleUartActionType.Write, id: nextId(), value };
}
export type BleUartDidWriteAction = Action<BleUartActionType.DidWrite> & {
id: number;
};
export function didWrite(id: number): BleUartDidWriteAction {
return { type: BleUartActionType.DidWrite, id };
}
export type BleUartDidFailToWriteAction = Action<BleUartActionType.DidFailToWrite> & {
id: number;
err: Error;
};
export function didFailToWrite(id: number, err: Error): BleUartDidFailToWriteAction {
return { type: BleUartActionType.DidFailToWrite, id, err };
}
export type BleUartNotifyAction = Action<BleUartActionType.Notify> & {
value: DataView;
};
export function notify(value: DataView): BleUartNotifyAction {
return { type: BleUartActionType.Notify, value };
}
/** Common type for low-level BLE data actions. */
export type BleUartAction =
| BleUartWriteAction
| BleUartDidWriteAction
| BleUartDidFailToWriteAction
| BleUartNotifyAction;
-65
View File
@@ -2,8 +2,6 @@
// Copyright (c) 2020 The Pybricks Authors
import { Action } from 'redux';
import { assert } from '../utils';
import { createCountFunc } from '../utils/iter';
/**
* Bluetooth low energy connection action types.
@@ -60,69 +58,6 @@ export function didDisconnect(): BLEConnectAction {
return { type: BLEConnectActionType.DidDisconnect };
}
export enum BLEDataActionType {
/**
* Write data.
*/
Write = 'ble.data.action.write',
/**
* Writing completed successfully.
*/
DidWrite = 'ble.data.didWrite',
/**
* Writing failed.
*/
DidFailToWrite = 'ble.data.action.didFailToWrite',
/**
* Notify that data was received.
*/
Notify = 'ble.data.action.receive',
}
const nextId = createCountFunc();
export type BLEDataWriteAction = Action<BLEDataActionType.Write> & {
id: number;
value: Uint8Array;
};
export function write(value: Uint8Array): BLEDataWriteAction {
assert(value.length <= 20, 'value can be at most 20 bytes');
return { type: BLEDataActionType.Write, id: nextId(), value };
}
export type BLEDataDidWriteAction = Action<BLEDataActionType.DidWrite> & {
id: number;
};
export function didWrite(id: number): BLEDataDidWriteAction {
return { type: BLEDataActionType.DidWrite, id };
}
export type BLEDataDidFailToWriteAction = Action<BLEDataActionType.DidFailToWrite> & {
id: number;
err: Error;
};
export function didFailToWrite(id: number, err: Error): BLEDataDidFailToWriteAction {
return { type: BLEDataActionType.DidFailToWrite, id, err };
}
export type BLEDataNotifyAction = Action<BLEDataActionType.Notify> & {
value: DataView;
};
export function notify(value: DataView): BLEDataNotifyAction {
return { type: BLEDataActionType.Notify, value };
}
/** Common type for low-level BLE data actions. */
export type BLEDataAction =
| BLEDataWriteAction
| BLEDataDidWriteAction
| BLEDataDidFailToWriteAction
| BLEDataNotifyAction;
/**
* High-level BLE actions.
*/
+3 -2
View File
@@ -2,7 +2,8 @@
// Copyright (c) 2020 The Pybricks Authors
import { Dispatch as ReduxDispatch } from 'redux';
import { BLEAction, BLEConnectAction, BLEDataAction } from './ble';
import { BLEAction, BLEConnectAction } from './ble';
import { BleUartAction } from './ble-uart';
import { EditorAction } from './editor';
import { FlashFirmwareAction } from './flash-firmware';
import { HubAction, HubMessageAction } from './hub';
@@ -23,7 +24,7 @@ import { TerminalDataAction } from './terminal';
export type Action =
| BLEAction
| BLEConnectAction
| BLEDataAction
| BleUartAction
| BootloaderConnectionAction
| BootloaderDidRequestAction
| BootloaderRequestAction
+1 -1
View File
@@ -2,7 +2,7 @@
// Copyright (c) 2020 The Pybricks Authors
import { AsyncSaga } from '../../test';
import { didFailToWrite } from '../actions/ble';
import { didFailToWrite } from '../actions/ble-uart';
import {
BootloaderConnectionFailureReason,
didError,
+3 -3
View File
@@ -2,7 +2,7 @@
// Copyright (c) 2020 The Pybricks Authors
import { takeEvery } from 'redux-saga/effects';
import { BLEDataActionType, BLEDataDidFailToWriteAction } from '../actions/ble';
import { BleUartActionType, BleUartDidFailToWriteAction } from '../actions/ble-uart';
import {
BootloaderConnectionActionType,
BootloaderConnectionDidErrorAction,
@@ -10,7 +10,7 @@ import {
BootloaderConnectionFailureReason,
} from '../actions/lwp3-bootloader';
function bleDataDidFailToWrite(action: BLEDataDidFailToWriteAction): void {
function bleDataDidFailToWrite(action: BleUartDidFailToWriteAction): void {
console.error(action.err);
}
@@ -29,7 +29,7 @@ function bootloaderDidError(action: BootloaderConnectionDidErrorAction): void {
}
export default function* (): Generator {
yield takeEvery(BLEDataActionType.DidFailToWrite, bleDataDidFailToWrite);
yield takeEvery(BleUartActionType.DidFailToWrite, bleDataDidFailToWrite);
yield takeEvery(
BootloaderConnectionActionType.DidFailToConnect,
bootloaderDidFailToConnect,
+12 -12
View File
@@ -4,7 +4,7 @@
import { Ace } from 'ace-builds';
import { mock } from 'jest-mock-extended';
import { AsyncSaga } from '../../test';
import { BLEDataActionType, BLEDataWriteAction, didWrite } from '../actions/ble';
import { BleUartActionType, BleUartWriteAction, didWrite } from '../actions/ble-uart';
import {
HubMessageActionType,
HubRuntimeStatusMessageAction,
@@ -42,23 +42,23 @@ describe('downloadAndRun', () => {
// first message is the length
const writeAction = await saga.take();
expect(writeAction.type).toBe(BLEDataActionType.Write);
expect((writeAction as BLEDataWriteAction).value.length).toBe(4);
saga.put(didWrite((writeAction as BLEDataWriteAction).id));
expect(writeAction.type).toBe(BleUartActionType.Write);
expect((writeAction as BleUartWriteAction).value.length).toBe(4);
saga.put(didWrite((writeAction as BleUartWriteAction).id));
saga.put(checksum(30));
// then the first chunk of 20 bytes
const writeAction2 = await saga.take();
expect(writeAction2.type).toBe(BLEDataActionType.Write);
expect((writeAction2 as BLEDataWriteAction).value.length).toBe(20);
saga.put(didWrite((writeAction2 as BLEDataWriteAction).id));
expect(writeAction2.type).toBe(BleUartActionType.Write);
expect((writeAction2 as BleUartWriteAction).value.length).toBe(20);
saga.put(didWrite((writeAction2 as BleUartWriteAction).id));
saga.put(checksum(0));
// then last chunk
const writeAction3 = await saga.take();
expect(writeAction3.type).toBe(BLEDataActionType.Write);
expect((writeAction3 as BLEDataWriteAction).value.length).toBe(10);
saga.put(didWrite((writeAction3 as BLEDataWriteAction).id));
expect(writeAction3.type).toBe(BleUartActionType.Write);
expect((writeAction3 as BleUartWriteAction).value.length).toBe(10);
saga.put(didWrite((writeAction3 as BleUartWriteAction).id));
saga.put(checksum(0));
// Then a status message saying that we are done
@@ -80,7 +80,7 @@ test('repl', async () => {
saga.put(repl());
const compileAction = await saga.take();
expect(compileAction.type).toBe(BLEDataActionType.Write);
expect(compileAction.type).toBe(BleUartActionType.Write);
await saga.end();
});
@@ -91,7 +91,7 @@ test('stop', async () => {
saga.put(stop());
const compileAction = await saga.take();
expect(compileAction.type).toBe(BLEDataActionType.Write);
expect(compileAction.type).toBe(BleUartActionType.Write);
await saga.end();
});
+13 -13
View File
@@ -15,12 +15,12 @@ import {
} from 'redux-saga/effects';
import { Action } from '../actions';
import {
BLEDataActionType,
BLEDataDidFailToWriteAction,
BLEDataDidWriteAction,
BLEDataWriteAction,
BleUartActionType,
BleUartDidFailToWriteAction,
BleUartDidWriteAction,
BleUartWriteAction,
write,
} from '../actions/ble';
} from '../actions/ble-uart';
import {
HubActionType,
HubChecksumMessageAction,
@@ -44,8 +44,8 @@ const downloadChunkSize = 100;
function waitForWrite(id: number): RaceEffect<TakeEffect> {
return race([
take((a: Action) => a.type === BLEDataActionType.DidWrite && a.id === id),
take((a: Action) => a.type === BLEDataActionType.DidFailToWrite && a.id === id),
take((a: Action) => a.type === BleUartActionType.DidWrite && a.id === id),
take((a: Action) => a.type === BleUartActionType.DidFailToWrite && a.id === id),
]);
}
@@ -82,10 +82,10 @@ function* downloadAndRun(_action: HubDownloadAndRunAction): Generator {
const sizeBuf = new Uint8Array(4);
const sizeView = new DataView(sizeBuf.buffer);
sizeView.setUint32(0, mpy.data.byteLength, true);
const writeAction = (yield put(write(sizeBuf))) as BLEDataWriteAction;
const writeAction = (yield put(write(sizeBuf))) as BleUartWriteAction;
const [, didFailToWrite] = (yield waitForWrite(writeAction.id)) as [
BLEDataDidWriteAction,
BLEDataDidFailToWriteAction,
BleUartDidWriteAction,
BleUartDidFailToWriteAction,
];
if (didFailToWrite) {
@@ -112,10 +112,10 @@ function* downloadAndRun(_action: HubDownloadAndRunAction): Generator {
for (let j = 0; j < chunk.length; j += 20) {
const writeAction = (yield put(
write(chunk.slice(j, j + 20)),
)) as BLEDataWriteAction;
)) as BleUartWriteAction;
const [, didFailToWrite] = (yield waitForWrite(writeAction.id)) as [
BLEDataDidWriteAction,
BLEDataDidFailToWriteAction,
BleUartDidWriteAction,
BleUartDidFailToWriteAction,
];
if (didFailToWrite) {
+25 -25
View File
@@ -4,12 +4,12 @@
import { AsyncSaga, delay } from '../../test';
import {
BLEDataActionType,
BLEDataWriteAction,
BleUartActionType,
BleUartWriteAction,
didFailToWrite,
didWrite,
notify,
} from '../actions/ble';
} from '../actions/ble-uart';
import {
HubChecksumMessageAction,
HubMessageActionType,
@@ -351,8 +351,8 @@ describe('Terminal data source responds to receive data actions', () => {
saga.put(receiveData('test1234'));
const action = await saga.take();
expect(action.type).toBe(BLEDataActionType.Write);
expect((action as BLEDataWriteAction).value).toEqual(expected);
expect(action.type).toBe(BleUartActionType.Write);
expect((action as BleUartWriteAction).value).toEqual(expected);
await saga.end();
});
@@ -372,19 +372,19 @@ describe('Terminal data source responds to receive data actions', () => {
expect(saga.numPending()).toBe(1);
const action = await saga.take();
expect(action.type).toBe(BLEDataActionType.Write);
expect((action as BLEDataWriteAction).value).toEqual(expected);
expect(action.type).toBe(BleUartActionType.Write);
expect((action as BleUartWriteAction).value).toEqual(expected);
// second message is queued until didWrite or didFailToWrite
expect(saga.numPending()).toBe(0);
saga.put(didWrite((action as BLEDataWriteAction).id));
saga.put(didWrite((action as BleUartWriteAction).id));
const action2 = await saga.take();
expect(action2.type).toBe(BLEDataActionType.Write);
expect((action2 as BLEDataWriteAction).value).toEqual(expected);
expect(action2.type).toBe(BleUartActionType.Write);
expect((action2 as BleUartWriteAction).value).toEqual(expected);
saga.put(didWrite((action2 as BLEDataWriteAction).id));
saga.put(didWrite((action2 as BleUartWriteAction).id));
await saga.end();
});
@@ -404,21 +404,21 @@ describe('Terminal data source responds to receive data actions', () => {
expect(saga.numPending()).toBe(1);
const action = await saga.take();
expect(action.type).toBe(BLEDataActionType.Write);
expect((action as BLEDataWriteAction).value).toEqual(expected);
expect(action.type).toBe(BleUartActionType.Write);
expect((action as BleUartWriteAction).value).toEqual(expected);
// second message is queued until didWrite or didFailToWrite
expect(saga.numPending()).toBe(0);
saga.put(
didFailToWrite((action as BLEDataWriteAction).id, new Error('test error')),
didFailToWrite((action as BleUartWriteAction).id, new Error('test error')),
);
const action2 = await saga.take();
expect(action2.type).toBe(BLEDataActionType.Write);
expect((action2 as BLEDataWriteAction).value).toEqual(expected);
expect(action2.type).toBe(BleUartActionType.Write);
expect((action2 as BleUartWriteAction).value).toEqual(expected);
saga.put(didWrite((action2 as BLEDataWriteAction).id));
saga.put(didWrite((action2 as BleUartWriteAction).id));
await saga.end();
});
@@ -434,8 +434,8 @@ describe('Terminal data source responds to receive data actions', () => {
saga.put(receiveData('test1234'));
const action = await saga.take();
expect(action.type).toBe(BLEDataActionType.Write);
expect((action as BLEDataWriteAction).value).toEqual(
expect(action.type).toBe(BleUartActionType.Write);
expect((action as BleUartWriteAction).value).toEqual(
new Uint8Array([...expected, ...expected]),
);
@@ -452,16 +452,16 @@ describe('Terminal data source responds to receive data actions', () => {
saga.put(receiveData('012345678901234567890123456789'));
const action = await saga.take();
expect(action.type).toBe(BLEDataActionType.Write);
expect((action as BLEDataWriteAction).value.length).toEqual(20);
expect(action.type).toBe(BleUartActionType.Write);
expect((action as BleUartWriteAction).value.length).toEqual(20);
saga.put(didWrite((action as BLEDataWriteAction).id));
saga.put(didWrite((action as BleUartWriteAction).id));
const action2 = await saga.take();
expect(action2.type).toBe(BLEDataActionType.Write);
expect((action2 as BLEDataWriteAction).value.length).toEqual(10);
expect(action2.type).toBe(BleUartActionType.Write);
expect((action2 as BleUartWriteAction).value.length).toEqual(10);
saga.put(didWrite((action2 as BLEDataWriteAction).id));
saga.put(didWrite((action2 as BleUartWriteAction).id));
await saga.end();
});
+10 -10
View File
@@ -15,11 +15,11 @@ import {
import PushStream from 'zen-push';
import { Action } from '../actions';
import {
BLEDataActionType,
BLEDataNotifyAction,
BLEDataWriteAction,
BleUartActionType,
BleUartNotifyAction,
BleUartWriteAction,
write,
} from '../actions/ble';
} from '../actions/ble-uart';
import { HubRuntimeStatusType, checksum, updateStatus } from '../actions/hub';
import {
TerminalActionType,
@@ -55,7 +55,7 @@ function* handleMatch(
return true;
}
function* receiveUartData(action: BLEDataNotifyAction): Generator {
function* receiveUartData(action: BleUartNotifyAction): Generator {
const hubState = (yield select((s: RootState) => s.hub.runtime)) as HubRuntimeState;
if (hubState === HubRuntimeState.Loading && action.value.buffer.byteLength === 1) {
@@ -119,17 +119,17 @@ function* receiveTerminalData(): Generator {
for (let i = 0; i < data.length; i += 20) {
const { id } = (yield put(
write(data.slice(i, i + 20)),
)) as BLEDataWriteAction;
)) as BleUartWriteAction;
yield take(
(a: Action) =>
(a.type === BLEDataActionType.DidWrite ||
a.type === BLEDataActionType.DidFailToWrite) &&
(a.type === BleUartActionType.DidWrite ||
a.type === BleUartActionType.DidFailToWrite) &&
a.id === id,
);
// wait for echo so tht we don't overrun the hub with messages
yield race([take(BLEDataActionType.Notify), delay(100)]);
yield race([take(BleUartActionType.Notify), delay(100)]);
}
}
}
@@ -140,7 +140,7 @@ function sendTerminalData(action: TerminalDataReceiveDataAction): void {
}
export default function* (): Generator {
yield takeEvery(BLEDataActionType.Notify, receiveUartData);
yield takeEvery(BleUartActionType.Notify, receiveUartData);
yield fork(receiveTerminalData);
yield takeEvery(TerminalActionType.SendData, sendTerminalData);
yield put(setDataSource(terminalDataSource.observable));
+6 -4
View File
@@ -5,15 +5,17 @@ import { Action, Dispatch } from '../actions';
import {
BLEActionType,
BLEConnectActionType,
BLEDataActionType,
connect as connectAction,
didConnect,
didDisconnect,
disconnect as disconnectAction,
} from '../actions/ble';
import {
BleUartActionType,
didFailToWrite,
didWrite,
disconnect as disconnectAction,
notify,
} from '../actions/ble';
} from '../actions/ble-uart';
import { stop } from '../actions/hub';
import * as notification from '../actions/notification';
import { RootState } from '../reducers';
@@ -118,7 +120,7 @@ function disconnect(action: Action): void {
}
async function write(action: Action, dispatch: Dispatch): Promise<void> {
if (action.type !== BLEDataActionType.Write) {
if (action.type !== BleUartActionType.Write) {
return;
}
try {