We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
AsyncioModbusSerialClient TypeError Coroutine
### Versions

* Python: 3.9
* OS: Ubuntu 20.04
* Pymodbus: `3.0.0dev4`
* Modbus Hardware (if used): 

### Pymodbus Specific
* Server: None
* Client: rtu - async

### Description

When I try  `3.0.0dev4` and the latest commit as of today. I am getting a type error that variable `coro` is not a coroutine in file `serial.py`. I am trying to create  `AsyncModbusSerialClient(schedulers.ASYNC_IO, port=connPort, baudrate=connSpeed, method=connMethod, timeout=commTimeout)` in an existing running loop.

I don't think the coroutine was created correctly. What do you think?

Old:
`future = asyncio.run_coroutine_threadsafe(coro, loop=loop)` 

Proposed:
` future = asyncio.run_coroutine_threadsafe(coro(), loop=loop)`
   """Create asyncio based asynchronous serial clients.
    :param port:  Serial port
    :param framer: Modbus Framer
    :param kwargs: Serial port options
    :return: asyncio event loop and serial client
    """
    try:
        loop = kwargs.pop("loop", None) or asyncio.get_running_loop()
    except RuntimeError:
        loop = asyncio.new_event_loop()

    proto_cls = kwargs.get("proto_cls") or ModbusClientProtocol

    client = AsyncioModbusSerialClient(port, proto_cls, framer, loop, **kwargs)
    coro = client.connect
    if not loop.is_running():
        loop.run_until_complete(coro())
    else:  # loop is not asyncio.get_event_loop():
        future = asyncio.run_coroutine_threadsafe(coro, loop=loop) <- `Fails here`
        future.result()

    return loop, client
