Skip to content

Commit

Permalink
Add TwoPortHandset (#119)
Browse files Browse the repository at this point in the history
#96 non-breaking
  • Loading branch information
rickjansen-dev committed Oct 27, 2020
1 parent 261f44b commit 0c1cd4c
Show file tree
Hide file tree
Showing 12 changed files with 312 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ DI Container Elements
- [X] Actions
- [X] Create Virtual Ports
- [X] Two Port Hub (88009)
- [X] Two Port Handset (88010)
- [X] Technic Medium Hub (88012)
- .. other hubs depend on availability of hardware / contributions
- Devices
Expand All @@ -261,6 +262,8 @@ DI Container Elements
- [X] Hub (88009) - Current
- [X] Hub (88009) - Voltage
- [X] Medium Linear Motor (88008)
- [X] Remote Control Button (88010)
- [X] Remote Control RSSI (88010)
- [X] Train Motor (88011)
- [X] Technic Large Motor (88013)
- [X] Technic XLarge Motor (88014)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using System.Threading.Tasks;
using System.Reactive.Linq;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using SharpBrick.PoweredUp;

namespace Example
{
public class ExampleRemoteControlButton : BaseExample
{
public override async Task ExecuteAsync()
{
using (var twoPortHandset = Host.FindByType<TwoPortHandset>())
{
var device = twoPortHandset.A;

await device.SetupNotificationAsync(device.ModeIndexBitField, true, deltaInterval: 1);

await twoPortHandset.RgbLight.SetRgbColorsAsync(0xFF, 0x00, 0x00);

Log.LogInformation("Press the '+' button on port A (left)");

await device.PlusObservable.Any(x => x);

Log.LogInformation("Thanks! Now press the 'red' button on port A (left)");

await device.RedObservable.Any(x => x);

Log.LogInformation("Thanks! Now press the '-' button on port A (left)");

await device.MinusObservable.Any(x => x);

Log.LogInformation("Thanks! Now press the '+' and '-' buttons on port A (left) at the same time");

await device.ButtonsObservable.Any(x => x.Minus && x.Plus);

var disposable = device.ButtonsObservable.Subscribe(x => Log.LogWarning($"Buttons: {x.Plus} - {x.Stop} - {x.Minus}"));
var disposable2 = device.PlusObservable.Subscribe(x => Log.LogWarning($"Plus: {x}"));
var disposable3 = device.RedObservable.Subscribe(x => Log.LogWarning($"Red: {x}"));
var disposable4 = device.MinusObservable.Subscribe(x => Log.LogWarning($"Minus: {x}"));

Log.LogInformation("Thanks! You now have 20 seconds to press any button combinations");

await Task.Delay(20_000);

disposable.Dispose();
disposable2.Dispose();
disposable3.Dispose();
disposable4.Dispose();

await twoPortHandset.SwitchOffAsync();
}
}
}
}
34 changes: 34 additions & 0 deletions examples/SharpBrick.PoweredUp.Examples/ExampleRemoteControlRssi.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Threading.Tasks;
using System.Reactive.Linq;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using SharpBrick.PoweredUp;

namespace Example
{
public class ExampleRemoteControlRssi : BaseExample
{
public override async Task ExecuteAsync()
{
using (var twoPortHandset = Host.FindByType<TwoPortHandset>())
{
var device = twoPortHandset.RemoteControlRssi;

await device.SetupNotificationAsync(device.ModeIndexRssi, true, deltaInterval: 1);

var disposable = device.RssiObservable.Subscribe(x => Log.LogWarning($"RSSI: {x}"));

await twoPortHandset.RgbLight.SetRgbColorsAsync(0x00, 0xFF, 0x00);

Log.LogInformation("Watching RSSI changes for the next 20 seconds");

await Task.Delay(20_000);

disposable.Dispose();

await twoPortHandset.SwitchOffAsync();
}
}
}
}
3 changes: 3 additions & 0 deletions examples/SharpBrick.PoweredUp.Examples/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ static async Task Main(string[] args)
//example = new Example.ExampleDiscoverByType();
//example = new Example.ExampleCalibrationSteering();
//example = new Example.ExampleTechnicMediumHubGestSensor();
//example = new Example.ExampleRemoteControlButton();
//example = new Example.ExampleRemoteControlRssi();

example = new Example.ExampleTechnicMediumAngularMotorGrey();

// NOTE: Examples are programmed object oriented style. Base class implements methods Configure, DiscoverAsync and ExecuteAsync to be overwriten on demand.
Expand Down
4 changes: 4 additions & 0 deletions src/SharpBrick.PoweredUp/Devices/DeviceFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public Type GetTypeFromDeviceType(DeviceType deviceType)
DeviceType.TechnicMediumAngularMotorGrey => typeof(TechnicMediumAngularMotorGrey),
DeviceType.TechnicLargeAngularMotorGrey => typeof(TechnicLargeAngularMotorGrey),
DeviceType.TechnicMediumHubGestureSensor => typeof(TechnicMediumHubGestureSensor),
DeviceType.RemoteControlButton => typeof(RemoteControlButton),
DeviceType.RemoteControlRssi => typeof(RemoteControlRssi),
DeviceType.TechnicMediumHubAccelerometer => typeof(TechnicMediumHubAccelerometer),
DeviceType.TechnicMediumHubGyroSensor => typeof(TechnicMediumHubGyroSensor),
DeviceType.TechnicMediumHubTiltSensor => typeof(TechnicMediumHubTiltSensor),
Expand All @@ -59,6 +61,8 @@ public static DeviceType GetDeviceTypeFromType(Type type)
nameof(TechnicMediumAngularMotorGrey) => DeviceType.TechnicMediumAngularMotorGrey,
nameof(TechnicLargeAngularMotorGrey) => DeviceType.TechnicLargeAngularMotorGrey,
nameof(TechnicMediumHubGestureSensor) => DeviceType.TechnicMediumHubGestureSensor,
nameof(RemoteControlButton) => DeviceType.RemoteControlButton,
nameof(RemoteControlRssi) => DeviceType.RemoteControlRssi,
nameof(TechnicMediumHubAccelerometer) => DeviceType.TechnicMediumHubAccelerometer,
nameof(TechnicMediumHubGyroSensor) => DeviceType.TechnicMediumHubGyroSensor,
nameof(TechnicMediumHubTiltSensor) => DeviceType.TechnicMediumHubTiltSensor,
Expand Down
85 changes: 85 additions & 0 deletions src/SharpBrick.PoweredUp/Devices/RemoteControlButton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using SharpBrick.PoweredUp.Protocol;
using SharpBrick.PoweredUp.Utils;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;

namespace SharpBrick.PoweredUp.Devices
{
public class RemoteControlButton : Device, IPoweredUpDevice
{
protected sbyte PlusBitMask = 0b0000_0001;
protected sbyte RedBitMask = 0b0000_0010;
protected sbyte MinusBitMask = 0b0000_0100;

protected SingleValueMode<sbyte> _keyBitFieldMode;
public byte ModeIndexBitField { get; protected set; } = 3;

public bool Plus => IsBitMaskSet(_keyBitFieldMode.SI, PlusBitMask);
public bool Red => IsBitMaskSet(_keyBitFieldMode.SI, RedBitMask);
public bool Minus => IsBitMaskSet(_keyBitFieldMode.SI, MinusBitMask);

public IObservable<(bool Plus, bool Stop, bool Minus)> ButtonsObservable => _keyBitFieldMode.Observable.Select(v => (IsBitMaskSet(_keyBitFieldMode.SI, PlusBitMask), IsBitMaskSet(_keyBitFieldMode.SI, RedBitMask), IsBitMaskSet(_keyBitFieldMode.SI, MinusBitMask)));
public IObservable<bool> PlusObservable => _keyBitFieldMode.Observable.Select(v => IsBitMaskSet(_keyBitFieldMode.SI, PlusBitMask)).DistinctUntilChanged();
public IObservable<bool> RedObservable => _keyBitFieldMode.Observable.Select(v => IsBitMaskSet(_keyBitFieldMode.SI, RedBitMask)).DistinctUntilChanged();
public IObservable<bool> MinusObservable => _keyBitFieldMode.Observable.Select(v => IsBitMaskSet(_keyBitFieldMode.SI, MinusBitMask)).DistinctUntilChanged();

public RemoteControlButton()
{ }

public RemoteControlButton(ILegoWirelessProtocol protocol, byte hubId, byte portId)
: base(protocol, hubId, portId)
{
_keyBitFieldMode = SingleValueMode<sbyte>(ModeIndexBitField);

ObserveForPropertyChanged(PlusObservable, nameof(Plus));
ObserveForPropertyChanged(RedObservable, nameof(Red));
ObserveForPropertyChanged(MinusObservable, nameof(Minus));
}

public IEnumerable<byte[]> GetStaticPortInfoMessages(Version softwareVersion, Version hardwareVersion, SystemType systemType)
=> @"
0B-00-43-00-01-02-05-1F-00-00-00
0C-00-44-00-00-00-52-43-4B-45-59-00
0E-00-44-00-00-01-00-00-80-BF-00-00-80-3F
0E-00-44-00-00-02-00-00-C8-C2-00-00-C8-42
0E-00-44-00-00-03-00-00-80-BF-00-00-80-3F
0A-00-44-00-00-04-62-74-6E-00
08-00-44-00-00-05-18-00
0A-00-44-00-00-80-01-00-02-00
0C-00-44-00-01-00-4B-45-59-41-20-00
0E-00-44-00-01-01-00-00-80-BF-00-00-80-3F
0E-00-44-00-01-02-00-00-C8-C2-00-00-C8-42
0E-00-44-00-01-03-00-00-80-BF-00-00-80-3F
0A-00-44-00-01-04-62-74-6E-00
08-00-44-00-01-05-70-00
0A-00-44-00-01-80-01-00-02-00
0C-00-44-00-02-00-4B-45-59-52-20-00
0E-00-44-00-02-01-00-00-80-BF-00-00-80-3F
0E-00-44-00-02-02-00-00-C8-C2-00-00-C8-42
0E-00-44-00-02-03-00-00-80-BF-00-00-80-3F
0A-00-44-00-02-04-62-74-6E-00
08-00-44-00-02-05-68-00
0A-00-44-00-02-80-01-00-02-00
0C-00-44-00-03-00-4B-45-59-44-20-00
0E-00-44-00-03-01-00-00-00-00-00-00-E0-40
0E-00-44-00-03-02-00-00-00-00-00-00-C8-42
0E-00-44-00-03-03-00-00-00-00-00-00-E0-40
0A-00-44-00-03-04-62-74-6E-00
08-00-44-00-03-05-04-00
0A-00-44-00-03-80-01-00-01-00
0C-00-44-00-04-00-4B-45-59-53-44-00
0E-00-44-00-04-01-00-00-00-00-00-00-80-3F
0E-00-44-00-04-02-00-00-00-00-00-00-C8-42
0E-00-44-00-04-03-00-00-00-00-00-00-80-3F
0A-00-44-00-04-04-62-74-6E-00
08-00-44-00-04-05-04-00
0A-00-44-00-04-80-03-00-01-00
".Trim().Split("\n").Select(s => BytesStringUtil.StringToData(s));

protected bool IsBitMaskSet(sbyte bitField, sbyte bitMask)
=> (bitField & bitMask) != 0;
}
}
42 changes: 42 additions & 0 deletions src/SharpBrick.PoweredUp/Devices/RemoteControlRssi.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using SharpBrick.PoweredUp.Protocol;
using SharpBrick.PoweredUp.Utils;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;

namespace SharpBrick.PoweredUp.Devices
{
public class RemoteControlRssi : Device, IPoweredUpDevice
{
protected SingleValueMode<sbyte> _rssiMode;
public byte ModeIndexRssi { get; protected set; } = 0;

public sbyte Rssi => _rssiMode.SI;
public IObservable<sbyte> RssiObservable => _rssiMode.Observable.Select(x => x.SI);

public RemoteControlRssi()
{ }

public RemoteControlRssi(ILegoWirelessProtocol protocol, byte hubId, byte portId)
: base(protocol, hubId, portId)
{
_rssiMode = SingleValueMode<sbyte>(ModeIndexRssi);

ObserveForPropertyChanged(_rssiMode.Observable, nameof(Rssi));
}

public IEnumerable<byte[]> GetStaticPortInfoMessages(Version softwareVersion, Version hardwareVersion, SystemType systemType)
=> @"
0B-00-43-3C-01-02-01-01-00-00-00
0C-00-44-3C-00-00-52-53-53-49-20-00
0E-00-44-3C-00-01-00-00-A0-C2-00-00-F0-C1
0E-00-44-3C-00-02-00-00-00-00-00-00-C8-42
0E-00-44-3C-00-03-00-00-A0-C2-00-00-F0-C1
0A-00-44-3C-00-04-64-62-6D-00
08-00-44-3C-00-05-50-00
0A-00-44-3C-00-80-01-00-03-00
".Trim().Split("\n").Select(s => BytesStringUtil.StringToData(s));
}
}
18 changes: 18 additions & 0 deletions src/SharpBrick.PoweredUp/Devices/RgbLight.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,24 @@ public IEnumerable<byte[]> GetStaticPortInfoMessages(Version softwareVersion, Ve
0B-00-44-32-01-04-00-00-00-00-00
08-00-44-32-01-05-00-10
0A-00-44-32-01-80-03-00-03-00
",

(_, _, SystemType.LegoSystem_TwoPortHandset) => @"
0B-00-43-34-01-01-02-00-00-03-00
0C-00-44-34-00-00-43-4F-4C-20-30-00
0E-00-44-34-00-01-00-00-00-00-00-00-20-41
0E-00-44-34-00-02-00-00-00-00-00-00-C8-42
0E-00-44-34-00-03-00-00-00-00-00-00-20-41
0A-00-44-34-00-04-69-64-78-00
08-00-44-34-00-05-00-64
0A-00-44-34-00-80-01-00-02-00
0C-00-44-34-01-00-52-47-42-20-30-00
0E-00-44-34-01-01-00-00-00-00-00-00-7F-43
0E-00-44-34-01-02-00-00-00-00-00-00-C8-42
0E-00-44-34-01-03-00-00-00-00-00-00-7F-43
0A-00-44-34-01-04-72-67-62-00
08-00-44-34-01-05-00-50
0A-00-44-34-01-80-03-00-03-00
",
_ => throw new NotSupportedException(),
}).Trim().Split("\n").Select(s => BytesStringUtil.StringToData(s));
Expand Down
18 changes: 18 additions & 0 deletions src/SharpBrick.PoweredUp/Devices/Voltage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,24 @@ public IEnumerable<byte[]> GetStaticPortInfoMessages(Version softwareVersion, Ve
08-00-44-3C-01-05-10-00
0A-00-44-3C-01-80-01-01-04-00
",
(_, _, SystemType.LegoSystem_TwoPortHandset) => @"
0B-00-43-3B-01-02-02-03-00-00-00
0C-00-44-3B-00-00-56-4C-54-20-4C-00
0E-00-44-3B-00-01-00-00-00-00-00-00-48-45
0E-00-44-3B-00-02-00-00-00-00-00-00-C8-42
0E-00-44-3B-00-03-00-00-00-00-00-00-C8-45
0A-00-44-3B-00-04-6D-76-00-00
08-00-44-3B-00-05-10-00
0A-00-44-3B-00-80-01-01-04-00
0C-00-44-3B-01-00-56-4C-54-20-53-00
0E-00-44-3B-01-01-00-00-00-00-00-00-48-45
0E-00-44-3B-01-02-00-00-00-00-00-00-C8-42
0E-00-44-3B-01-03-00-00-00-00-00-00-C8-45
0A-00-44-3B-01-04-6D-76-00-00
08-00-44-3B-01-05-10-00
0A-00-44-3B-01-80-01-01-04-00
",

_ => throw new NotSupportedException(),
}).Trim().Split("\n").Select(s => BytesStringUtil.StringToData(s));
}
Expand Down
2 changes: 2 additions & 0 deletions src/SharpBrick.PoweredUp/Hubs/HubFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public static Type GetTypeFromSystemType(SystemType systemType)
=> systemType switch
{
SystemType.LegoSystem_TwoPortHub => typeof(TwoPortHub),
SystemType.LegoSystem_TwoPortHandset => typeof(TwoPortHandset),
SystemType.LegoTechnic_MediumHub => typeof(TechnicMediumHub),
_ => throw new NotSupportedException(),
};
Expand All @@ -46,6 +47,7 @@ public static SystemType GetSystemTypeFromType(Type type)
=> type.Name switch
{
nameof(TwoPortHub) => SystemType.LegoSystem_TwoPortHub,
nameof(TwoPortHandset) => SystemType.LegoSystem_TwoPortHandset,
nameof(TechnicMediumHub) => SystemType.LegoTechnic_MediumHub,
_ => throw new NotSupportedException(),
};
Expand Down
46 changes: 46 additions & 0 deletions src/SharpBrick.PoweredUp/Hubs/TwoPortHandset.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Microsoft.Extensions.Logging;

