From fc63886b6dbb398ec05b45b4a8fbe00513d62a22 Mon Sep 17 00:00:00 2001 From: cornelius munz Date: Mon, 5 Oct 2020 08:13:27 +0200 Subject: [PATCH 01/10] initial commit with MoveHub --- src/SharpBrick.PoweredUp/Hubs/MoveHub.cs | 37 +++++++++++++++++++ .../IServiceCollectionExtensions.cs | 1 + 2 files changed, 38 insertions(+) create mode 100644 src/SharpBrick.PoweredUp/Hubs/MoveHub.cs diff --git a/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs b/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs new file mode 100644 index 0000000..d86b39c --- /dev/null +++ b/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs @@ -0,0 +1,37 @@ +using System; +using Microsoft.Extensions.Logging; +using SharpBrick.PoweredUp.Devices; +using SharpBrick.PoweredUp.Protocol; + +namespace SharpBrick.PoweredUp +{ + public class MoveHub : Hub + { + public MoveHub(ILegoWirelessProtocol protocol, IDeviceFactory deviceFactory, ILogger logger, IServiceProvider serviceProvider = default) + : base(protocol, deviceFactory, logger, serviceProvider, new Port[] { + new Port(0, nameof(A), false, expectedDevice: DeviceType.InternalMotorWithTacho), + new Port(1, nameof(B), false, expectedDevice: DeviceType.InternalMotorWithTacho), + new Port(2, nameof(C), true), + new Port(3, nameof(D), true), + new Port(16, nameof(AB), false, expectedDevice: DeviceType.InternalMotorWithTacho, true), + new Port(50, string.Empty, false, expectedDevice: DeviceType.RgbLight), + new Port(58, string.Empty, false, expectedDevice: DeviceType.InternalTilt), + new Port(59, string.Empty, false, expectedDevice: DeviceType.Current), + new Port(60, string.Empty, false, expectedDevice: DeviceType.Voltage), + new Port(70, string.Empty, false, expectedDevice: DeviceType.Unknown) + }) + { } + + public Port A => Port(0); + public Port B => Port(1); + public Port AB => Port(16); + public Port C => Port(2); + public Port D => Port(3); + + + public RgbLight RgbLight => Port(50).GetDevice(); + public Current Current => Port(59).GetDevice(); + public Voltage Voltage => Port(60).GetDevice(); + + } +} \ No newline at end of file diff --git a/src/SharpBrick.PoweredUp/IServiceCollectionExtensions.cs b/src/SharpBrick.PoweredUp/IServiceCollectionExtensions.cs index a95094f..132e4ed 100644 --- a/src/SharpBrick.PoweredUp/IServiceCollectionExtensions.cs +++ b/src/SharpBrick.PoweredUp/IServiceCollectionExtensions.cs @@ -22,6 +22,7 @@ public static IServiceCollection AddPoweredUp(this IServiceCollection self) // hubs .AddTransient() + .AddTransient() // functions .AddTransient() From b634d334457647732ea5848c261dacf9433e7890 Mon Sep 17 00:00:00 2001 From: Cornelius Munz Date: Mon, 5 Oct 2020 08:46:23 +0200 Subject: [PATCH 02/10] add missing changes --- src/SharpBrick.PoweredUp/Enums/SystemType.cs | 2 +- src/SharpBrick.PoweredUp/Hubs/HubFactory.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/SharpBrick.PoweredUp/Enums/SystemType.cs b/src/SharpBrick.PoweredUp/Enums/SystemType.cs index bcfe2b0..37a020f 100644 --- a/src/SharpBrick.PoweredUp/Enums/SystemType.cs +++ b/src/SharpBrick.PoweredUp/Enums/SystemType.cs @@ -6,7 +6,7 @@ public enum SystemType : byte LegoDuplo_DuploTrain = 0b001_00000, - LegoSystem_BoostHub = 0b010_00000, + LegoSystem_MoveHub = 0b010_00000, LegoSystem_TwoPortHub = 0b010_00001, LegoSystem_TwoPortHandset = 0b010_00010, LegoSystem_Mario = 0b0100_0011, // UNSPECED, https://github.com/bricklife/LEGO-Mario-Reveng, 0x43, diff --git a/src/SharpBrick.PoweredUp/Hubs/HubFactory.cs b/src/SharpBrick.PoweredUp/Hubs/HubFactory.cs index 796a9dc..00a5bea 100644 --- a/src/SharpBrick.PoweredUp/Hubs/HubFactory.cs +++ b/src/SharpBrick.PoweredUp/Hubs/HubFactory.cs @@ -38,6 +38,7 @@ public static Type GetTypeFromSystemType(SystemType systemType) => systemType switch { SystemType.LegoTechnic_MediumHub => typeof(TechnicMediumHub), + SystemType.LegoSystem_MoveHub => typeof(MoveHub), _ => throw new NotSupportedException(), }; @@ -45,6 +46,7 @@ public static SystemType GetSystemTypeFromType(Type type) => type.Name switch { nameof(TechnicMediumHub) => SystemType.LegoTechnic_MediumHub, + nameof(MoveHub) => SystemType.LegoSystem_MoveHub, _ => throw new NotSupportedException(), }; } From 95b2dc3cb469c6da0f90ca7db0d507212b489858 Mon Sep 17 00:00:00 2001 From: Cornelius Munz Date: Mon, 5 Oct 2020 11:07:53 +0200 Subject: [PATCH 03/10] added example for MoveHub --- ...ExampleMoveHubInternalTachoMotorControl.cs | 36 +++++++++++++++ .../SharpBrick.PoweredUp.Examples/Program.cs | 4 +- .../Properties/launchSettings.json | 8 ++++ .../Devices/DeviceFactory.cs | 2 + .../Devices/MoveHubInternalMotor.cs | 45 +++++++++++++++++++ src/SharpBrick.PoweredUp/Hubs/MoveHub.cs | 2 +- 6 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubInternalTachoMotorControl.cs create mode 100644 examples/SharpBrick.PoweredUp.Examples/Properties/launchSettings.json create mode 100644 src/SharpBrick.PoweredUp/Devices/MoveHubInternalMotor.cs diff --git a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubInternalTachoMotorControl.cs b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubInternalTachoMotorControl.cs new file mode 100644 index 0000000..0d9218f --- /dev/null +++ b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubInternalTachoMotorControl.cs @@ -0,0 +1,36 @@ +using System.Threading.Tasks; +using SharpBrick.PoweredUp; + +namespace Example +{ + public class ExampleMoveHubInternalTachoMotorControl : BaseExample + { + public override async Task ExecuteAsync() + { + using (var moveHub = Host.FindByType()) + { + //await moveHub.VerifyDeploymentModelAsync(modelBuilder => modelBuilder + // .AddHub(hubBuilder => hubBuilder + // .AddDevice(moveHub.A) + // ) + //); + + var motorA = moveHub.A.GetDevice(); + //var motorB = moveHub.B.GetDevice(); + + await motorA.StartSpeedAsync(50, 100); + //await motorA.StartSpeedForTimeAsync(6000, 90, 100, SpecialSpeed.Hold, SpeedProfiles.AccelerationProfile | SpeedProfiles.DecelerationProfile); + + //await Task.Delay(10_000); + + //await motorB.SetAccelerationTimeAsync(3000); + //await motorB.SetDecelerationTimeAsync(1000); + //await motorB.StartSpeedForTimeAsync(6000, 90, 100, SpecialSpeed.Hold, SpeedProfiles.AccelerationProfile | SpeedProfiles.DecelerationProfile); + + await Task.Delay(10_000); + + //await moveHub.SwitchOffAsync(); + } + } + } +} \ No newline at end of file diff --git a/examples/SharpBrick.PoweredUp.Examples/Program.cs b/examples/SharpBrick.PoweredUp.Examples/Program.cs index 4bc6a21..5c225e9 100644 --- a/examples/SharpBrick.PoweredUp.Examples/Program.cs +++ b/examples/SharpBrick.PoweredUp.Examples/Program.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Example; namespace SharpBrick.PoweredUp.Examples { @@ -33,7 +34,8 @@ static async Task Main(string[] args) //example = new Example.ExampleHubPropertyObserving(); //example = new Example.ExampleDiscoverByType(); //example = new Example.ExampleCalibrationSteering(); - example = new Example.ExampleTechnicMediumHubGestSensor(); + //example = new Example.ExampleTechnicMediumHubGestSensor(); + example = new Example.ExampleMoveHubInternalTachoMotorControl(); // NOTE: Examples are programmed object oriented style. Base class implements methods Configure, DiscoverAsync and ExecuteAsync to be overwriten on demand. await example.InitHostAndDiscoverAsync(enableTrace); diff --git a/examples/SharpBrick.PoweredUp.Examples/Properties/launchSettings.json b/examples/SharpBrick.PoweredUp.Examples/Properties/launchSettings.json new file mode 100644 index 0000000..d995074 --- /dev/null +++ b/examples/SharpBrick.PoweredUp.Examples/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "SharpBrick.PoweredUp.Examples": { + "commandName": "Project", + "commandLineArgs": "--trace" + } + } +} \ No newline at end of file diff --git a/src/SharpBrick.PoweredUp/Devices/DeviceFactory.cs b/src/SharpBrick.PoweredUp/Devices/DeviceFactory.cs index ccf4754..8329dbb 100644 --- a/src/SharpBrick.PoweredUp/Devices/DeviceFactory.cs +++ b/src/SharpBrick.PoweredUp/Devices/DeviceFactory.cs @@ -40,6 +40,7 @@ public Type GetTypeFromDeviceType(DeviceType deviceType) DeviceType.TechnicMediumHubGyroSensor => typeof(TechnicMediumHubGyroSensor), DeviceType.TechnicMediumHubTiltSensor => typeof(TechnicMediumHubTiltSensor), DeviceType.TechnicMediumHubTemperatureSensor => typeof(TechnicMediumHubTemperatureSensor), + DeviceType.InternalMotorWithTacho => typeof(MoveHubInternalMotor), _ => null, }; @@ -56,6 +57,7 @@ public static DeviceType GetDeviceTypeFromType(Type type) nameof(TechnicMediumHubGyroSensor) => DeviceType.TechnicMediumHubGyroSensor, nameof(TechnicMediumHubTiltSensor) => DeviceType.TechnicMediumHubTiltSensor, nameof(TechnicMediumHubTemperatureSensor) => DeviceType.TechnicMediumHubTemperatureSensor, + nameof(MoveHubInternalMotor) => DeviceType.InternalMotorWithTacho, _ => DeviceType.Unknown, }; } diff --git a/src/SharpBrick.PoweredUp/Devices/MoveHubInternalMotor.cs b/src/SharpBrick.PoweredUp/Devices/MoveHubInternalMotor.cs new file mode 100644 index 0000000..d4b0afd --- /dev/null +++ b/src/SharpBrick.PoweredUp/Devices/MoveHubInternalMotor.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SharpBrick.PoweredUp.Protocol; +using SharpBrick.PoweredUp.Utils; + +namespace SharpBrick.PoweredUp +{ + public class MoveHubInternalMotor : TachoMotor, IPoweredUpDevice + { + public MoveHubInternalMotor() + : base() + { } + public MoveHubInternalMotor(ILegoWirelessProtocol protocol, byte hubId, byte portId) + : base(protocol, hubId, portId) + { } + + public IEnumerable GetStaticPortInfoMessages(Version softwareVersion, Version hardwareVersion) + => @" +0B-00-43-00-01-0F-03-06-00-07-00 +07-00-43-00-02-06-00 +11-00-44-00-00-00-50-4F-57-45-52-00-00-00-00-00-00 +0E-00-44-00-00-01-00-00-C8-C2-00-00-C8-42 +0E-00-44-00-00-02-00-00-C8-C2-00-00-C8-42 +0E-00-44-00-00-03-00-00-C8-C2-00-00-C8-42 +0A-00-44-00-00-04-50-43-54-00 +08-00-44-00-00-05-00-10 +0A-00-44-00-00-80-01-00-01-00 +11-00-44-00-01-00-53-50-45-45-44-00-00-00-00-00-00 +0E-00-44-00-01-01-00-00-C8-C2-00-00-C8-42 +0E-00-44-00-01-02-00-00-C8-C2-00-00-C8-42 +0E-00-44-00-01-03-00-00-C8-C2-00-00-C8-42 +0A-00-44-00-01-04-50-43-54-00 +08-00-44-00-01-05-10-10 +0A-00-44-00-01-80-01-00-04-00 +11-00-44-00-02-00-50-4F-53-00-00-00-00-00-00-00-00 +0E-00-44-00-02-01-00-00-B4-C3-00-00-B4-43 +0E-00-44-00-02-02-00-00-C8-C2-00-00-C8-42 +0E-00-44-00-02-03-00-00-B4-C3-00-00-B4-43 +0A-00-44-00-02-04-44-45-47-00 +08-00-44-00-02-05-08-08 +0A-00-44-00-02-80-01-02-04-00 +".Trim().Split("\n").Select(s => BytesStringUtil.StringToData(s)); + } +} \ No newline at end of file diff --git a/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs b/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs index d86b39c..52a01d7 100644 --- a/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs +++ b/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs @@ -32,6 +32,6 @@ public MoveHub(ILegoWirelessProtocol protocol, IDeviceFactory deviceFactory, ILo public RgbLight RgbLight => Port(50).GetDevice(); public Current Current => Port(59).GetDevice(); public Voltage Voltage => Port(60).GetDevice(); - + } } \ No newline at end of file From d275e0dc84d1ce7694c04610386ffe33d47a0aae Mon Sep 17 00:00:00 2001 From: cornelius munz Date: Sun, 11 Oct 2020 23:42:05 +0200 Subject: [PATCH 04/10] updates --- .../ExampleMoveHubColors.cs | 25 +++++++++++++++++++ .../SharpBrick.PoweredUp.Examples/Program.cs | 3 ++- .../Devices/MoveHubInternalMotor.cs | 2 +- src/SharpBrick.PoweredUp/Devices/Voltage.cs | 18 +++++++++++++ src/SharpBrick.PoweredUp/Hubs/MoveHub.cs | 4 +-- 5 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubColors.cs diff --git a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubColors.cs b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubColors.cs new file mode 100644 index 0000000..88be8b9 --- /dev/null +++ b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubColors.cs @@ -0,0 +1,25 @@ +using System; +using System.Threading.Tasks; +using SharpBrick.PoweredUp; + +namespace Example +{ + public class ExampleMoveHubColors : BaseExample + { + public override async Task ExecuteAsync() + { + using (var technicMediumHub = Host.FindByType()) + { + await technicMediumHub.RgbLight.SetRgbColorsAsync(0x00, 0xff, 0x00); + + await Task.Delay(2000); + + await technicMediumHub.RgbLight.SetRgbColorsAsync(0xff, 0x00, 0x00); + + await Task.Delay(2000); + + await technicMediumHub.SwitchOffAsync(); + } + } + } +} \ No newline at end of file diff --git a/examples/SharpBrick.PoweredUp.Examples/Program.cs b/examples/SharpBrick.PoweredUp.Examples/Program.cs index 5c225e9..ba038bf 100644 --- a/examples/SharpBrick.PoweredUp.Examples/Program.cs +++ b/examples/SharpBrick.PoweredUp.Examples/Program.cs @@ -35,7 +35,8 @@ static async Task Main(string[] args) //example = new Example.ExampleDiscoverByType(); //example = new Example.ExampleCalibrationSteering(); //example = new Example.ExampleTechnicMediumHubGestSensor(); - example = new Example.ExampleMoveHubInternalTachoMotorControl(); + //example = new Example.ExampleMoveHubInternalTachoMotorControl(); + example = new Example.ExampleMoveHubColors(); // NOTE: Examples are programmed object oriented style. Base class implements methods Configure, DiscoverAsync and ExecuteAsync to be overwriten on demand. await example.InitHostAndDiscoverAsync(enableTrace); diff --git a/src/SharpBrick.PoweredUp/Devices/MoveHubInternalMotor.cs b/src/SharpBrick.PoweredUp/Devices/MoveHubInternalMotor.cs index d4b0afd..bad6fdc 100644 --- a/src/SharpBrick.PoweredUp/Devices/MoveHubInternalMotor.cs +++ b/src/SharpBrick.PoweredUp/Devices/MoveHubInternalMotor.cs @@ -15,7 +15,7 @@ public MoveHubInternalMotor(ILegoWirelessProtocol protocol, byte hubId, byte por : base(protocol, hubId, portId) { } - public IEnumerable GetStaticPortInfoMessages(Version softwareVersion, Version hardwareVersion) + public IEnumerable GetStaticPortInfoMessages(Version softwareVersion, Version hardwareVersion, SystemType systemType) => @" 0B-00-43-00-01-0F-03-06-00-07-00 07-00-43-00-02-06-00 diff --git a/src/SharpBrick.PoweredUp/Devices/Voltage.cs b/src/SharpBrick.PoweredUp/Devices/Voltage.cs index 53ea53f..b8643a9 100644 --- a/src/SharpBrick.PoweredUp/Devices/Voltage.cs +++ b/src/SharpBrick.PoweredUp/Devices/Voltage.cs @@ -54,6 +54,24 @@ public IEnumerable GetStaticPortInfoMessages(Version softwareVersion, Ve 0A-00-44-3C-01-04-6D-56-00-00 08-00-44-3C-01-05-10-00 0A-00-44-3C-01-80-01-01-04-00 +", + (_, _, SystemType.LegoSystem_MoveHub) => @" +0B-00-43-3C-01-02-02-03-00-00-00 +05-00-43-3C-02 +11-00-44-3C-00-00-56-4C-54-20-4C-00-00-00-00-00-00 +0E-00-44-3C-00-01-00-00-00-00-00-50-73-45 +0E-00-44-3C-00-02-00-00-00-00-00-00-C8-42 +0E-00-44-3C-00-03-00-00-00-00-00-00-16-46 +0A-00-44-3C-00-04-6D-56-00-00 +08-00-44-3C-00-05-10-00 +0A-00-44-3C-00-80-01-01-04-00 +11-00-44-3C-01-00-56-4C-54-20-53-00-00-00-00-00-00 +0E-00-44-3C-01-01-00-00-00-00-00-50-73-45 +0E-00-44-3C-01-02-00-00-00-00-00-00-C8-42 +0E-00-44-3C-01-03-00-00-00-00-00-00-16-46 +0A-00-44-3C-01-04-6D-56-00-00 +08-00-44-3C-01-05-10-00 +0A-00-44-3C-01-80-01-01-04-00 ", _ => throw new NotImplementedException(), }).Trim().Split("\n").Select(s => BytesStringUtil.StringToData(s)); diff --git a/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs b/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs index 52a01d7..c4affdc 100644 --- a/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs +++ b/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs @@ -6,9 +6,9 @@ namespace SharpBrick.PoweredUp { public class MoveHub : Hub - { + { public MoveHub(ILegoWirelessProtocol protocol, IDeviceFactory deviceFactory, ILogger logger, IServiceProvider serviceProvider = default) - : base(protocol, deviceFactory, logger, serviceProvider, new Port[] { + : base(protocol, deviceFactory, logger, serviceProvider, SystemType.LegoSystem_MoveHub, new Port[] { new Port(0, nameof(A), false, expectedDevice: DeviceType.InternalMotorWithTacho), new Port(1, nameof(B), false, expectedDevice: DeviceType.InternalMotorWithTacho), new Port(2, nameof(C), true), From f313e2db036d3981deb476bde5d9281331d8b044 Mon Sep 17 00:00:00 2001 From: Cornelius Munz Date: Mon, 12 Oct 2020 10:05:55 +0200 Subject: [PATCH 05/10] add static port info messages for Current and RgbLight --- .../ExampleMoveHubColors.cs | 8 ++++---- src/SharpBrick.PoweredUp/Devices/Current.cs | 18 ++++++++++++++++++ src/SharpBrick.PoweredUp/Devices/RgbLight.cs | 18 ++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubColors.cs b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubColors.cs index 88be8b9..5a7f9ee 100644 --- a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubColors.cs +++ b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubColors.cs @@ -8,17 +8,17 @@ public class ExampleMoveHubColors : BaseExample { public override async Task ExecuteAsync() { - using (var technicMediumHub = Host.FindByType()) + using (var moveHub = Host.FindByType()) { - await technicMediumHub.RgbLight.SetRgbColorsAsync(0x00, 0xff, 0x00); + await moveHub.RgbLight.SetRgbColorsAsync(0x00, 0xff, 0x00); await Task.Delay(2000); - await technicMediumHub.RgbLight.SetRgbColorsAsync(0xff, 0x00, 0x00); + await moveHub.RgbLight.SetRgbColorsAsync(0xff, 0x00, 0x00); await Task.Delay(2000); - await technicMediumHub.SwitchOffAsync(); + await moveHub.SwitchOffAsync(); } } } diff --git a/src/SharpBrick.PoweredUp/Devices/Current.cs b/src/SharpBrick.PoweredUp/Devices/Current.cs index ee2ad6c..6143bf4 100644 --- a/src/SharpBrick.PoweredUp/Devices/Current.cs +++ b/src/SharpBrick.PoweredUp/Devices/Current.cs @@ -72,6 +72,24 @@ public IEnumerable GetStaticPortInfoMessages(Version softwareVersion, Ve 0B-00-44-3B-01-04-6D-41-00-00-00 08-00-44-3B-01-05-10-00 0A-00-44-3B-01-80-01-01-04-00 +", + (_, _, SystemType.LegoSystem_MoveHub) => @" +0B-00-43-3B-01-02-02-03-00-00-00 +05-00-43-3B-02 +11-00-44-3B-00-00-43-55-52-20-4C-00-00-00-00-00-00 +0E-00-44-3B-00-01-00-00-00-00-00-F0-7F-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-C0-18-45 +0A-00-44-3B-00-04-6D-41-00-00 +08-00-44-3B-00-05-10-00 +0A-00-44-3B-00-80-01-01-04-00 +11-00-44-3B-01-00-43-55-52-20-53-00-00-00-00-00-00 +0E-00-44-3B-01-01-00-00-00-00-00-F0-7F-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-C0-18-45 +0A-00-44-3B-01-04-6D-41-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)); diff --git a/src/SharpBrick.PoweredUp/Devices/RgbLight.cs b/src/SharpBrick.PoweredUp/Devices/RgbLight.cs index cbb7c92..4500563 100644 --- a/src/SharpBrick.PoweredUp/Devices/RgbLight.cs +++ b/src/SharpBrick.PoweredUp/Devices/RgbLight.cs @@ -108,6 +108,24 @@ public IEnumerable 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_MoveHub) => @" +0B-00-43-32-01-01-02-00-00-03-00 +05-00-43-32-02 +11-00-44-32-00-00-43-4F-4C-20-4F-00-00-00-00-00-00 +0E-00-44-32-00-01-00-00-00-00-00-00-20-41 +0E-00-44-32-00-02-00-00-00-00-00-00-C8-42 +0E-00-44-32-00-03-00-00-00-00-00-00-20-41 +0A-00-44-32-00-04-00-00-00-00 +08-00-44-32-00-05-00-44 +0A-00-44-32-00-80-01-00-01-00 +11-00-44-32-01-00-52-47-42-20-4F-00-00-00-00-00-00 +0E-00-44-32-01-01-00-00-00-00-00-00-7F-43 +0E-00-44-32-01-02-00-00-00-00-00-00-C8-42 +0E-00-44-32-01-03-00-00-00-00-00-00-7F-43 +0A-00-44-32-01-04-00-00-00-00 +08-00-44-32-01-05-00-10 +0A-00-44-32-01-80-03-00-03-00 ", _ => throw new NotSupportedException(), }).Trim().Split("\n").Select(s => BytesStringUtil.StringToData(s)); From b91c935d3a7170ddaaec0453122533323de43493 Mon Sep 17 00:00:00 2001 From: Tim Pike <17920409+KeyDecoder@users.noreply.github.com> Date: Tue, 29 Dec 2020 21:15:58 +1000 Subject: [PATCH 06/10] Added seperate properties for move hub since it does not support the hardware network family in the default set of hub properties Added InternalMotor property for MoveHub to provide direct access to motor built into hub Moved OnHub Attached Virtual IO message to be handled only during connection to allow devices with automatic virtual ports to register their ports but avoid double handling of attaching device to a port Tidied up example internal MoveHub example --- ...ExampleMoveHubInternalTachoMotorControl.cs | 27 +++++++---------- src/SharpBrick.PoweredUp/Devices/Voltage.cs | 2 -- src/SharpBrick.PoweredUp/Hubs/Hub.cs | 12 ++++++++ src/SharpBrick.PoweredUp/Hubs/Hub_Ports.cs | 4 +-- src/SharpBrick.PoweredUp/Hubs/MoveHub.cs | 29 ++++++++++++++++--- 5 files changed, 49 insertions(+), 25 deletions(-) diff --git a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubInternalTachoMotorControl.cs b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubInternalTachoMotorControl.cs index 0d9218f..16e08cb 100644 --- a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubInternalTachoMotorControl.cs +++ b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubInternalTachoMotorControl.cs @@ -9,27 +9,22 @@ public override async Task ExecuteAsync() { using (var moveHub = Host.FindByType()) { - //await moveHub.VerifyDeploymentModelAsync(modelBuilder => modelBuilder - // .AddHub(hubBuilder => hubBuilder - // .AddDevice(moveHub.A) - // ) - //); + var internalMotor = moveHub.InternalMotor; + await internalMotor.StartSpeedAsync(50, 100); + await internalMotor.StartSpeedForTimeAsync(2000, 90, 100, SpecialSpeed.Hold, SpeedProfiles.AccelerationProfile | SpeedProfiles.DecelerationProfile); - var motorA = moveHub.A.GetDevice(); - //var motorB = moveHub.B.GetDevice(); + await Task.Delay(2000); - await motorA.StartSpeedAsync(50, 100); - //await motorA.StartSpeedForTimeAsync(6000, 90, 100, SpecialSpeed.Hold, SpeedProfiles.AccelerationProfile | SpeedProfiles.DecelerationProfile); + // This is if you have a linear motor plugged into port D (ie. R2D2) + var externalMotor = moveHub.D.GetDevice(); - //await Task.Delay(10_000); + await externalMotor.SetAccelerationTimeAsync(3000); + await externalMotor.SetDecelerationTimeAsync(1000); + await externalMotor.StartSpeedForTimeAsync(2000, 90, 100, SpecialSpeed.Hold, SpeedProfiles.AccelerationProfile | SpeedProfiles.DecelerationProfile); - //await motorB.SetAccelerationTimeAsync(3000); - //await motorB.SetDecelerationTimeAsync(1000); - //await motorB.StartSpeedForTimeAsync(6000, 90, 100, SpecialSpeed.Hold, SpeedProfiles.AccelerationProfile | SpeedProfiles.DecelerationProfile); + await Task.Delay(10000); - await Task.Delay(10_000); - - //await moveHub.SwitchOffAsync(); + await moveHub.SwitchOffAsync(); } } } diff --git a/src/SharpBrick.PoweredUp/Devices/Voltage.cs b/src/SharpBrick.PoweredUp/Devices/Voltage.cs index 8d31039..1410a2c 100644 --- a/src/SharpBrick.PoweredUp/Devices/Voltage.cs +++ b/src/SharpBrick.PoweredUp/Devices/Voltage.cs @@ -126,8 +126,6 @@ public IEnumerable GetStaticPortInfoMessages(Version softwareVersion, Ve 08-00-44-14-01-05-10-00 0A-00-44-14-01-80-01-01-04-00 ", - - _ => throw new NotSupportedException(), (_, _, SystemType.LegoSystem_MoveHub) => @" 0B-00-43-3C-01-02-02-03-00-00-00 05-00-43-3C-02 diff --git a/src/SharpBrick.PoweredUp/Hubs/Hub.cs b/src/SharpBrick.PoweredUp/Hubs/Hub.cs index d89c456..32b60bb 100644 --- a/src/SharpBrick.PoweredUp/Hubs/Hub.cs +++ b/src/SharpBrick.PoweredUp/Hubs/Hub.cs @@ -16,6 +16,7 @@ public abstract partial class Hub : IDisposable private readonly ILogger _logger; private readonly IDeviceFactory _deviceFactory; private readonly SystemType _knownSystemType; + private bool _connected = false; public ILegoWirelessProtocol Protocol { get; private set; } public byte HubId { get; private set; } @@ -74,6 +75,7 @@ public async Task ConnectAsync() //TODO HubId = hubId; _logger?.LogDebug("Finished Querying Hub Properties"); + _connected = true; } private void SetupOnHubChange() @@ -99,6 +101,16 @@ private void OnHubChange(LegoWirelessMessage message) { OnHubPropertyMessage(hubProperty); } + else if (message is HubAttachedIOForAttachedVirtualDeviceMessage attachedVirtualDeviceMessage) + { + if (!_connected) + { + // Virtual IO messages are only handled from the hubs during connect phase + // This is to allow notifications from hubs which have virtual ports built in (ie. MoveHub) when connecting + // and ensure devices are only attached once when virtual ports are manually created after connection + OnHubAttachedVirtualIOMessage(attachedVirtualDeviceMessage); + } + } else if (message is HubAttachedIOMessage hubAttachedIO) { OnHubAttachedIOMessage(hubAttachedIO); diff --git a/src/SharpBrick.PoweredUp/Hubs/Hub_Ports.cs b/src/SharpBrick.PoweredUp/Hubs/Hub_Ports.cs index d4843ad..87308ae 100644 --- a/src/SharpBrick.PoweredUp/Hubs/Hub_Ports.cs +++ b/src/SharpBrick.PoweredUp/Hubs/Hub_Ports.cs @@ -127,10 +127,8 @@ private void OnHubAttachedIOMessage(HubAttachedIOMessage hubAttachedIO) } break; - // case HubAttachedIOForAttachedVirtualDeviceMessage attachedVirtualDeviceMessage: - // OnHubAttachedVirtualIOMessage(attachedVirtualDeviceMessage); - // break; + // Note - HubAttachedIOForAttachedVirtualDeviceMessage is handled directly in OnHubChange not here } } diff --git a/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs b/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs index c4affdc..01fcbb2 100644 --- a/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs +++ b/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs @@ -11,6 +11,7 @@ public MoveHub(ILegoWirelessProtocol protocol, IDeviceFactory deviceFactory, ILo : base(protocol, deviceFactory, logger, serviceProvider, SystemType.LegoSystem_MoveHub, new Port[] { new Port(0, nameof(A), false, expectedDevice: DeviceType.InternalMotorWithTacho), new Port(1, nameof(B), false, expectedDevice: DeviceType.InternalMotorWithTacho), + // Since ports C and D can be any compatible sensor or motor, we don't set an expected device type here new Port(2, nameof(C), true), new Port(3, nameof(D), true), new Port(16, nameof(AB), false, expectedDevice: DeviceType.InternalMotorWithTacho, true), @@ -18,7 +19,24 @@ public MoveHub(ILegoWirelessProtocol protocol, IDeviceFactory deviceFactory, ILo new Port(58, string.Empty, false, expectedDevice: DeviceType.InternalTilt), new Port(59, string.Empty, false, expectedDevice: DeviceType.Current), new Port(60, string.Empty, false, expectedDevice: DeviceType.Voltage), - new Port(70, string.Empty, false, expectedDevice: DeviceType.Unknown) + new Port(70, string.Empty, false) + }, + 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, + //HubProperty.HardwareNetworkFamily, // Does not appear to work on Move Hub }) { } @@ -28,10 +46,13 @@ public MoveHub(ILegoWirelessProtocol protocol, IDeviceFactory deviceFactory, ILo public Port C => Port(2); public Port D => Port(3); - public RgbLight RgbLight => Port(50).GetDevice(); public Current Current => Port(59).GetDevice(); - public Voltage Voltage => Port(60).GetDevice(); - + public Voltage Voltage => Port(60).GetDevice(); + + /// + /// This is the motor built into the MoveHub + /// + public MoveHubInternalMotor InternalMotor => Port(16).GetDevice(); } } \ No newline at end of file From ff0fb38e7bdce95f2a1fc6bb252cae3d7fdbe78c Mon Sep 17 00:00:00 2001 From: Tim Pike <17920409+KeyDecoder@users.noreply.github.com> Date: Wed, 30 Dec 2020 10:55:06 +1000 Subject: [PATCH 07/10] Add tilt sensor into MoveHub Implement reading data from MoveHub tilt sensor for angle, tilt, orientation, impacts and acceleration Note sometimes the acceleration can be larger than an sbyte value and need to investigate this Implement basic configuration for tilt sensor Add example of using MoveHub tilt sensor --- .../ExampleMoveHubTiltSensor.cs | 55 ++++ .../SharpBrick.PoweredUp.Examples/Program.cs | 3 +- .../Devices/DeviceFactory.cs | 2 + .../Devices/MoveHubTiltSensor.cs | 242 ++++++++++++++++++ .../Enums/TiltFactoryOrientation.cs | 15 ++ .../Enums/TiltOrientation.cs | 12 + src/SharpBrick.PoweredUp/Hubs/MoveHub.cs | 1 + .../Messages/PortOutputCommandMessage.cs | 7 + 8 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubTiltSensor.cs create mode 100644 src/SharpBrick.PoweredUp/Devices/MoveHubTiltSensor.cs create mode 100644 src/SharpBrick.PoweredUp/Enums/TiltFactoryOrientation.cs create mode 100644 src/SharpBrick.PoweredUp/Enums/TiltOrientation.cs diff --git a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubTiltSensor.cs b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubTiltSensor.cs new file mode 100644 index 0000000..06fb451 --- /dev/null +++ b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubTiltSensor.cs @@ -0,0 +1,55 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using SharpBrick.PoweredUp; + +namespace Example +{ + public class ExampleMoveHubTiltSensor : BaseExample + { + public override async Task ExecuteAsync() + { + using (var moveHub = Host.FindByType()) + { + var device = moveHub.TiltSensor; + await device.TiltConfigOrientationAsync(TiltConfigOrientation.Front); + + // Note that you can only have 1 notification running at a time + + await device.SetupNotificationAsync(device.ModeIndexAngle, true, 1); + using var angleSubscription = device.AngleObservable.Subscribe(x => Log.LogWarning($"Angle: {x.x} / {x.y}")); + + Console.WriteLine("Press any key to continue"); + Console.ReadKey(); + + await device.SetupNotificationAsync(device.ModeIndexTilt, true, 1); + using var tiltSubscription = device.TiltObservable.Subscribe(x => Log.LogWarning($"Tilt: {x.SI}")); + + Console.WriteLine("Press any key to continue"); + Console.ReadKey(); + + await device.SetupNotificationAsync(device.ModeIndexOrientation, true, 1); + using var orientationSubscription = device.OrientationObservable.Subscribe(x => Log.LogWarning($"Orientation: {x}")); + + Console.WriteLine("Press any key to continue"); + Console.ReadKey(); + + await device.SetupNotificationAsync(device.ModeIndexAcceleration, true, 1); + using var accelerationSubscription = device.AccelerationObservable.Subscribe(x => Log.LogWarning($"Acceleration: {x.x} / {x.y} / {x.z}")); + + Console.WriteLine("Press any key to continue"); + Console.ReadKey(); + + // This configures a minimum threshold for an impact to be registered (should be a light tap) and subscribes to the count of impacts + await device.TiltConfigImpactAsync(10, 1270); + await device.SetupNotificationAsync(device.ModeIndexImpacts, true, deltaInterval: 1); + using var impactSubscription = device.ImpactsObservable.Subscribe(x => Log.LogWarning($"Impact: {x.SI} / {x.Pct} / {x.Raw}")); + + Console.WriteLine("Press any key to continue"); + Console.ReadKey(); + + await moveHub.SwitchOffAsync(); + } + } + } +} \ No newline at end of file diff --git a/examples/SharpBrick.PoweredUp.Examples/Program.cs b/examples/SharpBrick.PoweredUp.Examples/Program.cs index 2ba36dc..47c67d7 100644 --- a/examples/SharpBrick.PoweredUp.Examples/Program.cs +++ b/examples/SharpBrick.PoweredUp.Examples/Program.cs @@ -47,7 +47,8 @@ static async Task Main(string[] args) example = new Example.ExampleTechnicDistanceSensor(); //example = new Example.ExampleTechnicMediumHubGestSensor(); //example = new Example.ExampleMoveHubInternalTachoMotorControl(); - example = new Example.ExampleMoveHubColors(); + //example = new Example.ExampleMoveHubColors(); + example = new Example.ExampleMoveHubTiltSensor(); // NOTE: Examples are programmed object oriented style. Base class implements methods Configure, DiscoverAsync and ExecuteAsync to be overwriten on demand. await example.InitHostAndDiscoverAsync(enableTrace); diff --git a/src/SharpBrick.PoweredUp/Devices/DeviceFactory.cs b/src/SharpBrick.PoweredUp/Devices/DeviceFactory.cs index 6ca4bfa..222b85c 100644 --- a/src/SharpBrick.PoweredUp/Devices/DeviceFactory.cs +++ b/src/SharpBrick.PoweredUp/Devices/DeviceFactory.cs @@ -57,6 +57,7 @@ public Type GetTypeFromDeviceType(DeviceType deviceType) DeviceType.DuploTrainBaseColorSensor => typeof(DuploTrainBaseColorSensor), DeviceType.DuploTrainBaseSpeedometer => typeof(DuploTrainBaseSpeedometer), DeviceType.InternalMotorWithTacho => typeof(MoveHubInternalMotor), + DeviceType.InternalTilt => typeof(MoveHubTiltSensor), _ => null, }; @@ -90,6 +91,7 @@ public static DeviceType GetDeviceTypeFromType(Type type) nameof(DuploTrainBaseColorSensor) => DeviceType.DuploTrainBaseColorSensor, nameof(DuploTrainBaseSpeedometer) => DeviceType.DuploTrainBaseSpeedometer, nameof(MoveHubInternalMotor) => DeviceType.InternalMotorWithTacho, + nameof(MoveHubTiltSensor) => DeviceType.InternalTilt, _ => DeviceType.Unknown, }; } diff --git a/src/SharpBrick.PoweredUp/Devices/MoveHubTiltSensor.cs b/src/SharpBrick.PoweredUp/Devices/MoveHubTiltSensor.cs new file mode 100644 index 0000000..3a9f983 --- /dev/null +++ b/src/SharpBrick.PoweredUp/Devices/MoveHubTiltSensor.cs @@ -0,0 +1,242 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Threading.Tasks; +using SharpBrick.PoweredUp.Protocol; +using SharpBrick.PoweredUp.Protocol.Messages; +using SharpBrick.PoweredUp.Utils; + +namespace SharpBrick.PoweredUp +{ + public class MoveHubTiltSensor : Device, IPoweredUpDevice + { + protected MultiValueMode _angleMode; + protected SingleValueMode _tiltMode; + protected SingleValueMode _orientationMode; + protected SingleValueMode _impactsMode; + protected MultiValueMode _accelerationMode; + + /// + /// Simple 2 axis (XY) precise angle of tilt + /// + public byte ModeIndexAngle { get; protected set; } = 0; + /// + /// Tilt ? + /// + public byte ModeIndexTilt { get; protected set; } = 1; + /// + /// Orientation in the Z axis + /// + public byte ModeIndexOrientation { get; protected set; } = 2; + /// + /// Count of impacts + /// + public byte ModeIndexImpacts { get; protected set; } = 3; + /// + /// 3 axis acceleration + /// + public byte ModeIndexAcceleration { get; protected set; } = 4; + public byte ModeIndexOrientationConfig { get; protected set; } = 5; + public byte ModeIndexImpactsConfig { get; protected set; } = 6; + public byte ModeIndexCalibration { get; protected set; } = 7; + + public (sbyte x, sbyte y) Angle => (_angleMode.SI[0], _angleMode.SI[1]); + public sbyte Tilt => _tiltMode.SI; + public TiltOrientation Orientation => (TiltOrientation)_orientationMode.SI; + public int Impacts => _impactsMode.SI; + public (sbyte x, sbyte y, sbyte z) Acceleration => (_accelerationMode.SI[0], _accelerationMode.SI[1], _accelerationMode.SI[2]); + + public IObservable<(sbyte x, sbyte y)> AngleObservable => _angleMode.Observable.Select(v => (v.SI[0], v.SI[1])); + public IObservable> TiltObservable => _tiltMode.Observable; + public IObservable OrientationObservable => _orientationMode.Observable.Select(x => (TiltOrientation)x.SI); + public IObservable> ImpactsObservable => _impactsMode.Observable; + public IObservable<(sbyte x, sbyte y, sbyte z)> AccelerationObservable => _accelerationMode.Observable.Select(v => (v.SI[0], v.SI[1], v.SI[2])); + + public MoveHubTiltSensor() + { } + + public MoveHubTiltSensor(ILegoWirelessProtocol protocol, byte hubId, byte portId) + : base(protocol, hubId, portId) + { + _angleMode = MultiValueMode(ModeIndexAngle); + _tiltMode = SingleValueMode(ModeIndexTilt); + _orientationMode = SingleValueMode(ModeIndexOrientation); + _impactsMode = SingleValueMode(ModeIndexImpacts); + _accelerationMode = MultiValueMode(ModeIndexAcceleration); + + ObserveForPropertyChanged(_angleMode.Observable, nameof(Angle)); + ObserveForPropertyChanged(_tiltMode.Observable, nameof(Tilt)); + ObserveForPropertyChanged(_orientationMode.Observable, nameof(Orientation)); + ObserveForPropertyChanged(_impactsMode.Observable, nameof(Impacts)); + ObserveForPropertyChanged(_accelerationMode.Observable, nameof(Acceleration)); + } + + /// + /// Set the Tilt into ImpactCount mode and change (preset) the value to the given PresetValue. + /// + /// Value between 0 and int.MaxValue + /// + public async Task TiltImpactPresetAsync(int presetValue) + { + AssertIsConnected(); + + if (presetValue < 0) + { + throw new ArgumentOutOfRangeException("PresetValue has to be between 0 and int.MaxValue", nameof(presetValue)); + } + + var response = await _protocol.SendPortOutputCommandAsync(new PortOutputCommandTiltImpactPresetMessage() + { + HubId = _hubId, + PortId = _portId, + ModeIndex = ModeIndexImpacts, + StartupInformation = PortOutputCommandStartupInformation.ExecuteImmediately, + CompletionInformation = PortOutputCommandCompletionInformation.CommandFeedback, + PresetValue = presetValue, + }); + + return response; + } + + /// + /// Setup Tilt ImpactThreshold and BumpHoldoff + /// + /// Impact Threshold between 0 and 127. + /// Bump Holdoff between 10ms and 1270ms. + /// + public async Task TiltConfigImpactAsync(sbyte impactThreshold, short bumpHoldoffInMs) + { + AssertIsConnected(); + + if (impactThreshold < 0) + { + throw new ArgumentOutOfRangeException("Impact Threshold has to be between 0 and 127", nameof(impactThreshold)); + } + + if (bumpHoldoffInMs < 10 || bumpHoldoffInMs > 1270) + { + throw new ArgumentOutOfRangeException("Hold off has to be between 10 and 1270 ms (in steps of 10ms)", nameof(bumpHoldoffInMs)); + } + + var response = await _protocol.SendPortOutputCommandAsync(new PortOutputCommandTiltConfigImpactMessage() + { + HubId = _hubId, + PortId = _portId, + ModeIndex = ModeIndexImpactsConfig, + StartupInformation = PortOutputCommandStartupInformation.ExecuteImmediately, + CompletionInformation = PortOutputCommandCompletionInformation.CommandFeedback, + ImpactThreshold = impactThreshold, + BumpHoldoff = (sbyte)((float)bumpHoldoffInMs / 10), + }); + + return response; + } + + /// + /// Set the Tilt into Orientation mode and set the Orientation value to Orientation. + /// + /// orientation of the tilt for 0 values. + /// + public async Task TiltConfigOrientationAsync(TiltConfigOrientation orientation) + { + AssertIsConnected(); + + var response = await _protocol.SendPortOutputCommandAsync(new PortOutputCommandTiltConfigOrientationMessage() + { + HubId = _hubId, + PortId = _portId, + ModeIndex = ModeIndexOrientationConfig, + StartupInformation = PortOutputCommandStartupInformation.ExecuteImmediately, + CompletionInformation = PortOutputCommandCompletionInformation.CommandFeedback, + Orientation = orientation + }); + + return response; + } + + /// + /// Set the Tilt into calibration + /// + /// + public async Task TiltCalibrate(TiltFactoryOrientation orientation) + { + AssertIsConnected(); + + var response = await _protocol.SendPortOutputCommandAsync(new PortOutputCommandTiltFactoryCalibrationMessage() + { + HubId = _hubId, + PortId = _portId, + ModeIndex = ModeIndexCalibration, + StartupInformation = PortOutputCommandStartupInformation.ExecuteImmediately, + CompletionInformation = PortOutputCommandCompletionInformation.CommandFeedback, + Orientation = orientation + }); + + return response; + } + + public IEnumerable GetStaticPortInfoMessages(Version softwareVersion, Version hardwareVersion, SystemType systemType) + => +@" +0B-00-43-3A-01-06-08-FF-00-00-00 +07-00-43-3A-02-1F-00 +11-00-44-3A-00-00-41-4E-47-4C-45-00-00-00-00-00-00 +0E-00-44-3A-00-01-00-00-B4-C2-00-00-B4-42 +0E-00-44-3A-00-02-00-00-C8-C2-00-00-C8-42 +0E-00-44-3A-00-03-00-00-B4-C2-00-00-B4-42 +0A-00-44-3A-00-04-44-45-47-00 +08-00-44-3A-00-05-50-00 +0A-00-44-3A-00-80-02-00-03-00 +11-00-44-3A-01-00-54-49-4C-54-00-00-00-00-00-00-00 +0E-00-44-3A-01-01-00-00-00-00-00-00-20-41 +0E-00-44-3A-01-02-00-00-00-00-00-00-C8-42 +0E-00-44-3A-01-03-00-00-00-00-00-00-20-41 +0A-00-44-3A-01-04-44-49-52-00 +08-00-44-3A-01-05-44-00 +0A-00-44-3A-01-80-01-00-01-00 +11-00-44-3A-02-00-4F-52-49-4E-54-00-00-00-00-00-00 +0E-00-44-3A-02-01-00-00-00-00-00-00-A0-40 +0E-00-44-3A-02-02-00-00-00-00-00-00-C8-42 +0E-00-44-3A-02-03-00-00-00-00-00-00-A0-40 +0A-00-44-3A-02-04-44-49-52-00 +08-00-44-3A-02-05-10-00 +0A-00-44-3A-02-80-01-00-01-00 +11-00-44-3A-03-00-49-4D-50-43-54-00-00-00-00-00-00 +0E-00-44-3A-03-01-00-00-00-00-00-00-C8-42 +0E-00-44-3A-03-02-00-00-00-00-00-00-C8-42 +0E-00-44-3A-03-03-00-00-00-00-00-00-C8-42 +0A-00-44-3A-03-04-49-4D-50-00 +08-00-44-3A-03-05-08-00 +0A-00-44-3A-03-80-01-02-04-00 +11-00-44-3A-04-00-41-43-43-45-4C-00-00-00-00-00-00 +0E-00-44-3A-04-01-00-00-82-C2-00-00-82-42 +0E-00-44-3A-04-02-00-00-C8-C2-00-00-C8-42 +0E-00-44-3A-04-03-00-00-82-C2-00-00-82-42 +0A-00-44-3A-04-04-41-43-43-00 +08-00-44-3A-04-05-10-00 +0A-00-44-3A-04-80-03-00-03-00 +11-00-44-3A-05-00-4F-52-5F-43-46-00-00-00-00-00-00 +0E-00-44-3A-05-01-00-00-00-00-00-00-C0-40 +0E-00-44-3A-05-02-00-00-00-00-00-00-C8-42 +0E-00-44-3A-05-03-00-00-00-00-00-00-C0-40 +0A-00-44-3A-05-04-53-49-44-00 +08-00-44-3A-05-05-10-00 +0A-00-44-3A-05-80-01-00-01-00 +11-00-44-3A-06-00-49-4D-5F-43-46-00-00-00-00-00-00 +0E-00-44-3A-06-01-00-00-00-00-00-00-7F-43 +0E-00-44-3A-06-02-00-00-00-00-00-00-C8-42 +0E-00-44-3A-06-03-00-00-00-00-00-00-7F-43 +0A-00-44-3A-06-04-53-45-4E-00 +08-00-44-3A-06-05-10-00 +0A-00-44-3A-06-80-02-00-03-00 +11-00-44-3A-07-00-43-41-4C-49-42-00-00-00-00-00-00 +0E-00-44-3A-07-01-00-00-00-00-00-00-7F-43 +0E-00-44-3A-07-02-00-00-00-00-00-00-C8-42 +0E-00-44-3A-07-03-00-00-00-00-00-00-7F-43 +0A-00-44-3A-07-04-43-41-4C-00 +08-00-44-3A-07-05-10-00 +0A-00-44-3A-07-80-03-00-03-00 +".Trim().Split("\n").Select(s => BytesStringUtil.StringToData(s)); + } +} \ No newline at end of file diff --git a/src/SharpBrick.PoweredUp/Enums/TiltFactoryOrientation.cs b/src/SharpBrick.PoweredUp/Enums/TiltFactoryOrientation.cs new file mode 100644 index 0000000..1119278 --- /dev/null +++ b/src/SharpBrick.PoweredUp/Enums/TiltFactoryOrientation.cs @@ -0,0 +1,15 @@ +namespace SharpBrick.PoweredUp +{ + public enum TiltFactoryOrientation : byte + { + /// + /// Laying flat XY + /// + LayingFlat = 0x01, + + /// + /// Standing (Z) in long direction + /// + Standing = 0x02, + } +} \ No newline at end of file diff --git a/src/SharpBrick.PoweredUp/Enums/TiltOrientation.cs b/src/SharpBrick.PoweredUp/Enums/TiltOrientation.cs new file mode 100644 index 0000000..d26838c --- /dev/null +++ b/src/SharpBrick.PoweredUp/Enums/TiltOrientation.cs @@ -0,0 +1,12 @@ +namespace SharpBrick.PoweredUp +{ + public enum TiltOrientation : sbyte + { + Bottom = 0x00, + Front = 0x01, + Back = 0x02, + Left = 0x03, + Right = 0x04, + Top = 0x05, + } +} \ No newline at end of file diff --git a/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs b/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs index 01fcbb2..ca821c7 100644 --- a/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs +++ b/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs @@ -47,6 +47,7 @@ public MoveHub(ILegoWirelessProtocol protocol, IDeviceFactory deviceFactory, ILo public Port D => Port(3); public RgbLight RgbLight => Port(50).GetDevice(); + public MoveHubTiltSensor TiltSensor => Port(58).GetDevice(); public Current Current => Port(59).GetDevice(); public Voltage Voltage => Port(60).GetDevice(); diff --git a/src/SharpBrick.PoweredUp/Protocol/Messages/PortOutputCommandMessage.cs b/src/SharpBrick.PoweredUp/Protocol/Messages/PortOutputCommandMessage.cs index 2eec7ea..a677c26 100644 --- a/src/SharpBrick.PoweredUp/Protocol/Messages/PortOutputCommandMessage.cs +++ b/src/SharpBrick.PoweredUp/Protocol/Messages/PortOutputCommandMessage.cs @@ -193,6 +193,13 @@ public PortOutputCommandTiltConfigImpactMessage() : base(0x06) { } public sbyte BumpHoldoff { get; set; } } + // spec chapter: 3.27.18 + public class PortOutputCommandTiltFactoryCalibrationMessage : PortOutputCommandWriteDirectModeDataMessage + { + public PortOutputCommandTiltFactoryCalibrationMessage() : base(0x07) { } + public TiltFactoryOrientation Orientation { get; set; } + } + // spec chapter: 3.27.19 public class PortOutputCommandGenericZeroSetHardwareMessage : PortOutputCommandWriteDirectMessage { } From b7e623c1618175284b39e9fe49652855d3ab5f98 Mon Sep 17 00:00:00 2001 From: Tim Pike <17920409+KeyDecoder@users.noreply.github.com> Date: Wed, 30 Dec 2020 18:13:07 +1000 Subject: [PATCH 08/10] Added safe conversion of raw data scaled to SI and percentage values for sbyte decoding where if it exceeds min/max for an sbyte it clamps to min/max. This can occur if a value is returned larger than the expected min/max raw value which gives a larger than expected percentage. This is seen with MoveHub tilt sensor acceleration where if you manually accelerate it hard enough it returns raw beyond the min/max. --- .../ExampleMoveHubTiltSensor.cs | 2 +- .../Formatter/PortValueSingleEncoder.cs | 21 +++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubTiltSensor.cs b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubTiltSensor.cs index 06fb451..ab7f850 100644 --- a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubTiltSensor.cs +++ b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubTiltSensor.cs @@ -43,7 +43,7 @@ public override async Task ExecuteAsync() // This configures a minimum threshold for an impact to be registered (should be a light tap) and subscribes to the count of impacts await device.TiltConfigImpactAsync(10, 1270); await device.SetupNotificationAsync(device.ModeIndexImpacts, true, deltaInterval: 1); - using var impactSubscription = device.ImpactsObservable.Subscribe(x => Log.LogWarning($"Impact: {x.SI} / {x.Pct} / {x.Raw}")); + using var impactSubscription = device.ImpactsObservable.Subscribe(x => Log.LogWarning($"Impact Count: {x.SI}")); Console.WriteLine("Press any key to continue"); Console.ReadKey(); diff --git a/src/SharpBrick.PoweredUp/Protocol/Formatter/PortValueSingleEncoder.cs b/src/SharpBrick.PoweredUp/Protocol/Formatter/PortValueSingleEncoder.cs index 7e1f8c3..ef9689a 100644 --- a/src/SharpBrick.PoweredUp/Protocol/Formatter/PortValueSingleEncoder.cs +++ b/src/SharpBrick.PoweredUp/Protocol/Formatter/PortValueSingleEncoder.cs @@ -78,10 +78,10 @@ internal static PortValueData CreatePortValueDataSByte(PortModeInfo modeI { var rawValues = MemoryMarshal.Cast(dataSlice).ToArray(); - var siValues = rawValues.Select(rv => Scale(rv, modeInfo.RawMin, modeInfo.RawMax, modeInfo.SIMin, modeInfo.SIMax)).Select(f => Convert.ToSByte(f)).ToArray(); + var siValues = rawValues.Select(rv => Scale(rv, modeInfo.RawMin, modeInfo.RawMax, modeInfo.SIMin, modeInfo.SIMax)).Select(f => ConvertSByteValueFromFloat(f)).ToArray(); var pctValues = modeInfo.DisablePercentage switch { - false => rawValues.Select(rv => Scale(rv, modeInfo.RawMin, modeInfo.RawMax, modeInfo.PctMin, modeInfo.PctMax)).Select(f => Convert.ToSByte(f)).ToArray(), + false => rawValues.Select(rv => Scale(rv, modeInfo.RawMin, modeInfo.RawMax, modeInfo.PctMin, modeInfo.PctMax)).Select(f => ConvertSByteValueFromFloat(f)).ToArray(), true => new sbyte[rawValues.Length], }; @@ -93,6 +93,23 @@ internal static PortValueData CreatePortValueDataSByte(PortModeInfo modeI }; } + internal static sbyte ConvertSByteValueFromFloat(float value) + { + if (value >= sbyte.MinValue && value <= sbyte.MaxValue) + { + return Convert.ToSByte(value); + } + + // If we get a value higher than the sbyte, clamp it at the maximum value (127) or minimum value (-127) + // This can occur sometimes when a value returned exceeds expected min/max and trying to convert to a percentage + + if (value > sbyte.MaxValue) + { + return sbyte.MaxValue; + } + return sbyte.MinValue; + } + internal static PortValueData CreatePortValueDataInt16(PortModeInfo modeInfo, in Span dataSlice) { var rawValues = MemoryMarshal.Cast(dataSlice).ToArray(); From e80f7ab9a1954313787fb715ff873834aef65ab5 Mon Sep 17 00:00:00 2001 From: Tim Pike <17920409+KeyDecoder@users.noreply.github.com> Date: Wed, 30 Dec 2020 19:07:38 +1000 Subject: [PATCH 09/10] Tidy up naming for MoveHub tilt sensor to better reflect the data Add handling of simple 2 axis state as simple orientation enum output instead of raw value --- .../ExampleMoveHubTiltSensor.cs | 16 +++--- .../Devices/MoveHubTiltSensor.cs | 56 +++++++++---------- .../Enums/SimpleOrientation.cs | 11 ++++ 3 files changed, 47 insertions(+), 36 deletions(-) create mode 100644 src/SharpBrick.PoweredUp/Enums/SimpleOrientation.cs diff --git a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubTiltSensor.cs b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubTiltSensor.cs index ab7f850..5c5ded4 100644 --- a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubTiltSensor.cs +++ b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubTiltSensor.cs @@ -16,26 +16,26 @@ public override async Task ExecuteAsync() // Note that you can only have 1 notification running at a time - await device.SetupNotificationAsync(device.ModeIndexAngle, true, 1); - using var angleSubscription = device.AngleObservable.Subscribe(x => Log.LogWarning($"Angle: {x.x} / {x.y}")); + await device.SetupNotificationAsync(device.ModeIndexTwoAxisFull, true, 1); + using var twoAxisFullSubscription = device.TwoAxisFullObservable.Subscribe(x => Log.LogWarning($"Two Axis Values - Roll: {x.roll}, Pitch: {x.pitch}")); Console.WriteLine("Press any key to continue"); Console.ReadKey(); - await device.SetupNotificationAsync(device.ModeIndexTilt, true, 1); - using var tiltSubscription = device.TiltObservable.Subscribe(x => Log.LogWarning($"Tilt: {x.SI}")); + await device.SetupNotificationAsync(device.ModeIndexTwoAxisState, true, 1); + using var twoAxisStateSubscription = device.TwoAxisStateObservable.Subscribe(x => Log.LogWarning($"Two Axis State: {x}")); Console.WriteLine("Press any key to continue"); Console.ReadKey(); - await device.SetupNotificationAsync(device.ModeIndexOrientation, true, 1); - using var orientationSubscription = device.OrientationObservable.Subscribe(x => Log.LogWarning($"Orientation: {x}")); + await device.SetupNotificationAsync(device.ModeIndexThreeAxisState, true, 1); + using var threeAxisStateSubscription = device.ThreeAxisStateObservable.Subscribe(x => Log.LogWarning($"Three Axis State: {x}")); Console.WriteLine("Press any key to continue"); Console.ReadKey(); - await device.SetupNotificationAsync(device.ModeIndexAcceleration, true, 1); - using var accelerationSubscription = device.AccelerationObservable.Subscribe(x => Log.LogWarning($"Acceleration: {x.x} / {x.y} / {x.z}")); + await device.SetupNotificationAsync(device.ModeIndexThreeAxisFull, true, 1); + using var threeAxisFullSubscription = device.ThreeAxisFullObservable.Subscribe(x => Log.LogWarning($"Three Axis Values - Roll: {x.roll}, Pitch: {x.pitch}, Yaw: {x.yaw}")); Console.WriteLine("Press any key to continue"); Console.ReadKey(); diff --git a/src/SharpBrick.PoweredUp/Devices/MoveHubTiltSensor.cs b/src/SharpBrick.PoweredUp/Devices/MoveHubTiltSensor.cs index 3a9f983..1e66747 100644 --- a/src/SharpBrick.PoweredUp/Devices/MoveHubTiltSensor.cs +++ b/src/SharpBrick.PoweredUp/Devices/MoveHubTiltSensor.cs @@ -11,47 +11,47 @@ namespace SharpBrick.PoweredUp { public class MoveHubTiltSensor : Device, IPoweredUpDevice { - protected MultiValueMode _angleMode; - protected SingleValueMode _tiltMode; - protected SingleValueMode _orientationMode; + protected MultiValueMode _twoAxisFullMode; + protected SingleValueMode _twoAxisStateMode; + protected SingleValueMode _threeAxisStateMode; protected SingleValueMode _impactsMode; - protected MultiValueMode _accelerationMode; + protected MultiValueMode _threeAxisFullMode; /// - /// Simple 2 axis (XY) precise angle of tilt + /// Two axis full values /// - public byte ModeIndexAngle { get; protected set; } = 0; + public byte ModeIndexTwoAxisFull { get; protected set; } = 0; /// - /// Tilt ? + /// Two Axis simple state /// - public byte ModeIndexTilt { get; protected set; } = 1; + public byte ModeIndexTwoAxisState { get; protected set; } = 1; /// - /// Orientation in the Z axis + /// Three Axis simple state /// - public byte ModeIndexOrientation { get; protected set; } = 2; + public byte ModeIndexThreeAxisState { get; protected set; } = 2; /// /// Count of impacts /// public byte ModeIndexImpacts { get; protected set; } = 3; /// - /// 3 axis acceleration + /// Three axis full values /// - public byte ModeIndexAcceleration { get; protected set; } = 4; + public byte ModeIndexThreeAxisFull { get; protected set; } = 4; public byte ModeIndexOrientationConfig { get; protected set; } = 5; public byte ModeIndexImpactsConfig { get; protected set; } = 6; public byte ModeIndexCalibration { get; protected set; } = 7; - public (sbyte x, sbyte y) Angle => (_angleMode.SI[0], _angleMode.SI[1]); - public sbyte Tilt => _tiltMode.SI; - public TiltOrientation Orientation => (TiltOrientation)_orientationMode.SI; + public (sbyte roll, sbyte pitch) TwoAxisFull => (_twoAxisFullMode.SI[0], _twoAxisFullMode.SI[1]); + public SimpleOrientation TwoAxisState => (SimpleOrientation)_twoAxisStateMode.SI; + public TiltOrientation ThreeAxisState => (TiltOrientation)_threeAxisStateMode.SI; public int Impacts => _impactsMode.SI; - public (sbyte x, sbyte y, sbyte z) Acceleration => (_accelerationMode.SI[0], _accelerationMode.SI[1], _accelerationMode.SI[2]); + public (sbyte roll, sbyte pitch, sbyte yaw) ThreeAxisFull => (_threeAxisFullMode.SI[0], _threeAxisFullMode.SI[1], _threeAxisFullMode.SI[2]); - public IObservable<(sbyte x, sbyte y)> AngleObservable => _angleMode.Observable.Select(v => (v.SI[0], v.SI[1])); - public IObservable> TiltObservable => _tiltMode.Observable; - public IObservable OrientationObservable => _orientationMode.Observable.Select(x => (TiltOrientation)x.SI); + public IObservable<(sbyte roll, sbyte pitch)> TwoAxisFullObservable => _twoAxisFullMode.Observable.Select(v => (v.SI[0], v.SI[1])); + public IObservable TwoAxisStateObservable => _twoAxisStateMode.Observable.Select(x => (SimpleOrientation)x.SI); + public IObservable ThreeAxisStateObservable => _threeAxisStateMode.Observable.Select(x => (TiltOrientation)x.SI); public IObservable> ImpactsObservable => _impactsMode.Observable; - public IObservable<(sbyte x, sbyte y, sbyte z)> AccelerationObservable => _accelerationMode.Observable.Select(v => (v.SI[0], v.SI[1], v.SI[2])); + public IObservable<(sbyte roll, sbyte pitch, sbyte yaw)> ThreeAxisFullObservable => _threeAxisFullMode.Observable.Select(v => (v.SI[0], v.SI[1], v.SI[2])); public MoveHubTiltSensor() { } @@ -59,17 +59,17 @@ public MoveHubTiltSensor() public MoveHubTiltSensor(ILegoWirelessProtocol protocol, byte hubId, byte portId) : base(protocol, hubId, portId) { - _angleMode = MultiValueMode(ModeIndexAngle); - _tiltMode = SingleValueMode(ModeIndexTilt); - _orientationMode = SingleValueMode(ModeIndexOrientation); + _twoAxisFullMode = MultiValueMode(ModeIndexTwoAxisFull); + _twoAxisStateMode = SingleValueMode(ModeIndexTwoAxisState); + _threeAxisStateMode = SingleValueMode(ModeIndexThreeAxisState); _impactsMode = SingleValueMode(ModeIndexImpacts); - _accelerationMode = MultiValueMode(ModeIndexAcceleration); + _threeAxisFullMode = MultiValueMode(ModeIndexThreeAxisFull); - ObserveForPropertyChanged(_angleMode.Observable, nameof(Angle)); - ObserveForPropertyChanged(_tiltMode.Observable, nameof(Tilt)); - ObserveForPropertyChanged(_orientationMode.Observable, nameof(Orientation)); + ObserveForPropertyChanged(_twoAxisFullMode.Observable, nameof(TwoAxisFull)); + ObserveForPropertyChanged(_twoAxisStateMode.Observable, nameof(TwoAxisState)); + ObserveForPropertyChanged(_threeAxisStateMode.Observable, nameof(ThreeAxisState)); ObserveForPropertyChanged(_impactsMode.Observable, nameof(Impacts)); - ObserveForPropertyChanged(_accelerationMode.Observable, nameof(Acceleration)); + ObserveForPropertyChanged(_threeAxisFullMode.Observable, nameof(ThreeAxisFull)); } /// diff --git a/src/SharpBrick.PoweredUp/Enums/SimpleOrientation.cs b/src/SharpBrick.PoweredUp/Enums/SimpleOrientation.cs new file mode 100644 index 0000000..5d3ab88 --- /dev/null +++ b/src/SharpBrick.PoweredUp/Enums/SimpleOrientation.cs @@ -0,0 +1,11 @@ +namespace SharpBrick.PoweredUp +{ + public enum SimpleOrientation : sbyte + { + Horzontial = 0x00, + Down = 0x03, + Left = 0x05, + Right = 0x07, + Up = 0x09 + } +} \ No newline at end of file From 4b78e8578aafe53ca24369f873f09e3e56ab4ec7 Mon Sep 17 00:00:00 2001 From: Tim Pike <17920409+KeyDecoder@users.noreply.github.com> Date: Thu, 31 Dec 2020 11:22:23 +1000 Subject: [PATCH 10/10] Remove Visual Studio launch properties Split movehub internal motor and external motor into seperate examples since not everyone has the external motor plugged in Renamed DeviceType for movehub internal motor and tilt sensor to include MoveHub in naming so it is clearer what they are Changed MoveHub Tilt Sensor to disable percentage and removed workaround on port value single encoder when percentage was bigger than an sbyte Removed tilt calibration since message encoding is not implemented and unsure what this actually does at the moment so safer to remove for now Tidied up naming for move hub orientation enums Add null check in Hub when handling attach/detach messages so now logs information when getting attach or detach for a port it does not know about instead of generating an exception and blocking connection to a hub Added seperate left and right motors to MoveHub and updating naming to be clearer what type of motor and what port they are connected to --- ...MoveHubExternalMediumLinearMotorControl.cs | 25 +++++++++++ ...ExampleMoveHubInternalTachoMotorControl.cs | 20 +++++---- .../SharpBrick.PoweredUp.Examples/Program.cs | 3 +- .../Properties/launchSettings.json | 8 ---- .../Devices/DeviceFactory.cs | 8 ++-- .../Devices/MoveHubTiltSensor.cs | 45 ++++++++----------- src/SharpBrick.PoweredUp/Enums/DeviceType.cs | 4 +- ...on.cs => MoveHubTiltFactoryOrientation.cs} | 2 +- .../Enums/MoveHubTiltOrientation.cs | 15 +++++++ ...ion.cs => MoveHubTiltSimpleOrientation.cs} | 5 ++- .../Enums/TiltOrientation.cs | 12 ----- src/SharpBrick.PoweredUp/Hubs/Hub_Ports.cs | 12 ++++- src/SharpBrick.PoweredUp/Hubs/MoveHub.cs | 27 ++++++----- .../Formatter/PortValueSingleEncoder.cs | 21 +-------- .../Messages/PortOutputCommandMessage.cs | 7 --- 15 files changed, 113 insertions(+), 101 deletions(-) create mode 100644 examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubExternalMediumLinearMotorControl.cs delete mode 100644 examples/SharpBrick.PoweredUp.Examples/Properties/launchSettings.json rename src/SharpBrick.PoweredUp/Enums/{TiltFactoryOrientation.cs => MoveHubTiltFactoryOrientation.cs} (83%) create mode 100644 src/SharpBrick.PoweredUp/Enums/MoveHubTiltOrientation.cs rename src/SharpBrick.PoweredUp/Enums/{SimpleOrientation.cs => MoveHubTiltSimpleOrientation.cs} (51%) delete mode 100644 src/SharpBrick.PoweredUp/Enums/TiltOrientation.cs diff --git a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubExternalMediumLinearMotorControl.cs b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubExternalMediumLinearMotorControl.cs new file mode 100644 index 0000000..3b6bf25 --- /dev/null +++ b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubExternalMediumLinearMotorControl.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using SharpBrick.PoweredUp; + +namespace Example +{ + public class ExampleMoveHubExternalMediumLinearMotorControl : BaseExample + { + public override async Task ExecuteAsync() + { + using (var moveHub = Host.FindByType()) + { + // This is if you have a linear motor plugged into port D (ie. R2D2) + var externalMotor = moveHub.D.GetDevice(); + + await externalMotor.SetAccelerationTimeAsync(3000); + await externalMotor.SetDecelerationTimeAsync(1000); + await externalMotor.StartSpeedForTimeAsync(2000, 90, 100, SpecialSpeed.Hold, SpeedProfiles.AccelerationProfile | SpeedProfiles.DecelerationProfile); + + await Task.Delay(50000); + + await moveHub.SwitchOffAsync(); + } + } + } +} diff --git a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubInternalTachoMotorControl.cs b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubInternalTachoMotorControl.cs index 16e08cb..c1c5e1e 100644 --- a/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubInternalTachoMotorControl.cs +++ b/examples/SharpBrick.PoweredUp.Examples/ExampleMoveHubInternalTachoMotorControl.cs @@ -9,20 +9,24 @@ public override async Task ExecuteAsync() { using (var moveHub = Host.FindByType()) { - var internalMotor = moveHub.InternalMotor; + var internalMotor = moveHub.MotorAtAB; await internalMotor.StartSpeedAsync(50, 100); await internalMotor.StartSpeedForTimeAsync(2000, 90, 100, SpecialSpeed.Hold, SpeedProfiles.AccelerationProfile | SpeedProfiles.DecelerationProfile); - await Task.Delay(2000); + await Task.Delay(3000); + await internalMotor.StopByBrakeAsync(); - // This is if you have a linear motor plugged into port D (ie. R2D2) - var externalMotor = moveHub.D.GetDevice(); + var leftMotor = moveHub.LeftMotorAtB; + var rightMotor = moveHub.RightMotorAtA; + await leftMotor.StartSpeedAsync(10, 100); + await leftMotor.StartSpeedForTimeAsync(1000, 10, 100, SpecialSpeed.Hold, SpeedProfiles.AccelerationProfile | SpeedProfiles.DecelerationProfile); + await rightMotor.StartSpeedAsync(90, 100); + await rightMotor.StartSpeedForTimeAsync(1000, 90, 100, SpecialSpeed.Hold, SpeedProfiles.AccelerationProfile | SpeedProfiles.DecelerationProfile); - await externalMotor.SetAccelerationTimeAsync(3000); - await externalMotor.SetDecelerationTimeAsync(1000); - await externalMotor.StartSpeedForTimeAsync(2000, 90, 100, SpecialSpeed.Hold, SpeedProfiles.AccelerationProfile | SpeedProfiles.DecelerationProfile); + await Task.Delay(2000); - await Task.Delay(10000); + await leftMotor.StopByBrakeAsync(); + await rightMotor.StopByBrakeAsync(); await moveHub.SwitchOffAsync(); } diff --git a/examples/SharpBrick.PoweredUp.Examples/Program.cs b/examples/SharpBrick.PoweredUp.Examples/Program.cs index 47c67d7..f2d1b13 100644 --- a/examples/SharpBrick.PoweredUp.Examples/Program.cs +++ b/examples/SharpBrick.PoweredUp.Examples/Program.cs @@ -44,9 +44,10 @@ static async Task Main(string[] args) //example = new Example.ExampleMarioAccelerometer(); //example = new Example.ExampleDuploTrainBase(); //example = new Example.ExampleTechnicColorSensor(); - example = new Example.ExampleTechnicDistanceSensor(); + //example = new Example.ExampleTechnicDistanceSensor(); //example = new Example.ExampleTechnicMediumHubGestSensor(); //example = new Example.ExampleMoveHubInternalTachoMotorControl(); + //example = new Example.ExampleMoveHubExternalMediumLinearMotorControl(); //example = new Example.ExampleMoveHubColors(); example = new Example.ExampleMoveHubTiltSensor(); diff --git a/examples/SharpBrick.PoweredUp.Examples/Properties/launchSettings.json b/examples/SharpBrick.PoweredUp.Examples/Properties/launchSettings.json deleted file mode 100644 index d995074..0000000 --- a/examples/SharpBrick.PoweredUp.Examples/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "SharpBrick.PoweredUp.Examples": { - "commandName": "Project", - "commandLineArgs": "--trace" - } - } -} \ No newline at end of file diff --git a/src/SharpBrick.PoweredUp/Devices/DeviceFactory.cs b/src/SharpBrick.PoweredUp/Devices/DeviceFactory.cs index 222b85c..c41c77f 100644 --- a/src/SharpBrick.PoweredUp/Devices/DeviceFactory.cs +++ b/src/SharpBrick.PoweredUp/Devices/DeviceFactory.cs @@ -56,8 +56,8 @@ public Type GetTypeFromDeviceType(DeviceType deviceType) DeviceType.DuploTrainBaseSpeaker => typeof(DuploTrainBaseSpeaker), DeviceType.DuploTrainBaseColorSensor => typeof(DuploTrainBaseColorSensor), DeviceType.DuploTrainBaseSpeedometer => typeof(DuploTrainBaseSpeedometer), - DeviceType.InternalMotorWithTacho => typeof(MoveHubInternalMotor), - DeviceType.InternalTilt => typeof(MoveHubTiltSensor), + DeviceType.MoveHubInternalMotor => typeof(MoveHubInternalMotor), + DeviceType.MoveHubTiltSensor => typeof(MoveHubTiltSensor), _ => null, }; @@ -90,8 +90,8 @@ public static DeviceType GetDeviceTypeFromType(Type type) nameof(DuploTrainBaseSpeaker) => DeviceType.DuploTrainBaseSpeaker, nameof(DuploTrainBaseColorSensor) => DeviceType.DuploTrainBaseColorSensor, nameof(DuploTrainBaseSpeedometer) => DeviceType.DuploTrainBaseSpeedometer, - nameof(MoveHubInternalMotor) => DeviceType.InternalMotorWithTacho, - nameof(MoveHubTiltSensor) => DeviceType.InternalTilt, + nameof(MoveHubInternalMotor) => DeviceType.MoveHubInternalMotor, + nameof(MoveHubTiltSensor) => DeviceType.MoveHubTiltSensor, _ => DeviceType.Unknown, }; } diff --git a/src/SharpBrick.PoweredUp/Devices/MoveHubTiltSensor.cs b/src/SharpBrick.PoweredUp/Devices/MoveHubTiltSensor.cs index 1e66747..0a69bf8 100644 --- a/src/SharpBrick.PoweredUp/Devices/MoveHubTiltSensor.cs +++ b/src/SharpBrick.PoweredUp/Devices/MoveHubTiltSensor.cs @@ -4,6 +4,7 @@ using System.Reactive.Linq; using System.Threading.Tasks; using SharpBrick.PoweredUp.Protocol; +using SharpBrick.PoweredUp.Protocol.Knowledge; using SharpBrick.PoweredUp.Protocol.Messages; using SharpBrick.PoweredUp.Utils; @@ -22,11 +23,11 @@ public class MoveHubTiltSensor : Device, IPoweredUpDevice /// public byte ModeIndexTwoAxisFull { get; protected set; } = 0; /// - /// Two Axis simple state + /// Two Axis simple state of orientation /// public byte ModeIndexTwoAxisState { get; protected set; } = 1; /// - /// Three Axis simple state + /// Three Axis simple state of orientation which provides more states than /// public byte ModeIndexThreeAxisState { get; protected set; } = 2; /// @@ -42,14 +43,14 @@ public class MoveHubTiltSensor : Device, IPoweredUpDevice public byte ModeIndexCalibration { get; protected set; } = 7; public (sbyte roll, sbyte pitch) TwoAxisFull => (_twoAxisFullMode.SI[0], _twoAxisFullMode.SI[1]); - public SimpleOrientation TwoAxisState => (SimpleOrientation)_twoAxisStateMode.SI; - public TiltOrientation ThreeAxisState => (TiltOrientation)_threeAxisStateMode.SI; + public MoveHubTiltSimpleOrientation TwoAxisState => (MoveHubTiltSimpleOrientation)_twoAxisStateMode.SI; + public MoveHubTiltOrientation ThreeAxisState => (MoveHubTiltOrientation)_threeAxisStateMode.SI; public int Impacts => _impactsMode.SI; public (sbyte roll, sbyte pitch, sbyte yaw) ThreeAxisFull => (_threeAxisFullMode.SI[0], _threeAxisFullMode.SI[1], _threeAxisFullMode.SI[2]); public IObservable<(sbyte roll, sbyte pitch)> TwoAxisFullObservable => _twoAxisFullMode.Observable.Select(v => (v.SI[0], v.SI[1])); - public IObservable TwoAxisStateObservable => _twoAxisStateMode.Observable.Select(x => (SimpleOrientation)x.SI); - public IObservable ThreeAxisStateObservable => _threeAxisStateMode.Observable.Select(x => (TiltOrientation)x.SI); + public IObservable TwoAxisStateObservable => _twoAxisStateMode.Observable.Select(x => (MoveHubTiltSimpleOrientation)x.SI); + public IObservable ThreeAxisStateObservable => _threeAxisStateMode.Observable.Select(x => (MoveHubTiltOrientation)x.SI); public IObservable> ImpactsObservable => _impactsMode.Observable; public IObservable<(sbyte roll, sbyte pitch, sbyte yaw)> ThreeAxisFullObservable => _threeAxisFullMode.Observable.Select(v => (v.SI[0], v.SI[1], v.SI[2])); @@ -72,6 +73,17 @@ public MoveHubTiltSensor(ILegoWirelessProtocol protocol, byte hubId, byte portId ObserveForPropertyChanged(_threeAxisFullMode.Observable, nameof(ThreeAxisFull)); } + public void ExtendPortMode(PortModeInfo modeInfo) + { + // Percentage is disabled for three axis full (ACCEL) since in some cases the hub + // can report a larger than expected value which makes the percentage go beyond an sbyte min/max values and generate an exception + // TODO: This can be removed when #126 is implemented + if (modeInfo.ModeIndex == ModeIndexThreeAxisFull) + { + modeInfo.DisablePercentage = true; + } + } + /// /// Set the Tilt into ImpactCount mode and change (preset) the value to the given PresetValue. /// @@ -155,27 +167,6 @@ public async Task TiltConfigOrientationAsync(TiltConfigOrientation return response; } - /// - /// Set the Tilt into calibration - /// - /// - public async Task TiltCalibrate(TiltFactoryOrientation orientation) - { - AssertIsConnected(); - - var response = await _protocol.SendPortOutputCommandAsync(new PortOutputCommandTiltFactoryCalibrationMessage() - { - HubId = _hubId, - PortId = _portId, - ModeIndex = ModeIndexCalibration, - StartupInformation = PortOutputCommandStartupInformation.ExecuteImmediately, - CompletionInformation = PortOutputCommandCompletionInformation.CommandFeedback, - Orientation = orientation - }); - - return response; - } - public IEnumerable GetStaticPortInfoMessages(Version softwareVersion, Version hardwareVersion, SystemType systemType) => @" diff --git a/src/SharpBrick.PoweredUp/Enums/DeviceType.cs b/src/SharpBrick.PoweredUp/Enums/DeviceType.cs index 8b6c994..71ec8cb 100644 --- a/src/SharpBrick.PoweredUp/Enums/DeviceType.cs +++ b/src/SharpBrick.PoweredUp/Enums/DeviceType.cs @@ -16,8 +16,8 @@ public enum DeviceType : ushort MotionSensor = 0x0023, // MOTION_SENSOR VisionSensor = 0x0025, // COLOR_DISTANCE_SENSOR MediumLinearMotor = 0x0026, // MEDIUM_LINEAR_MOTOR - InternalMotorWithTacho = 0x0027, // MOVE_HUB_MEDIUM_LINEAR_MOTOR - InternalTilt = 0x0028, // MOVE_HUB_TILT_SENSOR + MoveHubInternalMotor = 0x0027, // MOVE_HUB_MEDIUM_LINEAR_MOTOR + MoveHubTiltSensor = 0x0028, // MOVE_HUB_TILT_SENSOR DuploTrainBaseMotor = 0x0029, // UNSPECED, DUPLO_TRAIN_BASE_MOTOR DuploTrainBaseSpeaker = 0x002A, // UNSPECED, DUPLO_TRAIN_BASE_SPEAKER diff --git a/src/SharpBrick.PoweredUp/Enums/TiltFactoryOrientation.cs b/src/SharpBrick.PoweredUp/Enums/MoveHubTiltFactoryOrientation.cs similarity index 83% rename from src/SharpBrick.PoweredUp/Enums/TiltFactoryOrientation.cs rename to src/SharpBrick.PoweredUp/Enums/MoveHubTiltFactoryOrientation.cs index 1119278..c5f413a 100644 --- a/src/SharpBrick.PoweredUp/Enums/TiltFactoryOrientation.cs +++ b/src/SharpBrick.PoweredUp/Enums/MoveHubTiltFactoryOrientation.cs @@ -1,6 +1,6 @@ namespace SharpBrick.PoweredUp { - public enum TiltFactoryOrientation : byte + public enum MoveHubTiltFactoryOrientation : byte { /// /// Laying flat XY diff --git a/src/SharpBrick.PoweredUp/Enums/MoveHubTiltOrientation.cs b/src/SharpBrick.PoweredUp/Enums/MoveHubTiltOrientation.cs new file mode 100644 index 0000000..75f36fc --- /dev/null +++ b/src/SharpBrick.PoweredUp/Enums/MoveHubTiltOrientation.cs @@ -0,0 +1,15 @@ +namespace SharpBrick.PoweredUp +{ + /// + /// Simple tilt orientation state based on 3-axis providing more possible states than + /// + public enum MoveHubTiltOrientation : sbyte + { + Bottom = 0x00, + Front = 0x01, + Back = 0x02, + Left = 0x03, + Right = 0x04, + Top = 0x05, + } +} \ No newline at end of file diff --git a/src/SharpBrick.PoweredUp/Enums/SimpleOrientation.cs b/src/SharpBrick.PoweredUp/Enums/MoveHubTiltSimpleOrientation.cs similarity index 51% rename from src/SharpBrick.PoweredUp/Enums/SimpleOrientation.cs rename to src/SharpBrick.PoweredUp/Enums/MoveHubTiltSimpleOrientation.cs index 5d3ab88..a2f0bd1 100644 --- a/src/SharpBrick.PoweredUp/Enums/SimpleOrientation.cs +++ b/src/SharpBrick.PoweredUp/Enums/MoveHubTiltSimpleOrientation.cs @@ -1,6 +1,9 @@ namespace SharpBrick.PoweredUp { - public enum SimpleOrientation : sbyte + /// + /// Simple tilt orientation state based on 2-axis only + /// + public enum MoveHubTiltSimpleOrientation : sbyte { Horzontial = 0x00, Down = 0x03, diff --git a/src/SharpBrick.PoweredUp/Enums/TiltOrientation.cs b/src/SharpBrick.PoweredUp/Enums/TiltOrientation.cs deleted file mode 100644 index d26838c..0000000 --- a/src/SharpBrick.PoweredUp/Enums/TiltOrientation.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace SharpBrick.PoweredUp -{ - public enum TiltOrientation : sbyte - { - Bottom = 0x00, - Front = 0x01, - Back = 0x02, - Left = 0x03, - Right = 0x04, - Top = 0x05, - } -} \ No newline at end of file diff --git a/src/SharpBrick.PoweredUp/Hubs/Hub_Ports.cs b/src/SharpBrick.PoweredUp/Hubs/Hub_Ports.cs index 87308ae..8790e10 100644 --- a/src/SharpBrick.PoweredUp/Hubs/Hub_Ports.cs +++ b/src/SharpBrick.PoweredUp/Hubs/Hub_Ports.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using SharpBrick.PoweredUp.Protocol; using SharpBrick.PoweredUp.Protocol.Messages; +using Microsoft.Extensions.Logging; namespace SharpBrick.PoweredUp { @@ -111,13 +112,22 @@ private void OnHubAttachedIOMessage(HubAttachedIOMessage hubAttachedIO) { case HubAttachedIOForAttachedDeviceMessage attachedDeviceMessage: port = Port(attachedDeviceMessage.PortId); - + if (port == null) + { + _logger?.LogInformation($"Hub sent notification of attached device with port id '{hubAttachedIO.PortId}' but hub type '{GetType().Name}' is not configured for this port"); + return; + } var device = _deviceFactory.CreateConnected(attachedDeviceMessage.IOTypeId, Protocol, attachedDeviceMessage.HubId, attachedDeviceMessage.PortId); port.AttachDevice(device, attachedDeviceMessage.IOTypeId); break; case HubAttachedIOForDetachedDeviceMessage detachedDeviceMessage: port = Port(detachedDeviceMessage.PortId); + if (port == null) + { + _logger?.LogInformation($"Hub sent notification of detached device with port id '{hubAttachedIO.PortId}' but hub type '{GetType().Name}' is not configured for this port"); + return; + } port.DetachDevice(); diff --git a/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs b/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs index ca821c7..f45b568 100644 --- a/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs +++ b/src/SharpBrick.PoweredUp/Hubs/MoveHub.cs @@ -9,17 +9,17 @@ public class MoveHub : Hub { public MoveHub(ILegoWirelessProtocol protocol, IDeviceFactory deviceFactory, ILogger logger, IServiceProvider serviceProvider = default) : base(protocol, deviceFactory, logger, serviceProvider, SystemType.LegoSystem_MoveHub, new Port[] { - new Port(0, nameof(A), false, expectedDevice: DeviceType.InternalMotorWithTacho), - new Port(1, nameof(B), false, expectedDevice: DeviceType.InternalMotorWithTacho), + new Port(0, "A", false, expectedDevice: DeviceType.MoveHubInternalMotor), + new Port(1, "B", false, expectedDevice: DeviceType.MoveHubInternalMotor), // Since ports C and D can be any compatible sensor or motor, we don't set an expected device type here new Port(2, nameof(C), true), new Port(3, nameof(D), true), - new Port(16, nameof(AB), false, expectedDevice: DeviceType.InternalMotorWithTacho, true), + new Port(16, "AB", false, expectedDevice: DeviceType.MoveHubInternalMotor, true), new Port(50, string.Empty, false, expectedDevice: DeviceType.RgbLight), - new Port(58, string.Empty, false, expectedDevice: DeviceType.InternalTilt), + new Port(58, string.Empty, false, expectedDevice: DeviceType.MoveHubTiltSensor), new Port(59, string.Empty, false, expectedDevice: DeviceType.Current), new Port(60, string.Empty, false, expectedDevice: DeviceType.Voltage), - new Port(70, string.Empty, false) + // Note that there is a port with id 70 but is not currently known what this does (suspected to be debug port) }, knownProperties: new HubProperty[] { HubProperty.AdvertisingName, @@ -40,9 +40,6 @@ public MoveHub(ILegoWirelessProtocol protocol, IDeviceFactory deviceFactory, ILo }) { } - public Port A => Port(0); - public Port B => Port(1); - public Port AB => Port(16); public Port C => Port(2); public Port D => Port(3); @@ -52,8 +49,18 @@ public MoveHub(ILegoWirelessProtocol protocol, IDeviceFactory deviceFactory, ILo public Voltage Voltage => Port(60).GetDevice(); /// - /// This is the motor built into the MoveHub + /// This is the virtual port of the motors built into the MoveHub. This controls both left and right motors /// - public MoveHubInternalMotor InternalMotor => Port(16).GetDevice(); + public MoveHubInternalMotor MotorAtAB => Port(16).GetDevice(); + + /// + /// This is the motor built into the MoveHub controlling the left motor (B) + /// + public MoveHubInternalMotor LeftMotorAtB => Port(1).GetDevice(); + + /// + /// This is the motor built into the MoveHub controlling the right motor (A) + /// + public MoveHubInternalMotor RightMotorAtA => Port(0).GetDevice(); } } \ No newline at end of file diff --git a/src/SharpBrick.PoweredUp/Protocol/Formatter/PortValueSingleEncoder.cs b/src/SharpBrick.PoweredUp/Protocol/Formatter/PortValueSingleEncoder.cs index ef9689a..7e1f8c3 100644 --- a/src/SharpBrick.PoweredUp/Protocol/Formatter/PortValueSingleEncoder.cs +++ b/src/SharpBrick.PoweredUp/Protocol/Formatter/PortValueSingleEncoder.cs @@ -78,10 +78,10 @@ internal static PortValueData CreatePortValueDataSByte(PortModeInfo modeI { var rawValues = MemoryMarshal.Cast(dataSlice).ToArray(); - var siValues = rawValues.Select(rv => Scale(rv, modeInfo.RawMin, modeInfo.RawMax, modeInfo.SIMin, modeInfo.SIMax)).Select(f => ConvertSByteValueFromFloat(f)).ToArray(); + var siValues = rawValues.Select(rv => Scale(rv, modeInfo.RawMin, modeInfo.RawMax, modeInfo.SIMin, modeInfo.SIMax)).Select(f => Convert.ToSByte(f)).ToArray(); var pctValues = modeInfo.DisablePercentage switch { - false => rawValues.Select(rv => Scale(rv, modeInfo.RawMin, modeInfo.RawMax, modeInfo.PctMin, modeInfo.PctMax)).Select(f => ConvertSByteValueFromFloat(f)).ToArray(), + false => rawValues.Select(rv => Scale(rv, modeInfo.RawMin, modeInfo.RawMax, modeInfo.PctMin, modeInfo.PctMax)).Select(f => Convert.ToSByte(f)).ToArray(), true => new sbyte[rawValues.Length], }; @@ -93,23 +93,6 @@ internal static PortValueData CreatePortValueDataSByte(PortModeInfo modeI }; } - internal static sbyte ConvertSByteValueFromFloat(float value) - { - if (value >= sbyte.MinValue && value <= sbyte.MaxValue) - { - return Convert.ToSByte(value); - } - - // If we get a value higher than the sbyte, clamp it at the maximum value (127) or minimum value (-127) - // This can occur sometimes when a value returned exceeds expected min/max and trying to convert to a percentage - - if (value > sbyte.MaxValue) - { - return sbyte.MaxValue; - } - return sbyte.MinValue; - } - internal static PortValueData CreatePortValueDataInt16(PortModeInfo modeInfo, in Span dataSlice) { var rawValues = MemoryMarshal.Cast(dataSlice).ToArray(); diff --git a/src/SharpBrick.PoweredUp/Protocol/Messages/PortOutputCommandMessage.cs b/src/SharpBrick.PoweredUp/Protocol/Messages/PortOutputCommandMessage.cs index a677c26..2eec7ea 100644 --- a/src/SharpBrick.PoweredUp/Protocol/Messages/PortOutputCommandMessage.cs +++ b/src/SharpBrick.PoweredUp/Protocol/Messages/PortOutputCommandMessage.cs @@ -193,13 +193,6 @@ public PortOutputCommandTiltConfigImpactMessage() : base(0x06) { } public sbyte BumpHoldoff { get; set; } } - // spec chapter: 3.27.18 - public class PortOutputCommandTiltFactoryCalibrationMessage : PortOutputCommandWriteDirectModeDataMessage - { - public PortOutputCommandTiltFactoryCalibrationMessage() : base(0x07) { } - public TiltFactoryOrientation Orientation { get; set; } - } - // spec chapter: 3.27.19 public class PortOutputCommandGenericZeroSetHardwareMessage : PortOutputCommandWriteDirectMessage { }