```
``` py
def async_io_factory(port=None, framer=None, **kwargs):
    """Create asyncio based asynchronous serial clients.
    :param port:  Serial port
    :param framer: Modbus Framer
    :param kwargs: Serial port options
    :return: asyncio event loop and serial client
    """
    try:
        loop = kwargs.pop("loop", None) or asyncio.get_running_loop()
    except RuntimeError:
        loop = asyncio.new_event_loop()

    proto_cls = kwargs.get("proto_cls") or ModbusClientProtocol

    client = AsyncioModbusSerialClient(port, proto_cls, framer, loop, **kwargs)
    coro = client.connect
    if not loop.is_running():
        loop.run_until_complete(coro())
    else:  # loop is not asyncio.get_event_loop():
        future = asyncio.run_coroutine_threadsafe(coro, loop=loop) <- `Fails here`
        future.result()

    return loop, client
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pymodbus/client/asynchronous/factory/serial.py`
Content:
```
1 """Factory to create asynchronous serial clients based on twisted/asyncio."""
2 # pylint: disable=missing-type-doc
3 import logging
4 import asyncio
5 
6 from pymodbus.client.asynchronous import schedulers
7 from pymodbus.client.asynchronous.thread import EventLoopThread
8 from pymodbus.client.asynchronous.async_io import (
9     ModbusClientProtocol,
10     AsyncioModbusSerialClient,
11 )
12 from pymodbus.factory import ClientDecoder
13 
14 
15 _logger = logging.getLogger(__name__)
16 
17 
18 def reactor_factory(port, framer, **kwargs):
19     """Create twisted serial asynchronous client.
20 
21     :param port: Serial port
22     :param framer: Modbus Framer
23     :param kwargs:
24     :return: event_loop_thread and twisted serial client
25     """
26     from twisted.internet import reactor  # pylint: disable=import-outside-toplevel
27     from twisted.internet.serialport import (  # pylint: disable=import-outside-toplevel
28         SerialPort,
29     )
30     from twisted.internet.protocol import (  # pylint: disable=import-outside-toplevel
31         ClientFactory,
32     )
33 
34     class SerialClientFactory(ClientFactory):
35         """Define serial client factory."""
36 
37         def __init__(self, framer, proto_cls):
38             """Remember things necessary for building a protocols."""
39             self.proto_cls = proto_cls
40             self.framer = framer
41 
42         def buildProtocol(self):  # pylint: disable=arguments-differ
43             """Create a protocol and start the reading cycle-"""
44             proto = self.proto_cls(self.framer)
45             proto.factory = self
46             return proto
47 
48     class SerialModbusClient(SerialPort):  # pylint: disable=abstract-method
49         """Define serial client."""
50 
51         def __init__(self, framer, *args, **kwargs):
52             """Initialize the client and start listening on the serial port.
53 
54             :param factory: The factory to build clients with
55             """
56             self.decoder = ClientDecoder()
57             proto_cls = kwargs.pop("proto_cls", None)
58             proto = SerialClientFactory(framer, proto_cls).buildProtocol()
59             SerialPort.__init__(self, proto, *args, **kwargs)
60 
61     proto = EventLoopThread(
62         "reactor",
63         reactor.run,  # pylint: disable=no-member
64         reactor.stop,  # pylint: disable=no-member
65         installSignalHandlers=0,
66     )
67     ser_client = SerialModbusClient(framer, port, reactor, **kwargs)
68 
69     return proto, ser_client
70 
71 
72 def async_io_factory(port=None, framer=None, **kwargs):
73     """Create asyncio based asynchronous serial clients.
74 
75     :param port:  Serial port
76     :param framer: Modbus Framer
77     :param kwargs: Serial port options
78     :return: asyncio event loop and serial client
79     """
80     try:
81         loop = kwargs.pop("loop", None) or asyncio.get_running_loop()
82     except RuntimeError:
83         loop = asyncio.new_event_loop()
84 
85     proto_cls = kwargs.get("proto_cls") or ModbusClientProtocol
86 
87     client = AsyncioModbusSerialClient(port, proto_cls, framer, loop, **kwargs)
88     coro = client.connect
89     if not loop.is_running():
90         loop.run_until_complete(coro())
91     else:  # loop is not asyncio.get_event_loop():
92         future = asyncio.run_coroutine_threadsafe(coro, loop=loop)
93         future.result()
94 
95     return loop, client
96 
97 
98 def get_factory(scheduler):
99     """Get protocol factory based on the backend scheduler being used.
100 
101     :param scheduler: REACTOR/ASYNC_IO
102     :return:
103     :raises Exception: Failure
104     """
105     if scheduler == schedulers.REACTOR:
106         return reactor_factory
107     if scheduler == schedulers.ASYNC_IO:
108         return async_io_factory
109 
110     txt = f"Allowed Schedulers: {schedulers.REACTOR}, {schedulers.ASYNC_IO}"
111     _logger.warning(txt)
112     txt = f'Invalid Scheduler "{scheduler}"'
113     raise Exception(txt)
114
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pymodbus/client/asynchronous/factory/serial.py b/pymodbus/client/asynchronous/factory/serial.py
--- a/pymodbus/client/asynchronous/factory/serial.py
+++ b/pymodbus/client/asynchronous/factory/serial.py
@@ -89,7 +89,7 @@
     if not loop.is_running():
         loop.run_until_complete(coro())
     else:  # loop is not asyncio.get_event_loop():
-        future = asyncio.run_coroutine_threadsafe(coro, loop=loop)
+        future = asyncio.run_coroutine_threadsafe(coro(), loop=loop)
         future.result()
 
     return loop, client

