public async Task<bool> ProcessDevice(SmlComServiceClient svc, Guid guid, CommunicationPort port, CancellationToken token) { // cancellation setup this.cts?.Cancel(); var timeoutCts = new CancellationTokenSource(TimeSpan.FromMinutes(5)); this.cts = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, token); token = cts.Token; var sw = Stopwatch.StartNew(); try { if (!this.IsOccupiedByDevice) { Log.Warning($"Station {this.Number} is not assigned by a device (MAC address missing)"); // only use active stations where a device is assigned (by scanning or user action) return false; } var dr = new DeviceRepository(); this.Device = dr.GetOne(this.Device.ServerId); this.SetStatusMessageAndProgress("Processing started...", 5); this.Status = StationStatus.Processing; var rnd = new Random(); var policy = Policy .Handle<Exception>() .WaitAndRetryAsync(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2) }); var portlist = await svc.GetPortListAsync(); if (!portlist.FirstOrDefault(p => p.ComPortName == this.ComAddress).IsInitialized) { throw new InvalidOperationException("Service Comport is not initialized!"); } foreach (var param in this.Device.ParameterList) { await Task.Delay(100, token); if (!param.IsActive) { continue; } // execute communication with retry policy... await policy.ExecuteAsync(async () => { this.SetStatusMessageAndProgress($"Writing at {port.ComPortName} parameter {param.TagId} with value {param.TargetValue}...", this.Progress); switch (param.TagId) { case ParameterTagId.ServerId: var serverId = param.TargetValue.FromHexString(); await svc.WriteServerIdAsync(guid, port, serverId); var serverIdParam = await svc.ReadServerIdAsync(guid, port); param.RealValue = serverIdParam.Data.AsHexString("-"); break; case ParameterTagId.ManufacturerSerialNumber: await svc.WriteManufacturerSerialNumberAsync(guid, port, param.TargetValue); var serialNoParam = await svc.ReadManufacturerSerialNoAsync(guid, port); var serialNoBytes = serialNoParam.Data; param.RealValue = Encoding.UTF8.GetString(serialNoBytes); break; case ParameterTagId.GenerateKeys: await svc.WriteCreateKeysAsync(guid, port); param.RealValue = "True"; param.IsWritten = true; break; case ParameterTagId.PublicKey: param.RealValue = (await svc.ReadPublicKeyAsync(guid, port)).Data.AsHexString("-"); break; case ParameterTagId.PinCodeActive: var isPinActive = bool.Parse(param.TargetValue); await svc.WriteIsPinProtectionActiveAsync(guid, port, isPinActive); param.RealValue = (await svc.ReadIsPinProtectionActiveAsync(guid, port)).Data.ToString(); break; case ParameterTagId.InitialKeyM: await svc.WriteInitialSymKeyAsync(guid, port, param.TargetValue.FromHexString()); param.RealValue = (await svc.ReadInitialSymKeyAsync(guid, port)).Data.AsHexString("-"); break; case ParameterTagId.PinCode: await svc.WritePinAsync(guid, port, param.TargetValue); param.RealValue = param.TargetValue; param.IsWritten = true; break; case ParameterTagId.MeasurementMode: await svc.WriteMeasurementModeAsync(guid, port, param.TargetValue); param.RealValue = $"MM{(await svc.ReadMeasurementModeAsync(guid, port)).Data}"; break; case ParameterTagId.GridOption: var isGridOption = bool.Parse(param.TargetValue); await svc.WriteEnableGridOptionAsync(guid, port, isGridOption); param.RealValue = (await svc.ReadEnableGridOptionAsync(guid, port)).Data.ToString(); break; case ParameterTagId.TarifOptionActive: var isTariffActive = bool.Parse(param.TargetValue); await svc.WriteEnableTariffFunctionAsync(guid, port, isTariffActive); param.RealValue = (await svc.ReadEnableTariffFunctionAsync(guid, port)).Data.ToString(); break; case ParameterTagId.InverseTariffControl: var isInverse = bool.Parse(param.TargetValue); await svc.WriteIsTerminalControlReverseAsync(guid, port, isInverse); param.RealValue = (await svc.ReadIsTerminalControlReverseAsync(guid, port)).Data.ToString(); break; case ParameterTagId.BaudRateConfigurable: var isBaudrateConfigurable = bool.Parse(param.TargetValue); await svc.WriteEnableBaudRateSettingAsync(guid, port, isBaudrateConfigurable); param.RealValue = (await svc.ReadEnableBaudRateSettingAsync(guid, port)).Data.ToString(); break; case ParameterTagId.BaudRate: break; case ParameterTagId.Type: param.RealValue = param.TargetValue; param.IsWritten = true; break; case ParameterTagId.Eigentumsnummer: param.RealValue = param.TargetValue; param.IsWritten = true; break; default: throw new InvalidEnumArgumentException(); } this.SetStatusMessageAndProgress($"{port.ComPortName} parameter {param.TagId} with value {param.TargetValue} write OK...", this.Progress += 5); }); } this.Device.SetAllParametersWritten(true); sw.Stop(); Log.Warning("Device completed in {@sw}!", sw.Elapsed); // update database this.Device.ProducedAt = DateTime.Now; // dr.Update(device); this.LastProducedDeviceServerId = this.Device.ServerId; this.SetStatusMessageAndProgress("Processed", 100); this.Status = StationStatus.ProcessingCompleted; await Task.Delay(TimeSpan.FromSeconds(1), token); return true; } catch (OperationCanceledException) { Log.Warning("Station {s} cancelled", this.Number); this.SetStatusMessageAndProgress($"Cancelled", 0); } catch (Exception ex) { Log.Error(ex, "Station {s} failed", this.Number); this.SetStatusMessageAndProgress($"Error: {ex.Message}", 0); this.Status = StationStatus.Error; } return false; }