-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#161 non-breaking
- Loading branch information
Showing
6 changed files
with
364 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using System.Threading.Tasks; | ||
using SharpBrick.PoweredUp.Deployment; | ||
|
||
namespace SharpBrick.PoweredUp.TestScript | ||
{ | ||
public interface ITestScript | ||
{ | ||
void DefineDeploymentModel(DeploymentModelBuilder builder); | ||
Task ExecuteScriptAsync(Hub hub, TestScriptExecutionContext context); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Logging; | ||
using SharpBrick.PoweredUp.Deployment; | ||
using SharpBrick.PoweredUp.Hubs; | ||
|
||
namespace SharpBrick.PoweredUp.TestScript | ||
{ | ||
class Program | ||
{ | ||
static async Task Main(string[] args) | ||
{ | ||
var serviceProvider = new ServiceCollection() | ||
.AddLogging(builder => | ||
{ | ||
builder.AddConsole(); | ||
}) | ||
.AddPoweredUp() | ||
.AddWinRTBluetooth() // using WinRT Bluetooth on Windows (separate NuGet SharpBrick.PoweredUp.WinRT) | ||
.BuildServiceProvider(); | ||
|
||
var host = serviceProvider.GetService<PoweredUpHost>(); | ||
|
||
IEnumerable<ITestScript> scripts = new ITestScript[] { | ||
new TechnicMotorTestScript<TechnicLargeLinearMotor>(), | ||
}; | ||
|
||
var context = new TestScriptExecutionContext(serviceProvider.GetService<ILogger<TestScriptExecutionContext>>()); | ||
|
||
foreach (var script in scripts) | ||
{ | ||
// Test Script | ||
context.Log.LogInformation($"Execute Script {script.GetType().Name}"); | ||
|
||
// build deployment model | ||
var model = BbuildDeploymentModel(script); | ||
PrintModel(context, model); | ||
|
||
// Accept to execute Test Script | ||
var executeTest = await context.ConfirmAsync("> Confirm to execute Test Script"); | ||
|
||
if (executeTest) | ||
{ | ||
context.Log.LogInformation("> Discovering & Connecting Hub"); | ||
var hubType = HubFactory.GetTypeFromSystemType(model.Hubs[0].HubType ?? throw new InvalidOperationException("Specify the hub type in the test script.")); | ||
using var hub = await host.DiscoverAsync(hubType); | ||
await hub.ConnectAsync(); | ||
|
||
context.Log.LogInformation("> Verifying Deployment Model (fix it if necessary)"); | ||
await hub.VerifyDeploymentModelAsync(model); | ||
|
||
context.Log.LogInformation("> Start Test Script"); | ||
await script.ExecuteScriptAsync(hub, context); | ||
|
||
context.Log.LogInformation("> Switch Off Hub"); | ||
await hub.SwitchOffAsync(); | ||
} | ||
else | ||
{ | ||
context.Log.LogWarning($"> User decided not to execute Test Script"); | ||
} | ||
} | ||
|
||
} | ||
|
||
private static void PrintModel(TestScriptExecutionContext context, DeploymentModel model) | ||
{ | ||
context.Log.LogInformation($"> Deployment Model of Test Script"); | ||
|
||
foreach (var hub in model.Hubs) | ||
{ | ||
context.Log.LogInformation($" > Hub: {hub.HubType}"); | ||
|
||
foreach (var device in hub.Devices) | ||
{ | ||
context.Log.LogInformation($" > Device: {device.DeviceType} @ {device.PortId}"); | ||
} | ||
} | ||
} | ||
|
||
private static DeploymentModel BbuildDeploymentModel(ITestScript script) | ||
{ | ||
var builder = new DeploymentModelBuilder(); | ||
script.DefineDeploymentModel(builder); | ||
var model = builder.Build(); | ||
return model; | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
test/SharpBrick.PoweredUp.TestScript/SharpBrick.PoweredUp.TestScript.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net5.0-windows10.0.19041.0</TargetFramework> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\src\SharpBrick.PoweredUp\SharpBrick.PoweredUp.csproj" /> | ||
<ProjectReference Include="..\..\src\SharpBrick.PoweredUp.WinRT\SharpBrick.PoweredUp.WinRT.csproj" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" /> | ||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" /> | ||
</ItemGroup> | ||
|
||
</Project> |
181 changes: 181 additions & 0 deletions
181
test/SharpBrick.PoweredUp.TestScript/TechnicMotorTestScript.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
using System; | ||
using System.Reactive.Linq; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.Logging; | ||
using SharpBrick.PoweredUp.Deployment; | ||
|
||
namespace SharpBrick.PoweredUp.TestScript | ||
{ | ||
public class TechnicMotorTestScript<TTechnicMotor> : ITestScript where TTechnicMotor : AbsoluteMotor, IPoweredUpDevice | ||
{ | ||
public void DefineDeploymentModel(DeploymentModelBuilder builder) | ||
=> builder.AddHub<TechnicMediumHub>(hubBuilder => | ||
{ | ||
hubBuilder.AddDevice<TTechnicMotor>(0); | ||
}); | ||
|
||
public async Task ExecuteScriptAsync(Hub hub, TestScriptExecutionContext context) | ||
{ | ||
var motor = hub.Port(0).GetDevice<TTechnicMotor>(); | ||
|
||
await motor.GotoRealZeroAsync(); | ||
await Task.Delay(2000); | ||
await motor.SetZeroAsync(); | ||
|
||
// TestCase: AbsoluteMotorReportsAbsolutePosition | ||
await motor.TryLockDeviceForCombinedModeNotificationSetupAsync(motor.ModeIndexAbsolutePosition, motor.ModeIndexPosition); | ||
await motor.SetupNotificationAsync(motor.ModeIndexPosition, true, 2); | ||
await motor.SetupNotificationAsync(motor.ModeIndexAbsolutePosition, true, 2); | ||
await motor.UnlockFromCombinedModeNotificationSetupAsync(true); | ||
|
||
await context.ConfirmAsync("AbsoluteMotor.GotoRealZeroAsync: Is in zero position? Adjust Beam to 0°?"); | ||
|
||
await TestCase1_TachoMotorPositionByDegreesAsync(context, motor); | ||
|
||
await TestCase2_TachoMotorExplicitPositionAsync(context, motor); | ||
|
||
await TestCase3_TachoMotorHighSpeedAndFloatingAsync(context, motor); | ||
|
||
await TestCase4_TachoMotorPositiveNegativeSpeedForTimeAsync(context, motor); | ||
|
||
await TestCase5_TachoMotorAccelerationAsync(context, motor); | ||
|
||
await TestCase6_BasicMotorAsync(context, motor); | ||
|
||
await TestCase7_InputAsync(context, motor); | ||
} | ||
|
||
private static async Task TestCase1_TachoMotorPositionByDegreesAsync(TestScriptExecutionContext context, TTechnicMotor motor) | ||
{ | ||
context.Log.LogInformation("TachoMotor: Testing positioning by degress"); | ||
|
||
await motor.StartSpeedForDegreesAsync(45, 10, 100); | ||
await Task.Delay(2000); | ||
context.Assert(motor.AbsolutePosition, 42, 48); | ||
context.Assert(motor.Position, 42, 48); | ||
|
||
await motor.StartSpeedForDegreesAsync(45, 10, 100); | ||
await Task.Delay(2000); | ||
context.Assert(motor.AbsolutePosition, 87, 93); | ||
context.Assert(motor.Position, 87, 93); | ||
|
||
await motor.StartSpeedForDegreesAsync(45, 10, 100); | ||
await Task.Delay(2000); | ||
context.Assert(motor.AbsolutePosition, 132, 138); | ||
context.Assert(motor.Position, 132, 138); | ||
|
||
await motor.StartSpeedForDegreesAsync(45, 10, 100); | ||
await Task.Delay(2000); | ||
context.Assert(Math.Abs(motor.AbsolutePosition), 177, 180); | ||
context.Assert(motor.Position, 177, 183); | ||
|
||
await context.ConfirmAsync("TachoMotor.StartSpeedForDegreesAsync: Has moved 40 times CW each by 45°?"); | ||
} | ||
|
||
private static async Task TestCase2_TachoMotorExplicitPositionAsync(TestScriptExecutionContext context, TTechnicMotor motor) | ||
{ | ||
context.Log.LogInformation("TachoMotor: Testing explicit position from TachoMotor.SetZero"); | ||
|
||
await motor.GotoPositionAsync(360, 10, 100); | ||
await Task.Delay(2000); | ||
context.Assert(motor.AbsolutePosition, -3, 3); | ||
context.Assert(motor.Position, 357, 363); | ||
|
||
await context.ConfirmAsync("TachoMotor.GotoPositionAsync: has moved CW to zero position?"); | ||
|
||
await motor.GotoPositionAsync(810, 10, 100); | ||
await Task.Delay(4000); | ||
context.Assert(motor.AbsolutePosition, 87, 93); | ||
context.Assert(motor.Position, 807, 813); | ||
|
||
await context.ConfirmAsync("TachoMotor.GotoPositionAsync: Motor has moved CW by 360° + 90° and is exaclty 90° off zero?"); | ||
} | ||
|
||
private static async Task TestCase3_TachoMotorHighSpeedAndFloatingAsync(TestScriptExecutionContext context, TTechnicMotor motor) | ||
{ | ||
context.Log.LogInformation("TachoMotor: High different Speed and Floating"); | ||
|
||
await motor.StartSpeedForDegreesAsync(810, -100, 100, SpecialSpeed.Float); | ||
await Task.Delay(2000); | ||
|
||
await context.ConfirmAsync("TachoMotor.StartSpeedForDegreesAsync: High speed CCW turn with floating end state?"); | ||
|
||
await ResetToZeroAsync(context, motor, 2000); | ||
} | ||
|
||
private static async Task TestCase4_TachoMotorPositiveNegativeSpeedForTimeAsync(TestScriptExecutionContext context, TTechnicMotor motor) | ||
{ | ||
context.Log.LogInformation("TachoMotor: Positive and Negative Speeds and for Time"); | ||
|
||
await motor.StartSpeedForTimeAsync(1000, 10, 100); | ||
await Task.Delay(2000); | ||
|
||
await context.ConfirmAsync("TachoMotor.StartSpeedForTimeAsync: CW for 1s?"); | ||
|
||
await motor.StartSpeedForTimeAsync(1000, -10, 100); | ||
await Task.Delay(2000); | ||
|
||
await context.ConfirmAsync("TachoMotor.StartSpeedForTimeAsync: CCW for 1s?"); | ||
|
||
await ResetToZeroAsync(context, motor, 3000); | ||
} | ||
|
||
private static async Task TestCase5_TachoMotorAccelerationAsync(TestScriptExecutionContext context, TTechnicMotor motor) | ||
{ | ||
context.Log.LogInformation("TachoMotor: Acceleration Profiles"); | ||
|
||
await motor.SetAccelerationTimeAsync(500); | ||
await motor.SetDecelerationTimeAsync(500); | ||
|
||
await motor.StartSpeedForTimeAsync(2000, 50, 100, SpecialSpeed.Brake, SpeedProfiles.AccelerationProfile | SpeedProfiles.DecelerationProfile); | ||
await Task.Delay(4000); | ||
|
||
await context.ConfirmAsync("TachoMotor.SetAccelerationTimeAsync: CW 0.5s each slow start and end?"); | ||
|
||
await ResetToZeroAsync(context, motor, 20_000); | ||
} | ||
|
||
private static async Task TestCase6_BasicMotorAsync(TestScriptExecutionContext context, TTechnicMotor motor) | ||
{ | ||
context.Log.LogInformation("TachoMotor: Start Speed & Power"); | ||
|
||
await motor.StartPowerAsync(100); | ||
await Task.Delay(1000); | ||
await motor.StopByBrakeAsync(); | ||
await motor.StartPowerAsync(-100); | ||
await Task.Delay(1000); | ||
await motor.StopByFloatAsync(); | ||
|
||
await context.ConfirmAsync("TachoMotor.StartPowerAsync: CW for 1s, brake, CCW for 1s, floating?"); | ||
|
||
await ResetToZeroAsync(context, motor, 3000); | ||
} | ||
|
||
private async Task TestCase7_InputAsync(TestScriptExecutionContext context, TTechnicMotor motor) | ||
{ | ||
context.Log.LogInformation("AbsoluteMotor: Input on Absolute and relative Position"); | ||
|
||
context.Log.LogInformation("Turn 90° clockwise"); | ||
|
||
await motor.AbsolutePositionObservable.Where(x => x.SI > 85 && x.SI < 95).FirstAsync().GetAwaiter(); | ||
|
||
context.Log.LogInformation("Turn 180° counter-clockwise"); | ||
|
||
await motor.AbsolutePositionObservable.Where(x => x.SI < -85 && x.SI > -95).FirstAsync().GetAwaiter(); | ||
|
||
context.Log.LogInformation("Turn 90° counter-clockwise"); | ||
|
||
await motor.PositionObservable.Where(x => x.SI < -175 && x.SI > -185).FirstAsync().GetAwaiter(); | ||
} | ||
|
||
private static async Task ResetToZeroAsync(TestScriptExecutionContext context, TTechnicMotor motor, int expectedTime) | ||
{ | ||
await motor.GotoPositionAsync(0, 10, 100); | ||
await Task.Delay(expectedTime); | ||
context.Assert(motor.AbsolutePosition, -3, 3); | ||
context.Assert(motor.Position, -3, 3); | ||
|
||
await context.ConfirmAsync("TachoMotor.GotoPositionAsync: has moved to zero position?"); | ||
} | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
test/SharpBrick.PoweredUp.TestScript/TestScriptExecutionContext.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace SharpBrick.PoweredUp.TestScript | ||
{ | ||
public class TestScriptExecutionContext | ||
{ | ||
public TestScriptExecutionContext(ILogger log) | ||
{ | ||
Log = log ?? throw new ArgumentNullException(nameof(log)); | ||
} | ||
|
||
public ILogger Log { get; } | ||
public Hub CurrentHub { get; set; } | ||
|
||
public async Task<bool> ConfirmAsync(string question) | ||
{ | ||
Console.Write(question + " (Y/n)"); | ||
|
||
var confirm = Console.ReadLine().Trim().ToUpperInvariant() != "N"; | ||
|
||
if (confirm) | ||
{ | ||
Log.LogInformation($"[OK] by User: {question}"); | ||
} | ||
else | ||
{ | ||
Log.LogError($"[FAIL] by User {question}"); | ||
} | ||
|
||
return confirm; | ||
} | ||
|
||
public void Assert(int value, int min, int max) | ||
{ | ||
if (value >= min && value <= max) | ||
{ | ||
Log.LogInformation($"[OK] by Assert within expectations: {min} <= {value} <= {max}"); | ||
} | ||
else | ||
{ | ||
Log.LogError($"[FAIL] by Assert outside expectations: {min} <= {value} <= {max}"); | ||
} | ||
} | ||
} | ||
} |