/// <summary> /// Method to send a Modbus read request to a Modbus slave and returns the requested value(s) /// 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 Discrete Input /// Single Holding Register /// Single Input Register /// /// Multiple Coils /// Multiple Discrete Inputs /// Multiple Holding Registers /// Multiple Input Registers /// /// Additional datatypes (single values, value arrays and strings) with read /// only access (discrete inputs and input registers) and read / write access /// (coils and holding registers) are supported: /// /// ASCII String (multiple registers) /// Hex String (multiple registers) /// Bool (single coil) /// Bits (single register) /// Short (single register) /// UShort (single register) /// Int32 (two registers) /// UInt32 (two registers) /// Float (two registers) /// Double (four registers) /// Long (four registers) /// ULong (four registers) /// /// </summary> /// <param name="request">The <see cref="ModbusRequestData"/> data.</param> /// <param name="function">The function name.</param> /// <returns>A task returning an action method result.</returns> protected async Task <IActionResult> ModbusReadRequest(ModbusRequestData request, string function) { try { request.Master = _client.RtuMaster; if (_client.Connect()) { switch (function) { case "ReadCoilAsync": { bool[] values = await _client.ReadCoilsAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseData <bool>(request, values[0]))); } case "ReadCoilsAsync": { bool[] values = await _client.ReadCoilsAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <bool>(request, values))); } case "ReadInputAsync": { bool[] values = await _client.ReadInputsAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseData <bool>(request, values[0]))); } case "ReadInputsAsync": { bool[] values = await _client.ReadInputsAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <bool>(request, values))); } case "ReadHoldingRegisterAsync": { ushort[] values = await _client.ReadHoldingRegistersAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseData <ushort>(request, values[0]))); } case "ReadHoldingRegistersAsync": { ushort[] values = await _client.ReadHoldingRegistersAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <ushort>(request, values))); } case "ReadInputRegisterAsync": { ushort[] values = await _client.ReadInputRegistersAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseData <ushort>(request, values[0]))); } case "ReadInputRegistersAsync": { ushort[] values = await _client.ReadInputRegistersAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <ushort>(request, values))); } case "ReadOnlyStringAsync": { string value = await _client.ReadOnlyStringAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseStringData(request, value))); } case "ReadOnlyHexStringAsync": { string value = await _client.ReadOnlyHexStringAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseStringData(request, value))); } case "ReadOnlyBoolAsync": { bool value = await _client.ReadOnlyBoolAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <bool>(request, value))); } case "ReadOnlyBitsAsync": { BitArray value = await _client.ReadOnlyBitsAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseStringData(request, value.ToDigitString()))); } case "ReadOnlyShortAsync": { short value = await _client.ReadOnlyShortAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <short>(request, value))); } case "ReadOnlyUShortAsync": { ushort value = await _client.ReadOnlyUShortAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <ushort>(request, value))); } case "ReadOnlyInt32Async": { int value = await _client.ReadOnlyInt32Async(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <int>(request, value))); } case "ReadOnlyUInt32Async": { uint value = await _client.ReadOnlyUInt32Async(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <uint>(request, value))); } case "ReadOnlyFloatAsync": { float value = await _client.ReadOnlyFloatAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <float>(request, value))); } case "ReadOnlyDoubleAsync": { double value = await _client.ReadOnlyDoubleAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <double>(request, value))); } case "ReadOnlyLongAsync": { long value = await _client.ReadOnlyLongAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <long>(request, value))); } case "ReadOnlyULongAsync": { ulong value = await _client.ReadOnlyULongAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <ulong>(request, value))); } case "ReadOnlyBoolArrayAsync": { bool[] values = await _client.ReadOnlyBoolArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <bool>(request, values))); } case "ReadOnlyBytesAsync": { byte[] values = await _client.ReadOnlyBytesAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <byte>(request, values))); } case "ReadOnlyShortArrayAsync": { short[] values = await _client.ReadOnlyShortArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <short>(request, values))); } case "ReadOnlyUShortArrayAsync": { ushort[] values = await _client.ReadOnlyUShortArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <ushort>(request, values))); } case "ReadOnlyInt32ArrayAsync": { int[] values = await _client.ReadOnlyInt32ArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <int>(request, values))); } case "ReadOnlyUInt32ArrayAsync": { uint[] values = await _client.ReadOnlyUInt32ArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <uint>(request, values))); } case "ReadOnlyFloatArrayAsync": { float[] values = await _client.ReadOnlyFloatArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <float>(request, values))); } case "ReadOnlyDoubleArrayAsync": { double[] values = await _client.ReadOnlyDoubleArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <double>(request, values))); } case "ReadOnlyLongArrayAsync": { long[] values = await _client.ReadOnlyLongArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <long>(request, values))); } case "ReadOnlyULongArrayAsync": { ulong[] values = await _client.ReadOnlyULongArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <ulong>(request, values))); } case "ReadStringAsync": { string value = await _client.ReadStringAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseStringData(request, value))); } case "ReadHexStringAsync": { string value = await _client.ReadHexStringAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseStringData(request, value))); } case "ReadBoolAsync": { bool value = await _client.ReadBoolAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <bool>(request, value))); } case "ReadBitsAsync": { BitArray value = await _client.ReadBitsAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseStringData(request, value.ToDigitString()))); } case "ReadShortAsync": { short value = await _client.ReadShortAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <short>(request, value))); } case "ReadUShortAsync": { ushort value = await _client.ReadUShortAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <ushort>(request, value))); } case "ReadInt32Async": { int value = await _client.ReadInt32Async(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <int>(request, value))); } case "ReadUInt32Async": { uint value = await _client.ReadUInt32Async(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <uint>(request, value))); } case "ReadFloatAsync": { float value = await _client.ReadFloatAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <float>(request, value))); } case "ReadDoubleAsync": { double value = await _client.ReadDoubleAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <double>(request, value))); } case "ReadLongAsync": { long value = await _client.ReadLongAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <long>(request, value))); } case "ReadULongAsync": { ulong value = await _client.ReadULongAsync(request.Slave.ID, request.Offset); _logger.LogTrace($"{function}(): {value}"); return(Ok(new ModbusResponseData <ulong>(request, value))); } case "ReadBoolArrayAsync": { bool[] values = await _client.ReadBoolArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <bool>(request, values))); } case "ReadBytesAsync": { byte[] values = await _client.ReadBytesAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <byte>(request, values))); } case "ReadShortArrayAsync": { short[] values = await _client.ReadShortArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <short>(request, values))); } case "ReadUShortArrayAsync": { ushort[] values = await _client.ReadUShortArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <ushort>(request, values))); } case "ReadInt32ArrayAsync": { int[] values = await _client.ReadInt32ArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <int>(request, values))); } case "ReadUInt32ArrayAsync": { uint[] values = await _client.ReadUInt32ArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <uint>(request, values))); } case "ReadFloatArrayAsync": { float[] values = await _client.ReadFloatArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <float>(request, values))); } case "ReadDoubleArrayAsync": { double[] values = await _client.ReadDoubleArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <double>(request, values))); } case "ReadLongArrayAsync": { long[] values = await _client.ReadLongArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <long>(request, values))); } case "ReadULongArrayAsync": { ulong[] values = await _client.ReadULongArrayAsync(request.Slave.ID, request.Offset, request.Number); _logger.LogTrace($"{function}(): {values}"); return(Ok(new ModbusResponseArrayData <ulong>(request, values))); } default: _client.Disconnect(); _logger.LogError($"RTU master read request {function}() not supported."); return(NotFound($"RTU master read 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(); } } }