Skip to content

Commit

Permalink
Cleanup version with remote connection
Browse files Browse the repository at this point in the history
  • Loading branch information
RobertK66 committed Nov 28, 2021
1 parent 0a0baf2 commit 93717f0
Show file tree
Hide file tree
Showing 15 changed files with 234 additions and 159 deletions.
31 changes: 24 additions & 7 deletions EmbeddedTools.sln
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScreenLib", "ScreenLib\ScreenLib.csproj", "{A807DB7A-A5FD-4DCC-8BDE-3DF94DC18653}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenLib", "ScreenLib\ScreenLib.csproj", "{A807DB7A-A5FD-4DCC-8BDE-3DF94DC18653}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatusConsole", "StatusConsole\StatusConsole.csproj", "{D99E0D06-B412-49BF-98E2-6DE72C2366EB}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatusConsole", "StatusConsole\StatusConsole.csproj", "{D99E0D06-B412-49BF-98E2-6DE72C2366EB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testtemp", "testtemp\testtemp.csproj", "{5EDCAF27-CA84-4BD6-B192-569CEE955363}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -16,9 +18,6 @@ Global
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A807DB7A-A5FD-4DCC-8BDE-3DF94DC18653}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A807DB7A-A5FD-4DCC-8BDE-3DF94DC18653}.Debug|Any CPU.Build.0 = Debug|Any CPU
Expand All @@ -44,5 +43,23 @@ Global
{D99E0D06-B412-49BF-98E2-6DE72C2366EB}.Release|x64.Build.0 = Release|Any CPU
{D99E0D06-B412-49BF-98E2-6DE72C2366EB}.Release|x86.ActiveCfg = Release|Any CPU
{D99E0D06-B412-49BF-98E2-6DE72C2366EB}.Release|x86.Build.0 = Release|Any CPU
{5EDCAF27-CA84-4BD6-B192-569CEE955363}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5EDCAF27-CA84-4BD6-B192-569CEE955363}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5EDCAF27-CA84-4BD6-B192-569CEE955363}.Debug|x64.ActiveCfg = Debug|Any CPU
{5EDCAF27-CA84-4BD6-B192-569CEE955363}.Debug|x64.Build.0 = Debug|Any CPU
{5EDCAF27-CA84-4BD6-B192-569CEE955363}.Debug|x86.ActiveCfg = Debug|Any CPU
{5EDCAF27-CA84-4BD6-B192-569CEE955363}.Debug|x86.Build.0 = Debug|Any CPU
{5EDCAF27-CA84-4BD6-B192-569CEE955363}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5EDCAF27-CA84-4BD6-B192-569CEE955363}.Release|Any CPU.Build.0 = Release|Any CPU
{5EDCAF27-CA84-4BD6-B192-569CEE955363}.Release|x64.ActiveCfg = Release|Any CPU
{5EDCAF27-CA84-4BD6-B192-569CEE955363}.Release|x64.Build.0 = Release|Any CPU
{5EDCAF27-CA84-4BD6-B192-569CEE955363}.Release|x86.ActiveCfg = Release|Any CPU
{5EDCAF27-CA84-4BD6-B192-569CEE955363}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {762B20EF-471D-4A98-B8BF-DC8C24ACDDFF}
EndGlobalSection
EndGlobal
2 changes: 1 addition & 1 deletion ScreenLib/MainScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void RunLine(String exitCmd) {

}

