From 7bd7d3ce6da4752df3ed2a08dcb0a83d06b8c2f4 Mon Sep 17 00:00:00 2001 From: Nathan Kellenicki Date: Fri, 2 Oct 2020 10:14:00 -0700 Subject: [PATCH] Mario support --- src/consts.ts | 46 ++++++++++++++++++++- src/devices/mariobarcodesensor.ts | 66 +++++++++++++++++++++++++++++++ src/devices/mariopantssensor.ts | 42 ++++++++++++++++++++ src/hubs/basehub.ts | 6 ++- src/hubs/mario.ts | 50 +++++++++++++++++++++++ src/index-browser.ts | 2 + src/index-node.ts | 2 + src/poweredup-browser.ts | 4 ++ src/poweredup-node.ts | 3 ++ 9 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 src/devices/mariobarcodesensor.ts create mode 100644 src/devices/mariopantssensor.ts create mode 100644 src/hubs/mario.ts diff --git a/src/consts.ts b/src/consts.ts index fe9de7a..7d8c025 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -7,6 +7,7 @@ * @property {number} POWERED_UP_REMOTE 4 * @property {number} DUPLO_TRAIN_HUB 5 * @property {number} CONTROL_PLUS_HUB 6 + * @property {number} MARIO 7 */ export enum HubType { UNKNOWN = 0, @@ -15,7 +16,8 @@ export enum HubType { HUB = 3, REMOTE_CONTROL = 4, DUPLO_TRAIN_BASE = 5, - TECHNIC_MEDIUM_HUB = 6 + TECHNIC_MEDIUM_HUB = 6, + MARIO = 7, } @@ -83,6 +85,8 @@ export enum DeviceType { TECHNIC_COLOR_SENSOR = 61, // Spike Prime TECHNIC_DISTANCE_SENSOR = 62, // Spike Prime TECHNIC_FORCE_SENSOR = 63, // Spike Prime + MARIO_BARCODE_SENSOR = 73, + MARIO_PANTS_SENSOR = 74, TECHNIC_MEDIUM_ANGULAR_MOTOR_GREY = 75, // Technic Control+ TECHNIC_LARGE_ANGULAR_MOTOR_GREY = 76, // Technic Control+ } @@ -178,6 +182,7 @@ export enum BLEManufacturerData { MOVE_HUB_ID = 64, HUB_ID = 65, REMOTE_CONTROL_ID = 66, + MARIO_ID = 67, TECHNIC_MEDIUM_HUB = 128 } @@ -636,4 +641,43 @@ export enum PortInputFormatSetupSubCommand { } +/** + * @typedef MarioPantsType + * @param {number} NONE 0x00 + * @param {number} PROPELLER 0x06 + * @param {number} CAT 0x11 + * @param {number} FIRE 0x12 + * @param {number} NORMAL 0x21 + * @param {number} BUILDER 0x22 + */ +export enum MarioPantsType { + NONE = 0x00, + PROPELLER = 0x06, + CAT = 0x11, + FIRE = 0x12, + NORMAL = 0x21, + BUILDER = 0x22, +} + +/** + * @typedef MarioColor + * @param {number} WHITE 0x1300 + * @param {number} RED 0x1500 + * @param {number} BLUE 0x1700 + * @param {number} YELLOW 0x1800 + * @param {number} BLACK 0x1a00 + * @param {number} GREEN 0x2500 + * @param {number} BROWN 0x6a00 + * @param {number} CYAN 0x4201 + */ +export enum MarioColor { + WHITE = 0x1300, + RED = 0x1500, + BLUE = 0x1700, + YELLOW = 0x1800, + BLACK = 0x1a00, + GREEN = 0x2500, + BROWN = 0x6a00, + CYAN = 0x4201, +} diff --git a/src/devices/mariobarcodesensor.ts b/src/devices/mariobarcodesensor.ts new file mode 100644 index 0000000..31bae31 --- /dev/null +++ b/src/devices/mariobarcodesensor.ts @@ -0,0 +1,66 @@ +import { Device } from "./device"; + +import { IDeviceInterface } from "../interfaces"; + +import * as Consts from "../consts"; + +/** + * @class MarioBarcodeSensor + * @extends Device + */ +export class MarioBarcodeSensor extends Device { + + constructor (hub: IDeviceInterface, portId: number) { + super(hub, portId, ModeMap, Consts.DeviceType.MARIO_BARCODE_SENSOR); + } + + public receive (message: Buffer) { + const mode = this._mode; + + switch (mode) { + case Mode.BARCODE: + /** + * Emits when the barcode sensor sees a barcode. + * @event MarioBarcodeSensor#barcode + * @type {object} + * @param {number} id + */ + const barcode = message.readUInt16LE(4); + const color = message.readUInt16LE(6); + if (color === 0xffff) { + // This is a barcode + this.notify("barcode", { barcode }); + } else if (barcode === 0xffff) { + // This is a color + this.notify("barcode", { color }); + } + break; + case Mode.RGB: + /** + * Emits when the barcode sensor sees a RGB color. + * @event MarioBarcodeSensor#rgb + * @type {object} + * @param {number} r + * @param {number} g + * @param {number} b + */ + const r = message[4]; + const g = message[5]; + const b = message[6]; + this.notify("rgb", { r, g, b }); + break; + + } + } + +} + +export enum Mode { + BARCODE = 0x00, + RGB = 0x01, +} + +export const ModeMap: {[event: string]: number} = { + "barcode": Mode.BARCODE, + "rgb": Mode.RGB, +}; diff --git a/src/devices/mariopantssensor.ts b/src/devices/mariopantssensor.ts new file mode 100644 index 0000000..b90e384 --- /dev/null +++ b/src/devices/mariopantssensor.ts @@ -0,0 +1,42 @@ +import { Device } from "./device"; + +import { IDeviceInterface } from "../interfaces"; + +import * as Consts from "../consts"; + +/** + * @class MarioPantsSensor + * @extends Device + */ +export class MarioPantsSensor extends Device { + + constructor (hub: IDeviceInterface, portId: number) { + super(hub, portId, ModeMap, Consts.DeviceType.MARIO_PANTS_SENSOR); + } + + public receive (message: Buffer) { + const mode = this._mode; + + switch (mode) { + case Mode.PANTS: + /** + * Emits when the user changes the pants on Mario. + * @event MarioPantsSensor#pants + * @type {object} + * @param {number} pants + */ + const pants = message[4]; + this.notify("pants", { pants }); + break; + } + } + +} + +export enum Mode { + PANTS = 0x00, +} + +export const ModeMap: {[event: string]: number} = { + "pants": Mode.PANTS, +}; diff --git a/src/hubs/basehub.ts b/src/hubs/basehub.ts index a6c06b1..418e99a 100644 --- a/src/hubs/basehub.ts +++ b/src/hubs/basehub.ts @@ -13,6 +13,8 @@ import { DuploTrainBaseSpeedometer } from "../devices/duplotrainbasespeedometer" import { HubLED } from "../devices/hubled"; import { Light } from "../devices/light"; +import { MarioBarcodeSensor } from "../devices/mariobarcodesensor"; +import { MarioPantsSensor } from "../devices/mariopantssensor"; import { MediumLinearMotor } from "../devices/mediumlinearmotor"; import { MotionSensor } from "../devices/motionsensor"; import { MoveHubMediumLinearMotor } from "../devices/movehubmediumlinearmotor"; @@ -416,7 +418,9 @@ export class BaseHub extends EventEmitter { [Consts.DeviceType.DUPLO_TRAIN_BASE_COLOR_SENSOR]: DuploTrainBaseColorSensor, [Consts.DeviceType.DUPLO_TRAIN_BASE_MOTOR]: DuploTrainBaseMotor, [Consts.DeviceType.DUPLO_TRAIN_BASE_SPEAKER]: DuploTrainBaseSpeaker, - [Consts.DeviceType.DUPLO_TRAIN_BASE_SPEEDOMETER]: DuploTrainBaseSpeedometer + [Consts.DeviceType.DUPLO_TRAIN_BASE_SPEEDOMETER]: DuploTrainBaseSpeedometer, + [Consts.DeviceType.MARIO_BARCODE_SENSOR]: MarioBarcodeSensor, + [Consts.DeviceType.MARIO_PANTS_SENSOR]: MarioPantsSensor, }; constructor = deviceConstructors[deviceType as Consts.DeviceType]; diff --git a/src/hubs/mario.ts b/src/hubs/mario.ts new file mode 100644 index 0000000..5f5f512 --- /dev/null +++ b/src/hubs/mario.ts @@ -0,0 +1,50 @@ +import { Peripheral } from "@abandonware/noble"; +import compareVersion from "compare-versions"; + +import { IBLEAbstraction } from "../interfaces"; + +import { LPF2Hub } from "./lpf2hub"; + +import * as Consts from "../consts"; + +import Debug = require("debug"); +const debug = Debug("movehub"); + + +/** + * Mario is emitted if the discovered device is a LEGO Super Mario brick. + * @class Mario + * @extends LPF2Hub + * @extends BaseHub + */ +export class Mario extends LPF2Hub { + + + public static IsMario (peripheral: Peripheral) { + return ( + peripheral.advertisement && + peripheral.advertisement.serviceUuids && + peripheral.advertisement.serviceUuids.indexOf(Consts.BLEService.LPF2_HUB.replace(/-/g, "")) >= 0 && + peripheral.advertisement.manufacturerData && + peripheral.advertisement.manufacturerData.length > 3 && + peripheral.advertisement.manufacturerData[3] === Consts.BLEManufacturerData.MARIO_ID + ); + } + + constructor (device: IBLEAbstraction) { + super(device, PortMap, Consts.HubType.MOVE_HUB); + debug("Discovered Mario"); + } + + + public async connect () { + debug("Connecting to Mario"); + await super.connect(); + debug("Connect completed"); + } + + +} + +export const PortMap: {[portName: string]: number} = { +}; diff --git a/src/index-browser.ts b/src/index-browser.ts index 551b82d..516bc5a 100644 --- a/src/index-browser.ts +++ b/src/index-browser.ts @@ -5,6 +5,7 @@ import { PoweredUP } from "./poweredup-browser"; import { BaseHub } from "./hubs/basehub"; import { DuploTrainBase } from "./hubs/duplotrainbase"; import { Hub } from "./hubs/hub"; +import { Mario } from "./hubs/mario"; import { MoveHub } from "./hubs/movehub"; import { RemoteControl } from "./hubs/remotecontrol"; import { TechnicMediumHub } from "./hubs/technicmediumhub"; @@ -63,6 +64,7 @@ window.PoweredUP = { DuploTrainBaseSpeedometer, HubLED, Light, + Mario, MediumLinearMotor, MotionSensor, MoveHub, diff --git a/src/index-node.ts b/src/index-node.ts index 2f4cec7..f776512 100644 --- a/src/index-node.ts +++ b/src/index-node.ts @@ -5,6 +5,7 @@ import { PoweredUP } from "./poweredup-node"; import { BaseHub } from "./hubs/basehub"; import { DuploTrainBase } from "./hubs/duplotrainbase"; import { Hub } from "./hubs/hub"; +import { Mario } from "./hubs/mario"; import { MoveHub } from "./hubs/movehub"; import { RemoteControl } from "./hubs/remotecontrol"; import { TechnicMediumHub } from "./hubs/technicmediumhub"; @@ -63,6 +64,7 @@ export { DuploTrainBaseSpeedometer, HubLED, Light, + Mario, MediumLinearMotor, MotionSensor, MoveHub, diff --git a/src/poweredup-browser.ts b/src/poweredup-browser.ts index 779f7ac..5afab27 100644 --- a/src/poweredup-browser.ts +++ b/src/poweredup-browser.ts @@ -3,6 +3,7 @@ import { WebBLEDevice } from "./webbleabstraction"; import { BaseHub } from "./hubs/basehub"; import { DuploTrainBase } from "./hubs/duplotrainbase"; import { Hub } from "./hubs/hub"; +import { Mario } from "./hubs/mario"; import { MoveHub } from "./hubs/movehub"; import { RemoteControl } from "./hubs/remotecontrol"; import { TechnicMediumHub } from "./hubs/technicmediumhub"; @@ -210,6 +211,9 @@ export class PoweredUP extends EventEmitter { case Consts.HubType.TECHNIC_MEDIUM_HUB: hub = new TechnicMediumHub(device); break; + case Consts.HubType.MARIO: + hub = new Mario(device); + break; default: return; } diff --git a/src/poweredup-node.ts b/src/poweredup-node.ts index 57aa53c..f1f8870 100644 --- a/src/poweredup-node.ts +++ b/src/poweredup-node.ts @@ -5,6 +5,7 @@ import { NobleDevice } from "./nobleabstraction"; import { BaseHub } from "./hubs/basehub"; import { DuploTrainBase } from "./hubs/duplotrainbase"; import { Hub } from "./hubs/hub"; +import { Mario } from "./hubs/mario"; import { MoveHub } from "./hubs/movehub"; import { RemoteControl } from "./hubs/remotecontrol"; import { TechnicMediumHub } from "./hubs/technicmediumhub"; @@ -169,6 +170,8 @@ export class PoweredUP extends EventEmitter { hub = new DuploTrainBase(device); } else if (TechnicMediumHub.IsTechnicMediumHub(peripheral)) { hub = new TechnicMediumHub(device); + } else if (Mario.IsMario(peripheral)) { + hub = new Mario(device); } else { return; }