/// <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();
                }
            }
        }