Skip to content

Commit

Permalink
FakePlcV2 support GetMetric. Tested DeviceMetricBoard.
Browse files Browse the repository at this point in the history
  • Loading branch information
hcoona committed Dec 10, 2019
1 parent bf098b1 commit 39d893b
Show file tree
Hide file tree
Showing 14 changed files with 177 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,35 @@ private void BackgroundTaskEntryPoint()
byte[] content = contentLength == 0 ? Array.Empty<byte>() : reader.ReadBytes(contentLength);

var messageType = (PlcMessageType)BinaryPrimitives.ReadUInt16BigEndian(header.AsSpan(0x06, 2));
PlcFrame responseFrame = null;
if (messageType == PlcMessageType.ConnectRequest)
PlcFrame responseFrame;
switch (messageType)
{
responseFrame = PlcFrame.Create(
PlcMessageType.ConnectResponse,
ByteString.CopyFrom(PhysicalAddress.Parse("10BF4879B2A4").GetAddressBytes()));
case PlcMessageType.ConnectRequest:
responseFrame = PlcFrame.Create(
PlcMessageType.ConnectResponse,
ByteString.CopyFrom(PhysicalAddress.Parse("10BF4879B2A4").GetAddressBytes()));
break;
case PlcMessageType.GetMetricRequest:
byte[] responseContent = new byte[0x20];
using (var writer = new BinaryWriter(new MemoryStream(responseContent)))
{
writer.Write(11F);
writer.Write(13F);
writer.Write(17F);
writer.Write(19F);
writer.Write(23F);
writer.Write(29F);
writer.Write(31F);
writer.Write(37F);
}

responseFrame = PlcFrame.Create(
PlcMessageType.GetMetricResponse,
ByteString.CopyFrom(responseContent));
break;
default:
responseFrame = null;
break;
}

if (responseFrame == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,14 @@ public void Dispose()
GC.SuppressFinalize(this);
}

