Skip to content

Commit

Permalink
Add IO Pin and DFU services
Browse files Browse the repository at this point in the history
  • Loading branch information
thegecko committed Jun 18, 2019
1 parent 728f7e6 commit 15426c0
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 28 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ Refer to the [micro:bit Web Bluetooth API Documentation](https://thegecko.github
- [x] Client Event

### IO Pin Service
- [ ] Pin Data
- [ ] Pin Data Changed Event
- [ ] Pin AD Configuration
- [ ] Pin IO Configuration
- [ ] PWM Control
- [x] Pin Data
- [x] Pin Data Changed Event
- [x] Pin AD Configuration
- [x] Pin IO Configuration
- [x] PWM Control

### DFU Control Service
- [ ] DFU Control
- [ ] Partial Flashing
- [x] Request DFU
- [x] Request Flash Code
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ export interface Services {
magnetometerService?: MagnetometerService;
uartService?: UartService;
eventService?: EventService;
dfuControlService?: DfuControlService;
ioPinService?: IoPinService;
}

/**
Expand Down Expand Up @@ -116,6 +118,8 @@ export const getServices = async (device: BluetoothDevice): Promise<Services> =>
const magnetometerService = await builder.createService(MagnetometerService);
const uartService = await builder.createService(UartService);
const eventService = await builder.createService(EventService);
const dfuControlService = await builder.createService(DfuControlService);
const ioPinService = await builder.createService(IoPinService);

return {
deviceInformationService,
Expand All @@ -126,5 +130,7 @@ export const getServices = async (device: BluetoothDevice): Promise<Services> =>
magnetometerService,
uartService,
eventService,
dfuControlService,
ioPinService
};
};
4 changes: 2 additions & 2 deletions src/services/accelerometer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ export class AccelerometerService extends (EventDispatcher as new() => TypedDisp
* Get accelerometer sample period
*/
public async getAccelerometerPeriod(): Promise<AccelerometerPeriod> {
const value = await this.helper.getCharacteristicValue(AccelerometerCharacteristic.accelerometerPeriod);
return value.getUint16(0, true) as AccelerometerPeriod;
const view = await this.helper.getCharacteristicValue(AccelerometerCharacteristic.accelerometerPeriod);
return view.getUint16(0, true) as AccelerometerPeriod;
}

/**
Expand Down
8 changes: 4 additions & 4 deletions src/services/button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,16 +112,16 @@ export class ButtonService extends (EventDispatcher as new() => TypedDispatcher<
* Read state of button A
*/
public async readButtonAState(): Promise<ButtonState> {
const value = await this.helper.getCharacteristicValue(ButtonCharacteristic.buttonAState);
return value.getUint8(0);
const view = await this.helper.getCharacteristicValue(ButtonCharacteristic.buttonAState);
return view.getUint8(0);
}

/**
* Read state of button B
*/
public async readButtonBState(): Promise<ButtonState> {
const value = await this.helper.getCharacteristicValue(ButtonCharacteristic.buttonBState);
return value.getUint8(0);
const view = await this.helper.getCharacteristicValue(ButtonCharacteristic.buttonBState);
return view.getUint8(0);
}

private buttonAStateChangedHandler(event: Event) {
Expand Down
14 changes: 14 additions & 0 deletions src/services/dfu-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,18 @@ export class DfuControlService {
constructor(service: BluetoothRemoteGATTService) {
this.helper = new ServiceHelper(service);
}

/**
* Request device switches to DFU mode
*/
public requestDfu(): Promise<void> {
return this.helper.setCharacteristicValue(DfuCharacteristic.dfuControl, new Uint8Array([1]));
}

/**
* Request flash code
*/
public requestFlashCode(): Promise<void> {
return this.helper.setCharacteristicValue(DfuCharacteristic.dfuControl, new Uint8Array([2]));
}
}
8 changes: 4 additions & 4 deletions src/services/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ export class EventService extends (EventDispatcher as new() => TypedDispatcher<M
* Get micro:bit event requirements
*/
public async getMicrobitRequirements(): Promise<MicrobitEvent> {
const value = await this.helper.getCharacteristicValue(EventCharacteristic.microBitRequirements);
return this.viewToMicrobitEvent(value);
const view = await this.helper.getCharacteristicValue(EventCharacteristic.microBitRequirements);
return this.viewToMicrobitEvent(view);
}

/**
Expand All @@ -130,8 +130,8 @@ export class EventService extends (EventDispatcher as new() => TypedDispatcher<M
* Read micro:bit event
*/
public async readMicrobitEvent(): Promise<MicrobitEvent> {
const value = await this.helper.getCharacteristicValue(EventCharacteristic.microBitEvent);
return this.viewToMicrobitEvent(value);
const view = await this.helper.getCharacteristicValue(EventCharacteristic.microBitEvent);
return this.viewToMicrobitEvent(view);
}

/**
Expand Down
199 changes: 196 additions & 3 deletions src/services/io-pin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/

import { ServiceHelper } from "../service-helper";
import { EventDispatcher, TypedDispatcher } from "../event-dispatcher";

/**
* @hidden
Expand All @@ -35,10 +36,76 @@ export enum IoPinCharacteristic {
pwmControl = "e95dd822-251d-470a-a062-fa1922dfa9a8"
}

/**
* Pin data
*/
export interface PinData {
/**
* Pin number
*/
pin: number;
/**
* Pin value
*/
value: number;
}

/**
* PWM control data
*/
export interface PwmControlData {
/**
* Pin number
*/
pin: number;
/**
* Pin value
*/
value: number;
/**
* Period (in milliseconds)
*/
period: number;
}

/**
* Analogue/Digital Enum
*/
export enum AD {
Digital = 0,
Analogue = 1
}

/**
* Input/Output Enum
*/
export enum IO {
Output = 0,
Input = 1
}

/**
* Events raised by the magnetometer service
*/
export interface IoPinEvents {
/**
* @hidden
*/
newListener: keyof IoPinEvents;
/**
* @hidden
*/
removeListener: keyof IoPinEvents;
/**
* Pin data changed event
*/
pindatachanged: PinData[];
}

/**
* @hidden
*/
export class IoPinService {
export class IoPinService extends (EventDispatcher as new() => TypedDispatcher<IoPinEvents>) {

/**
* @hidden
Expand All @@ -49,7 +116,9 @@ export class IoPinService {
* @hidden
*/
public static async create(service: BluetoothRemoteGATTService): Promise<IoPinService> {
return new IoPinService(service);
const bluetoothService = new IoPinService(service);
await bluetoothService.init();
return bluetoothService;
}

/**
Expand All @@ -61,6 +130,130 @@ export class IoPinService {
* @hidden
*/
constructor(service: BluetoothRemoteGATTService) {
this.helper = new ServiceHelper(service);
super();
this.helper = new ServiceHelper(service, this);
}

private async init() {
await this.helper.handleListener("pindatachanged", IoPinCharacteristic.pinData, this.pinDataChangedHandler.bind(this));
}

/**
* Read pin data
*/
public async readPinData(): Promise<PinData[]> {
const view = await this.helper.getCharacteristicValue(IoPinCharacteristic.pinData);
return this.dataViewToPinData(view);
}

/**
* Write pin data
* @param data The pin data to write
*/
public async writePinData(data: PinData[]): Promise<void> {
const view = this.pinDataToDataView(data);
return this.helper.setCharacteristicValue(IoPinCharacteristic.pinData, view);
}

/**
* Get pin analogue/digital configuration
*/
public async getAdConfiguration(): Promise<AD[]> {
const view = await this.helper.getCharacteristicValue(IoPinCharacteristic.pinAdConfiguration);
return this.dataViewToConfig(view);
}

/**
* Set pin analogue/digital configuration
* @param config The analogue/digital configuration to set
*/
public async setAdConfiguration(config: AD[]): Promise<void> {
const view = this.configToDataView(config);
return this.helper.setCharacteristicValue(IoPinCharacteristic.pinAdConfiguration, view);
}

/**
* Get pin input/output configuration
*/
public async getIoConfiguration(): Promise<IO[]> {
const view = await this.helper.getCharacteristicValue(IoPinCharacteristic.pinIoConfiguration);
return this.dataViewToConfig(view);
}

/**
* Set pin input/output configuration
* @param config The input/output configuration to set
*/
public async setIoConfiguration(config: IO[]): Promise<void> {
const view = this.configToDataView(config);
return this.helper.setCharacteristicValue(IoPinCharacteristic.pinIoConfiguration, view);
}

/**
* Set pin PWM control
* @param data The PWM control data to set
*/
public async setPwmControl(data: PwmControlData): Promise<void> {
const view = this.pwmControlDataToDataView(data);
return this.helper.setCharacteristicValue(IoPinCharacteristic.pwmControl, view);
}

private pinDataChangedHandler(event: Event) {
const view = (event.target as BluetoothRemoteGATTCharacteristic).value!;
const value = this.dataViewToPinData(view);
this.dispatchEvent("pindatachanged", value);
}

private dataViewToPinData(view: DataView): PinData[] {
const data = [];
for (let i = 0; i < view.byteLength; i += 2) {
data.push({
pin: view.getUint8(i),
value: view.getUint8(i + 1)
});
}
return data;
}

private pinDataToDataView(data: PinData[]): DataView {
const view = new DataView(new ArrayBuffer(data.length * 2));
data.forEach((pinData, index) => {
view.setUint8(index * 2, pinData.pin);
view.setUint8(index * 2 + 1, pinData.value);
});
return view;
}

private dataViewToConfig(view: DataView): number[] {
const result: number[] = [];
const value = (view.getUint16(0) << 8) + view.getUint8(2);

for (let i = 0; i < 24; i++) {
result.push(value >> i);
}

return result;
}

private configToDataView(config: number[]): DataView {
const view = new DataView(new ArrayBuffer(3));
let value = 0;

// tslint:disable-next-line:prefer-for-of
for (let i = 0; i < config.length; i++) {
value &= 1 << config[i];
}

view.setUint16(0, value >> 8);
view.setUint8(2, value & 0xff);
return view;
}

private pwmControlDataToDataView(data: PwmControlData): DataView {
const view = new DataView(new ArrayBuffer(7));
view.setUint8(0, data.pin);
view.setUint16(1, data.value);
view.setUint32(3, data.period);
return view;
}
}
4 changes: 2 additions & 2 deletions src/services/led.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ export class LedService {
* Get scrolling delay
*/
public async getScrollingDelay(): Promise<number> {
const value = await this.helper.getCharacteristicValue(LedCharacteristic.scrollingDelay);
return value.getUint16(0, true);
const view = await this.helper.getCharacteristicValue(LedCharacteristic.scrollingDelay);
return view.getUint16(0, true);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/services/magnetometer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ export class MagnetometerService extends (EventDispatcher as new() => TypedDispa
* Get magnetometer sample period
*/
public async getMagnetometerPeriod(): Promise<MagnetometerPeriod> {
const value = await this.helper.getCharacteristicValue(MagnetometerCharacteristic.magnetometerPeriod);
return value.getUint16(0, true) as MagnetometerPeriod;
const view = await this.helper.getCharacteristicValue(MagnetometerCharacteristic.magnetometerPeriod);
return view.getUint16(0, true) as MagnetometerPeriod;
}

/**
Expand Down
8 changes: 4 additions & 4 deletions src/services/temperature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,16 @@ export class TemperatureService extends (EventDispatcher as new() => TypedDispat
* Read temperature
*/
public async readTemperature(): Promise<number> {
const value = await this.helper.getCharacteristicValue(TemperatureCharacteristic.temperature);
return value.getInt8(0);
const view = await this.helper.getCharacteristicValue(TemperatureCharacteristic.temperature);
return view.getInt8(0);
}

/**
* Get temperature sample period
*/
public async getTemperaturePeriod(): Promise<number> {
const value = await this.helper.getCharacteristicValue(TemperatureCharacteristic.temperaturePeriod);
return value.getUint16(0, true);
const view = await this.helper.getCharacteristicValue(TemperatureCharacteristic.temperaturePeriod);
return view.getUint16(0, true);
}

/**
Expand Down

0 comments on commit 15426c0

Please sign in to comment.