Repository: mdabrowski1990/uds (language: python)

Issue:
Introduce basic Transport Interface for python-can
## Requires
#73 
#144 


## Description
As a user, I would like to have possibility to schedule CAN Packet transmission at provided time, so I can control how packets are transmitted.
As a user, I would like to have container that automatically detect received CAN packets and store them, so I have access to entire UDS communication.
As a user, I would like to have possibility to use [python-can](https://pypi.org/project/python-can/) library, so I do not have to buy any expensive tools.


## Testing Strategy
Integration Tests:
- receiving packets is possible (mock the incoming traffic)
- transmitting packets is possible (mock the transmission monitoring)

System Tests:
- GIVEN configured Transport Interface with python-can, WHEN I schedule CAN Packet transmission, THEN it is transmitted to the bus at the first timeslot after the scheduled time is reached, and record of transmitted packet is stored with proper timestamp.
- GIVEN configured Transport Interface with python-can, WHEN UDS CAN packet is received, THEN record of the received packet is stored with proper timestamp.
- GIVEN configured Transprort Interface with python-can, WHEN CAN frame that is not UDS Packet is received, THEN it is not stored by the Transport Interface.
- GIVEN configured Transport Interface with python-can, WHEN python-can bus is used to transmit other frames, THEN it is not blocked by this package.
- GIVEN configured Transport Interface with python-can, WHEN python-can bus is used to receive frames, THEN it is not blocked by this package, neither the package is malfunctioning.


## Acceptance Criteria
- described features are provided
- Provided features are document in [user documentation](https://uds.readthedocs.io/)
- 100% code coverage for this change
- system tests are executed and passing (preferably automatic, but it can be manual if impossible to automate).


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c633a760..5b1c72d9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -13,10 +13,10 @@ jobs:
         python-version: ["3.8", "3.9", "3.10", "3.11"]
 
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
 
       - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v1
+        uses: actions/setup-python@v4
         with:
           python-version: ${{ matrix.python-version }}
 
@@ -32,26 +32,26 @@ jobs:
 
       - name: Execute unit tests with coverage report [pytest]
         run: |
-          pytest --cov-report=term-missing --cov=uds -m "not integration and not performance"
+          pytest tests/software_tests --cov-report=term-missing --cov=uds -m "not integration and not performance"
 
       - name: Execute integration tests with coverage report [pytest]
         run: |
-          pytest --cov-report=term-missing --cov=uds -m "integration"
+          pytest tests/software_tests --cov-report=term-missing --cov=uds -m "integration"
 
 # TODO: uncomment when performance tests are added
 #      - name: Execute performance tests with coverage report [pytest]
 #        run: |
-#          pytest --cov-report=term-missing --cov=uds -m "performance"
+#          pytest tests/software_tests --cov-report=term-missing --cov=uds -m "performance"
 
 
   code_coverage:
     runs-on: ubuntu-latest
 
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
 
       - name: Set up Python 3.11
-        uses: actions/setup-python@v1
+        uses: actions/setup-python@v4
         with:
           python-version: 3.11
 
@@ -72,10 +72,10 @@ jobs:
 
       - name: Execute unit tests [pytest]
         run: |
-          pytest --cov-report=xml --cov=uds -m "not integration and not performance"
+          pytest tests/software_tests --cov-report=xml --cov=uds -m "not integration and not performance"
 
       - name: Upload unit tests report [CodeCov]
-        uses: codecov/codecov-action@v2
+        uses: codecov/codecov-action@v3
         with:
           token: ${{ secrets.CODECOV_TOKEN }}
           files: coverage.xml
@@ -83,10 +83,10 @@ jobs:
 
       - name: Execute integration tests [pytest]
         run: |
-          pytest --cov-report=xml --cov=uds -m "integration"
+          pytest tests/software_tests --cov-report=xml --cov=uds -m "integration"
 
       - name: Upload integration tests report [CodeCov]
-        uses: codecov/codecov-action@v2
+        uses: codecov/codecov-action@v3
         with:
           token: ${{ secrets.CODECOV_TOKEN }}
           files: coverage.xml
@@ -95,10 +95,10 @@ jobs:
 # TODO: uncomment when performance tests are added
 #      - name: Execute performance tests [pytest]
 #        run: |
-#          pytest --cov-report=xml --cov=uds -m "performance"
+#          pytest tests/software_tests --cov-report=xml --cov=uds -m "performance"
 #
 #      - name: Upload performance tests report [CodeCov]
-#        uses: codecov/codecov-action@v2
+#        uses: codecov/codecov-action@v3
 #        with:
 #          token: ${{ secrets.CODECOV_TOKEN }}
 #          files: coverage.xml
@@ -112,10 +112,10 @@ jobs:
         python-version: ["3.8", "3.9", "3.10", "3.11"]
 
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
 
       - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v1
+        uses: actions/setup-python@v4
         with:
           python-version: ${{ matrix.python-version }}
 
@@ -133,10 +133,6 @@ jobs:
         run: |
           prospector --profile tests/prospector_profile.yaml uds
 
-      - name: Execute static code analysis [pyroma]
-        run: |
-          pyroma -a .
-
 
   dependency_checks:
     runs-on: ubuntu-latest
@@ -145,10 +141,10 @@ jobs:
         python-version: ["3.8", "3.9", "3.10", "3.11"]
 
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
 
       - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v1
+        uses: actions/setup-python@v4
         with:
           python-version: ${{ matrix.python-version }}
 
diff --git a/examples/can/kvaser with python-can/config.wcc b/examples/can/kvaser with python-can/config.wcc
new file mode 100644
index 00000000..0f58375a
--- /dev/null
+++ b/examples/can/kvaser with python-can/config.wcc
@@ -0,0 +1,221 @@
+<?xml version="1.0" standalone="yes"?>
+<!DOCTYPE CK[
+ <!ELEMENT CK (DIR)* >
+ <!ELEMENT DIR (DIR|INT|EXTENDED|DOUBLE|BINARY|BOOL|STR)* >
+ <!ELEMENT INT (#PCDATA)>
+ <!ELEMENT EXTENDED (#PCDATA)>
+ <!ELEMENT DOUBLE (#PCDATA)>
+ <!ELEMENT BINARY (#PCDATA)>
+ <!ELEMENT BOOL (#PCDATA)>
+ <!ELEMENT STR (#PCDATA)>
+ <!ATTLIST CK version CDATA #REQUIRED>
+ <!ATTLIST DIR Name CDATA #REQUIRED>
+ <!ATTLIST INT Name CDATA #REQUIRED>
+ <!ATTLIST EXTENDED Name CDATA #REQUIRED>
+ <!ATTLIST DOUBLE Name CDATA #REQUIRED>
+ <!ATTLIST BINARY Name CDATA #REQUIRED>
+ <!ATTLIST BOOL Name CDATA #REQUIRED>
+ <!ATTLIST STR Name CDATA #REQUIRED>
+]>
+<CK version="1.2">
+<DIR Name="Config">
+  <DIR Name="CANKingProj">
+    <DIR Name="ProjMgr">
+      <INT Name="PixelsPerInch">96</INT>
+      <INT Name="Left">515</INT>
+      <INT Name="Top">215</INT>
+      <INT Name="Width">435</INT>
+      <INT Name="Height">300</INT>
+      <INT Name="State">0</INT>
+      <INT Name="Visible">0</INT>
+    </DIR>
+    <DIR Name="Desktop">
+      <INT Name="PixelsPerInch">96</INT>
+      <INT Name="Left">6</INT>
+      <INT Name="Top">21</INT>
+      <INT Name="Width">663</INT>
+      <INT Name="Height">101</INT>
+      <INT Name="State">0</INT>
+      <INT Name="Visible">1</INT>
+      <STR Name="Caption">Kvaser CanKing</STR>
+    </DIR>
+    <DIR Name="ConnectionRules">
+      <STR Name="R0">^TCANKingDialog\.,$,,0,TCanCtrlWin,,0</STR>
+      <STR Name="R1">^TCANKingDialog\.,$,,0,THistoryWindow,,0</STR>
+      <STR Name="R2">TTrafficGenerator$,$,,0,TCanCtrlWin,,0</STR>
+      <STR Name="R3">TTimedTransmission$,$,,0,TCanCtrlWin,,0</STR>
+    </DIR>
+    <DIR Name="Windows">
+      <DIR Name="0">
+        <STR Name="Class">TCanCtrlWin</STR>
+        <INT Name="Left">6</INT>
+        <INT Name="Top">127</INT>
+        <INT Name="Width">340</INT>
+        <INT Name="Height">650</INT>
+        <INT Name="State">0</INT>
+        <INT Name="Visible">1</INT>
+        <STR Name="Caption">CAN 1</STR>
+        <INT Name="PixelsPerInch">96</INT>
+        <INT Name="BitR">1000000</INT>
+        <INT Name="T1">5</INT>
+        <INT Name="T2">2</INT>
+        <INT Name="SJW">2</INT>
+        <INT Name="ArgBitR">500000</INT>
+        <INT Name="ArgT1">63</INT>
+        <INT Name="ArgT2">16</INT>
+        <INT Name="ArgSJW">16</INT>
+        <INT Name="DataBitR">4000000</INT>
+        <INT Name="DataT1">7</INT>
+        <INT Name="DataT2">2</INT>
+        <INT Name="DataSJW">2</INT>
+        <INT Name="Chan">1</INT>
+        <INT Name="Drv">0</INT>
+        <INT Name="CanFd">1</INT>
+        <INT Name="Page">0</INT>
+      </DIR>
+      <DIR Name="1">
+        <STR Name="Class">TFormatter</STR>
+        <INT Name="Left">351</INT>
+        <INT Name="Top">127</INT>
+        <INT Name="Width">319</INT>
+        <INT Name="Height">316</INT>
+        <INT Name="State">0</INT>
+        <INT Name="Visible">1</INT>
+        <STR Name="Caption">Select Formatters</STR>
+        <INT Name="PixelsPerInch">96</INT>
+        <DIR Name="Fmt0">
+          <STR Name="Name">StandardText</STR>
+          <INT Name="Octal">0</INT>
+          <INT Name="Hex">0</INT>
+          <INT Name="DeltaTime">0</INT>
+          <INT Name="ShowAscii">0</INT>
+          <INT Name="DefaultBase">0</INT>
+          <INT Name="CompactHex">0</INT>
+          <INT Name="HistoryList">0</INT>
+        </DIR>
+      </DIR>
+      <DIR Name="2">
+        <STR Name="Class">TOutputWindow</STR>
+        <INT Name="Left">676</INT>
+        <INT Name="Top">21</INT>
+        <INT Name="Width">1724</INT>
+        <INT Name="Height">1061</INT>
+        <INT Name="State">0</INT>
+        <INT Name="Visible">1</INT>
+        <STR Name="Caption">Output Window</STR>
+        <INT Name="PixelsPerInch">96</INT>
+        <INT Name="AutoScroll">1</INT>
+        <INT Name="FixedPos">0</INT>
+      </DIR>
+      <DIR Name="3">
+        <STR Name="Class">THistoryWindow</STR>
+        <INT Name="Left">389</INT>
+        <INT Name="Top">411</INT>
+        <INT Name="Width">453</INT>
+        <INT Name="Height">275</INT>
+        <INT Name="State">0</INT>
+        <INT Name="Visible">0</INT>
+        <STR Name="Caption">History list</STR>
+        <INT Name="PixelsPerInch">96</INT>
+      </DIR>
+      <DIR Name="4">
+        <STR Name="Class">TTimedTransmission</STR>
+        <INT Name="Left">389</INT>
+        <INT Name="Top">411</INT>
+        <INT Name="State">0</INT>
+        <INT Name="Visible">0</INT>
+        <STR Name="Caption">Timed transmission</STR>
+        <INT Name="PixelsPerInch">96</INT>
+        <INT Name="Interval">10</INT>
+        <INT Name="Mode">0</INT>
+        <INT Name="Timing">0</INT>
+      </DIR>
+      <DIR Name="5">
+        <STR Name="Class">TLogToFile</STR>
+        <INT Name="Left">530</INT>
+        <INT Name="Top">448</INT>
+        <INT Name="State">0</INT>
+        <INT Name="Visible">0</INT>
+        <STR Name="Caption">Log To Text File</STR>
+        <INT Name="PixelsPerInch">96</INT>
+        <STR Name="FileName"></STR>
+      </DIR>
+      <DIR Name="6">
+        <STR Name="Class">TTextWindow</STR>
+        <INT Name="Left">389</INT>
+        <INT Name="Top">411</INT>
+        <INT Name="Width">600</INT>
+        <INT Name="Height">233</INT>
+        <INT Name="State">0</INT>
+        <INT Name="Visible">0</INT>
+        <STR Name="Caption">System Messages</STR>
+        <INT Name="PixelsPerInch">96</INT>
+      </DIR>
+      <DIR Name="7">
+        <STR Name="Class">TLogFilePlayer</STR>
+        <INT Name="Left">356</INT>
+        <INT Name="Top">455</INT>
+        <INT Name="State">0</INT>
+        <INT Name="Visible">0</INT>
+        <STR Name="Caption">Log File Player</STR>
+        <INT Name="PixelsPerInch">96</INT>
+        <STR Name="FileName"></STR>
+        <INT Name="AutoStart">1</INT>
+      </DIR>
+      <STR Name="ReverseZOrder">1,0,2</STR>
+    </DIR>
+    <DIR Name="Connections">
+      <STR Name="C0">0,1,0,0</STR>
+      <STR Name="C1">1,2,0,0</STR>
+      <STR Name="C2">3,4,1,0</STR>
+      <STR Name="C3">1,2,1,1</STR>
+      <STR Name="C4">4,0,0,0</STR>
+      <STR Name="C5">1,5,0,0</STR>
+      <STR Name="C6">1,5,1,1</STR>
+      <STR Name="C7">7,4,0,0</STR>
+    </DIR>
+  </DIR>
+  <DIR Name="CKMenu">
+    <DIR Name="0">
+      <STR Name="Parent">$MAIN</STR>
+      <INT Name="InsertBefore">0</INT>
+      <STR Name="TargetItem">View1</STR>
+      <STR Name="Item0">*,&amp;Messages,MsgMenu</STR>
+    </DIR>
+    <DIR Name="MsgMenu">
+      <STR Name="Item0">Universal,C,U,TCanKingDialog.TUtilPage.TUniversalMessage</STR>
+      <STR Name="Item1">Traffic Generator,C,G,TTrafficGenerator</STR>
+      <STR Name="Item2">*,Misc,MiscMenu</STR>
+    </DIR>
+    <DIR Name="MiscMenu">
+      <STR Name="Item0">1-4 Ints,C,I,TCanKingDialog.TUtilPage.TInt4Page</STR>
+      <STR Name="Item1">1-2 Longs,C,L,TCanKingDialog.TUtilPage.TLongintPage</STR>
+      <STR Name="Item2">1-2 Floats,C,F,TCanKingDialog.TUtilPage.TFloatPage</STR>
+      <STR Name="Item3">String,C,S,TCanKingDialog.TUtilPage.TStrPage</STR>
+      <STR Name="Item4">Error Frame,C,E,TCanKingDialog.TUtilPage.TErrorFlagPage</STR>
+    </DIR>
+    <DIR Name="1">
+      <STR Name="Parent">$MAIN</STR>
+      <INT Name="InsertBefore">0</INT>
+      <STR Name="TargetItem">_MsgMenu</STR>
+      <STR Name="Item0">*,&amp;Options,OptionsMenu</STR>
+    </DIR>
+    <DIR Name="OptionsMenu">
+      <STR Name="Item0">&amp;Global...,,,TGlobalOptionsDlg</STR>
+    </DIR>
+  </DIR>
+  <DIR Name="Plugin">
+    <DIR Name="&#123;FC073F12-61C1-11D2-BCE1-0060089830AD&#125;">
+      <INT Name="KingsEnvelope">0</INT>
+      <INT Name="DefaultCityGrpAddress">0</INT>
+      <INT Name="KingsEnvIsExt">0</INT>
+    </DIR>
+  </DIR>
+  <DIR Name="MdiMode">
+    <INT Name="MdiMode">0</INT>
+  </DIR>
+  <DIR Name="Global">
+    <INT Name="UseHex">0</INT>
+  </DIR>
+</DIR>
+</CK>
diff --git a/examples/can/kvaser with python-can/python_can_timing_issue.py b/examples/can/kvaser with python-can/python_can_timing_issue.py
new file mode 100644
index 00000000..0c26d4c5
--- /dev/null
+++ b/examples/can/kvaser with python-can/python_can_timing_issue.py
@@ -0,0 +1,29 @@
+"""UDS Issue: https://github.com/mdabrowski1990/uds/issues/228"""
+
+from time import time
+from threading import Timer
+from can import Notifier, BufferedReader, Bus, Message
+
+if __name__ == "__main__":
+    kvaser_interface_1 = Bus(interface="kvaser", channel=0, fd=True, receive_own_messages=True)
+    kvaser_interface_2 = Bus(interface="kvaser", channel=1, fd=True, receive_own_messages=True)  # connected with bus 1
+
+    buffered_reader = BufferedReader()
+    notifier = Notifier(bus=kvaser_interface_1, listeners=[buffered_reader])
+
+    message = Message(data=[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0], arbitration_id=0x100)
+
+    for _ in range(10):
+        Timer(interval=0.1, function=kvaser_interface_1.send, args=(message,)).start()
+
+        sent_message = buffered_reader.get_message(timeout=1)
+        timestamp_after_send = time()
+
+        print(f"-----------------------------------------------\n"
+              f"Result:\n"
+              f"Message timestamp: {sent_message.timestamp}\n"
+              f"Current timestamp: {timestamp_after_send}\n"
+              f"Message timestamp <= Current timestamp: {sent_message.timestamp <= timestamp_after_send} (expected `True`)")
+
+    kvaser_interface_1.shutdown()
+    kvaser_interface_2.shutdown()
diff --git a/examples/can/kvaser with python-can/receive_packets.py b/examples/can/kvaser with python-can/receive_packets.py
new file mode 100644
index 00000000..6f53fda2
--- /dev/null
+++ b/examples/can/kvaser with python-can/receive_packets.py
@@ -0,0 +1,46 @@
+from pprint import pprint
+from threading import Timer
+from time import sleep
+
+from can import Bus, Message
+from uds.transport_interface import PyCanTransportInterface
+from uds.can import CanAddressingInformation, CanAddressingFormat
+
+if __name__ == "__main__":
+    # configure CAN interfaces
+    kvaser_interface_1 = Bus(interface="kvaser", channel=0, fd=True, receive_own_messages=True)
+    kvaser_interface_2 = Bus(interface="kvaser", channel=1, fd=True, receive_own_messages=True)
+
+    # configure Addressing Information of a CAN Node
+    addressing_information = CanAddressingInformation(
+        addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+        tx_physical={"can_id": 0x611},
+        rx_physical={"can_id": 0x612},
+        tx_functional={"can_id": 0x6FF},
+        rx_functional={"can_id": 0x6FE})
+
+    # create Transport Interface object for UDS communication
+    can_ti = PyCanTransportInterface(can_bus_manager=kvaser_interface_1,
+                                     addressing_information=addressing_information)
+
+    # some frames to be received later on
+    frame_1 = Message(arbitration_id=0x6FE, data=[0x10, 0x03])
+    frame_2 = Message(arbitration_id=0x611, data=[0x10, 0x03])  # shall be ignored, as it is not observed CAN ID
+    frame_3 = Message(arbitration_id=0x612, data=[0x3E, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA])
+
+    # receive CAN packet 1
+    Timer(interval=0.1, function=kvaser_interface_1.send, args=(frame_1,)).start()  # schedule transmission of frame 1
+    record_1 = can_ti.receive_packet(timeout=1000)  # receive CAN packet 1 carried by frame 1
+    pprint(record_1.__dict__)  # show attributes of CAN packet record 1
+
+    # receive CAN packet 2
+    Timer(interval=0.3, function=kvaser_interface_1.send, args=(frame_2,)).start()  # schedule transmission of frame 2
+    Timer(interval=0.8, function=kvaser_interface_1.send, args=(frame_3,)).start()  # schedule transmission of frame 3
+    record_2 = can_ti.receive_packet(timeout=1000)  # receive CAN packet 2 carried by frame 3
+    pprint(record_2.__dict__)  # show attributes of CAN packet record 2
+
+    # close connections with CAN interfaces
+    del can_ti
+    sleep(0.1)  # wait to make sure all tasks are closed
+    kvaser_interface_1.shutdown()
+    kvaser_interface_2.shutdown()
diff --git a/examples/can/kvaser with python-can/receive_packets_asyncio.py b/examples/can/kvaser with python-can/receive_packets_asyncio.py
new file mode 100644
index 00000000..6e78a38f
--- /dev/null
+++ b/examples/can/kvaser with python-can/receive_packets_asyncio.py
@@ -0,0 +1,50 @@
+import asyncio
+from pprint import pprint
+
+from can import Bus, Message
+from uds.transport_interface import PyCanTransportInterface
+from uds.can import CanAddressingInformation, CanAddressingFormat
+
+
+async def main():
+    # configure CAN interfaces
+    kvaser_interface_1 = Bus(interface="kvaser", channel=0, fd=True, receive_own_messages=True)
+    kvaser_interface_2 = Bus(interface="kvaser", channel=1, fd=True, receive_own_messages=True)
+
+    # configure Addressing Information of a CAN Node
+    addressing_information = CanAddressingInformation(
+        addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+        tx_physical={"can_id": 0x611},
+        rx_physical={"can_id": 0x612},
+        tx_functional={"can_id": 0x6FF},
+        rx_functional={"can_id": 0x6FE})
+
+    # create Transport Interface object for UDS communication
+    can_ti = PyCanTransportInterface(can_bus_manager=kvaser_interface_1,
+                                     addressing_information=addressing_information)
+
+    # some frames to be received later on
+    frame_1 = Message(arbitration_id=0x6FE, data=[0x10, 0x03])
+    frame_2 = Message(arbitration_id=0x611, data=[0x10, 0x03])  # shall be ignored, as it is not observed CAN ID
+    frame_3 = Message(arbitration_id=0x612, data=[0x3E, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA])
+
+    # receive CAN packet 1
+    kvaser_interface_2.send(frame_1)  # transmit CAN Frame 1
+    record_1 = await can_ti.async_receive_packet(timeout=1000)   # receive CAN packet 1 carried by frame 1
+    pprint(record_1.__dict__)  # show attributes of CAN packet record 1
+
+    # receive CAN packet 2
+    kvaser_interface_2.send(frame_2)  # transmit CAN Frame 2
+    kvaser_interface_2.send(frame_3)  # transmit CAN Frame 3
+    record_2 = await can_ti.async_receive_packet(timeout=1000)
+    pprint(record_2.__dict__)  # show attributes of CAN packet record 2
+
+    # close connections with CAN interfaces
+    del can_ti
+    await asyncio.sleep(0.1)  # wait to make sure all tasks are closed
+    kvaser_interface_1.shutdown()
+    kvaser_interface_2.shutdown()
+
+
+if __name__ == "__main__":
+    asyncio.run(main())
diff --git a/examples/can/kvaser with python-can/send_packets.py b/examples/can/kvaser with python-can/send_packets.py
new file mode 100644
index 00000000..90f4e72e
--- /dev/null
+++ b/examples/can/kvaser with python-can/send_packets.py
@@ -0,0 +1,52 @@
+from pprint import pprint
+from time import sleep
+
+from can import Bus
+from uds.transport_interface import PyCanTransportInterface
+from uds.can import CanAddressingInformation, CanAddressingFormat
+from uds.message import UdsMessage
+from uds.transmission_attributes import AddressingType
+
+
+def main():
+    # configure CAN interfaces
+    kvaser_interface_1 = Bus(interface="kvaser", channel=0, fd=True, receive_own_messages=True)
+    kvaser_interface_2 = Bus(interface="kvaser", channel=1, fd=True, receive_own_messages=True)
+
+    # configure Addressing Information of a CAN Node
+    addressing_information = CanAddressingInformation(
+        addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+        tx_physical={"can_id": 0x611},
+        rx_physical={"can_id": 0x612},
+        tx_functional={"can_id": 0x6FF},
+        rx_functional={"can_id": 0x6FE})
+
+    # create Transport Interface object for UDS communication
+    can_ti = PyCanTransportInterface(can_bus_manager=kvaser_interface_1,
+                                     addressing_information=addressing_information)
+
+    # define UDS Messages to send
+    message_1 = UdsMessage(addressing_type=AddressingType.PHYSICAL, payload=[0x10, 0x03])
+    message_2 = UdsMessage(addressing_type=AddressingType.FUNCTIONAL, payload=[0x3E])
+
+    # create CAN packets that carries those UDS Messages
+    packet_1 = can_ti.segmenter.segmentation(message_1)[0]
+    packet_2 = can_ti.segmenter.segmentation(message_2)[0]
+
+    # send CAN Packet 1
+    record_1 = can_ti.send_packet(packet_1)
+    pprint(record_1.__dict__)
+
+    # send CAN Packet 2
+    record_2 = can_ti.send_packet(packet_2)
+    pprint(record_2.__dict__)
+
+    # close connections with CAN interfaces
+    del can_ti
+    sleep(0.1)  # wait to make sure all tasks are closed
+    kvaser_interface_1.shutdown()
+    kvaser_interface_2.shutdown()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/examples/can/kvaser with python-can/send_packets_asyncio.py b/examples/can/kvaser with python-can/send_packets_asyncio.py
new file mode 100644
index 00000000..7c734345
--- /dev/null
+++ b/examples/can/kvaser with python-can/send_packets_asyncio.py
@@ -0,0 +1,52 @@
+import asyncio
+from pprint import pprint
+
+from can import Bus
+from uds.transport_interface import PyCanTransportInterface
+from uds.can import CanAddressingInformation, CanAddressingFormat
+from uds.message import UdsMessage
+from uds.transmission_attributes import AddressingType
+
+
+async def main():
+    # configure CAN interfaces
+    kvaser_interface_1 = Bus(interface="kvaser", channel=0, fd=True, receive_own_messages=True)
+    kvaser_interface_2 = Bus(interface="kvaser", channel=1, fd=True, receive_own_messages=True)
+
+    # configure Addressing Information of a CAN Node
+    addressing_information = CanAddressingInformation(
+        addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+        tx_physical={"can_id": 0x611},
+        rx_physical={"can_id": 0x612},
+        tx_functional={"can_id": 0x6FF},
+        rx_functional={"can_id": 0x6FE})
+
+    # create Transport Interface object for UDS communication
+    can_ti = PyCanTransportInterface(can_bus_manager=kvaser_interface_1,
+                                     addressing_information=addressing_information)
+
+    # define UDS Messages to send
+    message_1 = UdsMessage(addressing_type=AddressingType.PHYSICAL, payload=[0x10, 0x03])
+    message_2 = UdsMessage(addressing_type=AddressingType.FUNCTIONAL, payload=[0x3E])
+
+    # create CAN packets that carries those UDS Messages
+    packet_1 = can_ti.segmenter.segmentation(message_1)[0]
+    packet_2 = can_ti.segmenter.segmentation(message_2)[0]
+
+    # send CAN Packet 1
+    record_1 = await can_ti.async_send_packet(packet_1)
+    pprint(record_1.__dict__)
+
+    # send CAN Packet 2
+    record_2 = await can_ti.async_send_packet(packet_2)
+    pprint(record_2.__dict__)
+
+    # close connections with CAN interfaces
+    del can_ti
+    await asyncio.sleep(0.1)  # wait to make sure all tasks are closed
+    kvaser_interface_1.shutdown()
+    kvaser_interface_2.shutdown()
+
+
+if __name__ == "__main__":
+    asyncio.run(main())
diff --git a/pyproject.toml b/pyproject.toml
index dbef4523..5a10d77d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -40,8 +40,8 @@ maintainers = [
     {name="UDS Package Development", email="uds-package-development@googlegroups.com"},
 ]
 dependencies = [
-    "aenum",
-    "python-can"
+    "aenum >=3.0.0, <3.1.13",  # version 3.1.13 contains a breaking change (potentially a defect)
+    "python-can == 4.*"
 ]
 dynamic = ["version"]
 
@@ -60,10 +60,10 @@ Wiki = "https://github.com/mdabrowski1990/uds/wiki"
 
 [project.optional-dependencies]
 test = [
-    "pytest >= 6.0.0",
+    "pytest == 7.*",
     "pytest-cov",
     "pytest-asyncio",
-    "mock"
+    "mock == 4.*"
 ]
 docs = [
     "sphinx",
@@ -101,12 +101,12 @@ docs = [
 
 [tool.setuptools.packages.find]
 include = [
-    "uds*"
+    "uds.*"
 ]
 
 
 [tool.pytest.ini_options]
-minversion = "6.0"
+minversion = "7.0"
 markers = [
     "integration: Software integration tests.",
     "performance: Performance (non-functional) tests."
diff --git a/requirements.txt b/requirements.txt
index 185a99fa..aeea7f7e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,2 @@
-aenum>=3.0.0
-python-can>=3.0.0
\ No newline at end of file
+aenum >=3.0.0, <3.1.13  # version 3.1.13 contains a breaking change (potentially a defect)
+python-can==4.*
\ No newline at end of file
diff --git a/uds/can/__init__.py b/uds/can/__init__.py
index 20f49c36..116f88d1 100644
--- a/uds/can/__init__.py
+++ b/uds/can/__init__.py
@@ -16,7 +16,7 @@
 """
 
 from .addressing_format import CanAddressingFormat, CanAddressingFormatAlias
-from .abstract_addressing_information import AbstractCanAddressingInformation
+from .abstract_addressing_information import AbstractCanAddressingInformation, PacketAIParamsAlias
 from .normal_addressing_information import Normal11BitCanAddressingInformation, NormalFixedCanAddressingInformation
 from .extended_addressing_information import ExtendedCanAddressingInformation
 from .mixed_addressing_information import Mixed11BitCanAddressingInformation, Mixed29BitCanAddressingInformation
diff --git a/uds/can/abstract_addressing_information.py b/uds/can/abstract_addressing_information.py
index 05b4a6ab..bf60471c 100644
--- a/uds/can/abstract_addressing_information.py
+++ b/uds/can/abstract_addressing_information.py
@@ -1,6 +1,6 @@
 """Abstract definition of Addressing Information handler."""
 
-__all__ = ["AbstractCanAddressingInformation"]
+__all__ = ["AbstractCanAddressingInformation", "PacketAIParamsAlias"]
 
 from typing import Optional, TypedDict
 from abc import ABC, abstractmethod
@@ -11,10 +11,21 @@
 from .frame_fields import CanIdHandler
 
 
+class PacketAIParamsAlias(TypedDict):
+    """Alias of :ref:`Addressing Information <knowledge-base-n-ai>` parameters of CAN packets stream."""
+
+    addressing_format: CanAddressingFormatAlias
+    addressing_type: AddressingTypeAlias
+    can_id: int
+    target_address: Optional[int]
+    source_address: Optional[int]
+    address_extension: Optional[int]
+
+
 class AbstractCanAddressingInformation(ABC):
     """Abstract definition of CAN Entity (either server or client) Addressing Information."""
 
-    ADDRESSING_FORMAT_NAME: str = "addressing_format"
+    ADDRESSING_FORMAT_NAME: str = "addressing_format"  # noqa: F841
     """Name of :ref:`CAN Addressing Format <knowledge-base-can-addressing>` parameter in Addressing Information."""
     ADDRESSING_TYPE_NAME: str = CanIdHandler.ADDRESSING_TYPE_NAME
     """Name of :ref:`Addressing Type <knowledge-base-can-addressing>` parameter in Addressing Information."""
@@ -27,6 +38,9 @@ class AbstractCanAddressingInformation(ABC):
     ADDRESS_EXTENSION_NAME: str = "address_extension"
     """Name of Address Extension parameter in Addressing Information."""
 
+    AI_DATA_BYTES_NUMBER: int
+    """Number of CAN Frame data bytes that are used to carry Addressing Information."""
+
     class InputAIParamsAlias(TypedDict, total=False):
         """Alias of :ref:`Addressing Information <knowledge-base-n-ai>` configuration parameters."""
 
@@ -35,23 +49,6 @@ class InputAIParamsAlias(TypedDict, total=False):
         source_address: int
         address_extension: int
 
-    class _OptionalPacketAIParamsAlias(TypedDict, total=False):
-        """Alias of optional :ref:`Addressing Information <knowledge-base-n-ai>` parameters of CAN packets stream."""
-
-        target_address: int
-        source_address: int
-        address_extension: int
-
-    class PacketAIParamsAlias(_OptionalPacketAIParamsAlias, total=True):
-        """Alias of :ref:`Addressing Information <knowledge-base-n-ai>` parameters of CAN packets stream."""
-
-        addressing_format: CanAddressingFormatAlias
-        addressing_type: AddressingTypeAlias
-        can_id: int
-
-    AI_DATA_BYTES_NUMBER: int
-    """Number of CAN Frame data bytes that are used to carry Addressing Information."""
-
     def __init__(self,
                  rx_physical: InputAIParamsAlias,
                  tx_physical: InputAIParamsAlias,
@@ -87,8 +84,7 @@ def rx_packets_physical_ai(self, value: InputAIParamsAlias):
 
         :param value: Addressing Information parameters to set.
         """
-        # lgtm [py/procedure-return-value-used]
-        self.__rx_packets_physical_ai: AbstractCanAddressingInformation.PacketAIParamsAlias \
+        self.__rx_packets_physical_ai: PacketAIParamsAlias \
             = self.validate_packet_ai(**{self.ADDRESSING_TYPE_NAME: AddressingType.PHYSICAL}, **value)
 
     @property
@@ -103,8 +99,7 @@ def tx_packets_physical_ai(self, value: InputAIParamsAlias):
 
         :param value: Addressing Information parameters to set.
         """
-        # lgtm [py/procedure-return-value-used]
-        self.__tx_packets_physical_ai: AbstractCanAddressingInformation.PacketAIParamsAlias \
+        self.__tx_packets_physical_ai: PacketAIParamsAlias \
             = self.validate_packet_ai(**{self.ADDRESSING_TYPE_NAME: AddressingType.PHYSICAL}, **value)
 
     @property
@@ -119,8 +114,7 @@ def rx_packets_functional_ai(self, value: InputAIParamsAlias):
 
         :param value: Addressing Information parameters to set.
         """
-        # lgtm [py/procedure-return-value-used]
-        self.__rx_packets_functional_ai: AbstractCanAddressingInformation.PacketAIParamsAlias \
+        self.__rx_packets_functional_ai: PacketAIParamsAlias \
             = self.validate_packet_ai(**{self.ADDRESSING_TYPE_NAME: AddressingType.FUNCTIONAL}, **value)
 
     @property
@@ -135,8 +129,7 @@ def tx_packets_functional_ai(self, value: InputAIParamsAlias):
 
         :param value: Addressing Information parameters to set.
         """
-        # lgtm [py/procedure-return-value-used]
-        self.__tx_packets_functional_ai: AbstractCanAddressingInformation.PacketAIParamsAlias \
+        self.__tx_packets_functional_ai: PacketAIParamsAlias \
             = self.validate_packet_ai(**{self.ADDRESSING_TYPE_NAME: AddressingType.FUNCTIONAL}, **value)
 
     @classmethod
diff --git a/uds/can/addressing_information.py b/uds/can/addressing_information.py
index 394f24d3..97b237dd 100644
--- a/uds/can/addressing_information.py
+++ b/uds/can/addressing_information.py
@@ -8,12 +8,11 @@
 
 from typing import Optional, Dict, TypedDict, Type
 
-from uds.utilities import RawBytes, RawBytesList, validate_raw_byte, validate_raw_bytes, \
-    InconsistentArgumentsError
+from uds.utilities import RawBytes, RawBytesList, validate_raw_byte, validate_raw_bytes, InconsistentArgumentsError
 from uds.transmission_attributes import AddressingTypeAlias
 from .addressing_format import CanAddressingFormat, CanAddressingFormatAlias
 from .frame_fields import CanIdHandler
-from .abstract_addressing_information import AbstractCanAddressingInformation
+from .abstract_addressing_information import AbstractCanAddressingInformation, PacketAIParamsAlias
 from .normal_addressing_information import Normal11BitCanAddressingInformation, NormalFixedCanAddressingInformation
 from .extended_addressing_information import ExtendedCanAddressingInformation
 from .mixed_addressing_information import Mixed11BitCanAddressingInformation, Mixed29BitCanAddressingInformation
@@ -74,7 +73,7 @@ def validate_packet_ai(cls,
                            target_address: Optional[int] = None,
                            source_address: Optional[int] = None,
                            address_extension: Optional[int] = None
-                           ) -> AbstractCanAddressingInformation.PacketAIParamsAlias:
+                           ) -> PacketAIParamsAlias:
         """
         Validate Addressing Information parameters of a CAN packet.
 
@@ -93,8 +92,7 @@ def validate_packet_ai(cls,
             can_id=can_id,
             target_address=target_address,
             source_address=source_address,
-            address_extension=address_extension
-        )
+            address_extension=address_extension)
 
     @classmethod
     def validate_ai_data_bytes(cls, addressing_format: CanAddressingFormatAlias, ai_data_bytes: RawBytes) -> None:
diff --git a/uds/can/extended_addressing_information.py b/uds/can/extended_addressing_information.py
index 98f16e7d..6f70460d 100644
--- a/uds/can/extended_addressing_information.py
+++ b/uds/can/extended_addressing_information.py
@@ -8,7 +8,7 @@
 from uds.transmission_attributes import AddressingType, AddressingTypeAlias
 from .addressing_format import CanAddressingFormat, CanAddressingFormatAlias
 from .frame_fields import CanIdHandler
-from .abstract_addressing_information import AbstractCanAddressingInformation
+from .abstract_addressing_information import AbstractCanAddressingInformation, PacketAIParamsAlias
 
 
 class ExtendedCanAddressingInformation(AbstractCanAddressingInformation):
@@ -29,7 +29,7 @@ def validate_packet_ai(cls,
                            target_address: Optional[int] = None,
                            source_address: Optional[int] = None,
                            address_extension: Optional[int] = None
-                           ) -> AbstractCanAddressingInformation.PacketAIParamsAlias:
+                           ) -> PacketAIParamsAlias:
         """
         Validate Addressing Information parameters of a CAN packet that uses Extended Addressing format.
 
@@ -53,9 +53,10 @@ def validate_packet_ai(cls,
         if not CanIdHandler.is_extended_addressed_can_id(can_id):  # type: ignore
             raise InconsistentArgumentsError(f"Provided value of CAN ID is not compatible with "
                                              f"Extended Addressing Format. Actual value: {can_id}")
-        return {
-            cls.ADDRESSING_FORMAT_NAME: CanAddressingFormat.EXTENDED_ADDRESSING,  # type: ignore
-            cls.ADDRESSING_TYPE_NAME: addressing_type,
-            cls.CAN_ID_NAME: can_id,
-            cls.TARGET_ADDRESS_NAME: target_address,
-        }
+        return PacketAIParamsAlias(
+            addressing_format=CanAddressingFormat.EXTENDED_ADDRESSING,
+            addressing_type=addressing_type,
+            can_id=can_id,  # type: ignore
+            target_address=target_address,
+            source_address=source_address,
+            address_extension=address_extension)
diff --git a/uds/can/mixed_addressing_information.py b/uds/can/mixed_addressing_information.py
index b5d35592..f346c86c 100644
--- a/uds/can/mixed_addressing_information.py
+++ b/uds/can/mixed_addressing_information.py
@@ -8,7 +8,7 @@
 from uds.transmission_attributes import AddressingType, AddressingTypeAlias
 from .addressing_format import CanAddressingFormat, CanAddressingFormatAlias
 from .frame_fields import CanIdHandler
-from .abstract_addressing_information import AbstractCanAddressingInformation
+from .abstract_addressing_information import AbstractCanAddressingInformation, PacketAIParamsAlias
 
 
 class Mixed11BitCanAddressingInformation(AbstractCanAddressingInformation):
@@ -29,7 +29,7 @@ def validate_packet_ai(cls,
                            target_address: Optional[int] = None,
                            source_address: Optional[int] = None,
                            address_extension: Optional[int] = None
-                           ) -> AbstractCanAddressingInformation.PacketAIParamsAlias:
+                           ) -> PacketAIParamsAlias:
         """
         Validate Addressing Information parameters of a CAN packet that uses Mixed 11-bit Addressing format.
 
@@ -53,12 +53,13 @@ def validate_packet_ai(cls,
         if not CanIdHandler.is_mixed_11bit_addressed_can_id(can_id):  # type: ignore
             raise InconsistentArgumentsError(f"Provided value of CAN ID is not compatible with "
                                              f"Mixed 11-bit Addressing Format. Actual value: {can_id}")
-        return {
-            cls.ADDRESSING_FORMAT_NAME: CanAddressingFormat.MIXED_11BIT_ADDRESSING,  # type: ignore
-            cls.ADDRESSING_TYPE_NAME: addressing_type,
-            cls.CAN_ID_NAME: can_id,
-            cls.ADDRESS_EXTENSION_NAME: address_extension,
-        }
+        return PacketAIParamsAlias(
+            addressing_format=CanAddressingFormat.MIXED_11BIT_ADDRESSING,
+            addressing_type=addressing_type,
+            can_id=can_id,  # type: ignore
+            target_address=target_address,
+            source_address=source_address,
+            address_extension=address_extension)
 
 
 class Mixed29BitCanAddressingInformation(AbstractCanAddressingInformation):
@@ -79,7 +80,7 @@ def validate_packet_ai(cls,
                            target_address: Optional[int] = None,
                            source_address: Optional[int] = None,
                            address_extension: Optional[int] = None
-                           ) -> AbstractCanAddressingInformation.PacketAIParamsAlias:
+                           ) -> PacketAIParamsAlias:
         """
         Validate Addressing Information parameters of a CAN packet that uses Mixed 29-bit Addressing format.
 
@@ -108,14 +109,13 @@ def validate_packet_ai(cls,
                 addressing_type=addressing_type,
                 target_address=target_address,  # type: ignore
                 source_address=source_address)  # type: ignore
-            return {
-                cls.ADDRESSING_FORMAT_NAME: CanAddressingFormat.MIXED_29BIT_ADDRESSING,  # type: ignore
-                cls.ADDRESSING_TYPE_NAME: addressing_type,
-                cls.CAN_ID_NAME: encoded_can_id,
-                cls.TARGET_ADDRESS_NAME: target_address,
-                cls.SOURCE_ADDRESS_NAME: source_address,
-                cls.ADDRESS_EXTENSION_NAME: address_extension,
-            }
+            return PacketAIParamsAlias(
+                addressing_format=CanAddressingFormat.MIXED_29BIT_ADDRESSING,
+                addressing_type=addressing_type,
+                can_id=encoded_can_id,
+                target_address=target_address,
+                source_address=source_address,
+                address_extension=address_extension)
         decoded_info = CanIdHandler.decode_mixed_addressed_29bit_can_id(can_id)
         if addressing_type != decoded_info[CanIdHandler.ADDRESSING_TYPE_NAME]:  # type: ignore
             raise InconsistentArgumentsError(f"Provided value of CAN ID is not compatible with Addressing Type."
@@ -126,11 +126,10 @@ def validate_packet_ai(cls,
         if source_address not in (decoded_info[CanIdHandler.SOURCE_ADDRESS_NAME], None):  # type: ignore
             raise InconsistentArgumentsError(f"Provided value of CAN ID is not compatible with Source Address."
                                              f"Actual values: can_id={can_id}, source_address={source_address}")
-        return {
-            cls.ADDRESSING_FORMAT_NAME: CanAddressingFormat.MIXED_29BIT_ADDRESSING,  # type: ignore
-            cls.ADDRESSING_TYPE_NAME: addressing_type,
-            cls.CAN_ID_NAME: can_id,
-            cls.TARGET_ADDRESS_NAME: decoded_info[CanIdHandler.TARGET_ADDRESS_NAME],
-            cls.SOURCE_ADDRESS_NAME: decoded_info[CanIdHandler.SOURCE_ADDRESS_NAME],
-            cls.ADDRESS_EXTENSION_NAME: address_extension,
-        }
+        return PacketAIParamsAlias(
+            addressing_format=CanAddressingFormat.MIXED_29BIT_ADDRESSING,
+            addressing_type=addressing_type,
+            can_id=can_id,
+            target_address=decoded_info[CanIdHandler.TARGET_ADDRESS_NAME],  # type: ignore
+            source_address=decoded_info[CanIdHandler.SOURCE_ADDRESS_NAME],  # type: ignore
+            address_extension=address_extension)
diff --git a/uds/can/normal_addressing_information.py b/uds/can/normal_addressing_information.py
index 68d88dd9..eb029fd9 100644
--- a/uds/can/normal_addressing_information.py
+++ b/uds/can/normal_addressing_information.py
@@ -8,7 +8,7 @@
 from uds.transmission_attributes import AddressingType, AddressingTypeAlias
 from .addressing_format import CanAddressingFormat, CanAddressingFormatAlias
 from .frame_fields import CanIdHandler
-from .abstract_addressing_information import AbstractCanAddressingInformation
+from .abstract_addressing_information import AbstractCanAddressingInformation, PacketAIParamsAlias
 
 
 class Normal11BitCanAddressingInformation(AbstractCanAddressingInformation):
@@ -29,7 +29,7 @@ def validate_packet_ai(cls,
                            target_address: Optional[int] = None,
                            source_address: Optional[int] = None,
                            address_extension: Optional[int] = None
-                           ) -> AbstractCanAddressingInformation.PacketAIParamsAlias:
+                           ) -> PacketAIParamsAlias:
         """
         Validate Addressing Information parameters of a CAN packet that uses Normal 11-bit Addressing format.
 
@@ -52,11 +52,13 @@ def validate_packet_ai(cls,
         if not CanIdHandler.is_normal_11bit_addressed_can_id(can_id):  # type: ignore
             raise InconsistentArgumentsError(f"Provided value of CAN ID is not compatible with "
                                              f"Normal 11-bit Addressing Format. Actual value: {can_id}")
-        return {
-            cls.ADDRESSING_FORMAT_NAME: CanAddressingFormat.NORMAL_11BIT_ADDRESSING,  # type: ignore
-            cls.ADDRESSING_TYPE_NAME: addressing_type,
-            cls.CAN_ID_NAME: can_id
-        }
+        return PacketAIParamsAlias(
+            addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+            addressing_type=addressing_type,
+            can_id=can_id,  # type: ignore
+            target_address=target_address,
+            source_address=source_address,
+            address_extension=address_extension)
 
 
 class NormalFixedCanAddressingInformation(AbstractCanAddressingInformation):
@@ -77,7 +79,7 @@ def validate_packet_ai(cls,
                            target_address: Optional[int] = None,
                            source_address: Optional[int] = None,
                            address_extension: Optional[int] = None
-                           ) -> AbstractCanAddressingInformation.PacketAIParamsAlias:
+                           ) -> PacketAIParamsAlias:
         """
         Validate Addressing Information parameters of a CAN packet that uses Normal Fixed Addressing format.
 
@@ -109,13 +111,13 @@ def validate_packet_ai(cls,
                 addressing_type=addressing_type,
                 target_address=target_address,  # type: ignore
                 source_address=source_address)  # type: ignore
-            return {
-                cls.ADDRESSING_FORMAT_NAME: CanAddressingFormat.NORMAL_FIXED_ADDRESSING,  # type: ignore
-                cls.ADDRESSING_TYPE_NAME: addressing_type,
-                cls.CAN_ID_NAME: encoded_can_id,
-                cls.TARGET_ADDRESS_NAME: target_address,
-                cls.SOURCE_ADDRESS_NAME: source_address,
-            }
+            return PacketAIParamsAlias(
+                addressing_format=CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
+                addressing_type=addressing_type,
+                can_id=encoded_can_id,
+                target_address=target_address,
+                source_address=source_address,
+                address_extension=address_extension)
         decoded_info = CanIdHandler.decode_normal_fixed_addressed_can_id(can_id)
         if addressing_type != decoded_info[CanIdHandler.ADDRESSING_TYPE_NAME]:  # type: ignore
             raise InconsistentArgumentsError(f"Provided value of CAN ID is not compatible with Addressing Type."
@@ -126,10 +128,10 @@ def validate_packet_ai(cls,
         if source_address not in (decoded_info[CanIdHandler.SOURCE_ADDRESS_NAME], None):  # type: ignore
             raise InconsistentArgumentsError(f"Provided value of CAN ID is not compatible with Source Address."
                                              f"Actual values: can_id={can_id}, source_address={source_address}")
-        return {
-            cls.ADDRESSING_FORMAT_NAME: CanAddressingFormat.NORMAL_FIXED_ADDRESSING,  # type: ignore
-            cls.ADDRESSING_TYPE_NAME: addressing_type,
-            cls.CAN_ID_NAME: can_id,
-            cls.TARGET_ADDRESS_NAME: decoded_info[CanIdHandler.TARGET_ADDRESS_NAME],
-            cls.SOURCE_ADDRESS_NAME: decoded_info[CanIdHandler.SOURCE_ADDRESS_NAME],
-        }
+        return PacketAIParamsAlias(
+            addressing_format=CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
+            addressing_type=addressing_type,
+            can_id=can_id,
+            target_address=decoded_info[CanIdHandler.TARGET_ADDRESS_NAME],  # type: ignore
+            source_address=decoded_info[CanIdHandler.SOURCE_ADDRESS_NAME],  # type: ignore
+            address_extension=address_extension)
diff --git a/uds/message/nrc.py b/uds/message/nrc.py
index deaf136c..f23a85b1 100644
--- a/uds/message/nrc.py
+++ b/uds/message/nrc.py
@@ -228,5 +228,3 @@ class NRC(ByteEnum, ValidatedEnum, ExtendableEnum):
     information is temporality not available. This NRC is in general supported by each diagnostic service, as not
     otherwise stated in the data link specific implementation document, therefore it is not listed in the list of
     applicable response codes of the diagnostic services."""
-
-# TODO: add alias
diff --git a/uds/message/service_identifiers.py b/uds/message/service_identifiers.py
index 1ec6d19e..f76a0873 100644
--- a/uds/message/service_identifiers.py
+++ b/uds/message/service_identifiers.py
@@ -58,11 +58,10 @@ def is_request_sid(cls, value: int) -> bool:
 
         :return: True if value is valid SID, else False.
         """
-        if cls.is_member(value):
-            return True
         if value in POSSIBLE_REQUEST_SIDS:
-            warn(message=f"SID 0x{value:X} is not recognized by this version of the package.",
-                 category=UnrecognizedSIDWarning)
+            if not cls.is_member(value):
+                warn(message=f"SID 0x{value:X} is not recognized by this version of the package.",
+                     category=UnrecognizedSIDWarning)
             return True
         return False
 
@@ -121,11 +120,10 @@ def is_response_sid(cls, value: int) -> bool:
 
         :return: True if value is valid RSID, else False.
         """
-        if cls.is_member(value):
-            return True
         if value in POSSIBLE_RESPONSE_SIDS:
-            warn(message=f"RSID 0x{value:X} is not recognized by this version of the package",
-                 category=UnrecognizedSIDWarning)
+            if not cls.is_member(value):
+                warn(message=f"RSID 0x{value:X} is not recognized by this version of the package",
+                     category=UnrecognizedSIDWarning)
             return True
         return False
 
@@ -135,5 +133,3 @@ def is_response_sid(cls, value: int) -> bool:
 # extend 'ResponseSID' with members that were defined in RequestSID
 for request_sid_member in RequestSID:  # type: ignore
     ResponseSID.add_member(request_sid_member.name, request_sid_member.value + 0x40)
-
-# TODO: add aliases
diff --git a/uds/packet/__init__.py b/uds/packet/__init__.py
index 8b0c064d..f6053d29 100644
--- a/uds/packet/__init__.py
+++ b/uds/packet/__init__.py
@@ -15,5 +15,5 @@
     PacketsSequence, PacketsTuple, PacketsList, \
     PacketsRecordsSequence, PacketsRecordsTuple, PacketsRecordsList
 from .abstract_can_packet_container import AbstractCanPacketContainer
-from .can_packet import CanPacket
+from .can_packet import CanPacket, AnyCanPacket
 from .can_packet_record import CanPacketRecord
diff --git a/uds/packet/can_packet.py b/uds/packet/can_packet.py
index 04909fae..cb056d45 100644
--- a/uds/packet/can_packet.py
+++ b/uds/packet/can_packet.py
@@ -2,7 +2,7 @@
 
 __all__ = ["CanPacket", "AnyCanPacket"]
 
-from typing import Optional, Any, TypedDict
+from typing import Optional, Any
 from warnings import warn
 
 from uds.utilities import AmbiguityError, UnusedArgumentWarning, RawBytes, RawBytesTuple, validate_raw_bytes
@@ -18,7 +18,7 @@
 from .can_packet_type import CanPacketType, CanPacketTypeAlias
 
 
-class CanPacket(AbstractCanPacketContainer, AbstractUdsPacket):  # lgtm [py/conflicting-attributes]
+class CanPacket(AbstractCanPacketContainer, AbstractUdsPacket):
     """
     Definition of a CAN packet.
 
@@ -562,7 +562,7 @@ def __update_ai_data_byte(self) -> None:
             self.__raw_frame_data = tuple(ai_data_bytes + list(self.__raw_frame_data[len(ai_data_bytes):]))
 
 
-class AnyCanPacket(AbstractCanPacketContainer, AbstractUdsPacket):  # lgtm [py/conflicting-attributes]
+class AnyCanPacket(AbstractCanPacketContainer, AbstractUdsPacket):
     """
     Definition of a CAN packet in any format.
 
@@ -577,14 +577,6 @@ class AnyCanPacket(AbstractCanPacketContainer, AbstractUdsPacket):  # lgtm [py/c
         other features that this class is missing.
     """
 
-    class DecodedAIParamsAlias(TypedDict, total=True):
-        """Alias of :ref:`Addressing Information <knowledge-base-n-ai>` parameters encoded in any CAN Packet."""
-
-        addressing_type: Optional[AddressingTypeAlias]
-        target_address: Optional[int]
-        source_address: Optional[int]
-        address_extension: Optional[int]
-
     def __init__(self, *,
                  raw_frame_data: RawBytes,
                  addressing_format: CanAddressingFormatAlias,
@@ -688,7 +680,7 @@ def packet_type(self) -> Optional[int]:  # type: ignore
             return None
         return self.raw_frame_data[ai_data_bytes_number] >> 4
 
-    def get_addressing_information(self) -> DecodedAIParamsAlias:
+    def get_addressing_information(self) -> CanAddressingInformation.DecodedAIParamsAlias:
         """
         Get Addressing Information carried by this packet.
 
diff --git a/uds/packet/can_packet_record.py b/uds/packet/can_packet_record.py
index ab858963..56b4bc17 100644
--- a/uds/packet/can_packet_record.py
+++ b/uds/packet/can_packet_record.py
@@ -20,7 +20,7 @@
 """Alias of supported CAN frames objects."""
 
 
-class CanPacketRecord(AbstractCanPacketContainer, AbstractUdsPacketRecord):  # lgtm [py/conflicting-attributes]
+class CanPacketRecord(AbstractCanPacketContainer, AbstractUdsPacketRecord):
     """
     Definition of a CAN packet Record.
 
@@ -136,7 +136,7 @@ def _validate_frame(value: Any) -> None:
         :raise ValueError: Some attribute of the frame argument is missing or its value is unexpected.
         """
         if isinstance(value, PythonCanMessage):
-            CanIdHandler.validate_can_id(value.arbitration_id, extended_can_id=value.is_extended_id)
+            CanIdHandler.validate_can_id(value.arbitration_id)
             CanDlcHandler.validate_data_bytes_number(len(value.data))
             return None
         raise TypeError(f"Unsupported CAN Frame type was provided. Actual type: {type(value)}")
diff --git a/uds/segmentation/abstract_segmenter.py b/uds/segmentation/abstract_segmenter.py
index acedb04d..b35939bd 100644
--- a/uds/segmentation/abstract_segmenter.py
+++ b/uds/segmentation/abstract_segmenter.py
@@ -2,11 +2,13 @@
 
 __all__ = ["SegmentationError", "AbstractSegmenter"]
 
-from typing import Tuple, Type, Union, Any
+from typing import Optional, Union, Sequence, Type
 from abc import ABC, abstractmethod
 
 from uds.message import UdsMessage, UdsMessageRecord
-from uds.packet import AbstractUdsPacketContainer, PacketsContainersSequence, PacketsTuple
+from uds.packet import AbstractUdsPacketContainer, AbstractUdsPacket, AbstractUdsPacketRecord, \
+    PacketsContainersSequence, PacketsTuple
+from uds.transmission_attributes import AddressingType
 
 
 class SegmentationError(ValueError):
@@ -27,38 +29,54 @@ class AbstractSegmenter(ABC):
 
     @property
     @abstractmethod
-    def supported_packet_classes(self) -> Tuple[Type[AbstractUdsPacketContainer], ...]:
-        """Classes that define packet objects supported by this segmenter."""
+    def supported_packet_class(self) -> Type[AbstractUdsPacket]:
+        """Class of UDS Packet supported by this segmenter."""
 
-    def is_supported_packet(self, value: Any) -> bool:
+    @property
+    @abstractmethod
+    def supported_packet_record_class(self) -> Type[AbstractUdsPacketRecord]:
+        """Class of UDS Packet Record supported by this segmenter."""
+
+    def is_supported_packet_type(self, packet: AbstractUdsPacketContainer) -> bool:
         """
         Check if the argument value is a packet object of a supported type.
 
-        :param value: Value to check.
+        :param packet: Packet object to check.
 
         :return: True if provided value is an object of a supported packet type, False otherwise.
         """
-        return isinstance(value, self.supported_packet_classes)  # type: ignore
+        return isinstance(packet, (self.supported_packet_class, self.supported_packet_record_class))
+
+    @abstractmethod
+    def is_input_packet(self, **kwargs) -> Optional[AddressingType]:
+        """
+        Check if provided frame attributes belong to a UDS packet which is an input for this Segmenter.
+
+        :param kwargs: Attributes of a frame to check.
 
-    def is_supported_packets_sequence(self, value: Any) -> bool:
+        :return: Addressing Type used for transmission of this UDS packet according to the configuration of this
+            Segmenter (if provided attributes belongs to an input UDS packet), otherwise None.
         """
-        Check if the argument value is a packet sequence of a supported type.
 
-        :param value: Value to check.
+    def is_supported_packets_sequence_type(self, packets: Sequence[AbstractUdsPacketContainer]) -> bool:
+        """
+        Check if the argument value is a packets sequence of a supported type.
+
+        :param packets: Packets sequence to check.
 
-        :return: True if provided value is a packet sequence of a supported type, False otherwise.
+        :return: True if provided value is a packets sequence of a supported type, False otherwise.
         """
-        if not isinstance(value, (list, tuple)):
+        if not isinstance(packets, Sequence):
             # not a sequence
             return False
-        if not all(self.is_supported_packet(element) for element in value):
+        if not all(self.is_supported_packet_type(packet) for packet in packets):
             # at least one element is not a packet of a supported type
             return False
         # check if all packets are the same type
-        return len({type(element) for element in value}) == 1
+        return len({type(packet) for packet in packets}) == 1
 
     @abstractmethod
-    def is_complete_packets_sequence(self, packets: PacketsContainersSequence) -> bool:
+    def is_desegmented_message(self, packets: PacketsContainersSequence) -> bool:
         """
         Check whether provided packets are full sequence of packets that form exactly one diagnostic message.
 
@@ -77,7 +95,7 @@ def desegmentation(self, packets: PacketsContainersSequence) -> Union[UdsMessage
 
         :raise SegmentationError: Provided packets are not a complete packet sequence that form a diagnostic message.
 
-        :return: A diagnostic message that is an outcome of UDS packets desegmentation.
+        :return: A diagnostic message that is carried by provided UDS packets.
         """
 
     @abstractmethod
@@ -89,5 +107,5 @@ def segmentation(self, message: UdsMessage) -> PacketsTuple:
 
         :raise SegmentationError: Provided diagnostic message cannot be segmented.
 
-        :return: UDS packets that are an outcome of UDS message segmentation.
+        :return: UDS packet(s) that carry provided diagnostic message.
         """
diff --git a/uds/segmentation/can_segmenter.py b/uds/segmentation/can_segmenter.py
index fb5a5da9..ac2b58e4 100644
--- a/uds/segmentation/can_segmenter.py
+++ b/uds/segmentation/can_segmenter.py
@@ -2,106 +2,94 @@
 
 __all__ = ["CanSegmenter"]
 
-from typing import Union, Tuple, Type
-from copy import copy
+from typing import Optional, Union, Type
 
-from uds.utilities import RawBytesList, validate_raw_byte
+from uds.utilities import RawBytesList, RawBytes, validate_raw_byte
 from uds.transmission_attributes import AddressingType
-from uds.can import AbstractCanAddressingInformation, CanAddressingInformation, \
-    CanAddressingFormat, CanAddressingFormatAlias, \
+from uds.can import AbstractCanAddressingInformation, CanAddressingInformation, PacketAIParamsAlias, \
+    CanAddressingFormatAlias, \
     CanDlcHandler, CanSingleFrameHandler, CanFirstFrameHandler, CanConsecutiveFrameHandler, DEFAULT_FILLER_BYTE
 from uds.packet import CanPacket, CanPacketRecord, CanPacketType, \
-    AbstractUdsPacketContainer, PacketsContainersSequence, PacketsTuple
+    AbstractUdsPacket, AbstractUdsPacketRecord, PacketsContainersSequence, PacketsTuple
 from uds.message import UdsMessage, UdsMessageRecord
 from .abstract_segmenter import AbstractSegmenter, SegmentationError
 
 
-InputAiParamsAlias = Union[AbstractCanAddressingInformation.InputAIParamsAlias,
-                           AbstractCanAddressingInformation.PacketAIParamsAlias]
-"""Alias of :ref:`Addressing Information <knowledge-base-n-ai>` configuration parameters."""
-
-
 class CanSegmenter(AbstractSegmenter):
-    """Segmenter class that provides utilities for segmentation and desegmentation on CAN bus."""
+    """Segmenter class that provides utilities for segmentation and desegmentation specific for CAN bus."""
 
     def __init__(self, *,
-                 addressing_format: CanAddressingFormatAlias,
-                 physical_ai: InputAiParamsAlias,
-                 functional_ai: InputAiParamsAlias,
+                 addressing_information: AbstractCanAddressingInformation,
                  dlc: int = CanDlcHandler.MIN_BASE_UDS_DLC,
                  use_data_optimization: bool = False,
                  filler_byte: int = DEFAULT_FILLER_BYTE) -> None:
         """
         Configure CAN Segmenter.
 
-        :param addressing_format: CAN Addressing format used.
-        :param physical_ai: CAN Addressing Information parameters to use for physically addressed communication.
-        :param functional_ai: CAN Addressing Information parameters to use for functionally addressed communication.
-        :param dlc: Base CAN DLC value to use for CAN Packets.
-        :param use_data_optimization: Information whether to use CAN Frame Data Optimization during segmentation.
-        :param filler_byte: Filler byte value to use for CAN Frame Data Padding during segmentation.
+        :param addressing_information: Addressing Information configuration of a CAN node.
+        :param dlc: Base CAN DLC value to use for creating CAN Packets.
+        :param use_data_optimization: Information whether to use CAN Frame Data Optimization in created CAN Packets
+            during segmentation.
+        :param filler_byte: Filler byte value to use for CAN Frame Data Padding in created CAN Packets during
+            segmentation.
         """
-        CanAddressingFormat.validate_member(addressing_format)
-        self.__addressing_format: CanAddressingFormatAlias = CanAddressingFormat(addressing_format)
-        self.physical_ai = physical_ai  # type: ignore
-        self.functional_ai = functional_ai  # type: ignore
+        self.addressing_information = addressing_information
         self.dlc = dlc
         self.use_data_optimization = use_data_optimization
         self.filler_byte = filler_byte
 
     @property
-    def supported_packet_classes(self) -> Tuple[Type[AbstractUdsPacketContainer], ...]:
-        """Classes that define packet objects supported by this segmenter."""
-        return CanPacket, CanPacketRecord
+    def supported_packet_class(self) -> Type[AbstractUdsPacket]:
+        """Class of UDS Packet supported by CAN segmenter."""
+        return CanPacket
+
+    @property
+    def supported_packet_record_class(self) -> Type[AbstractUdsPacketRecord]:
+        """Class of UDS Packet Record supported by CAN segmenter."""
+        return CanPacketRecord
 
     @property
     def addressing_format(self) -> CanAddressingFormatAlias:
         """CAN Addressing format used."""
-        return self.__addressing_format
+        return self.addressing_information.addressing_format
 
     @property
-    def physical_ai(self) -> AbstractCanAddressingInformation.PacketAIParamsAlias:
-        """CAN Addressing Information parameters used for outgoing physically addressed communication."""
-        return copy(self.__physical_ai)
+    def rx_packets_physical_ai(self) -> PacketAIParamsAlias:
+        """Addressing Information parameters of incoming physically addressed CAN packets."""
+        return self.addressing_information.rx_packets_physical_ai
 
-    @physical_ai.setter
-    def physical_ai(self, value: InputAiParamsAlias):
-        """
-        Set Addressing Information parameters of physically addressed CAN packets.
+    @property
+    def tx_packets_physical_ai(self) -> PacketAIParamsAlias:
+        """Addressing Information parameters of outgoing physically addressed CAN packets."""
+        return self.addressing_information.tx_packets_physical_ai
 
-        :param value: Addressing Information parameters to set.
-        """
-        kwargs = {
-            AbstractCanAddressingInformation.ADDRESSING_FORMAT_NAME: self.addressing_format,
-            AbstractCanAddressingInformation.ADDRESSING_TYPE_NAME: AddressingType.PHYSICAL
-        }
-        for item_name, item_value in value.items():
-            if item_name not in (AbstractCanAddressingInformation.ADDRESSING_FORMAT_NAME,
-                                 AbstractCanAddressingInformation.ADDRESSING_TYPE_NAME):
-                kwargs[item_name] = item_value  # type: ignore
-        self.__physical_ai = CanAddressingInformation.validate_packet_ai(**kwargs)  # type: ignore
+    @property
+    def rx_packets_functional_ai(self) -> PacketAIParamsAlias:
+        """Addressing Information parameters of incoming functionally addressed CAN packets."""
+        return self.addressing_information.rx_packets_functional_ai
+
+    @property
+    def tx_packets_functional_ai(self) -> PacketAIParamsAlias:
+        """Addressing Information parameters of outgoing functionally addressed CAN packets."""
+        return self.addressing_information.tx_packets_functional_ai
 
     @property
-    def functional_ai(self) -> AbstractCanAddressingInformation.PacketAIParamsAlias:
-        """CAN Addressing Information parameters used for outgoing functionally addressed communication."""
-        return copy(self.__functional_ai)
+    def addressing_information(self) -> AbstractCanAddressingInformation:
+        """Addressing Information configuration of a CAN node."""
+        return self.__addressing_information
 
-    @functional_ai.setter
-    def functional_ai(self, value: InputAiParamsAlias):
+    @addressing_information.setter
+    def addressing_information(self, value: AbstractCanAddressingInformation):
         """
-        Set Addressing Information parameters of functionally addressed CAN packets.
+        Set Addressing Information configuration to be used for segmentation and desegmentation.
 
-        :param value: Addressing Information parameters to set.
+        :param value: Addressing Information configuration to set.
+
+        :raise TypeError: Provided value has unexpected type.
         """
-        kwargs = {
-            AbstractCanAddressingInformation.ADDRESSING_FORMAT_NAME: self.addressing_format,
-            AbstractCanAddressingInformation.ADDRESSING_TYPE_NAME: AddressingType.FUNCTIONAL
-        }
-        for item_name, item_value in value.items():
-            if item_name not in (AbstractCanAddressingInformation.ADDRESSING_FORMAT_NAME,
-                                 AbstractCanAddressingInformation.ADDRESSING_TYPE_NAME):
-                kwargs[item_name] = item_value  # type: ignore
-        self.__functional_ai = CanAddressingInformation.validate_packet_ai(**kwargs)  # type: ignore
+        if not isinstance(value, AbstractCanAddressingInformation):
+            raise TypeError(f"Provided `value` is not CAN Addressing Information type. Actual type: {type(value)}")
+        self.__addressing_information: AbstractCanAddressingInformation = value
 
     @property
     def dlc(self) -> int:
@@ -158,6 +146,65 @@ def filler_byte(self, value: int):
         validate_raw_byte(value)
         self.__filler_byte: int = value
 
+    def is_input_packet(self, can_id: int, data: RawBytes) -> Optional[AddressingType]:  # type: ignore # noqa
+        """
+        Check if provided frame attributes belong to a UDS CAN packet which is an input for this CAN Segmenter.
+
+        :param can_id: Identifier of CAN frame to check.
+        :param data: Data field of CAN frame to check.
+
+        :return: Addressing Type used for transmission of this UDS CAN packet according to the configuration of this
+            CAN Segmenter (if provided attributes belongs to an input UDS CAN packet), otherwise None.
+        """
+        try:
+            decoded_frame_ai = CanAddressingInformation.decode_packet_ai(
+                addressing_format=self.addressing_format,
+                can_id=can_id,
+                ai_data_bytes=data[:self.addressing_information.AI_DATA_BYTES_NUMBER])
+            decoded_frame_ai.update(can_id=can_id, addressing_format=self.addressing_format)  # type: ignore
+        except ValueError:
+            return None
+        decoded_frame_ai[AbstractCanAddressingInformation.ADDRESSING_TYPE_NAME] = AddressingType.PHYSICAL  # type: ignore # noqa
+        if self.rx_packets_physical_ai == decoded_frame_ai:
+            return AddressingType.PHYSICAL
+        decoded_frame_ai[AbstractCanAddressingInformation.ADDRESSING_TYPE_NAME] = AddressingType.FUNCTIONAL  # type: ignore # noqa
+        if self.rx_packets_functional_ai == decoded_frame_ai:
+            return AddressingType.FUNCTIONAL
+        return None
+
+    def is_desegmented_message(self, packets: PacketsContainersSequence) -> bool:
+        """
+        Check whether provided packets are full sequence of packets that form exactly one diagnostic message.
+
+        :param packets: Packets sequence to check.
+
+        :raise ValueError: Provided value is not CAN packets sequence.
+        :raise NotImplementedError: There is missing implementation for the provided initial packet type.
+            Please create an issue in our `Issues Tracking System <https://github.com/mdabrowski1990/uds/issues>`_
+            with detailed description if you face this error.
+
+        :return: True if the packets form exactly one diagnostic message.
+            False if there are missing, additional or inconsistent (e.g. two packets that initiate a message) packets.
+        """
+        if not self.is_supported_packets_sequence_type(packets):
+            raise ValueError("Provided packets are not consistent CAN Packets sequence.")
+        if not CanPacketType.is_initial_packet_type(packets[0].packet_type):
+            return False
+        if packets[0].packet_type == CanPacketType.SINGLE_FRAME:
+            return len(packets) == 1
+        if packets[0].packet_type == CanPacketType.FIRST_FRAME:
+            total_payload_size = packets[0].data_length
+            payload_bytes_found = len(packets[0].payload)  # type: ignore
+            for following_packet in packets[1:]:
+                if CanPacketType.is_initial_packet_type(following_packet.packet_type):
+                    return False
+                if payload_bytes_found >= total_payload_size:  # type: ignore
+                    return False
+                if following_packet.payload is not None:
+                    payload_bytes_found += len(following_packet.payload)
+            return payload_bytes_found >= total_payload_size  # type: ignore
+        raise NotImplementedError(f"Unknown packet type received: {packets[0].packet_type}")
+
     def desegmentation(self, packets: PacketsContainersSequence) -> Union[UdsMessage, UdsMessageRecord]:
         """
         Perform desegmentation of CAN packets.
@@ -171,7 +218,7 @@ def desegmentation(self, packets: PacketsContainersSequence) -> Union[UdsMessage
 
         :return: A diagnostic message that is an outcome of CAN packets desegmentation.
         """
-        if not self.is_complete_packets_sequence(packets):
+        if not self.is_desegmented_message(packets):
             raise SegmentationError("Provided packets are not a complete packets sequence")
         if isinstance(packets[0], CanPacketRecord):
             return UdsMessageRecord(packets)  # type: ignore
@@ -210,39 +257,6 @@ def segmentation(self, message: UdsMessage) -> PacketsTuple:
             return self.__functional_segmentation(message)
         raise NotImplementedError(f"Unknown addressing type received: {message.addressing_type}")
 
-    def is_complete_packets_sequence(self, packets: PacketsContainersSequence) -> bool:
-        """
-        Check whether provided packets are full sequence of packets that form exactly one diagnostic message.
-
-        :param packets: Packets sequence to check.
-
-        :raise ValueError: Provided value is not CAN packets sequence.
-        :raise NotImplementedError: There is missing implementation for the provided initial packet type.
-            Please create an issue in our `Issues Tracking System <https://github.com/mdabrowski1990/uds/issues>`_
-            with detailed description if you face this error.
-
-        :return: True if the packets form exactly one diagnostic message.
-            False if there are missing, additional or inconsistent (e.g. two packets that initiate a message) packets.
-        """
-        if not self.is_supported_packets_sequence(packets):
-            raise ValueError("Provided packets are not consistent CAN Packets sequence.")
-        if not CanPacketType.is_initial_packet_type(packets[0].packet_type):
-            return False
-        if packets[0].packet_type == CanPacketType.SINGLE_FRAME:
-            return len(packets) == 1
-        if packets[0].packet_type == CanPacketType.FIRST_FRAME:
-            total_payload_size = packets[0].data_length
-            payload_bytes_found = len(packets[0].payload)  # type: ignore
-            for following_packet in packets[1:]:
-                if CanPacketType.is_initial_packet_type(following_packet.packet_type):
-                    return False
-                if payload_bytes_found >= total_payload_size:  # type: ignore
-                    return False
-                if following_packet.payload is not None:
-                    payload_bytes_found += len(following_packet.payload)
-            return payload_bytes_found >= total_payload_size  # type: ignore
-        raise NotImplementedError(f"Unknown packet type received: {packets[0].packet_type}")
-
     def __physical_segmentation(self, message: UdsMessage) -> PacketsTuple:
         """
         Segment physically addressed diagnostic message.
@@ -263,7 +277,7 @@ def __physical_segmentation(self, message: UdsMessage) -> PacketsTuple:
                                      payload=message.payload,
                                      filler_byte=self.filler_byte,
                                      dlc=None if self.use_data_optimization else self.dlc,
-                                     **self.physical_ai)
+                                     **self.tx_packets_physical_ai)
             return (single_frame,)
         ff_payload_size = CanFirstFrameHandler.get_payload_size(
             addressing_format=self.addressing_format,
@@ -273,7 +287,7 @@ def __physical_segmentation(self, message: UdsMessage) -> PacketsTuple:
                                 payload=message.payload[:ff_payload_size],
                                 dlc=self.dlc,
                                 data_length=message_payload_size,
-                                **self.physical_ai)
+                                **self.tx_packets_physical_ai)
         cf_payload_size = CanConsecutiveFrameHandler.get_max_payload_size(addressing_format=self.addressing_format,
                                                                           dlc=self.dlc)
         total_cfs_number = (message_payload_size - ff_payload_size + cf_payload_size - 1) // cf_payload_size
@@ -288,7 +302,7 @@ def __physical_segmentation(self, message: UdsMessage) -> PacketsTuple:
                                           else self.dlc,
                                           sequence_number=sequence_number,
                                           filler_byte=self.filler_byte,
-                                          **self.physical_ai)
+                                          **self.tx_packets_physical_ai)
             consecutive_frames.append(consecutive_frame)
         return (first_frame, *consecutive_frames)
 
@@ -312,5 +326,5 @@ def __functional_segmentation(self, message: UdsMessage) -> PacketsTuple:
                                  payload=message.payload,
                                  filler_byte=self.filler_byte,
                                  dlc=None if self.use_data_optimization else self.dlc,
-                                 **self.functional_ai)
+                                 **self.tx_packets_functional_ai)
         return (single_frame,)
diff --git a/uds/transmission_attributes/addressing.py b/uds/transmission_attributes/addressing.py
index 73f2d3e7..df15fef2 100644
--- a/uds/transmission_attributes/addressing.py
+++ b/uds/transmission_attributes/addressing.py
@@ -21,9 +21,9 @@ class AddressingType(StrEnum, ValidatedEnum):
     :ref:`Addressing <knowledge-base-addressing>` describes a communication model that is used during UDS communication.
     """
 
-    PHYSICAL = "Physical"
+    PHYSICAL: "AddressingType" = "Physical"  # type: ignore
     """:ref:`Physical addressing <knowledge-base-physical-addressing>` - 1 (client) to 1 (server) communication."""
-    FUNCTIONAL = "Functional"
+    FUNCTIONAL: "AddressingType" = "Functional"  # type: ignore
     """:ref:`Functional addressing <knowledge-base-functional-addressing>` - 1 (client) to many (servers)
     communication."""
 
diff --git a/uds/transport_interface/__init__.py b/uds/transport_interface/__init__.py
index aee2bce5..adcaba2f 100644
--- a/uds/transport_interface/__init__.py
+++ b/uds/transport_interface/__init__.py
@@ -10,5 +10,4 @@
 """
 
 from .abstract_transport_interface import AbstractTransportInterface
-from .abstract_can_transport_interface import AbstractCanTransportInterface
-from .python_can_transport_interface import PyCanTransportInterface
+from .can_transport_interface import AbstractCanTransportInterface, PyCanTransportInterface
diff --git a/uds/transport_interface/abstract_can_transport_interface.py b/uds/transport_interface/abstract_can_transport_interface.py
deleted file mode 100644
index 4897cbf3..00000000
--- a/uds/transport_interface/abstract_can_transport_interface.py
+++ /dev/null
@@ -1,435 +0,0 @@
-"""Abstract definition of UDS Transport Interface for CAN bus."""
-
-__all__ = ["AbstractCanTransportInterface"]
-
-
-from typing import Optional, Union, Any, Iterator, Iterable
-from abc import abstractmethod
-from warnings import warn
-
-from uds.utilities import TimeMilliseconds, ValueWarning
-from uds.packet import CanPacket, CanPacketRecord, CanPacketType
-from uds.can import AbstractCanAddressingInformation, CanFlowStatus, CanSTminTranslator
-from uds.segmentation import CanSegmenter
-from .abstract_transport_interface import AbstractTransportInterface
-from .records_queue import RecordsQueue
-from .transmission_queue import TransmissionQueue
-
-
-FlowControlGeneratorAlias = Union[CanPacket, Iterator[CanPacket]]
-"""Alias of :ref:`Flow Control <knowledge-base-can-flow-control>` CAN Packets generator."""
-
-
-class AbstractCanTransportInterface(AbstractTransportInterface):
-    """
-    Abstract definition of Transport Interface for managing UDS on CAN bus.
-
-    CAN Transport Interfaces are meant to handle UDS middle layers (Transport and Network) on CAN bus.
-    """
-
-    N_AS_TIMEOUT: TimeMilliseconds = 1000
-    """Timeout value of :ref:`N_As <knowledge-base-can-n-as>` time parameter according to ISO 15765-2."""
-    N_AR_TIMEOUT: TimeMilliseconds = 1000
-    """Timeout value of :ref:`N_Ar <knowledge-base-can-n-ar>` time parameter according to ISO 15765-2."""
-    N_BS_TIMEOUT: TimeMilliseconds = 1000
-    """Timeout value of :ref:`N_Bs <knowledge-base-can-n-bs>` time parameter according to ISO 15765-2."""
-    N_CR_TIMEOUT: TimeMilliseconds = 1000
-    """Timeout value of :ref:`N_Cr <knowledge-base-can-n-cr>` time parameter according to ISO 15765-2."""
-
-    DEFAULT_N_BR: TimeMilliseconds = 0
-    """Default value of :ref:`N_Br <knowledge-base-can-n-br>` time parameter."""
-    DEFAULT_N_CS: Optional[TimeMilliseconds] = None
-    """Default value of :ref:`N_Cs <knowledge-base-can-n-br>` time parameter."""
-
-    DEFAULT_FLOW_CONTROL_ARGS = {
-        "packet_type": CanPacketType.FLOW_CONTROL,
-        "flow_status": CanFlowStatus.ContinueToSend,
-        "block_size": 0x10,
-        "st_min": CanSTminTranslator.encode(0),
-    }
-    """Default parameters of Flow Control CAN Packet."""
-
-    def __init__(self,
-                 can_bus_manager: Any,
-                 addressing_information: AbstractCanAddressingInformation,
-                 packet_records_number: int = AbstractTransportInterface.DEFAULT_PACKET_RECORDS_NUMBER,
-                 message_records_number: int = AbstractTransportInterface.DEFAULT_MESSAGE_RECORDS_NUMBER,
-                 **kwargs: Any) -> None:
-        """
-        Create Transport Interface (an object for handling UDS Transport and Network layers).
-
-        :param can_bus_manager: An object that handles CAN bus (Physical and Data layers of OSI Model).
-        :param addressing_information: Addressing Information of CAN Transport Interface.
-        :param packet_records_number: Number of UDS packet records to store.
-        :param message_records_number: Number of UDS Message records to store.
-        :param kwargs: Optional arguments that are specific for CAN bus.
-
-            - :parameter n_as_timeout: Timeout value for :ref:`N_As <knowledge-base-can-n-as>` time parameter.
-            - :parameter n_ar_timeout: Timeout value for :ref:`N_Ar <knowledge-base-can-n-ar>` time parameter.
-            - :parameter n_bs_timeout: Timeout value for :ref:`N_Bs <knowledge-base-can-n-bs>` time parameter.
-            - :parameter n_br: Value of :ref:`N_Br <knowledge-base-can-n-br>` time parameter to use in communication.
-            - :parameter n_cs: Value of :ref:`N_Cs <knowledge-base-can-n-cs>` time parameter to use in communication.
-            - :parameter n_cr_timeout: Timeout value for :ref:`N_Cr <knowledge-base-can-n-cr>` time parameter.
-            - :parameter dlc: Base CAN DLC value to use for CAN Packets.
-            - :parameter use_data_optimization: Information whether to use CAN Frame Data Optimization.
-            - :parameter filler_byte: Filler byte value to use for CAN Frame Data Padding.
-            - :parameter flow_control_generator: Generator of Flow Control CAN packets.
-
-        :raise TypeError: Provided Addressing Information value has unexpected type.
-        """
-        if not isinstance(addressing_information, AbstractCanAddressingInformation):
-            raise TypeError("Unsupported type of Addressing Information was provided.")
-        self.__addressing_information: AbstractCanAddressingInformation = addressing_information
-        super().__init__(bus_manager=can_bus_manager,
-                         message_records_number=message_records_number)
-        self.n_as_timeout = kwargs.pop("n_as_timeout", self.N_AS_TIMEOUT)
-        self.n_ar_timeout = kwargs.pop("n_ar_timeout", self.N_AR_TIMEOUT)
-        self.n_bs_timeout = kwargs.pop("n_bs_timeout", self.N_BS_TIMEOUT)
-        self.n_br = kwargs.pop("n_br", self.DEFAULT_N_BR)
-        self.n_cs = kwargs.pop("n_cs", self.DEFAULT_N_CS)
-        self.n_cr_timeout = kwargs.pop("n_cr_timeout", self.N_CR_TIMEOUT)
-        flow_control_generator = kwargs.pop("flow_control_generator", None)
-        self.__segmenter = CanSegmenter(addressing_format=addressing_information.addressing_format,
-                                        physical_ai=addressing_information.tx_packets_physical_ai,
-                                        functional_ai=addressing_information.tx_packets_functional_ai,
-                                        **kwargs)
-        self.__packet_records_queue = RecordsQueue(records_type=CanPacketRecord, history_size=packet_records_number)
-        self.__packet_transmission_queue = TransmissionQueue(pdu_type=CanPacket)
-        self.flow_control_generator = flow_control_generator if flow_control_generator is not None else \
-            CanPacket(**self.DEFAULT_FLOW_CONTROL_ARGS,
-                      **addressing_information.tx_packets_physical_ai,
-                      dlc=None if self.use_data_optimization else self.dlc,
-                      filler_byte=self.filler_byte)
-
-    @property
-    def _packet_records_queue(self) -> RecordsQueue:
-        """Queue with UDS packet records that were either received or transmitted."""
-        return self.__packet_records_queue
-
-    @property  # noqa
-    def _packet_transmission_queue(self) -> TransmissionQueue:
-        """Queue with UDS packets that are planned for the transmission."""
-        return self.__packet_transmission_queue
-
-    @property
-    def segmenter(self) -> CanSegmenter:
-        """Value of the segmenter used by this CAN Transport Interface."""
-        return self.__segmenter
-
-    # Time parameter - CAN Network Layer
-
-    @property
-    def n_as_timeout(self) -> TimeMilliseconds:
-        """Timeout value for N_As time parameter."""
-        return self.__n_as_timeout
-
-    @n_as_timeout.setter
-    def n_as_timeout(self, value: TimeMilliseconds):
-        """
-        Set timeout value for N_As time parameter.
-
-        :param value: Value of timeout to set.
-
-        :raise TypeError: Provided value is not int or float.
-        :raise ValueError: Provided value is less or equal 0.
-        """
-        if not isinstance(value, (int, float)):
-            raise TypeError("Provided time parameter value must be int or float type.")
-        if value <= 0:
-            raise ValueError("Provided time parameter value must be greater than 0.")
-        if value != self.N_AS_TIMEOUT:
-            warn(message="Non-default value of N_As timeout was set.",
-                 category=ValueWarning)
-        self.__n_as_timeout = value
-
-    @property
-    @abstractmethod
-    def n_as_measured(self) -> Optional[TimeMilliseconds]:
-        """
-        Get the last measured value of N_As time parameter.
-
-        :return: Time in milliseconds or None if the value was never measured.
-        """
-
-    @property
-    def n_ar_timeout(self) -> TimeMilliseconds:
-        """Timeout value for N_Ar time parameter."""
-        return self.__n_ar_timeout
-
-    @n_ar_timeout.setter
-    def n_ar_timeout(self, value: TimeMilliseconds):
-        """
-        Set timeout value for N_Ar time parameter.
-
-        :param value: Value of timeout to set.
-
-        :raise TypeError: Provided value is not int or float.
-        :raise ValueError: Provided value is less or equal 0.
-        """
-        if not isinstance(value, (int, float)):
-            raise TypeError("Provided time parameter value must be int or float type.")
-        if value <= 0:
-            raise ValueError("Provided time parameter value must be greater than 0.")
-        if value != self.N_AR_TIMEOUT:
-            warn(message="Non-default value of N_Ar timeout was set.",
-                 category=ValueWarning)
-        self.__n_ar_timeout = value
-
-    @property
-    @abstractmethod
-    def n_ar_measured(self) -> Optional[TimeMilliseconds]:
-        """
-        Get the last measured value of N_Ar time parameter.
-
-        :return: Time in milliseconds or None if the value was never measured.
-        """
-
-    @property
-    def n_bs_timeout(self) -> TimeMilliseconds:
-        """Timeout value for N_Bs time parameter."""
-        return self.__n_bs_timeout
-
-    @n_bs_timeout.setter
-    def n_bs_timeout(self, value: TimeMilliseconds):
-        """
-        Set timeout value for N_Bs time parameter.
-
-        :param value: Value of timeout to set.
-
-        :raise TypeError: Provided value is not int or float.
-        :raise ValueError: Provided value is less or equal 0.
-        """
-        if not isinstance(value, (int, float)):
-            raise TypeError("Provided time parameter value must be int or float type.")
-        if value <= 0:
-            raise ValueError("Provided time parameter value must be greater than 0.")
-        if value != self.N_BS_TIMEOUT:
-            warn(message="Non-default value of N_Bs timeout was set.",
-                 category=ValueWarning)
-        self.__n_bs_timeout = value
-
-    @property  # noqa
-    @abstractmethod
-    def n_bs_measured(self) -> Optional[TimeMilliseconds]:
-        """
-        Get the last measured value of N_Bs time parameter.
-
-        :return: Time in milliseconds or None if the value was never measured.
-        """
-
-    @property
-    def n_br(self) -> TimeMilliseconds:
-        """
-        Get the value of N_Br time parameter which is currently set.
-
-        .. note:: The actual (observed on the bus) value will be slightly longer as it also includes computation
-            and CAN Interface delays.
-        """
-        return self.__n_br
-
-    @n_br.setter
-    def n_br(self, value: TimeMilliseconds):
-        """
-        Set the value of N_Br time parameter to use.
-
-        :param value: The value to set.
-
-        :raise TypeError: Provided value is not int or float.
-        :raise ValueError: Provided value is out of range.
-        """
-        if not isinstance(value, (int, float)):
-            raise TypeError("Provided time parameter value must be int or float type.")
-        if not 0 <= value < self.n_br_max:
-            raise ValueError("Provided time parameter value is out of range.")
-        self.__n_br = value
-
-    @property
-    def n_br_max(self) -> TimeMilliseconds:
-        """
-        Get the maximum valid value of N_Br time parameter.
-
-        .. warning:: To assess maximal value of :ref:`N_Br <knowledge-base-can-n-br>`, the actual value of
-            :ref:`N_Ar <knowledge-base-can-n-ar>` time parameter is required.
-            Either the latest measured value of N_Ar would be used, or 0ms would be assumed (if there are
-            no measurement result).
-        """
-        n_ar_measured = 0 if self.n_ar_measured is None else self.n_ar_measured
-        return 0.9 * self.n_bs_timeout - n_ar_measured
-
-    @property
-    def n_cs(self) -> Optional[TimeMilliseconds]:
-        """
-        Get the value of N_Cs time parameter which is currently set.
-
-        .. note:: The actual (observed on the bus) value will be slightly longer as it also includes computation
-            and CAN Interface delays.
-        """
-        return self.__n_cs
-
-    @n_cs.setter
-    def n_cs(self, value: Optional[TimeMilliseconds]):
-        """
-        Set the value of N_Cs time parameter to use.
-
-        :param value: The value to set.
-
-        :raise TypeError: Provided value is not int or float.
-        :raise ValueError: Provided value is out of range.
-        """
-        if value is not None:
-            if not isinstance(value, (int, float)):
-                raise TypeError("Provided time parameter value must be int or float type.")
-            if not 0 <= value < self.n_cs_max:
-                raise ValueError("Provided time parameter value is out of range.")
-        self.__n_cs = value
-
-    @property
-    def n_cs_max(self) -> TimeMilliseconds:
-        """
-        Get the maximum valid value of N_Cs time parameter.
-
-        .. warning:: To assess maximal value of :ref:`N_Cs <knowledge-base-can-n-cs>`, the actual value of
-            :ref:`N_As <knowledge-base-can-n-as>` time parameter is required.
-            Either the latest measured value of N_Ar would be used, or 0ms would be assumed (if there are
-            no measurement result).
-        """
-        n_as_measured = 0 if self.n_as_measured is None else self.n_as_measured
-        return 0.9 * self.n_cr_timeout - n_as_measured
-
-    @property
-    def n_cr_timeout(self) -> TimeMilliseconds:
-        """Timeout value for N_Cr time parameter."""
-        return self.__n_cr_timeout
-
-    @n_cr_timeout.setter
-    def n_cr_timeout(self, value: TimeMilliseconds):
-        """
-        Set timeout value for N_Cr time parameter.
-
-        :param value: Value of timeout to set.
-
-        :raise TypeError: Provided value is not int or float.
-        :raise ValueError: Provided value is less or equal 0.
-        """
-        if not isinstance(value, (int, float)):
-            raise TypeError("Provided time parameter value must be int or float type.")
-        if value <= 0:
-            raise ValueError("Provided time parameter value must be greater than 0.")
-        if value != self.N_CR_TIMEOUT:
-            warn(message="Non-default value of N_Cr timeout was set.",
-                 category=ValueWarning)
-        self.__n_cr_timeout = value
-
-    @property  # noqa
-    @abstractmethod
-    def n_cr_measured(self) -> Optional[TimeMilliseconds]:
-        """
-        Get the last measured value of N_Cr time parameter.
-
-        :return: Time in milliseconds or None if the value was never measured.
-        """
-
-    # Communication parameters
-
-    @property
-    def addressing_information(self) -> AbstractCanAddressingInformation:
-        """Addressing Information of Transport Interface."""
-        return self.__addressing_information
-
-    @property
-    def dlc(self) -> int:
-        """
-        Value of base CAN DLC to use for CAN Packets.
-
-        .. note:: All output CAN Packets will have this DLC value set unless
-            :ref:`CAN Frame Data Optimization <knowledge-base-can-data-optimization>` is used.
-        """
-        return self.segmenter.dlc
-
-    @dlc.setter
-    def dlc(self, value: int):
-        """
-        Set value of base CAN DLC to use for CAN Packets.
-
-        :param value: Value to set.
-        """
-        self.segmenter.dlc = value
-
-    @property
-    def use_data_optimization(self) -> bool:
-        """Information whether to use CAN Frame Data Optimization during CAN Packets creation."""
-        return self.segmenter.use_data_optimization
-
-    @use_data_optimization.setter
-    def use_data_optimization(self, value: bool):
-        """
-        Set whether to use CAN Frame Data Optimization during CAN Packets creation.
-
-        :param value: Value to set.
-        """
-        self.segmenter.use_data_optimization = value
-
-    @property
-    def filler_byte(self) -> int:
-        """Filler byte value to use for CAN Frame Data Padding during segmentation."""
-        return self.segmenter.filler_byte
-
-    @filler_byte.setter
-    def filler_byte(self, value: int):
-        """
-        Set value of filler byte to use for CAN Frame Data Padding.
-
-        :param value: Value to set.
-        """
-        self.segmenter.filler_byte = value
-
-    # Flow Control
-
-    @property
-    def flow_control_generator(self) -> FlowControlGeneratorAlias:
-        """Get the generator of Flow Control CAN Packets."""
-        return self.__flow_control_generator
-
-    @flow_control_generator.setter
-    def flow_control_generator(self, value: FlowControlGeneratorAlias):
-        """
-        Set the value of Flow Control generator.
-
-        :param value: The value of Flow Control CAN Packet generator to use.
-            It must be either:
-
-            - object of `CanPacket` class - in this case the same Flow Control CAN Packet will always be used
-            - generator of `CanPacket` objects - built-in functions `iter` and `next` will be used on the generator
-              to restart iteration (upon reception of a new First Frame) and to produce the following
-              Flow Control CAN Packets
-
-        :raise TypeError: Provided value has unexpected type.
-        """
-        if not isinstance(value, (CanPacket, Iterable)):
-            raise TypeError("Provided value is not CAN Packet neither CAN Packet generator.")
-        self.__flow_control_generator = value
-        self.__flow_control_iterator = None
-
-    def _get_flow_control(self, is_first: bool) -> CanPacket:
-        """
-        Get the next Flow Control CAN Packet to send.
-
-        .. warning:: This method is restricted for internal use and shall not be called by the user as it might cause
-            malfunctioning of Flow Control CAN Packets generation.
-
-        :param is_first: Information whether it is the first Flow Control to respond to a message.
-
-            - True - Flow Control to return is the first Flow Control CAN Packet to send in current diagnostic message
-              reception. In other words, it is the first Flow Control which directly responds to
-              :ref:`First Frame <knowledge-base-can-first-frame>`.
-            - False - Flow Control to return is the following Flow Control CAN Packet to send in current
-              diagnostic message reception. In other words, there was at least one Flow Control already sent since
-              the reception of the last :ref:`First Frame <knowledge-base-can-first-frame>`.
-
-        :return: Flow Control CAN Packet to send in this diagnostic message reception
-        """
-        if isinstance(self.flow_control_generator, CanPacket):
-            return self.flow_control_generator
-        if is_first:
-            self.__flow_control_iterator = iter(self.flow_control_generator)  # type: ignore
-        return next(self.__flow_control_iterator)  # type: ignore
diff --git a/uds/transport_interface/abstract_transport_interface.py b/uds/transport_interface/abstract_transport_interface.py
index e70932b0..204ac508 100644
--- a/uds/transport_interface/abstract_transport_interface.py
+++ b/uds/transport_interface/abstract_transport_interface.py
@@ -2,15 +2,13 @@
 
 __all__ = ["AbstractTransportInterface"]
 
-from typing import Optional, Any, Tuple
+from typing import Optional, Any
 from abc import ABC, abstractmethod
+from asyncio import AbstractEventLoop
 
 from uds.utilities import TimeMilliseconds
 from uds.packet import AbstractUdsPacket, AbstractUdsPacketRecord
-from uds.message import UdsMessage, UdsMessageRecord
 from uds.segmentation import AbstractSegmenter
-from .records_queue import RecordsQueue
-from .transmission_queue import TransmissionQueue
 
 
 class AbstractTransportInterface(ABC):
@@ -20,47 +18,17 @@ class AbstractTransportInterface(ABC):
     Transport Interfaces are meant to handle middle layers (Transport and Network) of UDS OSI Model.
     """
 
-    DEFAULT_PACKET_RECORDS_NUMBER: int = 100
-    """Default number of UDS packet records stored."""
-    DEFAULT_MESSAGE_RECORDS_NUMBER: int = 10
-    """Default number of UDS message records stored."""
-
-    def __init__(self,
-                 bus_manager: Any,
-                 message_records_number: int = DEFAULT_MESSAGE_RECORDS_NUMBER) -> None:
+    def __init__(self, bus_manager: Any) -> None:
         """
         Create Transport Interface (an object for handling UDS Transport and Network layers).
 
         :param bus_manager: An object that handles the bus (Physical and Data layers of OSI Model).
-        :param message_records_number: Number of UDS Message records to store.
 
         :raise ValueError: Provided value of bus manager is not supported by this Transport Interface.
         """
         if not self.is_supported_bus_manager(bus_manager):
             raise ValueError("Unsupported bus manager was provided.")
         self.__bus_manager = bus_manager
-        self.__message_records_queue = RecordsQueue(records_type=UdsMessageRecord, history_size=message_records_number)
-        self.__message_transmission_queue = TransmissionQueue(pdu_type=UdsMessage)
-
-    @property
-    @abstractmethod
-    def _packet_records_queue(self) -> RecordsQueue:
-        """Queue with UDS packet records that were either received or transmitted."""
-
-    @property  # noqa
-    @abstractmethod
-    def _packet_transmission_queue(self) -> TransmissionQueue:
-        """Queue with UDS packets that are planned for the transmission."""
-
-    @property
-    def _message_records_queue(self) -> RecordsQueue:
-        """Queue with UDS messages records that were either received or transmitted."""
-        return self.__message_records_queue
-
-    @property  # noqa
-    def _message_transmission_queue(self) -> TransmissionQueue:
-        """Queue with UDS messages that are planned for the transmission."""
-        return self.__message_transmission_queue
 
     @property
     def bus_manager(self) -> Any:
@@ -71,20 +39,15 @@ def bus_manager(self) -> Any:
         """
         return self.__bus_manager
 
-    @property  # noqa
-    def message_records_history(self) -> Tuple[UdsMessageRecord]:
-        """Historic records of UDS messages that were either received or transmitted."""
-        return self._message_records_queue.records_history  # type: ignore
-
-    @property  # noqa
-    def packet_records_history(self) -> Tuple[AbstractUdsPacketRecord]:
-        """Historic records of UDS packets that were either received or transmitted."""
-        return self._packet_records_queue.records_history  # type: ignore
-
     @property
     @abstractmethod
     def segmenter(self) -> AbstractSegmenter:
-        """Value of the segmenter used by this Transport Interface."""
+        """
+        Value of the segmenter used by this Transport Interface.
+
+        .. warning:: Do not change any segmenter attributes as it might cause malfunction of the entire
+            Transport Interface.
+        """
 
     @staticmethod
     @abstractmethod
@@ -97,112 +60,53 @@ def is_supported_bus_manager(bus_manager: Any) -> bool:
         :return: True if provided bus object is compatible with this Transport Interface, False otherwise.
         """
 
-    async def await_packet_received(self,
-                                    timeout: Optional[TimeMilliseconds] = None,  # noqa: F841
-                                    ignore_interruptions: bool = False) -> AbstractUdsPacketRecord:  # noqa: F841
+    @abstractmethod
+    def send_packet(self, packet: AbstractUdsPacket) -> AbstractUdsPacketRecord:
         """
-        Wait until the next UDS packet is received.
-
-        :param timeout: Maximal time (in milliseconds) to wait.
-        :param ignore_interruptions: Flag informing whether to stop if meanwhile UDS packet was transmitted.
-
-            - True - ignore transmitted UDS packets and do not raise InterruptedError
-            - False - raise InterruptedError if UDS packet is transmitted when awaiting
+        Transmit UDS packet.
 
-        :raise TypeError: Timeout value is not int or float type.
-        :raise ValueError: Timeout value is less or equal 0.
-        :raise TimeoutError: Timeout was reached.
-        :raise InterruptedError: UDS packet was transmitted during awaiting.
+        :param packet: A packet to send.
 
-        :return: Record with historic information of a packet that was just received.
+        :return: Record with historic information about transmitted UDS packet.
         """
-        raise NotImplementedError
 
-    async def await_packet_transmitted(self,
-                                       timeout: Optional[TimeMilliseconds] = None,  # noqa: F841
-                                       ignore_interruptions: bool = False) -> AbstractUdsPacketRecord:  # noqa: F841
+    @abstractmethod
+    def receive_packet(self, timeout: Optional[TimeMilliseconds] = None) -> AbstractUdsPacketRecord:
         """
-        Wait until the next UDS packet is transmitted.
+        Receive UDS packet.
 
         :param timeout: Maximal time (in milliseconds) to wait.
-        :param ignore_interruptions: Flag informing whether to stop if meanwhile UDS packet was received.
 
-            - True - ignore received UDS packets and do not raise InterruptedError
-            - False - raise InterruptedError if UDS packet is received when awaiting
-
-        :raise TypeError: Timeout value is not int or float type.
-        :raise ValueError: Timeout value is less or equal 0.
         :raise TimeoutError: Timeout was reached.
-        :raise InterruptedError: UDS packet was received during awaiting.
 
-        :return: Record with historic information of a packet that was just transmitted.
+        :return: Record with historic information about received UDS packet.
         """
-        raise NotImplementedError
 
-    async def await_message_received(self,
-                                     timeout: Optional[TimeMilliseconds] = None,  # noqa: F841
-                                     ignore_interruptions: bool = False) -> UdsMessageRecord:  # noqa: F841
+    @abstractmethod
+    async def async_send_packet(self,
+                                packet: AbstractUdsPacket,
+                                loop: Optional[AbstractEventLoop] = None) -> AbstractUdsPacketRecord:
         """
-        Wait until the next UDS message is received.
-
-        :param timeout: Maximal time (in milliseconds) to wait.
-        :param ignore_interruptions: Flag informing whether to stop if meanwhile UDS packet was transmitted.
-
-            - True - ignore transmitted UDS packets and do not raise InterruptedError
-            - False - raise InterruptedError if UDS packet is transmitted when awaiting
+        Transmit UDS packet asynchronously.
 
-        :raise TypeError: Timeout value is not int or float type.
-        :raise ValueError: Timeout value is less or equal 0.
-        :raise TimeoutError: Timeout was reached.
-        :raise InterruptedError: UDS packet was transmitted during awaiting.
+        :param packet: A packet to send.
+        :param loop: An asyncio event loop to use for scheduling this task.
 
-        :return: Record with historic information of a message that was just received.
+        :return: Record with historic information about transmitted UDS packet.
         """
-        raise NotImplementedError
 
-    async def await_message_transmitted(self,
-                                        timeout: Optional[TimeMilliseconds] = None,  # noqa: F841
-                                        ignore_interruptions: bool = False) -> UdsMessageRecord:  # noqa: F841
+    @abstractmethod
+    async def async_receive_packet(self,
+                                   timeout: Optional[TimeMilliseconds] = None,
+                                   loop: Optional[AbstractEventLoop] = None) -> AbstractUdsPacketRecord:
         """
-        Wait until the next UDS message is transmitted.
+        Receive UDS packet asynchronously.
 
         :param timeout: Maximal time (in milliseconds) to wait.
-        :param ignore_interruptions: Flag informing whether to stop if meanwhile UDS packet was received.
+        :param loop: An asyncio event loop to use for scheduling this task.
 
-            - True - ignore received UDS packets and do not raise InterruptedError
-            - False - raise InterruptedError if UDS packet is received when awaiting
-
-        :raise TypeError: Timeout value is not int or float type.
-        :raise ValueError: Timeout value is less or equal 0.
         :raise TimeoutError: Timeout was reached.
-        :raise InterruptedError: UDS packet was received during awaiting.
-
-        :return: Record with historic information of a message that was just transmitted.
-        """
-        raise NotImplementedError
-
-    def send_packet(self, packet: AbstractUdsPacket, delay: Optional[TimeMilliseconds] = None) -> None:  # noqa: F841
-        """
-        Transmit UDS packet on the configured bus.
-
-        :param packet: A packet to send.
-        :param delay: Value of a delay (in milliseconds) if the transmission to be scheduled in the future.
-            None if the transmission to be executed immediately.
-
-        :raise TypeError: Delay value is not int or float type.
-        :raise ValueError: Delay value is less or equal 0.
-        """
-        raise NotImplementedError
-
-    def send_message(self, message: UdsMessage, delay: Optional[TimeMilliseconds] = None) -> None:  # noqa: F841
-        """
-        Transmit UDS message on the configured bus.
-
-        :param message: A message to send.
-        :param delay: Value of a delay (in milliseconds) if the transmission to be scheduled in the future.
-            None if the transmission to be executed immediately.
+        :raise asyncio.TimeoutError: Timeout was reached.
 
-        :raise TypeError: Delay value is not int or float type.
-        :raise ValueError: Delay value is less or equal 0.
+        :return: Record with historic information about received UDS packet.
         """
-        raise NotImplementedError
diff --git a/uds/transport_interface/can_transport_interface.py b/uds/transport_interface/can_transport_interface.py
new file mode 100644
index 00000000..38b646a3
--- /dev/null
+++ b/uds/transport_interface/can_transport_interface.py
@@ -0,0 +1,681 @@
+"""Definition and implementation of UDS Transport Interface for CAN bus."""
+
+__all__ = ["AbstractCanTransportInterface", "PyCanTransportInterface"]
+
+from typing import Any, Optional
+from abc import abstractmethod
+from warnings import warn
+from asyncio import AbstractEventLoop, wait_for, get_running_loop
+from datetime import datetime
+from time import time
+
+from can import BusABC, AsyncBufferedReader, BufferedReader, Notifier, Message
+
+from uds.utilities import TimeMilliseconds, ValueWarning
+from uds.can import AbstractCanAddressingInformation, CanIdHandler, CanDlcHandler
+from uds.packet import CanPacket, CanPacketRecord, CanPacketType
+from uds.transmission_attributes import TransmissionDirection
+from uds.segmentation import CanSegmenter
+from .abstract_transport_interface import AbstractTransportInterface
+
+
+class AbstractCanTransportInterface(AbstractTransportInterface):
+    """
+    Abstract definition of Transport Interface for managing UDS on CAN bus.
+
+    CAN Transport Interfaces are meant to handle UDS middle layers (Transport and Network) on CAN bus.
+    """
+
+    N_AS_TIMEOUT: TimeMilliseconds = 1000
+    """Timeout value of :ref:`N_As <knowledge-base-can-n-as>` time parameter according to ISO 15765-2."""
+    N_AR_TIMEOUT: TimeMilliseconds = 1000
+    """Timeout value of :ref:`N_Ar <knowledge-base-can-n-ar>` time parameter according to ISO 15765-2."""
+    N_BS_TIMEOUT: TimeMilliseconds = 1000
+    """Timeout value of :ref:`N_Bs <knowledge-base-can-n-bs>` time parameter according to ISO 15765-2."""
+    N_CR_TIMEOUT: TimeMilliseconds = 1000
+    """Timeout value of :ref:`N_Cr <knowledge-base-can-n-cr>` time parameter according to ISO 15765-2."""
+
+    DEFAULT_N_BR: TimeMilliseconds = 0
+    """Default value of :ref:`N_Br <knowledge-base-can-n-br>` time parameter."""
+    DEFAULT_N_CS: Optional[TimeMilliseconds] = None
+    """Default value of :ref:`N_Cs <knowledge-base-can-n-cs>` time parameter."""
+
+    def __init__(self,
+                 can_bus_manager: Any,
+                 addressing_information: AbstractCanAddressingInformation,
+                 **kwargs: Any) -> None:
+        """
+        Create Transport Interface (an object for handling UDS Transport and Network layers).
+
+        :param can_bus_manager: An object that handles CAN bus (Physical and Data layers of OSI Model).
+        :param addressing_information: Addressing Information of CAN Transport Interface.
+        :param kwargs: Optional arguments that are specific for CAN bus.
+
+            - :parameter n_as_timeout: Timeout value for :ref:`N_As <knowledge-base-can-n-as>` time parameter.
+            - :parameter n_ar_timeout: Timeout value for :ref:`N_Ar <knowledge-base-can-n-ar>` time parameter.
+            - :parameter n_bs_timeout: Timeout value for :ref:`N_Bs <knowledge-base-can-n-bs>` time parameter.
+            - :parameter n_br: Value of :ref:`N_Br <knowledge-base-can-n-br>` time parameter to use in communication.
+            - :parameter n_cs: Value of :ref:`N_Cs <knowledge-base-can-n-cs>` time parameter to use in communication.
+            - :parameter n_cr_timeout: Timeout value for :ref:`N_Cr <knowledge-base-can-n-cr>` time parameter.
+            - :parameter dlc: Base CAN DLC value to use for CAN Packets.
+            - :parameter use_data_optimization: Information whether to use CAN Frame Data Optimization.
+            - :parameter filler_byte: Filler byte value to use for CAN Frame Data Padding.
+
+        :raise TypeError: Provided Addressing Information value has unexpected type.
+        """
+        if not isinstance(addressing_information, AbstractCanAddressingInformation):
+            raise TypeError("Unsupported type of Addressing Information was provided.")
+        self.__addressing_information: AbstractCanAddressingInformation = addressing_information
+        super().__init__(bus_manager=can_bus_manager)
+        self.n_as_timeout = kwargs.pop("n_as_timeout", self.N_AS_TIMEOUT)
+        self.n_ar_timeout = kwargs.pop("n_ar_timeout", self.N_AR_TIMEOUT)
+        self.n_bs_timeout = kwargs.pop("n_bs_timeout", self.N_BS_TIMEOUT)
+        self.n_cr_timeout = kwargs.pop("n_cr_timeout", self.N_CR_TIMEOUT)
+        self.n_br = kwargs.pop("n_br", self.DEFAULT_N_BR)
+        self.n_cs = kwargs.pop("n_cs", self.DEFAULT_N_CS)
+        self.__segmenter = CanSegmenter(addressing_information=addressing_information, **kwargs)
+
+    @property
+    def segmenter(self) -> CanSegmenter:
+        """Value of the segmenter used by this CAN Transport Interface."""
+        return self.__segmenter
+
+    # Time parameter - CAN Network Layer
+
+    @property
+    def n_as_timeout(self) -> TimeMilliseconds:
+        """Timeout value for N_As time parameter."""
+        return self.__n_as_timeout
+
+    @n_as_timeout.setter
+    def n_as_timeout(self, value: TimeMilliseconds):
+        """
+        Set timeout value for N_As time parameter.
+
+        :param value: Value of timeout to set.
+
+        :raise TypeError: Provided value is not int or float.
+        :raise ValueError: Provided value is less or equal 0.
+        """
+        if not isinstance(value, (int, float)):
+            raise TypeError("Provided time parameter value must be int or float type.")
+        if value <= 0:
+            raise ValueError("Provided time parameter value must be greater than 0.")
+        if value != self.N_AS_TIMEOUT:
+            warn(message="Non-default value of N_As timeout was set.",
+                 category=ValueWarning)
+        self.__n_as_timeout = value
+
+    @property
+    @abstractmethod
+    def n_as_measured(self) -> Optional[TimeMilliseconds]:
+        """
+        Get the last measured value of N_As time parameter.
+
+        :return: Time in milliseconds or None if the value was never measured.
+        """
+
+    @property
+    def n_ar_timeout(self) -> TimeMilliseconds:
+        """Timeout value for N_Ar time parameter."""
+        return self.__n_ar_timeout
+
+    @n_ar_timeout.setter
+    def n_ar_timeout(self, value: TimeMilliseconds):
+        """
+        Set timeout value for N_Ar time parameter.
+
+        :param value: Value of timeout to set.
+
+        :raise TypeError: Provided value is not int or float.
+        :raise ValueError: Provided value is less or equal 0.
+        """
+        if not isinstance(value, (int, float)):
+            raise TypeError("Provided time parameter value must be int or float type.")
+        if value <= 0:
+            raise ValueError("Provided time parameter value must be greater than 0.")
+        if value != self.N_AR_TIMEOUT:
+            warn(message="Non-default value of N_Ar timeout was set.",
+                 category=ValueWarning)
+        self.__n_ar_timeout = value
+
+    @property
+    @abstractmethod
+    def n_ar_measured(self) -> Optional[TimeMilliseconds]:
+        """
+        Get the last measured value of N_Ar time parameter.
+
+        :return: Time in milliseconds or None if the value was never measured.
+        """
+
+    @property
+    def n_bs_timeout(self) -> TimeMilliseconds:
+        """Timeout value for N_Bs time parameter."""
+        return self.__n_bs_timeout
+
+    @n_bs_timeout.setter
+    def n_bs_timeout(self, value: TimeMilliseconds):
+        """
+        Set timeout value for N_Bs time parameter.
+
+        :param value: Value of timeout to set.
+
+        :raise TypeError: Provided value is not int or float.
+        :raise ValueError: Provided value is less or equal 0.
+        """
+        if not isinstance(value, (int, float)):
+            raise TypeError("Provided time parameter value must be int or float type.")
+        if value <= 0:
+            raise ValueError("Provided time parameter value must be greater than 0.")
+        if value != self.N_BS_TIMEOUT:
+            warn(message="Non-default value of N_Bs timeout was set.",
+                 category=ValueWarning)
+        self.__n_bs_timeout = value
+
+    @property  # noqa
+    @abstractmethod
+    def n_bs_measured(self) -> Optional[TimeMilliseconds]:
+        """
+        Get the last measured value of N_Bs time parameter.
+
+        :return: Time in milliseconds or None if the value was never measured.
+        """
+
+    @property
+    def n_br(self) -> TimeMilliseconds:
+        """
+        Get the value of N_Br time parameter which is currently set.
+
+        .. note:: The actual (observed on the bus) value will be slightly longer as it also includes computation
+            and CAN Interface delays.
+        """
+        return self.__n_br
+
+    @n_br.setter
+    def n_br(self, value: TimeMilliseconds):
+        """
+        Set the value of N_Br time parameter to use.
+
+        :param value: The value to set.
+
+        :raise TypeError: Provided value is not int or float.
+        :raise ValueError: Provided value is out of range.
+        """
+        if not isinstance(value, (int, float)):
+            raise TypeError("Provided time parameter value must be int or float type.")
+        if not 0 <= value < self.n_br_max:
+            raise ValueError("Provided time parameter value is out of range.")
+        self.__n_br = value
+
+    @property
+    def n_br_max(self) -> TimeMilliseconds:
+        """
+        Get the maximum valid value of N_Br time parameter.
+
+        .. warning:: To assess maximal value of :ref:`N_Br <knowledge-base-can-n-br>`, the actual value of
+            :ref:`N_Ar <knowledge-base-can-n-ar>` time parameter is required.
+            Either the latest measured value of N_Ar would be used, or 0ms would be assumed (if there are
+            no measurement result).
+        """
+        n_ar_measured = 0 if self.n_ar_measured is None else self.n_ar_measured
+        return 0.9 * self.n_bs_timeout - n_ar_measured
+
+    @property
+    def n_cs(self) -> Optional[TimeMilliseconds]:
+        """
+        Get the value of N_Cs time parameter which is currently set.
+
+        .. note:: The actual (observed on the bus) value will be slightly longer as it also includes computation
+            and CAN Interface delays.
+        """
+        return self.__n_cs
+
+    @n_cs.setter
+    def n_cs(self, value: Optional[TimeMilliseconds]):
+        """
+        Set the value of N_Cs time parameter to use.
+
+        :param value: The value to set.
+            - None - use timing compatible with STmin value received in a preceding Flow Control packet
+            - int/float type - timing value to be used regardless of a received STmin value
+
+        :raise TypeError: Provided value is not int or float.
+        :raise ValueError: Provided value is out of range.
+        """
+        if value is not None:
+            if not isinstance(value, (int, float)):
+                raise TypeError("Provided time parameter value must be int or float type.")
+            if not 0 <= value < self.n_cs_max:
+                raise ValueError("Provided time parameter value is out of range.")
+        self.__n_cs = value
+
+    @property
+    def n_cs_max(self) -> TimeMilliseconds:
+        """
+        Get the maximum valid value of N_Cs time parameter.
+
+        .. warning:: To assess maximal value of :ref:`N_Cs <knowledge-base-can-n-cs>`, the actual value of
+            :ref:`N_As <knowledge-base-can-n-as>` time parameter is required.
+            Either the latest measured value of N_Ar would be used, or 0ms would be assumed (if there are
+            no measurement result).
+        """
+        n_as_measured = 0 if self.n_as_measured is None else self.n_as_measured
+        return 0.9 * self.n_cr_timeout - n_as_measured
+
+    @property
+    def n_cr_timeout(self) -> TimeMilliseconds:
+        """Timeout value for N_Cr time parameter."""
+        return self.__n_cr_timeout
+
+    @n_cr_timeout.setter
+    def n_cr_timeout(self, value: TimeMilliseconds):
+        """
+        Set timeout value for N_Cr time parameter.
+
+        :param value: Value of timeout to set.
+
+        :raise TypeError: Provided value is not int or float.
+        :raise ValueError: Provided value is less or equal 0.
+        """
+        if not isinstance(value, (int, float)):
+            raise TypeError("Provided time parameter value must be int or float type.")
+        if value <= 0:
+            raise ValueError("Provided time parameter value must be greater than 0.")
+        if value != self.N_CR_TIMEOUT:
+            warn(message="Non-default value of N_Cr timeout was set.",
+                 category=ValueWarning)
+        self.__n_cr_timeout = value
+
+    @property  # noqa
+    @abstractmethod
+    def n_cr_measured(self) -> Optional[TimeMilliseconds]:
+        """
+        Get the last measured value of N_Cr time parameter.
+
+        :return: Time in milliseconds or None if the value was never measured.
+        """
+
+    # Communication parameters
+
+    @property
+    def addressing_information(self) -> AbstractCanAddressingInformation:
+        """Addressing Information of Transport Interface."""
+        return self.__addressing_information
+
+    @property
+    def dlc(self) -> int:
+        """
+        Value of base CAN DLC to use for output CAN Packets.
+
+        .. note:: All output CAN Packets will have this DLC value set unless
+            :ref:`CAN Frame Data Optimization <knowledge-base-can-data-optimization>` is used.
+        """
+        return self.segmenter.dlc
+
+    @dlc.setter
+    def dlc(self, value: int):
+        """
+        Set value of base CAN DLC to use for output CAN Packets.
+
+        :param value: Value to set.
+        """
+        self.segmenter.dlc = value
+
+    @property
+    def use_data_optimization(self) -> bool:
+        """Information whether to use CAN Frame Data Optimization during CAN Packets creation."""
+        return self.segmenter.use_data_optimization
+
+    @use_data_optimization.setter
+    def use_data_optimization(self, value: bool):
+        """
+        Set whether to use CAN Frame Data Optimization during CAN Packets creation.
+
+        :param value: Value to set.
+        """
+        self.segmenter.use_data_optimization = value
+
+    @property
+    def filler_byte(self) -> int:
+        """Filler byte value to use for output CAN Frame Data Padding during segmentation."""
+        return self.segmenter.filler_byte
+
+    @filler_byte.setter
+    def filler_byte(self, value: int):
+        """
+        Set value of filler byte to use for output CAN Frame Data Padding.
+
+        :param value: Value to set.
+        """
+        self.segmenter.filler_byte = value
+
+
+class PyCanTransportInterface(AbstractCanTransportInterface):
+    """
+    Transport Interface for managing UDS on CAN with python-can package as bus handler.
+
+    .. note:: Documentation for python-can package: https://python-can.readthedocs.io/
+    """
+
+    _MAX_LISTENER_TIMEOUT: float = 4280000.  # ms
+    """Maximal timeout value accepted by python-can listeners."""
+    _MIN_NOTIFIER_TIMEOUT: float = 0.0000001  # s
+    """Minimal timeout for notifiers that does not cause malfunctioning of listeners."""
+
+    def __init__(self,
+                 can_bus_manager: BusABC,
+                 addressing_information: AbstractCanAddressingInformation,
+                 **kwargs: Any) -> None:
+        """
+        Create python-can Transport Interface.
+
+        :param can_bus_manager: Python-can bus object for handling CAN.
+
+            .. warning:: Bus must have capability of receiving transmitted frame (``receive_own_messages=True`` set).
+
+        :param addressing_information: Addressing Information of CAN Transport Interface.
+        :param kwargs: Optional arguments that are specific for CAN bus.
+
+            - :parameter n_as_timeout: Timeout value for :ref:`N_As <knowledge-base-can-n-as>` time parameter.
+            - :parameter n_ar_timeout: Timeout value for :ref:`N_Ar <knowledge-base-can-n-ar>` time parameter.
+            - :parameter n_bs_timeout: Timeout value for :ref:`N_Bs <knowledge-base-can-n-bs>` time parameter.
+            - :parameter n_br: Value of :ref:`N_Br <knowledge-base-can-n-br>` time parameter to use in communication.
+            - :parameter n_cs: Value of :ref:`N_Cs <knowledge-base-can-n-cs>` time parameter to use in communication.
+            - :parameter n_cr_timeout: Timeout value for :ref:`N_Cr <knowledge-base-can-n-cr>` time parameter.
+            - :parameter dlc: Base CAN DLC value to use for CAN Packets.
+            - :parameter use_data_optimization: Information whether to use CAN Frame Data Optimization.
+            - :parameter filler_byte: Filler byte value to use for CAN Frame Data Padding.
+        """
+        self.__n_as_measured: Optional[TimeMilliseconds] = None
+        self.__n_ar_measured: Optional[TimeMilliseconds] = None
+        self.__n_bs_measured: Optional[TimeMilliseconds] = None
+        self.__n_cr_measured: Optional[TimeMilliseconds] = None
+        super().__init__(can_bus_manager=can_bus_manager,
+                         addressing_information=addressing_information,
+                         **kwargs)
+        self.__notifier: Optional[Notifier] = None
+        self.__frames_buffer = BufferedReader()
+        self.__async_notifier: Optional[Notifier] = None
+        self.__async_frames_buffer = AsyncBufferedReader()
+
+    def __del__(self):
+        """Safely close all threads open by this object."""
+        self._teardown_notifier(suppress_warning=True)
+        self._teardown_async_notifier(suppress_warning=True)
+
+    @property
+    def n_as_measured(self) -> Optional[TimeMilliseconds]:
+        """
+        Get the last measured value of N_As time parameter.
+
+        :return: Time in milliseconds or None if the value was never measured.
+        """
+        return self.__n_as_measured
+
+    @property
+    def n_ar_measured(self) -> Optional[TimeMilliseconds]:
+        """
+        Get the last measured value of N_Ar time parameter.
+
+        :return: Time in milliseconds or None if the value was never measured.
+        """
+        return self.__n_ar_measured
+
+    @property  # noqa
+    def n_bs_measured(self) -> Optional[TimeMilliseconds]:
+        """
+        Get the last measured value of N_Bs time parameter.
+
+        :return: Time in milliseconds or None if the value was never measured.
+        """
+        return self.__n_bs_measured
+
+    @property  # noqa
+    def n_cr_measured(self) -> Optional[TimeMilliseconds]:
+        """
+        Get the last measured value of N_Cr time parameter.
+
+        :return: Time in milliseconds or None if the value was never measured.
+        """
+        return self.__n_cr_measured
+
+    def _teardown_notifier(self, suppress_warning: bool = False) -> None:
+        """
+        Stop and remove CAN frame notifier for synchronous communication.
+
+        :param suppress_warning: Do not warn about mixing Synchronous and Asynchronous implementation.
+        """
+        if self.__notifier is not None:
+            self.__notifier.stop(self._MIN_NOTIFIER_TIMEOUT)
+            self.__notifier = None
+            if not suppress_warning:
+                warn(message="Asynchronous (`PyCanTransportInterface.async_send_packet`, "
+                             "`PyCanTransportInterface.async_receive_packet methods`) "
+                             "and synchronous (`PyCanTransportInterface.send_packet`, "
+                             "`PyCanTransportInterface.receive_packet methods`) shall not be used together.",
+                     category=UserWarning)
+
+    def _teardown_async_notifier(self, suppress_warning: bool = False) -> None:
+        """
+        Stop and remove CAN frame notifier for asynchronous communication.
+
+        :param suppress_warning: Do not warn about mixing Synchronous and Asynchronous implementation.
+        """
+        if self.__async_notifier is not None:
+            self.__async_notifier.stop(self._MIN_NOTIFIER_TIMEOUT)
+            self.__async_notifier = None
+            if not suppress_warning:
+                if not suppress_warning:
+                    warn(message="Asynchronous (`PyCanTransportInterface.async_send_packet`, "
+                                 "`PyCanTransportInterface.async_receive_packet methods`) "
+                                 "and synchronous (`PyCanTransportInterface.send_packet`, "
+                                 "`PyCanTransportInterface.receive_packet methods`) shall not be used together.",
+                         category=UserWarning)
+
+    def _setup_notifier(self) -> None:
+        """Configure CAN frame notifier for synchronous communication."""
+        self._teardown_async_notifier()
+        if self.__notifier is None:
+            self.__notifier = Notifier(bus=self.bus_manager,
+                                       listeners=[self.__frames_buffer],
+                                       timeout=self._MIN_NOTIFIER_TIMEOUT)
+
+    def _setup_async_notifier(self, loop: AbstractEventLoop) -> None:
+        """
+        Configure CAN frame notifier for asynchronous communication.
+
+        :param loop: An :mod:`asyncio` event loop to use.
+        """
+        self._teardown_notifier()
+        if self.__async_notifier is None:
+            self.__async_notifier = Notifier(bus=self.bus_manager,
+                                             listeners=[self.__async_frames_buffer],
+                                             timeout=self._MIN_NOTIFIER_TIMEOUT,
+                                             loop=loop)
+
+    def clear_frames_buffers(self) -> None:
+        """
+        Clear buffers with transmitted and received frames.
+
+        .. warning:: This will cause that all CAN packets received in a past are no longer accessible.
+        """
+        for _ in range(self.__frames_buffer.buffer.qsize()):
+            self.__frames_buffer.buffer.get_nowait()
+        for _ in range(self.__async_frames_buffer.buffer.qsize()):
+            self.__async_frames_buffer.buffer.get_nowait()
+
+    @staticmethod
+    def is_supported_bus_manager(bus_manager: Any) -> bool:
+        """
+        Check whether provided value is a bus manager that is supported by this Transport Interface.
+
+        :param bus_manager: Value to check.
+
+        :return: True if provided bus object is compatible with this Transport Interface, False otherwise.
+        """
+        return isinstance(bus_manager, BusABC)
+
+    def send_packet(self, packet: CanPacket) -> CanPacketRecord:  # type: ignore
+        """
+        Transmit CAN packet.
+
+        .. warning:: Must not be called within an asynchronous function.
+
+        :param packet: CAN packet to send.
+
+        :return: Record with historic information about transmitted CAN packet.
+        """
+        time_start = time()
+        if not isinstance(packet, CanPacket):
+            raise TypeError("Provided packet value does not contain a CAN Packet.")
+        is_flow_control_packet = packet.packet_type == CanPacketType.FLOW_CONTROL
+        timeout = self.n_ar_timeout if is_flow_control_packet else self.n_as_timeout
+        can_message = Message(arbitration_id=packet.can_id,
+                              is_extended_id=CanIdHandler.is_extended_can_id(packet.can_id),
+                              data=packet.raw_frame_data,
+                              is_fd=CanDlcHandler.is_can_fd_specific_dlc(packet.dlc))
+        self._setup_notifier()
+        self.clear_frames_buffers()
+        self.bus_manager.send(can_message)
+        observed_frame = None
+        while observed_frame is None \
+                or observed_frame.arbitration_id != packet.can_id \
+                or tuple(observed_frame.data) != packet.raw_frame_data \
+                or not observed_frame.is_rx \
+                or observed_frame.timestamp < time_start:
+            timeout_left = timeout / 1000. - (time() - time_start)
+            if timeout_left <= 0:
+                raise TimeoutError("Timeout was reached before observing a CAN Packet being transmitted.")
+            observed_frame = self.__frames_buffer.get_message(timeout=timeout_left)
+        if is_flow_control_packet:
+            self.__n_ar_measured = observed_frame.timestamp - time_start
+        else:
+            self.__n_as_measured = observed_frame.timestamp - time_start
+        return CanPacketRecord(frame=observed_frame,
+                               direction=TransmissionDirection.TRANSMITTED,
+                               addressing_type=packet.addressing_type,
+                               addressing_format=packet.addressing_format,
+                               transmission_time=datetime.fromtimestamp(observed_frame.timestamp))
+
+    def receive_packet(self, timeout: Optional[TimeMilliseconds] = None) -> CanPacketRecord:
+        """
+        Receive CAN packet.
+
+        .. warning:: Must not be called within an asynchronous function.
+
+        :param timeout: Maximal time (in milliseconds) to wait.
+
+        :raise TypeError: Provided timeout value is not None neither int nor float type.
+        :raise ValueError: Provided timeout value is less or equal 0.
+        :raise TimeoutError: Timeout was reached.
+
+        :return: Record with historic information about received CAN packet.
+        """
+        time_start = time()
+        if timeout is not None:
+            if not isinstance(timeout, (int, float)):
+                raise TypeError("Provided timeout value is not None neither int nor float type.")
+            if timeout <= 0:
+                raise ValueError("Provided timeout value is less or equal 0.")
+        self._setup_notifier()
+        packet_addressing_type = None
+        while packet_addressing_type is None:
+            time_now = time()
+            timeout_left = self._MAX_LISTENER_TIMEOUT if timeout is None else timeout / 1000. - (time_now - time_start)
+            if timeout_left <= 0:
+                raise TimeoutError("Timeout was reached before a CAN Packet was received.")
+            received_frame = self.__frames_buffer.get_message(timeout=timeout_left)
+            if received_frame is None:
+                raise TimeoutError("Timeout was reached before a CAN Packet was received.")
+            packet_addressing_type = self.segmenter.is_input_packet(can_id=received_frame.arbitration_id,
+                                                                    data=received_frame.data)
+        return CanPacketRecord(frame=received_frame,
+                               direction=TransmissionDirection.RECEIVED,
+                               addressing_type=packet_addressing_type,
+                               addressing_format=self.segmenter.addressing_format,
+                               transmission_time=datetime.fromtimestamp(received_frame.timestamp))
+
+    async def async_send_packet(self,
+                                packet: CanPacket,  # type: ignore
+                                loop: Optional[AbstractEventLoop] = None) -> CanPacketRecord:
+        """
+        Transmit CAN packet.
+
+        :param packet: CAN packet to send.
+        :param loop: An asyncio event loop used for observing messages.
+
+        :raise TypeError: Provided packet is not CAN Packet.
+
+        :return: Record with historic information about transmitted CAN packet.
+        """
+        time_start = time()
+        if not isinstance(packet, CanPacket):
+            raise TypeError("Provided packet value does not contain a CAN Packet.")
+        loop = get_running_loop() if loop is None else loop
+        is_flow_control_packet = packet.packet_type == CanPacketType.FLOW_CONTROL
+        timeout = self.n_ar_timeout if is_flow_control_packet else self.n_as_timeout
+        self._setup_async_notifier(loop)
+        self.clear_frames_buffers()
+        can_message = Message(arbitration_id=packet.can_id,
+                              is_extended_id=CanIdHandler.is_extended_can_id(packet.can_id),
+                              data=packet.raw_frame_data,
+                              is_fd=CanDlcHandler.is_can_fd_specific_dlc(packet.dlc))
+        self.bus_manager.send(can_message)
+        observed_frame = None
+        while observed_frame is None \
+                or observed_frame.arbitration_id != packet.can_id \
+                or tuple(observed_frame.data) != packet.raw_frame_data \
+                or not observed_frame.is_rx \
+                or observed_frame.timestamp < time_start:
+            timeout_left = timeout / 1000. - (time() - time_start)
+            observed_frame = await wait_for(self.__async_frames_buffer.get_message(), timeout=timeout_left)
+        if is_flow_control_packet:
+            self.__n_ar_measured = observed_frame.timestamp - time_start
+        else:
+            self.__n_as_measured = observed_frame.timestamp - time_start
+        return CanPacketRecord(frame=observed_frame,
+                               direction=TransmissionDirection.TRANSMITTED,
+                               addressing_type=packet.addressing_type,
+                               addressing_format=packet.addressing_format,
+                               transmission_time=datetime.fromtimestamp(observed_frame.timestamp))
+
+    async def async_receive_packet(self,
+                                   timeout: Optional[TimeMilliseconds] = None,
+                                   loop: Optional[AbstractEventLoop] = None) -> CanPacketRecord:
+        """
+        Receive CAN packet.
+
+        :param timeout: Maximal time (in milliseconds) to wait.
+        :param loop: An asyncio event loop used for observing messages.
+
+        :raise TypeError: Provided timeout value is not None neither int nor float type.
+        :raise ValueError: Provided timeout value is less or equal 0.
+        :raise TimeoutError: Timeout was reached.
+
+        :return: Record with historic information about received CAN packet.
+        """
+        time_start = time()
+        if timeout is not None:
+            if not isinstance(timeout, (int, float)):
+                raise TypeError("Provided timeout value is not None neither int nor float type.")
+            if timeout <= 0:
+                raise ValueError("Provided timeout value is less or equal 0.")
+        loop = get_running_loop() if loop is None else loop
+        self._setup_async_notifier(loop)
+        packet_addressing_type = None
+        while packet_addressing_type is None:
+            if timeout is None:
+                timeout_left = None
+            else:
+                timeout_left = timeout / 1000. - (time() - time_start)
+                if timeout_left <= 0:
+                    raise TimeoutError("Timeout was reached before a CAN Packet was received.")
+            received_frame = await wait_for(self.__async_frames_buffer.get_message(),
+                                            timeout=timeout_left)
+            packet_addressing_type = self.segmenter.is_input_packet(can_id=received_frame.arbitration_id,
+                                                                    data=received_frame.data)
+        return CanPacketRecord(frame=received_frame,
+                               direction=TransmissionDirection.RECEIVED,
+                               addressing_type=packet_addressing_type,
+                               addressing_format=self.segmenter.addressing_format,
+                               transmission_time=datetime.fromtimestamp(received_frame.timestamp))
diff --git a/uds/transport_interface/python_can_transport_interface.py b/uds/transport_interface/python_can_transport_interface.py
deleted file mode 100644
index fc6bb856..00000000
--- a/uds/transport_interface/python_can_transport_interface.py
+++ /dev/null
@@ -1,103 +0,0 @@
-"""
-Implementation of python-can Transport Interface.
-
-Documentation for python-can package: https://python-can.readthedocs.io/
-"""
-
-__all__ = ["PyCanTransportInterface"]
-
-from typing import Optional, Any
-
-from can import BusABC
-
-from uds.utilities import TimeMilliseconds
-from uds.can import AbstractCanAddressingInformation
-from .abstract_transport_interface import AbstractTransportInterface
-from .abstract_can_transport_interface import AbstractCanTransportInterface
-
-
-class PyCanTransportInterface(AbstractCanTransportInterface):
-    """Transport Interface for managing UDS on CAN using python-can package."""
-
-    def __init__(self,
-                 can_bus_manager: Any,
-                 addressing_information: AbstractCanAddressingInformation,
-                 packet_records_number: int = AbstractTransportInterface.DEFAULT_PACKET_RECORDS_NUMBER,
-                 message_records_number: int = AbstractTransportInterface.DEFAULT_MESSAGE_RECORDS_NUMBER,
-                 **kwargs: Any) -> None:
-        """
-        Create python-can Transport Interface.
-
-        :param can_bus_manager: An object that handles CAN bus (Physical and Data layers of OSI Model).
-        :param addressing_information: Addressing Information of CAN Transport Interface.
-        :param packet_records_number: Number of UDS packet records to store.
-        :param message_records_number: Number of UDS Message records to store.
-        :param kwargs: Optional arguments that are specific for CAN bus.
-
-            - :parameter n_as_timeout: Timeout value for :ref:`N_As <knowledge-base-can-n-as>` time parameter.
-            - :parameter n_ar_timeout: Timeout value for :ref:`N_Ar <knowledge-base-can-n-ar>` time parameter.
-            - :parameter n_bs_timeout: Timeout value for :ref:`N_Bs <knowledge-base-can-n-bs>` time parameter.
-            - :parameter n_br: Value of :ref:`N_Br <knowledge-base-can-n-br>` time parameter to use in communication.
-            - :parameter n_cs: Value of :ref:`N_Cs <knowledge-base-can-n-cs>` time parameter to use in communication.
-            - :parameter n_cr_timeout: Timeout value for :ref:`N_Cr <knowledge-base-can-n-cr>` time parameter.
-            - :parameter dlc: Base CAN DLC value to use for CAN Packets.
-            - :parameter use_data_optimization: Information whether to use CAN Frame Data Optimization.
-            - :parameter filler_byte: Filler byte value to use for CAN Frame Data Padding.
-            - :parameter flow_control_generator: Generator of Flow Control CAN packets.
-        """
-        self.__n_as_measured: Optional[TimeMilliseconds] = None
-        self.__n_ar_measured: Optional[TimeMilliseconds] = None
-        self.__n_bs_measured: Optional[TimeMilliseconds] = None
-        self.__n_cr_measured: Optional[TimeMilliseconds] = None
-        super().__init__(can_bus_manager=can_bus_manager,
-                         addressing_information=addressing_information,
-                         packet_records_number=packet_records_number,
-                         message_records_number=message_records_number,
-                         **kwargs)
-
-    @property
-    def n_as_measured(self) -> Optional[TimeMilliseconds]:
-        """
-        Get the last measured value of N_As time parameter.
-
-        :return: Time in milliseconds or None if the value was never measured.
-        """
-        return self.__n_as_measured
-
-    @property
-    def n_ar_measured(self) -> Optional[TimeMilliseconds]:
-        """
-        Get the last measured value of N_Ar time parameter.
-
-        :return: Time in milliseconds or None if the value was never measured.
-        """
-        return self.__n_ar_measured
-
-    @property  # noqa
-    def n_bs_measured(self) -> Optional[TimeMilliseconds]:
-        """
-        Get the last measured value of N_Bs time parameter.
-
-        :return: Time in milliseconds or None if the value was never measured.
-        """
-        return self.__n_bs_measured
-
-    @property  # noqa
-    def n_cr_measured(self) -> Optional[TimeMilliseconds]:
-        """
-        Get the last measured value of N_Cr time parameter.
-
-        :return: Time in milliseconds or None if the value was never measured.
-        """
-        return self.__n_cr_measured
-
-    @staticmethod
-    def is_supported_bus_manager(bus_manager: Any) -> bool:
-        """
-        Check whether provided value is a bus manager that is supported by this Transport Interface.
-
-        :param bus_manager: Value to check.
-
-        :return: True if provided bus object is compatible with this Transport Interface, False otherwise.
-        """
-        return isinstance(bus_manager, BusABC)
diff --git a/uds/transport_interface/records_queue.py b/uds/transport_interface/records_queue.py
deleted file mode 100644
index b4aa95e2..00000000
--- a/uds/transport_interface/records_queue.py
+++ /dev/null
@@ -1,99 +0,0 @@
-"""Implementation of queues with historic records."""
-
-__all__ = ["RecordsQueue"]
-
-from typing import Union, Type, Tuple, List
-from asyncio import Event
-
-from uds.message import UdsMessageRecord
-from uds.packet import AbstractUdsPacketRecord
-
-
-class RecordsQueue:
-    """Queue with historic records of UDS Packets or Messages."""
-
-    RecordsTypeAlias = Union[Type[UdsMessageRecord], Type[AbstractUdsPacketRecord]]
-    """Alias of a record type that is accepted by this Queue."""
-    RecordAlias = Union[UdsMessageRecord, AbstractUdsPacketRecord]
-    """Alias of a record stored by this Queue."""
-
-    def __init__(self, records_type: RecordsTypeAlias, history_size: int) -> None:
-        """
-        Create FIFO queue with historic records of UDS Packets or Messages.
-
-        :param records_type: Type of records to store.
-        :param history_size: Number of records to store.
-
-        :raise TypeError: Provided value has unsupported type.
-        :raise ValueError: Provided value is out of range.
-        """
-        if not issubclass(records_type, (UdsMessageRecord, AbstractUdsPacketRecord)):
-            raise TypeError("Provided 'records_type' value does not store supported record class.")
-        if not isinstance(history_size, int):
-            raise TypeError("Provided 'history_size' value is not int type.")
-        if history_size <= 0:
-            raise ValueError("Provided value of 'history_size' is lower than 0.")
-        self.__records_type = records_type
-        self.__history_size: int = history_size
-        self.__total_records_number: int = 0
-        self.__records_history: List[Union[UdsMessageRecord, AbstractUdsPacketRecord]] = []
-        self.__event_new_record = Event()
-
-    @property
-    def records_type(self) -> RecordsTypeAlias:
-        """Type of records stored by this queue."""
-        return self.__records_type
-
-    @property
-    def history_size(self) -> int:
-        """
-        Get number of records stored by this queue.
-
-        .. note:: If a record beyond this number is received, then the oldest one is pushed out of the queue.
-        """
-        return self.__history_size
-
-    @property  # noqa: F841
-    def total_records_number(self) -> int:
-        """Total number of records that went through the queue."""
-        return self.__total_records_number
-
-    @property
-    def records_history(self) -> Tuple[RecordAlias, ...]:
-        """Historic records from the youngest to the oldest."""
-        return tuple(self.__records_history)
-
-    def clear_records_history(self) -> None:
-        """Clear all stored records."""
-        self.__records_history = []
-        self.__total_records_number = 0
-
-    def put_record(self, record: RecordAlias) -> None:
-        """
-        Add a new record to the queue.
-
-        :param record: A new record to add.
-
-        :raise TypeError: Provided record value has unexpected type.
-        """
-        if not isinstance(record, self.records_type):
-            raise TypeError("Provided value has unexpected type.")
-        self.__records_history.insert(0, record)
-        self.__records_history = self.__records_history[:self.history_size]
-        self.__total_records_number += 1
-        self.__event_new_record.set()
-
-    async def get_next_record(self) -> RecordAlias:
-        """
-        Get the next record to enter the queue.
-
-        .. warning:: More than one record might enter the queue when awaited.
-            Regardless of the number of new records, always the next record would be returned.
-
-        :return: The next record that was put to the queue.
-        """
-        self.__event_new_record.clear()
-        records_number_at_start = self.total_records_number
-        await self.__event_new_record.wait()
-        records_number_with_new_records = self.total_records_number
-        return self.records_history[records_number_with_new_records - records_number_at_start - 1]
diff --git a/uds/transport_interface/transmission_queue.py b/uds/transport_interface/transmission_queue.py
deleted file mode 100644
index 8e26d6be..00000000
--- a/uds/transport_interface/transmission_queue.py
+++ /dev/null
@@ -1,126 +0,0 @@
-"""Implementation of a queue with PDUs to transmit."""
-
-__all__ = ["TransmissionQueue"]
-
-from typing import Union, Optional, Type, Set
-from warnings import warn
-from time import perf_counter
-from asyncio import PriorityQueue, Event, QueueEmpty, wait_for
-from asyncio import TimeoutError as AsyncioTimeoutError
-
-from uds.message import UdsMessage
-from uds.packet import AbstractUdsPacket
-
-
-PDUTypeAlias = Union[Type[UdsMessage], Type[AbstractUdsPacket]]
-"""Alias of a PDU type that is accepted by this Queue."""
-PDUAlias = Union[UdsMessage, AbstractUdsPacket]
-"""Alias of a PDU (either a message or a packet) stored by this Queue."""
-
-
-class TransmissionQueue:
-    """Queue with PDUs to transmit."""
-
-    def __init__(self, pdu_type: PDUTypeAlias) -> None:
-        """
-        Create timestamped queue with PDUs to transmit.
-
-        :param pdu_type: Type of PDUs to store.
-
-        :raise TypeError: Provided value has unsupported type.
-        """
-        if not issubclass(pdu_type, (UdsMessage, AbstractUdsPacket)):
-            raise TypeError("Provided 'pdu_type' value does not store supported UDS message or packet class.")
-        self.__pdu_type = pdu_type
-        self.__async_queue: PriorityQueue = PriorityQueue()
-        self.__event_pdu_added: Event = Event()
-        self.__timestamps: Set[float] = set()
-
-    def __len__(self) -> int:
-        """Get number of elements that are currently stored."""
-        return self.__async_queue.qsize()
-
-    async def __pdu_ready(self) -> float:
-        """
-        Await until the next PDU's timestamp is achieved.
-
-        :return: The lowest timestamp of a PDU that is ready for transmission.
-        """
-        min_timestamp = min(self.__timestamps) if self.__timestamps else float("inf")
-        current_time = perf_counter()
-        while current_time < min_timestamp:
-            self.__event_pdu_added.clear()
-            try:
-                await wait_for(fut=self.__event_pdu_added.wait(), timeout=min_timestamp - current_time)
-            except AsyncioTimeoutError:
-                return min_timestamp
-            current_time = perf_counter()
-            min_timestamp = min(self.__timestamps)
-        return min_timestamp
-
-    @property
-    def pdu_type(self) -> PDUTypeAlias:
-        """Type of PDUs stored by this queue."""
-        return self.__pdu_type
-
-    @property  # noqa
-    def is_empty(self) -> bool:
-        """Flag whether the queue is empty (does not contain any PDUs)."""
-        return len(self) == 0
-
-    def mark_pdu_sent(self) -> None:
-        """
-        Inform that one PDU transmission was completed or aborted.
-
-        This method is used for monitoring PDU transmission tasks, so they can be completed safely and closed quietly.
-        """
-        self.__async_queue.task_done()
-
-    def clear(self) -> None:
-        """Delete all PDUs stored by the queue."""
-        for _ in range(len(self)):
-            try:
-                self.__async_queue.get_nowait()
-            except QueueEmpty:
-                warn(message=f"At least one packet was gotten from {self} queue during the clearing.",
-                     category=RuntimeWarning)
-                break
-            else:
-                self.mark_pdu_sent()
-
-    async def get_pdu(self) -> PDUAlias:
-        """
-        Get the next PDU from the queue.
-
-        .. note:: If called when there are no packets available in the queue, then the method would await until
-            the next packet is ready (timestamp is achieved).
-
-        :raise RuntimeError: Internal implementation problem occurred.
-
-        :return: The next PDU from the queue.
-        """
-        min_timestamp = await self.__pdu_ready()
-        packet_timestamp, pdu = self.__async_queue.get_nowait()
-        if min_timestamp != packet_timestamp:
-            raise RuntimeError("Something went wrong - packet_timestamp does not match the lowest timestamp.")
-        self.__timestamps.remove(packet_timestamp)
-        return pdu
-
-    def put_pdu(self, pdu: PDUAlias, timestamp: Optional[float] = None) -> None:
-        """
-        Add a PDU to the queue.
-
-        :param pdu: A PDU to add to the queue.
-        :param timestamp: Timestamp value (from perf_counter) when make the packet available (gettable) in the queue.
-
-        :raise TypeError: Provided PDU or timestamp value has unexpected type.
-        """
-        if not isinstance(pdu, self.pdu_type):
-            raise TypeError("Provided PDU value has unexpected type.")
-        if timestamp is None:
-            timestamp = perf_counter()
-        elif not isinstance(timestamp, float):
-            raise TypeError("Provided timestamp value is not float (perf_counter) value.")
-        self.__async_queue.put_nowait((timestamp, pdu))
-        self.__timestamps.add(timestamp)
-        self.__event_pdu_added.set()


Test patch:
diff --git a/tests/prospector_profile.yaml b/tests/prospector_profile.yaml
index c31685d5..0cd940ad 100644
--- a/tests/prospector_profile.yaml
+++ b/tests/prospector_profile.yaml
@@ -6,6 +6,7 @@ doc-warnings: true
 autodetect: false
 test-warnings: true
 
+
 # default tools configuration: http://prospector.landscape.io/en/master/supported_tools.html#defaults
 
 pep8:
@@ -35,11 +36,6 @@ pep257:
     - D212
     - D407
     - D413
-# Should I add these? For details visit:
-#  https://stackoverflow.com/questions/66408022/what-is-the-reason-for-d407-error-raised-by-pydocstyle
-#    - D213
-#    - D215
-#    - D408
 
 mccabe:
   run: true
@@ -57,8 +53,8 @@ mypy:
 vulture:
   run: true
 
-bandit:  # there is probably no use of it (not applicable for this project), but it is run anyways to make sure everything is secured
+bandit:  # there is probably no use of it (not applicable for this project), but it is run anyway to make sure everything is secured
   run: true
 
 pyroma:
-  run: false
+  run: true
diff --git a/tests/requirements_for_software_tests.txt b/tests/requirements_for_software_tests.txt
index 3fffb44b..4e1de699 100644
--- a/tests/requirements_for_software_tests.txt
+++ b/tests/requirements_for_software_tests.txt
@@ -1,4 +1,4 @@
-pytest>=6.2.2
-pytest-cov>=3.0.0
+pytest==7.*
+pytest-cov==3.*
 pytest-asyncio>=0.17.2
-mock>=4.0.2
\ No newline at end of file
+mock==4.*
\ No newline at end of file
diff --git a/tests/software_tests/can/test_abstract_addressing_information.py b/tests/software_tests/can/test_abstract_addressing_information.py
index 2e7376da..9c830578 100644
--- a/tests/software_tests/can/test_abstract_addressing_information.py
+++ b/tests/software_tests/can/test_abstract_addressing_information.py
@@ -4,12 +4,13 @@
 from uds.can.abstract_addressing_information import AbstractCanAddressingInformation, AddressingType
 
 
+SCRIPT_LOCATION = "uds.can.abstract_addressing_information"
+
+
 class TestAbstractCanAddressingInformation:
     """Unit tests for `AbstractCanAddressingInformation` class."""
 
-    SCRIPT_LOCATION = "uds.can.abstract_addressing_information"
-
-    def setup(self):
+    def setup_method(self):
         self.mock_addressing_information = Mock(spec=AbstractCanAddressingInformation,
                                                 ADDRESSING_FORMAT_NAME="addressing_format",
                                                 ADDRESSING_TYPE_NAME="addressing_type",
@@ -17,10 +18,10 @@ def setup(self):
                                                 SOURCE_ADDRESS_NAME="source_address",
                                                 ADDRESS_EXTENSION_NAME="address_extension")
         # patching
-        self._patcher_deepcopy = patch(f"{self.SCRIPT_LOCATION}.deepcopy")
+        self._patcher_deepcopy = patch(f"{SCRIPT_LOCATION}.deepcopy")
         self.mock_deepcopy = self._patcher_deepcopy.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_deepcopy.stop()
 
     # __init__
diff --git a/tests/software_tests/can/test_addressing_information.py b/tests/software_tests/can/test_addressing_information.py
index d877f096..27c48a09 100644
--- a/tests/software_tests/can/test_addressing_information.py
+++ b/tests/software_tests/can/test_addressing_information.py
@@ -6,33 +6,34 @@
 from uds.transmission_attributes import AddressingType
 
 
+SCRIPT_LOCATION = "uds.can.addressing_information"
+
+
 class TestCanAddressingInformation:
     """Unit tests for `CanAddressingInformation` class."""
 
-    SCRIPT_LOCATION = "uds.can.addressing_information"
-
-    def setup(self):
+    def setup_method(self):
         # patching
-        self._patcher_can_id_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanIdHandler")
+        self._patcher_can_id_handler_class = patch(f"{SCRIPT_LOCATION}.CanIdHandler")
         self.mock_can_id_handler_class = self._patcher_can_id_handler_class.start()
-        self._patcher_validate_addressing_format = patch(f"{self.SCRIPT_LOCATION}.CanAddressingFormat.validate_member")
+        self._patcher_validate_addressing_format = patch(f"{SCRIPT_LOCATION}.CanAddressingFormat.validate_member")
         self.mock_validate_addressing_format = self._patcher_validate_addressing_format.start()
-        self._patcher_normal_11bit_ai_class = patch(f"{self.SCRIPT_LOCATION}.Normal11BitCanAddressingInformation")
+        self._patcher_normal_11bit_ai_class = patch(f"{SCRIPT_LOCATION}.Normal11BitCanAddressingInformation")
         self.mock_normal_11bit_ai_class = self._patcher_normal_11bit_ai_class.start()
-        self._patcher_normal_fixed_ai_class = patch(f"{self.SCRIPT_LOCATION}.NormalFixedCanAddressingInformation")
+        self._patcher_normal_fixed_ai_class = patch(f"{SCRIPT_LOCATION}.NormalFixedCanAddressingInformation")
         self.mock_normal_fixed_ai_class = self._patcher_normal_fixed_ai_class.start()
-        self._patcher_extended_ai_class = patch(f"{self.SCRIPT_LOCATION}.ExtendedCanAddressingInformation")
+        self._patcher_extended_ai_class = patch(f"{SCRIPT_LOCATION}.ExtendedCanAddressingInformation")
         self.mock_extended_ai_class = self._patcher_extended_ai_class.start()
-        self._patcher_mixed_11bit_ai_class = patch(f"{self.SCRIPT_LOCATION}.Mixed11BitCanAddressingInformation")
+        self._patcher_mixed_11bit_ai_class = patch(f"{SCRIPT_LOCATION}.Mixed11BitCanAddressingInformation")
         self.mock_mixed_11bit_ai_class = self._patcher_mixed_11bit_ai_class.start()
-        self._patcher_mixed_29bit_ai_class = patch(f"{self.SCRIPT_LOCATION}.Mixed29BitCanAddressingInformation")
+        self._patcher_mixed_29bit_ai_class = patch(f"{SCRIPT_LOCATION}.Mixed29BitCanAddressingInformation")
         self.mock_mixed_29bit_ai_class = self._patcher_mixed_29bit_ai_class.start()
-        self._patcher_validate_raw_bytes = patch(f"{self.SCRIPT_LOCATION}.validate_raw_bytes")
+        self._patcher_validate_raw_bytes = patch(f"{SCRIPT_LOCATION}.validate_raw_bytes")
         self.mock_validate_raw_bytes = self._patcher_validate_raw_bytes.start()
-        self._patcher_validate_raw_byte = patch(f"{self.SCRIPT_LOCATION}.validate_raw_byte")
+        self._patcher_validate_raw_byte = patch(f"{SCRIPT_LOCATION}.validate_raw_byte")
         self.mock_validate_raw_byte = self._patcher_validate_raw_byte.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_can_id_handler_class.stop()
         self._patcher_validate_addressing_format.stop()
         self._patcher_normal_11bit_ai_class.stop()
@@ -248,6 +249,7 @@ def test_get_ai_data_bytes_number(self, mock_ai_mapping, addressing_format):
         mock_ai_mapping.__getitem__.assert_called_once_with(addressing_format)
 
 
+@pytest.mark.integration
 class TestCanAddressingInformationIntegration:
     """Integration tests for `CanAddressingInformation` class."""
 
@@ -259,16 +261,28 @@ class TestCanAddressingInformationIntegration:
           "tx_functional": {"can_id": 0x6FF}},
          {"rx_packets_physical_ai": {"addressing_format": CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
                                      "addressing_type": AddressingType.PHYSICAL,
-                                     "can_id": 0x601},
+                                     "can_id": 0x601,
+                                     "target_address": None,
+                                     "source_address": None,
+                                     "address_extension": None},
           "tx_packets_physical_ai": {"addressing_format": CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
                                      "addressing_type": AddressingType.PHYSICAL,
-                                     "can_id": 0x602},
+                                     "can_id": 0x602,
+                                     "target_address": None,
+                                     "source_address": None,
+                                     "address_extension": None},
           "rx_packets_functional_ai": {"addressing_format": CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
                                        "addressing_type": AddressingType.FUNCTIONAL,
-                                       "can_id": 0x6FE},
+                                       "can_id": 0x6FE,
+                                       "target_address": None,
+                                       "source_address": None,
+                                       "address_extension": None},
           "tx_packets_functional_ai": {"addressing_format": CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
                                        "addressing_type": AddressingType.FUNCTIONAL,
-                                       "can_id": 0x6FF}}),
+                                       "can_id": 0x6FF,
+                                       "target_address": None,
+                                       "source_address": None,
+                                       "address_extension": None}}),
         ({"addressing_format": CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
           "rx_physical": {"can_id": 0x18DA0E2B},
           "tx_physical": {"target_address": 0x2B, "source_address": 0x0E},
@@ -278,22 +292,26 @@ class TestCanAddressingInformationIntegration:
                                      "addressing_type": AddressingType.PHYSICAL,
                                      "can_id": 0x18DA0E2B,
                                      "target_address": 0x0E,
-                                     "source_address": 0x2B},
+                                     "source_address": 0x2B,
+                                     "address_extension": None},
           "tx_packets_physical_ai": {"addressing_format": CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
                                      "addressing_type": AddressingType.PHYSICAL,
                                      "can_id": 0x18DA2B0E,
                                      "target_address": 0x2B,
-                                     "source_address": 0x0E},
+                                     "source_address": 0x0E,
+                                     "address_extension": None},
           "rx_packets_functional_ai": {"addressing_format": CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
                                        "addressing_type": AddressingType.FUNCTIONAL,
                                        "can_id": 0x18DBFEDC,
                                        "target_address": 0xFE,
-                                       "source_address": 0xDC},
+                                       "source_address": 0xDC,
+                                       "address_extension": None},
           "tx_packets_functional_ai": {"addressing_format": CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
                                        "addressing_type": AddressingType.FUNCTIONAL,
                                        "can_id": 0x18DBFD92,
                                        "target_address": 0xFD,
-                                       "source_address": 0x92}}),
+                                       "source_address": 0x92,
+                                       "address_extension": None}}),
         ({"addressing_format": CanAddressingFormat.EXTENDED_ADDRESSING,
           "rx_physical": {"can_id": 0x621, "target_address": 0x1F},
           "tx_physical": {"can_id": 0x621, "target_address": 0x91},
@@ -302,19 +320,27 @@ class TestCanAddressingInformationIntegration:
          {"rx_packets_physical_ai": {"addressing_format": CanAddressingFormat.EXTENDED_ADDRESSING,
                                      "addressing_type": AddressingType.PHYSICAL,
                                      "can_id": 0x621,
-                                     "target_address": 0x1F},
+                                     "target_address": 0x1F,
+                                     "source_address": None,
+                                     "address_extension": None},
           "tx_packets_physical_ai": {"addressing_format": CanAddressingFormat.EXTENDED_ADDRESSING,
                                      "addressing_type": AddressingType.PHYSICAL,
                                      "can_id": 0x621,
-                                     "target_address": 0x91},
+                                     "target_address": 0x91,
+                                     "source_address": None,
+                                     "address_extension": None},
           "rx_packets_functional_ai": {"addressing_format": CanAddressingFormat.EXTENDED_ADDRESSING,
                                        "addressing_type": AddressingType.FUNCTIONAL,
                                        "can_id": 0x12345,
-                                       "target_address": 0x82},
+                                       "target_address": 0x82,
+                                       "source_address": None,
+                                       "address_extension": None},
           "tx_packets_functional_ai": {"addressing_format": CanAddressingFormat.EXTENDED_ADDRESSING,
                                        "addressing_type": AddressingType.FUNCTIONAL,
                                        "can_id": 0x12346,
-                                       "target_address": 0x83}}),
+                                       "target_address": 0x83,
+                                       "source_address": None,
+                                       "address_extension": None}}),
         ({"addressing_format": CanAddressingFormat.MIXED_11BIT_ADDRESSING,
           "rx_physical": {"can_id": 0x641, "address_extension": 0x00},
           "tx_physical": {"can_id": 0x642, "address_extension": 0xFF},
@@ -323,19 +349,27 @@ class TestCanAddressingInformationIntegration:
          {"rx_packets_physical_ai": {"addressing_format": CanAddressingFormat.MIXED_11BIT_ADDRESSING,
                                      "addressing_type": AddressingType.PHYSICAL,
                                      "can_id": 0x641,
-                                     "address_extension": 0x00},
+                                     "address_extension": 0x00,
+                                     "target_address": None,
+                                     "source_address": None},
           "tx_packets_physical_ai": {"addressing_format": CanAddressingFormat.MIXED_11BIT_ADDRESSING,
                                      "addressing_type": AddressingType.PHYSICAL,
                                      "can_id": 0x642,
-                                     "address_extension": 0xFF},
+                                     "address_extension": 0xFF,
+                                     "target_address": None,
+                                     "source_address": None},
           "rx_packets_functional_ai": {"addressing_format": CanAddressingFormat.MIXED_11BIT_ADDRESSING,
                                        "addressing_type": AddressingType.FUNCTIONAL,
                                        "can_id": 0x6DE,
-                                       "address_extension": 0xFE},
+                                       "address_extension": 0xFE,
+                                       "target_address": None,
+                                       "source_address": None},
           "tx_packets_functional_ai": {"addressing_format": CanAddressingFormat.MIXED_11BIT_ADDRESSING,
                                        "addressing_type": AddressingType.FUNCTIONAL,
                                        "can_id": 0x6DF,
-                                       "address_extension": 0xFF}}),
+                                       "address_extension": 0xFF,
+                                       "target_address": None,
+                                       "source_address": None}}),
         ({"addressing_format": CanAddressingFormat.MIXED_29BIT_ADDRESSING,
           "rx_physical": {"can_id": 0x18CE1234, "target_address": 0x12, "source_address": 0x34, "address_extension": 0x00},
           "tx_physical": {"can_id": 0x18CEFF0F, "target_address": 0xFF, "address_extension": 0x5E},
diff --git a/tests/software_tests/can/test_consecutive_frame.py b/tests/software_tests/can/test_consecutive_frame.py
index a7a34128..47513886 100644
--- a/tests/software_tests/can/test_consecutive_frame.py
+++ b/tests/software_tests/can/test_consecutive_frame.py
@@ -6,32 +6,33 @@
 from uds.can import CanAddressingFormat
 
 
+SCRIPT_LOCATION = "uds.can.consecutive_frame"
+
+
 class TestCanConsecutiveFrameHandler:
     """Unit tests for `CanConsecutiveFrameHandler` class."""
 
-    SCRIPT_LOCATION = "uds.can.consecutive_frame"
-
-    def setup(self):
-        self._patcher_validate_nibble = patch(f"{self.SCRIPT_LOCATION}.validate_nibble")
+    def setup_method(self):
+        self._patcher_validate_nibble = patch(f"{SCRIPT_LOCATION}.validate_nibble")
         self.mock_validate_nibble = self._patcher_validate_nibble.start()
-        self._patcher_validate_raw_byte = patch(f"{self.SCRIPT_LOCATION}.validate_raw_byte")
+        self._patcher_validate_raw_byte = patch(f"{SCRIPT_LOCATION}.validate_raw_byte")
         self.mock_validate_raw_byte = self._patcher_validate_raw_byte.start()
-        self._patcher_validate_raw_bytes = patch(f"{self.SCRIPT_LOCATION}.validate_raw_bytes")
+        self._patcher_validate_raw_bytes = patch(f"{SCRIPT_LOCATION}.validate_raw_bytes")
         self.mock_validate_raw_bytes = self._patcher_validate_raw_bytes.start()
-        self._patcher_encode_dlc = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler.encode_dlc")
+        self._patcher_encode_dlc = patch(f"{SCRIPT_LOCATION}.CanDlcHandler.encode_dlc")
         self.mock_encode_dlc = self._patcher_encode_dlc.start()
-        self._patcher_decode_dlc = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler.decode_dlc")
+        self._patcher_decode_dlc = patch(f"{SCRIPT_LOCATION}.CanDlcHandler.decode_dlc")
         self.mock_decode_dlc = self._patcher_decode_dlc.start()
-        self._patcher_get_min_dlc = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler.get_min_dlc")
+        self._patcher_get_min_dlc = patch(f"{SCRIPT_LOCATION}.CanDlcHandler.get_min_dlc")
         self.mock_get_min_dlc = self._patcher_get_min_dlc.start()
         self._patcher_encode_ai_data_bytes = \
-            patch(f"{self.SCRIPT_LOCATION}.CanAddressingInformation.encode_ai_data_bytes")
+            patch(f"{SCRIPT_LOCATION}.CanAddressingInformation.encode_ai_data_bytes")
         self.mock_encode_ai_data_bytes = self._patcher_encode_ai_data_bytes.start()
         self._patcher_get_ai_data_bytes_number = \
-            patch(f"{self.SCRIPT_LOCATION}.CanAddressingInformation.get_ai_data_bytes_number")
+            patch(f"{SCRIPT_LOCATION}.CanAddressingInformation.get_ai_data_bytes_number")
         self.mock_get_ai_data_bytes_number = self._patcher_get_ai_data_bytes_number.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_nibble.stop()
         self._patcher_validate_raw_byte.stop()
         self._patcher_validate_raw_bytes.stop()
diff --git a/tests/software_tests/can/test_extended_addressing_information.py b/tests/software_tests/can/test_extended_addressing_information.py
index b19bccd5..13bf99d9 100644
--- a/tests/software_tests/can/test_extended_addressing_information.py
+++ b/tests/software_tests/can/test_extended_addressing_information.py
@@ -5,22 +5,23 @@
     CanAddressingFormat, InconsistentArgumentsError, UnusedArgumentError, AbstractCanAddressingInformation
 
 
+SCRIPT_LOCATION = "uds.can.extended_addressing_information"
+
+
 class TestExtendedCanAddressingInformation:
     """Unit tests for `ExtendedCanAddressingInformation` class."""
 
-    SCRIPT_LOCATION = "uds.can.extended_addressing_information"
-
-    def setup(self):
+    def setup_method(self):
         self.mock_addressing_information = Mock(spec=ExtendedCanAddressingInformation)
         # patching
-        self._patcher_validate_raw_byte = patch(f"{self.SCRIPT_LOCATION}.validate_raw_byte")
+        self._patcher_validate_raw_byte = patch(f"{SCRIPT_LOCATION}.validate_raw_byte")
         self.mock_validate_raw_byte = self._patcher_validate_raw_byte.start()
-        self._patcher_validate_addressing_type = patch(f"{self.SCRIPT_LOCATION}.AddressingType.validate_member")
+        self._patcher_validate_addressing_type = patch(f"{SCRIPT_LOCATION}.AddressingType.validate_member")
         self.mock_validate_addressing_type = self._patcher_validate_addressing_type.start()
-        self._patcher_can_id_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanIdHandler")
+        self._patcher_can_id_handler_class = patch(f"{SCRIPT_LOCATION}.CanIdHandler")
         self.mock_can_id_handler_class = self._patcher_can_id_handler_class.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_raw_byte.stop()
         self._patcher_validate_addressing_type.stop()
         self._patcher_can_id_handler_class.stop()
@@ -73,6 +74,8 @@ def test_validate_packet_ai__valid(self, addressing_type, can_id, target_address
             AbstractCanAddressingInformation.ADDRESSING_TYPE_NAME: addressing_type,
             AbstractCanAddressingInformation.CAN_ID_NAME: can_id,
             AbstractCanAddressingInformation.TARGET_ADDRESS_NAME: target_address,
+            AbstractCanAddressingInformation.SOURCE_ADDRESS_NAME: None,
+            AbstractCanAddressingInformation.ADDRESS_EXTENSION_NAME: None,
         }
         self.mock_can_id_handler_class.validate_can_id.assert_called_once_with(can_id)
         self.mock_can_id_handler_class.is_extended_addressed_can_id.assert_called_once_with(can_id)
diff --git a/tests/software_tests/can/test_first_frame.py b/tests/software_tests/can/test_first_frame.py
index a8d45098..f88d8221 100644
--- a/tests/software_tests/can/test_first_frame.py
+++ b/tests/software_tests/can/test_first_frame.py
@@ -6,28 +6,29 @@
 from uds.can import CanAddressingFormat
 
 
+SCRIPT_LOCATION = "uds.can.first_frame"
+
+
 class TestCanFirstFrameHandler:
     """Unit tests for `CanFirstFrameHandler` class."""
 
-    SCRIPT_LOCATION = "uds.can.first_frame"
-
-    def setup(self):
-        self._patcher_validate_raw_bytes = patch(f"{self.SCRIPT_LOCATION}.validate_raw_bytes")
+    def setup_method(self):
+        self._patcher_validate_raw_bytes = patch(f"{SCRIPT_LOCATION}.validate_raw_bytes")
         self.mock_validate_raw_bytes = self._patcher_validate_raw_bytes.start()
-        self._patcher_bytes_list_to_int = patch(f"{self.SCRIPT_LOCATION}.bytes_list_to_int")
+        self._patcher_bytes_list_to_int = patch(f"{SCRIPT_LOCATION}.bytes_list_to_int")
         self.mock_bytes_list_to_int = self._patcher_bytes_list_to_int.start()
-        self._patcher_get_ai_data_bytes_number = patch(f"{self.SCRIPT_LOCATION}.CanAddressingInformation.get_ai_data_bytes_number")
+        self._patcher_get_ai_data_bytes_number = patch(f"{SCRIPT_LOCATION}.CanAddressingInformation.get_ai_data_bytes_number")
         self.mock_get_ai_data_bytes_number = self._patcher_get_ai_data_bytes_number.start()
-        self._patcher_encode_ai_data_bytes = patch(f"{self.SCRIPT_LOCATION}.CanAddressingInformation.encode_ai_data_bytes")
+        self._patcher_encode_ai_data_bytes = patch(f"{SCRIPT_LOCATION}.CanAddressingInformation.encode_ai_data_bytes")
         self.mock_encode_ai_data_bytes = self._patcher_encode_ai_data_bytes.start()
-        self._patcher_decode_dlc = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler.decode_dlc")
+        self._patcher_decode_dlc = patch(f"{SCRIPT_LOCATION}.CanDlcHandler.decode_dlc")
         self.mock_decode_dlc = self._patcher_decode_dlc.start()
-        self._patcher_encode_dlc = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler.encode_dlc")
+        self._patcher_encode_dlc = patch(f"{SCRIPT_LOCATION}.CanDlcHandler.encode_dlc")
         self.mock_encode_dlc = self._patcher_encode_dlc.start()
-        self._patcher_get_max_sf_dl = patch(f"{self.SCRIPT_LOCATION}.CanSingleFrameHandler.get_max_payload_size")
+        self._patcher_get_max_sf_dl = patch(f"{SCRIPT_LOCATION}.CanSingleFrameHandler.get_max_payload_size")
         self.mock_get_max_sf_dl = self._patcher_get_max_sf_dl.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_bytes_list_to_int.stop()
         self._patcher_validate_raw_bytes.stop()
         self._patcher_get_ai_data_bytes_number.stop()
diff --git a/tests/software_tests/can/test_flow_control.py b/tests/software_tests/can/test_flow_control.py
index 0992ac6d..f827aeeb 100644
--- a/tests/software_tests/can/test_flow_control.py
+++ b/tests/software_tests/can/test_flow_control.py
@@ -7,6 +7,9 @@
 from uds.utilities import ValidatedEnum, NibbleEnum
 
 
+SCRIPT_LOCATION = "uds.can.flow_control"
+
+
 class TestCanFlowStatus:
     """Unit tests for 'CanFlowStatus' class."""
 
@@ -20,15 +23,13 @@ def test_inheritance__nibble_enum(self):
 class TestCanSTmin:
     """Unit tests for 'CanSTmin' class."""
 
-    SCRIPT_LOCATION = "uds.can.flow_control"
-
-    def setup(self):
-        self._patcher_validate_raw_byte = patch(f"{self.SCRIPT_LOCATION}.validate_raw_byte")
+    def setup_method(self):
+        self._patcher_validate_raw_byte = patch(f"{SCRIPT_LOCATION}.validate_raw_byte")
         self.mock_validate_raw_byte = self._patcher_validate_raw_byte.start()
-        self._patcher_warn = patch(f"{self.SCRIPT_LOCATION}.warn")
+        self._patcher_warn = patch(f"{SCRIPT_LOCATION}.warn")
         self.mock_warn = self._patcher_warn.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_raw_byte.stop()
         self._patcher_warn.stop()
 
@@ -135,31 +136,29 @@ def test_encode_and_decode(self, time_value):
 class TestCanFlowControlHandler:
     """Unit tests for `CanFlowControlHandler` class."""
 
-    SCRIPT_LOCATION = TestCanSTmin.SCRIPT_LOCATION
-
-    def setup(self):
-        self._patcher_validate_nibble = patch(f"{self.SCRIPT_LOCATION}.validate_nibble")
+    def setup_method(self):
+        self._patcher_validate_nibble = patch(f"{SCRIPT_LOCATION}.validate_nibble")
         self.mock_validate_nibble = self._patcher_validate_nibble.start()
-        self._patcher_validate_raw_byte = patch(f"{self.SCRIPT_LOCATION}.validate_raw_byte")
+        self._patcher_validate_raw_byte = patch(f"{SCRIPT_LOCATION}.validate_raw_byte")
         self.mock_validate_raw_byte = self._patcher_validate_raw_byte.start()
-        self._patcher_validate_raw_bytes = patch(f"{self.SCRIPT_LOCATION}.validate_raw_bytes")
+        self._patcher_validate_raw_bytes = patch(f"{SCRIPT_LOCATION}.validate_raw_bytes")
         self.mock_validate_raw_bytes = self._patcher_validate_raw_bytes.start()
-        self._patcher_encode_dlc = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler.encode_dlc")
+        self._patcher_encode_dlc = patch(f"{SCRIPT_LOCATION}.CanDlcHandler.encode_dlc")
         self.mock_encode_dlc = self._patcher_encode_dlc.start()
-        self._patcher_decode_dlc = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler.decode_dlc")
+        self._patcher_decode_dlc = patch(f"{SCRIPT_LOCATION}.CanDlcHandler.decode_dlc")
         self.mock_decode_dlc = self._patcher_decode_dlc.start()
-        self._patcher_get_min_dlc = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler.get_min_dlc")
+        self._patcher_get_min_dlc = patch(f"{SCRIPT_LOCATION}.CanDlcHandler.get_min_dlc")
         self.mock_get_min_dlc = self._patcher_get_min_dlc.start()
         self._patcher_encode_ai_data_bytes = \
-            patch(f"{self.SCRIPT_LOCATION}.CanAddressingInformation.encode_ai_data_bytes")
+            patch(f"{SCRIPT_LOCATION}.CanAddressingInformation.encode_ai_data_bytes")
         self.mock_encode_ai_data_bytes = self._patcher_encode_ai_data_bytes.start()
         self._patcher_get_ai_data_bytes_number = \
-            patch(f"{self.SCRIPT_LOCATION}.CanAddressingInformation.get_ai_data_bytes_number")
+            patch(f"{SCRIPT_LOCATION}.CanAddressingInformation.get_ai_data_bytes_number")
         self.mock_get_ai_data_bytes_number = self._patcher_get_ai_data_bytes_number.start()
-        self._patcher_validate_flow_status = patch(f"{self.SCRIPT_LOCATION}.CanFlowStatus.validate_member")
+        self._patcher_validate_flow_status = patch(f"{SCRIPT_LOCATION}.CanFlowStatus.validate_member")
         self.mock_validate_flow_status = self._patcher_validate_flow_status.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_nibble.stop()
         self._patcher_validate_raw_byte.stop()
         self._patcher_validate_raw_bytes.stop()
diff --git a/tests/software_tests/can/test_frame_fields.py b/tests/software_tests/can/test_frame_fields.py
index 7d6c7540..00acc30b 100644
--- a/tests/software_tests/can/test_frame_fields.py
+++ b/tests/software_tests/can/test_frame_fields.py
@@ -5,20 +5,21 @@
     AddressingType, CanAddressingFormat
 
 
+SCRIPT_LOCATION = "uds.can.frame_fields"
+
+
 class TestCanIdHandler:
     """Unit tests for `CanIdHandler` class."""
 
-    SCRIPT_LOCATION = "uds.can.frame_fields"
-
-    def setup(self):
-        self._patcher_validate_raw_byte = patch(f"{self.SCRIPT_LOCATION}.validate_raw_byte")
+    def setup_method(self):
+        self._patcher_validate_raw_byte = patch(f"{SCRIPT_LOCATION}.validate_raw_byte")
         self.mock_validate_raw_byte = self._patcher_validate_raw_byte.start()
-        self._patcher_validate_addressing_format = patch(f"{self.SCRIPT_LOCATION}.CanAddressingFormat.validate_member")
+        self._patcher_validate_addressing_format = patch(f"{SCRIPT_LOCATION}.CanAddressingFormat.validate_member")
         self.mock_validate_addressing_format = self._patcher_validate_addressing_format.start()
-        self._patcher_validate_addressing_type = patch(f"{self.SCRIPT_LOCATION}.AddressingType.validate_member")
+        self._patcher_validate_addressing_type = patch(f"{SCRIPT_LOCATION}.AddressingType.validate_member")
         self.mock_validate_addressing_type = self._patcher_validate_addressing_type.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_raw_byte.stop()
         self._patcher_validate_addressing_format.stop()
         self._patcher_validate_addressing_type.stop()
@@ -499,8 +500,6 @@ def test_validate_can_id__valid(self, mock_is_can_id, mock_is_standard_can_id, m
 class TestCanDlcHandler:
     """Unit tests for `CanDlcHandler` class."""
 
-    SCRIPT_LOCATION = TestCanIdHandler.SCRIPT_LOCATION
-
     # decode_dlc
 
     @pytest.mark.parametrize("dlc, data_bytes_number", [
diff --git a/tests/software_tests/can/test_mixed_addressing_information.py b/tests/software_tests/can/test_mixed_addressing_information.py
index d1275ba5..59e42501 100644
--- a/tests/software_tests/can/test_mixed_addressing_information.py
+++ b/tests/software_tests/can/test_mixed_addressing_information.py
@@ -5,22 +5,23 @@
     CanAddressingFormat, InconsistentArgumentsError, UnusedArgumentError, AbstractCanAddressingInformation
 
 
+SCRIPT_LOCATION = "uds.can.mixed_addressing_information"
+
+
 class TestMixed11BitCanAddressingInformation:
     """Unit tests for `Mixed11BitCanAddressingInformation` class."""
 
-    SCRIPT_LOCATION = "uds.can.mixed_addressing_information"
-
-    def setup(self):
+    def setup_method(self):
         self.mock_addressing_information = Mock(spec=Mixed11BitCanAddressingInformation)
         # patching
-        self._patcher_validate_raw_byte = patch(f"{self.SCRIPT_LOCATION}.validate_raw_byte")
+        self._patcher_validate_raw_byte = patch(f"{SCRIPT_LOCATION}.validate_raw_byte")
         self.mock_validate_raw_byte = self._patcher_validate_raw_byte.start()
-        self._patcher_validate_addressing_type = patch(f"{self.SCRIPT_LOCATION}.AddressingType.validate_member")
+        self._patcher_validate_addressing_type = patch(f"{SCRIPT_LOCATION}.AddressingType.validate_member")
         self.mock_validate_addressing_type = self._patcher_validate_addressing_type.start()
-        self._patcher_can_id_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanIdHandler")
+        self._patcher_can_id_handler_class = patch(f"{SCRIPT_LOCATION}.CanIdHandler")
         self.mock_can_id_handler_class = self._patcher_can_id_handler_class.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_raw_byte.stop()
         self._patcher_validate_addressing_type.stop()
         self._patcher_can_id_handler_class.stop()
@@ -73,6 +74,8 @@ def test_validate_ai_mixed_11bit__valid(self, addressing_type, can_id, address_e
             AbstractCanAddressingInformation.ADDRESSING_TYPE_NAME: addressing_type,
             AbstractCanAddressingInformation.CAN_ID_NAME: can_id,
             AbstractCanAddressingInformation.ADDRESS_EXTENSION_NAME: address_extension,
+            AbstractCanAddressingInformation.TARGET_ADDRESS_NAME: None,
+            AbstractCanAddressingInformation.SOURCE_ADDRESS_NAME: None,
         }
         self.mock_can_id_handler_class.validate_can_id.assert_called_once_with(can_id)
         self.mock_can_id_handler_class.is_mixed_11bit_addressed_can_id.assert_called_once_with(can_id)
@@ -83,19 +86,17 @@ def test_validate_ai_mixed_11bit__valid(self, addressing_type, can_id, address_e
 class TestMixed29BitCanAddressingInformation:
     """Unit tests for `Mixed29BitCanAddressingInformation` class."""
 
-    SCRIPT_LOCATION = TestMixed11BitCanAddressingInformation.SCRIPT_LOCATION
-
-    def setup(self):
+    def setup_method(self):
         self.mock_addressing_information = Mock(spec=Mixed29BitCanAddressingInformation)
         # patching
-        self._patcher_validate_raw_byte = patch(f"{self.SCRIPT_LOCATION}.validate_raw_byte")
+        self._patcher_validate_raw_byte = patch(f"{SCRIPT_LOCATION}.validate_raw_byte")
         self.mock_validate_raw_byte = self._patcher_validate_raw_byte.start()
-        self._patcher_validate_addressing_type = patch(f"{self.SCRIPT_LOCATION}.AddressingType.validate_member")
+        self._patcher_validate_addressing_type = patch(f"{SCRIPT_LOCATION}.AddressingType.validate_member")
         self.mock_validate_addressing_type = self._patcher_validate_addressing_type.start()
-        self._patcher_can_id_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanIdHandler")
+        self._patcher_can_id_handler_class = patch(f"{SCRIPT_LOCATION}.CanIdHandler")
         self.mock_can_id_handler_class = self._patcher_can_id_handler_class.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_raw_byte.stop()
         self._patcher_validate_addressing_type.stop()
         self._patcher_can_id_handler_class.stop()
diff --git a/tests/software_tests/can/test_normal_addressing_information.py b/tests/software_tests/can/test_normal_addressing_information.py
index 66d133dc..037eba90 100644
--- a/tests/software_tests/can/test_normal_addressing_information.py
+++ b/tests/software_tests/can/test_normal_addressing_information.py
@@ -5,22 +5,23 @@
     CanAddressingFormat, InconsistentArgumentsError, UnusedArgumentError, AbstractCanAddressingInformation
 
 
+SCRIPT_LOCATION = "uds.can.normal_addressing_information"
+
+
 class TestNormal11BitCanAddressingInformation:
     """Unit tests for `Normal11BitCanAddressingInformation` class."""
 
-    SCRIPT_LOCATION = "uds.can.normal_addressing_information"
-
-    def setup(self):
+    def setup_method(self):
         self.mock_addressing_information = Mock(spec=Normal11BitCanAddressingInformation)
         # patching
-        self._patcher_validate_raw_byte = patch(f"{self.SCRIPT_LOCATION}.validate_raw_byte")
+        self._patcher_validate_raw_byte = patch(f"{SCRIPT_LOCATION}.validate_raw_byte")
         self.mock_validate_raw_byte = self._patcher_validate_raw_byte.start()
-        self._patcher_validate_addressing_type = patch(f"{self.SCRIPT_LOCATION}.AddressingType.validate_member")
+        self._patcher_validate_addressing_type = patch(f"{SCRIPT_LOCATION}.AddressingType.validate_member")
         self.mock_validate_addressing_type = self._patcher_validate_addressing_type.start()
-        self._patcher_can_id_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanIdHandler")
+        self._patcher_can_id_handler_class = patch(f"{SCRIPT_LOCATION}.CanIdHandler")
         self.mock_can_id_handler_class = self._patcher_can_id_handler_class.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_raw_byte.stop()
         self._patcher_validate_addressing_type.stop()
         self._patcher_can_id_handler_class.stop()
@@ -66,7 +67,10 @@ def test_validate_packet_ai__valid(self, addressing_type, can_id):
                                                                       can_id=can_id) == {
                    AbstractCanAddressingInformation.ADDRESSING_FORMAT_NAME: CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
                    AbstractCanAddressingInformation.ADDRESSING_TYPE_NAME: addressing_type,
-                   AbstractCanAddressingInformation.CAN_ID_NAME: can_id
+                   AbstractCanAddressingInformation.CAN_ID_NAME: can_id,
+                   AbstractCanAddressingInformation.TARGET_ADDRESS_NAME: None,
+                   AbstractCanAddressingInformation.SOURCE_ADDRESS_NAME: None,
+                   AbstractCanAddressingInformation.ADDRESS_EXTENSION_NAME: None,
                }
         self.mock_can_id_handler_class.validate_can_id.assert_called_once_with(can_id)
         self.mock_can_id_handler_class.is_normal_11bit_addressed_can_id.assert_called_once_with(can_id)
@@ -76,19 +80,17 @@ def test_validate_packet_ai__valid(self, addressing_type, can_id):
 class TestNormalFixedCanAddressingInformation:
     """Unit tests for `NormalFixedCanAddressingInformation` class."""
 
-    SCRIPT_LOCATION = TestNormal11BitCanAddressingInformation.SCRIPT_LOCATION
-
-    def setup(self):
+    def setup_method(self):
         self.mock_addressing_information = Mock(spec=NormalFixedCanAddressingInformation)
         # patching
-        self._patcher_validate_raw_byte = patch(f"{self.SCRIPT_LOCATION}.validate_raw_byte")
+        self._patcher_validate_raw_byte = patch(f"{SCRIPT_LOCATION}.validate_raw_byte")
         self.mock_validate_raw_byte = self._patcher_validate_raw_byte.start()
-        self._patcher_validate_addressing_type = patch(f"{self.SCRIPT_LOCATION}.AddressingType.validate_member")
+        self._patcher_validate_addressing_type = patch(f"{SCRIPT_LOCATION}.AddressingType.validate_member")
         self.mock_validate_addressing_type = self._patcher_validate_addressing_type.start()
-        self._patcher_can_id_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanIdHandler")
+        self._patcher_can_id_handler_class = patch(f"{SCRIPT_LOCATION}.CanIdHandler")
         self.mock_can_id_handler_class = self._patcher_can_id_handler_class.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_raw_byte.stop()
         self._patcher_validate_addressing_type.stop()
         self._patcher_can_id_handler_class.stop()
@@ -160,7 +162,8 @@ def test_validate_packet_ai__valid_without_can_id(self, addressing_type, target_
             AbstractCanAddressingInformation.ADDRESSING_TYPE_NAME: addressing_type,
             AbstractCanAddressingInformation.CAN_ID_NAME: self.mock_can_id_handler_class.encode_normal_fixed_addressed_can_id.return_value,
             AbstractCanAddressingInformation.TARGET_ADDRESS_NAME: target_address,
-            AbstractCanAddressingInformation.SOURCE_ADDRESS_NAME: source_address
+            AbstractCanAddressingInformation.SOURCE_ADDRESS_NAME: source_address,
+            AbstractCanAddressingInformation.ADDRESS_EXTENSION_NAME: None,
         }
         self.mock_validate_addressing_type.assert_called_once_with(addressing_type)
         self.mock_validate_raw_byte.assert_has_calls([call(target_address), call(source_address)], any_order=True)
@@ -197,6 +200,7 @@ def test_validate_packet_ai__valid_with_can_id(self, addressing_type, can_id, ta
             AbstractCanAddressingInformation.CAN_ID_NAME: can_id,
             AbstractCanAddressingInformation.TARGET_ADDRESS_NAME: decoded_target_address,
             AbstractCanAddressingInformation.SOURCE_ADDRESS_NAME: decoded_source_address,
+            AbstractCanAddressingInformation.ADDRESS_EXTENSION_NAME: None,
         }
         self.mock_validate_addressing_type.assert_called_once_with(addressing_type)
         self.mock_validate_raw_byte.assert_not_called()
diff --git a/tests/software_tests/can/test_single_frame.py b/tests/software_tests/can/test_single_frame.py
index 5b22dab5..805f1a77 100644
--- a/tests/software_tests/can/test_single_frame.py
+++ b/tests/software_tests/can/test_single_frame.py
@@ -6,34 +6,35 @@
 from uds.can import CanAddressingFormat
 
 
+SCRIPT_LOCATION = "uds.can.single_frame"
+
+
 class TestCanSingleFrameHandler:
     """Unit tests for `CanSingleFrameHandler` class."""
 
-    SCRIPT_LOCATION = "uds.can.single_frame"
-
-    def setup(self):
-        self._patcher_validate_nibble = patch(f"{self.SCRIPT_LOCATION}.validate_nibble")
+    def setup_method(self):
+        self._patcher_validate_nibble = patch(f"{SCRIPT_LOCATION}.validate_nibble")
         self.mock_validate_nibble = self._patcher_validate_nibble.start()
-        self._patcher_validate_raw_byte = patch(f"{self.SCRIPT_LOCATION}.validate_raw_byte")
+        self._patcher_validate_raw_byte = patch(f"{SCRIPT_LOCATION}.validate_raw_byte")
         self.mock_validate_raw_byte = self._patcher_validate_raw_byte.start()
-        self._patcher_validate_raw_bytes = patch(f"{self.SCRIPT_LOCATION}.validate_raw_bytes")
+        self._patcher_validate_raw_bytes = patch(f"{SCRIPT_LOCATION}.validate_raw_bytes")
         self.mock_validate_raw_bytes = self._patcher_validate_raw_bytes.start()
-        self._patcher_encode_dlc = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler.encode_dlc")
+        self._patcher_encode_dlc = patch(f"{SCRIPT_LOCATION}.CanDlcHandler.encode_dlc")
         self.mock_encode_dlc = self._patcher_encode_dlc.start()
-        self._patcher_decode_dlc = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler.decode_dlc")
+        self._patcher_decode_dlc = patch(f"{SCRIPT_LOCATION}.CanDlcHandler.decode_dlc")
         self.mock_decode_dlc = self._patcher_decode_dlc.start()
-        self._patcher_get_min_dlc = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler.get_min_dlc")
+        self._patcher_get_min_dlc = patch(f"{SCRIPT_LOCATION}.CanDlcHandler.get_min_dlc")
         self.mock_get_min_dlc = self._patcher_get_min_dlc.start()
-        self._patcher_validate_dlc = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler.validate_dlc")
+        self._patcher_validate_dlc = patch(f"{SCRIPT_LOCATION}.CanDlcHandler.validate_dlc")
         self.mock_validate_dlc = self._patcher_validate_dlc.start()
         self._patcher_encode_ai_data_bytes = \
-            patch(f"{self.SCRIPT_LOCATION}.CanAddressingInformation.encode_ai_data_bytes")
+            patch(f"{SCRIPT_LOCATION}.CanAddressingInformation.encode_ai_data_bytes")
         self.mock_encode_ai_data_bytes = self._patcher_encode_ai_data_bytes.start()
         self._patcher_get_ai_data_bytes_number = \
-            patch(f"{self.SCRIPT_LOCATION}.CanAddressingInformation.get_ai_data_bytes_number")
+            patch(f"{SCRIPT_LOCATION}.CanAddressingInformation.get_ai_data_bytes_number")
         self.mock_get_ai_data_bytes_number = self._patcher_get_ai_data_bytes_number.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_nibble.stop()
         self._patcher_validate_raw_byte.stop()
         self._patcher_validate_raw_bytes.stop()
diff --git a/tests/software_tests/conftest.py b/tests/software_tests/conftest.py
index f7d8e814..18efe23d 100644
--- a/tests/software_tests/conftest.py
+++ b/tests/software_tests/conftest.py
@@ -3,7 +3,8 @@
 from can import Message
 
 from uds.transmission_attributes import TransmissionDirection, AddressingType
-from uds.can import CanAddressingFormat
+from uds.can import CanAddressingFormat, Normal11BitCanAddressingInformation, NormalFixedCanAddressingInformation, \
+    ExtendedCanAddressingInformation, Mixed11BitCanAddressingInformation, Mixed29BitCanAddressingInformation
 from uds.segmentation import CanSegmenter
 
 
@@ -53,21 +54,34 @@ def example_can_addressing_format(request):
 
 
 @fixture(params=[
-    CanSegmenter(addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
-                 physical_ai=dict(can_id=0x724),
-                 functional_ai=dict(can_id=0x7FF)),
-    CanSegmenter(addressing_format=CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
-                 physical_ai=dict(target_address=0x1E, source_address=0xFF),
-                 functional_ai=dict(target_address=0xB1, source_address=0xFF),
+    CanSegmenter(addressing_information=Normal11BitCanAddressingInformation(rx_physical={"can_id": 0x643},
+                                                                            tx_physical={"can_id": 0x644},
+                                                                            rx_functional={"can_id": 0x7DE},
+                                                                            tx_functional={"can_id": 0x7DF})),
+    CanSegmenter(addressing_information=NormalFixedCanAddressingInformation(rx_physical={"target_address": 0x12, "source_address": 0xF8},
+                                                                            tx_physical={"can_id": 0x18DAF812,"target_address": 0xF8, "source_address": 0x12},
+                                                                            rx_functional={"can_id": 0x18DB0BFF, "target_address": 0x0B, "source_address": 0xFF},
+                                                                            tx_functional={"target_address": 0xFF, "source_address": 0x0B}),
                  dlc=0xF,
                  use_data_optimization=True,
-                 filler_byte=0x71),
-    CanSegmenter(addressing_format=CanAddressingFormat.EXTENDED_ADDRESSING,
-                 physical_ai=dict(target_address=0xE0, can_id=0x129834),
-                 functional_ai=dict(target_address=0xFF, can_id=0x12FFFF),
-                 dlc=0xC,
-                 use_data_optimization=True,
-                 filler_byte=0x8E)
+                 filler_byte=0xE9),
+    CanSegmenter(addressing_information=ExtendedCanAddressingInformation(rx_physical={"can_id": 0x752, "target_address": 0x9C},
+                                                                         tx_physical={"can_id": 0x752, "target_address": 0xF0},
+                                                                         rx_functional={"can_id": 0x12CDEF59, "target_address": 0x9A},
+                                                                         tx_functional={"can_id": 0x9876543, "target_address": 0x0E}),
+                 dlc=0xA,
+                 filler_byte=0x55),
+    CanSegmenter(addressing_information=Mixed11BitCanAddressingInformation(rx_physical={"can_id": 0x6FE, "address_extension": 0x6B},
+                                                                           tx_physical={"can_id": 0x720, "address_extension": 0xD0},
+                                                                           rx_functional={"can_id": 0x7BD, "address_extension": 0x9C},
+                                                                           tx_functional={"can_id": 0x7BD, "address_extension": 0xF2}),
+                 use_data_optimization=True),
+    CanSegmenter(addressing_information=Mixed29BitCanAddressingInformation(rx_physical={"can_id": 0x18CEF1E2, "address_extension": 0x6B},
+                                                                           tx_physical={"can_id": 0x18CEE2F1, "target_address": 0xE2, "source_address": 0xF1, "address_extension": 0xD0},
+                                                                           rx_functional={"target_address": 0xFF, "source_address": 0xFF, "address_extension": 0x55},
+                                                                           tx_functional={"can_id": 0x18CDFFFF, "address_extension": 0xEF}),
+                 dlc=0xF,
+                 filler_byte=0xAA),
 ])
 def example_can_segmenter(request):
     return request.param
diff --git a/tests/software_tests/message/test_service_identifiers.py b/tests/software_tests/message/test_service_identifiers.py
index 8442c874..9d1d0e3c 100644
--- a/tests/software_tests/message/test_service_identifiers.py
+++ b/tests/software_tests/message/test_service_identifiers.py
@@ -5,20 +5,21 @@
     ByteEnum, ValidatedEnum, ExtendableEnum
 
 
+SCRIPT_LOCATION = "uds.message.service_identifiers"
+
+
 class TestRequestSID:
     """Unit tests for 'RequestSID' enum."""
 
-    SCRIPT_LOCATION = "uds.message.service_identifiers"
-
-    def setup(self):
-        self._patcher_warn = patch(f"{self.SCRIPT_LOCATION}.warn")
+    def setup_method(self):
+        self._patcher_warn = patch(f"{SCRIPT_LOCATION}.warn")
         self.mock_warn = self._patcher_warn.start()
-        self._patcher_is_member = patch(f"{self.SCRIPT_LOCATION}.RequestSID.is_member")
+        self._patcher_is_member = patch(f"{SCRIPT_LOCATION}.RequestSID.is_member")
         self.mock_is_member = self._patcher_is_member.start()
-        self._patcher_possible_request_sids = patch(f"{self.SCRIPT_LOCATION}.POSSIBLE_REQUEST_SIDS")
+        self._patcher_possible_request_sids = patch(f"{SCRIPT_LOCATION}.POSSIBLE_REQUEST_SIDS")
         self.mock_possible_request_sids = self._patcher_possible_request_sids.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_warn.stop()
         self._patcher_is_member.stop()
         self._patcher_possible_request_sids.stop()
@@ -35,10 +36,11 @@ def test_inheritance__extendable_enum(self):
     @pytest.mark.parametrize("value", [1, 0x55, 0xFF])
     def test_is_request_sid__member(self, value):
         self.mock_is_member.return_value = True
+        self.mock_possible_request_sids.__contains__.return_value = True
         assert RequestSID.is_request_sid(value=value) is True
         self.mock_warn.assert_not_called()
         self.mock_is_member.assert_called_once_with(value)
-        self.mock_possible_request_sids.__contains__.assert_not_called()
+        self.mock_possible_request_sids.__contains__.assert_called_once_with(value)
 
     @pytest.mark.parametrize("value", [1, 0x55, 0xFF])
     def test_is_request_sid__unsupported(self, value):
@@ -55,24 +57,22 @@ def test_is_request_sid__invalid(self, value):
         self.mock_possible_request_sids.__contains__.return_value = False
         assert RequestSID.is_request_sid(value=value) is False
         self.mock_warn.assert_not_called()
-        self.mock_is_member.assert_called_once_with(value)
+        self.mock_is_member.assert_not_called()
         self.mock_possible_request_sids.__contains__.assert_called_once_with(value)
 
 
 class TestResponseSID:
     """Unit tests for 'ResponseSID' enum."""
 
-    SCRIPT_LOCATION = TestRequestSID.SCRIPT_LOCATION
-
-    def setup(self):
-        self._patcher_warn = patch(f"{self.SCRIPT_LOCATION}.warn")
+    def setup_method(self):
+        self._patcher_warn = patch(f"{SCRIPT_LOCATION}.warn")
         self.mock_warn = self._patcher_warn.start()
-        self._patcher_is_member = patch(f"{self.SCRIPT_LOCATION}.ResponseSID.is_member")
+        self._patcher_is_member = patch(f"{SCRIPT_LOCATION}.ResponseSID.is_member")
         self.mock_is_member = self._patcher_is_member.start()
-        self._patcher_possible_response_sids = patch(f"{self.SCRIPT_LOCATION}.POSSIBLE_RESPONSE_SIDS")
+        self._patcher_possible_response_sids = patch(f"{SCRIPT_LOCATION}.POSSIBLE_RESPONSE_SIDS")
         self.mock_possible_response_sids = self._patcher_possible_response_sids.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_warn.stop()
         self._patcher_is_member.stop()
         self._patcher_possible_response_sids.stop()
@@ -89,10 +89,11 @@ def test_inheritance__extendable_enum(self):
     @pytest.mark.parametrize("value", [1, 0x55, 0xFF])
     def test_is_response_sid__member(self, value):
         self.mock_is_member.return_value = True
+        self.mock_possible_response_sids.__contains__.return_value = True
         assert ResponseSID.is_response_sid(value=value) is True
         self.mock_warn.assert_not_called()
         self.mock_is_member.assert_called_once_with(value)
-        self.mock_possible_response_sids.__contains__.assert_not_called()
+        self.mock_possible_response_sids.__contains__.assert_called_once_with(value)
 
     @pytest.mark.parametrize("value", [1, 0x55, 0xFF])
     def test_is_response_sid__unsupported(self, value):
@@ -109,7 +110,7 @@ def test_is_response_sid__invalid(self, value):
         self.mock_possible_response_sids.__contains__.return_value = False
         assert ResponseSID.is_response_sid(value=value) is False
         self.mock_warn.assert_not_called()
-        self.mock_is_member.assert_called_once_with(value)
+        self.mock_is_member.assert_not_called()
         self.mock_possible_response_sids.__contains__.assert_called_once_with(value)
 
 
diff --git a/tests/software_tests/message/test_uds_message.py b/tests/software_tests/message/test_uds_message.py
index 352295ed..6d3602e0 100644
--- a/tests/software_tests/message/test_uds_message.py
+++ b/tests/software_tests/message/test_uds_message.py
@@ -6,20 +6,21 @@
 from uds.transmission_attributes import TransmissionDirection
 
 
+SCRIPT_LOCATION = "uds.message.uds_message"
+
+
 class TestUdsMessage:
     """Unit tests for 'UdsMessage' class."""
 
-    SCRIPT_LOCATION = "uds.message.uds_message"
-
-    def setup(self):
+    def setup_method(self):
         self.mock_uds_message = Mock(spec=UdsMessage)
         # patching
-        self._patcher_validate_raw_bytes = patch(f"{self.SCRIPT_LOCATION}.validate_raw_bytes")
+        self._patcher_validate_raw_bytes = patch(f"{SCRIPT_LOCATION}.validate_raw_bytes")
         self.mock_validate_raw_bytes = self._patcher_validate_raw_bytes.start()
-        self._patcher_validate_addressing = patch(f"{self.SCRIPT_LOCATION}.AddressingType.validate_member")
+        self._patcher_validate_addressing = patch(f"{SCRIPT_LOCATION}.AddressingType.validate_member")
         self.mock_validate_addressing = self._patcher_validate_addressing.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_raw_bytes.stop()
         self._patcher_validate_addressing.stop()
 
@@ -88,17 +89,15 @@ def test_addressing_type__set_second_call(self, example_addressing_type):
 class TestUdsMessageRecord:
     """Unit tests for 'UdsMessageRecord' class."""
 
-    SCRIPT_LOCATION = TestUdsMessage.SCRIPT_LOCATION
-
-    def setup(self):
+    def setup_method(self):
         self.mock_uds_message_record = Mock(spec=UdsMessageRecord)
         # patching
-        self._patcher_validate_raw_bytes = patch(f"{self.SCRIPT_LOCATION}.validate_raw_bytes")
+        self._patcher_validate_raw_bytes = patch(f"{SCRIPT_LOCATION}.validate_raw_bytes")
         self.mock_validate_raw_bytes = self._patcher_validate_raw_bytes.start()
-        self._patcher_validate_addressing = patch(f"{self.SCRIPT_LOCATION}.AddressingType.validate_member")
+        self._patcher_validate_addressing = patch(f"{SCRIPT_LOCATION}.AddressingType.validate_member")
         self.mock_validate_addressing = self._patcher_validate_addressing.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_raw_bytes.stop()
         self._patcher_validate_addressing.stop()
 
diff --git a/tests/software_tests/packet/test_abstract_can_packet_container.py b/tests/software_tests/packet/test_abstract_can_packet_container.py
index 3ec646ea..f04cd5f8 100644
--- a/tests/software_tests/packet/test_abstract_can_packet_container.py
+++ b/tests/software_tests/packet/test_abstract_can_packet_container.py
@@ -6,34 +6,35 @@
 from uds.transmission_attributes import AddressingType
 
 
+SCRIPT_LOCATION = "uds.packet.abstract_can_packet_container"
+
+
 class TestAbstractCanPacketContainer:
     """Unit tests for 'AbstractCanPacketContainer' class."""
 
-    SCRIPT_LOCATION = "uds.packet.abstract_can_packet_container"
-
-    def setup(self):
+    def setup_method(self):
         self.mock_can_packet_container = Mock(spec=AbstractCanPacketContainer)
         mock_can_packet_type_class = Mock(SINGLE_FRAME=CanPacketType.SINGLE_FRAME,
                                           FIRST_FRAME=CanPacketType.FIRST_FRAME,
                                           CONSECUTIVE_FRAME=CanPacketType.CONSECUTIVE_FRAME,
                                           FLOW_CONTROL=CanPacketType.FLOW_CONTROL)
         # patching
-        self._patcher_ai_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanAddressingInformation")
+        self._patcher_ai_handler_class = patch(f"{SCRIPT_LOCATION}.CanAddressingInformation")
         self.mock_ai_handler_class = self._patcher_ai_handler_class.start()
-        self._patcher_can_dlc_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler")
+        self._patcher_can_dlc_handler_class = patch(f"{SCRIPT_LOCATION}.CanDlcHandler")
         self.mock_can_dlc_handler_class = self._patcher_can_dlc_handler_class.start()
-        self._patcher_single_frame_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanSingleFrameHandler")
+        self._patcher_single_frame_handler_class = patch(f"{SCRIPT_LOCATION}.CanSingleFrameHandler")
         self.mock_single_frame_handler_class = self._patcher_single_frame_handler_class.start()
-        self._patcher_first_frame_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanFirstFrameHandler")
+        self._patcher_first_frame_handler_class = patch(f"{SCRIPT_LOCATION}.CanFirstFrameHandler")
         self.mock_first_frame_handler_class = self._patcher_first_frame_handler_class.start()
-        self._patcher_consecutive_frame_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanConsecutiveFrameHandler")
+        self._patcher_consecutive_frame_handler_class = patch(f"{SCRIPT_LOCATION}.CanConsecutiveFrameHandler")
         self.mock_consecutive_frame_handler_class = self._patcher_consecutive_frame_handler_class.start()
-        self._patcher_flow_control_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanFlowControlHandler")
+        self._patcher_flow_control_handler_class = patch(f"{SCRIPT_LOCATION}.CanFlowControlHandler")
         self.mock_flow_control_handler_class = self._patcher_flow_control_handler_class.start()
-        self._patcher_can_packet_type_class = patch(f"{self.SCRIPT_LOCATION}.CanPacketType", mock_can_packet_type_class)
+        self._patcher_can_packet_type_class = patch(f"{SCRIPT_LOCATION}.CanPacketType", mock_can_packet_type_class)
         self.mock_can_packet_type_class = self._patcher_can_packet_type_class.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_ai_handler_class.stop()
         self._patcher_can_dlc_handler_class.stop()
         self._patcher_single_frame_handler_class.stop()
diff --git a/tests/software_tests/packet/test_abstract_packet.py b/tests/software_tests/packet/test_abstract_packet.py
index d20bb7db..edfcb7c4 100644
--- a/tests/software_tests/packet/test_abstract_packet.py
+++ b/tests/software_tests/packet/test_abstract_packet.py
@@ -5,18 +5,19 @@
     TransmissionDirection, ReassignmentError, datetime
 
 
+SCRIPT_LOCATION = "uds.packet.abstract_packet"
+
+
 class TestAbstractUdsPacketRecord:
     """Unit tests for 'AbstractUdsPacketRecord' class."""
 
-    SCRIPT_LOCATION = "uds.packet.abstract_packet"
-
-    def setup(self):
+    def setup_method(self):
         self.mock_packet_record = Mock(spec=AbstractUdsPacketRecord)
         # patching
-        self._patcher_validate_direction = patch(f"{self.SCRIPT_LOCATION}.TransmissionDirection.validate_member")
+        self._patcher_validate_direction = patch(f"{SCRIPT_LOCATION}.TransmissionDirection.validate_member")
         self.mock_validate_direction = self._patcher_validate_direction.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_direction.stop()
 
     # __init__
diff --git a/tests/software_tests/packet/test_abstract_packet_type.py b/tests/software_tests/packet/test_abstract_packet_type.py
index 71d538dc..cb3681d2 100644
--- a/tests/software_tests/packet/test_abstract_packet_type.py
+++ b/tests/software_tests/packet/test_abstract_packet_type.py
@@ -2,11 +2,12 @@
 from uds.utilities import NibbleEnum, ValidatedEnum, ExtendableEnum
 
 
+SCRIPT_LOCATION = "uds.packet.abstract_packet"
+
+
 class TestAbstractPacketType:
     """Unit tests for 'AbstractPacketType' class."""
 
-    SCRIPT_LOCATION = "uds.packet.abstract_packet"
-
     def test_inheritance__nibble_enum(self):
         assert issubclass(AbstractUdsPacketType, NibbleEnum)
 
diff --git a/tests/software_tests/packet/test_can_packet.py b/tests/software_tests/packet/test_can_packet.py
index 16b40b09..22c8b046 100644
--- a/tests/software_tests/packet/test_can_packet.py
+++ b/tests/software_tests/packet/test_can_packet.py
@@ -7,52 +7,53 @@
 from uds.can import CanFlowStatus
 
 
+SCRIPT_LOCATION = "uds.packet.can_packet"
+
+
 class TestCanPacket:
     """Unit tests for 'CanPacket' class."""
 
-    SCRIPT_LOCATION = "uds.packet.can_packet"
-
-    def setup(self):
+    def setup_method(self):
         self.mock_can_packet = Mock(spec=CanPacket)
         mock_can_id_handler_class = Mock(spec=CanIdHandler,
                                          ADDRESSING_TYPE_NAME=CanIdHandler.ADDRESSING_TYPE_NAME,
                                          TARGET_ADDRESS_NAME=CanIdHandler.TARGET_ADDRESS_NAME,
                                          SOURCE_ADDRESS_NAME=CanIdHandler.SOURCE_ADDRESS_NAME)
         # patching
-        self._patcher_warn = patch(f"{self.SCRIPT_LOCATION}.warn")
+        self._patcher_warn = patch(f"{SCRIPT_LOCATION}.warn")
         self.mock_warn = self._patcher_warn.start()
-        self._patcher_can_dlc_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler")
+        self._patcher_can_dlc_handler_class = patch(f"{SCRIPT_LOCATION}.CanDlcHandler")
         self.mock_can_dlc_handler_class = self._patcher_can_dlc_handler_class.start()
-        self._patcher_can_id_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanIdHandler", mock_can_id_handler_class)
+        self._patcher_can_id_handler_class = patch(f"{SCRIPT_LOCATION}.CanIdHandler", mock_can_id_handler_class)
         self.mock_can_id_handler_class = self._patcher_can_id_handler_class.start()
-        self._patcher_ai_class = patch(f"{self.SCRIPT_LOCATION}.CanAddressingInformation")
+        self._patcher_ai_class = patch(f"{SCRIPT_LOCATION}.CanAddressingInformation")
         self.mock_ai_class = self._patcher_ai_class.start()
-        self._patcher_normal_11bit_ai_class = patch(f"{self.SCRIPT_LOCATION}.Normal11BitCanAddressingInformation")
+        self._patcher_normal_11bit_ai_class = patch(f"{SCRIPT_LOCATION}.Normal11BitCanAddressingInformation")
         self.mock_normal_11bit_ai_class = self._patcher_normal_11bit_ai_class.start()
-        self._patcher_normal_fixed_ai_class = patch(f"{self.SCRIPT_LOCATION}.NormalFixedCanAddressingInformation")
+        self._patcher_normal_fixed_ai_class = patch(f"{SCRIPT_LOCATION}.NormalFixedCanAddressingInformation")
         self.mock_normal_fixed_ai_class = self._patcher_normal_fixed_ai_class.start()
-        self._patcher_extended_ai_class = patch(f"{self.SCRIPT_LOCATION}.ExtendedCanAddressingInformation")
+        self._patcher_extended_ai_class = patch(f"{SCRIPT_LOCATION}.ExtendedCanAddressingInformation")
         self.mock_extended_ai_class = self._patcher_extended_ai_class.start()
-        self._patcher_mixed_11bit_ai_class = patch(f"{self.SCRIPT_LOCATION}.Mixed11BitCanAddressingInformation")
+        self._patcher_mixed_11bit_ai_class = patch(f"{SCRIPT_LOCATION}.Mixed11BitCanAddressingInformation")
         self.mock_mixed_11bit_ai_class = self._patcher_mixed_11bit_ai_class.start()
-        self._patcher_mixed_29bit_ai_class = patch(f"{self.SCRIPT_LOCATION}.Mixed29BitCanAddressingInformation")
+        self._patcher_mixed_29bit_ai_class = patch(f"{SCRIPT_LOCATION}.Mixed29BitCanAddressingInformation")
         self.mock_mixed_29bit_ai_class = self._patcher_mixed_29bit_ai_class.start()
-        self._patcher_single_frame_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanSingleFrameHandler")
+        self._patcher_single_frame_handler_class = patch(f"{SCRIPT_LOCATION}.CanSingleFrameHandler")
         self.mock_single_frame_handler_class = self._patcher_single_frame_handler_class.start()
-        self._patcher_first_frame_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanFirstFrameHandler")
+        self._patcher_first_frame_handler_class = patch(f"{SCRIPT_LOCATION}.CanFirstFrameHandler")
         self.mock_first_frame_handler_class = self._patcher_first_frame_handler_class.start()
-        self._patcher_consecutive_frame_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanConsecutiveFrameHandler")
+        self._patcher_consecutive_frame_handler_class = patch(f"{SCRIPT_LOCATION}.CanConsecutiveFrameHandler")
         self.mock_consecutive_frame_handler_class = self._patcher_consecutive_frame_handler_class.start()
-        self._patcher_flow_control_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanFlowControlHandler")
+        self._patcher_flow_control_handler_class = patch(f"{SCRIPT_LOCATION}.CanFlowControlHandler")
         self.mock_flow_control_handler_class = self._patcher_flow_control_handler_class.start()
-        self._patcher_addressing_type_class = patch(f"{self.SCRIPT_LOCATION}.AddressingType")
+        self._patcher_addressing_type_class = patch(f"{SCRIPT_LOCATION}.AddressingType")
         self.mock_addressing_type_class = self._patcher_addressing_type_class.start()
-        self._patcher_validate_addressing_format = patch(f"{self.SCRIPT_LOCATION}.CanAddressingFormat.validate_member")
+        self._patcher_validate_addressing_format = patch(f"{SCRIPT_LOCATION}.CanAddressingFormat.validate_member")
         self.mock_validate_addressing_format = self._patcher_validate_addressing_format.start()
-        self._patcher_validate_packet_type = patch(f"{self.SCRIPT_LOCATION}.CanPacketType.validate_member")
+        self._patcher_validate_packet_type = patch(f"{SCRIPT_LOCATION}.CanPacketType.validate_member")
         self.mock_validate_packet_type = self._patcher_validate_packet_type.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_warn.stop()
         self._patcher_can_dlc_handler_class.stop()
         self._patcher_can_id_handler_class.stop()
@@ -812,27 +813,25 @@ def test_update_ai_data_byte(self, addressing_format, raw_frame_data, ai_data_by
 class TestAnyCanPacket:
     """Unit tests for `AnyCanPacket` class."""
 
-    SCRIPT_LOCATION = TestCanPacket.SCRIPT_LOCATION
-
-    def setup(self):
+    def setup_method(self):
         self.mock_any_can_packet = Mock(spec=AnyCanPacket)
         # patching
-        self._patcher_validate_raw_bytes = patch(f"{self.SCRIPT_LOCATION}.validate_raw_bytes")
+        self._patcher_validate_raw_bytes = patch(f"{SCRIPT_LOCATION}.validate_raw_bytes")
         self.mock_validate_raw_bytes = self._patcher_validate_raw_bytes.start()
-        self._patcher_addressing_type_class = patch(f"{self.SCRIPT_LOCATION}.AddressingType")
+        self._patcher_addressing_type_class = patch(f"{SCRIPT_LOCATION}.AddressingType")
         self.mock_addressing_type_class = self._patcher_addressing_type_class.start()
-        self._patcher_addressing_format_class = patch(f"{self.SCRIPT_LOCATION}.CanAddressingFormat")
+        self._patcher_addressing_format_class = patch(f"{SCRIPT_LOCATION}.CanAddressingFormat")
         self.mock_addressing_format_class = self._patcher_addressing_format_class.start()
-        self._patcher_can_id_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanIdHandler")
+        self._patcher_can_id_handler_class = patch(f"{SCRIPT_LOCATION}.CanIdHandler")
         self.mock_can_id_handler_class = self._patcher_can_id_handler_class.start()
-        self._patcher_can_dlc_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler")
+        self._patcher_can_dlc_handler_class = patch(f"{SCRIPT_LOCATION}.CanDlcHandler")
         self.mock_can_dlc_handler_class = self._patcher_can_dlc_handler_class.start()
-        self._patcher_ai_class = patch(f"{self.SCRIPT_LOCATION}.CanAddressingInformation")
+        self._patcher_ai_class = patch(f"{SCRIPT_LOCATION}.CanAddressingInformation")
         self.mock_ai_class = self._patcher_ai_class.start()
-        self._patcher_can_packet_class = patch(f"{self.SCRIPT_LOCATION}.CanPacket")
+        self._patcher_can_packet_class = patch(f"{SCRIPT_LOCATION}.CanPacket")
         self.mock_can_packet_class = self._patcher_can_packet_class.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_raw_bytes.stop()
         self._patcher_addressing_type_class.stop()
         self._patcher_addressing_format_class.stop()
diff --git a/tests/software_tests/packet/test_can_packet_record.py b/tests/software_tests/packet/test_can_packet_record.py
index 03d9b1ac..9b5814dc 100644
--- a/tests/software_tests/packet/test_can_packet_record.py
+++ b/tests/software_tests/packet/test_can_packet_record.py
@@ -9,30 +9,31 @@
 from uds.can import CanFlowStatus
 
 
+SCRIPT_LOCATION = "uds.packet.can_packet_record"
+
+
 class TestCanPacketRecord:
     """Unit tests for `CanPacketRecord` class."""
 
-    SCRIPT_LOCATION = "uds.packet.can_packet_record"
-
-    def setup(self):
+    def setup_method(self):
         self.mock_can_packet_record = Mock(spec=CanPacketRecord)
         # patching
-        self._patcher_addressing_type_class = patch(f"{self.SCRIPT_LOCATION}.AddressingType")
+        self._patcher_addressing_type_class = patch(f"{SCRIPT_LOCATION}.AddressingType")
         self.mock_addressing_type_class = self._patcher_addressing_type_class.start()
-        self._patcher_can_addressing_format_class = patch(f"{self.SCRIPT_LOCATION}.CanAddressingFormat")
+        self._patcher_can_addressing_format_class = patch(f"{SCRIPT_LOCATION}.CanAddressingFormat")
         self.mock_can_addressing_format_class = self._patcher_can_addressing_format_class.start()
-        self._patcher_can_ai_class = patch(f"{self.SCRIPT_LOCATION}.CanAddressingInformation")
+        self._patcher_can_ai_class = patch(f"{SCRIPT_LOCATION}.CanAddressingInformation")
         self.mock_can_ai_class = self._patcher_can_ai_class.start()
-        self._patcher_can_packet_type_class = patch(f"{self.SCRIPT_LOCATION}.CanPacketType")
+        self._patcher_can_packet_type_class = patch(f"{SCRIPT_LOCATION}.CanPacketType")
         self.mock_can_packet_type_class = self._patcher_can_packet_type_class.start()
-        self._patcher_can_id_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanIdHandler")
+        self._patcher_can_id_handler_class = patch(f"{SCRIPT_LOCATION}.CanIdHandler")
         self.mock_can_id_handler_class = self._patcher_can_id_handler_class.start()
-        self._patcher_can_dlc_handler_class = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler")
+        self._patcher_can_dlc_handler_class = patch(f"{SCRIPT_LOCATION}.CanDlcHandler")
         self.mock_can_dlc_handler_class = self._patcher_can_dlc_handler_class.start()
-        self._patcher_abstract_uds_packet_record_init = patch(f"{self.SCRIPT_LOCATION}.AbstractUdsPacketRecord.__init__")
+        self._patcher_abstract_uds_packet_record_init = patch(f"{SCRIPT_LOCATION}.AbstractUdsPacketRecord.__init__")
         self.mock_abstract_uds_packet_record_init = self._patcher_abstract_uds_packet_record_init.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_addressing_type_class.stop()
         self._patcher_can_addressing_format_class.stop()
         self._patcher_can_ai_class.stop()
@@ -147,7 +148,7 @@ def test_validate_frame__invalid_type(self, frame):
     def test_validate_frame__valid_python_can(self, example_python_can_message):
         assert CanPacketRecord._validate_frame(example_python_can_message) is None
         self.mock_can_id_handler_class.validate_can_id.assert_called_once_with(
-            example_python_can_message.arbitration_id, extended_can_id=example_python_can_message.is_extended_id)
+            example_python_can_message.arbitration_id)
         self.mock_can_dlc_handler_class.validate_data_bytes_number.assert_called_once_with(
             len(example_python_can_message.data))
 
diff --git a/tests/software_tests/packet/test_can_packet_type.py b/tests/software_tests/packet/test_can_packet_type.py
index 85e2aee6..3b9c278d 100644
--- a/tests/software_tests/packet/test_can_packet_type.py
+++ b/tests/software_tests/packet/test_can_packet_type.py
@@ -8,11 +8,11 @@
 class TestCanPacketType:
     """Unit tests for `CanPacketType` class."""
 
-    def setup(self):
+    def setup_method(self):
         self._patcher_validate_member = patch("uds.utilities.ValidatedEnum.validate_member")
         self.mock_validate_member = self._patcher_validate_member.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_member.stop()
 
     # inheritance
diff --git a/tests/software_tests/segmentation/test_abstract_segmenter.py b/tests/software_tests/segmentation/test_abstract_segmenter.py
index 210f417d..1ded96ba 100644
--- a/tests/software_tests/segmentation/test_abstract_segmenter.py
+++ b/tests/software_tests/segmentation/test_abstract_segmenter.py
@@ -4,30 +4,33 @@
 from uds.segmentation.abstract_segmenter import AbstractSegmenter
 
 
+SCRIPT_PATH = "uds.segmentation.abstract_segmenter"
+
+
 class TestAbstractSegmenter:
     """Unit tests for `AbstractSegmenter` class."""
 
-    SCRIPT_PATH = "uds.segmentation.abstract_segmenter"
-
-    def setup(self):
+    def setup_method(self):
         self.mock_abstract_segmenter = Mock(spec=AbstractSegmenter)
 
-    # is_supported_packet
+    # is_supported_packet_type
 
     @pytest.mark.parametrize("result", [True, False])
     @pytest.mark.parametrize("value", [None, 5, "some value", Mock()])
     @patch(f"{SCRIPT_PATH}.isinstance")
-    def test_is_supported_packet(self, mock_isinstance, value, result):
+    def test_is_supported_packet_type(self, mock_isinstance, value, result):
         mock_isinstance.return_value = result
-        assert AbstractSegmenter.is_supported_packet(self=self.mock_abstract_segmenter, value=value) is result
-        mock_isinstance.assert_called_once_with(value, self.mock_abstract_segmenter.supported_packet_classes)
+        assert AbstractSegmenter.is_supported_packet_type(self=self.mock_abstract_segmenter, packet=value) is result
+        mock_isinstance.assert_called_once_with(value, (self.mock_abstract_segmenter.supported_packet_class,
+                                                        self.mock_abstract_segmenter.supported_packet_record_class))
 
-    # is_supported_packets_sequence
+    # is_supported_packets_sequence_type
 
     @pytest.mark.parametrize("value", [None, True, 1, Mock(), {1, 2, 3}])
-    def test_is_supported_packets_sequence__false__invalid_type(self, value):
-        assert AbstractSegmenter.is_supported_packets_sequence(self=self.mock_abstract_segmenter, value=value) is False
-        self.mock_abstract_segmenter.is_supported_packet.assert_not_called()
+    def test_is_supported_packets_sequence_type__false__invalid_type(self, value):
+        assert AbstractSegmenter.is_supported_packets_sequence_type(self=self.mock_abstract_segmenter,
+                                                                    packets=value) is False
+        self.mock_abstract_segmenter.is_supported_packet_type.assert_not_called()
 
     @pytest.mark.parametrize("value", [
         (1, 2, 3, 4),
@@ -36,30 +39,34 @@ def test_is_supported_packets_sequence__false__invalid_type(self, value):
         [None, True, False],
         (True, False),
     ])
-    def test_is_supported_packets_sequence__false__invalid_elements_type(self, value):
-        self.mock_abstract_segmenter.is_supported_packet.return_value = False
-        assert AbstractSegmenter.is_supported_packets_sequence(self=self.mock_abstract_segmenter, value=value) is False
-        self.mock_abstract_segmenter.is_supported_packet.assert_called_once()
+    def test_is_supported_packets_sequence_type__false__invalid_elements_type(self, value):
+        self.mock_abstract_segmenter.is_supported_packet_type.return_value = False
+        assert AbstractSegmenter.is_supported_packets_sequence_type(self=self.mock_abstract_segmenter,
+                                                                    packets=value) is False
+        self.mock_abstract_segmenter.is_supported_packet_type.assert_called_once()
 
     @pytest.mark.parametrize("value", [
         (1, 2.1, 3, 4.4),
         [None, True, False],
     ])
-    def test_is_supported_packets_sequence__false__more_element_types(self, value):
-        self.mock_abstract_segmenter.is_supported_packet.return_value = True
-        assert AbstractSegmenter.is_supported_packets_sequence(self=self.mock_abstract_segmenter, value=value) is False
-        self.mock_abstract_segmenter.is_supported_packet.assert_called()
+    def test_is_supported_packets_sequence_type__false__more_element_types(self, value):
+        self.mock_abstract_segmenter.is_supported_packet_type.return_value = True
+        assert AbstractSegmenter.is_supported_packets_sequence_type(self=self.mock_abstract_segmenter,
+                                                                    packets=value) is False
+        self.mock_abstract_segmenter.is_supported_packet_type.assert_called()
 
-    def test_is_supported_packets_sequence__false__empty_sequence(self):
-        self.mock_abstract_segmenter.is_supported_packet.return_value = True
-        assert AbstractSegmenter.is_supported_packets_sequence(self=self.mock_abstract_segmenter, value=[]) is False
+    def test_is_supported_packets_sequence_type__false__empty_sequence(self):
+        self.mock_abstract_segmenter.is_supported_packet_type.return_value = True
+        assert AbstractSegmenter.is_supported_packets_sequence_type(self=self.mock_abstract_segmenter,
+                                                                    packets=[]) is False
 
     @pytest.mark.parametrize("value", [
         (1, 2, 3, 4),
         [2.2, 3.3, 4.4],
         (True, False),
     ])
-    def test_is_supported_packets_sequence__true(self, value):
-        self.mock_abstract_segmenter.is_supported_packet.return_value = True
-        assert AbstractSegmenter.is_supported_packets_sequence(self=self.mock_abstract_segmenter, value=value) is True
-        self.mock_abstract_segmenter.is_supported_packet.assert_called()
+    def test_is_supported_packets_sequence_type__true(self, value):
+        self.mock_abstract_segmenter.is_supported_packet_type.return_value = True
+        assert AbstractSegmenter.is_supported_packets_sequence_type(self=self.mock_abstract_segmenter,
+                                                                    packets=value) is True
+        self.mock_abstract_segmenter.is_supported_packet_type.assert_called()
diff --git a/tests/software_tests/segmentation/test_can_segmenter.py b/tests/software_tests/segmentation/test_can_segmenter.py
index a922a7a2..44f9825e 100644
--- a/tests/software_tests/segmentation/test_can_segmenter.py
+++ b/tests/software_tests/segmentation/test_can_segmenter.py
@@ -1,46 +1,47 @@
 import pytest
-from mock import Mock, patch, call
+from mock import Mock, MagicMock, patch, call
 
 from uds.segmentation.can_segmenter import CanSegmenter, \
     CanDlcHandler, CanPacket, CanPacketRecord, CanPacketType, CanFirstFrameHandler, \
-    AddressingType, UdsMessage, DEFAULT_FILLER_BYTE, SegmentationError
+    AddressingType, UdsMessage, DEFAULT_FILLER_BYTE, SegmentationError, AbstractCanAddressingInformation
+from uds.can import Normal11BitCanAddressingInformation, NormalFixedCanAddressingInformation, \
+    ExtendedCanAddressingInformation, Mixed11BitCanAddressingInformation, Mixed29BitCanAddressingInformation
+
+
+SCRIPT_LOCATION = "uds.segmentation.can_segmenter"
 
 
 class TestCanSegmenter:
     """Unit tests for `CanSegmenter` class."""
 
-    SCRIPT_LOCATION = "uds.segmentation.can_segmenter"
-
-    def setup(self):
+    def setup_method(self):
         self.mock_can_segmenter = Mock(spec=CanSegmenter)
+        self.mock_can_segmenter.addressing_information.AI_DATA_BYTES_NUMBER = 0
         # patching
-        self._patcher_can_addressing_format_class = patch(f"{self.SCRIPT_LOCATION}.CanAddressingFormat")
-        self.mock_can_addressing_format_class = self._patcher_can_addressing_format_class.start()
-        self._patcher_can_ai_class = patch(f"{self.SCRIPT_LOCATION}.CanAddressingInformation")
+        self._patcher_can_ai_class = patch(f"{SCRIPT_LOCATION}.CanAddressingInformation")
         self.mock_can_ai_class = self._patcher_can_ai_class.start()
-        self._patcher_validate_dlc = patch(f"{self.SCRIPT_LOCATION}.CanDlcHandler.validate_dlc")
+        self._patcher_validate_dlc = patch(f"{SCRIPT_LOCATION}.CanDlcHandler.validate_dlc")
         self.mock_validate_dlc = self._patcher_validate_dlc.start()
-        self._patcher_is_initial_packet_type = patch(f"{self.SCRIPT_LOCATION}.CanPacketType.is_initial_packet_type")
+        self._patcher_is_initial_packet_type = patch(f"{SCRIPT_LOCATION}.CanPacketType.is_initial_packet_type")
         self.mock_is_initial_packet_type = self._patcher_is_initial_packet_type.start()
         self._patcher_get_max_sf_payload_size \
-            = patch(f"{self.SCRIPT_LOCATION}.CanSingleFrameHandler.get_max_payload_size")
+            = patch(f"{SCRIPT_LOCATION}.CanSingleFrameHandler.get_max_payload_size")
         self.mock_get_max_sf_payload_size = self._patcher_get_max_sf_payload_size.start()
-        self._patcher_get_ff_payload_size = patch(f"{self.SCRIPT_LOCATION}.CanFirstFrameHandler.get_payload_size")
+        self._patcher_get_ff_payload_size = patch(f"{SCRIPT_LOCATION}.CanFirstFrameHandler.get_payload_size")
         self.mock_get_ff_payload_size = self._patcher_get_ff_payload_size.start()
         self._patcher_get_max_cf_payload_size \
-            = patch(f"{self.SCRIPT_LOCATION}.CanConsecutiveFrameHandler.get_max_payload_size")
+            = patch(f"{SCRIPT_LOCATION}.CanConsecutiveFrameHandler.get_max_payload_size")
         self.mock_get_max_cf_payload_size = self._patcher_get_max_cf_payload_size.start()
-        self._patcher_can_packet_class = patch(f"{self.SCRIPT_LOCATION}.CanPacket")
+        self._patcher_can_packet_class = patch(f"{SCRIPT_LOCATION}.CanPacket")
         self.mock_can_packet_class = self._patcher_can_packet_class.start()
-        self._patcher_uds_message_class = patch(f"{self.SCRIPT_LOCATION}.UdsMessage")
+        self._patcher_uds_message_class = patch(f"{SCRIPT_LOCATION}.UdsMessage")
         self.mock_uds_message_class = self._patcher_uds_message_class.start()
-        self._patcher_uds_message_record_class = patch(f"{self.SCRIPT_LOCATION}.UdsMessageRecord")
+        self._patcher_uds_message_record_class = patch(f"{SCRIPT_LOCATION}.UdsMessageRecord")
         self.mock_uds_message_record_class = self._patcher_uds_message_record_class.start()
-        self._patcher_validate_raw_byte = patch(f"{self.SCRIPT_LOCATION}.validate_raw_byte")
+        self._patcher_validate_raw_byte = patch(f"{SCRIPT_LOCATION}.validate_raw_byte")
         self.mock_validate_raw_byte = self._patcher_validate_raw_byte.start()
 
-    def teardown(self):
-        self._patcher_can_addressing_format_class.stop()
+    def teardown_method(self):
         self._patcher_can_ai_class.stop()
         self._patcher_validate_dlc.stop()
         self._patcher_is_initial_packet_type.stop()
@@ -54,100 +55,91 @@ def teardown(self):
 
     # __init__
 
-    @pytest.mark.parametrize("addressing_format, physical_ai, functional_ai", [
-        ("some format", "Addressing Info1 ", "Addressing Info 2"),
-        ("Normal", None, {}),
+    @pytest.mark.parametrize("addressing_information", [
+        "some addressing information",
+        Mock()
     ])
-    def test_init__mandatory_args(self, addressing_format, physical_ai, functional_ai):
+    def test_init__mandatory_args(self, addressing_information):
         CanSegmenter.__init__(self=self.mock_can_segmenter,
-                              addressing_format=addressing_format,
-                              physical_ai=physical_ai,
-                              functional_ai=functional_ai)
-        assert self.mock_can_segmenter._CanSegmenter__addressing_format \
-               == self.mock_can_addressing_format_class.return_value
-        assert self.mock_can_segmenter.physical_ai == physical_ai
-        assert self.mock_can_segmenter.functional_ai == functional_ai
+                              addressing_information=addressing_information)
+        assert self.mock_can_segmenter.addressing_information == addressing_information
         assert self.mock_can_segmenter.dlc == CanDlcHandler.MIN_BASE_UDS_DLC
         assert self.mock_can_segmenter.use_data_optimization is False
         assert self.mock_can_segmenter.filler_byte == DEFAULT_FILLER_BYTE
-        self.mock_can_addressing_format_class.validate_member.assert_called_once_with(addressing_format)
-        self.mock_can_addressing_format_class.assert_called_once_with(addressing_format)
 
-    @pytest.mark.parametrize("addressing_format, physical_ai, functional_ai, dlc, use_data_optimization, filler_byte", [
-        ("some format", "Addressing Info1 ", "Addressing Info 2", "DLC", "whether tyo use data optimization", "filler"),
-        ("Normal", None, {}, 0xF, False, 0x71),
+    @pytest.mark.parametrize("addressing_information, dlc, use_data_optimization, filler_byte", [
+        ("some addressing info", "some dlc", "True or False", "filler"),
+        (Mock(), Mock(), Mock(), Mock()),
     ])
-    def test_init__all_args(self, addressing_format, physical_ai, functional_ai, dlc, use_data_optimization,
-                            filler_byte):
+    def test_init__all_args(self, addressing_information, dlc, use_data_optimization, filler_byte):
         CanSegmenter.__init__(self=self.mock_can_segmenter,
-                              addressing_format=addressing_format,
-                              physical_ai=physical_ai,
-                              functional_ai=functional_ai,
+                              addressing_information=addressing_information,
                               dlc=dlc,
                               use_data_optimization=use_data_optimization,
                               filler_byte=filler_byte)
-        assert self.mock_can_segmenter._CanSegmenter__addressing_format \
-               == self.mock_can_addressing_format_class.return_value
-        assert self.mock_can_segmenter.physical_ai == physical_ai
-        assert self.mock_can_segmenter.functional_ai == functional_ai
+        assert self.mock_can_segmenter.addressing_information == addressing_information
         assert self.mock_can_segmenter.dlc == dlc
         assert self.mock_can_segmenter.use_data_optimization == use_data_optimization
         assert self.mock_can_segmenter.filler_byte == filler_byte
-        self.mock_can_addressing_format_class.validate_member.assert_called_once_with(addressing_format)
-        self.mock_can_addressing_format_class.assert_called_once_with(addressing_format)
 
     # supported_packet_classes
 
-    def test_supported_packet_classes__get(self):
-        assert CanSegmenter.supported_packet_classes.fget(self.mock_can_segmenter) \
-               == (self.mock_can_packet_class, CanPacketRecord)
+    def test_supported_packet_class__get(self):
+        assert CanSegmenter.supported_packet_class.fget(self.mock_can_segmenter) == self.mock_can_packet_class
+
+    # supported_packet_record_class
+
+    def test_supported_packet_record_class__get(self):
+        assert CanSegmenter.supported_packet_record_class.fget(self.mock_can_segmenter) == CanPacketRecord
 
     # addressing_format
 
-    @pytest.mark.parametrize("value", ["something", 5.5])
-    def test_addressing_format__get(self, value):
-        self.mock_can_segmenter._CanSegmenter__addressing_format = value
-        assert CanSegmenter.addressing_format.fget(self.mock_can_segmenter) == value
+    def test_addressing_format__get(self):
+        assert CanSegmenter.addressing_format.fget(self.mock_can_segmenter) \
+               == self.mock_can_segmenter.addressing_information.addressing_format
 
-    # physical_ai
+    # rx_packets_physical_ai
 
-    @pytest.mark.parametrize("value", ["something", 5.5])
-    def test_physical_ai__get(self, value):
-        self.mock_can_segmenter._CanSegmenter__physical_ai = value
-        assert CanSegmenter.physical_ai.fget(self.mock_can_segmenter) == value
-
-    @pytest.mark.parametrize("value", [{"a": 1, "b": 2, "addressing_format": Mock(), "addressing_type": Mock()},
-                                       {"arg1": "something", "arg2": "something else"}])
-    def test_physical_ai__set(self, value):
-        CanSegmenter.physical_ai.fset(self.mock_can_segmenter, value=value)
-        value.pop("addressing_format", None)
-        value.pop("addressing_type", None)
-        self.mock_can_ai_class.validate_packet_ai.assert_called_once_with(
-            addressing_format=self.mock_can_segmenter.addressing_format,
-            addressing_type=AddressingType.PHYSICAL,
-            **value)
-        assert self.mock_can_segmenter._CanSegmenter__physical_ai \
-               == self.mock_can_ai_class.validate_packet_ai.return_value
+    def test_rx_packets_physical_ai__get(self):
+        assert CanSegmenter.rx_packets_physical_ai.fget(self.mock_can_segmenter) \
+               == self.mock_can_segmenter.addressing_information.rx_packets_physical_ai
 
-    # functional_ai
+    # tx_packets_physical_ai
 
-    @pytest.mark.parametrize("value", ["something", 5.5])
-    def test_functional_ai__get(self, value):
-        self.mock_can_segmenter._CanSegmenter__functional_ai = value
-        assert CanSegmenter.functional_ai.fget(self.mock_can_segmenter) == value
-
-    @pytest.mark.parametrize("value", [{"a": 1, "b": 2, "addressing_format": Mock(), "addressing_type": Mock()},
-                                       {"arg1": "something", "arg2": "something else"}])
-    def test_functional_ai__set(self, value):
-        CanSegmenter.functional_ai.fset(self.mock_can_segmenter, value=value)
-        value.pop("addressing_format", None)
-        value.pop("addressing_type", None)
-        self.mock_can_ai_class.validate_packet_ai.assert_called_once_with(
-            addressing_format=self.mock_can_segmenter.addressing_format,
-            addressing_type=AddressingType.FUNCTIONAL,
-            **value)
-        assert self.mock_can_segmenter._CanSegmenter__functional_ai \
-               == self.mock_can_ai_class.validate_packet_ai.return_value
+    def test_tx_packets_physical_ai__get(self):
+        assert CanSegmenter.tx_packets_physical_ai.fget(self.mock_can_segmenter) \
+               == self.mock_can_segmenter.addressing_information.tx_packets_physical_ai
+
+    # rx_packets_functional_ai
+
+    def test_rx_packets_functional_ai__get(self):
+        assert CanSegmenter.rx_packets_functional_ai.fget(self.mock_can_segmenter) \
+               == self.mock_can_segmenter.addressing_information.rx_packets_functional_ai
+
+    # tx_packets_functional_ai
+
+    def test_tx_packets_functional_ai__get(self):
+        assert CanSegmenter.tx_packets_functional_ai.fget(self.mock_can_segmenter) \
+               == self.mock_can_segmenter.addressing_information.tx_packets_functional_ai
+
+    # addressing_information
+
+    @pytest.mark.parametrize("value", ["some AI", Mock()])
+    def test_addressing_information__get(self, value):
+        self.mock_can_segmenter._CanSegmenter__addressing_information = value
+        assert CanSegmenter.addressing_information.fget(self.mock_can_segmenter) \
+               == self.mock_can_segmenter._CanSegmenter__addressing_information
+
+    @pytest.mark.parametrize("value", [Mock(), "some value"])
+    def test_addressing_information__set__type_error(self, value):
+        with pytest.raises(TypeError):
+            CanSegmenter.addressing_information.fset(self.mock_can_segmenter, value=value)
+
+    @pytest.mark.parametrize("value", [Mock(spec=AbstractCanAddressingInformation),
+                                       Mock(spec=Normal11BitCanAddressingInformation)])
+    def test_addressing_information__set(self, value):
+        CanSegmenter.addressing_information.fset(self.mock_can_segmenter, value=value)
+        assert self.mock_can_segmenter._CanSegmenter__addressing_information == value
 
     # dlc
 
@@ -170,12 +162,12 @@ def test_dlc__set(self, value):
 
     # use_data_optimization
 
-    @pytest.mark.parametrize("value", ["something", 5.5])
+    @pytest.mark.parametrize("value", [False, True])
     def test_use_data_optimization__get(self, value):
         self.mock_can_segmenter._CanSegmenter__use_data_optimization = value
         assert CanSegmenter.use_data_optimization.fget(self.mock_can_segmenter) == value
 
-    @pytest.mark.parametrize("value", ["something", 5.5])
+    @pytest.mark.parametrize("value", [False, True, "something"])
     def test_use_data_optimization__set(self, value):
         CanSegmenter.use_data_optimization.fset(self.mock_can_segmenter, value=value)
         assert self.mock_can_segmenter._CanSegmenter__use_data_optimization == bool(value)
@@ -193,6 +185,153 @@ def test_filler_byte__set(self, value):
         self.mock_validate_raw_byte.assert_called_once_with(value)
         assert self.mock_can_segmenter._CanSegmenter__filler_byte == value
 
+    # is_input_packet
+
+    @pytest.mark.parametrize("frame_can_id, frame_data", [
+        ("some ID", "some data"),
+        (Mock(), MagicMock()),
+    ])
+    def test_is_input_packet__decoding_error(self, frame_can_id, frame_data):
+        self.mock_can_ai_class.decode_packet_ai.side_effect = ValueError
+        assert CanSegmenter.is_input_packet(self.mock_can_segmenter, can_id=frame_can_id, data=frame_data) is None
+
+    @pytest.mark.parametrize("frame_can_id, frame_data, decoded_ai", [
+        ("some ID", "some data", {"a": 1, "b": 2}),
+        (Mock(), MagicMock(), MagicMock()),
+    ])
+    def test_is_input_packet__physical(self, frame_can_id, frame_data, decoded_ai):
+        self.mock_can_ai_class.decode_packet_ai.return_value = decoded_ai
+        mock_eq_physical = Mock(return_value=True)
+        self.mock_can_segmenter.rx_packets_physical_ai = MagicMock(__eq__=mock_eq_physical)
+        self.mock_can_segmenter.rx_packets_functional_ai = MagicMock(__eq__=Mock(return_value=False))
+        assert CanSegmenter.is_input_packet(self.mock_can_segmenter, can_id=frame_can_id, data=frame_data) \
+               == AddressingType.PHYSICAL
+        mock_eq_physical.assert_called_once()
+
+    @pytest.mark.parametrize("frame_can_id, frame_data, decoded_ai", [
+        ("some ID", "some data", {"a": 1, "b": 2}),
+        (Mock(), MagicMock(), MagicMock()),
+    ])
+    def test_is_input_packet__functional(self, frame_can_id, frame_data, decoded_ai):
+        self.mock_can_ai_class.decode_packet_ai.return_value = decoded_ai
+        mock_eq_functional = Mock(return_value=True)
+        self.mock_can_segmenter.rx_packets_physical_ai = MagicMock(__eq__=Mock(return_value=False))
+        self.mock_can_segmenter.rx_packets_functional_ai = MagicMock(__eq__=mock_eq_functional)
+        assert CanSegmenter.is_input_packet(self.mock_can_segmenter, can_id=frame_can_id, data=frame_data) \
+               == AddressingType.FUNCTIONAL
+        mock_eq_functional.assert_called_once()
+
+    @pytest.mark.parametrize("frame_can_id, frame_data, decoded_ai", [
+        ("some ID", "some data", {"a": 1, "b": 2}),
+        (Mock(), MagicMock(), MagicMock()),
+    ])
+    def test_is_input_packet__no_match(self, frame_can_id, frame_data, decoded_ai):
+        self.mock_can_ai_class.decode_packet_ai.return_value = decoded_ai
+        mock_eq_physical = Mock(return_value=False)
+        mock_eq_functional = Mock(return_value=False)
+        self.mock_can_segmenter.rx_packets_physical_ai = MagicMock(__eq__=mock_eq_physical)
+        self.mock_can_segmenter.rx_packets_functional_ai = MagicMock(__eq__=mock_eq_functional)
+        assert CanSegmenter.is_input_packet(self.mock_can_segmenter, can_id=frame_can_id, data=frame_data) is None
+        mock_eq_physical.assert_called_once()
+        mock_eq_functional.assert_called_once()
+
+    # is_desegmented_message
+
+    @pytest.mark.parametrize("packets", ["some packets", range(4)])
+    def test_is_desegmented_message__value_error(self, packets):
+        self.mock_can_segmenter.is_supported_packets_sequence_type.return_value = False
+        with pytest.raises(ValueError):
+            CanSegmenter.is_desegmented_message(self=self.mock_can_segmenter, packets=packets)
+        self.mock_can_segmenter.is_supported_packets_sequence_type.assert_called_once_with(packets)
+
+    @pytest.mark.parametrize("packets", [
+        [Mock()],
+        (Mock(), Mock(), Mock()),
+    ])
+    def test_is_desegmented_message__not_implemented_error(self, packets):
+        self.mock_can_segmenter.is_supported_packets_sequence_type.return_value = True
+        self.mock_is_initial_packet_type.return_value = True
+        with pytest.raises(NotImplementedError):
+            CanSegmenter.is_desegmented_message(self=self.mock_can_segmenter, packets=packets)
+        self.mock_can_segmenter.is_supported_packets_sequence_type.assert_called_once_with(packets)
+        self.mock_is_initial_packet_type.assert_called_once_with(packets[0].packet_type)
+
+    @pytest.mark.parametrize("packets", [
+        [Mock()],
+        (Mock(), Mock(), Mock()),
+    ])
+    def test_is_desegmented_message__false__not_initial_packet(self, packets):
+        self.mock_can_segmenter.is_supported_packets_sequence_type.return_value = True
+        self.mock_is_initial_packet_type.return_value = False
+        assert CanSegmenter.is_desegmented_message(self=self.mock_can_segmenter, packets=packets) is False
+        self.mock_can_segmenter.is_supported_packets_sequence_type.assert_called_once_with(packets)
+        self.mock_is_initial_packet_type.assert_called_once_with(packets[0].packet_type)
+
+    @pytest.mark.parametrize("packets", [
+        [Mock(packet_type=CanPacketType.SINGLE_FRAME)],
+        [Mock(packet_type=CanPacketType.SINGLE_FRAME), Mock()],
+        (Mock(packet_type=CanPacketType.SINGLE_FRAME), Mock(), Mock()),
+    ])
+    def test_is_desegmented_message__single_frame(self, packets):
+        self.mock_can_segmenter.is_supported_packets_sequence_type.return_value = True
+        self.mock_is_initial_packet_type.return_value = True
+        assert CanSegmenter.is_desegmented_message(self=self.mock_can_segmenter, packets=packets) \
+               is (len(packets) == 1)
+        self.mock_can_segmenter.is_supported_packets_sequence_type.assert_called_once_with(packets)
+        self.mock_is_initial_packet_type.assert_called_once_with(packets[0].packet_type)
+
+    @pytest.mark.parametrize("packets", [
+        [Mock(packet_type=CanPacketType.FIRST_FRAME, payload=[]), Mock()],
+        (Mock(packet_type=CanPacketType.FIRST_FRAME, payload=range(5)), Mock(), Mock()),
+    ])
+    def test_is_desegmented_message__first_frame__multiple_initial_packets(self, packets):
+        self.mock_can_segmenter.is_supported_packets_sequence_type.return_value = True
+        self.mock_is_initial_packet_type.return_value = True
+        assert CanSegmenter.is_desegmented_message(self=self.mock_can_segmenter, packets=packets) is False
+        self.mock_can_segmenter.is_supported_packets_sequence_type.assert_called_once_with(packets)
+        self.mock_is_initial_packet_type.assert_has_calls(
+            [call(packets[0].packet_type), call(packets[1].packet_type)])
+
+    @pytest.mark.parametrize("packets", [
+        [Mock(packet_type=CanPacketType.FIRST_FRAME, data_length=11, payload=range(4)), Mock(payload=range(6))],
+        (Mock(packet_type=CanPacketType.FIRST_FRAME, data_length=143, payload=[0xFF] * 10), Mock(payload=None),
+         Mock(payload=range(50, 100)), Mock(payload=range(150, 200))),
+    ])
+    def test_is_desegmented_message__first_frame__too_little_packets(self, packets):
+        self.mock_can_segmenter.is_supported_packets_sequence_type.return_value = True
+        self.mock_is_initial_packet_type.side_effect = [True] + (len(packets) - 1) * [False]
+        assert CanSegmenter.is_desegmented_message(self=self.mock_can_segmenter, packets=packets) is False
+        self.mock_can_segmenter.is_supported_packets_sequence_type.assert_called_once_with(packets)
+        self.mock_is_initial_packet_type.assert_has_calls(
+            [call(packet.packet_type) for packet in packets])
+
+    @pytest.mark.parametrize("packets", [
+        [Mock(packet_type=CanPacketType.FIRST_FRAME, data_length=10, payload=range(4)), Mock(payload=range(6)),
+         Mock(payload=None)],
+        (Mock(packet_type=CanPacketType.FIRST_FRAME, data_length=54, payload=[0xFF] * 10), Mock(payload=None),
+         Mock(payload=range(50, 100)), Mock(payload=range(150, 200))),
+    ])
+    def test_is_desegmented_message__first_frame__too_many_packets(self, packets):
+        self.mock_can_segmenter.is_supported_packets_sequence_type.return_value = True
+        self.mock_is_initial_packet_type.side_effect = [True] + (len(packets) - 1) * [False]
+        assert CanSegmenter.is_desegmented_message(self=self.mock_can_segmenter, packets=packets) is False
+        self.mock_can_segmenter.is_supported_packets_sequence_type.assert_called_once_with(packets)
+        self.mock_is_initial_packet_type.assert_has_calls(
+            [call(packet.packet_type) for packet in packets])
+
+    @pytest.mark.parametrize("packets", [
+        [Mock(packet_type=CanPacketType.FIRST_FRAME, data_length=11, payload=range(4)), Mock(payload=range(7))],
+        (Mock(packet_type=CanPacketType.FIRST_FRAME, data_length=100, payload=[0xFF] * 10), Mock(payload=None),
+         Mock(payload=range(50, 100)), Mock(payload=range(150, 200))),
+    ])
+    def test_is_desegmented_message__first_frame__true(self, packets):
+        self.mock_can_segmenter.is_supported_packets_sequence_type.return_value = True
+        self.mock_is_initial_packet_type.side_effect = [True] + (len(packets) - 1) * [False]
+        assert CanSegmenter.is_desegmented_message(self=self.mock_can_segmenter, packets=packets) is True
+        self.mock_can_segmenter.is_supported_packets_sequence_type.assert_called_once_with(packets)
+        self.mock_is_initial_packet_type.assert_has_calls(
+            [call(packet.packet_type) for packet in packets])
+
     # desegmentation
 
     @pytest.mark.parametrize("packets", [
@@ -200,10 +339,10 @@ def test_filler_byte__set(self, value):
         (Mock(), Mock()),
     ])
     def test_desegmentation__segmentation_error(self, packets):
-        self.mock_can_segmenter.is_complete_packets_sequence.return_value = False
+        self.mock_can_segmenter.is_desegmented_message.return_value = False
         with pytest.raises(SegmentationError):
             CanSegmenter.desegmentation(self=self.mock_can_segmenter, packets=packets)
-        self.mock_can_segmenter.is_complete_packets_sequence.assert_called_once_with(packets)
+        self.mock_can_segmenter.is_desegmented_message.assert_called_once_with(packets)
 
     @pytest.mark.parametrize("packets", [
         [Mock()],
@@ -211,11 +350,11 @@ def test_desegmentation__segmentation_error(self, packets):
     ])
     @patch(f"{SCRIPT_LOCATION}.isinstance")
     def test_desegmentation__not_implemented(self, mock_isinstance, packets):
-        self.mock_can_segmenter.is_complete_packets_sequence.return_value = True
+        self.mock_can_segmenter.is_desegmented_message.return_value = True
         mock_isinstance.return_value = False
         with pytest.raises(NotImplementedError):
             CanSegmenter.desegmentation(self=self.mock_can_segmenter, packets=packets)
-        self.mock_can_segmenter.is_complete_packets_sequence.assert_called_once_with(packets)
+        self.mock_can_segmenter.is_desegmented_message.assert_called_once_with(packets)
         mock_isinstance.assert_called()
 
     @pytest.mark.parametrize("packets", [
@@ -223,10 +362,10 @@ def test_desegmentation__not_implemented(self, mock_isinstance, packets):
         (Mock(spec=CanPacketRecord), Mock(spec=CanPacketRecord)),
     ])
     def test_desegmentation__records(self, packets):
-        self.mock_can_segmenter.is_complete_packets_sequence.return_value = True
+        self.mock_can_segmenter.is_desegmented_message.return_value = True
         assert CanSegmenter.desegmentation(self=self.mock_can_segmenter, packets=packets) \
                == self.mock_uds_message_record_class.return_value
-        self.mock_can_segmenter.is_complete_packets_sequence.assert_called_once_with(packets)
+        self.mock_can_segmenter.is_desegmented_message.assert_called_once_with(packets)
         self.mock_uds_message_record_class.assert_called_once_with(packets)
 
     @pytest.mark.parametrize("packets", [
@@ -235,12 +374,11 @@ def test_desegmentation__records(self, packets):
     ])
     @patch(f"{SCRIPT_LOCATION}.isinstance")
     def test_desegmentation__definition__unsegmented_message(self, mock_isinstance, packets):
-        self.mock_can_segmenter.is_complete_packets_sequence.return_value = True
-        mock_isinstance.side_effect = lambda value, types: types == self.mock_can_packet_class and isinstance(value,
-                                                                                                              CanPacket)
+        self.mock_can_segmenter.is_desegmented_message.return_value = True
+        mock_isinstance.side_effect = lambda value, types: types == self.mock_can_packet_class and isinstance(value, CanPacket)
         assert CanSegmenter.desegmentation(self=self.mock_can_segmenter, packets=packets) \
                == self.mock_uds_message_class.return_value
-        self.mock_can_segmenter.is_complete_packets_sequence.assert_called_once_with(packets)
+        self.mock_can_segmenter.is_desegmented_message.assert_called_once_with(packets)
         self.mock_uds_message_class.assert_called_once_with(payload=packets[0].payload,
                                                             addressing_type=packets[0].addressing_type)
 
@@ -255,12 +393,11 @@ def test_desegmentation__definition__unsegmented_message(self, mock_isinstance,
     ])
     @patch(f"{SCRIPT_LOCATION}.isinstance")
     def test_desegmentation__definitions__segmented_message(self, mock_isinstance, packets):
-        self.mock_can_segmenter.is_complete_packets_sequence.return_value = True
-        mock_isinstance.side_effect = lambda value, types: types == self.mock_can_packet_class and isinstance(value,
-                                                                                                              CanPacket)
+        self.mock_can_segmenter.is_desegmented_message.return_value = True
+        mock_isinstance.side_effect = lambda value, types: types == self.mock_can_packet_class and isinstance(value, CanPacket)
         assert CanSegmenter.desegmentation(self=self.mock_can_segmenter, packets=packets) \
                == self.mock_uds_message_class.return_value
-        self.mock_can_segmenter.is_complete_packets_sequence.assert_called_once_with(packets)
+        self.mock_can_segmenter.is_desegmented_message.assert_called_once_with(packets)
         total_payload = []
         for packet in packets:
             if packet.payload is not None:
@@ -274,12 +411,11 @@ def test_desegmentation__definitions__segmented_message(self, mock_isinstance, p
     ])
     @patch(f"{SCRIPT_LOCATION}.isinstance")
     def test_desegmentation__definitions__segmentation_error(self, mock_isinstance, packets):
-        self.mock_can_segmenter.is_complete_packets_sequence.return_value = True
-        mock_isinstance.side_effect = lambda value, types: types == self.mock_can_packet_class and isinstance(value,
-                                                                                                              CanPacket)
+        self.mock_can_segmenter.is_desegmented_message.return_value = True
+        mock_isinstance.side_effect = lambda value, types: types == self.mock_can_packet_class and isinstance(value, CanPacket)
         with pytest.raises(SegmentationError):
             CanSegmenter.desegmentation(self=self.mock_can_segmenter, packets=packets)
-        self.mock_can_segmenter.is_complete_packets_sequence.assert_called_once_with(packets)
+        self.mock_can_segmenter.is_desegmented_message.assert_called_once_with(packets)
 
     # segmentation
 
@@ -318,103 +454,6 @@ def test_segmentation__physical(self, mock_isinstance):
                == self.mock_can_segmenter._CanSegmenter__physical_segmentation.return_value
         self.mock_can_segmenter._CanSegmenter__physical_segmentation.assert_called_once_with(mock_message)
 
-    # is_complete_packets_sequence
-
-    @pytest.mark.parametrize("packets", ["some packets", range(4)])
-    def test_is_complete_packets_sequence__value_error(self, packets):
-        self.mock_can_segmenter.is_supported_packets_sequence.return_value = False
-        with pytest.raises(ValueError):
-            CanSegmenter.is_complete_packets_sequence(self=self.mock_can_segmenter, packets=packets)
-        self.mock_can_segmenter.is_supported_packets_sequence.assert_called_once_with(packets)
-
-    @pytest.mark.parametrize("packets", [
-        [Mock()],
-        (Mock(), Mock(), Mock()),
-    ])
-    def test_is_complete_packets_sequence__not_implemented_error(self, packets):
-        self.mock_can_segmenter.is_supported_packets_sequence.return_value = True
-        self.mock_is_initial_packet_type.return_value = True
-        with pytest.raises(NotImplementedError):
-            CanSegmenter.is_complete_packets_sequence(self=self.mock_can_segmenter, packets=packets)
-        self.mock_can_segmenter.is_supported_packets_sequence.assert_called_once_with(packets)
-        self.mock_is_initial_packet_type.assert_called_once_with(packets[0].packet_type)
-
-    @pytest.mark.parametrize("packets", [
-        [Mock()],
-        (Mock(), Mock(), Mock()),
-    ])
-    def test_is_complete_packets_sequence__false__not_initial_packet(self, packets):
-        self.mock_can_segmenter.is_supported_packets_sequence.return_value = True
-        self.mock_is_initial_packet_type.return_value = False
-        assert CanSegmenter.is_complete_packets_sequence(self=self.mock_can_segmenter, packets=packets) is False
-        self.mock_can_segmenter.is_supported_packets_sequence.assert_called_once_with(packets)
-        self.mock_is_initial_packet_type.assert_called_once_with(packets[0].packet_type)
-
-    @pytest.mark.parametrize("packets", [
-        [Mock(packet_type=CanPacketType.SINGLE_FRAME)],
-        [Mock(packet_type=CanPacketType.SINGLE_FRAME), Mock()],
-        (Mock(packet_type=CanPacketType.SINGLE_FRAME), Mock(), Mock()),
-    ])
-    def test_is_complete_packets_sequence__single_frame(self, packets):
-        self.mock_can_segmenter.is_supported_packets_sequence.return_value = True
-        self.mock_is_initial_packet_type.return_value = True
-        assert CanSegmenter.is_complete_packets_sequence(self=self.mock_can_segmenter, packets=packets) \
-               is (len(packets) == 1)
-        self.mock_can_segmenter.is_supported_packets_sequence.assert_called_once_with(packets)
-        self.mock_is_initial_packet_type.assert_called_once_with(packets[0].packet_type)
-
-    @pytest.mark.parametrize("packets", [
-        [Mock(packet_type=CanPacketType.FIRST_FRAME, payload=[]), Mock()],
-        (Mock(packet_type=CanPacketType.FIRST_FRAME, payload=range(5)), Mock(), Mock()),
-    ])
-    def test_is_complete_packets_sequence__first_frame__multiple_initial_packets(self, packets):
-        self.mock_can_segmenter.is_supported_packets_sequence.return_value = True
-        self.mock_is_initial_packet_type.return_value = True
-        assert CanSegmenter.is_complete_packets_sequence(self=self.mock_can_segmenter, packets=packets) is False
-        self.mock_can_segmenter.is_supported_packets_sequence.assert_called_once_with(packets)
-        self.mock_is_initial_packet_type.assert_has_calls(
-            [call(packets[0].packet_type), call(packets[1].packet_type)])
-
-    @pytest.mark.parametrize("packets", [
-        [Mock(packet_type=CanPacketType.FIRST_FRAME, data_length=11, payload=range(4)), Mock(payload=range(6))],
-        (Mock(packet_type=CanPacketType.FIRST_FRAME, data_length=143, payload=[0xFF] * 10), Mock(payload=None),
-         Mock(payload=range(50, 100)), Mock(payload=range(150, 200))),
-    ])
-    def test_is_complete_packets_sequence__first_frame__too_little_packets(self, packets):
-        self.mock_can_segmenter.is_supported_packets_sequence.return_value = True
-        self.mock_is_initial_packet_type.side_effect = [True] + (len(packets) - 1) * [False]
-        assert CanSegmenter.is_complete_packets_sequence(self=self.mock_can_segmenter, packets=packets) is False
-        self.mock_can_segmenter.is_supported_packets_sequence.assert_called_once_with(packets)
-        self.mock_is_initial_packet_type.assert_has_calls(
-            [call(packet.packet_type) for packet in packets])
-
-    @pytest.mark.parametrize("packets", [
-        [Mock(packet_type=CanPacketType.FIRST_FRAME, data_length=10, payload=range(4)), Mock(payload=range(6)),
-         Mock(payload=None)],
-        (Mock(packet_type=CanPacketType.FIRST_FRAME, data_length=54, payload=[0xFF] * 10), Mock(payload=None),
-         Mock(payload=range(50, 100)), Mock(payload=range(150, 200))),
-    ])
-    def test_is_complete_packets_sequence__first_frame__too_many_packets(self, packets):
-        self.mock_can_segmenter.is_supported_packets_sequence.return_value = True
-        self.mock_is_initial_packet_type.side_effect = [True] + (len(packets) - 1) * [False]
-        assert CanSegmenter.is_complete_packets_sequence(self=self.mock_can_segmenter, packets=packets) is False
-        self.mock_can_segmenter.is_supported_packets_sequence.assert_called_once_with(packets)
-        self.mock_is_initial_packet_type.assert_has_calls(
-            [call(packet.packet_type) for packet in packets])
-
-    @pytest.mark.parametrize("packets", [
-        [Mock(packet_type=CanPacketType.FIRST_FRAME, data_length=11, payload=range(4)), Mock(payload=range(7))],
-        (Mock(packet_type=CanPacketType.FIRST_FRAME, data_length=100, payload=[0xFF] * 10), Mock(payload=None),
-         Mock(payload=range(50, 100)), Mock(payload=range(150, 200))),
-    ])
-    def test_is_complete_packets_sequence__first_frame__true(self, packets):
-        self.mock_can_segmenter.is_supported_packets_sequence.return_value = True
-        self.mock_is_initial_packet_type.side_effect = [True] + (len(packets) - 1) * [False]
-        assert CanSegmenter.is_complete_packets_sequence(self=self.mock_can_segmenter, packets=packets) is True
-        self.mock_can_segmenter.is_supported_packets_sequence.assert_called_once_with(packets)
-        self.mock_is_initial_packet_type.assert_has_calls(
-            [call(packet.packet_type) for packet in packets])
-
     # __physical_segmentation
 
     @pytest.mark.parametrize("message_payload_size", [CanFirstFrameHandler.MAX_LONG_FF_DL_VALUE + 1,
@@ -438,7 +477,7 @@ def test_physical_segmentation__sf_with_data_optimization(self, mock_len,
         mock_len.return_value = message_payload_size
         self.mock_get_max_sf_payload_size.return_value = max_payload
         self.mock_can_segmenter.use_data_optimization = True
-        self.mock_can_segmenter.physical_ai = physical_ai
+        self.mock_can_segmenter.tx_packets_physical_ai = physical_ai
         mock_message = Mock(spec=UdsMessage, addressing_type=AddressingType.PHYSICAL)
         packets = CanSegmenter._CanSegmenter__physical_segmentation(self=self.mock_can_segmenter,
                                                                     message=mock_message)
@@ -466,7 +505,7 @@ def test_physical_segmentation__sf_without_data_optimization(self, mock_len,
         mock_len.return_value = message_payload_size
         self.mock_get_max_sf_payload_size.return_value = max_payload
         self.mock_can_segmenter.use_data_optimization = False
-        self.mock_can_segmenter.physical_ai = physical_ai
+        self.mock_can_segmenter.tx_packets_physical_ai = physical_ai
         mock_message = Mock(spec=UdsMessage, addressing_type=AddressingType.PHYSICAL)
         packets = CanSegmenter._CanSegmenter__physical_segmentation(self=self.mock_can_segmenter,
                                                                     message=mock_message)
@@ -496,7 +535,7 @@ def test_physical_segmentation__ff_cf_with_data_optimization(self, mock_len, phy
         self.mock_get_ff_payload_size.return_value = ff_size
         self.mock_get_max_cf_payload_size.return_value = cf_size
         self.mock_can_segmenter.use_data_optimization = True
-        self.mock_can_segmenter.physical_ai = physical_ai
+        self.mock_can_segmenter.tx_packets_physical_ai = physical_ai
         mock_message = Mock(spec=UdsMessage, addressing_type=AddressingType.PHYSICAL,
                             payload=range(message_payload_size))
         packets = CanSegmenter._CanSegmenter__physical_segmentation(self=self.mock_can_segmenter,
@@ -562,7 +601,7 @@ def test_functional_segmentation__with_data_optimization(self, mock_len, message
         mock_len.return_value = message_payload_size
         self.mock_get_max_sf_payload_size.return_value = max_payload
         self.mock_can_segmenter.use_data_optimization = True
-        self.mock_can_segmenter.functional_ai = functional_ai
+        self.mock_can_segmenter.tx_packets_functional_ai = functional_ai
         mock_message = Mock(spec=UdsMessage, addressing_type=AddressingType.FUNCTIONAL)
         packets = CanSegmenter._CanSegmenter__functional_segmentation(self=self.mock_can_segmenter,
                                                                       message=mock_message)
@@ -589,7 +628,7 @@ def test_functional_segmentation__without_data_optimization(self, mock_len, mess
         mock_len.return_value = message_payload_size
         self.mock_get_max_sf_payload_size.return_value = max_payload
         self.mock_can_segmenter.use_data_optimization = False
-        self.mock_can_segmenter.functional_ai = functional_ai
+        self.mock_can_segmenter.tx_packets_functional_ai = functional_ai
         mock_message = Mock(spec=UdsMessage, addressing_type=AddressingType.FUNCTIONAL)
         packets = CanSegmenter._CanSegmenter__functional_segmentation(self=self.mock_can_segmenter,
                                                                       message=mock_message)
@@ -610,6 +649,84 @@ def test_functional_segmentation__without_data_optimization(self, mock_len, mess
 class TestCanSegmenterIntegration:
     """Integration tests for `CanSegmenter` class."""
 
+    @pytest.mark.parametrize("addressing_information, frame_can_id, frame_data", [
+        (Normal11BitCanAddressingInformation(rx_physical={"can_id": 0x611},
+                                             tx_physical={"can_id": 0x612},
+                                             rx_functional={"can_id": 0x6FE},
+                                             tx_functional={"can_id": 0x6FF}), 0x611, [0x10, 0x01]),
+        (NormalFixedCanAddressingInformation(rx_physical={"can_id": 0x18DA1234, "target_address": 0x12, "source_address": 0x34},
+                                             tx_physical={"can_id": 0x18DA3412, "target_address": 0x34, "source_address": 0x12},
+                                             rx_functional={"can_id": 0x18DBF0E1, "target_address": 0xF0, "source_address": 0xE1},
+                                             tx_functional={"can_id": 0x18DBE1F0}), 0x18DA1234, [0xAB, 0xCD, 0x12, 0xF5]),
+        (ExtendedCanAddressingInformation(rx_physical={"can_id": 0x1234, "target_address": 0xF0},
+                                          tx_physical={"can_id": 0x1234, "target_address": 0xE2,},
+                                          rx_functional={"can_id": 0xFEDCBA, "target_address": 0xBB},
+                                          tx_functional={"can_id": 0xFEDCBA, "target_address": 0x12}), 0x1234, [0xF0, *range(63)]),
+        (Mixed11BitCanAddressingInformation(rx_physical={"can_id": 0x645, "address_extension": 0x01},
+                                            tx_physical={"can_id": 0x646, "address_extension": 0xFE},
+                                            rx_functional={"can_id": 0x6DE, "address_extension": 0x05},
+                                            tx_functional={"can_id": 0x6DF, "address_extension": 0xFF}), 0x645, [0x01, 0x3E]),
+        (Mixed29BitCanAddressingInformation(rx_physical={"can_id": 0x18CEC2D0, "address_extension": 0x52, "target_address": 0xC2, "source_address": 0xD0},
+                                            tx_physical={"can_id": 0x18CED0C2, "address_extension": 0xD8, "target_address": 0xD0, "source_address": 0xC2},
+                                            rx_functional={"can_id": 0x18CD7186, "address_extension": 0x05, "target_address": 0x71, "source_address": 0x86},
+                                            tx_functional={"can_id": 0x18CD8671, "address_extension": 0xFF}), 0x18CEC2D0, [0x52, 0x3E]),
+    ])
+    def test_is_input_packet__physical(self, addressing_information, frame_can_id, frame_data):
+        can_segmenter = CanSegmenter(addressing_information=addressing_information)
+        assert can_segmenter.is_input_packet(can_id=frame_can_id, data=frame_data) is AddressingType.PHYSICAL
+
+    @pytest.mark.parametrize("addressing_information, frame_can_id, frame_data", [
+        (Normal11BitCanAddressingInformation(rx_physical={"can_id": 0x611},
+                                             tx_physical={"can_id": 0x612},
+                                             rx_functional={"can_id": 0x6FE},
+                                             tx_functional={"can_id": 0x6FF}), 0x6FE, [0x10, 0x01]),
+        (NormalFixedCanAddressingInformation(rx_physical={"can_id": 0x18DA1234, "target_address": 0x12, "source_address": 0x34},
+                                             tx_physical={"can_id": 0x18DA3412, "target_address": 0x34, "source_address": 0x12},
+                                             rx_functional={"can_id": 0x18DBF0E1, "target_address": 0xF0, "source_address": 0xE1},
+                                             tx_functional={"can_id": 0x18DBE1F0}), 0x18DBF0E1, [0xAB, 0xCD, 0x12, 0xF5]),
+        (ExtendedCanAddressingInformation(rx_physical={"can_id": 0x1234, "target_address": 0xF0},
+                                          tx_physical={"can_id": 0x1234, "target_address": 0xE2,},
+                                          rx_functional={"can_id": 0xFEDCBA, "target_address": 0xBB},
+                                          tx_functional={"can_id": 0xFEDCBA, "target_address": 0x12}), 0xFEDCBA, [0xBB, *range(63)]),
+        (Mixed11BitCanAddressingInformation(rx_physical={"can_id": 0x645, "address_extension": 0x01},
+                                            tx_physical={"can_id": 0x646, "address_extension": 0xFE},
+                                            rx_functional={"can_id": 0x6DE, "address_extension": 0x05},
+                                            tx_functional={"can_id": 0x6DF, "address_extension": 0xFF}), 0x6DE, [0x05, 0x3E]),
+        (Mixed29BitCanAddressingInformation(rx_physical={"can_id": 0x18CEC2D0, "address_extension": 0x52, "target_address": 0xC2, "source_address": 0xD0},
+                                            tx_physical={"can_id": 0x18CED0C2, "address_extension": 0xD8, "target_address": 0xD0, "source_address": 0xC2},
+                                            rx_functional={"can_id": 0x18CD7186, "address_extension": 0x05, "target_address": 0x71, "source_address": 0x86},
+                                            tx_functional={"can_id": 0x18CD8671, "address_extension": 0xFF}), 0x18CD7186, [0x05, 0x3E]),
+    ])
+    def test_is_input_packet__functional(self, addressing_information, frame_can_id, frame_data):
+        can_segmenter = CanSegmenter(addressing_information=addressing_information)
+        assert can_segmenter.is_input_packet(can_id=frame_can_id, data=frame_data) is AddressingType.FUNCTIONAL
+
+    @pytest.mark.parametrize("addressing_information, frame_can_id, frame_data", [
+        (Normal11BitCanAddressingInformation(rx_physical={"can_id": 0x611},
+                                             tx_physical={"can_id": 0x612},
+                                             rx_functional={"can_id": 0x6FE},
+                                             tx_functional={"can_id": 0x6FF}), 0x6FF, [0x10, 0x01]),
+        (NormalFixedCanAddressingInformation(rx_physical={"can_id": 0x18DA1234, "target_address": 0x12, "source_address": 0x34},
+                                             tx_physical={"can_id": 0x18DA3412, "target_address": 0x34, "source_address": 0x12},
+                                             rx_functional={"can_id": 0x18DBF0E1, "target_address": 0xF0, "source_address": 0xE1},
+                                             tx_functional={"can_id": 0x18DBE1F0}), 0x18DA3412, [0xAB, 0xCD, 0x12, 0xF5]),
+        (ExtendedCanAddressingInformation(rx_physical={"can_id": 0x1234, "target_address": 0xF0},
+                                          tx_physical={"can_id": 0x1234, "target_address": 0xE2,},
+                                          rx_functional={"can_id": 0xFEDCBA, "target_address": 0xBB},
+                                          tx_functional={"can_id": 0xFEDCBA, "target_address": 0x12}), 0xFEDCBA, [0xF0, *range(63)]),
+        (Mixed11BitCanAddressingInformation(rx_physical={"can_id": 0x645, "address_extension": 0x01},
+                                            tx_physical={"can_id": 0x646, "address_extension": 0xFE},
+                                            rx_functional={"can_id": 0x6DE, "address_extension": 0x05},
+                                            tx_functional={"can_id": 0x6DF, "address_extension": 0xFF}), 0x646, [0xFE, 0x3E]),
+        (Mixed29BitCanAddressingInformation(rx_physical={"can_id": 0x18CEC2D0, "address_extension": 0x52, "target_address": 0xC2, "source_address": 0xD0},
+                                            tx_physical={"can_id": 0x18CED0C2, "address_extension": 0xD8, "target_address": 0xD0, "source_address": 0xC2},
+                                            rx_functional={"can_id": 0x18CD7186, "address_extension": 0x05, "target_address": 0x71, "source_address": 0x86},
+                                            tx_functional={"can_id": 0x18CD8671, "address_extension": 0xFF}), 0x18CD7186, [0x52, 0x3E]),
+    ])
+    def test_is_input_packet__false(self, addressing_information, frame_can_id, frame_data):
+        can_segmenter = CanSegmenter(addressing_information=addressing_information)
+        assert can_segmenter.is_input_packet(can_id=frame_can_id, data=frame_data) is None
+
     @pytest.mark.parametrize("uds_message", [
         UdsMessage(payload=bytearray([0x54]), addressing_type=AddressingType.PHYSICAL),
         UdsMessage(payload=(0x3E, 0x00), addressing_type=AddressingType.FUNCTIONAL),
diff --git a/tests/software_tests/transport_interface/test_abstract_can_transport_interface.py b/tests/software_tests/transport_interface/test_abstract_can_transport_interface.py
deleted file mode 100644
index 6a100b34..00000000
--- a/tests/software_tests/transport_interface/test_abstract_can_transport_interface.py
+++ /dev/null
@@ -1,622 +0,0 @@
-import pytest
-from mock import MagicMock, Mock, patch
-
-from uds.transport_interface.abstract_can_transport_interface import AbstractCanTransportInterface, \
-    AbstractTransportInterface, AbstractCanAddressingInformation, CanPacket, CanPacketRecord, Iterable
-
-
-class TestAbstractCanTransportInterface:
-    """Unit tests for `AbstractCanTransportInterface` class."""
-
-    SCRIPT_LOCATION = "uds.transport_interface.abstract_can_transport_interface"
-
-    def setup(self):
-        self.mock_can_transport_interface = Mock(spec=AbstractCanTransportInterface,
-                                                 DEFAULT_FLOW_CONTROL_ARGS=AbstractCanTransportInterface.DEFAULT_FLOW_CONTROL_ARGS)
-        # patching
-        self._patcher_abstract_transport_interface_init \
-            = patch(f"{self.SCRIPT_LOCATION}.AbstractTransportInterface.__init__")
-        self.mock_abstract_transport_interface_init = self._patcher_abstract_transport_interface_init.start()
-        self._patcher_records_queue_class = patch(f"{self.SCRIPT_LOCATION}.RecordsQueue")
-        self.mock_records_queue_class = self._patcher_records_queue_class.start()
-        self._patcher_transmission_queue_class = patch(f"{self.SCRIPT_LOCATION}.TransmissionQueue")
-        self.mock_transmission_queue_class = self._patcher_transmission_queue_class.start()
-        self._patcher_can_segmenter_class = patch(f"{self.SCRIPT_LOCATION}.CanSegmenter")
-        self.mock_can_segmenter_class = self._patcher_can_segmenter_class.start()
-        self._patcher_can_packet_class = patch(f"{self.SCRIPT_LOCATION}.CanPacket")
-        self.mock_can_packet_class = self._patcher_can_packet_class.start()
-        self._patcher_warn = patch(f"{self.SCRIPT_LOCATION}.warn")
-        self.mock_warn = self._patcher_warn.start()
-
-    def teardown(self):
-        self._patcher_abstract_transport_interface_init.stop()
-        self._patcher_records_queue_class.stop()
-        self._patcher_transmission_queue_class.stop()
-        self._patcher_can_segmenter_class.stop()
-        self._patcher_can_packet_class.stop()
-        self._patcher_warn.stop()
-
-    # __init__
-
-    @pytest.mark.parametrize("can_bus_manager, addressing_information", [
-        ("can_bus_manager", "addressing_information"),
-        (Mock(), Mock()),
-    ])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_init__type_error(self, mock_isinstance,
-                              can_bus_manager, addressing_information):
-        mock_isinstance.return_value = False
-        with pytest.raises(TypeError):
-            AbstractCanTransportInterface.__init__(self=self.mock_can_transport_interface,
-                                                   can_bus_manager=can_bus_manager,
-                                                   addressing_information=addressing_information)
-        mock_isinstance.assert_called_once_with(addressing_information, AbstractCanAddressingInformation)
-
-    @pytest.mark.parametrize("can_bus_manager, addressing_information", [
-        ("can_bus_manager", Mock(tx_packets_physical_ai={"addressing_format": Mock(),
-                                                         "addressing_type": Mock()})),
-        (Mock(), Mock(tx_packets_physical_ai={"arg1": 1, "arg2": 2})),
-    ])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_init__valid_mandatory_args(self, mock_isinstance,
-                                        can_bus_manager, addressing_information):
-        mock_isinstance.return_value = True
-        AbstractCanTransportInterface.__init__(self=self.mock_can_transport_interface,
-                                               can_bus_manager=can_bus_manager,
-                                               addressing_information=addressing_information)
-        mock_isinstance.assert_called_once_with(addressing_information, AbstractCanAddressingInformation)
-        self.mock_abstract_transport_interface_init.assert_called_once_with(
-            bus_manager=can_bus_manager,
-            message_records_number=AbstractTransportInterface.DEFAULT_MESSAGE_RECORDS_NUMBER)
-        self.mock_can_segmenter_class.assert_called_once_with(
-            addressing_format=addressing_information.addressing_format,
-            physical_ai=addressing_information.tx_packets_physical_ai,
-            functional_ai=addressing_information.tx_packets_functional_ai)
-        self.mock_records_queue_class.assert_called_once_with(
-            records_type=CanPacketRecord,
-            history_size=AbstractTransportInterface.DEFAULT_PACKET_RECORDS_NUMBER)
-        self.mock_transmission_queue_class.assert_called_once_with(pdu_type=self.mock_can_packet_class)
-        self.mock_can_packet_class.assert_called_once_with(
-            dlc=None if self.mock_can_transport_interface.use_data_optimization else self.mock_can_transport_interface.dlc,
-            filler_byte=self.mock_can_transport_interface.filler_byte,
-            **addressing_information.tx_packets_physical_ai,
-            **self.mock_can_transport_interface.DEFAULT_FLOW_CONTROL_ARGS)
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__addressing_information \
-               == addressing_information
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__segmenter \
-               == self.mock_can_segmenter_class.return_value
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__packet_records_queue \
-               == self.mock_records_queue_class.return_value
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__packet_transmission_queue \
-               == self.mock_transmission_queue_class.return_value
-        assert self.mock_can_transport_interface.flow_control_generator == self.mock_can_packet_class.return_value
-        assert self.mock_can_transport_interface.n_as_timeout == self.mock_can_transport_interface.N_AS_TIMEOUT
-        assert self.mock_can_transport_interface.n_ar_timeout == self.mock_can_transport_interface.N_AR_TIMEOUT
-        assert self.mock_can_transport_interface.n_bs_timeout == self.mock_can_transport_interface.N_BS_TIMEOUT
-        assert self.mock_can_transport_interface.n_br == self.mock_can_transport_interface.DEFAULT_N_BR
-        assert self.mock_can_transport_interface.n_cs == self.mock_can_transport_interface.DEFAULT_N_CS
-        assert self.mock_can_transport_interface.n_cr_timeout == self.mock_can_transport_interface.N_CR_TIMEOUT
-
-    @pytest.mark.parametrize("can_bus_manager, addressing_information", [
-        ("can_bus_manager", Mock(tx_packets_physical_ai={"addressing_format": Mock(),
-                                                         "addressing_type": Mock()})),
-        (Mock(), Mock(tx_packets_physical_ai={"arg1": 1, "arg2": 2})),
-    ])
-    @pytest.mark.parametrize("n_as_timeout, n_ar_timeout, n_bs_timeout, n_br, n_cs, n_cr_timeout, "
-                             "dlc, use_data_optimization, filler_byte, flow_control_generator, "
-                             "packet_records_number, message_records_number", [
-        ("n_as_timeout", "n_ar_timeout", "n_bs_timeout", "n_br", "n_cs", "n_cr_timeout", "dlc", "use_data_optimization",
-         "filler_byte", "flow_control_generator", "packet_records_number", "message_records_number"),
-        (Mock(), Mock(), Mock(), Mock(), Mock(), Mock(), Mock(), Mock(), Mock(), Mock(), Mock(), Mock()),
-    ])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_init__valid_all_args(self, mock_isinstance,
-                                  can_bus_manager, addressing_information,
-                                  n_as_timeout, n_ar_timeout, n_bs_timeout, n_br, n_cs, n_cr_timeout,
-                                  dlc, use_data_optimization, filler_byte, flow_control_generator,
-                                  packet_records_number, message_records_number):
-        mock_isinstance.return_value = True
-        AbstractCanTransportInterface.__init__(self=self.mock_can_transport_interface,
-                                               can_bus_manager=can_bus_manager,
-                                               packet_records_number=packet_records_number,
-                                               message_records_number=message_records_number,
-                                               addressing_information=addressing_information,
-                                               n_as_timeout=n_as_timeout,
-                                               n_ar_timeout=n_ar_timeout,
-                                               n_bs_timeout=n_bs_timeout,
-                                               n_br=n_br,
-                                               n_cs=n_cs,
-                                               n_cr_timeout=n_cr_timeout,
-                                               dlc=dlc,
-                                               use_data_optimization=use_data_optimization,
-                                               filler_byte=filler_byte,
-                                               flow_control_generator=flow_control_generator)
-        mock_isinstance.assert_called_once_with(addressing_information, AbstractCanAddressingInformation)
-        self.mock_abstract_transport_interface_init.assert_called_once_with(
-            bus_manager=can_bus_manager,
-            message_records_number=message_records_number)
-        self.mock_can_segmenter_class.assert_called_once_with(
-            addressing_format=addressing_information.addressing_format,
-            physical_ai=addressing_information.tx_packets_physical_ai,
-            functional_ai=addressing_information.tx_packets_functional_ai,
-            dlc=dlc,
-            use_data_optimization=use_data_optimization,
-            filler_byte=filler_byte)
-        self.mock_records_queue_class.assert_called_once_with(records_type=CanPacketRecord,
-                                                              history_size=packet_records_number)
-        self.mock_transmission_queue_class.assert_called_once_with(pdu_type=self.mock_can_packet_class)
-        self.mock_can_packet_class.assert_not_called()
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__addressing_information \
-               == addressing_information
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__segmenter \
-               == self.mock_can_segmenter_class.return_value
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__packet_records_queue \
-               == self.mock_records_queue_class.return_value
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__packet_transmission_queue \
-               == self.mock_transmission_queue_class.return_value
-        assert self.mock_can_transport_interface.flow_control_generator == flow_control_generator
-        assert self.mock_can_transport_interface.n_as_timeout == n_as_timeout
-        assert self.mock_can_transport_interface.n_ar_timeout == n_ar_timeout
-        assert self.mock_can_transport_interface.n_bs_timeout == n_bs_timeout
-        assert self.mock_can_transport_interface.n_br == n_br
-        assert self.mock_can_transport_interface.n_cs == n_cs
-        assert self.mock_can_transport_interface.n_cr_timeout == n_cr_timeout
-
-    # _packet_records_queue
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_packet_records_queue__get(self, value):
-        self.mock_can_transport_interface._AbstractCanTransportInterface__packet_records_queue = value
-        assert AbstractCanTransportInterface._packet_records_queue.fget(self.mock_can_transport_interface) == value
-
-    # _packet_transmission_queue
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_packet_transmission_queue__get(self, value):
-        self.mock_can_transport_interface._AbstractCanTransportInterface__packet_transmission_queue = value
-        assert AbstractCanTransportInterface._packet_transmission_queue.fget(self.mock_can_transport_interface) == value
-
-    # segmenter
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_segmenter(self, value):
-        self.mock_can_transport_interface._AbstractCanTransportInterface__segmenter = value
-        assert AbstractCanTransportInterface.segmenter.fget(self.mock_can_transport_interface) \
-               == self.mock_can_transport_interface._AbstractCanTransportInterface__segmenter
-
-    # n_as
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_n_as_timeout__get(self, value):
-        self.mock_can_transport_interface._AbstractCanTransportInterface__n_as_timeout = value
-        assert AbstractCanTransportInterface.n_as_timeout.fget(self.mock_can_transport_interface) == value
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_as_timeout__set__type_error(self, mock_isinstance, value):
-        mock_isinstance.return_value = False
-        with pytest.raises(TypeError):
-            AbstractCanTransportInterface.n_as_timeout.fset(self.mock_can_transport_interface, value)
-        mock_isinstance.assert_called_once_with(value, (int, float))
-
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_as_timeout__set__value_error(self, mock_isinstance):
-        mock_isinstance.return_value = True
-        mock_le = Mock(return_value=True)
-        mock_value = MagicMock(__le__=mock_le)
-        with pytest.raises(ValueError):
-            AbstractCanTransportInterface.n_as_timeout.fset(self.mock_can_transport_interface, mock_value)
-        mock_isinstance.assert_called_once_with(mock_value, (int, float))
-        mock_le.assert_called_once_with(0)
-
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_as_timeout__set__valid_with_warn(self, mock_isinstance):
-        mock_isinstance.return_value = True
-        mock_le = Mock(return_value=False)
-        mock_ne = Mock(return_value=True)
-        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
-        AbstractCanTransportInterface.n_as_timeout.fset(self.mock_can_transport_interface, mock_value)
-        mock_isinstance.assert_called_once_with(mock_value, (int, float))
-        mock_le.assert_called_once_with(0)
-        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_AS_TIMEOUT)
-        self.mock_warn.assert_called_once()
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_as_timeout == mock_value
-
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_as_timeout__set__valid_without_warn(self, mock_isinstance):
-        mock_isinstance.return_value = True
-        mock_le = Mock(return_value=False)
-        mock_ne = Mock(return_value=False)
-        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
-        AbstractCanTransportInterface.n_as_timeout.fset(self.mock_can_transport_interface, mock_value)
-        mock_isinstance.assert_called_once_with(mock_value, (int, float))
-        mock_le.assert_called_once_with(0)
-        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_AS_TIMEOUT)
-        self.mock_warn.assert_not_called()
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_as_timeout == mock_value
-
-    # n_ar
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_n_ar_timeout__get(self, value):
-        self.mock_can_transport_interface._AbstractCanTransportInterface__n_ar_timeout = value
-        assert AbstractCanTransportInterface.n_ar_timeout.fget(self.mock_can_transport_interface) == value
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_ar_timeout__set__type_error(self, mock_isinstance, value):
-        mock_isinstance.return_value = False
-        with pytest.raises(TypeError):
-            AbstractCanTransportInterface.n_ar_timeout.fset(self.mock_can_transport_interface, value)
-        mock_isinstance.assert_called_once_with(value, (int, float))
-
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_ar_timeout__set__value_error(self, mock_isinstance):
-        mock_isinstance.return_value = True
-        mock_le = Mock(return_value=True)
-        mock_value = MagicMock(__le__=mock_le)
-        with pytest.raises(ValueError):
-            AbstractCanTransportInterface.n_ar_timeout.fset(self.mock_can_transport_interface, mock_value)
-        mock_isinstance.assert_called_once_with(mock_value, (int, float))
-        mock_le.assert_called_once_with(0)
-
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_ar_timeout__set__valid_with_warn(self, mock_isinstance):
-        mock_isinstance.return_value = True
-        mock_le = Mock(return_value=False)
-        mock_ne = Mock(return_value=True)
-        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
-        AbstractCanTransportInterface.n_ar_timeout.fset(self.mock_can_transport_interface, mock_value)
-        mock_isinstance.assert_called_once_with(mock_value, (int, float))
-        mock_le.assert_called_once_with(0)
-        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_AR_TIMEOUT)
-        self.mock_warn.assert_called_once()
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_ar_timeout == mock_value
-
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_ar_timeout__set__valid_without_warn(self, mock_isinstance):
-        mock_isinstance.return_value = True
-        mock_le = Mock(return_value=False)
-        mock_ne = Mock(return_value=False)
-        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
-        AbstractCanTransportInterface.n_ar_timeout.fset(self.mock_can_transport_interface, mock_value)
-        mock_isinstance.assert_called_once_with(mock_value, (int, float))
-        mock_le.assert_called_once_with(0)
-        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_AR_TIMEOUT)
-        self.mock_warn.assert_not_called()
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_ar_timeout == mock_value
-            
-    # n_bs
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_n_bs_timeout__get(self, value):
-        self.mock_can_transport_interface._AbstractCanTransportInterface__n_bs_timeout = value
-        assert AbstractCanTransportInterface.n_bs_timeout.fget(self.mock_can_transport_interface) == value
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_bs_timeout__set__type_error(self, mock_isinstance, value):
-        mock_isinstance.return_value = False
-        with pytest.raises(TypeError):
-            AbstractCanTransportInterface.n_bs_timeout.fset(self.mock_can_transport_interface, value)
-        mock_isinstance.assert_called_once_with(value, (int, float))
-
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_bs_timeout__set__value_error(self, mock_isinstance):
-        mock_isinstance.return_value = True
-        mock_le = Mock(return_value=True)
-        mock_value = MagicMock(__le__=mock_le)
-        with pytest.raises(ValueError):
-            AbstractCanTransportInterface.n_bs_timeout.fset(self.mock_can_transport_interface, mock_value)
-        mock_isinstance.assert_called_once_with(mock_value, (int, float))
-        mock_le.assert_called_once_with(0)
-
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_bs_timeout__set__valid_with_warn(self, mock_isinstance):
-        mock_isinstance.return_value = True
-        mock_le = Mock(return_value=False)
-        mock_ne = Mock(return_value=True)
-        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
-        AbstractCanTransportInterface.n_bs_timeout.fset(self.mock_can_transport_interface, mock_value)
-        mock_isinstance.assert_called_once_with(mock_value, (int, float))
-        mock_le.assert_called_once_with(0)
-        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_BS_TIMEOUT)
-        self.mock_warn.assert_called_once()
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_bs_timeout == mock_value
-
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_bs_timeout__set__valid_without_warn(self, mock_isinstance):
-        mock_isinstance.return_value = True
-        mock_le = Mock(return_value=False)
-        mock_ne = Mock(return_value=False)
-        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
-        AbstractCanTransportInterface.n_bs_timeout.fset(self.mock_can_transport_interface, mock_value)
-        mock_isinstance.assert_called_once_with(mock_value, (int, float))
-        mock_le.assert_called_once_with(0)
-        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_BS_TIMEOUT)
-        self.mock_warn.assert_not_called()
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_bs_timeout == mock_value
-            
-    # n_br
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_n_br__get(self, value):
-        self.mock_can_transport_interface._AbstractCanTransportInterface__n_br = value
-        assert AbstractCanTransportInterface.n_br.fget(self.mock_can_transport_interface) == value
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_br__set__type_error(self, mock_isinstance, value):
-        mock_isinstance.return_value = False
-        with pytest.raises(TypeError):
-            AbstractCanTransportInterface.n_br.fset(self.mock_can_transport_interface, value)
-        mock_isinstance.assert_called_once_with(value, (int, float))
-
-    @pytest.mark.parametrize("value, max_value", [
-        (-0.00000001, 100),
-        (-1, 900),
-        (901, 900.5),
-        (450.1, 450),
-    ])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_br__set__value_error(self, mock_isinstance, value, max_value):
-        mock_isinstance.return_value = True
-        self.mock_can_transport_interface.n_br_max = max_value
-        with pytest.raises(ValueError):
-            AbstractCanTransportInterface.n_br.fset(self.mock_can_transport_interface, value)
-        mock_isinstance.assert_called_once_with(value, (int, float))
-
-    @pytest.mark.parametrize("value, max_value", [
-        (99, 100),
-        (899.99, 900),
-        (45.59, 900.5),
-        (0, 450),
-    ])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_br__set__valid(self, mock_isinstance, value, max_value):
-        mock_isinstance.return_value = True
-        self.mock_can_transport_interface.n_br_max = max_value
-        AbstractCanTransportInterface.n_br.fset(self.mock_can_transport_interface, value)
-        mock_isinstance.assert_called_once_with(value, (int, float))
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_br == value
-
-    @pytest.mark.parametrize("n_bs_timeout, n_ar_measured", [
-        (1000, 10),
-        (965.43, 12.45),
-    ])
-    def test_n_br_max__n_ar_measured(self, n_bs_timeout, n_ar_measured):
-        self.mock_can_transport_interface.n_bs_timeout = n_bs_timeout
-        self.mock_can_transport_interface.n_ar_measured = n_ar_measured
-        assert AbstractCanTransportInterface.n_br_max.fget(self.mock_can_transport_interface) \
-               == 0.9 * n_bs_timeout - n_ar_measured
-
-    @pytest.mark.parametrize("n_bs_timeout", [1000, 965.43])
-    def test_n_br_max__n_ar_not_measured(self, n_bs_timeout):
-        self.mock_can_transport_interface.n_bs_timeout = n_bs_timeout
-        self.mock_can_transport_interface.n_ar_measured = None
-        assert AbstractCanTransportInterface.n_br_max.fget(self.mock_can_transport_interface) \
-               == 0.9 * n_bs_timeout
-
-    # n_cs
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_n_cs__get(self, value):
-        self.mock_can_transport_interface._AbstractCanTransportInterface__n_cs = value
-        assert AbstractCanTransportInterface.n_cs.fget(self.mock_can_transport_interface) == value
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_cs__set__type_error(self, mock_isinstance, value):
-        mock_isinstance.return_value = False
-        with pytest.raises(TypeError):
-            AbstractCanTransportInterface.n_cs.fset(self.mock_can_transport_interface, value)
-        mock_isinstance.assert_called_once_with(value, (int, float))
-
-    @pytest.mark.parametrize("value, max_value", [
-        (-0.00000001, 100),
-        (-1, 900),
-        (901, 900.5),
-        (450.1, 450),
-    ])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_cs__set__value_error(self, mock_isinstance, value, max_value):
-        mock_isinstance.return_value = True
-        self.mock_can_transport_interface.n_cs_max = max_value
-        with pytest.raises(ValueError):
-            AbstractCanTransportInterface.n_cs.fset(self.mock_can_transport_interface, value)
-        mock_isinstance.assert_called_once_with(value, (int, float))
-
-    @pytest.mark.parametrize("value, max_value", [
-        (99, 100),
-        (899.99, 900),
-        (45.59, 900.5),
-        (0, 450),
-    ])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_cs__set__valid(self, mock_isinstance, value, max_value):
-        mock_isinstance.return_value = True
-        self.mock_can_transport_interface.n_cs_max = max_value
-        AbstractCanTransportInterface.n_cs.fset(self.mock_can_transport_interface, value)
-        mock_isinstance.assert_called_once_with(value, (int, float))
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_cs == value
-
-    def test_n_cs__set__none(self):
-        AbstractCanTransportInterface.n_cs.fset(self.mock_can_transport_interface, None)
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_cs is None
-
-    @pytest.mark.parametrize("n_cr_timeout, n_as_measured", [
-        (1000, 10),
-        (965.43, 12.45),
-    ])
-    def test_n_cs_max__n_as_measured(self, n_cr_timeout, n_as_measured):
-        self.mock_can_transport_interface.n_cr_timeout = n_cr_timeout
-        self.mock_can_transport_interface.n_as_measured = n_as_measured
-        assert AbstractCanTransportInterface.n_cs_max.fget(self.mock_can_transport_interface) \
-               == 0.9 * n_cr_timeout - n_as_measured
-
-    @pytest.mark.parametrize("n_cr_timeout", [1000, 965.43])
-    def test_n_cs_max__n_as_not_measured(self, n_cr_timeout):
-        self.mock_can_transport_interface.n_cr_timeout = n_cr_timeout
-        self.mock_can_transport_interface.n_as_measured = None
-        assert AbstractCanTransportInterface.n_cs_max.fget(self.mock_can_transport_interface) \
-               == 0.9 * n_cr_timeout
-            
-    # n_cr
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_n_cr_timeout__get(self, value):
-        self.mock_can_transport_interface._AbstractCanTransportInterface__n_cr_timeout = value
-        assert AbstractCanTransportInterface.n_cr_timeout.fget(self.mock_can_transport_interface) == value
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_cr_timeout__set__type_error(self, mock_isinstance, value):
-        mock_isinstance.return_value = False
-        with pytest.raises(TypeError):
-            AbstractCanTransportInterface.n_cr_timeout.fset(self.mock_can_transport_interface, value)
-        mock_isinstance.assert_called_once_with(value, (int, float))
-
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_cr_timeout__set__value_error(self, mock_isinstance):
-        mock_isinstance.return_value = True
-        mock_le = Mock(return_value=True)
-        mock_value = MagicMock(__le__=mock_le)
-        with pytest.raises(ValueError):
-            AbstractCanTransportInterface.n_cr_timeout.fset(self.mock_can_transport_interface, mock_value)
-        mock_isinstance.assert_called_once_with(mock_value, (int, float))
-        mock_le.assert_called_once_with(0)
-
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_cr_timeout__set__valid_with_warn(self, mock_isinstance):
-        mock_isinstance.return_value = True
-        mock_le = Mock(return_value=False)
-        mock_ne = Mock(return_value=True)
-        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
-        AbstractCanTransportInterface.n_cr_timeout.fset(self.mock_can_transport_interface, mock_value)
-        mock_isinstance.assert_called_once_with(mock_value, (int, float))
-        mock_le.assert_called_once_with(0)
-        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_CR_TIMEOUT)
-        self.mock_warn.assert_called_once()
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_cr_timeout == mock_value
-
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_n_cr_timeout__set__valid_without_warn(self, mock_isinstance):
-        mock_isinstance.return_value = True
-        mock_le = Mock(return_value=False)
-        mock_ne = Mock(return_value=False)
-        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
-        AbstractCanTransportInterface.n_cr_timeout.fset(self.mock_can_transport_interface, mock_value)
-        mock_isinstance.assert_called_once_with(mock_value, (int, float))
-        mock_le.assert_called_once_with(0)
-        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_CR_TIMEOUT)
-        self.mock_warn.assert_not_called()
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_cr_timeout == mock_value
-
-    # addressing_information
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_addressing_information(self, value):
-        self.mock_can_transport_interface._AbstractCanTransportInterface__addressing_information = value
-        assert AbstractCanTransportInterface.addressing_information.fget(self.mock_can_transport_interface) \
-               == self.mock_can_transport_interface._AbstractCanTransportInterface__addressing_information
-
-    # dlc
-
-    def test_dlc__get(self):
-        assert AbstractCanTransportInterface.dlc.fget(self.mock_can_transport_interface) \
-               == self.mock_can_transport_interface.segmenter.dlc
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_dlc__set(self, value):
-        AbstractCanTransportInterface.dlc.fset(self.mock_can_transport_interface, value)
-        assert self.mock_can_transport_interface.segmenter.dlc == value
-            
-    # use_data_optimization
-
-    def test_use_data_optimization__get(self):
-        assert AbstractCanTransportInterface.use_data_optimization.fget(self.mock_can_transport_interface) \
-               == self.mock_can_transport_interface.segmenter.use_data_optimization
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_use_data_optimization__set(self, value):
-        AbstractCanTransportInterface.use_data_optimization.fset(self.mock_can_transport_interface, value)
-        assert self.mock_can_transport_interface.segmenter.use_data_optimization == value
-            
-    # filler_byte
-
-    def test_filler_byte__get(self):
-        assert AbstractCanTransportInterface.filler_byte.fget(self.mock_can_transport_interface) \
-               == self.mock_can_transport_interface.segmenter.filler_byte
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_filler_byte__set(self, value):
-        AbstractCanTransportInterface.filler_byte.fset(self.mock_can_transport_interface, value)
-        assert self.mock_can_transport_interface.segmenter.filler_byte == value
-
-    # flow_control_generator
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_flow_control_generator__get(self, value):
-        self.mock_can_transport_interface._AbstractCanTransportInterface__flow_control_generator = value
-        assert AbstractCanTransportInterface.flow_control_generator.fget(self.mock_can_transport_interface) \
-               == self.mock_can_transport_interface._AbstractCanTransportInterface__flow_control_generator
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_flow_control_generator__set__type_error(self, mock_isinstance, value):
-        mock_isinstance.return_value = False
-        with pytest.raises(TypeError):
-            AbstractCanTransportInterface.flow_control_generator.fset(self.mock_can_transport_interface, value)
-        mock_isinstance.assert_called_once_with(value, (self.mock_can_packet_class, Iterable))
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_flow_control_generator__set__valid(self, mock_isinstance, value):
-        mock_isinstance.return_value = True
-        AbstractCanTransportInterface.flow_control_generator.fset(self.mock_can_transport_interface, value)
-        mock_isinstance.assert_called_once_with(value, (self.mock_can_packet_class, Iterable))
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__flow_control_generator == value
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__flow_control_iterator is None
-
-    # _get_flow_control
-
-    @pytest.mark.parametrize("is_first", [True, False])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_get_flow_control__packet(self, mock_isinstance, is_first):
-        mock_isinstance.return_value = True
-        assert AbstractCanTransportInterface._get_flow_control(self=self.mock_can_transport_interface,
-                                                               is_first=is_first) \
-               == self.mock_can_transport_interface.flow_control_generator
-        mock_isinstance.assert_called_once_with(self.mock_can_transport_interface.flow_control_generator,
-                                                self.mock_can_packet_class)
-
-    @patch(f"{SCRIPT_LOCATION}.iter")
-    @patch(f"{SCRIPT_LOCATION}.next")
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_get_flow_control__generator__first(self, mock_isinstance, mock_next, mock_iter):
-        mock_isinstance.return_value = False
-        assert AbstractCanTransportInterface._get_flow_control(self=self.mock_can_transport_interface,
-                                                               is_first=True) \
-               == mock_next.return_value
-        mock_isinstance.assert_called_once_with(self.mock_can_transport_interface.flow_control_generator,
-                                                self.mock_can_packet_class)
-        mock_iter.assert_called_once_with(self.mock_can_transport_interface.flow_control_generator)
-        mock_next.assert_called_once_with(
-            self.mock_can_transport_interface._AbstractCanTransportInterface__flow_control_iterator)
-        assert self.mock_can_transport_interface._AbstractCanTransportInterface__flow_control_iterator \
-               == mock_iter.return_value
-
-    @patch(f"{SCRIPT_LOCATION}.iter")
-    @patch(f"{SCRIPT_LOCATION}.next")
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_get_flow_control__generator__following(self, mock_isinstance, mock_next, mock_iter):
-        mock_isinstance.return_value = False
-        self.mock_can_transport_interface._AbstractCanTransportInterface__flow_control_iterator = Mock()
-        assert AbstractCanTransportInterface._get_flow_control(self=self.mock_can_transport_interface,
-                                                               is_first=False) \
-               == mock_next.return_value
-        mock_isinstance.assert_called_once_with(self.mock_can_transport_interface.flow_control_generator,
-                                                self.mock_can_packet_class)
-        mock_iter.assert_not_called()
-        mock_next.assert_called_once_with(
-            self.mock_can_transport_interface._AbstractCanTransportInterface__flow_control_iterator)
diff --git a/tests/software_tests/transport_interface/test_abstract_transport_interface.py b/tests/software_tests/transport_interface/test_abstract_transport_interface.py
index e187fbcb..e05d7d54 100644
--- a/tests/software_tests/transport_interface/test_abstract_transport_interface.py
+++ b/tests/software_tests/transport_interface/test_abstract_transport_interface.py
@@ -1,26 +1,17 @@
 import pytest
-from mock import Mock, patch
+from mock import Mock
 
-from uds.transport_interface.abstract_transport_interface import AbstractTransportInterface, \
-    UdsMessageRecord, UdsMessage
+from uds.transport_interface.abstract_transport_interface import AbstractTransportInterface
+
+
+SCRIPT_LOCATION = "uds.transport_interface.abstract_transport_interface"
 
 
 class TestAbstractTransportInterface:
     """Unit tests for `AbstractTransportInterface` class."""
 
-    SCRIPT_LOCATION = "uds.transport_interface.abstract_transport_interface"
-
-    def setup(self):
+    def setup_method(self):
         self.mock_transport_interface = Mock(spec=AbstractTransportInterface)
-        # patching
-        self._patcher_records_queue_class = patch(f"{self.SCRIPT_LOCATION}.RecordsQueue")
-        self.mock_records_queue_class = self._patcher_records_queue_class.start()
-        self._patcher_transmission_queue_class = patch(f"{self.SCRIPT_LOCATION}.TransmissionQueue")
-        self.mock_transmission_queue_class = self._patcher_transmission_queue_class.start()
-
-    def teardown(self):
-        self._patcher_records_queue_class.stop()
-        self._patcher_transmission_queue_class.stop()
 
     # __init__
 
@@ -28,8 +19,7 @@ def test_init__value_error(self):
         self.mock_transport_interface.is_supported_bus_manager.return_value = False
         with pytest.raises(ValueError):
             AbstractTransportInterface.__init__(self=self.mock_transport_interface,
-                                                bus_manager=Mock(),
-                                                message_records_number=Mock())
+                                                bus_manager=Mock())
         self.mock_transport_interface.is_supported_bus_manager.assert_called_once()
 
     @pytest.mark.parametrize("bus_manager, message_records_number, packet_records_number", [
@@ -39,31 +29,9 @@ def test_init__value_error(self):
     def test_init__valid(self, bus_manager, message_records_number, packet_records_number):
         self.mock_transport_interface.is_supported_bus_manager.return_value = True
         AbstractTransportInterface.__init__(self=self.mock_transport_interface,
-                                            bus_manager=bus_manager,
-                                            message_records_number=message_records_number)
+                                            bus_manager=bus_manager)
         self.mock_transport_interface.is_supported_bus_manager.assert_called_once_with(bus_manager)
-        self.mock_records_queue_class.assert_called_once_with(records_type=UdsMessageRecord,
-                                                              history_size=message_records_number)
-        self.mock_transmission_queue_class.assert_called_once_with(pdu_type=UdsMessage)
         assert self.mock_transport_interface._AbstractTransportInterface__bus_manager == bus_manager
-        assert self.mock_transport_interface._AbstractTransportInterface__message_records_queue \
-               == self.mock_records_queue_class.return_value
-        assert self.mock_transport_interface._AbstractTransportInterface__message_transmission_queue \
-               == self.mock_transmission_queue_class.return_value
-
-    # _message_records_queue
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_message_records_queue__get(self, value):
-        self.mock_transport_interface._AbstractTransportInterface__message_records_queue = value
-        assert AbstractTransportInterface._message_records_queue.fget(self.mock_transport_interface) == value
-
-    # _message_transmission_queue
-    
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_message_transmission_queue__get(self, value):
-        self.mock_transport_interface._AbstractTransportInterface__message_transmission_queue = value
-        assert AbstractTransportInterface._message_transmission_queue.fget(self.mock_transport_interface) == value
 
     # bus_manager
 
@@ -71,55 +39,3 @@ def test_message_transmission_queue__get(self, value):
     def test_bus_manager(self, value):
         self.mock_transport_interface._AbstractTransportInterface__bus_manager = value
         assert AbstractTransportInterface.bus_manager.fget(self.mock_transport_interface) == value
-
-    # message_records_history
-
-    def test_message_records_history__get(self):
-        assert AbstractTransportInterface.message_records_history.fget(self.mock_transport_interface) \
-               == self.mock_transport_interface._message_records_queue.records_history
-
-    # packet_records_history
-
-    def test_packet_records_history__get(self):
-        assert AbstractTransportInterface.packet_records_history.fget(self.mock_transport_interface) \
-               == self.mock_transport_interface._packet_records_queue.records_history
-
-    # await_packet_received
-
-    @pytest.mark.asyncio
-    async def test_await_packet_received(self):
-        with pytest.raises(NotImplementedError):
-            await AbstractTransportInterface.await_packet_received(self=self.mock_transport_interface)
-
-    # await_packet_transmitted
-
-    @pytest.mark.asyncio
-    async def test_await_packet_transmitted(self):
-        with pytest.raises(NotImplementedError):
-            await AbstractTransportInterface.await_packet_transmitted(self=self.mock_transport_interface)
-
-    # await_message_received
-
-    @pytest.mark.asyncio
-    async def test_await_message_received(self):
-        with pytest.raises(NotImplementedError):
-            await AbstractTransportInterface.await_message_received(self=self.mock_transport_interface)
-            
-    # await_message_transmitted
-
-    @pytest.mark.asyncio
-    async def test_await_message_transmitted(self):
-        with pytest.raises(NotImplementedError):
-            await AbstractTransportInterface.await_message_transmitted(self=self.mock_transport_interface)
-            
-    # send_packet
-
-    def test_send_packet(self):
-        with pytest.raises(NotImplementedError):
-            AbstractTransportInterface.send_packet(self=self.mock_transport_interface, packet=Mock())
-            
-    # send_message
-
-    def test_send_message(self):
-        with pytest.raises(NotImplementedError):
-            AbstractTransportInterface.send_message(self=self.mock_transport_interface, message=Mock())
diff --git a/tests/software_tests/transport_interface/test_can_transport_interface.py b/tests/software_tests/transport_interface/test_can_transport_interface.py
new file mode 100644
index 00000000..e6cda8a1
--- /dev/null
+++ b/tests/software_tests/transport_interface/test_can_transport_interface.py
@@ -0,0 +1,1015 @@
+import pytest
+from mock import MagicMock, Mock, AsyncMock, patch
+
+from uds.transport_interface.can_transport_interface import AbstractCanTransportInterface, PyCanTransportInterface, \
+    AbstractCanAddressingInformation, BusABC, CanPacket, CanPacketType, TransmissionDirection
+from uds.can import CanAddressingInformation, CanAddressingFormat
+
+
+SCRIPT_LOCATION = "uds.transport_interface.can_transport_interface"
+
+
+class TestAbstractCanTransportInterface:
+    """Unit tests for `AbstractCanTransportInterface` class."""
+
+    def setup_method(self):
+        self.mock_can_transport_interface = Mock(spec=AbstractCanTransportInterface)
+        # patching
+        self._patcher_abstract_transport_interface_init \
+            = patch(f"{SCRIPT_LOCATION}.AbstractTransportInterface.__init__")
+        self.mock_abstract_transport_interface_init = self._patcher_abstract_transport_interface_init.start()
+        self._patcher_can_segmenter_class = patch(f"{SCRIPT_LOCATION}.CanSegmenter")
+        self.mock_can_segmenter_class = self._patcher_can_segmenter_class.start()
+        self._patcher_warn = patch(f"{SCRIPT_LOCATION}.warn")
+        self.mock_warn = self._patcher_warn.start()
+
+    def teardown_method(self):
+        self._patcher_abstract_transport_interface_init.stop()
+        self._patcher_can_segmenter_class.stop()
+        self._patcher_warn.stop()
+
+    # __init__
+
+    @pytest.mark.parametrize("can_bus_manager, addressing_information", [
+        ("can_bus_manager", "addressing_information"),
+        (Mock(), Mock()),
+    ])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_init__type_error(self, mock_isinstance,
+                              can_bus_manager, addressing_information):
+        mock_isinstance.return_value = False
+        with pytest.raises(TypeError):
+            AbstractCanTransportInterface.__init__(self=self.mock_can_transport_interface,
+                                                   can_bus_manager=can_bus_manager,
+                                                   addressing_information=addressing_information)
+        mock_isinstance.assert_called_once_with(addressing_information, AbstractCanAddressingInformation)
+
+    @pytest.mark.parametrize("can_bus_manager, addressing_information", [
+        ("can_bus_manager", "some addressing information"),
+        (Mock(), Mock()),
+    ])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_init__valid_mandatory_args(self, mock_isinstance,
+                                        can_bus_manager, addressing_information):
+        mock_isinstance.return_value = True
+        AbstractCanTransportInterface.__init__(self=self.mock_can_transport_interface,
+                                               can_bus_manager=can_bus_manager,
+                                               addressing_information=addressing_information)
+        mock_isinstance.assert_called_once_with(addressing_information, AbstractCanAddressingInformation)
+        self.mock_abstract_transport_interface_init.assert_called_once_with(bus_manager=can_bus_manager)
+        self.mock_can_segmenter_class.assert_called_once_with(addressing_information=addressing_information)
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__addressing_information \
+               == addressing_information
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__segmenter \
+               == self.mock_can_segmenter_class.return_value
+        assert self.mock_can_transport_interface.n_as_timeout == self.mock_can_transport_interface.N_AS_TIMEOUT
+        assert self.mock_can_transport_interface.n_ar_timeout == self.mock_can_transport_interface.N_AR_TIMEOUT
+        assert self.mock_can_transport_interface.n_bs_timeout == self.mock_can_transport_interface.N_BS_TIMEOUT
+        assert self.mock_can_transport_interface.n_br == self.mock_can_transport_interface.DEFAULT_N_BR
+        assert self.mock_can_transport_interface.n_cs == self.mock_can_transport_interface.DEFAULT_N_CS
+        assert self.mock_can_transport_interface.n_cr_timeout == self.mock_can_transport_interface.N_CR_TIMEOUT
+
+    @pytest.mark.parametrize("can_bus_manager, addressing_information", [
+        ("can_bus_manager", "addressing_information"),
+        (Mock(), Mock()),
+    ])
+    @pytest.mark.parametrize("n_as_timeout, n_ar_timeout, n_bs_timeout, n_br, n_cs, n_cr_timeout, "
+                             "dlc, use_data_optimization, filler_byte", [
+        ("n_as_timeout", "n_ar_timeout", "n_bs_timeout", "n_br", "n_cs", "n_cr_timeout", "dlc", "use_data_optimization",
+         "filler_byte"),
+        (Mock(), Mock(), Mock(), Mock(), Mock(), Mock(), Mock(), Mock(), Mock()),
+    ])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_init__valid_all_args(self, mock_isinstance,
+                                  can_bus_manager, addressing_information,
+                                  n_as_timeout, n_ar_timeout, n_bs_timeout, n_br, n_cs, n_cr_timeout,
+                                  dlc, use_data_optimization, filler_byte):
+        mock_isinstance.return_value = True
+        AbstractCanTransportInterface.__init__(self=self.mock_can_transport_interface,
+                                               can_bus_manager=can_bus_manager,
+                                               addressing_information=addressing_information,
+                                               n_as_timeout=n_as_timeout,
+                                               n_ar_timeout=n_ar_timeout,
+                                               n_bs_timeout=n_bs_timeout,
+                                               n_br=n_br,
+                                               n_cs=n_cs,
+                                               n_cr_timeout=n_cr_timeout,
+                                               dlc=dlc,
+                                               use_data_optimization=use_data_optimization,
+                                               filler_byte=filler_byte)
+        mock_isinstance.assert_called_once_with(addressing_information, AbstractCanAddressingInformation)
+        self.mock_abstract_transport_interface_init.assert_called_once_with(bus_manager=can_bus_manager)
+        self.mock_can_segmenter_class.assert_called_once_with(
+            addressing_information=addressing_information,
+            dlc=dlc,
+            use_data_optimization=use_data_optimization,
+            filler_byte=filler_byte)
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__addressing_information \
+               == addressing_information
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__segmenter \
+               == self.mock_can_segmenter_class.return_value
+        assert self.mock_can_transport_interface.n_as_timeout == n_as_timeout
+        assert self.mock_can_transport_interface.n_ar_timeout == n_ar_timeout
+        assert self.mock_can_transport_interface.n_bs_timeout == n_bs_timeout
+        assert self.mock_can_transport_interface.n_br == n_br
+        assert self.mock_can_transport_interface.n_cs == n_cs
+        assert self.mock_can_transport_interface.n_cr_timeout == n_cr_timeout
+
+    # segmenter
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_segmenter(self, value):
+        self.mock_can_transport_interface._AbstractCanTransportInterface__segmenter = value
+        assert AbstractCanTransportInterface.segmenter.fget(self.mock_can_transport_interface) \
+               == self.mock_can_transport_interface._AbstractCanTransportInterface__segmenter
+
+    # n_as
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_n_as_timeout__get(self, value):
+        self.mock_can_transport_interface._AbstractCanTransportInterface__n_as_timeout = value
+        assert AbstractCanTransportInterface.n_as_timeout.fget(self.mock_can_transport_interface) == value
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_as_timeout__set__type_error(self, mock_isinstance, value):
+        mock_isinstance.return_value = False
+        with pytest.raises(TypeError):
+            AbstractCanTransportInterface.n_as_timeout.fset(self.mock_can_transport_interface, value)
+        mock_isinstance.assert_called_once_with(value, (int, float))
+
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_as_timeout__set__value_error(self, mock_isinstance):
+        mock_isinstance.return_value = True
+        mock_le = Mock(return_value=True)
+        mock_value = MagicMock(__le__=mock_le)
+        with pytest.raises(ValueError):
+            AbstractCanTransportInterface.n_as_timeout.fset(self.mock_can_transport_interface, mock_value)
+        mock_isinstance.assert_called_once_with(mock_value, (int, float))
+        mock_le.assert_called_once_with(0)
+
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_as_timeout__set__valid_with_warn(self, mock_isinstance):
+        mock_isinstance.return_value = True
+        mock_le = Mock(return_value=False)
+        mock_ne = Mock(return_value=True)
+        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
+        AbstractCanTransportInterface.n_as_timeout.fset(self.mock_can_transport_interface, mock_value)
+        mock_isinstance.assert_called_once_with(mock_value, (int, float))
+        mock_le.assert_called_once_with(0)
+        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_AS_TIMEOUT)
+        self.mock_warn.assert_called_once()
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_as_timeout == mock_value
+
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_as_timeout__set__valid_without_warn(self, mock_isinstance):
+        mock_isinstance.return_value = True
+        mock_le = Mock(return_value=False)
+        mock_ne = Mock(return_value=False)
+        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
+        AbstractCanTransportInterface.n_as_timeout.fset(self.mock_can_transport_interface, mock_value)
+        mock_isinstance.assert_called_once_with(mock_value, (int, float))
+        mock_le.assert_called_once_with(0)
+        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_AS_TIMEOUT)
+        self.mock_warn.assert_not_called()
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_as_timeout == mock_value
+
+    # n_ar
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_n_ar_timeout__get(self, value):
+        self.mock_can_transport_interface._AbstractCanTransportInterface__n_ar_timeout = value
+        assert AbstractCanTransportInterface.n_ar_timeout.fget(self.mock_can_transport_interface) == value
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_ar_timeout__set__type_error(self, mock_isinstance, value):
+        mock_isinstance.return_value = False
+        with pytest.raises(TypeError):
+            AbstractCanTransportInterface.n_ar_timeout.fset(self.mock_can_transport_interface, value)
+        mock_isinstance.assert_called_once_with(value, (int, float))
+
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_ar_timeout__set__value_error(self, mock_isinstance):
+        mock_isinstance.return_value = True
+        mock_le = Mock(return_value=True)
+        mock_value = MagicMock(__le__=mock_le)
+        with pytest.raises(ValueError):
+            AbstractCanTransportInterface.n_ar_timeout.fset(self.mock_can_transport_interface, mock_value)
+        mock_isinstance.assert_called_once_with(mock_value, (int, float))
+        mock_le.assert_called_once_with(0)
+
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_ar_timeout__set__valid_with_warn(self, mock_isinstance):
+        mock_isinstance.return_value = True
+        mock_le = Mock(return_value=False)
+        mock_ne = Mock(return_value=True)
+        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
+        AbstractCanTransportInterface.n_ar_timeout.fset(self.mock_can_transport_interface, mock_value)
+        mock_isinstance.assert_called_once_with(mock_value, (int, float))
+        mock_le.assert_called_once_with(0)
+        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_AR_TIMEOUT)
+        self.mock_warn.assert_called_once()
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_ar_timeout == mock_value
+
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_ar_timeout__set__valid_without_warn(self, mock_isinstance):
+        mock_isinstance.return_value = True
+        mock_le = Mock(return_value=False)
+        mock_ne = Mock(return_value=False)
+        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
+        AbstractCanTransportInterface.n_ar_timeout.fset(self.mock_can_transport_interface, mock_value)
+        mock_isinstance.assert_called_once_with(mock_value, (int, float))
+        mock_le.assert_called_once_with(0)
+        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_AR_TIMEOUT)
+        self.mock_warn.assert_not_called()
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_ar_timeout == mock_value
+
+    # n_bs
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_n_bs_timeout__get(self, value):
+        self.mock_can_transport_interface._AbstractCanTransportInterface__n_bs_timeout = value
+        assert AbstractCanTransportInterface.n_bs_timeout.fget(self.mock_can_transport_interface) == value
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_bs_timeout__set__type_error(self, mock_isinstance, value):
+        mock_isinstance.return_value = False
+        with pytest.raises(TypeError):
+            AbstractCanTransportInterface.n_bs_timeout.fset(self.mock_can_transport_interface, value)
+        mock_isinstance.assert_called_once_with(value, (int, float))
+
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_bs_timeout__set__value_error(self, mock_isinstance):
+        mock_isinstance.return_value = True
+        mock_le = Mock(return_value=True)
+        mock_value = MagicMock(__le__=mock_le)
+        with pytest.raises(ValueError):
+            AbstractCanTransportInterface.n_bs_timeout.fset(self.mock_can_transport_interface, mock_value)
+        mock_isinstance.assert_called_once_with(mock_value, (int, float))
+        mock_le.assert_called_once_with(0)
+
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_bs_timeout__set__valid_with_warn(self, mock_isinstance):
+        mock_isinstance.return_value = True
+        mock_le = Mock(return_value=False)
+        mock_ne = Mock(return_value=True)
+        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
+        AbstractCanTransportInterface.n_bs_timeout.fset(self.mock_can_transport_interface, mock_value)
+        mock_isinstance.assert_called_once_with(mock_value, (int, float))
+        mock_le.assert_called_once_with(0)
+        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_BS_TIMEOUT)
+        self.mock_warn.assert_called_once()
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_bs_timeout == mock_value
+
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_bs_timeout__set__valid_without_warn(self, mock_isinstance):
+        mock_isinstance.return_value = True
+        mock_le = Mock(return_value=False)
+        mock_ne = Mock(return_value=False)
+        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
+        AbstractCanTransportInterface.n_bs_timeout.fset(self.mock_can_transport_interface, mock_value)
+        mock_isinstance.assert_called_once_with(mock_value, (int, float))
+        mock_le.assert_called_once_with(0)
+        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_BS_TIMEOUT)
+        self.mock_warn.assert_not_called()
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_bs_timeout == mock_value
+
+    # n_br
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_n_br__get(self, value):
+        self.mock_can_transport_interface._AbstractCanTransportInterface__n_br = value
+        assert AbstractCanTransportInterface.n_br.fget(self.mock_can_transport_interface) == value
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_br__set__type_error(self, mock_isinstance, value):
+        mock_isinstance.return_value = False
+        with pytest.raises(TypeError):
+            AbstractCanTransportInterface.n_br.fset(self.mock_can_transport_interface, value)
+        mock_isinstance.assert_called_once_with(value, (int, float))
+
+    @pytest.mark.parametrize("value, max_value", [
+        (-0.00000001, 100),
+        (-1, 900),
+        (901, 900.5),
+        (450.1, 450),
+    ])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_br__set__value_error(self, mock_isinstance, value, max_value):
+        mock_isinstance.return_value = True
+        self.mock_can_transport_interface.n_br_max = max_value
+        with pytest.raises(ValueError):
+            AbstractCanTransportInterface.n_br.fset(self.mock_can_transport_interface, value)
+        mock_isinstance.assert_called_once_with(value, (int, float))
+
+    @pytest.mark.parametrize("value, max_value", [
+        (99, 100),
+        (899.99, 900),
+        (45.59, 900.5),
+        (0, 450),
+    ])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_br__set__valid(self, mock_isinstance, value, max_value):
+        mock_isinstance.return_value = True
+        self.mock_can_transport_interface.n_br_max = max_value
+        AbstractCanTransportInterface.n_br.fset(self.mock_can_transport_interface, value)
+        mock_isinstance.assert_called_once_with(value, (int, float))
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_br == value
+
+    @pytest.mark.parametrize("n_bs_timeout, n_ar_measured", [
+        (1000, 10),
+        (965.43, 12.45),
+    ])
+    def test_n_br_max__n_ar_measured(self, n_bs_timeout, n_ar_measured):
+        self.mock_can_transport_interface.n_bs_timeout = n_bs_timeout
+        self.mock_can_transport_interface.n_ar_measured = n_ar_measured
+        assert AbstractCanTransportInterface.n_br_max.fget(self.mock_can_transport_interface) \
+               == 0.9 * n_bs_timeout - n_ar_measured
+
+    @pytest.mark.parametrize("n_bs_timeout", [1000, 965.43])
+    def test_n_br_max__n_ar_not_measured(self, n_bs_timeout):
+        self.mock_can_transport_interface.n_bs_timeout = n_bs_timeout
+        self.mock_can_transport_interface.n_ar_measured = None
+        assert AbstractCanTransportInterface.n_br_max.fget(self.mock_can_transport_interface) \
+               == 0.9 * n_bs_timeout
+
+    # n_cs
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_n_cs__get(self, value):
+        self.mock_can_transport_interface._AbstractCanTransportInterface__n_cs = value
+        assert AbstractCanTransportInterface.n_cs.fget(self.mock_can_transport_interface) == value
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_cs__set__type_error(self, mock_isinstance, value):
+        mock_isinstance.return_value = False
+        with pytest.raises(TypeError):
+            AbstractCanTransportInterface.n_cs.fset(self.mock_can_transport_interface, value)
+        mock_isinstance.assert_called_once_with(value, (int, float))
+
+    @pytest.mark.parametrize("value, max_value", [
+        (-0.00000001, 100),
+        (-1, 900),
+        (901, 900.5),
+        (450.1, 450),
+    ])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_cs__set__value_error(self, mock_isinstance, value, max_value):
+        mock_isinstance.return_value = True
+        self.mock_can_transport_interface.n_cs_max = max_value
+        with pytest.raises(ValueError):
+            AbstractCanTransportInterface.n_cs.fset(self.mock_can_transport_interface, value)
+        mock_isinstance.assert_called_once_with(value, (int, float))
+
+    @pytest.mark.parametrize("value, max_value", [
+        (99, 100),
+        (899.99, 900),
+        (45.59, 900.5),
+        (0, 450),
+    ])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_cs__set__valid(self, mock_isinstance, value, max_value):
+        mock_isinstance.return_value = True
+        self.mock_can_transport_interface.n_cs_max = max_value
+        AbstractCanTransportInterface.n_cs.fset(self.mock_can_transport_interface, value)
+        mock_isinstance.assert_called_once_with(value, (int, float))
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_cs == value
+
+    def test_n_cs__set__none(self):
+        AbstractCanTransportInterface.n_cs.fset(self.mock_can_transport_interface, None)
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_cs is None
+
+    @pytest.mark.parametrize("n_cr_timeout, n_as_measured", [
+        (1000, 10),
+        (965.43, 12.45),
+    ])
+    def test_n_cs_max__n_as_measured(self, n_cr_timeout, n_as_measured):
+        self.mock_can_transport_interface.n_cr_timeout = n_cr_timeout
+        self.mock_can_transport_interface.n_as_measured = n_as_measured
+        assert AbstractCanTransportInterface.n_cs_max.fget(self.mock_can_transport_interface) \
+               == 0.9 * n_cr_timeout - n_as_measured
+
+    @pytest.mark.parametrize("n_cr_timeout", [1000, 965.43])
+    def test_n_cs_max__n_as_not_measured(self, n_cr_timeout):
+        self.mock_can_transport_interface.n_cr_timeout = n_cr_timeout
+        self.mock_can_transport_interface.n_as_measured = None
+        assert AbstractCanTransportInterface.n_cs_max.fget(self.mock_can_transport_interface) \
+               == 0.9 * n_cr_timeout
+
+    # n_cr
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_n_cr_timeout__get(self, value):
+        self.mock_can_transport_interface._AbstractCanTransportInterface__n_cr_timeout = value
+        assert AbstractCanTransportInterface.n_cr_timeout.fget(self.mock_can_transport_interface) == value
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_cr_timeout__set__type_error(self, mock_isinstance, value):
+        mock_isinstance.return_value = False
+        with pytest.raises(TypeError):
+            AbstractCanTransportInterface.n_cr_timeout.fset(self.mock_can_transport_interface, value)
+        mock_isinstance.assert_called_once_with(value, (int, float))
+
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_cr_timeout__set__value_error(self, mock_isinstance):
+        mock_isinstance.return_value = True
+        mock_le = Mock(return_value=True)
+        mock_value = MagicMock(__le__=mock_le)
+        with pytest.raises(ValueError):
+            AbstractCanTransportInterface.n_cr_timeout.fset(self.mock_can_transport_interface, mock_value)
+        mock_isinstance.assert_called_once_with(mock_value, (int, float))
+        mock_le.assert_called_once_with(0)
+
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_cr_timeout__set__valid_with_warn(self, mock_isinstance):
+        mock_isinstance.return_value = True
+        mock_le = Mock(return_value=False)
+        mock_ne = Mock(return_value=True)
+        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
+        AbstractCanTransportInterface.n_cr_timeout.fset(self.mock_can_transport_interface, mock_value)
+        mock_isinstance.assert_called_once_with(mock_value, (int, float))
+        mock_le.assert_called_once_with(0)
+        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_CR_TIMEOUT)
+        self.mock_warn.assert_called_once()
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_cr_timeout == mock_value
+
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_n_cr_timeout__set__valid_without_warn(self, mock_isinstance):
+        mock_isinstance.return_value = True
+        mock_le = Mock(return_value=False)
+        mock_ne = Mock(return_value=False)
+        mock_value = MagicMock(__le__=mock_le, __ne__=mock_ne)
+        AbstractCanTransportInterface.n_cr_timeout.fset(self.mock_can_transport_interface, mock_value)
+        mock_isinstance.assert_called_once_with(mock_value, (int, float))
+        mock_le.assert_called_once_with(0)
+        mock_ne.assert_called_once_with(self.mock_can_transport_interface.N_CR_TIMEOUT)
+        self.mock_warn.assert_not_called()
+        assert self.mock_can_transport_interface._AbstractCanTransportInterface__n_cr_timeout == mock_value
+
+    # addressing_information
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_addressing_information(self, value):
+        self.mock_can_transport_interface._AbstractCanTransportInterface__addressing_information = value
+        assert AbstractCanTransportInterface.addressing_information.fget(self.mock_can_transport_interface) \
+               == self.mock_can_transport_interface._AbstractCanTransportInterface__addressing_information
+
+    # dlc
+
+    def test_dlc__get(self):
+        assert AbstractCanTransportInterface.dlc.fget(self.mock_can_transport_interface) \
+               == self.mock_can_transport_interface.segmenter.dlc
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_dlc__set(self, value):
+        AbstractCanTransportInterface.dlc.fset(self.mock_can_transport_interface, value)
+        assert self.mock_can_transport_interface.segmenter.dlc == value
+
+    # use_data_optimization
+
+    def test_use_data_optimization__get(self):
+        assert AbstractCanTransportInterface.use_data_optimization.fget(self.mock_can_transport_interface) \
+               == self.mock_can_transport_interface.segmenter.use_data_optimization
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_use_data_optimization__set(self, value):
+        AbstractCanTransportInterface.use_data_optimization.fset(self.mock_can_transport_interface, value)
+        assert self.mock_can_transport_interface.segmenter.use_data_optimization == value
+
+    # filler_byte
+
+    def test_filler_byte__get(self):
+        assert AbstractCanTransportInterface.filler_byte.fget(self.mock_can_transport_interface) \
+               == self.mock_can_transport_interface.segmenter.filler_byte
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_filler_byte__set(self, value):
+        AbstractCanTransportInterface.filler_byte.fset(self.mock_can_transport_interface, value)
+        assert self.mock_can_transport_interface.segmenter.filler_byte == value
+
+
+class TestPyCanTransportInterface:
+    """Unit tests for `PyCanTransportInterface` class."""
+
+    def setup_method(self):
+        self.mock_can_transport_interface = MagicMock(spec=PyCanTransportInterface)
+        # patching
+        self._patcher_warn = patch(f"{SCRIPT_LOCATION}.warn")
+        self.mock_warn = self._patcher_warn.start()
+        self._patcher_wait_for = patch(f"{SCRIPT_LOCATION}.wait_for", AsyncMock(side_effect=lambda *args, **kwargs: args[0]))
+        self.mock_wait_for = self._patcher_wait_for.start()
+        self._patcher_time = patch(f"{SCRIPT_LOCATION}.time")
+        self.mock_time = self._patcher_time.start()
+        self._patcher_datetime = patch(f"{SCRIPT_LOCATION}.datetime")
+        self.mock_datetime = self._patcher_datetime.start()
+        self._patcher_abstract_can_ti_init = patch(f"{SCRIPT_LOCATION}.AbstractCanTransportInterface.__init__")
+        self.mock_abstract_can_ti_init = self._patcher_abstract_can_ti_init.start()
+        self._patcher_can_id_handler = patch(f"{SCRIPT_LOCATION}.CanIdHandler")
+        self.mock_can_id_handler = self._patcher_can_id_handler.start()
+        self._patcher_can_dlc_handler = patch(f"{SCRIPT_LOCATION}.CanDlcHandler")
+        self.mock_can_dlc_handler = self._patcher_can_dlc_handler.start()
+        self._patcher_can_packet_record = patch(f"{SCRIPT_LOCATION}.CanPacketRecord")
+        self.mock_can_packet_record = self._patcher_can_packet_record.start()
+        self._patcher_notifier = patch(f"{SCRIPT_LOCATION}.Notifier")
+        self.mock_notifier = self._patcher_notifier.start()
+        self._patcher_message = patch(f"{SCRIPT_LOCATION}.Message")
+        self.mock_message = self._patcher_message.start()
+
+    def teardown_method(self):
+        self._patcher_warn.stop()
+        self._patcher_wait_for.stop()
+        self._patcher_time.stop()
+        self._patcher_datetime.stop()
+        self._patcher_abstract_can_ti_init.stop()
+        self._patcher_can_id_handler.stop()
+        self._patcher_can_dlc_handler.stop()
+        self._patcher_can_packet_record.stop()
+        self._patcher_notifier.stop()
+        self._patcher_message.stop()
+
+    # __init__
+
+    @pytest.mark.parametrize("can_bus_manager, addressing_information", [
+        ("can_bus_manager", "addressing_information"),
+        (Mock(), Mock())
+    ])
+    def test_init__default_args(self, can_bus_manager, addressing_information):
+        PyCanTransportInterface.__init__(self=self.mock_can_transport_interface,
+                                         can_bus_manager=can_bus_manager,
+                                         addressing_information=addressing_information)
+        self.mock_abstract_can_ti_init.assert_called_once_with(
+            can_bus_manager=can_bus_manager,
+            addressing_information=addressing_information)
+        assert self.mock_can_transport_interface._PyCanTransportInterface__n_as_measured is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__n_ar_measured is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__n_bs_measured is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__n_cr_measured is None
+
+    @pytest.mark.parametrize("can_bus_manager, addressing_information", [
+        ("can_bus_manager", "addressing_information"),
+        (Mock(), Mock())
+    ])
+    @pytest.mark.parametrize("kwargs", [
+        {"a": Mock(), "b": Mock()},
+        {"param1": Mock(), "param2": Mock(), "something_else": Mock()},
+    ])
+    def test_init__all_args(self, can_bus_manager, addressing_information, kwargs):
+        PyCanTransportInterface.__init__(self=self.mock_can_transport_interface,
+                                         can_bus_manager=can_bus_manager,
+                                         addressing_information=addressing_information,
+                                         **kwargs)
+        self.mock_abstract_can_ti_init.assert_called_once_with(can_bus_manager=can_bus_manager,
+                                                               addressing_information=addressing_information,
+                                                               **kwargs)
+        assert self.mock_can_transport_interface._PyCanTransportInterface__n_as_measured is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__n_ar_measured is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__n_bs_measured is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__n_cr_measured is None
+
+    # __del__
+
+    def test_del(self):
+        assert PyCanTransportInterface.__del__(self.mock_can_transport_interface) is None
+        self.mock_can_transport_interface._teardown_notifier.assert_called_once_with(suppress_warning=True)
+        self.mock_can_transport_interface._teardown_async_notifier.assert_called_once_with(suppress_warning=True)
+
+    # n_as_measured
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_n_as_measured(self, value):
+        self.mock_can_transport_interface._PyCanTransportInterface__n_as_measured = value
+        assert PyCanTransportInterface.n_as_measured.fget(self.mock_can_transport_interface) == value
+
+    # n_as_measured
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_n_ar_measured(self, value):
+        self.mock_can_transport_interface._PyCanTransportInterface__n_ar_measured = value
+        assert PyCanTransportInterface.n_ar_measured.fget(self.mock_can_transport_interface) == value
+
+    # n_bs_measured
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_n_bs_measured(self, value):
+        self.mock_can_transport_interface._PyCanTransportInterface__n_bs_measured = value
+        assert PyCanTransportInterface.n_bs_measured.fget(self.mock_can_transport_interface) == value
+
+    # n_cr_measured
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    def test_n_cr_measured(self, value):
+        self.mock_can_transport_interface._PyCanTransportInterface__n_cr_measured = value
+        assert PyCanTransportInterface.n_cr_measured.fget(self.mock_can_transport_interface) == value
+
+    # _teardown_notifier
+
+    def test_teardown_notifier__no_notifier(self):
+        self.mock_can_transport_interface._PyCanTransportInterface__notifier = None
+        assert PyCanTransportInterface._teardown_notifier(self.mock_can_transport_interface) is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__notifier is None
+        self.mock_warn.assert_not_called()
+
+    def test_teardown_notifier__notifier(self):
+        mock_notifier = Mock()
+        self.mock_can_transport_interface._PyCanTransportInterface__notifier = mock_notifier
+        assert PyCanTransportInterface._teardown_notifier(self.mock_can_transport_interface) is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__notifier is None
+        mock_notifier.stop.assert_called_once_with(self.mock_can_transport_interface._MIN_NOTIFIER_TIMEOUT)
+        self.mock_warn.assert_called_once()
+
+    def test_teardown_notifier__notifier_with_suppressed_warning(self):
+        mock_notifier = Mock()
+        self.mock_can_transport_interface._PyCanTransportInterface__notifier = mock_notifier
+        assert PyCanTransportInterface._teardown_notifier(self.mock_can_transport_interface, suppress_warning=True) is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__notifier is None
+        mock_notifier.stop.assert_called_once_with(self.mock_can_transport_interface._MIN_NOTIFIER_TIMEOUT)
+        self.mock_warn.assert_not_called()
+
+    # _teardown_async_notifier
+
+    def test_teardown_async_notifier__no_notifier(self):
+        self.mock_can_transport_interface._PyCanTransportInterface__async_notifier = None
+        assert PyCanTransportInterface._teardown_async_notifier(self.mock_can_transport_interface) is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__async_notifier is None
+        self.mock_warn.assert_not_called()
+
+    def test_teardown_async_notifier__notifier(self):
+        mock_notifier = Mock()
+        self.mock_can_transport_interface._PyCanTransportInterface__async_notifier = mock_notifier
+        assert PyCanTransportInterface._teardown_async_notifier(self.mock_can_transport_interface) is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__async_notifier is None
+        mock_notifier.stop.assert_called_once_with(self.mock_can_transport_interface._MIN_NOTIFIER_TIMEOUT)
+        self.mock_warn.assert_called_once()
+
+    def test_teardown_async_notifier__notifier_with_suppressed_warning(self):
+        mock_notifier = Mock()
+        self.mock_can_transport_interface._PyCanTransportInterface__async_notifier = mock_notifier
+        assert PyCanTransportInterface._teardown_async_notifier(self.mock_can_transport_interface, suppress_warning=True) is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__async_notifier is None
+        mock_notifier.stop.assert_called_once_with(self.mock_can_transport_interface._MIN_NOTIFIER_TIMEOUT)
+        self.mock_warn.assert_not_called()
+
+    # _setup_notifier
+
+    def test_setup_notifier__no_notifier(self):
+        self.mock_can_transport_interface._PyCanTransportInterface__notifier = None
+        self.mock_can_transport_interface._PyCanTransportInterface__frames_buffer = Mock()
+        assert PyCanTransportInterface._setup_notifier(self.mock_can_transport_interface) is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__notifier == self.mock_notifier.return_value
+        self.mock_notifier.assert_called_once_with(
+            bus=self.mock_can_transport_interface.bus_manager,
+            listeners=[self.mock_can_transport_interface._PyCanTransportInterface__frames_buffer],
+            timeout=self.mock_can_transport_interface._MIN_NOTIFIER_TIMEOUT)
+        self.mock_can_transport_interface._teardown_async_notifier.assert_called_once_with()
+
+    def test_setup_notifier__notifier_exists(self):
+        mock_notifier = Mock()
+        self.mock_can_transport_interface._PyCanTransportInterface__notifier = mock_notifier
+        assert PyCanTransportInterface._setup_notifier(self.mock_can_transport_interface) is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__notifier == mock_notifier
+        self.mock_notifier.assert_not_called()
+        self.mock_can_transport_interface._teardown_async_notifier.assert_called_once_with()
+
+    # _setup_async_notifier
+
+    @pytest.mark.parametrize("loop", ["some loop", Mock()])
+    def test_setup_async_notifier__no_notifier(self, loop):
+        self.mock_can_transport_interface._PyCanTransportInterface__async_notifier = None
+        self.mock_can_transport_interface._PyCanTransportInterface__async_frames_buffer = Mock()
+        assert PyCanTransportInterface._setup_async_notifier(self.mock_can_transport_interface, loop=loop) is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__async_notifier == self.mock_notifier.return_value
+        self.mock_notifier.assert_called_once_with(
+            bus=self.mock_can_transport_interface.bus_manager,
+            listeners=[self.mock_can_transport_interface._PyCanTransportInterface__async_frames_buffer],
+            timeout=self.mock_can_transport_interface._MIN_NOTIFIER_TIMEOUT,
+            loop=loop)
+        self.mock_can_transport_interface._teardown_notifier.assert_called_once_with()
+
+    @pytest.mark.parametrize("loop", ["some loop", Mock()])
+    def test_setup_async_notifier__notifier_exists(self, loop):
+        mock_notifier = Mock()
+        self.mock_can_transport_interface._PyCanTransportInterface__async_notifier = mock_notifier
+        assert PyCanTransportInterface._setup_async_notifier(self.mock_can_transport_interface, loop=loop) is None
+        assert self.mock_can_transport_interface._PyCanTransportInterface__async_notifier == mock_notifier
+        self.mock_notifier.assert_not_called()
+        self.mock_can_transport_interface._teardown_notifier.assert_called_once_with()
+
+    # clear_frames_buffers
+
+    @pytest.mark.parametrize("sync_queue_size", [0, 1, 7])
+    @pytest.mark.parametrize("async_queue_size", [0, 1, 43])
+    def test_clear_frames_buffers(self, sync_queue_size, async_queue_size):
+        mock_sync_queue = Mock(qsize=Mock(return_value=sync_queue_size))
+        mock_async_queue = Mock(qsize=Mock(return_value=async_queue_size))
+        self.mock_can_transport_interface._PyCanTransportInterface__frames_buffer = Mock(buffer=mock_sync_queue)
+        self.mock_can_transport_interface._PyCanTransportInterface__async_frames_buffer = Mock(buffer=mock_async_queue)
+        assert PyCanTransportInterface.clear_frames_buffers(self.mock_can_transport_interface) is None
+        mock_sync_queue.qsize.assert_called_once_with()
+        mock_async_queue.qsize.assert_called_once_with()
+        assert mock_sync_queue.get_nowait.call_count == sync_queue_size
+        assert mock_async_queue.get_nowait.call_count == async_queue_size
+
+    # is_supported_bus_manager
+
+    @pytest.mark.parametrize("value", ["something", Mock()])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_is_supported_bus_manager(self, mock_isinstance, value):
+        assert PyCanTransportInterface.is_supported_bus_manager(value) == mock_isinstance.return_value
+        mock_isinstance.assert_called_once_with(value, BusABC)
+
+    # send_packet
+
+    @pytest.mark.parametrize("packet", ["something", Mock()])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_send_packet__type_error(self, mock_isinstance, packet):
+        mock_isinstance.return_value = False
+        with pytest.raises(TypeError):
+            PyCanTransportInterface.send_packet(self.mock_can_transport_interface, packet)
+        mock_isinstance.assert_called_once_with(packet, CanPacket)
+
+    @pytest.mark.parametrize("packet", [
+        Mock(spec=CanPacket, packet_type=CanPacketType.FIRST_FRAME, raw_frame_data=(0x12, 0x34)),
+        Mock(spec=CanPacket, packet_type=CanPacketType.FLOW_CONTROL, raw_frame_data=tuple(range(8))),
+        Mock(spec=CanPacket, packet_type=CanPacketType.CONSECUTIVE_FRAME, raw_frame_data=tuple(range(64, 128))),
+    ])
+    def test_send_packet__timeout(self, packet):
+        mock_get_message = Mock(return_value=MagicMock(arbitration_id=packet.can_id,
+                                                       data=packet.raw_frame_data,
+                                                       is_rx=True,
+                                                       timestamp=MagicMock(__lt__=Mock(return_value=False))))
+        self.mock_can_transport_interface._PyCanTransportInterface__frames_buffer = Mock(get_message=mock_get_message)
+        self.mock_can_transport_interface._PyCanTransportInterface__n_ar_measured = None
+        self.mock_can_transport_interface._PyCanTransportInterface__n_as_measured = None
+        self.mock_can_transport_interface.n_ar_timeout = self.mock_can_transport_interface.n_as_timeout \
+            = MagicMock(__truediv__=lambda this, other: this,
+                        __div__=lambda this, other: this,
+                        __sub__=lambda this, other: this,
+                        __le__=Mock(return_value=True))
+        with pytest.raises(TimeoutError):
+            PyCanTransportInterface.send_packet(self.mock_can_transport_interface, packet)
+        self.mock_can_id_handler.is_extended_can_id.assert_called_once_with(packet.can_id)
+        self.mock_can_dlc_handler.is_can_fd_specific_dlc.assert_called_once_with(packet.dlc)
+        self.mock_message.assert_called_once_with(arbitration_id=packet.can_id,
+                                                  is_extended_id=self.mock_can_id_handler.is_extended_can_id.return_value,
+                                                  data=packet.raw_frame_data,
+                                                  is_fd=self.mock_can_dlc_handler.is_can_fd_specific_dlc.return_value)
+        self.mock_can_transport_interface.bus_manager.send.assert_called_once_with(self.mock_message.return_value)
+
+    @pytest.mark.parametrize("packet", [
+        Mock(spec=CanPacket, packet_type=CanPacketType.FIRST_FRAME, raw_frame_data=(0x12, 0x34)),
+        Mock(spec=CanPacket, packet_type=CanPacketType.FLOW_CONTROL, raw_frame_data=tuple(range(8))),
+        Mock(spec=CanPacket, packet_type=CanPacketType.CONSECUTIVE_FRAME, raw_frame_data=tuple(range(64, 128))),
+    ])
+    def test_send_packet(self, packet):
+        mock_get_message = Mock(return_value=MagicMock(arbitration_id=packet.can_id,
+                                                       data=packet.raw_frame_data,
+                                                       is_rx=True,
+                                                       timestamp=MagicMock(__lt__=Mock(return_value=False))))
+        self.mock_can_transport_interface._PyCanTransportInterface__frames_buffer = Mock(get_message=mock_get_message)
+        self.mock_can_transport_interface._PyCanTransportInterface__n_ar_measured = None
+        self.mock_can_transport_interface._PyCanTransportInterface__n_as_measured = None
+        self.mock_can_transport_interface.n_ar_timeout = self.mock_can_transport_interface.n_as_timeout \
+            = MagicMock(__truediv__=lambda this, other: this,
+                        __div__=lambda this, other: this,
+                        __sub__=lambda this, other: this,
+                        __le__=Mock(return_value=False))
+        assert PyCanTransportInterface.send_packet(self.mock_can_transport_interface, packet) \
+               == self.mock_can_packet_record.return_value
+        self.mock_can_id_handler.is_extended_can_id.assert_called_once_with(packet.can_id)
+        self.mock_can_dlc_handler.is_can_fd_specific_dlc.assert_called_once_with(packet.dlc)
+        self.mock_message.assert_called_once_with(arbitration_id=packet.can_id,
+                                                  is_extended_id=self.mock_can_id_handler.is_extended_can_id.return_value,
+                                                  data=packet.raw_frame_data,
+                                                  is_fd=self.mock_can_dlc_handler.is_can_fd_specific_dlc.return_value)
+        self.mock_can_transport_interface.bus_manager.send.assert_called_once_with(self.mock_message.return_value)
+        self.mock_datetime.fromtimestamp.assert_called_once_with(mock_get_message.return_value.timestamp)
+        self.mock_can_packet_record.assert_called_once_with(frame=mock_get_message.return_value,
+                                                            direction=TransmissionDirection.TRANSMITTED,
+                                                            addressing_type=packet.addressing_type,
+                                                            addressing_format=packet.addressing_format,
+                                                            transmission_time=self.mock_datetime.fromtimestamp.return_value)
+        if packet.packet_type == CanPacketType.FLOW_CONTROL:
+            assert self.mock_can_transport_interface._PyCanTransportInterface__n_as_measured is None
+            assert self.mock_can_transport_interface._PyCanTransportInterface__n_ar_measured \
+                   == mock_get_message.return_value.timestamp.__sub__.return_value
+            mock_get_message.return_value.timestamp.__sub__.assert_called_once_with(self.mock_time.return_value)
+        else:
+            assert self.mock_can_transport_interface._PyCanTransportInterface__n_as_measured \
+                   == mock_get_message.return_value.timestamp.__sub__.return_value
+            assert self.mock_can_transport_interface._PyCanTransportInterface__n_ar_measured is None
+            mock_get_message.return_value.timestamp.__sub__.assert_called_once_with(self.mock_time.return_value)
+
+    # receive_packet
+
+    @pytest.mark.parametrize("timeout", ["something", Mock()])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    def test_receive_packet__type_error(self, mock_isinstance, timeout):
+        mock_isinstance.return_value = False
+        with pytest.raises(TypeError):
+            PyCanTransportInterface.receive_packet(self.mock_can_transport_interface, timeout)
+        mock_isinstance.assert_called_once_with(timeout, (int, float))
+
+    @pytest.mark.parametrize("timeout", [0, -654])
+    def test_receive_packet__value_error(self, timeout):
+        with pytest.raises(ValueError):
+            PyCanTransportInterface.receive_packet(self.mock_can_transport_interface, timeout)
+
+    @pytest.mark.parametrize("timeout", [0.001, 123.456])
+    def test_receive_packet__timeout_error__no_message(self, timeout):
+        mock_is_timeout_reached = Mock(return_value=False)
+        self.mock_time.return_value = MagicMock(__sub__=lambda this, other: this,
+                                                __rsub__=lambda this, other: this,
+                                                __le__=mock_is_timeout_reached)
+        mock_get_message = Mock(return_value=None)
+        self.mock_can_transport_interface._PyCanTransportInterface__frames_buffer = Mock(get_message=mock_get_message)
+        with pytest.raises(TimeoutError):
+            PyCanTransportInterface.receive_packet(self.mock_can_transport_interface, timeout)
+        mock_get_message.assert_called_once()
+
+    @pytest.mark.parametrize("timeout", [0.001, 123.456])
+    def test_receive_packet__timeout_error__out_of_time(self, timeout):
+        mock_is_timeout_reached = Mock(return_value=True)
+        self.mock_time.return_value = MagicMock(__sub__=lambda this, other: this,
+                                                __rsub__=lambda this, other: this,
+                                                __le__=mock_is_timeout_reached)
+        mock_get_message = Mock()
+        self.mock_can_transport_interface._PyCanTransportInterface__frames_buffer = Mock(get_message=mock_get_message)
+        with pytest.raises(TimeoutError):
+            PyCanTransportInterface.receive_packet(self.mock_can_transport_interface, timeout)
+        mock_is_timeout_reached.assert_called_once_with(0)
+
+    @pytest.mark.parametrize("timeout", [None, 0.001, 123.456])
+    def test_receive_packet(self, timeout):
+        mock_is_timeout_reached = Mock(return_value=False)
+        self.mock_time.return_value = self.mock_can_transport_interface._MAX_LISTENER_TIMEOUT \
+            = MagicMock(__sub__=lambda this, other: this,
+                        __rsub__=lambda this, other: this,
+                        __le__=mock_is_timeout_reached)
+        mock_get_message = Mock()
+        self.mock_can_transport_interface._PyCanTransportInterface__frames_buffer = Mock(get_message=mock_get_message)
+        assert PyCanTransportInterface.receive_packet(self.mock_can_transport_interface, timeout) \
+               == self.mock_can_packet_record.return_value
+        self.mock_datetime.fromtimestamp.assert_called_once_with(mock_get_message.return_value.timestamp)
+        self.mock_can_transport_interface.segmenter.is_input_packet.assert_called_once_with(
+            can_id=mock_get_message.return_value.arbitration_id,
+            data=mock_get_message.return_value.data)
+        self.mock_can_packet_record.assert_called_once_with(
+            frame=mock_get_message.return_value,
+            direction=TransmissionDirection.RECEIVED,
+            addressing_type=self.mock_can_transport_interface.segmenter.is_input_packet.return_value,
+            addressing_format=self.mock_can_transport_interface.segmenter.addressing_format,
+            transmission_time=self.mock_datetime.fromtimestamp.return_value)
+
+    # async_send_packet
+
+    @pytest.mark.parametrize("packet", ["something", Mock()])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    @pytest.mark.asyncio
+    async def test_async_send_packet__type_error(self, mock_isinstance, packet):
+        mock_isinstance.return_value = False
+        with pytest.raises(TypeError):
+            await PyCanTransportInterface.async_send_packet(self.mock_can_transport_interface, packet)
+        mock_isinstance.assert_called_once_with(packet, CanPacket)
+
+    @pytest.mark.parametrize("packet", [
+        Mock(spec=CanPacket, packet_type=CanPacketType.FIRST_FRAME, raw_frame_data=(0x12, 0x34)),
+        Mock(spec=CanPacket, packet_type=CanPacketType.FLOW_CONTROL, raw_frame_data=tuple(range(8))),
+        Mock(spec=CanPacket, packet_type=CanPacketType.CONSECUTIVE_FRAME, raw_frame_data=tuple(range(64, 128))),
+    ])
+    @pytest.mark.asyncio
+    async def test_async_send_packet(self, packet):
+        mock_get_message = Mock(return_value=MagicMock(arbitration_id=packet.can_id,
+                                                       data=packet.raw_frame_data,
+                                                       is_rx=True,
+                                                       timestamp=MagicMock(__lt__=Mock(return_value=False))))
+        self.mock_can_transport_interface._PyCanTransportInterface__async_frames_buffer = Mock(get_message=mock_get_message)
+        self.mock_can_transport_interface._PyCanTransportInterface__n_ar_measured = None
+        self.mock_can_transport_interface._PyCanTransportInterface__n_as_measured = None
+        assert await PyCanTransportInterface.async_send_packet(self.mock_can_transport_interface, packet) \
+               == self.mock_can_packet_record.return_value
+        self.mock_can_id_handler.is_extended_can_id.assert_called_once_with(packet.can_id)
+        self.mock_can_dlc_handler.is_can_fd_specific_dlc.assert_called_once_with(packet.dlc)
+        self.mock_message.assert_called_once_with(arbitration_id=packet.can_id,
+                                                  is_extended_id=self.mock_can_id_handler.is_extended_can_id.return_value,
+                                                  data=packet.raw_frame_data,
+                                                  is_fd=self.mock_can_dlc_handler.is_can_fd_specific_dlc.return_value)
+        self.mock_can_transport_interface.bus_manager.send.assert_called_once_with(self.mock_message.return_value)
+        self.mock_datetime.fromtimestamp.assert_called_once_with(mock_get_message.return_value.timestamp)
+        self.mock_can_packet_record.assert_called_once_with(frame=mock_get_message.return_value,
+                                                            direction=TransmissionDirection.TRANSMITTED,
+                                                            addressing_type=packet.addressing_type,
+                                                            addressing_format=packet.addressing_format,
+                                                            transmission_time=self.mock_datetime.fromtimestamp.return_value)
+        if packet.packet_type == CanPacketType.FLOW_CONTROL:
+            assert self.mock_can_transport_interface._PyCanTransportInterface__n_as_measured is None
+            assert self.mock_can_transport_interface._PyCanTransportInterface__n_ar_measured \
+                   == mock_get_message.return_value.timestamp.__sub__.return_value
+            mock_get_message.return_value.timestamp.__sub__.assert_called_once_with(self.mock_time.return_value)
+        else:
+            assert self.mock_can_transport_interface._PyCanTransportInterface__n_as_measured \
+                   == mock_get_message.return_value.timestamp.__sub__.return_value
+            assert self.mock_can_transport_interface._PyCanTransportInterface__n_ar_measured is None
+            mock_get_message.return_value.timestamp.__sub__.assert_called_once_with(self.mock_time.return_value)
+
+    # async_receive_packet
+
+    @pytest.mark.parametrize("timeout", ["something", Mock()])
+    @patch(f"{SCRIPT_LOCATION}.isinstance")
+    @pytest.mark.asyncio
+    async def test_async_receive_packet__type_error(self, mock_isinstance, timeout):
+        mock_isinstance.return_value = False
+        with pytest.raises(TypeError):
+            await PyCanTransportInterface.async_receive_packet(self.mock_can_transport_interface, timeout)
+        mock_isinstance.assert_called_once_with(timeout, (int, float))
+
+    @pytest.mark.parametrize("timeout", [0, -654])
+    @pytest.mark.asyncio
+    async def test_async_receive_packet__value_error(self, timeout):
+        with pytest.raises(ValueError):
+            await PyCanTransportInterface.async_receive_packet(self.mock_can_transport_interface, timeout)
+
+    @pytest.mark.parametrize("timeout", [0.001, 123.456])
+    @pytest.mark.asyncio
+    async def test_async_receive_packet__timeout(self, timeout):
+        mock_is_timeout_reached = Mock(return_value=True)
+        self.mock_time.return_value = MagicMock(__sub__=lambda this, other: this,
+                                                __rsub__=lambda this, other: this,
+                                                __le__=mock_is_timeout_reached)
+        mock_get_message = Mock()
+        self.mock_can_transport_interface._PyCanTransportInterface__async_frames_buffer = Mock(get_message=mock_get_message)
+        with pytest.raises(TimeoutError):
+            await PyCanTransportInterface.async_receive_packet(self.mock_can_transport_interface, timeout)
+        mock_is_timeout_reached.assert_called_once_with(0)
+
+    @pytest.mark.parametrize("timeout", [None, 0.001, 123.456])
+    @pytest.mark.asyncio
+    async def test_async_receive_packet(self, timeout):
+        mock_is_timeout_reached = Mock(return_value=False)
+        self.mock_time.return_value = MagicMock(__sub__=lambda this, other: this,
+                                                __rsub__=lambda this, other: this,
+                                                __le__=mock_is_timeout_reached)
+        mock_get_message = Mock()
+        self.mock_can_transport_interface._PyCanTransportInterface__async_frames_buffer = Mock(get_message=mock_get_message)
+        assert await PyCanTransportInterface.async_receive_packet(self.mock_can_transport_interface, timeout) \
+               == self.mock_can_packet_record.return_value
+        self.mock_datetime.fromtimestamp.assert_called_once_with(mock_get_message.return_value.timestamp)
+        self.mock_can_transport_interface.segmenter.is_input_packet.assert_called_once_with(
+            can_id=mock_get_message.return_value.arbitration_id,
+            data=mock_get_message.return_value.data)
+        self.mock_can_packet_record.assert_called_once_with(
+            frame=mock_get_message.return_value,
+            direction=TransmissionDirection.RECEIVED,
+            addressing_type=self.mock_can_transport_interface.segmenter.is_input_packet.return_value,
+            addressing_format=self.mock_can_transport_interface.segmenter.addressing_format,
+            transmission_time=self.mock_datetime.fromtimestamp.return_value)
+
+
+@pytest.mark.integration
+class TestPyCanTransportInterfaceIntegration:
+    """Integration tests for `PyCanTransportInterface` class."""
+
+    @pytest.mark.parametrize("init_kwargs", [
+        {
+            "can_bus_manager": Mock(spec=BusABC),
+            "addressing_information": CanAddressingInformation(
+                addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+                rx_physical={"can_id": 0x641},
+                tx_physical={"can_id": 0x642},
+                rx_functional={"can_id": 0x6FE},
+                tx_functional={"can_id": 0x6FF}),
+        },
+        {
+            "can_bus_manager": Mock(spec=BusABC),
+            "addressing_information": CanAddressingInformation(
+                addressing_format=CanAddressingFormat.MIXED_29BIT_ADDRESSING,
+                tx_physical={"target_address": 0x1B, "source_address": 0xFF, "address_extension": 0x87},
+                rx_physical={"target_address": 0xFF, "source_address": 0x1B, "address_extension": 0x87},
+                tx_functional={"target_address": 0xAC, "source_address": 0xFE, "address_extension": 0xFF},
+                rx_functional={"target_address": 0xFE, "source_address": 0xAC, "address_extension": 0xFF}),
+            "n_as_timeout": 0.1,
+            "n_ar_timeout": 987,
+            "n_bs_timeout": 43,
+            "n_br": 5.3,
+            "n_cs": 0.92,
+            "n_cr_timeout": 98.32,
+        },
+    ])
+    def test_init(self, init_kwargs):
+        py_can_ti = PyCanTransportInterface(**init_kwargs)
+        assert py_can_ti.bus_manager == init_kwargs["can_bus_manager"]
+        assert py_can_ti.addressing_information == init_kwargs["addressing_information"]
+        assert py_can_ti.n_as_measured is None
+        assert py_can_ti.n_ar_measured is None
+        assert py_can_ti.n_bs_measured is None
+        assert py_can_ti.n_cr_measured is None
+        assert py_can_ti.n_as_timeout == init_kwargs.get("n_as_timeout", AbstractCanTransportInterface.N_AS_TIMEOUT)
+        assert py_can_ti.n_ar_timeout == init_kwargs.get("n_ar_timeout", AbstractCanTransportInterface.N_AR_TIMEOUT)
+        assert py_can_ti.n_bs_timeout == init_kwargs.get("n_bs_timeout", AbstractCanTransportInterface.N_BS_TIMEOUT)
+        assert py_can_ti.n_br == init_kwargs.get("n_br", AbstractCanTransportInterface.DEFAULT_N_BR)
+        assert py_can_ti.n_cs == init_kwargs.get("n_cs", AbstractCanTransportInterface.DEFAULT_N_CS)
+        assert py_can_ti.n_cr_timeout == init_kwargs.get("n_cr_timeout", AbstractCanTransportInterface.N_CR_TIMEOUT)
diff --git a/tests/software_tests/transport_interface/test_python_can_transport_interface.py b/tests/software_tests/transport_interface/test_python_can_transport_interface.py
deleted file mode 100644
index 3abf02d7..00000000
--- a/tests/software_tests/transport_interface/test_python_can_transport_interface.py
+++ /dev/null
@@ -1,127 +0,0 @@
-import pytest
-from mock import Mock, patch
-
-from uds.transport_interface.python_can_transport_interface import PyCanTransportInterface, \
-    BusABC, AbstractTransportInterface
-from uds.can import CanAddressingInformation, CanAddressingFormat
-
-
-class TestPyCanTransportInterface:
-    """Unit tests for `PyCanTransportInterface` class."""
-
-    SCRIPT_LOCATION = "uds.transport_interface.python_can_transport_interface"
-
-    def setup(self):
-        self.mock_can_transport_interface = Mock(spec=PyCanTransportInterface)
-        # patching
-        self._patcher_abstract_can_ti_init = patch(f"{self.SCRIPT_LOCATION}.AbstractCanTransportInterface.__init__")
-        self.mock_abstract_can_ti_init = self._patcher_abstract_can_ti_init.start()
-
-    def teardown(self):
-        self._patcher_abstract_can_ti_init.stop()
-
-    # __init__
-
-    @pytest.mark.parametrize("can_bus_manager, addressing_information", [
-        ("can_bus_manager", "addressing_information"),
-        (Mock(), Mock())
-    ])
-    def test_init__default_args(self, can_bus_manager, addressing_information):
-        PyCanTransportInterface.__init__(self=self.mock_can_transport_interface,
-                                         can_bus_manager=can_bus_manager,
-                                         addressing_information=addressing_information)
-        self.mock_abstract_can_ti_init.assert_called_once_with(
-            can_bus_manager=can_bus_manager,
-            addressing_information=addressing_information,
-            packet_records_number=AbstractTransportInterface.DEFAULT_PACKET_RECORDS_NUMBER,
-            message_records_number=AbstractTransportInterface.DEFAULT_MESSAGE_RECORDS_NUMBER)
-        assert self.mock_can_transport_interface._PyCanTransportInterface__n_as_measured is None
-        assert self.mock_can_transport_interface._PyCanTransportInterface__n_ar_measured is None
-        assert self.mock_can_transport_interface._PyCanTransportInterface__n_bs_measured is None
-        assert self.mock_can_transport_interface._PyCanTransportInterface__n_cr_measured is None
-
-    @pytest.mark.parametrize("can_bus_manager, addressing_information", [
-        ("can_bus_manager", "addressing_information"),
-        (Mock(), Mock())
-    ])
-    @pytest.mark.parametrize("packet_records_number, message_records_number, kwargs", [
-        (1, 2, {"a": Mock(), "b": Mock()}),
-        (Mock(), Mock(), {"param1": Mock(), "param2": Mock(), "something_else": Mock()}),
-    ])
-    def test_init__all_args(self, can_bus_manager, addressing_information,
-                            packet_records_number, message_records_number, kwargs):
-        PyCanTransportInterface.__init__(self=self.mock_can_transport_interface,
-                                         can_bus_manager=can_bus_manager,
-                                         addressing_information=addressing_information,
-                                         packet_records_number=packet_records_number,
-                                         message_records_number=message_records_number,
-                                         **kwargs)
-        self.mock_abstract_can_ti_init.assert_called_once_with(
-            can_bus_manager=can_bus_manager,
-            addressing_information=addressing_information,
-            packet_records_number=packet_records_number,
-            message_records_number=message_records_number,
-            **kwargs)
-        assert self.mock_can_transport_interface._PyCanTransportInterface__n_as_measured is None
-        assert self.mock_can_transport_interface._PyCanTransportInterface__n_ar_measured is None
-        assert self.mock_can_transport_interface._PyCanTransportInterface__n_bs_measured is None
-        assert self.mock_can_transport_interface._PyCanTransportInterface__n_cr_measured is None
-
-    # n_as_measured
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_n_as_measured(self, value):
-        self.mock_can_transport_interface._PyCanTransportInterface__n_as_measured = value
-        assert PyCanTransportInterface.n_as_measured.fget(self.mock_can_transport_interface) == value
-
-    # n_as_measured
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_n_ar_measured(self, value):
-        self.mock_can_transport_interface._PyCanTransportInterface__n_ar_measured = value
-        assert PyCanTransportInterface.n_ar_measured.fget(self.mock_can_transport_interface) == value
-            
-    # n_bs_measured
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_n_bs_measured(self, value):
-        self.mock_can_transport_interface._PyCanTransportInterface__n_bs_measured = value
-        assert PyCanTransportInterface.n_bs_measured.fget(self.mock_can_transport_interface) == value
-            
-    # n_cr_measured
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_n_cr_measured(self, value):
-        self.mock_can_transport_interface._PyCanTransportInterface__n_cr_measured = value
-        assert PyCanTransportInterface.n_cr_measured.fget(self.mock_can_transport_interface) == value
-            
-    # is_supported_bus_manager
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_is_supported_bus_manager(self, mock_isinstance, value):
-        assert PyCanTransportInterface.is_supported_bus_manager(value) == mock_isinstance.return_value
-        mock_isinstance.assert_called_once_with(value, BusABC)
-
-
-class TestPyCanTransportInterfaceIntegration:
-    """Integration tests for `PyCanTransportInterface` class."""
-
-    @pytest.mark.parametrize("init_kwargs", [
-        {
-            "can_bus_manager": Mock(spec=BusABC),
-            "addressing_information": CanAddressingInformation(
-                addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
-                rx_physical={"can_id": 0x641},
-                tx_physical={"can_id": 0x642},
-                rx_functional={"can_id": 0x6FE},
-                tx_functional={"can_id": 0x6FF},
-            ),
-        }
-    ])
-    def test_init(self, init_kwargs):
-        py_can_ti = PyCanTransportInterface(**init_kwargs)
-        assert py_can_ti.n_as_measured is None
-        assert py_can_ti.n_ar_measured is None
-        assert py_can_ti.n_bs_measured is None
-        assert py_can_ti.n_cr_measured is None
diff --git a/tests/software_tests/transport_interface/test_records_queue.py b/tests/software_tests/transport_interface/test_records_queue.py
deleted file mode 100644
index fffc281d..00000000
--- a/tests/software_tests/transport_interface/test_records_queue.py
+++ /dev/null
@@ -1,184 +0,0 @@
-import pytest
-from copy import deepcopy
-from mock import AsyncMock, Mock, patch
-
-from uds.transport_interface.records_queue import RecordsQueue, \
-    UdsMessageRecord, AbstractUdsPacketRecord
-
-
-class TestRecordsQueue:
-    """Unit tests for 'RecordsQueue' class."""
-
-    SCRIPT_LOCATION = "uds.transport_interface.records_queue"
-
-    def setup(self):
-        self.mock_records_queue = Mock(spec=RecordsQueue)
-        # patching
-        self._patcher_event_class = patch(f"{self.SCRIPT_LOCATION}.Event")
-        self.mock_event_class = self._patcher_event_class.start()
-
-    def teardown(self):
-        self._patcher_event_class.stop()
-
-    # __init__
-
-    @pytest.mark.parametrize("records_type, history_size", [
-        (Mock(), Mock()),
-        ("some type", "some history size"),
-    ])
-    @patch(f"{SCRIPT_LOCATION}.issubclass")
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_init__type_error__records_type(self, mock_isinstance, mock_issubclass, records_type, history_size):
-        mock_isinstance.return_value = True
-        mock_issubclass.return_value = False
-        with pytest.raises(TypeError):
-            RecordsQueue.__init__(self=self.mock_records_queue,
-                                  records_type=records_type,
-                                  history_size=history_size)
-        mock_issubclass.assert_called_once_with(records_type, (UdsMessageRecord, AbstractUdsPacketRecord))
-
-    @pytest.mark.parametrize("records_type, history_size", [
-        (Mock(), Mock()),
-        ("some type", "some history size"),
-    ])
-    @patch(f"{SCRIPT_LOCATION}.issubclass")
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_init__type_error__history_size(self, mock_isinstance, mock_issubclass, records_type, history_size):
-        mock_isinstance.return_value = False
-        mock_issubclass.return_value = True
-        with pytest.raises(TypeError):
-            RecordsQueue.__init__(self=self.mock_records_queue,
-                                  records_type=records_type,
-                                  history_size=history_size)
-        mock_isinstance.assert_called_once_with(history_size, int)
-
-    @pytest.mark.parametrize("records_type", [Mock(), "some type"])
-    @patch(f"{SCRIPT_LOCATION}.issubclass")
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_init__value_error(self, mock_isinstance, mock_issubclass, records_type):
-        mock_isinstance.return_value = True
-        mock_issubclass.return_value = True
-        mock_le = Mock(return_value=True)
-        mock_history_size = Mock(__le__=mock_le)
-        with pytest.raises(ValueError):
-            RecordsQueue.__init__(self=self.mock_records_queue,
-                                  records_type=records_type,
-                                  history_size=mock_history_size)
-        mock_isinstance.assert_called_once_with(mock_history_size, int)
-        mock_issubclass.assert_called_once_with(records_type, (UdsMessageRecord, AbstractUdsPacketRecord))
-        mock_le.assert_called_once_with(0)
-
-    @pytest.mark.parametrize("records_type", [Mock(), "some type"])
-    @patch(f"{SCRIPT_LOCATION}.issubclass")
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_init__valid(self, mock_isinstance, mock_issubclass, records_type):
-        mock_isinstance.return_value = True
-        mock_issubclass.return_value = True
-        mock_le = Mock(return_value=False)
-        mock_history_size = Mock(__le__=mock_le)
-        assert RecordsQueue.__init__(self=self.mock_records_queue,
-                                     records_type=records_type,
-                                     history_size=mock_history_size) is None
-        mock_isinstance.assert_called_once_with(mock_history_size, int)
-        mock_issubclass.assert_called_once_with(records_type, (UdsMessageRecord, AbstractUdsPacketRecord))
-        mock_le.assert_called_once_with(0)
-        self.mock_event_class.assert_called_once_with()
-        assert self.mock_records_queue._RecordsQueue__records_type == records_type
-        assert self.mock_records_queue._RecordsQueue__history_size == mock_history_size
-        assert self.mock_records_queue._RecordsQueue__total_records_number == 0
-        assert self.mock_records_queue._RecordsQueue__records_history == []
-        assert self.mock_records_queue._RecordsQueue__event_new_record == self.mock_event_class.return_value
-
-    # records_type
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_records_type__get(self, value):
-        self.mock_records_queue._RecordsQueue__records_type = value
-        assert RecordsQueue.records_type.fget(self.mock_records_queue) == value
-        
-    # history_size
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_history_size__get(self, value):
-        self.mock_records_queue._RecordsQueue__history_size = value
-        assert RecordsQueue.history_size.fget(self.mock_records_queue) == value
-        
-    # total_records_number
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_total_records_number__get(self, value):
-        self.mock_records_queue._RecordsQueue__total_records_number = value
-        assert RecordsQueue.total_records_number.fget(self.mock_records_queue) == value
-
-    # records_history
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    @patch(f"{SCRIPT_LOCATION}.tuple")
-    def test_records_history__get(self, mock_tuple, value):
-        self.mock_records_queue._RecordsQueue__records_history = value
-        assert RecordsQueue.records_history.fget(self.mock_records_queue) == mock_tuple.return_value
-        mock_tuple.assert_called_once_with(value)
-
-    # clear_records_history
-
-    def test_clear_records_history(self):
-        assert RecordsQueue.clear_records_history(self.mock_records_queue) is None
-        assert self.mock_records_queue._RecordsQueue__records_history == []
-        assert self.mock_records_queue._RecordsQueue__total_records_number == 0
-
-    # put_record
-
-    @pytest.mark.parametrize("record", ["some record", Mock()])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_put_record__type_error(self, mock_isinstance, record):
-        mock_isinstance.return_value = False
-        with pytest.raises(TypeError):
-            RecordsQueue.put_record(self=self.mock_records_queue, record=record)
-        mock_isinstance.assert_called_once_with(record, self.mock_records_queue.records_type)
-
-    @pytest.mark.parametrize("records_history, history_size", [
-        ([], 0),
-        (list(range(10)), 15),
-        (["record 1", "record 2"], 2),
-    ])
-    @pytest.mark.parametrize("record, total_records_number", [
-        ("some record", 0),
-        (Mock(), 12325),
-    ])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_put_record__valid(self, mock_isinstance, record, total_records_number, records_history, history_size):
-        mock_isinstance.return_value = True
-        self.mock_records_queue._RecordsQueue__total_records_number = total_records_number
-        self.mock_records_queue._RecordsQueue__records_history = deepcopy(records_history)
-        self.mock_records_queue._RecordsQueue__event_new_record = Mock()
-        self.mock_records_queue.history_size = history_size
-        assert RecordsQueue.put_record(self=self.mock_records_queue, record=record) is None
-        mock_isinstance.assert_called_once_with(record, self.mock_records_queue.records_type)
-        self.mock_records_queue._RecordsQueue__event_new_record.set.assert_called_once_with()
-        assert self.mock_records_queue._RecordsQueue__records_history == ([record] + records_history)[:history_size]
-        assert self.mock_records_queue._RecordsQueue__total_records_number == total_records_number + 1
-
-    # get_next_record
-
-    @pytest.mark.asyncio
-    @pytest.mark.parametrize("records_history", [
-        (Mock(), Mock(), Mock(), Mock()),
-        tuple(range(100)),
-    ])
-    @pytest.mark.parametrize("records_number_1, records_number_2", [
-        (0, 1),
-        (5, 8),
-        (65, 67),
-    ])
-    async def test_get_next_record(self, records_history, records_number_1, records_number_2):
-        def _update_records_number():
-            self.mock_records_queue.total_records_number = records_number_2
-
-        self.mock_records_queue.records_history = records_history
-        self.mock_records_queue.total_records_number = records_number_1
-        self.mock_records_queue._RecordsQueue__event_new_record \
-            = Mock(wait=AsyncMock(side_effect=_update_records_number))
-        assert await RecordsQueue.get_next_record(self=self.mock_records_queue) \
-               == records_history[records_number_2 - records_number_1 - 1]
-        self.mock_records_queue._RecordsQueue__event_new_record.clear.assert_called_once_with()
-        self.mock_records_queue._RecordsQueue__event_new_record.wait.assert_awaited_once_with()
diff --git a/tests/software_tests/transport_interface/test_transmission_queue.py b/tests/software_tests/transport_interface/test_transmission_queue.py
deleted file mode 100644
index 41537dcc..00000000
--- a/tests/software_tests/transport_interface/test_transmission_queue.py
+++ /dev/null
@@ -1,248 +0,0 @@
-import pytest
-from mock import AsyncMock, MagicMock, Mock, patch, call
-from copy import deepcopy
-
-from uds.transport_interface.transmission_queue import TransmissionQueue, \
-    UdsMessage, AbstractUdsPacket, QueueEmpty, Event, AsyncioTimeoutError, PriorityQueue
-
-
-class TestTransmissionQueue:
-    """Unit tests for 'TransmissionQueue' class."""
-
-    SCRIPT_LOCATION = "uds.transport_interface.transmission_queue"
-
-    def setup(self):
-        self.mock_transmission_queue = Mock(spec=TransmissionQueue,
-                                            _TransmissionQueue__timestamps=MagicMock(spec=set),
-                                            _TransmissionQueue__event_pdu_added=MagicMock(spec=Event,
-                                                                                          wait=AsyncMock()),
-                                            _TransmissionQueue__async_queue=MagicMock(spec=PriorityQueue,
-                                                                                      get=AsyncMock(),
-                                                                                      put=AsyncMock(),
-                                                                                      join=AsyncMock()))
-        # patching
-        self._patcher_len = patch(f"{self.SCRIPT_LOCATION}.len")
-        self.mock_len = self._patcher_len.start()
-        self._patcher_priority_queue_class = patch(f"{self.SCRIPT_LOCATION}.PriorityQueue")
-        self.mock_priority_queue_class = self._patcher_priority_queue_class.start()
-        self._patcher_event_class = patch(f"{self.SCRIPT_LOCATION}.Event")
-        self.mock_event_class = self._patcher_event_class.start()
-        self._patcher_wait_for = patch(f"{self.SCRIPT_LOCATION}.wait_for")
-        self.mock_wait_for = self._patcher_wait_for.start()
-        self._patcher_warn = patch(f"{self.SCRIPT_LOCATION}.warn")
-        self.mock_warn = self._patcher_warn.start()
-        self._patcher_perf_counter = patch(f"{self.SCRIPT_LOCATION}.perf_counter")
-        self.mock_perf_counter = self._patcher_perf_counter.start()
-
-    def teardown(self):
-        self._patcher_len.stop()
-        self._patcher_priority_queue_class.stop()
-        self._patcher_event_class.stop()
-        self._patcher_wait_for.stop()
-        self._patcher_warn.stop()
-        self._patcher_perf_counter.stop()
-
-    # __init__
-
-    @pytest.mark.parametrize("pdu_type", ["something", Mock()])
-    @patch(f"{SCRIPT_LOCATION}.issubclass")
-    def test_init__type_error(self, mock_issubclass, pdu_type):
-        mock_issubclass.return_value = False
-        with pytest.raises(TypeError):
-            TransmissionQueue.__init__(self=self.mock_transmission_queue, pdu_type=pdu_type)
-        mock_issubclass.assert_called_once_with(pdu_type, (UdsMessage, AbstractUdsPacket))
-
-    @pytest.mark.parametrize("pdu_type", ["something", Mock()])
-    @patch(f"{SCRIPT_LOCATION}.issubclass")
-    def test_init__valid(self, mock_issubclass, pdu_type):
-        mock_issubclass.return_value = True
-        assert TransmissionQueue.__init__(self=self.mock_transmission_queue, pdu_type=pdu_type) is None
-        mock_issubclass.assert_called_once_with(pdu_type, (UdsMessage, AbstractUdsPacket))
-        self.mock_event_class.assert_called_once_with()
-        assert self.mock_transmission_queue._TransmissionQueue__pdu_type == pdu_type
-        assert self.mock_transmission_queue._TransmissionQueue__async_queue \
-               == self.mock_priority_queue_class.return_value
-        assert self.mock_transmission_queue._TransmissionQueue__event_pdu_added \
-               == self.mock_event_class.return_value
-        assert self.mock_transmission_queue._TransmissionQueue__timestamps == set()
-
-    # __len__
-
-    def test_len(self):
-        mock_len = Mock()
-        self.mock_transmission_queue._TransmissionQueue__async_queue = Mock(qsize=mock_len)
-        assert TransmissionQueue.__len__(self=self.mock_transmission_queue) == mock_len.return_value
-
-    # __pdu_ready
-
-    @pytest.mark.asyncio
-    @pytest.mark.parametrize("current_timestamp, timestamps", [
-        (0, {0, 0.1}),
-        (100, {43.123, 102, 150})
-    ])
-    async def test_pdu_ready__now(self, current_timestamp, timestamps):
-        self.mock_perf_counter.return_value = current_timestamp
-        self.mock_transmission_queue._TransmissionQueue__timestamps = deepcopy(timestamps)
-        assert await TransmissionQueue._TransmissionQueue__pdu_ready(self=self.mock_transmission_queue) \
-               == min(timestamps)
-        self.mock_perf_counter.assert_called_once_with()
-        assert self.mock_transmission_queue._TransmissionQueue__timestamps == timestamps
-
-    @pytest.mark.asyncio
-    @pytest.mark.parametrize("current_timestamp, next_timestamp", [
-        (0, 2.56789),
-        (9654.4312965, 93921321.2315312),
-    ])
-    async def test_pdu_ready__await_packet(self, current_timestamp, next_timestamp):
-        self.mock_perf_counter.side_effect = [current_timestamp, next_timestamp]
-        self.mock_transmission_queue._TransmissionQueue__timestamps = set()
-        self.mock_wait_for.side_effect \
-            = lambda *args, **kwargs: self.mock_transmission_queue._TransmissionQueue__timestamps.add(next_timestamp)
-        assert await TransmissionQueue._TransmissionQueue__pdu_ready(self=self.mock_transmission_queue) \
-               == next_timestamp
-        self.mock_wait_for.assert_awaited_once()  # TODO: https://stackoverflow.com/questions/70448262/how-to-use-asyncmock-and-get-coroutines-futures-returned-from-call
-        assert self.mock_wait_for.mock_calls[0].kwargs["timeout"] == float("inf")
-        self.mock_perf_counter.assert_has_calls([call(), call()])
-        assert self.mock_transmission_queue._TransmissionQueue__timestamps == {next_timestamp}
-
-    @pytest.mark.asyncio
-    @pytest.mark.parametrize("current_timestamp, timestamps", [
-        (0, {1, 0.1}),
-        (100, {983221, 102, 150})
-    ])
-    async def test_pdu_ready__await_timestamp(self, current_timestamp, timestamps):
-        self.mock_perf_counter.return_value = current_timestamp
-        self.mock_transmission_queue._TransmissionQueue__timestamps = deepcopy(timestamps)
-        self.mock_wait_for.side_effect = AsyncioTimeoutError
-        assert await TransmissionQueue._TransmissionQueue__pdu_ready(self=self.mock_transmission_queue) \
-               == min(timestamps)
-        self.mock_wait_for.assert_awaited_once()  # TODO: https://stackoverflow.com/questions/70448262/how-to-use-asyncmock-and-get-coroutines-futures-returned-from-call
-        assert self.mock_wait_for.mock_calls[0].kwargs["timeout"] == min(timestamps) - current_timestamp
-        self.mock_perf_counter.assert_called_once_with()
-        assert self.mock_transmission_queue._TransmissionQueue__timestamps == timestamps
-
-    # pdu_type
-
-    @pytest.mark.parametrize("value", ["something", Mock()])
-    def test_pdu_type__get(self, value):
-        self.mock_transmission_queue._TransmissionQueue__pdu_type = value
-        assert TransmissionQueue.pdu_type.fget(self.mock_transmission_queue) == value
-
-    # is_empty
-
-    @pytest.mark.parametrize("value", [True, False])
-    def test_is_empty(self, value):
-        mock_eq = Mock(return_value=value)
-        self.mock_len.return_value = MagicMock(__eq__=mock_eq)
-        assert TransmissionQueue.is_empty.fget(self.mock_transmission_queue) is value
-        mock_eq.assert_called_once_with(0)
-
-    # mark_pdu_sent
-
-    def test_mark_pdu_sent(self):
-        mock_task_done = Mock()
-        self.mock_transmission_queue._TransmissionQueue__async_queue = Mock(task_done=mock_task_done)
-        assert TransmissionQueue.mark_pdu_sent(self=self.mock_transmission_queue) is None
-        mock_task_done.assert_called_once_with()
-
-    # clear
-
-    @pytest.mark.parametrize("packets_number", [0, 1, 99])
-    def test_clear(self, packets_number):
-        self.mock_len.return_value = packets_number
-        mock_get_nowait = Mock()
-        self.mock_transmission_queue._TransmissionQueue__async_queue = Mock(get_nowait=mock_get_nowait)
-        assert TransmissionQueue.clear(self=self.mock_transmission_queue) is None
-        self.mock_len.assert_called_once_with(self.mock_transmission_queue)
-        mock_get_nowait.assert_has_calls([call()] * packets_number)
-        self.mock_warn.assert_not_called()
-        self.mock_transmission_queue.mark_pdu_sent.assert_has_calls([call()] * packets_number)
-
-    @pytest.mark.parametrize("packets_number", [1, 99])
-    def test_clear__queue_empty(self, packets_number):
-        self.mock_len.return_value = packets_number
-        mock_get_nowait = Mock(side_effect=QueueEmpty)
-        self.mock_transmission_queue._TransmissionQueue__async_queue = Mock(get_nowait=mock_get_nowait)
-        assert TransmissionQueue.clear(self=self.mock_transmission_queue) is None
-        self.mock_len.assert_called_once_with(self.mock_transmission_queue)
-        mock_get_nowait.assert_called_once()
-        self.mock_warn.assert_called_once()
-        self.mock_transmission_queue.mark_pdu_sent.assert_not_called()
-
-    # get_pdu
-
-    @pytest.mark.asyncio
-    @pytest.mark.parametrize("pdu_timestamp", [123.456, 0.91784])
-    @pytest.mark.parametrize("pdu", ["something", Mock()])
-    async def test_get_pdu(self, pdu_timestamp, pdu):
-        self.mock_transmission_queue._TransmissionQueue__pdu_ready.return_value = pdu_timestamp
-        self.mock_transmission_queue._TransmissionQueue__async_queue.get_nowait.return_value = [pdu_timestamp, pdu]
-        assert await TransmissionQueue.get_pdu(self=self.mock_transmission_queue) == pdu
-        self.mock_transmission_queue._TransmissionQueue__pdu_ready.assert_awaited_once_with()
-        self.mock_transmission_queue._TransmissionQueue__async_queue.get_nowait.assert_called_once_with()
-        self.mock_transmission_queue._TransmissionQueue__timestamps.remove.assert_called_once_with(pdu_timestamp)
-
-    @pytest.mark.asyncio
-    @pytest.mark.parametrize("min_timestamp, pdu_timestamp", [
-        (1, 2),
-        (9.5, 3.123),
-    ])
-    @pytest.mark.parametrize("pdu", ["something", Mock()])
-    async def test_get_pdu__runtime_error(self, min_timestamp, pdu_timestamp, pdu):
-        self.mock_transmission_queue._TransmissionQueue__pdu_ready.return_value = min_timestamp
-        self.mock_transmission_queue._TransmissionQueue__async_queue.get_nowait.return_value = [pdu_timestamp, pdu]
-        with pytest.raises(RuntimeError):
-            await TransmissionQueue.get_pdu(self=self.mock_transmission_queue)
-        self.mock_transmission_queue._TransmissionQueue__pdu_ready.assert_awaited_once_with()
-        self.mock_transmission_queue._TransmissionQueue__async_queue.get_nowait.assert_called_once_with()
-
-    # put_pdu
-
-    @pytest.mark.parametrize("pdu", [Mock(), "a pdu"])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_put_pdu__type_error__pdu(self, mock_isinstance, pdu):
-        mock_isinstance.return_value = False
-        with pytest.raises(TypeError):
-            TransmissionQueue.put_pdu(self=self.mock_transmission_queue, pdu=pdu)
-        mock_isinstance.assert_called_once_with(pdu, self.mock_transmission_queue.pdu_type)
-
-    @pytest.mark.parametrize("pdu, timestamp", [
-        (Mock(), Mock()),
-        ("a pdu", "some timestamp")
-    ])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_put_pdu__type_error__timestamp(self, mock_isinstance, pdu, timestamp):
-        mock_isinstance.side_effect = [True, False]
-        with pytest.raises(TypeError):
-            TransmissionQueue.put_pdu(self=self.mock_transmission_queue,
-                                      pdu=pdu,
-                                      timestamp=timestamp)
-        mock_isinstance.assert_has_calls([call(pdu, self.mock_transmission_queue.pdu_type),
-                                          call(timestamp, float)])
-
-    @pytest.mark.parametrize("pdu", [Mock(), "a pdu"])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_put_pdu__without_timestamp(self, mock_isinstance, pdu):
-        mock_isinstance.return_value = True
-        timestamp = self.mock_perf_counter.return_value
-        assert TransmissionQueue.put_pdu(self=self.mock_transmission_queue, pdu=pdu) is None
-        mock_isinstance.assert_called_once_with(pdu, self.mock_transmission_queue.pdu_type)
-        self.mock_transmission_queue._TransmissionQueue__async_queue.put_nowait.assert_called_once_with((timestamp, pdu))
-        self.mock_transmission_queue._TransmissionQueue__timestamps.add.assert_called_once_with(timestamp)
-        self.mock_transmission_queue._TransmissionQueue__event_pdu_added.set.assert_called_once_with()
-
-    @pytest.mark.parametrize("pdu, timestamp", [
-        (Mock(), Mock()),
-        ("a pdu", "some timestamp")
-    ])
-    @patch(f"{SCRIPT_LOCATION}.isinstance")
-    def test_put_pdu__with_timestamp(self, mock_isinstance, pdu, timestamp):
-        mock_isinstance.return_value = True
-        assert TransmissionQueue.put_pdu(self=self.mock_transmission_queue,
-                                         pdu=pdu,
-                                         timestamp=timestamp) is None
-        mock_isinstance.assert_has_calls([call(pdu, self.mock_transmission_queue.pdu_type),
-                                          call(timestamp, float)])
-        self.mock_transmission_queue._TransmissionQueue__async_queue.put_nowait.assert_called_once_with((timestamp, pdu))
-        self.mock_transmission_queue._TransmissionQueue__timestamps.add.assert_called_once_with(timestamp)
-        self.mock_transmission_queue._TransmissionQueue__event_pdu_added.set.assert_called_once_with()
diff --git a/tests/software_tests/utilities/test_bytes_operations.py b/tests/software_tests/utilities/test_bytes_operations.py
index af9f3a18..05585d76 100644
--- a/tests/software_tests/utilities/test_bytes_operations.py
+++ b/tests/software_tests/utilities/test_bytes_operations.py
@@ -6,6 +6,9 @@
     InconsistentArgumentsError
 
 
+SCRIPT_LOCATION = "uds.utilities.bytes_operations"
+
+
 class TestEndianness:
     """Unit tests for `Endianness` class."""
 
@@ -16,15 +19,13 @@ def test_inheritance_validated_enum(self):
 class TestFunctions:
     """Unit tests for module functions."""
 
-    SCRIPT_LOCATION = "uds.utilities.bytes_operations"
-
-    def setup(self):
-        self._patcher_validate_raw_bytes = patch(f"{self.SCRIPT_LOCATION}.validate_raw_bytes")
+    def setup_method(self):
+        self._patcher_validate_raw_bytes = patch(f"{SCRIPT_LOCATION}.validate_raw_bytes")
         self.mock_validate_raw_bytes = self._patcher_validate_raw_bytes.start()
-        self._patcher_validate_endianness = patch(f"{self.SCRIPT_LOCATION}.Endianness.validate_member")
+        self._patcher_validate_endianness = patch(f"{SCRIPT_LOCATION}.Endianness.validate_member")
         self.mock_validate_endianness = self._patcher_validate_endianness.start()
 
-    def teardown(self):
+    def teardown_method(self):
         self._patcher_validate_raw_bytes.stop()
         self._patcher_validate_endianness.stop()
 
diff --git a/tests/software_tests/utilities/test_enums.py b/tests/software_tests/utilities/test_enums.py
index 786f2d83..68d6e1e5 100644
--- a/tests/software_tests/utilities/test_enums.py
+++ b/tests/software_tests/utilities/test_enums.py
@@ -5,6 +5,9 @@
 from uds.utilities.enums import ExtendableEnum, ValidatedEnum, ByteEnum, NibbleEnum
 
 
+SCRIPT_LOCATION = "uds.utilities.enums"
+
+
 class TestByteEnum:
     """
     Tests for `ByteEnum` class.
@@ -72,8 +75,6 @@ class TestValidatedEnum:
         In fact these are integration tests, but we were unable to effectively mock enum and it is not worth the effort.
     """
 
-    SCRIPT_LOCATION = "uds.utilities.enums"
-
     class ExampleByteEnum1(ValidatedEnum):
         A = 0
         B = 987654321
@@ -182,8 +183,6 @@ def test_add_member__existing_value(self, enum_class, name, value):
 class TestMultipleEnums:
     """Integration tests for multiple Enum classes."""
 
-    SCRIPT_LOCATION = "uds.utilities.enums"
-
     class ExtendableByteEnumWithValidated(ByteEnum, ValidatedEnum, ExtendableEnum):
         V1 = 11
         V2 = 0x11
diff --git a/tests/system_tests/__init__.py b/tests/system_tests/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/system_tests/transport_interface/__init__.py b/tests/system_tests/transport_interface/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/system_tests/transport_interface/can_transport_interface/__init__.py b/tests/system_tests/transport_interface/can_transport_interface/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/system_tests/transport_interface/can_transport_interface/test_python_can.py b/tests/system_tests/transport_interface/can_transport_interface/test_python_can.py
new file mode 100644
index 00000000..d574271b
--- /dev/null
+++ b/tests/system_tests/transport_interface/can_transport_interface/test_python_can.py
@@ -0,0 +1,923 @@
+import pytest
+import asyncio
+from threading import Timer
+from time import time, sleep
+from datetime import datetime
+from can import Bus, Message
+
+from uds.can import CanAddressingInformation, CanAddressingFormat, CanFlowStatus
+from uds.transport_interface import PyCanTransportInterface
+from uds.transmission_attributes import AddressingType, TransmissionDirection
+from uds.packet import CanPacket, CanPacketType, CanPacketRecord
+from uds.message import UdsMessage
+
+
+class TestPythonCanKvaser:
+    """
+    System Tests for `PyCanTransportInterface` with Kvaser as bus manager.
+
+    Hardware setup:
+        - two Kvaser interfaces (either https://www.kvaser.com/products-services/our-products/#/?pc_int=usb)
+          connected with each in the same CAN bus (do not forget about CAN termination)
+    """
+
+    TASK_TIMING_TOLERANCE = 30.  # ms
+
+    def setup_class(self):
+        self.can_interface_1 = Bus(interface="kvaser", channel=0, fd=True, receive_own_messages=True)
+        self.can_interface_2 = Bus(interface="kvaser", channel=1, fd=True, receive_own_messages=True)
+
+    def setup_method(self):
+        self.can_interface_1.flush_tx_buffer()
+        self.can_interface_2.flush_tx_buffer()
+
+    def teardown_class(self):
+        """Safely close bus objects."""
+        self.can_interface_1.shutdown()
+        self.can_interface_2.shutdown()
+
+    # send_packet
+
+    @pytest.mark.parametrize("packet_type, addressing_type, addressing_information, packet_type_specific_kwargs", [
+        (CanPacketType.SINGLE_FRAME,
+         AddressingType.FUNCTIONAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x611},
+                                  rx_physical={"can_id": 0x612},
+                                  tx_functional={"can_id": 0x6FF},
+                                  rx_functional={"can_id": 0x6FE}),
+         {"filler_byte": 0x1E, "payload": [0x10, 0x04]}),
+        (CanPacketType.FIRST_FRAME,
+         AddressingType.PHYSICAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC}),
+         {"dlc": 8, "payload": [0x22, 0x10, 0x00, 0x10, 0x01, 0x10], "data_length": 0x13}),
+        (CanPacketType.CONSECUTIVE_FRAME,
+         AddressingType.PHYSICAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.EXTENDED_ADDRESSING,
+                                  tx_physical={"can_id": 0x987, "target_address": 0x90},
+                                  rx_physical={"can_id": 0x987, "target_address": 0xFE},
+                                  tx_functional={"can_id": 0x11765, "target_address": 0x5A},
+                                  rx_functional={"can_id": 0x11765, "target_address": 0xFF}),
+         {"payload": [0x32, 0xFF], "sequence_number": 0xF}),
+        (CanPacketType.FLOW_CONTROL,
+         AddressingType.PHYSICAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x651, "address_extension": 0x87},
+                                  rx_physical={"can_id": 0x652, "address_extension": 0xFE},
+                                  tx_functional={"can_id": 0x6FF, "address_extension": 0xA5},
+                                  rx_functional={"can_id": 0x6FF, "address_extension": 0xFF}),
+         {"dlc": 8, "flow_status": CanFlowStatus.ContinueToSend, "block_size": 0x15, "st_min": 0xFE}),
+        (CanPacketType.SINGLE_FRAME,
+         AddressingType.PHYSICAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_29BIT_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF, "address_extension": 0x87},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B, "address_extension": 0x87},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE, "address_extension": 0xFF},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC, "address_extension": 0xFF}),
+         {"filler_byte": 0xBC, "payload": [0x22, 0x12, 0x34, 0x12, 0x56, 0x12, 0x78, 0x12, 0x9A, 0x12, 0xBC], "dlc":0xF}),
+    ])
+    def test_send_packet(self, packet_type, addressing_type, addressing_information, packet_type_specific_kwargs):
+        """
+        Check for simple sending of a CAN packet.
+
+        Procedure:
+        1. Send CAN packet via Transport Interface.
+            Expected: CAN packet record returned.
+        2. Validate transmitted CAN packet record attributes.
+            Expected: Attributes of CAN packet record are in line with the transmitted CAN packet.
+
+        :param packet_type: Type of CAN Packet to send.
+        :param addressing_type: Addressing type to use for transmitting a CAN packet.
+        :param addressing_information: Example Addressing Information of a CAN Node.
+        :param packet_type_specific_kwargs: Parameters specific for this CAN Packet type.
+        """
+        if addressing_type == AddressingType.PHYSICAL:
+            can_id = addressing_information.tx_packets_physical_ai["can_id"]
+            target_address = addressing_information.tx_packets_physical_ai["target_address"]
+            source_address = addressing_information.tx_packets_physical_ai["source_address"]
+            address_extension = addressing_information.tx_packets_physical_ai["address_extension"]
+        else:
+            can_id = addressing_information.tx_packets_functional_ai["can_id"]
+            target_address = addressing_information.tx_packets_functional_ai["target_address"]
+            source_address = addressing_information.tx_packets_functional_ai["source_address"]
+            address_extension = addressing_information.tx_packets_functional_ai["address_extension"]
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=addressing_information)
+        packet = CanPacket(packet_type=packet_type,
+                           addressing_format=addressing_information.addressing_format,
+                           addressing_type=addressing_type,
+                           can_id=can_id,
+                           target_address=target_address,
+                           source_address=source_address,
+                           address_extension=address_extension,
+                           **packet_type_specific_kwargs)
+        datetime_before_send = datetime.now()
+        packet_record = can_transport_interface.send_packet(packet)
+        datetime_after_send = datetime.now()
+        assert isinstance(packet_record, CanPacketRecord)
+        assert packet_record.direction == TransmissionDirection.TRANSMITTED
+        assert packet_record.raw_frame_data == packet.raw_frame_data
+        assert packet_record.addressing_format == packet.addressing_format == addressing_information.addressing_format
+        assert packet_record.packet_type == packet.packet_type == packet_type
+        assert packet_record.can_id == packet.can_id == can_id
+        assert packet_record.addressing_type == packet.addressing_type == addressing_type
+        assert packet_record.target_address == packet.target_address == target_address
+        assert packet_record.source_address == packet.source_address == source_address
+        assert packet_record.address_extension == packet.address_extension == address_extension
+        # performance checks
+        # TODO: https://github.com/mdabrowski1990/uds/issues/228 - uncomment when resolved
+        # assert datetime_before_send < packet_record.transmission_time < datetime_after_send
+
+    # receive_packet
+
+    @pytest.mark.parametrize("addressing_type, addressing_information, frame", [
+        (AddressingType.PHYSICAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x611},
+                                  rx_physical={"can_id": 0x612},
+                                  tx_functional={"can_id": 0x6FF},
+                                  rx_functional={"can_id": 0x6FE}),
+         Message(data=[0x02, 0x10, 0x03])),
+        (AddressingType.PHYSICAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC}),
+         Message(data=[0x2C] + list(range(100, 163)), is_fd=True)),
+        (AddressingType.FUNCTIONAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.EXTENDED_ADDRESSING,
+                                  tx_physical={"can_id": 0x987, "target_address": 0x90},
+                                  rx_physical={"can_id": 0x987, "target_address": 0xFE},
+                                  tx_functional={"can_id": 0x11765, "target_address": 0x5A},
+                                  rx_functional={"can_id": 0x11765, "target_address": 0xFF}, ),
+         Message(data=[0xFF, 0x30, 0xAB, 0x7F])),
+        (AddressingType.FUNCTIONAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x651, "address_extension": 0x87},
+                                  rx_physical={"can_id": 0x652, "address_extension": 0xFE},
+                                  tx_functional={"can_id": 0x6FF, "address_extension": 0xA5},
+                                  rx_functional={"can_id": 0x6FF, "address_extension": 0xFF}, ),
+         Message(data=[0xFF, 0x11, 0x23, 0x62, 0x92, 0xD0, 0xB1, 0x00])),
+        (AddressingType.FUNCTIONAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_29BIT_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF,
+                                               "address_extension": 0x87},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B,
+                                               "address_extension": 0x87},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE,
+                                                 "address_extension": 0xFF},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC,
+                                                 "address_extension": 0xFF}, ),
+         Message(data=[0xFF, 0x02, 0x3E, 0x80, 0xAA, 0xAA, 0xAA, 0xAA])),
+    ])
+    @pytest.mark.parametrize("timeout, send_after", [
+        (1000, 1001),  # ms
+        (50, 55),
+    ])
+    def test_receive_packet__timeout(self, addressing_information, addressing_type, frame, timeout, send_after):
+        """
+        Check for a timeout during packet receiving.
+
+        Procedure:
+        1. Schedule transmission (using second CAN interface) of a CAN frame that carries received CAN packet.
+        2. Call method to receive packet via Transport Interface with timeout set just before CAN packet reaches CAN bus.
+            Expected: Timeout exception is raised.
+
+        :param addressing_type: Addressing type to use for transmitting a CAN packet.
+        :param addressing_information: Example Addressing Information of CAN Node.
+        :param frame: CAN frame to send (must be decoded as UDS CAN Packet).
+        :param timeout: Timeout to pass to receive method [ms].
+        :param send_after: Time when to send CAN frame after call of receive method [ms].
+        """
+        if addressing_type == AddressingType.PHYSICAL:
+            frame.arbitration_id = addressing_information.rx_packets_physical_ai["can_id"]
+        else:
+            frame.arbitration_id = addressing_information.rx_packets_functional_ai["can_id"]
+        # data parameter of `frame` object must be set manually and according to `addressing_format`
+        # and `addressing_information`
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=addressing_information)
+        Timer(interval=send_after/1000., function=self.can_interface_2.send, args=(frame,)).start()
+        time_before_receive = time()
+        with pytest.raises(TimeoutError):
+            can_transport_interface.receive_packet(timeout=timeout)
+        time_after_receive = time()
+        assert timeout < (time_after_receive - time_before_receive) * 1000. < timeout + self.TASK_TIMING_TOLERANCE
+
+    @pytest.mark.parametrize("addressing_information, frame", [
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x611},
+                                  rx_physical={"can_id": 0x612},
+                                  tx_functional={"can_id": 0x6FF},
+                                  rx_functional={"can_id": 0x6FE}),
+         Message(data=[0x02, 0x10, 0x03])),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC}),
+         Message(data=[0x2C] + list(range(100, 163)), is_fd=True)),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.EXTENDED_ADDRESSING,
+                                  tx_physical={"can_id": 0x987, "target_address": 0x90},
+                                  rx_physical={"can_id": 0x987, "target_address": 0xFE},
+                                  tx_functional={"can_id": 0x11765, "target_address": 0x5A},
+                                  rx_functional={"can_id": 0x11765, "target_address": 0xFF}),
+         Message(data=[0xFE, 0x30, 0xAB, 0x7F])),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x651, "address_extension": 0x87},
+                                  rx_physical={"can_id": 0x652, "address_extension": 0xFE},
+                                  tx_functional={"can_id": 0x6FF, "address_extension": 0xA5},
+                                  rx_functional={"can_id": 0x6FF, "address_extension": 0xFF}),
+         Message(data=[0xFE, 0x11, 0x23, 0x62, 0x92, 0xD0, 0xB1, 0x00])),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_29BIT_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF, "address_extension": 0x87},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B, "address_extension": 0x87},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE, "address_extension": 0xFF},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC, "address_extension": 0xFF}),
+         Message(data=[0x87, 0x02, 0x3E, 0x80, 0xAA, 0xAA, 0xAA, 0xAA])),
+    ])
+    @pytest.mark.parametrize("timeout, send_after", [
+        (1000, 950),  # ms
+        (50, 20),
+    ])
+    def test_receive_packet__physical(self, addressing_information, frame, timeout, send_after):
+        """
+        Check for a simple CAN packet (physically addressed) receiving.
+
+        Procedure:
+        1. Schedule transmission (using second CAN interface) of a CAN frame that carries received CAN packet.
+        2. Call method to receive packet via Transport Interface with timeout set just after CAN packet reaches CAN bus.
+            Expected: CAN packet is received.
+        3. Validate received CAN packet record attributes.
+            Expected: Attributes of CAN packet record are in line with the received CAN packet.
+
+        :param addressing_information: Example Addressing Information of CAN Node.
+        :param frame: CAN frame to send (must be decoded as UDS CAN Packet).
+        :param timeout: Timeout to pass to receive method [ms].
+        :param send_after: Time when to send CAN frame after call of receive method [ms].
+        """
+        frame.arbitration_id = addressing_information.rx_packets_physical_ai["can_id"]
+        # data parameter of `frame` object must be set manually and according to `addressing_format`
+        # and `addressing_information`
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=addressing_information)
+        Timer(interval=send_after/1000., function=self.can_interface_2.send, args=(frame,)).start()
+        datetime_before_receive = datetime.now()
+        packet_record = can_transport_interface.receive_packet(timeout=timeout)
+        datetime_after_receive = datetime.now()
+        assert isinstance(packet_record, CanPacketRecord)
+        assert packet_record.direction == TransmissionDirection.RECEIVED
+        assert packet_record.raw_frame_data == tuple(frame.data)
+        assert packet_record.addressing_format == addressing_information.addressing_format
+        assert packet_record.addressing_type == AddressingType.PHYSICAL
+        assert packet_record.can_id == frame.arbitration_id == addressing_information.rx_packets_physical_ai["can_id"]
+        assert packet_record.target_address == addressing_information.rx_packets_physical_ai["target_address"]
+        assert packet_record.source_address == addressing_information.rx_packets_physical_ai["source_address"]
+        assert packet_record.address_extension == addressing_information.rx_packets_physical_ai["address_extension"]
+        # performance checks
+        assert send_after <= (datetime_after_receive - datetime_before_receive).total_seconds() * 1000. < timeout
+        # TODO: https://github.com/mdabrowski1990/uds/issues/228 - uncomment when resolved
+        # assert datetime_before_receive < packet_record.transmission_time < datetime_after_receive
+
+    @pytest.mark.parametrize("addressing_information, frame", [
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x611},
+                                  rx_physical={"can_id": 0x612},
+                                  tx_functional={"can_id": 0x6FF},
+                                  rx_functional={"can_id": 0x6FE}),
+         Message(data=[0x02, 0x10, 0x03])),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC}),
+         Message(data=[0x2C] + list(range(100, 163)), is_fd=True)),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.EXTENDED_ADDRESSING,
+                                  tx_physical={"can_id": 0x987, "target_address": 0x90},
+                                  rx_physical={"can_id": 0x987, "target_address": 0xFE},
+                                  tx_functional={"can_id": 0x11765, "target_address": 0x5A},
+                                  rx_functional={"can_id": 0x11765, "target_address": 0xFF},),
+         Message(data=[0xFF, 0x30, 0xAB, 0x7F])),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x651, "address_extension": 0x87},
+                                  rx_physical={"can_id": 0x652, "address_extension": 0xFE},
+                                  tx_functional={"can_id": 0x6FF, "address_extension": 0xA5},
+                                  rx_functional={"can_id": 0x6FF, "address_extension": 0xFF}, ),
+         Message(data=[0xFF, 0x11, 0x23, 0x62, 0x92, 0xD0, 0xB1, 0x00])),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_29BIT_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF, "address_extension": 0x87},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B, "address_extension": 0x87},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE, "address_extension": 0xFF},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC, "address_extension": 0xFF}, ),
+         Message(data=[0xFF, 0x02, 0x3E, 0x80, 0xAA, 0xAA, 0xAA, 0xAA])),
+    ])
+    @pytest.mark.parametrize("timeout, send_after", [
+        (1000, 950),  # ms
+        (50, 20),
+    ])
+    def test_receive_packet__functional(self, addressing_information, frame, timeout, send_after):
+        """
+        Check for a simple CAN packet (functionally addressed) receiving.
+
+        Procedure:
+        1. Schedule transmission (using second CAN interface) of a CAN frame that carries received CAN packet.
+        2. Call method to receive packet via Transport Interface with timeout set just after CAN packet reaches CAN bus.
+            Expected: CAN packet is received.
+        3. Validate received CAN packet record attributes.
+            Expected: Attributes of CAN packet record are in line with the received CAN packet.
+
+        :param addressing_information: Example Addressing Information of CAN Node.
+        :param frame: CAN frame to send (must be decoded as UDS CAN Packet).
+        :param timeout: Timeout to pass to receive method [ms].
+        :param send_after: Time when to send CAN frame after call of receive method [ms].
+        """
+        frame.arbitration_id = addressing_information.rx_packets_functional_ai["can_id"]
+        # data parameter of `frame` object must be set manually and according to `addressing_format`
+        # and `addressing_information`
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=addressing_information)
+        Timer(interval=send_after/1000., function=self.can_interface_2.send, args=(frame,)).start()
+        datetime_before_receive = datetime.now()
+        packet_record = can_transport_interface.receive_packet(timeout=timeout)
+        datetime_after_receive = datetime.now()
+        assert isinstance(packet_record, CanPacketRecord)
+        assert packet_record.direction == TransmissionDirection.RECEIVED
+        assert packet_record.raw_frame_data == tuple(frame.data)
+        assert packet_record.addressing_format == addressing_information.addressing_format
+        assert packet_record.addressing_type == AddressingType.FUNCTIONAL
+        assert packet_record.can_id == frame.arbitration_id == addressing_information.rx_packets_functional_ai["can_id"]
+        assert packet_record.target_address == addressing_information.rx_packets_functional_ai["target_address"]
+        assert packet_record.source_address == addressing_information.rx_packets_functional_ai["source_address"]
+        assert packet_record.address_extension == addressing_information.rx_packets_functional_ai["address_extension"]
+        # performance checks
+        assert send_after <= (datetime_after_receive - datetime_before_receive).total_seconds() * 1000. < timeout
+        # TODO: https://github.com/mdabrowski1990/uds/issues/228 - uncomment when resolved
+        # assert datetime_before_receive < packet_record.transmission_time < datetime_after_receive
+
+    # async_send_packet
+
+    @pytest.mark.parametrize("packet_type, addressing_type, addressing_information, packet_type_specific_kwargs", [
+        (CanPacketType.SINGLE_FRAME,
+         AddressingType.FUNCTIONAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x611},
+                                  rx_physical={"can_id": 0x612},
+                                  tx_functional={"can_id": 0x6FF},
+                                  rx_functional={"can_id": 0x6FE}),
+         {"filler_byte": 0x1E, "payload": [0x10, 0x04]}),
+        (CanPacketType.FIRST_FRAME,
+         AddressingType.PHYSICAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC}),
+         {"dlc": 8, "payload": [0x22, 0x10, 0x00, 0x10, 0x01, 0x10], "data_length": 0x13}),
+        (CanPacketType.CONSECUTIVE_FRAME,
+         AddressingType.PHYSICAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.EXTENDED_ADDRESSING,
+                                  tx_physical={"can_id": 0x987, "target_address": 0x90},
+                                  rx_physical={"can_id": 0x987, "target_address": 0xFE},
+                                  tx_functional={"can_id": 0x11765, "target_address": 0x5A},
+                                  rx_functional={"can_id": 0x11765, "target_address": 0xFF}),
+         {"payload": [0x32, 0xFF], "sequence_number": 0xF}),
+        (CanPacketType.FLOW_CONTROL,
+         AddressingType.PHYSICAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x651, "address_extension": 0x87},
+                                  rx_physical={"can_id": 0x652, "address_extension": 0xFE},
+                                  tx_functional={"can_id": 0x6FF, "address_extension": 0xA5},
+                                  rx_functional={"can_id": 0x6FF, "address_extension": 0xFF}),
+         {"dlc": 8, "flow_status": CanFlowStatus.ContinueToSend, "block_size": 0x15, "st_min": 0xFE}),
+        (CanPacketType.SINGLE_FRAME,
+         AddressingType.PHYSICAL,
+         CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_29BIT_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF, "address_extension": 0x87},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B, "address_extension": 0x87},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE, "address_extension": 0xFF},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC, "address_extension": 0xFF}),
+         {"filler_byte": 0xBC, "payload": [0x22, 0x12, 0x34, 0x12, 0x56, 0x12, 0x78, 0x12, 0x9A, 0x12, 0xBC], "dlc":0xF}),
+    ])
+    @pytest.mark.asyncio
+    async def test_async_send_packet(self, packet_type, addressing_type, addressing_information, packet_type_specific_kwargs):
+        """
+        Check for simple asynchronous sending of a CAN packet.
+
+        Procedure:
+        1. Send (using async method) a CAN packet via Transport Interface.
+            Expected: CAN packet record returned.
+        2. Validate transmitted CAN packet record attributes.
+            Expected: Attributes of CAN packet record are in line with the transmitted CAN packet.
+
+        :param packet_type: Type of CAN Packet to send.
+        :param addressing_type: Addressing type to use for transmitting a CAN packet.
+        :param addressing_information: Example Addressing Information of a CAN Node.
+        :param packet_type_specific_kwargs: Parameters specific for this CAN Packet type.
+        """
+        if addressing_type == AddressingType.PHYSICAL:
+            can_id = addressing_information.tx_packets_physical_ai["can_id"]
+            target_address = addressing_information.tx_packets_physical_ai["target_address"]
+            source_address = addressing_information.tx_packets_physical_ai["source_address"]
+            address_extension = addressing_information.tx_packets_physical_ai["address_extension"]
+        else:
+            can_id = addressing_information.tx_packets_functional_ai["can_id"]
+            target_address = addressing_information.tx_packets_functional_ai["target_address"]
+            source_address = addressing_information.tx_packets_functional_ai["source_address"]
+            address_extension = addressing_information.tx_packets_functional_ai["address_extension"]
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=addressing_information)
+        packet = CanPacket(packet_type=packet_type,
+                           addressing_format=addressing_information.addressing_format,
+                           addressing_type=addressing_type,
+                           can_id=can_id,
+                           target_address=target_address,
+                           source_address=source_address,
+                           address_extension=address_extension,
+                           **packet_type_specific_kwargs)
+        datetime_before_send = datetime.now()
+        packet_record = await can_transport_interface.async_send_packet(packet)
+        datetime_after_send = datetime.now()
+        assert isinstance(packet_record, CanPacketRecord)
+        assert packet_record.direction == TransmissionDirection.TRANSMITTED
+        assert packet_record.raw_frame_data == packet.raw_frame_data
+        assert packet_record.addressing_format == packet.addressing_format == addressing_information.addressing_format
+        assert packet_record.packet_type == packet.packet_type == packet_type
+        assert packet_record.can_id == packet.can_id == can_id
+        assert packet_record.addressing_type == packet.addressing_type == addressing_type
+        assert packet_record.target_address == packet.target_address == target_address
+        assert packet_record.source_address == packet.source_address == source_address
+        assert packet_record.address_extension == packet.address_extension == address_extension
+        # performance checks
+        # TODO: https://github.com/mdabrowski1990/uds/issues/228 - uncomment when resolved
+        # assert datetime_before_send < packet_record.transmission_time < datetime_after_send
+
+    # async_receive_packet
+
+    @pytest.mark.parametrize("timeout", [1000, 50])
+    @pytest.mark.asyncio
+    async def test_async_receive_packet__timeout(self, example_addressing_information, timeout):
+        """
+        Check for a timeout during packet asynchronous receiving.
+
+        Procedure:
+        1. Call async method to receive packet via Transport Interface with timeout set just before CAN packet reaches CAN bus.
+            Expected: Timeout exception is raised.
+
+        :param example_addressing_information: Example Addressing Information of a CAN Node.
+        :param timeout: Timeout to pass to receive method [ms].
+        """
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=example_addressing_information)
+        time_before_receive = time()
+        with pytest.raises((TimeoutError, asyncio.TimeoutError)):
+            await can_transport_interface.async_receive_packet(timeout=timeout)
+        time_after_receive = time()
+        assert timeout < (time_after_receive - time_before_receive) * 1000. < timeout + self.TASK_TIMING_TOLERANCE
+
+    @pytest.mark.parametrize("addressing_information, frame", [
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x611},
+                                  rx_physical={"can_id": 0x612},
+                                  tx_functional={"can_id": 0x6FF},
+                                  rx_functional={"can_id": 0x6FE}),
+         Message(data=[0x02, 0x10, 0x03])),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC}),
+         Message(data=[0x2C] + list(range(100, 163)), is_fd=True)),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.EXTENDED_ADDRESSING,
+                                  tx_physical={"can_id": 0x987, "target_address": 0x90},
+                                  rx_physical={"can_id": 0x987, "target_address": 0xFE},
+                                  tx_functional={"can_id": 0x11765, "target_address": 0x5A},
+                                  rx_functional={"can_id": 0x11765, "target_address": 0xFF}),
+         Message(data=[0xFE, 0x30, 0xAB, 0x7F])),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x651, "address_extension": 0x87},
+                                  rx_physical={"can_id": 0x652, "address_extension": 0xFE},
+                                  tx_functional={"can_id": 0x6FF, "address_extension": 0xA5},
+                                  rx_functional={"can_id": 0x6FF, "address_extension": 0xFF}),
+         Message(data=[0xFE, 0x11, 0x23, 0x62, 0x92, 0xD0, 0xB1, 0x00])),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_29BIT_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF, "address_extension": 0x87},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B, "address_extension": 0x87},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE, "address_extension": 0xFF},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC, "address_extension": 0xFF}),
+         Message(data=[0x87, 0x02, 0x3E, 0x80, 0xAA, 0xAA, 0xAA, 0xAA])),
+    ])
+    @pytest.mark.parametrize("timeout, send_after", [
+        (1000, 950),  # ms
+        (50, 20),
+    ])
+    @pytest.mark.asyncio
+    async def test_async_receive_packet__physical(self, addressing_information, frame, timeout, send_after):
+        """
+        Check for a simple asynchronous CAN packet (physically addressed) receiving.
+
+        Procedure:
+        1. Schedule transmission (using second CAN interface) of a CAN frame that carries received CAN packet.
+        2. Call async method to receive packet via Transport Interface with timeout set just after CAN packet reaches CAN bus.
+            Expected: CAN packet is received.
+        3. Validate received CAN packet record attributes.
+            Expected: Attributes of CAN packet record are in line with the received CAN packet.
+
+        :param addressing_information: Example Addressing Information of CAN Node.
+        :param frame: CAN frame to send (must be decoded as UDS CAN Packet).
+        :param timeout: Timeout to pass to receive method [ms].
+        :param send_after: Time when to send CAN frame after call of receive method [ms].
+        """
+        async def _send_frame():
+            await asyncio.sleep(send_after/1000.)
+            self.can_interface_2.send(frame)
+
+        frame.arbitration_id = addressing_information.rx_packets_physical_ai["can_id"]
+        # data parameter of `frame` object must be set manually and according to `addressing_format`
+        # and `addressing_information`
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=addressing_information)
+        future_record = can_transport_interface.async_receive_packet(timeout=timeout)
+        datetime_before_receive = datetime.now()
+        done_tasks, _ = await asyncio.wait([_send_frame(), future_record])
+        datetime_after_receive = datetime.now()
+        received_records = tuple(filter(lambda result: isinstance(result, CanPacketRecord),
+                                        (done_task.result() for done_task in done_tasks)))
+        assert len(received_records) == 1, "CAN Packet was received"
+        packet_record = received_records[0]
+        assert isinstance(packet_record, CanPacketRecord)
+        assert packet_record.direction == TransmissionDirection.RECEIVED
+        assert packet_record.raw_frame_data == tuple(frame.data)
+        assert packet_record.addressing_format == addressing_information.addressing_format
+        assert packet_record.addressing_type == AddressingType.PHYSICAL
+        assert packet_record.can_id == frame.arbitration_id == addressing_information.rx_packets_physical_ai["can_id"]
+        assert packet_record.target_address == addressing_information.rx_packets_physical_ai["target_address"]
+        assert packet_record.source_address == addressing_information.rx_packets_physical_ai["source_address"]
+        assert packet_record.address_extension == addressing_information.rx_packets_physical_ai["address_extension"]
+        # performance checks
+        assert send_after <= (datetime_after_receive - datetime_before_receive).total_seconds() * 1000. < timeout
+        # TODO: https://github.com/mdabrowski1990/uds/issues/228 - uncomment when resolved
+        # assert datetime_before_receive < packet_record.transmission_time < datetime_after_receive
+
+    @pytest.mark.parametrize("addressing_information, frame", [
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x611},
+                                  rx_physical={"can_id": 0x612},
+                                  tx_functional={"can_id": 0x6FF},
+                                  rx_functional={"can_id": 0x6FE}),
+         Message(data=[0x02, 0x10, 0x03])),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_FIXED_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC}),
+         Message(data=[0x2C] + list(range(100, 163)), is_fd=True)),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.EXTENDED_ADDRESSING,
+                                  tx_physical={"can_id": 0x987, "target_address": 0x90},
+                                  rx_physical={"can_id": 0x987, "target_address": 0xFE},
+                                  tx_functional={"can_id": 0x11765, "target_address": 0x5A},
+                                  rx_functional={"can_id": 0x11765, "target_address": 0xFF},),
+         Message(data=[0xFF, 0x30, 0xAB, 0x7F])),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_11BIT_ADDRESSING,
+                                  tx_physical={"can_id": 0x651, "address_extension": 0x87},
+                                  rx_physical={"can_id": 0x652, "address_extension": 0xFE},
+                                  tx_functional={"can_id": 0x6FF, "address_extension": 0xA5},
+                                  rx_functional={"can_id": 0x6FF, "address_extension": 0xFF}, ),
+         Message(data=[0xFF, 0x11, 0x23, 0x62, 0x92, 0xD0, 0xB1, 0x00])),
+        (CanAddressingInformation(addressing_format=CanAddressingFormat.MIXED_29BIT_ADDRESSING,
+                                  tx_physical={"target_address": 0x1B, "source_address": 0xFF, "address_extension": 0x87},
+                                  rx_physical={"target_address": 0xFF, "source_address": 0x1B, "address_extension": 0x87},
+                                  tx_functional={"target_address": 0xAC, "source_address": 0xFE, "address_extension": 0xFF},
+                                  rx_functional={"target_address": 0xFE, "source_address": 0xAC, "address_extension": 0xFF}, ),
+         Message(data=[0xFF, 0x02, 0x3E, 0x80, 0xAA, 0xAA, 0xAA, 0xAA])),
+    ])
+    @pytest.mark.parametrize("timeout, send_after", [
+        (1000, 950),  # ms
+        (50, 20),
+    ])
+    @pytest.mark.asyncio
+    async def test_async_receive_packet__functional(self, addressing_information, frame, timeout, send_after):
+        """
+        Check for a simple asynchronous CAN packet (functionally addressed) receiving.
+
+        Procedure:
+        1. Schedule transmission (using second CAN interface) of a CAN frame that carries received CAN packet.
+        2. Call async method to receive packet via Transport Interface with timeout set just after CAN packet reaches CAN bus.
+            Expected: CAN packet is received.
+        3. Validate received CAN packet record attributes.
+            Expected: Attributes of CAN packet record are in line with the received CAN packet.
+
+        :param addressing_information: Example Addressing Information of CAN Node.
+        :param frame: CAN frame to send (must be decoded as UDS CAN Packet).
+        :param timeout: Timeout to pass to receive method [ms].
+        :param send_after: Time when to send CAN frame after call of receive method [ms].
+        """
+        async def _send_frame():
+            await asyncio.sleep(send_after/1000.)
+            self.can_interface_2.send(frame)
+
+        frame.arbitration_id = addressing_information.rx_packets_functional_ai["can_id"]
+        # data parameter of `frame` object must be set manually and according to `addressing_format`
+        # and `addressing_information`
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=addressing_information)
+        future_record = can_transport_interface.async_receive_packet(timeout=timeout)
+        datetime_before_receive = datetime.now()
+        done_tasks, _ = await asyncio.wait([_send_frame(), future_record])
+        datetime_after_receive = datetime.now()
+        received_records = tuple(filter(lambda result: isinstance(result, CanPacketRecord),
+                                        (done_task.result() for done_task in done_tasks)))
+        assert len(received_records) == 1, "CAN Packet was received"
+        packet_record = received_records[0]
+        assert isinstance(packet_record, CanPacketRecord)
+        assert packet_record.direction == TransmissionDirection.RECEIVED
+        assert packet_record.raw_frame_data == tuple(frame.data)
+        assert packet_record.addressing_format == addressing_information.addressing_format
+        assert packet_record.addressing_type == AddressingType.FUNCTIONAL
+        assert packet_record.can_id == frame.arbitration_id == addressing_information.rx_packets_functional_ai["can_id"]
+        assert packet_record.target_address == addressing_information.rx_packets_functional_ai["target_address"]
+        assert packet_record.source_address == addressing_information.rx_packets_functional_ai["source_address"]
+        assert packet_record.address_extension == addressing_information.rx_packets_functional_ai["address_extension"]
+        # performance checks
+        assert send_after <= (datetime_after_receive - datetime_before_receive).total_seconds() * 1000. < timeout
+        # TODO: https://github.com/mdabrowski1990/uds/issues/228 - uncomment when resolved
+        # assert datetime_before_receive < packet_record.transmission_time < datetime_after_receive
+
+    # use cases
+
+    @pytest.mark.parametrize("payload, addressing_type", [
+        ([0x22, 0x10, 0xF5], AddressingType.PHYSICAL),
+        ([0x3E, 0x80], AddressingType.FUNCTIONAL),
+    ])
+    def test_send_on_one_receive_on_other_bus(self, example_addressing_information,
+                                              example_addressing_information_2nd_node,
+                                              payload, addressing_type):
+        """
+        Check for sending and receiving CAN Packet using two Transport Interfaces.
+
+        Procedure:
+        1. Send a CAN Packet using Transport Interface 1 (via CAN Interface 1).
+            Expected: CAN packet record returned.
+        2. Receive a CAN Packet using Transport Interface 2 (via CAN Interface 2).
+            Expected: CAN packet is received.
+        3. Validate received CAN packet records attributes.
+            Expected: Attributes of CAN packet records are in line with each other
+                (the same packet was received and transmitted).
+
+        :param example_addressing_information: Addressing Information for a receiving CAN Node.
+        :param example_addressing_information_2nd_node: Addressing Information for a transmitting CAN Node.
+            It is compatible with `example_addressing_information`.
+        :param payload: Payload of CAN Message to send.
+        :param addressing_type: Addressing Type of CAN Message to send.
+        """
+        can_transport_interface_1 = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                            addressing_information=example_addressing_information)
+        can_transport_interface_2 = PyCanTransportInterface(can_bus_manager=self.can_interface_2,
+                                                            addressing_information=example_addressing_information_2nd_node)
+        uds_message = UdsMessage(payload=payload, addressing_type=addressing_type)
+        packet = can_transport_interface_2.segmenter.segmentation(uds_message)[0]
+
+        sent_packet_record = can_transport_interface_2.send_packet(packet)
+        received_packet_record = can_transport_interface_1.receive_packet(timeout=100)
+        assert isinstance(sent_packet_record, CanPacketRecord)
+        assert isinstance(received_packet_record, CanPacketRecord)
+        assert sent_packet_record.direction == TransmissionDirection.TRANSMITTED
+        assert received_packet_record.direction == TransmissionDirection.RECEIVED
+        assert sent_packet_record.addressing_format == received_packet_record.addressing_format
+        assert sent_packet_record.can_id == received_packet_record.can_id
+        assert sent_packet_record.raw_frame_data == received_packet_record.raw_frame_data
+        assert sent_packet_record.addressing_type == received_packet_record.addressing_type
+
+    @pytest.mark.parametrize("payload, addressing_type", [
+        ([0x22, 0x10, 0xF5], AddressingType.PHYSICAL),
+        ([0x3E, 0x80], AddressingType.FUNCTIONAL),
+    ])
+    @pytest.mark.asyncio
+    async def test_async_send_on_one_receive_on_other_bus(self, example_addressing_information,
+                                                          example_addressing_information_2nd_node,
+                                                          payload, addressing_type):
+        """
+        Check for asynchronous sending and receiving CAN Packet using two Transport Interfaces.
+
+        Procedure:
+        1. Send (using async method) a CAN Packet using Transport Interface 1 (via CAN Interface 1).
+            Expected: CAN packet record returned.
+        2. Receive (using async method) a CAN Packet using Transport Interface 2 (via CAN Interface 2).
+            Expected: CAN packet is received.
+        3. Validate received CAN packet records attributes.
+            Expected: Attributes of CAN packet records are in line with each other
+                (the same packet was received and transmitted).
+
+        :param example_addressing_information: Addressing Information for a receiving CAN Node.
+        :param example_addressing_information_2nd_node: Addressing Information for a transmitting CAN Node.
+            It is compatible with `example_addressing_information`.
+        :param payload: Payload of CAN Message to send.
+        :param addressing_type: Addressing Type of CAN Message to send.
+        """
+        can_transport_interface_1 = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                            addressing_information=example_addressing_information)
+        can_transport_interface_2 = PyCanTransportInterface(can_bus_manager=self.can_interface_2,
+                                                            addressing_information=example_addressing_information_2nd_node)
+        uds_message = UdsMessage(payload=payload, addressing_type=addressing_type)
+        packet = can_transport_interface_2.segmenter.segmentation(uds_message)[0]
+        done_tasks, _ = await asyncio.wait([can_transport_interface_2.async_send_packet(packet),
+                                            can_transport_interface_1.async_receive_packet(timeout=100)])
+        packet_record_1, packet_record_2 = [done_task.result() for done_task in done_tasks]
+        assert isinstance(packet_record_1, CanPacketRecord) and isinstance(packet_record_2, CanPacketRecord)
+        assert {packet_record_1.direction, packet_record_2.direction} \
+               == {TransmissionDirection.TRANSMITTED, TransmissionDirection.RECEIVED}
+        assert packet_record_1.addressing_format == packet_record_2.addressing_format
+        assert packet_record_1.can_id == packet_record_2.can_id
+        assert packet_record_1.raw_frame_data == packet_record_2.raw_frame_data
+        assert packet_record_1.addressing_type == packet_record_2.addressing_type
+
+    # error guessing
+
+    @pytest.mark.parametrize("payload, addressing_type", [
+        ([0x62, 0x10, 0xF5, 0x12, 0x34, 0xF0], AddressingType.PHYSICAL),
+        ([0x10, 0x81], AddressingType.FUNCTIONAL),
+    ])
+    def test_timeout_then_send(self, example_addressing_information, payload, addressing_type):
+        """
+        Check for sending a CAN Packet after a timeout exception during receiving.
+
+        Procedure:
+        1. Call method to receive packet via Transport Interface.
+            Expected: Timeout exception is raised.
+        2. Send a CAN packet via Transport Interface.
+            Expected: CAN packet record returned.
+        3. Validate transmitted CAN packet record attributes.
+            Expected: Attributes of CAN packet record are in line with the transmitted CAN packet.
+
+        :param example_addressing_information: Example Addressing Information of a CAN Node.
+        :param payload: Payload of CAN Message to send.
+        :param addressing_type: Addressing Type of CAN Message to send.
+        """
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=example_addressing_information)
+        uds_message = UdsMessage(payload=payload, addressing_type=addressing_type)
+        packet = can_transport_interface.segmenter.segmentation(uds_message)[0]
+        with pytest.raises(TimeoutError):
+            can_transport_interface.receive_packet(timeout=100)
+        packet_record = can_transport_interface.send_packet(packet)
+        assert isinstance(packet_record, CanPacketRecord)
+        assert packet_record.direction == TransmissionDirection.TRANSMITTED
+        assert packet_record.addressing_type == packet.addressing_type == addressing_type
+        assert packet_record.raw_frame_data == packet.raw_frame_data
+        assert packet_record.payload == packet.payload == tuple(payload)
+        assert packet_record.can_id == packet.can_id
+
+    @pytest.mark.parametrize("payload, addressing_type", [
+        ([0x62, 0x10, 0xF5, 0x12, 0x34, 0xF0], AddressingType.PHYSICAL),
+        ([0x10, 0x81], AddressingType.FUNCTIONAL),
+    ])
+    @pytest.mark.asyncio
+    async def test_async_timeout_then_send(self, example_addressing_information, payload, addressing_type):
+        """
+        Check for asynchronous sending a CAN Packet after a timeout exception during asynchronous receiving.
+
+        Procedure:
+        1. Call async method to receive packet via Transport Interface.
+            Expected: Timeout exception is raised.
+        2. Send (using async method) a CAN packet via Transport Interface.
+            Expected: CAN packet record returned.
+        3. Validate transmitted CAN packet record attributes.
+            Expected: Attributes of CAN packet record are in line with the transmitted CAN packet.
+
+        :param example_addressing_information: Example Addressing Information of a CAN Node.
+        :param payload: Payload of CAN Message to send.
+        :param addressing_type: Addressing Type of CAN Message to send.
+        """
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=example_addressing_information)
+        uds_message = UdsMessage(payload=payload, addressing_type=addressing_type)
+        packet = can_transport_interface.segmenter.segmentation(uds_message)[0]
+        with pytest.raises((TimeoutError, asyncio.TimeoutError)):
+            await can_transport_interface.async_receive_packet(timeout=100)
+        packet_record = await can_transport_interface.async_send_packet(packet)
+        assert isinstance(packet_record, CanPacketRecord)
+        assert packet_record.direction == TransmissionDirection.TRANSMITTED
+        assert packet_record.addressing_type == packet.addressing_type == addressing_type
+        assert packet_record.raw_frame_data == packet.raw_frame_data
+        assert packet_record.payload == packet.payload == tuple(payload)
+        assert packet_record.can_id == packet.can_id
+
+    def test_timeout_then_receive(self, example_addressing_information, example_rx_frame):
+        """
+        Check for receiving a CAN Packet after a timeout exception during receiving.
+
+        Procedure:
+        1. Call method to receive packet via Transport Interface.
+            Expected: Timeout exception is raised.
+        2. Send a CAN frame that carries CAN packet targeting configured CAN Node.
+        3. Call method to receive packet via Transport Interface.
+            Expected: CAN packet is received.
+        4. Validate received CAN packet record attributes.
+            Expected: Attributes of CAN packet record are in line with the received CAN packet.
+
+        :param example_addressing_information: Example Addressing Information of a CAN Node.
+        :param example_rx_frame: Example CAN frame that shall be recognized as a CAN packet.
+        """
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=example_addressing_information)
+        with pytest.raises(TimeoutError):
+            can_transport_interface.receive_packet(timeout=100)
+        datetime_before_send = datetime.now()
+        self.can_interface_2.send(example_rx_frame)
+        packet_record = can_transport_interface.receive_packet(timeout=100)
+        assert isinstance(packet_record, CanPacketRecord)
+        assert packet_record.direction == TransmissionDirection.RECEIVED
+        assert packet_record.transmission_time > datetime_before_send
+
+    @pytest.mark.asyncio
+    async def test_async_timeout_then_receive(self, example_addressing_information, example_rx_frame):
+        """
+        Check for asynchronous receiving a CAN Packet after a timeout exception during receiving.
+
+        Procedure:
+        1. Call async method to receive packet via Transport Interface.
+            Expected: Timeout exception is raised.
+        2. Send a CAN frame that carries CAN packet targeting configured CAN Node.
+        3. Call async method to receive packet via Transport Interface.
+            Expected: CAN packet is received.
+        4. Validate received CAN packet record attributes.
+            Expected: Attributes of CAN packet record are in line with the received CAN packet.
+
+        :param example_addressing_information: Example Addressing Information of a CAN Node.
+        :param example_rx_frame: Example CAN frame that shall be recognized as a CAN packet.
+        """
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=example_addressing_information)
+        with pytest.raises((TimeoutError, asyncio.TimeoutError)):
+            await can_transport_interface.async_receive_packet(timeout=100)
+        datetime_before_send = datetime.now()
+        self.can_interface_2.send(example_rx_frame)
+        packet_record = await can_transport_interface.async_receive_packet(timeout=100)
+        assert isinstance(packet_record, CanPacketRecord)
+        assert packet_record.direction == TransmissionDirection.RECEIVED
+        assert packet_record.transmission_time > datetime_before_send
+
+    def test_observe_tx_packet(self, example_addressing_information, example_tx_frame, example_tx_uds_message):
+        """
+        Check for transmitting a CAN Packet after a sending identical CAN frame.
+
+        Procedure:
+        1. Send a CAN frame (which is identical to a future CAN packet) directly using CAN interface.
+        2. Send a CAN packet via Transport Interface.
+            Expected: CAN packet record returned.
+        2. Validate transmitted CAN packet record attributes.
+            Expected: Attributes of CAN packet record are in line with the transmitted CAN packet.
+                Make sure timing confirms that it is packet transmitted in step two.
+
+        :param example_addressing_information: Example Addressing Information of a CAN Node.
+        :param example_tx_frame: Example CAN frame that shall be recognized as a CAN packet.
+        :param example_tx_uds_message: CAN Message carried by CAN packet in example_tx_frame.
+        """
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=example_addressing_information)
+        packet = can_transport_interface.segmenter.segmentation(example_tx_uds_message)[0]
+        self.can_interface_1.send(example_tx_frame)
+        sleep(0.1)
+        datetime_before_send = datetime.now()
+        packet_record = can_transport_interface.send_packet(packet)
+        assert isinstance(packet_record, CanPacketRecord)
+        assert packet_record.direction == TransmissionDirection.TRANSMITTED
+        assert packet_record.raw_frame_data == packet.raw_frame_data == tuple(example_tx_frame.data)
+        assert packet_record.payload == packet.payload
+        assert packet_record.can_id == packet.can_id == example_tx_frame.arbitration_id
+        assert packet_record.transmission_time > datetime_before_send
+
+    @pytest.mark.asyncio
+    async def test_async_observe_tx_packet(self, example_addressing_information, example_tx_frame, example_tx_uds_message):
+        """
+        Check for asynchronous transmitting a CAN Packet after a sending identical CAN frame.
+
+        Procedure:
+        1. Send a CAN frame (which is identical to a future CAN packet) directly using CAN interface.
+        2. Send (using async method) a CAN packet via Transport Interface.
+            Expected: CAN packet record returned.
+        2. Validate transmitted CAN packet record attributes.
+            Expected: Attributes of CAN packet record are in line with the transmitted CAN packet.
+                Make sure timing confirms that it is packet transmitted in step two.
+
+        :param example_addressing_information: Example Addressing Information of a CAN Node.
+        :param example_tx_frame: Example CAN frame that shall be recognized as a CAN packet.
+        :param example_tx_uds_message: CAN Message carried by CAN packet in example_tx_frame.
+        """
+        can_transport_interface = PyCanTransportInterface(can_bus_manager=self.can_interface_1,
+                                                          addressing_information=example_addressing_information)
+        packet = can_transport_interface.segmenter.segmentation(example_tx_uds_message)[0]
+        self.can_interface_1.send(example_tx_frame)
+        sleep(0.1)
+        datetime_before_send = datetime.now()
+        packet_record = await can_transport_interface.async_send_packet(packet)
+        assert isinstance(packet_record, CanPacketRecord)
+        assert packet_record.direction == TransmissionDirection.TRANSMITTED
+        assert packet_record.raw_frame_data == packet.raw_frame_data
+        assert packet_record.payload == packet.payload
+        assert packet_record.can_id == packet.can_id
+        assert packet_record.transmission_time > datetime_before_send
diff --git a/tests/system_tests/transport_interface/conftest.py b/tests/system_tests/transport_interface/conftest.py
new file mode 100644
index 00000000..07c155f6
--- /dev/null
+++ b/tests/system_tests/transport_interface/conftest.py
@@ -0,0 +1,67 @@
+from pytest import fixture
+
+from can import Message
+
+from uds.can import CanAddressingInformation, CanAddressingFormat
+from uds.message import UdsMessage
+from uds.transmission_attributes import AddressingType
+
+
+@fixture
+def example_addressing_information():
+    """Example Addressing Information of a CAN Node."""
+    return CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+                                    tx_physical={"can_id": 0x611},
+                                    rx_physical={"can_id": 0x612},
+                                    tx_functional={"can_id": 0x6FF},
+                                    rx_functional={"can_id": 0x6FE})
+
+
+@fixture
+def example_addressing_information_2nd_node():
+    """
+    Example Addressing Information of a 2nd CAN Node.
+
+    .. note::
+        Values of example_addressing_information and example_addressing_information_2nd_node are compatible, so
+        these two CAN nodes can communicate with each other over physical and functional addressing.
+    """
+    return CanAddressingInformation(addressing_format=CanAddressingFormat.NORMAL_11BIT_ADDRESSING,
+                                    tx_physical={"can_id": 0x612},
+                                    rx_physical={"can_id": 0x611},
+                                    tx_functional={"can_id": 0x6FE},
+                                    rx_functional={"can_id": 0x6FF})
+
+
+@fixture
+def example_rx_frame():
+    """
+    Example CAN Frame containing a CAN Packet with received addressing information.
+
+    .. note::
+        Compatible with example_addressing_information.
+    """
+    return Message(arbitration_id=0x612, data=[0x02, 0x10, 0x03])
+
+
+@fixture
+def example_tx_frame():
+    """
+    Example CAN Frame containing a CAN Packet with transmitted addressing information.
+
+    .. note::
+        Compatible with example_addressing_information.
+    """
+    return Message(arbitration_id=0x611, data=[0x02, 0x50, 0x03, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC])
+
+
+@fixture
+def example_tx_uds_message():
+    """
+    Example CAN Frame containing a CAN Packet with transmitted addressing information.
+
+    .. note::
+        It is the same message as one carried in example_tx_frame.
+        Compatible with example_addressing_information.
+    """
+    return UdsMessage(payload=[0x50, 0x03], addressing_type=AddressingType.PHYSICAL)