Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Beta/1.1.0 #5

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
*.user
*.userosscache
*.sln.docstates
*.ncrunchsolution
gitversion.json


# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
Expand Down Expand Up @@ -244,4 +247,3 @@ ModelManifest.xml

# FAKE - F# Make
.fake/
*.ncrunchsolution

This file was deleted.

128 changes: 59 additions & 69 deletions ReadMe.md

Large diffs are not rendered by default.

This file was deleted.

This file was deleted.

72 changes: 36 additions & 36 deletions TA.ArduinoPowerController.DeviceInterface/DeviceController.cs
Original file line number Diff line number Diff line change
@@ -1,115 +1,115 @@
// This file is part of the TA.ArduinoPowerController project
//
// Copyright © 2016-2017 Tigra Astronomy, all rights reserved.
// Licensed under the MIT license, see http://tigra.mit-license.org/
//
// File: DeviceController.cs Last modified: 2017-03-16@23:33 by Tim Long
//
// Copyright © 2016-2019 Tigra Astronomy, all rights reserved.
// Licensed under the Tigra MIT license, see http://tigra.mit-license.org/
//
// File: DeviceController.cs Last modified: 2019-09-08@08:36 by Tim Long

using System;
using NLog;
using TA.Ascom.ReactiveCommunications;
using TA.Utils.Core.Diagnostics;

