/// <summary> /// Method to send a Modbus write request to a Modbus slave. providing common /// communication setup and associated exception handling (logging). /// A TCP client is created and used to send the request to the Modbus TCP client. /// The following requests are supported: /// /// Single Coil /// Single Holding Register /// /// Additional datatypes with read / write access (coils and holding registers) are supported: /// /// ASCII String (multiple holding registers) /// Hex String (multiple holding registers) /// Bool (single coil) /// Bits (single holding register) /// Short (single holding register) /// UShort (single holding register) /// Int32 (two holding registers) /// UInt32 (two holding registers) /// Float (two holding registers) /// Double (four holding registers) /// Long (four holding registers) /// ULong (four holding registers) /// /// </summary> /// <param name="request">The <see cref="ModbusRequestData"/> data.</param> /// <param name="data">The data value.</param> /// <param name="function">The function name.</param> /// <returns>A task returning an action method result.</returns> protected async Task <IActionResult> ModbusWriteSingleRequest <T>(ModbusRequestData request, T data, string function) { try { request.Master = _client.RtuMaster; if (_client.Connect()) { switch (function) { case "WriteCoilAsync": { bool value = (bool)Convert.ChangeType(data, typeof(bool)); await _client.WriteSingleCoilAsync(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } case "WriteHoldingRegisterAsync": { ushort value = (ushort)Convert.ChangeType(data, typeof(ushort)); await _client.WriteSingleRegisterAsync(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } case "WriteStringAsync": { string value = (string)Convert.ChangeType(data, typeof(string)); await _client.WriteStringAsync(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } case "WriteHexStringAsync": { string value = (string)Convert.ChangeType(data, typeof(string)); await _client.WriteHexStringAsync(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } case "WriteBoolAsync": { bool value = (bool)Convert.ChangeType(data, typeof(bool)); await _client.WriteBoolAsync(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } case "WriteBitsAsync": { BitArray value = ((string)Convert.ChangeType(data, typeof(string))).ToBitArray(); await _client.WriteBitsAsync(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } case "WriteShortAsync": { short value = (short)Convert.ChangeType(data, typeof(short)); await _client.WriteShortAsync(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } case "WriteUShortAsync": { ushort value = (ushort)Convert.ChangeType(data, typeof(ushort)); await _client.WriteUShortAsync(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } case "WriteInt32Async": { int value = (int)Convert.ChangeType(data, typeof(int)); await _client.WriteInt32Async(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } case "WriteUInt32Async": { uint value = (uint)Convert.ChangeType(data, typeof(uint)); await _client.WriteUInt32Async(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } case "WriteFloatAsync": { float value = (float)Convert.ChangeType(data, typeof(float)); await _client.WriteFloatAsync(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } case "WriteDoubleAsync": { double value = (double)Convert.ChangeType(data, typeof(double)); await _client.WriteDoubleAsync(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } case "WriteLongAsync": { long value = (long)Convert.ChangeType(data, typeof(long)); await _client.WriteLongAsync(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } case "WriteULongAsync": { ulong value = (ulong)Convert.ChangeType(data, typeof(ulong)); await _client.WriteULongAsync(request.Slave.ID, request.Offset, value); _logger.LogTrace($"{function}() OK."); return(Ok(request)); } default: _client.Disconnect(); _logger.LogError($"RTU master write request {function}() not supported."); return(NotFound($"RTU master write request {function}() not supported.")); } } else { _logger.LogError($"RTU master ({request.Master.SerialPort}) not open."); return(NotFound("RTU master COM port not open.")); } } catch (UnauthorizedAccessException uae) { _logger.LogError(uae, $"{function}() Unauthorized Access Exception."); return(NotFound($"Unauthorized Access Exception: {uae.Message}")); } catch (ArgumentOutOfRangeException are) { _logger.LogError(are, $"{function}() Argument out of Range Exception."); return(BadRequest($"Argument out of Range Exception: {are.Message}")); } catch (ArgumentException aex) { _logger.LogError(aex, $"{function}() Argument Exception."); return(BadRequest($"Argument Exception: {aex.Message}")); } catch (NModbus.SlaveException mse) { _logger.LogError(mse, $"{function}() Modbus SlaveException."); return(StatusCode(502, $"Modbus SlaveException: {mse.Message}")); } catch (System.IO.IOException ioe) { _logger.LogError(ioe, $"{function}() IO Exception."); return(StatusCode(500, $"IO Exception: {ioe.Message}")); } catch (TimeoutException tex) { _logger.LogError(tex, $"{function}() Timeout Exception."); return(StatusCode(500, $"Timeout Exception: {tex.Message}")); } catch (Exception ex) { _logger.LogError(ex, $"{function}() Exception."); return(StatusCode(500, $"Exception: {ex.Message}")); } finally { if (_client.Connected) { _client.Disconnect(); } } }