using SharpBrick.PoweredUp.Devices;
using SharpBrick.PoweredUp.Protocol;

using System;

namespace SharpBrick.PoweredUp
{
public class TwoPortHandset : Hub
{
public TwoPortHandset(ILegoWirelessProtocol protocol, IDeviceFactory deviceFactory, ILogger<TwoPortHandset> logger, IServiceProvider serviceProvider = default)
: base(protocol, deviceFactory, logger, serviceProvider, SystemType.LegoSystem_TwoPortHandset, new Port[] {
new Port(0, string.Empty, false, expectedDevice: DeviceType.RemoteControlButton),
new Port(1, string.Empty, false, expectedDevice: DeviceType.RemoteControlButton),
new Port(52, string.Empty, false, expectedDevice: DeviceType.RgbLight),
new Port(59, string.Empty, false, expectedDevice: DeviceType.Voltage),
new Port(60, string.Empty, false, expectedDevice: DeviceType.RemoteControlRssi),
},
knownProperties: new HubProperty[] {
HubProperty.AdvertisingName,
HubProperty.Button,
HubProperty.FwVersion,
HubProperty.HwVersion,
HubProperty.Rssi,
HubProperty.BatteryVoltage,
HubProperty.BatteryType,
HubProperty.ManufacturerName,
HubProperty.RadioFirmwareVersion,
HubProperty.LegoWirelessProtocolVersion,
HubProperty.SystemTypeId,
HubProperty.HardwareNetworkId,
HubProperty.PrimaryMacAddress,
//HubProperty.SecondaryMacAddress, // unsupported on the two port handset
HubProperty.HardwareNetworkFamily,
})
{ }

public RemoteControlButton A => Port(0).GetDevice<RemoteControlButton>();
public RemoteControlButton B => Port(1).GetDevice<RemoteControlButton>();

public RgbLight RgbLight => Port(52).GetDevice<RgbLight>();
public Voltage Voltage => Port(59).GetDevice<Voltage>();
public RemoteControlRssi RemoteControlRssi => Port(60).GetDevice<RemoteControlRssi>();
}
}
1 change: 1 addition & 0 deletions src/SharpBrick.PoweredUp/IServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public static IServiceCollection AddPoweredUp(this IServiceCollection self)

// hubs
.AddTransient<TwoPortHub>()
.AddTransient<TwoPortHandset>()
.AddTransient<TechnicMediumHub>()

// functions
Expand Down

0 comments on commit 0c1cd4c

Please sign in to comment.