namespace TA.ArduinoPowerController.DeviceInterface
{
{
public class DeviceController : IDisposable
{
{
private readonly ITransactionProcessorFactory factory;
private readonly Logger log = LogManager.GetCurrentClassLogger();
private readonly ILog log;

private bool disposed;
private ITransactionProcessor transactionProcessor;

public DeviceController(ITransactionProcessorFactory factory)
{
public DeviceController(ITransactionProcessorFactory factory, ILog logService)
{
this.factory = factory;
}
log = logService;
}

public bool IsOnline => transactionProcessor != null && (factory?.Channel?.IsOpen ?? false);

public void Dispose()
{
{
Dispose(true);
GC.SuppressFinalize(this);
}
}

public void ClearRelay(ushort id)
{
{
var transaction = new WriteRelayTransaction(id, false);
transactionProcessor.CommitTransaction(transaction);
transaction.WaitForCompletionOrTimeout();
RaiseRelayStateChanged(id, false);
}
}

/// <summary>
/// Close the connection to the AWR system. This should never fail.
/// </summary>
public void Close()
{
{
log.Warn("Close requested");
if (!IsOnline)
{
{
log.Warn("Ignoring Close request because already closed");
return;
}
}
log.Info($"Closing device endpoint: {factory.Endpoint}");
factory.DestroyTransactionProcessor();
log.Info("====== Channel closed: the device is now disconnected ======");
}
}

protected virtual void Dispose(bool fromUserCode)
{
{
if (!disposed)
if (fromUserCode)
Close();
disposed = true;

// ToDo: Call the base class's Dispose(Boolean) method, if available.
// base.Dispose(fromUserCode);
}
}

// The IDisposable pattern, as described at
// http://www.codeproject.com/Articles/15360/Implementing-IDisposable-and-the-Dispose-Pattern-P


/// <summary>
/// Finalizes this instance (called prior to garbage collection by the CLR)
/// </summary>
~DeviceController()
{
{
Dispose(false);
}
}

/// <summary>
/// Opens the transaction pipeline for sending and receiving and performs initial state synchronization with the drive
/// system.
/// </summary>
public void Open()
{
{
log.Info($"Opening device endpoint: {factory.Endpoint}");
transactionProcessor = factory.CreateTransactionProcessor();
log.Info("====== Initialization completed successfully : Device is now ready to accept commands ======");
}

}

public void PerformOnConnectTasks()
{
{
//ToDo: perform any tasks that must occur as soon as the communication channel is connected.
}
}

protected void RaiseRelayStateChanged(int relay, bool newState)
{
{
var args = new RelayStateChangedEventArgs(relay, newState);
RelayStateChanged?.Invoke(this, args);
}
}

public event EventHandler<RelayStateChangedEventArgs> RelayStateChanged;

public void SetRelay(ushort id)
{
{
var transaction = new WriteRelayTransaction(id, true);
transactionProcessor.CommitTransaction(transaction);
transaction.WaitForCompletionOrTimeout();
RaiseRelayStateChanged(id, true);
}
if (transaction.Successful)
RaiseRelayStateChanged(id, true);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
using System.Reflection;

[assembly: AssemblyTitle("TA.ArduinoPowerController.DeviceInterface")]
[assembly: AssemblyDescription("Low level device communications layer")]
[assembly: AssemblyDescription("Low level device communications layer for Arduino Power Controller")]
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
// This file is part of the TA.ArduinoPowerController project
//
// Copyright © 2016-2017 Tigra Astronomy, all rights reserved.
// Licensed under the MIT license, see http://tigra.mit-license.org/
//
// File: ReactiveTransactionProcessorFactory.cs Last modified: 2017-03-16@23:33 by Tim Long
//
// Copyright © 2016-2019 Tigra Astronomy, all rights reserved.
// Licensed under the Tigra MIT license, see http://tigra.mit-license.org/
//
// File: ReactiveTransactionProcessorFactory.cs Last modified: 2019-09-08@06:37 by Tim Long

using System;
using System.Threading;
using System.Threading.Tasks;
using TA.Ascom.ReactiveCommunications;

namespace TA.ArduinoPowerController.DeviceInterface
{
{
/// <summary>
/// Class ReactiveTransactionProcessorFactory. Used to set up and tear down the communications stack
/// as the device is connected and disconnected.
/// Implements <see cref="TA.ArduinoPowerController.DeviceInterface.ITransactionProcessorFactory" />
/// </summary>
/// <seealso cref="TA.ArduinoPowerController.DeviceInterface.ITransactionProcessorFactory" />
public class ReactiveTransactionProcessorFactory : ITransactionProcessorFactory
{
public string ConnectionString { get; }

{
private TransactionObserver observer;
private ReactiveTransactionProcessor processor;

public ReactiveTransactionProcessorFactory(string connectionString)
{
this.ConnectionString = connectionString;
// Endpoint will be InvalidEndpoint if the connection string is invalid.
Endpoint = DeviceEndpoint.FromConnectionString(connectionString);
}
{
ConnectionString = connectionString;
}

public string ConnectionString { get; }

public ICommunicationChannel Channel { get; private set; }

Expand All @@ -33,17 +37,16 @@ public ReactiveTransactionProcessorFactory(string connectionString)
/// </summary>
/// <returns>ITransactionProcessor.</returns>
public ITransactionProcessor CreateTransactionProcessor()
{
Endpoint = DeviceEndpoint.FromConnectionString(ConnectionString);
Channel = CommunicationsStackBuilder.BuildChannel(Endpoint);
{
Channel = new ChannelFactory().FromConnectionString(ConnectionString);
observer = new TransactionObserver(Channel);
processor = new ReactiveTransactionProcessor();
processor.SubscribeTransactionObserver(observer, TimeSpan.FromMilliseconds(100));
Channel.Open();
//Task.Delay(TimeSpan.FromSeconds(2)).Wait(); // Arduino needs 2 seconds to initialize
Thread.Sleep(TimeSpan.FromSeconds(3));
// Arduino may need a few seconds to initialize after starting the connection
Task.Delay(TimeSpan.FromSeconds(5)).Wait();
return processor;
}
}

/// <summary>
/// Destroys the transaction processor and its dependencies. Ensures that the
Expand All @@ -53,7 +56,7 @@ public ITransactionProcessor CreateTransactionProcessor()
/// <see cref="CreateTransactionProcessor" /> again.
/// </summary>
public void DestroyTransactionProcessor()
{
{
processor?.Dispose();
processor = null; // [Sentinel]
observer = null;
Expand All @@ -62,8 +65,8 @@ public void DestroyTransactionProcessor()
Channel?.Dispose();
Channel = null; // [Sentinel]
GC.Collect(3, GCCollectionMode.Forced, blocking: true);
}

public DeviceEndpoint Endpoint { get; set; }
}
}

public DeviceEndpoint Endpoint => Channel?.Endpoint ?? new InvalidEndpoint();
}
}
5 changes: 5 additions & 0 deletions TA.ArduinoPowerController.DeviceInterface/ReadMe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Device Interface project

It is best practice to place the device communications and interfacing code in its own separate project. One reason for doing so is so that this "business logic" code can be unit tested in isolation.

This will become particularly important in projects that contain more than one driver class. The driver classes can then share the common device interface code.
26 changes: 26 additions & 0 deletions TA.ArduinoPowerController.DeviceInterface/RelayCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// This file is part of the TA.ArduinoPowerController project
//
// Copyright � 2016-2019 Tigra Astronomy, all rights reserved.
// Licensed under the Tigra MIT license, see http://tigra.mit-license.org/
//
// File: RelayCommand.cs Last modified: 2019-09-08@12:35 by Tim Long
namespace TA.ArduinoPowerController.DeviceInterface
{
/// <summary>
/// A simple data transfer object (DTO) for storing relay operations
/// </summary>
class RelayCommand
{
public string Operation { get; set; }

public ushort Relay { get; set; }

public bool State { get; set; }

/// Debugging is always easier if there is a ToString method.
public override string ToString()
{
return $"{nameof(Operation)}: {Operation}, {nameof(Relay)}: {Relay}, {nameof(State)}: {State}";
}
}
}
Loading