Skip to content

Commit

Permalink
Merge branch 'master' into issue-57-rampup
Browse files Browse the repository at this point in the history
  • Loading branch information
tthiery committed Dec 23, 2020
2 parents 529a87d + 6f7980b commit e7ba9a8
Show file tree
Hide file tree
Showing 87 changed files with 2,738 additions and 350 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ jobs:
with:
dotnet-version: 3.1.100
- name: Build Version
run: echo ::set-env name=RELEASE_VERSION::$(echo ${GITHUB_REF:11})
# run: echo ::set-env name=RELEASE_VERSION::$(echo ${GITHUB_REF:11}) // deprecated
run: echo "RELEASE_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV
- name: Build Project
run: dotnet build --configuration Release -p:Version=$RELEASE_VERSION
- name: Test Project
Expand Down
28 changes: 28 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,34 @@
"console": "integratedTerminal",
"stopAtEntry": false
},
{
"name": "poweredup device pretty-print --t 128 --h 0 --p 100 --io 0036 --hw 1.0.0.2 --sw 1.0.0.3 --file test.txt",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/src/SharpBrick.PoweredUp.Cli/bin/Debug/netcoreapp3.1/SharpBrick.PoweredUp.Cli.dll",
"args": [
"device",
"pretty-print",
"--t",
"128",
"--h",
"0",
"--io",
"0036",
"--p",
"100",
"--hw",
"1.0.0.2",
"--sw",
"1.0.0.3",
"--file",
"test.txt"
],
"cwd": "${workspaceFolder}/src/SharpBrick.PoweredUp.Cli",
"console": "integratedTerminal",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
Expand Down
121 changes: 82 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SharpBrick.PoweredUp

SharpBrick.PoweredUp is a .NET implementation of the Bluetooth Low Energy Protocol for Lego Powered Up products.
SharpBrick.PoweredUp is a .NET implementation of the Bluetooth Low Energy Protocol for Lego Powered UP products.

[![Nuget](https://img.shields.io/nuget/v/SharpBrick.PoweredUp?style=flat-square)](https://www.nuget.org/packages/SharpBrick.PoweredUp/)
![license:MIT](https://img.shields.io/github/license/sharpbrick/powered-up?style=flat-square)
Expand Down Expand Up @@ -28,7 +28,6 @@ Additional to code fragments below, look into the `examples/SharpBrick.PoweredUp

````csharp
using SharpBrick.PoweredUp;
using SharpBrick.PoweredUp.WinRT; // for WinRT Bluetooth NuGet
````

## Discovering Hubs
Expand All @@ -37,12 +36,12 @@ using SharpBrick.PoweredUp.WinRT; // for WinRT Bluetooth NuGet
var serviceProvider = new ServiceCollection()
.AddLogging()
.AddPoweredUp()
.AddSingleton<IPoweredUpBluetoothAdapter, WinRTPoweredUpBluetoothAdapter>() // using WinRT Bluetooth on Windows
.AddWinRTBluetooth() // using WinRT Bluetooth on Windows (separate NuGet SharpBrick.PoweredUp.WinRT)
.BuildServiceProvider();

var host = serviceProvider.GetService<PoweredUpHost>();

var hub = await host.DiscoverAsync<TechnicMediumHub>(); // starting version 2.1
var hub = await host.DiscoverAsync<TechnicMediumHub>();
await hub.ConnectAsync();
````

Expand Down Expand Up @@ -70,7 +69,7 @@ See source code in `examples/SharpBrick.PoweredUp.Examples` for more examples.
using (var technicMediumHub = hub as TechnicMediumHub)
{
// optionally verify if everything is wired up correctly (v2.0 onwards)
// optionally verify if everything is wired up correctly
await technicMediumHub.VerifyDeploymentModelAsync(modelBuilder => modelBuilder
.AddHub<TechnicMediumHub>(hubBuilder => hubBuilder
.AddDevice<TechnicXLargeLinearMotor>(technicMediumHub.A)
Expand All @@ -81,9 +80,9 @@ using (var technicMediumHub = hub as TechnicMediumHub)

var motor = technicMediumHub.A.GetDevice<TechnicXLargeLinearMotor>();

await motor.GotoAbsolutePositionAsync(45, 10, 100, PortOutputCommandSpecialSpeed.Brake, PortOutputCommandSpeedProfile.None);
await motor.GotoPositionAsync(45, 10, 100, PortOutputCommandSpecialSpeed.Brake);
await Task.Delay(2000);
await motor.GotoAbsolutePositionAsync(-45, 10, 100, PortOutputCommandSpecialSpeed.Brake, PortOutputCommandSpeedProfile.None);
await motor.GotoPositionAsync(-45, 10, 100, PortOutputCommandSpecialSpeed.Brake);

await technicMediumHub.SwitchOffAsync();
}
Expand All @@ -105,19 +104,8 @@ disposable.Dispose();
Console.WriteLine(motor.AbsolutePosition);
````

## Little Helpers

````csharp
using SharpBrick.PoweredUp;
using static SharpBrick.PoweredUp.Directions; // CW & CCW starting version 2.1
await motor.GotoAbsolutePositionAsync(CW * 45, 10, 100, SpecialSpeed.Brake, SpeedProfiles.None);
````

## Connecting to an unknown device

***Note:** Starting version 2.0*

````csharp
// deployment model verification with unknown devices
await technicMediumHub.VerifyDeploymentModelAsync(mb => mb
Expand Down Expand Up @@ -158,12 +146,14 @@ Console.WriteLine($"Or directly read the latest value: {aposMode.SI} / {aposMode

## Connect to Hub and Send a Message and retrieving answers (directly on protocol layer)

***Note**: The `ILegoWirelessProtocol` class was renamed in 3.0. Previously it is known as `IPoweredUpProtocol`.*

````csharp

var serviceProvider = new ServiceCollection()
.AddLogging()
.AddPoweredUp()
.AddSingleton<IPoweredUpBluetoothAdapter, WinRTPoweredUpBluetoothAdapter>() // using WinRT Bluetooth on Windows
.AddWinRTBluetooth() // using WinRT Bluetooth on Windows (separate NuGet SharpBrick.PoweredUp.WinRT)
.BuildServiceProvider();

using (var scope = serviceProvider.CreateScope()) // create a scoped DI container per intented active connection/protocol. If disposed, disposes all disposable artifacts.
Expand Down Expand Up @@ -196,12 +186,40 @@ using (var scope = serviceProvider.CreateScope()) // create a scoped DI containe

// fun with motor on hub 0 and port 0
var motor = new TechnicXLargeLinearMotor(protocol, 0, 0);
await motor.GotoAbsolutePositionAsync(45, 10, 100, PortOutputCommandSpecialSpeed.Brake, PortOutputCommandSpeedProfile.None);
await motor.GotoPositionAsync(45, 10, 100, PortOutputCommandSpecialSpeed.Brake);
await Task.Delay(2000);
await motor.GotoAbsolutePositionAsync(-45, 10, 100, PortOutputCommandSpecialSpeed.Brake, PortOutputCommandSpeedProfile.None);
await motor.GotoPositionAsync(-45, 10, 100, PortOutputCommandSpecialSpeed.Brake);
}
````

# Command Line Experience

The `poweredup` command line utility intends to allow the inspection of LEGO Wireless Protocol / Powered UP hubs and devices for their properties. It has utilities for ...

- **Enumerating all connected Devices** including hub internal devices and emit their static self-description as they expose using the LEGO Wireless Protocol.
````
poweredup device list
````
- **Binary dumping the self-description** helps protocol implementors with a lack of devices to understand and try to implement the devices without having the physical device. Also the output is needed when programming the library to enable a fast bootup of the SDK.
````
poweredup device dump-static-port -p 0
````
- **Pretty Print Binary Dumps**: Help to convert a binary dump in a nice representation.

***Note**: Currently only Windows based WinRT Bluetooth drivers are available. Work is on the way to support bluez to run the utility also on Linux.*

## Installation Instruction

1. Install the [latest .NET (Core)](https://dotnet.microsoft.com/download) on your machine (e.g. .NET Core 3.1).
2. Install the `poweredup` dotnet utility using the following instruction
````
dotnet tools install -g SharpBrick.PoweredUp.Cli
````
3. Start using the tool
````
poweredup device list
````

# SDK Status, Hardware Support, Contributions, ..

Basic Architecture within the SDK
Expand Down Expand Up @@ -245,7 +263,7 @@ DI Container Elements
- [X] .NET Core 3.1 (on Windows 10 using WinRT)
- Library uses `Span<T>` / C# 8.0 and is therefore not supported in .NET Framework 1.0 - 4.8 and UWP Apps until arrival of .NET 5 (WinForms and WPF work in .NET Core 3.1)
- Library uses WinRT for communication therefore only Windows 10
- [ ] Xamarin (on iOS / Android using Xamarin.Essentials)
- [ ] Xamarin (on iOS / Android using ?)
- [ ] Blazor (on Browser using WebBluetooth)
- Hub Model
- Hubs
Expand All @@ -254,32 +272,53 @@ DI Container Elements
- [X] Alerts
- [X] Actions
- [X] Create Virtual Ports
- [X] Technic Medium Hub
- [ ] Hub (88009)
- [X] Two Port Hub (88009)
- [X] Two Port Handset (88010)
- [X] Technic Medium Hub (88012)
- [X] MarioHub (set 71360)
- [X] Duplo Train Base (set 10874)
- .. other hubs depend on availability of hardware / contributions
- Devices
- [X] Technic Medium Hub - Rgb Light
- [X] Technic Medium Hub - Current
- [X] Technic Medium Hub - Voltage
- [X] Technic Medium Hub - Temperature Sensor 1 + 2
- [X] Technic Medium Hub - Accelerometer
- [X] Technic Medium Hub - Gyro Sensor
- [X] Technic Medium Hub - Tilt Sensor
- [ ] Technic Medium Hub - Gesture Sensor
- [X] Technic XLarge Motor
- [X] Technic Large Motor
- [ ] Technic Angular Motor (depend on availability of hardware / contributions)
- [ ] Hub (88009) - Rgb Light
- [ ] Hub (88009) - Current
- [ ] Hub (88009) - Voltage
- [X] Technic Medium Hub (88012) - Rgb Light
- [X] Technic Medium Hub (88012) - Current
- [X] Technic Medium Hub (88012) - Voltage
- [X] Technic Medium Hub (88012) - Temperature Sensor 1 + 2
- [X] Technic Medium Hub (88012) - Accelerometer
- [X] Technic Medium Hub (88012) - Gyro Sensor
- [X] Technic Medium Hub (88012) - Tilt Sensor
- [X] Technic Medium Hub (88012) - Gesture Sensor (⚠ Usable but Gesture mapping is pending)
- [X] Hub (88009) - Rgb Light
- [X] Hub (88009) - Current
- [X] Hub (88009) - Voltage
- [X] Mario Hub (set 71360) - Accelerometer (Raw & Gesture) (⚠ Usable but Gesture mapping is a rough draft)
- [X] Mario Hub (set 71360) - TagSensor (Barcode & RGB)
- [X] Mario Hub (set 71360) - Pants
- [ ] Mario Hub (set 71360) - Debug
- [X] Duplo Train Base (set 10874) - Motor
- [X] Duplo Train Base (set 10874) - Speaker
- [X] Duplo Train Base (set 10874) - Rgb Light
- [X] Duplo Train Base (set 10874) - ColorSensor
- [X] Duplo Train Base (set 10874) - Speedometer
- [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)
- [ ] Technic Medium Angular Motor (Spike)
- [X] Technic Medium Angular Motor (Grey)
- [ ] Technic Large Angular Motor (Spike)
- [X] Technic Large Angular Motor (Grey)
- [ ] Technic Color Sensor
- [ ] Technic Distance Sensor
- .. other devices depend on availability of hardware / contributions
- Protocol
- [X] Message Encoding (98% [spec coverage](docs/specification/coverage.md))
- [X] Knowledge
- Features
- [X] Dynamic Device
- [X] Deployment Verifier
- Command Line (`dotnet install -g SharpBrick.PoweredUp.Cli`)
- Command Line (`dotnet tool install -g SharpBrick.PoweredUp.Cli`)
- [X] `poweredup device list` (discover all connected devices and their port (mode) properties)
- [X] `poweredup device dump-static-port -p <port number>` (see [adding new devices tutorial](docs/development/adding-new-device.md))

Expand Down Expand Up @@ -307,3 +346,7 @@ DI Container Elements
SharpBrick is an organization intended to host volunteers willing to contribute to the SharpBrick.PoweredUp and related projects. Everyone is welcome (private and commercial entities). Please read our **[Code of Conduct](CODE_OF_CONDUCT.md)** before participating in our project.

The product is licensed under **MIT License** to allow a easy and wide adoption into prviate and commercial products.

## Thanks ...

Thanks to [@nathankellenicki](https://github.com/nathankellenicki), [@corneliusmunz](https://github.com/corneliusmunz) and [@vuurbeving](https://github.com/vuurbeving) for their code, answers, testing and other important contributions.
71 changes: 71 additions & 0 deletions examples/SharpBrick.PoweredUp.Examples/ExampleDuploTrainBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using SharpBrick.PoweredUp;

namespace Example
{
public class ExampleDuploTrainBase : BaseExample
{
public override async Task ExecuteAsync()
{
using (var train = Host.FindByType<DuploTrainBaseHub>())
{
await train.VerifyDeploymentModelAsync(modelBuilder => modelBuilder
.AddHub<DuploTrainBaseHub>(hubBuilder => { })
);

using var d1 = train.Voltage.VoltageSObservable.Subscribe(x => Log.LogWarning($"Voltage: {x.Pct}% / {x.SI}"));
using var d2 = train.Motor.OnSecondsObservable.Subscribe(x => Log.LogWarning($"Seconds: {x}"));
using var d3 = train.Speedometer.SpeedObservable.Subscribe(x => Log.LogWarning($"Speed: {x.Pct}% / {x.SI}"));
using var d4 = train.Speedometer.CountObservable.Subscribe(x => Log.LogWarning($"Count: {x}"));
using var d5 = train.ColorSensor.ColorObservable.Subscribe(x => Log.LogWarning($"Color: {x}"));
using var d6 = train.ColorSensor.ColorTagObservable.Subscribe(x => Log.LogWarning($"Color Tag: {x}")); // does not work
using var d7 = train.ColorSensor.ReflectionObservable.Subscribe(x => Log.LogWarning($"Reflection: {x}"));
using var d8 = train.ColorSensor.RgbObservable.Subscribe(x => Log.LogWarning($"RGB {x.red}/{x.green}/{x.blue}"));

await train.Voltage.SetupNotificationAsync(train.Voltage.ModeIndexVoltageS, true);

// Motor: motor can either be queried for seconds active OR be instructed to run
//await train.Motor.SetupNotificationAsync(train.Motor.ModeIndexOnSec, false);

await train.Speedometer.TryLockDeviceForCombinedModeNotificationSetupAsync(train.Speedometer.ModeIndexSpeed, train.Speedometer.ModeIndexCount);
await train.Speedometer.SetupNotificationAsync(train.Speedometer.ModeIndexSpeed, true, deltaInterval: 1);
await train.Speedometer.SetupNotificationAsync(train.Speedometer.ModeIndexCount, true, deltaInterval: 1);
await train.Speedometer.UnlockFromCombinedModeNotificationSetupAsync(true);

// ColorSensor: either this combination
// await train.ColorSensor.TryLockDeviceForCombinedModeNotificationSetupAsync(train.ColorSensor.ModeIndexColor, train.ColorSensor.ModeIndexReflection, train.ColorSensor.ModeIndexRgb);
// await train.ColorSensor.SetupNotificationAsync(train.ColorSensor.ModeIndexColor, true, deltaInterval: 1);
// await train.ColorSensor.SetupNotificationAsync(train.ColorSensor.ModeIndexReflection, true, deltaInterval: 1);
// await train.ColorSensor.SetupNotificationAsync(train.ColorSensor.ModeIndexRgb, true, deltaInterval: 1);
// await train.ColorSensor.UnlockFromCombinedModeNotificationSetupAsync(true);

// ColorSensor: or standalone
await train.ColorSensor.SetupNotificationAsync(train.ColorSensor.ModeIndexColorTag, true, deltaInterval: 1);

await train.Speaker.PlaySoundAsync(DuploTrainBaseSound.Horn);
await train.RgbLight.SetRgbColorNoAsync(PoweredUpColor.Red);
await Task.Delay(1_000);
await train.RgbLight.SetRgbColorNoAsync(PoweredUpColor.Yellow);
await Task.Delay(1_000);
await train.RgbLight.SetRgbColorNoAsync(PoweredUpColor.Green);
await train.Speaker.PlaySoundAsync(DuploTrainBaseSound.StationDeparture);

await train.Motor.StartPowerAsync(40);
await Task.Delay(3_000);
await train.Speaker.PlaySoundAsync(DuploTrainBaseSound.Steam);
await train.Motor.StartPowerAsync(-40);
await Task.Delay(3_000);
await train.Speaker.PlaySoundAsync(DuploTrainBaseSound.Brake);
await train.Motor.StopByFloatAsync();
await Task.Delay(1_000);
await train.Speaker.PlaySoundAsync(DuploTrainBaseSound.WaterRefill);

await Task.Delay(1_000);

await train.SwitchOffAsync();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using SharpBrick.PoweredUp;

namespace Example
{
public class ExampleMarioAccelerometer : BaseExample
{
public override async Task ExecuteAsync()
{
using (var mario = Host.FindByType<MarioHub>())
{
await mario.VerifyDeploymentModelAsync(modelBuilder => modelBuilder
.AddHub<MarioHub>(hubBuilder => { })
);

var d1 = mario.Accelerometer.GestureObservable.Subscribe(x => Log.LogWarning($"Gesture: {x[0]}/{x[1]}"));

await mario.Accelerometer.SetupNotificationAsync(mario.Accelerometer.ModeIndexGesture, true);

await Task.Delay(20_000);

d1.Dispose();

await mario.SwitchOffAsync();
}
}
}
}
Loading

0 comments on commit e7ba9a8

Please sign in to comment.