abstract public void HandleConsoleInput(Screen inputScreen, string debugOption, int sleep);
abstract public void HandleConsoleInput(Screen inputScreen);

}
}
8 changes: 4 additions & 4 deletions ScreenLib/Screen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ public void Write(String message, ConsoleColor? col = null) {
var cs = GetConsoleState();
Console.BackgroundColor = this.BackgroundColor;
Console.ForegroundColor = col??this.TextColor;
//if (((Offset.Left + CursorPos.Left) >= Console.BufferWidth-1) || ((Offset.Left + CursorPos.Left) < 0)) {
// int i = 55;
//}
if (((Offset.Left + CursorPos.Left) >= Console.BufferWidth-1) || ((Offset.Left + CursorPos.Left) < 0)) {
Console.BackgroundColor = ConsoleColor.Yellow;
}
Console.SetCursorPosition(Offset.Left + CursorPos.Left, Offset.Top + CursorPos.Top);
Console.Write(message);
CursorPos.Left += message.Length;
Expand Down Expand Up @@ -213,7 +213,7 @@ public void WriteData(byte[] inBuffer, int bytesRead) {
String received = String.Empty;
int bytesProcessed = bytesRead;

while(String.IsNullOrEmpty(received)) {
while(String.IsNullOrEmpty(received) && (bytesProcessed > 0)) {
try {
received = encoding.GetString(buffer, 0, bytesProcessed);
} catch (Exception ) {
Expand Down
13 changes: 4 additions & 9 deletions StatusConsole/HostedCmdlineApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,13 @@ public class HostedCmdlineApp : IHostedService {
private readonly Dictionary<string, ITtyService> uarts;
private Task guiInputHandler;
public ITtyService uartInFocus { get; set; }

private Screen appLogScreen;
private String debugOption;
private int sleepTime;



// Constructor with IOC injection
// Constructor called by IOC with injected ServiceCollection and Config
public HostedCmdlineApp(IConfigurableServices service, IConfiguration conf) {
_myServices = service ?? throw new ArgumentNullException(nameof(service));
uarts = service.GetTtyServices();
debugOption = conf.GetValue<String>("Option") ?? "A";
sleepTime = conf.GetValue<int?>("Sleep") ?? 100;
uarts = _myServices.GetTtyServices();
}

public async Task StartAsync(CancellationToken cancellationToken) {
Expand Down Expand Up @@ -75,7 +70,7 @@ public async Task StartAsync(CancellationToken cancellationToken) {
appLogScreen.WriteLine("Use TAB to switch input control.");

// prepare Input cursor
guiInputHandler = Task.Run(() => main.HandleConsoleInput(appLogScreen, debugOption, sleepTime));
guiInputHandler = Task.Run(() => main.HandleConsoleInput(appLogScreen));

uartInFocus = _myServices.GetCurrentService();
}
Expand Down
2 changes: 1 addition & 1 deletion StatusConsole/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ private static IHostBuilder CreateHostBuilder(string[] args) {
})
.ConfigureServices(services => {
services.AddHostedService<HostedCmdlineApp>();
services.AddTransient<IConfigurableServices, ObcEm2Uarts>();
services.AddTransient<IConfigurableServices, ServiceCollection>();
});
}
Expand Down
182 changes: 78 additions & 104 deletions StatusConsole/RemoteCli.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,66 +12,69 @@
using System.Threading.Tasks;

namespace StatusConsole {

//
// This allows to access a remote socket on hostname:PORTNR
// If the remote machine is running linux there we could connect up any available tty device by running
// nc -l 9000 > /dev/ttyUSB0 < /dev/ttyUSB0
// where 9000 is the port number and ttyUSB0 an example device.

// The version
// while :; do nc -l 9801 > /dev/ttyUSB1 < /dev/ttyUSB1 ; done
// gives repeated call to the nc commans when connection was closed somehow.
//
public class RemoteCli : ITtyService {
private IConfigurationSection Config;
Socket sock = null;
protected String IfName;

private String HostName;
private int Port;

private const int BufferSize = 255;
private byte[] Buffer = new byte[BufferSize+5];
private Socket socket = null;
private bool Continue;
private String NewLine = String.Empty;

// TODO: refactor to seperate UI Config ...???...
IConOutput Screen;
Task Receiver;
char NewLine = '\n';
private IConfigurationSection screenConfig;

public void Initialize(IConfigurationSection cs) {
Config = cs;
IfName = cs.Key;
HostName = cs?.GetValue<String>("RemoteHost") ?? "localhost";
Port = cs?.GetValue<int?>("RemotePort") ?? 9000;
NewLine = cs?.GetValue<String>("NewLine");

screenConfig = cs.GetSection("Screen");
}

string ITtyService.GetInterfaceName() {
return Config.Key;
return IfName;
}

IConfigurationSection ITtyService.GetScreenConfig() {
return Config.GetSection("Screen");
return screenConfig;
}

Task IHostedService.StartAsync(CancellationToken cancellationToken) {
try {
String server = Config?.GetValue<String>("RemoteHost") ?? "localhost";
int port = Config?.GetValue<int?>("RemotePort") ?? 9000;

// Instanziere ein gültiges Socket Objekt mit den übergebenen Argumenten
sock = ConnectSocket(server, port);

//_serialPort.ReadTimeout = 10;
Screen.WriteLine("Remote port " + server + ":" + port + " connected");
Continue = true;

// TODO: refactor ....
public void SetScreen(IConOutput scr) {
Screen = scr;
}

// Receiver = Task.Run(() => Read());
sock.BeginReceive(buffer, 0, 5, 0, new AsyncCallback(ReceiveCallback), sock);

Task IHostedService.StartAsync(CancellationToken cancellationToken) {
try {
BeginnConnect(HostName, Port);
} catch (Exception ex) {
Continue = false;
//ConsoleColor csave = Screen.TextColor;
//Screen.TextColor = ConsoleColor.Red;
Screen.WriteLine("Error starting '" + Config?.GetValue<String>("ComName")??"<null>->COM1" + "' !", ConsoleColor.Red);
Screen.WriteLine("Error starting '" + IfName + "' !", ConsoleColor.Red);
Screen.WriteLine(ex.Message, ConsoleColor.Red);
//Screen.TextColor = csave;
}
return Task.CompletedTask;
}

byte[] buffer = new byte[256];
// Searches for all Host Endpoints and initates Connect to (all of) them.
private List<IAsyncResult> BeginnConnect(string server, int port) {
List<IAsyncResult> retVal = new List<IAsyncResult> ();

// Initialisiert die Socketverbindung und gibt diese zurück
private static Socket ConnectSocket(string server, int port) {
Socket sock = null;
IPHostEntry hostEntry = null;

hostEntry = Dns.GetHostEntry(server);

// Nutze die Eigenschaft AddressFamily von IPEndPoint um Konflikte zwischen
Expand All @@ -81,103 +84,74 @@ private static Socket ConnectSocket(string server, int port) {
Socket tempSocket = new Socket(ipo.AddressFamily,
SocketType.Stream,
ProtocolType.Tcp);
retVal.Add(tempSocket.BeginConnect(ipo, ConnectCallback, tempSocket));
}
return retVal;
}

tempSocket.Connect(ipo);

if (tempSocket.Connected) {
sock = tempSocket;
break;
private void ConnectCallback(IAsyncResult ar) {
try {
// Retrieve the socket from the state object.
if (socket == null) { // First one wins, all other are ignored.....
socket = (Socket)ar.AsyncState;
// Complete the connection.
socket.EndConnect(ar);
Screen.WriteLine("Remote port " + HostName + ":" + Port + " connected");

Continue = true;
// Start Receiving data by entering a data Buffer and a callback.
socket.BeginReceive(Buffer, 0, BufferSize, 0, new AsyncCallback(ReceiveCallback), null);
} else {
continue;
Screen.WriteLine("Duplicate connection to host !!!");
// If more than one addresss was tried. gracefully close others. (to be tested somehow ;-) .....)
((Socket)ar.AsyncState)?.EndConnect(ar);
((Socket)ar.AsyncState)?.Disconnect(false);
}
} catch (Exception ex) {
socket = null;
Continue = false;
Screen.WriteLine("Error connecting " + IfName + " to " + HostName + ":" + Port + " !", ConsoleColor.Red);
Screen.WriteLine(ex.Message, ConsoleColor.Red);
}
return sock;
}


private void ReceiveCallback(IAsyncResult ar) {
try {
// Retrieve the state object and the client socket
// from the asynchronous state object.
Socket client = (Socket)(ar.AsyncState);

// Read data from the remote device.
int bytesRead = client.EndReceive(ar);

int bytesRead = socket.EndReceive(ar);
if (bytesRead > 0) {
// Encoding is ISO Layer 6 !!!???
// How to solve this here for chunked Buffer reads !?
//String received = Encoding.UTF8.GetString(buffer, 0, bytesRead);

//for (int i=0; i<received.Length; i++) {
// String singleChar = received.Substring(i, 1);
// if (singleChar.Equals(NewLine)) {
// Screen.WriteLine("");
// } else {
// Screen.Write(singleChar);
// }
//}
Screen.WriteData(buffer, bytesRead);
// Get the rest of the data.
client.BeginReceive(buffer, 0, 5, 0,
new AsyncCallback(ReceiveCallback), client);
Screen.WriteData(Buffer, bytesRead);
// Get next chunk of the data.
socket.BeginReceive(Buffer, 0, BufferSize, 0, new AsyncCallback(ReceiveCallback), null);
} else {
// Nothing left -> rrestart receive again....
//
Screen.Write(".");
client.BeginReceive(buffer, 0, 5, 0,
new AsyncCallback(ReceiveCallback), client);
// Nothing left -> This gets called only if socket was closed. Either when Disconnect() was called locally or remote connection closed.
Screen.WriteLine("Socket to remote port " + HostName + ":" + Port + " closed.");
Continue = false;
socket?.Disconnect(false);
socket = null;
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
Screen.WriteLine("Exception in ReceiverCallback: " + e.ToString(), ConsoleColor.Red);
}
}

//public void Read() {
// int idx = 0;
// byte[] buffer = new byte[256];

// while (Continue) {
// int rec = sock.Receive(buffer, 1, SocketFlags.None);
// if (rec == 1) {
// char ch = (char)buffer[0];
// if (ch.ToString().Equals(NewLine)) {
// Screen.WriteLine("");
// } else {
// Screen.Write(ch.ToString());
// }
// }
// }

//}




async Task IHostedService.StopAsync(CancellationToken cancellationToken) {
// terminate the reader Task.
Continue = false;
if(Receiver != null) {
//await Receiver; // reader Task will be finished and execution "awaits it" and continues afterwards. (Without blocking any thread here)
sock.Close();
Screen.WriteLine("Socket closed.");
if(socket != null) {
if (socket.Connected) {
await socket.DisconnectAsync(false, cancellationToken);
}
}
}

void ITtyService.SendUart(string line) {
if(Continue) {
line += '\n';
sock.Send(Encoding.UTF8.GetBytes(line));
if(IsConnected()) {
line += NewLine;
socket.Send(Encoding.UTF8.GetBytes(line));
}
}

public bool IsConnected() {
return Continue;
}

public void SetScreen(IConOutput scr) {
Screen = scr;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
using System.Threading.Tasks;

namespace StatusConsole {
public class ObcEm2Uarts : IConfigurableServices {
public class ServiceCollection : IConfigurableServices {

private Dictionary<string, ITtyService> services = new Dictionary<string, ITtyService>();
private List<string> keys = new List<string>();
private ITtyService currentService = null;

public ObcEm2Uarts(IConfiguration conf) {
// This gets called by IOC Container and allows to read the Configuration (from appsettings.json)
// Here we Instanciate all tty Services ("UARTS") configured
public ServiceCollection(IConfiguration conf) {
var uartConfigs = conf?.GetSection("UARTS").GetChildren();
foreach(var uc in uartConfigs) {
var type = Type.GetType(uc.GetValue<String>("Impl")??"dummy");
Expand Down
Loading

0 comments on commit 93717f0

Please sign in to comment.