using System.IO.Ports; using System.Text; namespace c64_inteface; public class MonitorBackgroundService : IHostedService, IDisposable { private const string ArduinoId = "F28339B0-78C6-4445-905A-76F77F667D95"; private const string ArduinoPingMsg = "ping " + ArduinoId + "\n"; private const string ArduinoPongMsg = "pong " + ArduinoId; private readonly ILogger _logger; private readonly ArduinoMessageContainer _arduinoMessageContainer; private readonly ArduinoHub _arduinoHub; private SerialPort? _arduinoPort; public MonitorBackgroundService(ILogger logger, ArduinoMessageContainer arduinoMessageContainer, ArduinoHub arduinoHub) { _logger = logger; _arduinoMessageContainer = arduinoMessageContainer; _arduinoHub = arduinoHub; } public Task StartAsync(CancellationToken stoppingToken) { _logger.LogInformation("{Service} running.", nameof(MonitorBackgroundService)); Task.Run(() => RunServiceAsync(stoppingToken), stoppingToken); return Task.CompletedTask; } private async Task DoWork(CancellationToken cancellationToken) { _logger.LogInformation("DoWork running..."); while (!cancellationToken.IsCancellationRequested) { if (_arduinoMessageContainer.Ready) { try { await _arduinoHub.SendMessage(new ArduinoMessage { Status = "online", StatusText = $"Sending message with {Encoding.ASCII.GetBytes(_arduinoMessageContainer.Message).Length} bytes..." }); _logger.LogInformation("Sending message: {Message}", _arduinoMessageContainer.Message); await _arduinoHub.SendMessage(new ArduinoMessage { Status = "online", StatusText = "Done" }); _arduinoPort?.WriteLine(_arduinoMessageContainer.Message); _arduinoMessageContainer.Ready = false; } catch (Exception e) { Console.WriteLine(e); await _arduinoHub.SendMessage(new ArduinoMessage() { StatusText = "Error: " + e.Message, Status = "offline" }); } } } } private async Task RunServiceAsync(CancellationToken cancellationToken) { await FindArduinoPort(cancellationToken); await DoWork(cancellationToken); } public Task StopAsync(CancellationToken stoppingToken) { _logger.LogInformation("{Service} is stopping.", nameof(MonitorBackgroundService)); return Task.CompletedTask; } private async Task FindArduinoPort(CancellationToken cancellationToken) { while (_arduinoPort is null && !cancellationToken.IsCancellationRequested) { await _arduinoHub.SendMessage(new ArduinoMessage() { StatusText = "Searching for Arduino...", Status = "offline" }); var ports = SerialPort.GetPortNames().ToList(); _logger.LogInformation("available ports: {Ports}", ports); foreach (var portName in ports) { var port = new SerialPort(portName, 9600); port.ReadTimeout = 1000; try { port.Open(); await Task.Delay(2000, cancellationToken); } catch (IOException) { continue; } port.WriteLine(ArduinoPingMsg); try { var response = port.ReadLine(); _logger.LogInformation(response); if (!response.Contains(ArduinoPongMsg)) { _logger.LogInformation("{portName} not my arduino", portName); port.Close(); continue; } } catch (Exception ex) { _logger.LogError(ex, ex.Message); _logger.LogInformation("{portName} did not respond", portName); continue; } _logger.LogInformation("Arduino found on {portName}", portName); await _arduinoHub.SendMessage(new ArduinoMessage() { StatusText = $"Arduino found on {portName}", Status = "online" }); _arduinoPort = port; return; } await Task.Delay(1000, cancellationToken); } } public void Dispose() { _arduinoPort?.Close(); _arduinoPort?.Dispose(); } }