{"golden_diff": "diff --git a/pymodbus/client/asynchronous/factory/serial.py b/pymodbus/client/asynchronous/factory/serial.py\n--- a/pymodbus/client/asynchronous/factory/serial.py\n+++ b/pymodbus/client/asynchronous/factory/serial.py\n@@ -89,7 +89,7 @@\n     if not loop.is_running():\n         loop.run_until_complete(coro())\n     else:  # loop is not asyncio.get_event_loop():\n-        future = asyncio.run_coroutine_threadsafe(coro, loop=loop)\n+        future = asyncio.run_coroutine_threadsafe(coro(), loop=loop)\n         future.result()\n \n     return loop, client\n", "issue": "AsyncioModbusSerialClient TypeError Coroutine\n### Versions\r\n\r\n* Python: 3.9\r\n* OS: Ubuntu 20.04\r\n* Pymodbus: `3.0.0dev4`\r\n* Modbus Hardware (if used): \r\n\r\n### Pymodbus Specific\r\n* Server: None\r\n* Client: rtu - async\r\n\r\n### Description\r\n\r\nWhen I try  `3.0.0dev4` and the latest commit as of today. I am getting a type error that variable `coro` is not a coroutine in file `serial.py`. I am trying to create  `AsyncModbusSerialClient(schedulers.ASYNC_IO, port=connPort, baudrate=connSpeed, method=connMethod, timeout=commTimeout)` in an existing running loop.\r\n\r\nI don't think the coroutine was created correctly. What do you think?\r\n\r\nOld:\r\n`future = asyncio.run_coroutine_threadsafe(coro, loop=loop)` \r\n\r\nProposed:\r\n` future = asyncio.run_coroutine_threadsafe(coro(), loop=loop)`\r\n   \"\"\"Create asyncio based asynchronous serial clients.\r\n    :param port:  Serial port\r\n    :param framer: Modbus Framer\r\n    :param kwargs: Serial port options\r\n    :return: asyncio event loop and serial client\r\n    \"\"\"\r\n    try:\r\n        loop = kwargs.pop(\"loop\", None) or asyncio.get_running_loop()\r\n    except RuntimeError:\r\n        loop = asyncio.new_event_loop()\r\n\r\n    proto_cls = kwargs.get(\"proto_cls\") or ModbusClientProtocol\r\n\r\n    client = AsyncioModbusSerialClient(port, proto_cls, framer, loop, **kwargs)\r\n    coro = client.connect\r\n    if not loop.is_running():\r\n        loop.run_until_complete(coro())\r\n    else:  # loop is not asyncio.get_event_loop():\r\n        future = asyncio.run_coroutine_threadsafe(coro, loop=loop) <- `Fails here`\r\n        future.result()\r\n\r\n    return loop, client\r\n```\r\n``` py\r\ndef async_io_factory(port=None, framer=None, **kwargs):\r\n    \"\"\"Create asyncio based asynchronous serial clients.\r\n    :param port:  Serial port\r\n    :param framer: Modbus Framer\r\n    :param kwargs: Serial port options\r\n    :return: asyncio event loop and serial client\r\n    \"\"\"\r\n    try:\r\n        loop = kwargs.pop(\"loop\", None) or asyncio.get_running_loop()\r\n    except RuntimeError:\r\n        loop = asyncio.new_event_loop()\r\n\r\n    proto_cls = kwargs.get(\"proto_cls\") or ModbusClientProtocol\r\n\r\n    client = AsyncioModbusSerialClient(port, proto_cls, framer, loop, **kwargs)\r\n    coro = client.connect\r\n    if not loop.is_running():\r\n        loop.run_until_complete(coro())\r\n    else:  # loop is not asyncio.get_event_loop():\r\n        future = asyncio.run_coroutine_threadsafe(coro, loop=loop) <- `Fails here`\r\n        future.result()\r\n\r\n    return loop, client\r\n```\r\n\n", "before_files": [{"content": "\"\"\"Factory to create asynchronous serial clients based on twisted/asyncio.\"\"\"\n# pylint: disable=missing-type-doc\nimport logging\nimport asyncio\n\nfrom pymodbus.client.asynchronous import schedulers\nfrom pymodbus.client.asynchronous.thread import EventLoopThread\nfrom pymodbus.client.asynchronous.async_io import (\n    ModbusClientProtocol,\n    AsyncioModbusSerialClient,\n)\nfrom pymodbus.factory import ClientDecoder\n\n\n_logger = logging.getLogger(__name__)\n\n\ndef reactor_factory(port, framer, **kwargs):\n    \"\"\"Create twisted serial asynchronous client.\n\n    :param port: Serial port\n    :param framer: Modbus Framer\n    :param kwargs:\n    :return: event_loop_thread and twisted serial client\n    \"\"\"\n    from twisted.internet import reactor  # pylint: disable=import-outside-toplevel\n    from twisted.internet.serialport import (  # pylint: disable=import-outside-toplevel\n        SerialPort,\n    )\n    from twisted.internet.protocol import (  # pylint: disable=import-outside-toplevel\n        ClientFactory,\n    )\n\n    class SerialClientFactory(ClientFactory):\n        \"\"\"Define serial client factory.\"\"\"\n\n        def __init__(self, framer, proto_cls):\n            \"\"\"Remember things necessary for building a protocols.\"\"\"\n            self.proto_cls = proto_cls\n            self.framer = framer\n\n        def buildProtocol(self):  # pylint: disable=arguments-differ\n            \"\"\"Create a protocol and start the reading cycle-\"\"\"\n            proto = self.proto_cls(self.framer)\n            proto.factory = self\n            return proto\n\n    class SerialModbusClient(SerialPort):  # pylint: disable=abstract-method\n        \"\"\"Define serial client.\"\"\"\n\n        def __init__(self, framer, *args, **kwargs):\n            \"\"\"Initialize the client and start listening on the serial port.\n\n            :param factory: The factory to build clients with\n            \"\"\"\n            self.decoder = ClientDecoder()\n            proto_cls = kwargs.pop(\"proto_cls\", None)\n            proto = SerialClientFactory(framer, proto_cls).buildProtocol()\n            SerialPort.__init__(self, proto, *args, **kwargs)\n\n    proto = EventLoopThread(\n        \"reactor\",\n        reactor.run,  # pylint: disable=no-member\n        reactor.stop,  # pylint: disable=no-member\n        installSignalHandlers=0,\n    )\n    ser_client = SerialModbusClient(framer, port, reactor, **kwargs)\n\n    return proto, ser_client\n\n\ndef async_io_factory(port=None, framer=None, **kwargs):\n    \"\"\"Create asyncio based asynchronous serial clients.\n\n    :param port:  Serial port\n    :param framer: Modbus Framer\n    :param kwargs: Serial port options\n    :return: asyncio event loop and serial client\n    \"\"\"\n    try:\n        loop = kwargs.pop(\"loop\", None) or asyncio.get_running_loop()\n    except RuntimeError:\n        loop = asyncio.new_event_loop()\n\n    proto_cls = kwargs.get(\"proto_cls\") or ModbusClientProtocol\n\n    client = AsyncioModbusSerialClient(port, proto_cls, framer, loop, **kwargs)\n    coro = client.connect\n    if not loop.is_running():\n        loop.run_until_complete(coro())\n    else:  # loop is not asyncio.get_event_loop():\n        future = asyncio.run_coroutine_threadsafe(coro, loop=loop)\n        future.result()\n\n    return loop, client\n\n\ndef get_factory(scheduler):\n    \"\"\"Get protocol factory based on the backend scheduler being used.\n\n    :param scheduler: REACTOR/ASYNC_IO\n    :return:\n    :raises Exception: Failure\n    \"\"\"\n    if scheduler == schedulers.REACTOR:\n        return reactor_factory\n    if scheduler == schedulers.ASYNC_IO:\n        return async_io_factory\n\n    txt = f\"Allowed Schedulers: {schedulers.REACTOR}, {schedulers.ASYNC_IO}\"\n    _logger.warning(txt)\n    txt = f'Invalid Scheduler \"{scheduler}\"'\n    raise Exception(txt)\n", "path": "pymodbus/client/asynchronous/factory/serial.py"}], "after_files": [{"content": "\"\"\"Factory to create asynchronous serial clients based on twisted/asyncio.\"\"\"\n# pylint: disable=missing-type-doc\nimport logging\nimport asyncio\n\nfrom pymodbus.client.asynchronous import schedulers\nfrom pymodbus.client.asynchronous.thread import EventLoopThread\nfrom pymodbus.client.asynchronous.async_io import (\n    ModbusClientProtocol,\n    AsyncioModbusSerialClient,\n)\nfrom pymodbus.factory import ClientDecoder\n\n\n_logger = logging.getLogger(__name__)\n\n\ndef reactor_factory(port, framer, **kwargs):\n    \"\"\"Create twisted serial asynchronous client.\n\n    :param port: Serial port\n    :param framer: Modbus Framer\n    :param kwargs:\n    :return: event_loop_thread and twisted serial client\n    \"\"\"\n    from twisted.internet import reactor  # pylint: disable=import-outside-toplevel\n    from twisted.internet.serialport import (  # pylint: disable=import-outside-toplevel\n        SerialPort,\n    )\n    from twisted.internet.protocol import (  # pylint: disable=import-outside-toplevel\n        ClientFactory,\n    )\n\n    class SerialClientFactory(ClientFactory):\n        \"\"\"Define serial client factory.\"\"\"\n\n        def __init__(self, framer, proto_cls):\n            \"\"\"Remember things necessary for building a protocols.\"\"\"\n            self.proto_cls = proto_cls\n            self.framer = framer\n\n        def buildProtocol(self):  # pylint: disable=arguments-differ\n            \"\"\"Create a protocol and start the reading cycle-\"\"\"\n            proto = self.proto_cls(self.framer)\n            proto.factory = self\n            return proto\n\n    class SerialModbusClient(SerialPort):  # pylint: disable=abstract-method\n        \"\"\"Define serial client.\"\"\"\n\n        def __init__(self, framer, *args, **kwargs):\n            \"\"\"Initialize the client and start listening on the serial port.\n\n            :param factory: The factory to build clients with\n            \"\"\"\n            self.decoder = ClientDecoder()\n            proto_cls = kwargs.pop(\"proto_cls\", None)\n            proto = SerialClientFactory(framer, proto_cls).buildProtocol()\n            SerialPort.__init__(self, proto, *args, **kwargs)\n\n    proto = EventLoopThread(\n        \"reactor\",\n        reactor.run,  # pylint: disable=no-member\n        reactor.stop,  # pylint: disable=no-member\n        installSignalHandlers=0,\n    )\n    ser_client = SerialModbusClient(framer, port, reactor, **kwargs)\n\n    return proto, ser_client\n\n\ndef async_io_factory(port=None, framer=None, **kwargs):\n    \"\"\"Create asyncio based asynchronous serial clients.\n\n    :param port:  Serial port\n    :param framer: Modbus Framer\n    :param kwargs: Serial port options\n    :return: asyncio event loop and serial client\n    \"\"\"\n    try:\n        loop = kwargs.pop(\"loop\", None) or asyncio.get_running_loop()\n    except RuntimeError:\n        loop = asyncio.new_event_loop()\n\n    proto_cls = kwargs.get(\"proto_cls\") or ModbusClientProtocol\n\n    client = AsyncioModbusSerialClient(port, proto_cls, framer, loop, **kwargs)\n    coro = client.connect\n    if not loop.is_running():\n        loop.run_until_complete(coro())\n    else:  # loop is not asyncio.get_event_loop():\n        future = asyncio.run_coroutine_threadsafe(coro(), loop=loop)\n        future.result()\n\n    return loop, client\n\n\ndef get_factory(scheduler):\n    \"\"\"Get protocol factory based on the backend scheduler being used.\n\n    :param scheduler: REACTOR/ASYNC_IO\n    :return:\n    :raises Exception: Failure\n    \"\"\"\n    if scheduler == schedulers.REACTOR:\n        return reactor_factory\n    if scheduler == schedulers.ASYNC_IO:\n        return async_io_factory\n\n    txt = f\"Allowed Schedulers: {schedulers.REACTOR}, {schedulers.ASYNC_IO}\"\n    _logger.warning(txt)\n    txt = f'Invalid Scheduler \"{scheduler}\"'\n    raise Exception(txt)\n", "path": "pymodbus/client/asynchronous/factory/serial.py"}]}