public async void Close()
public async Task Close()
{
if (!this.closingCancellationTokenSource.IsCancellationRequested)
{
this.closingCancellationTokenSource.Cancel();
this.requestContextSendingBufferBlock.Complete();
this.tcpClient.Close();

this.OnClosed?.Invoke(this, EventArgs.Empty);

await this.sendingBackgroundTask.ConfigureAwait(false);
Expand All @@ -102,10 +103,12 @@ protected virtual void Dispose(bool disposing)
{
if (disposing)
{
this.Close();
this.Close().ConfigureAwait(false).GetAwaiter().GetResult();

this.sendingBackgroundTask.Dispose();
this.receivingBackgroundTask.Dispose();
this.deadlineBackgroundTask.Dispose();

this.tcpClient.Dispose();
this.closingCancellationTokenSource.Dispose();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ private void ReceivingBackgroundTaskEntryPoint()
catch (IOException e)
{
this.logger.LogError(e, "Failed to receiving from {0}", this.RemoteEndPoint);
this.Close();
this.Close().ConfigureAwait(false).GetAwaiter().GetResult();
}
catch (InvalidDataException e)
{
this.logger.LogError(e, "Received invalid data from {0}", this.RemoteEndPoint);
this.Close();
this.Close().ConfigureAwait(false).GetAwaiter().GetResult();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ private async void SendingBackgroundTaskEntryPoint()
catch (IOException e)
{
this.logger.LogError(e, "Failed to send message to {0}", this.RemoteEndPoint);
this.Close();
this.Close().ConfigureAwait(false).GetAwaiter().GetResult();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using GeothermalResearchInstitute.PlcV2;
using GeothermalResearchInstitute.ServerConsole.Models;
using GeothermalResearchInstitute.v2;
using Google.Protobuf;
Expand Down Expand Up @@ -111,5 +112,22 @@ from e in g.DefaultIfEmpty()

return Task.FromResult(response);
}

public override Task<GrpcDeviceMetrics> GetMetric(GetMetricRequest request, ServerCallContext context)
{
if (request.DeviceId.IsEmpty)
{
throw new RpcException(new Status(StatusCode.InvalidArgument, "Must specify device_id."));
}

if (this.plcManager.PlcDictionary.TryGetValue(request.DeviceId, out PlcClient client))
{
return client.GetMetricAsync(request, context.Deadline);
}
else
{
throw new RpcException(new Status(StatusCode.NotFound, "Device is currently offline."));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public Task StartAsync(CancellationToken cancellationToken)

public Task StopAsync(CancellationToken cancellationToken)
{
return this.plcManager.StopAsync(cancellationToken);
return this.plcManager.StopAsync();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public Task StartAsync(CancellationToken cancellationToken)
return Task.CompletedTask;
}

public async Task StopAsync(CancellationToken cancellationToken)
public async Task StopAsync()
{
this.cancellationTokenSource.Cancel();
await this.backgroundTask.ConfigureAwait(false);
Expand All @@ -66,7 +66,7 @@ public async Task StopAsync(CancellationToken cancellationToken)
{
if (this.PlcDictionary.TryRemove(id, out PlcClient client))
{
client.Close();
await client.Close().ConfigureAwait(false);
client.Dispose();
}
}
Expand Down Expand Up @@ -122,7 +122,7 @@ private async void BackgroundTaskEntryPoint()
"Failed to add the client(MAC={0}, EndPoint={1}) into dictionary.",
BitConverter.ToString(response.Id.ToByteArray()),
client.RemoteEndPoint);
client.Close();
await client.Close().ConfigureAwait(false);
client.Dispose();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,5 @@ public override AsyncUnaryCall<Switch> UpdateSwitchAsync(UpdateSwitchRequest req
() => new Metadata(),
() => { });
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,45 @@

using System;
using System.Threading.Tasks;
using System.Windows.Threading;
using GeothermalResearchInstitute.v2;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Microsoft.Extensions.Logging;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;

namespace GeothermalResearchInstitute.Wpf.ViewModels
{
public class DeviceControlViewModel : BindableBase
public class DeviceControlViewModel : BindableBase, IRegionMemberLifetime, INavigationAware
{
private readonly DeviceService.DeviceServiceClient client;
private readonly ILogger<DeviceControlViewModel> logger;
private readonly DispatcherTimer timer;
private ViewModelContext viewModelContext;
private Switch switchInfo;
private Metric metric;
private DeviceService.DeviceServiceClient client;

public DeviceControlViewModel(DeviceService.DeviceServiceClient client)
public DeviceControlViewModel(
DeviceService.DeviceServiceClient client,
ILogger<DeviceControlViewModel> logger)
{
this.client = client ?? throw new ArgumentNullException(nameof(client));
this.SwitchOnClickCommand = new DelegateCommand<object>(this.ExecuteSwitchOnClickCommand);
this.SwitchOffClickCommand = new DelegateCommand<object>(this.ExecuteSwitchOffClickCommand);
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
this.timer = new DispatcherTimer(
TimeSpan.FromSeconds(1),
DispatcherPriority.DataBind,
this.Timer_Tick,
Dispatcher.CurrentDispatcher);

this.SwitchOnClickCommand = new DelegateCommand<string>(this.ExecuteSwitchOnClickCommand);
this.SwitchOffClickCommand = new DelegateCommand<string>(this.ExecuteSwitchOffClickCommand);
}

public DelegateCommand<object> SwitchOnClickCommand { get; }
public DelegateCommand<string> SwitchOnClickCommand { get; }

public DelegateCommand<object> SwitchOffClickCommand { get; }
public DelegateCommand<string> SwitchOffClickCommand { get; }

public ViewModelContext ViewModelContext
{
Expand All @@ -48,82 +63,80 @@ public Metric Metric
set
{
this.SetProperty(ref this.metric, value);
this.RaisePropertyChanged("WaterPump");
this.RaisePropertyChanged("HeaterWaterTemperature");
this.RaisePropertyChanged(nameof(this.WaterPump));
this.RaisePropertyChanged(nameof(this.HeaterWaterTemperature));
}
}

public bool HeaterWaterTemperature
{
get => this.Metric.HeaterOutputWaterCelsiusDegree - this.Metric.InputWaterCelsiusDegree > 0 ? true : false;
get => this.Metric.HeaterOutputWaterCelsiusDegree - this.Metric.InputWaterCelsiusDegree > 0;
}

public bool WaterPump
{
get => this.Metric.WaterPumpFlowRateCubicMeterPerHour > 0 ? true : false;
get => this.Metric.WaterPumpFlowRateCubicMeterPerHour > 0;
}

public async Task LoadMetricAsync()
public bool KeepAlive => false;

public bool IsNavigationTarget(NavigationContext navigationContext) => false;

public void OnNavigatedFrom(NavigationContext navigationContext)
{
Metric response = await this.client.GetMetricAsync(
new GetMetricRequest()
{
DeviceId = this.ViewModelContext.SelectedDevice.Id,
},
deadline: DateTime.UtcNow.AddMilliseconds(500));
this.Metric = response;
this.timer.Stop();
}

public async Task LoadSwitchAsync()
public void OnNavigatedTo(NavigationContext navigationContext)
{
this.timer.Start();
}

public async Task LoadMetricAsync()
{
Switch response = await this.client.GetSwitchAsync(
new GetSwitchRequest()
try
{
Metric response = await this.client.GetMetricAsync(
new GetMetricRequest()
{
DeviceId = this.ViewModelContext.SelectedDevice.Id,
},
deadline: DateTime.UtcNow.AddMilliseconds(500));
this.Switch = response;
this.Metric = response;
}
catch (RpcException e)
{
this.logger.LogError(
e,
"Failed to get switch for device {0}",
this.ViewModelContext.SelectedDevice.Id);
}
}

private async Task UpdateSwitchAsync(Switch s, FieldMask mask)
public async Task LoadSwitchAsync()
{
Switch response;
if (false)
{
response = s.Clone();
}
else
try
{
response = (await this.client.UpdateSwitchAsync(
new UpdateSwitchRequest()
Switch response = await this.client.GetSwitchAsync(
new GetSwitchRequest()
{
DeviceId = this.ViewModelContext.SelectedDevice.Id,
Switch = s.Clone(),
UpdateMask = mask,
},
deadline: DateTime.UtcNow.AddMilliseconds(500))).Clone();
deadline: DateTime.UtcNow.AddMilliseconds(500));
this.Switch = response;
}
catch (RpcException e)
{
this.logger.LogError(
e,
"Failed to get switch for device {0}",
this.ViewModelContext.SelectedDevice.Id);
}

this.Switch = response;
}

private async void ExecuteSwitchOnClickCommand(object type)
{
FieldMask updateMask = FieldMask.FromString((string)type);
Switch obj = this.UpdateSwitchInfo((string)type, true);
await this.UpdateSwitchAsync(obj, updateMask).ConfigureAwait(true);
}

private async void ExecuteSwitchOffClickCommand(object type)
{
FieldMask updateMask = FieldMask.FromString((string)type);
Switch obj = this.UpdateSwitchInfo((string)type, false);
await this.UpdateSwitchAsync(obj, updateMask).ConfigureAwait(false);
}

private Switch UpdateSwitchInfo(string type, bool status)
private static Switch UpdateSwitchInfo(string type, bool status)
{
Switch obj = new Switch();
var obj = new Switch();
switch (type)
{
case "device_power_on":
Expand Down Expand Up @@ -151,5 +164,46 @@ private Switch UpdateSwitchInfo(string type, bool status)

return obj;
}

private async void Timer_Tick(object sender, EventArgs e)
{
await this.LoadMetricAsync().ConfigureAwait(true);
}

private async Task UpdateSwitchAsync(Switch s, FieldMask mask)
{
Switch response;
if (false)
{
response = s.Clone();
}
else
{
response = (await this.client.UpdateSwitchAsync(
new UpdateSwitchRequest()
{
DeviceId = this.ViewModelContext.SelectedDevice.Id,
Switch = s.Clone(),
UpdateMask = mask,
},
deadline: DateTime.UtcNow.AddMilliseconds(500))).Clone();
}

this.Switch = response;
}

private async void ExecuteSwitchOnClickCommand(string type)
{
var updateMask = FieldMask.FromString(type);
Switch obj = UpdateSwitchInfo(type, true);
await this.UpdateSwitchAsync(obj, updateMask).ConfigureAwait(true);
}

private async void ExecuteSwitchOffClickCommand(string type)
{
var updateMask = FieldMask.FromString(type);
Switch obj = UpdateSwitchInfo(type, false);
await this.UpdateSwitchAsync(obj, updateMask).ConfigureAwait(false);
}
}
}
Loading

0 comments on commit 39d893b

Please sign in to comment.