diff --git a/docs/source/diagrams/Architecture.drawio b/docs/source/diagrams/Architecture.drawio new file mode 100644 index 00000000..f3b8aa0d --- /dev/null +++ b/docs/source/diagrams/Architecture.drawio @@ -0,0 +1 @@ +7Zxhc6I4GMc/jS+9ERCwL1tqdzvb2+6tnbu5e5dClMxGwoW46n36e5AgWqTg1oAMzHRa8hASkl8S/v5DHRjOcvOJo9D/nXmYDvSRtxkY9wNd10e2Dn/iyDaJTHQZWHDiJSEtC8zIf1gGRzK6Ih6OjjIKxqgg4XHQZUGAXXEUQ5yz9XG2OaPHtYZogXOBmYtoPvoX8YSfRC1zlMU/Y7LwZc12emKJ0rwyEPnIY+uDkDEdGA5nTCRHy42Dadx3abck1z0UnN3fF8eBqHJBhP80bu5Gf/yDnK3297+2a0y/DMcSxk9EV7LB8m7FNu0BuPEwPhToNQ7d+WJJIanB4donAs9C5Mbn1zAAIBYJxIXkOII0gBGIBJjLa1xGKQojsissyeET6j2hLVuJtJo0dcfZKvCwJ3NGP7BwfZmQd465wJvCPtH2PQ0jFLMlFnwLWeQFQysdZnJ0jmVynaE2bRnzDzBPxmM5xOTwWuzLzhDAgaRwDhGjOhFoqCCIfodxj4JFFTj5zvc4C18QX2AhAyEjgcB8+hP6MJKxOaHUYZTFDAMWxBUJFsqTFM/Ta1+ZEGwpE1x2177QXVeZd/ADPeqMfjMHJrTGgbSWpeEnzs6Fw4JIcBg5cRkYRWKNI1EV+zuDPT8YSmEbqliPc6yfZ48QgOEP8+WS2HeLI8qwf5goAwJzulvQfOJ5OPgYGqMUjZbOjHrQmDk0j7NnCMygzz3EvajHs19G92gOcd3YdeKycrgckCIQeVgFriAsQJQIgntqGTXjxMNuMqkRmnliji1DipfQLHjk66PXbY9rj2usT/KTLNVv9Uwyu5cmNUuT7THSMqWiW7Yq9pMceylSRlClRePmv0LKWsRHt2FIiYvidbdTM9j+NRWjENvNiSmb0IpCFKS8HLZcAirjNo8yjUD1h1ecKmUIFSUiCdYl/Wao5UvLsui2NjaHxocq/NDFzu3XeGCG2CVz4l667TU17IHizXe0rdqQ9+54fPYdZxmnwsc8gHW65D7e1mkW15lFvgyfSIDPLdqqUvTTY+kYeFuu3b4FDaTvAv7eJ9crWN/O/Rigbr1L3TdVEqWlD6AzFb9CPlaP43xFr5CH1kv6ZiS9YVa1mjVV7PPefyrpTzw8v3EcQYM7p+nNgh2EUmdSGbb8BsE78v2t4G7h4/Bi8qUI5dkupjK0+f2A9uFSxqeyX6kMTwu1vzIa1e1IVTjsSS9VapEqY0OrKFVUOc923sZKpcoJC2GGo6hjKiWZC1e0fzrJfxCvpFISk6WFj72LqZQilFez15ou6G2iowxH45uokxbOFWU0mt8jtY1elNQiSkxt3LQoyX9aS0XJib2UF46CKO6pTk3Xa3uty86/clJhH/BAnpi2tTNRyveWXp7vn3eljZDnwe/5Kt4k26Fv7RtklxM51/5Cmd2pjYoSHI2LHLtTzksJjeZFjtU7LzWJnHTNa0zkWMXOy4lXXL5isWb8R5cmq3Vtzks6PNrU/RfTFUU0rkdXdMo8KcHRvK7olHlSQuMKdEVvntSjK6xJ0y+fWMXmyYlP1/dIoE7N1F/1TZThMtvX/ZcTFZcyK5TR6ZRZUYKj8ddErE6ZFSU0mn9NxOzNinpEhW01/ZqIWWxWnPhfpG/+NiIuol2area1uRVWl92KIhpX41ZYnXIrSnA07lZYnXIrSmiodCsgmX0v0+7cwZdbGdP/AQ== \ No newline at end of file diff --git a/docs/source/diagrams/KnowledgeBase-Gateway_request.png b/docs/source/diagrams/KnowledgeBase-Gateway_request.png new file mode 100644 index 00000000..57739805 Binary files /dev/null and b/docs/source/diagrams/KnowledgeBase-Gateway_request.png differ diff --git a/docs/source/diagrams/KnowledgeBase-Gateway_response.png b/docs/source/diagrams/KnowledgeBase-Gateway_response.png new file mode 100644 index 00000000..f84f0eeb Binary files /dev/null and b/docs/source/diagrams/KnowledgeBase-Gateway_response.png differ diff --git a/docs/source/diagrams/KnowledgeBase-PDUs.png b/docs/source/diagrams/KnowledgeBase-PDUs.png new file mode 100644 index 00000000..2e1de0f1 Binary files /dev/null and b/docs/source/diagrams/KnowledgeBase-PDUs.png differ diff --git a/docs/source/diagrams/KnowledgeBase.drawio b/docs/source/diagrams/KnowledgeBase.drawio new file mode 100644 index 00000000..48ac4030 --- /dev/null +++ b/docs/source/diagrams/KnowledgeBase.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/source/diagrams/Workflow.drawio b/docs/source/diagrams/Workflow.drawio new file mode 100644 index 00000000..27a48943 --- /dev/null +++ b/docs/source/diagrams/Workflow.drawio @@ -0,0 +1 @@ +7VrRkqI4FP0aa556CgigPnZrd09X7W516cNM78tUCiJkJxIrxFb36yeRIJDQiiwqszVPbW7CTTjn3Ns3CQMwWW6fGVzFf9IQkYFjhdsBmA4cx7ZGI/FHWnaZZTSyMkPEcKgGFYY5/hflTyrrGocorQzklBKOV1VjQJMEBbxig4zRTXXYgpLqrCsYIcMwDyAxrV9xyOPM6ntWYf+CcBSrmX3HyzqWMB+rRqYxDOmmZAKPAzBhlPLs13I7QURil8OSPff0Qe9hXQwlvMkD34E1XTsRmH1xZ0HA0MvWTu+Ul3dI1up9/0IbtV6+yzFgdJ2ESPqxB+BhE2OO5isYyN6NYF3YYr4kqttcVz4JYhxtSya1zmdEl4iznRiS9+aY5ZpRzU1BgG0pW1wCPycFKs6jg+cCF/FDQXMGTK4B0wy9Y4mUhRP5toxGDKVp75Bz3VtD5xvQTWmCegeU590aqFF9KFo4TYVBJDiGIBcI6cihJLyXeU60AgLTFAdVsARGbPdNNKzPXt58k828Md1WWjvV+hBkDlmE+OmkgsJKZjWpKEHtHUGaIQI5fq/m4zr41QyvFIsVF0wPq0zbGoEpXbMAqYfK+VPz41hVP47mJ4PF8LPXwuGl28tjXJOCFjhpI4gt5iU9iNZbqadQg2ycFEOG3mkxnBQN6JVogEa2PW6pGuBpjtzryiZXe0k3L8sVQUtBpACIJnvtQNYqs7QQUufZ6KQAQUMBOr0S4KHm2WntswUINEfgygI0S8xD7fT/Fp7TUHhur4SnZz5X10vbzAd0BV9aeMAQ3hNOcBp3JjirleDsiwnO/yUFp9dnftsCDbiaI+vKgjN3iV9p8kmuMKStJWeXBXeQ3weSE4zO1RSU8ZhGNIHksbAWorQrObBQaOeibFr/+b0SJRhryUvXUlNRupoojf3jB6IU2oC70rCVHJAeWbA2j215ZwWLN6yMFz+yFXQbId7vCGlfoPY7QuzWBarmaNiwTjg7QvT9u3MiQqxbRIh5XDZDdIWS9iXLZaLDulZ0NC1q+rV9uxvXi+3s6NAdDS3NUUfRcfzfwanhwO02Nnwye+Hf/148j8nb0+P93T9449bcVRwLikSeMoOHEO4L/iwmSuEh7a+Qc8SSvcWxgLCmnNEfh3se55hweyI0V8tSvn4s2bhQ0U+8LlY815LrGORO5fEmTiKDZI62vEpmRtuEEsoK5heYEM0ECY4k3YEgEwn7g7wvwAEk96pjicNwn+fqLiCKKwqZ0RY04eq2UiTtTu4k9FrRrru88Wu0pJ8ptrmTqGXF3EJPUSqh6j8nw8twUnsXeVVOzF2mfqDbe24uFC/uzbkx9zfz6R8T+Z4xTJF5PdwjatSi7CpVztHi7T+ktoZM6YePnTFl1tlXKCYax0BPigtby3362UXT2sJveQjSVXFhXq3/JvsU2QCAtmS7xx1d+BjWrCRf5CXna18/0QFOTS686pcndVVe/acFt8bq8A3GBbASzeJjvEyMxReN4PEn \ No newline at end of file diff --git a/docs/source/images/UDS_logo.PNG b/docs/source/images/UDS_logo.PNG new file mode 100644 index 00000000..30ff310f Binary files /dev/null and b/docs/source/images/UDS_logo.PNG differ diff --git a/docs/source/index.rst b/docs/source/index.rst index 38f55dbc..f5698428 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,7 +1,7 @@ -Welcome to UDS's documentation! -=============================== +Welcome to UDS documentation! +============================= .. toctree:: - :maxdepth: 3 + :maxdepth: 4 :hidden: Home @@ -14,6 +14,12 @@ Welcome to UDS's documentation! pages/contribution.rst +.. figure:: images/UDS_logo.PNG + :alt: UDS + :width: 200px + :figclass: align-center + + Overview -------- The purpose of this project is to provide python tools for simulation (on both sides - client and server) and diff --git a/docs/source/pages/knowledge_base.rst b/docs/source/pages/knowledge_base.rst index 5bbd0259..812ea661 100644 --- a/docs/source/pages/knowledge_base.rst +++ b/docs/source/pages/knowledge_base.rst @@ -5,16 +5,552 @@ for every user of `UDS package `_ so you UDS protocol itself. -Data Flow ---------- +Client +------ +TODO DURING `CLIENT EPIC `_ -Diagnostic Service +Server +------ +TODO DURING `SERVER EPIC `_ + + +Diagnostic Message +------------------ +If we only consider the top layer of OSI Model (layer 7 - Application), then the messages that are exchanged by +clients and servers during UDS communication are called 'Application Protocol Data Units' (A_PDU), +'diagnostic messages' or 'UDS messages' in this documentation. + +There are two types of diagnostic messages: + - `diagnostic request`_ - a message transmitted by a client + - `diagnostic response`_ - a message transmitted by a server + + +UDS communication is always initiated by a client_ who sends a `diagnostic request`_ to a network that it is connected to. +The client_ might not be directly connected to a desired recipient(s) of the request, therefore some servers might be +forced to act as gateways and transmit the request to another network(s) to which they are connected. Server_ decision +(whether to redirect the request to another vehicle sub-network or not) depends on a target(s) of the request i.e. +server_ shall transmit the request in the sub-network if at least on ECU in this sub-network is the target of +the request. + +.. figure:: ../diagrams/KnowledgeBase-Gateway_request.png + :alt: Gateway - request + :figclass: align-center + + Diagnostic request routing in example vehicle networks. + + In this example all ECUs in the vehicle are the targets of the request - functionally addressed request was sent. + + +Each server_ which was the recipient of the request, might decide to send a response back to the nearest client_ +(the one which transmitted the request in this sub-network). Then, the client_ shall act as the gateway again and +redirect the response back until it reaches the request message originator (Diagnostic Tester). + +.. figure:: ../diagrams/KnowledgeBase-Gateway_response.png + :alt: Gateway - response + :figclass: align-center + + Diagnostic responses routing in example vehicle networks. + + In this example all ECUs in the vehicle responds to the request. + + +To better understand 'diagnostic message' terminology, we need to know how these messages are actually transmitted +(what entities carry the message on all layers of OSI model). Pictorial drawing is presented in the figure below: + +.. figure:: ../diagrams/KnowledgeBase-PDUs.png + :alt: UDS PDUs + :figclass: align-center + :width: 100% + + UDS Protocol Data Units on different layers of OSI Model. + +We distinguish (in UDS package implementation) following entities that take part in UDS communication on +different layers of UDS OSI model: + - `Diagnostic message`_ - also called 'Application Protocol Data Unit' (A_PDU) + - `UDS packet`_ - also called 'Network Protocol Data Unit' (N_PDU). UDS packets types and transmission rules are + bus specific. + - `Frame `_ - the smallest piece of information exchanged by nodes + in a bus network + + +Diagnostic Request `````````````````` +Diagnostic request is a `diagnostic message`_ that was transmitted by a client and targets a server or group of servers. +Diagnostic request can be identified by its `Service Identifier`_ (SID) value. + + +Diagnostic Response +``````````````````` +Diagnostic response is a `diagnostic message`_ that was transmitted by a server and targets a client. +Diagnostic response can be identified by its `Service Identifier`_ (SID) value. + +UDS describes two formats of diagnostic responses: + - `positive response message`_ + - `negative response message`_ + + +Positive Response Message +''''''''''''''''''''''''' +If a server responds with positive response message, it means that the server received the corresponding request +message and executed actions requested by a client. + ++------+------------------+------------+ +| Byte | Description | Value | ++======+==================+============+ +| 1 | Response SID | SID + 0x40 | ++------+------------------+------------+ +| 2 | data-parameter#1 | XX | ++------+------------------+------------+ +| ... | ... | ... | ++------+------------------+------------+ +| n | data-parameter#n | XX | ++------+------------------+------------+ + +Where: + - SID - `Service Identifier`_ value that was received in the request message to which the server responded + - XX - any byte value + + +Negative Response Message +''''''''''''''''''''''''' +If a server responds with negative response message, it means that the server for some reason the server could not +execute actions requested by a client. + ++------+-----------------------+-------+ +| Byte | Description | Value | ++======+=======================+=======+ +| 1 | Negative Response SID | 0x7F | ++------+-----------------------+-------+ +| 2 | Request SID | SID | ++------+-----------------------+-------+ +| 3 | NRC | XX | ++------+-----------------------+-------+ + +Where: + - SID - `Service Identifier`_ value that was received in the request message to which the server responded + - NRC - `Negative Response Code`_ value that identified the reason for negative response + + +Service Identifier +`````````````````` +Service Identifier (SID) is one byte integer located in the first byte of Application Data (A_Data) in the +`diagnostic message`_. SID determines whether the message is `diagnostic request`_ or `diagnostic response`_. +General purpose (application) and format of `diagnostic message`_ is also by determined by SID value. + +List of all Service Identifier (SID) values and their application: + - 0x00 - not applicable, reserved by ISO 14229-1 + - 0x01-0x0F - ISO 15031-5/SAE J1979 specific services + - 0x10 - `DiagnosticSessionControl`_ service request + - 0x11 - `ECUReset`_ service request + - 0x12-0x13 - reserved by ISO 14229-1 + - 0x14 - `ClearDiagnosticInformation`_ service request + - 0x15-0x18 - reserved by ISO 14229-1 + - 0x19 - `ReadDTCInformation`_ service request + - 0x1A-0x21 - reserved by ISO 14229-1 + - 0x22 - `ReadDataByIdentifier`_ service request + - 0x23 - `ReadMemoryByAddress`_ service request + - 0x24 - `ReadScalingDataByIdentifier`_ service request + - 0x25-0x26 - reserved by ISO 14229-1 + - 0x27 - `SecurityAccess`_ service request + - 0x28 - `CommunicationControl`_ service request + - 0x29 - `Authentication`_ service request + - 0x2A - `ReadDataByPeriodicIdentifier`_ service request + - 0x2B - reserved by ISO 14229-1 + - 0x2C - `DynamicallyDefineDataIdentifier`_ service request + - 0x2D - reserved by ISO 14229-1 + - 0x2E - `WriteDataByIdentifier`_ service request + - 0x2F - `InputOutputControlByIdentifier`_ service request + - 0x30 - reserved by ISO 14229-1 + - 0x31 - `RoutineControl`_ service request + - 0x32-0x23 - reserved by ISO 14229-1 + - 0x34 - `RequestDownload`_ service request + - 0x35 - `RequestUpload`_ service request + - 0x36 - `TransferData`_ service request + - 0x37 - `RequestTransferExit`_ service request + - 0x38 - `RequestFileTransfer`_ service request + - 0x39-0x3C - reserved by ISO 14229-1 + - 0x3D - `WriteMemoryByAddress`_ service request + - 0x3E - `TesterPresent`_ service request + - 0x3F - not applicable, reserved by ISO 14229-1 + - 0x40 - not applicable, reserved by ISO 14229-1 + - 0x41-0x4F - ISO 15031-5/SAE J1979 specific services + - 0x50 - positive response to `DiagnosticSessionControl`_ service + - 0x51 - positive response to `ECUReset`_ service + - 0x52-0x53 - reserved by ISO 14229-1 + - 0x54 - positive response to `ClearDiagnosticInformation`_ service + - 0x55-0x58 - reserved by ISO 14229-1 + - 0x59 - positive response to `ReadDTCInformation`_ service + - 0x5A-0x61 - reserved by ISO 14229-1 + - 0x62 - positive response to `ReadDataByIdentifier`_ service + - 0x63 - positive response to `ReadMemoryByAddress`_ service + - 0x64 - positive response to `ReadScalingDataByIdentifier`_ service + - 0x63-0x66 - reserved by ISO 14229-1 + - 0x67 - positive response to `SecurityAccess`_ service + - 0x68 - positive response to `CommunicationControl`_ service + - 0x69 - positive response to `Authentication`_ service + - 0x6A - positive response to `ReadDataByPeriodicIdentifier`_ service + - 0x6B - reserved by ISO 14229-1 + - 0x6C - positive response to `DynamicallyDefineDataIdentifier`_ service + - 0x6D - reserved by ISO 14229-1 + - 0x6E - positive response to `WriteDataByIdentifier`_ service + - 0x6F - positive response to `InputOutputControlByIdentifier`_ service + - 0x70 - reserved by ISO 14229-1 + - 0x71 - positive response to `RoutineControl`_ service + - 0x72-0x73 - reserved by ISO 14229-1 + - 0x74 - positive response to `RequestDownload`_ service + - 0x75 - positive response to `RequestUpload`_ service + - 0x76 - positive response to `TransferData`_ service + - 0x77 - positive response to `RequestTransferExit`_ service + - 0x78 - positive response to `RequestFileTransfer`_ service + - 0x79-0x7C - reserved by ISO 14229-1 + - 0x7D - positive response to `WriteMemoryByAddress`_ service + - 0x7E - positive response to `TesterPresent`_ service + - 0x7F - negative response service identifier + - 0x80-0x82 - not applicable, reserved by ISO 14229-1 + - 0x83 - reserved by ISO 14229-1 + - 0x84 - `SecuredDataTransmission`_ service request + - 0x85 - `ControlDTCSetting`_ service request + - 0x86 - `ResponseOnEvent`_ service request + - 0x87 - `LinkControl`_ service request + - 0x88 - reserved by ISO 14229-1 + - 0x89-0xB9 - not applicable, reserved by ISO 14229-1 + - 0xBA-0xBE - system supplier specific service requests + - 0xBF-0xC2 - not applicable, reserved by ISO 14229-1 + - 0xC3 - reserved by ISO 14229-1 + - 0xC4 - positive response to `SecuredDataTransmission`_ service + - 0xC5 - positive response to `ControlDTCSetting`_ service + - 0xC6 - positive response to `ResponseOnEvent`_ service + - 0xC7 - positive response to `LinkControl`_ service + - 0xC8 - reserved by ISO 14229-1 + - 0xC9-0xF9 - not applicable, reserved by ISO 14229-1 + - 0xFA-0xFE - positive responses to system supplier specific requests + - 0xFF - not applicable, reserved by ISO 14229-1 + + +DiagnosticSessionControl +'''''''''''''''''''''''' +DiagnosticSessionControl service is used to change diagnostic sessions in the server(s). +In each diagnostic session a different set of diagnostic services (and/or functionalities) is enabled in the server. +Server shall always be in exactly one diagnostic session. + + +ECUReset +'''''''' +ECUReset service is used by the client to request a server reset. + + +ClearDiagnosticInformation +'''''''''''''''''''''''''' +ClearDiagnosticInformation service is used by the client to clear all diagnostic information (DTC and related data) +in one or multiple servers' memory. + + +ReadDTCInformation +'''''''''''''''''' +ReadDTCInformation service allows the client to read from any server or group of servers within a vehicle, +current information about all Diagnostic Trouble Codes. This could be a status of reported Diagnostic Trouble Code (DTC), +number of currently active DTCs or any other information returned by supported ReadDTCInformation SubFunctions. + + +ReadDataByIdentifier +'''''''''''''''''''' +ReadDataByIdentifier service allows the client to request data record values from the server identifier by one or more +DataIdentifiers (DIDs). + + +ReadMemoryByAddress +''''''''''''''''''' +ReadMemoryByAddress service allows the client to request server's memory data stored under provided memory address. + + +ReadScalingDataByIdentifier +''''''''''''''''''''''''''' +ReadScalingDataByIdentifier service allows the client to request from the server a scaling data record identified +by a DataIdentifier (DID). The scaling data contains information such as data record type (e.g. ASCII, signed float), +formula and its coefficients used for value calculation, units, etc. + + +SecurityAccess +'''''''''''''' +SecurityAccess service allows the client to unlock functions/services with restricted access. + + +CommunicationControl +'''''''''''''''''''' +CommunicationControl service allows the client to switch on/off the transmission and/or the reception of certain +messages on a server(s). + + +Authentication +'''''''''''''' +Authentication service provides a means for the client to prove its identity, allowing it to access data and/or +diagnostic services, which have restricted access for, for example security, emissions, or safety reasons. + + +ReadDataByPeriodicIdentifier +'''''''''''''''''''''''''''' +ReadDataByPeriodicIdentifier service allows the client to request the periodic transmission of data record values +from the server identified by one or more periodicDataIdentifiers. + + +DynamicallyDefineDataIdentifier +''''''''''''''''''''''''''''''' +DynamicallyDefineDataIdentifier service allows the client to dynamically define in a server a DataIdentifier (DID) +that can be read via the ReadDataByIdentifier_ service at a later time. + + +WriteDataByIdentifier +''''''''''''''''''''' +WriteDataByIdentifier service allows the client to write information into the server at an internal location +specified by the provided DataIdentifier (DID). + + +InputOutputControlByIdentifier +'''''''''''''''''''''''''''''' +InputOutputControlByIdentifier service allows the client to substitute a value for an input signal, internal server +function and/or force control to a value for an output (actuator) of an electronic system. + + +RoutineControl +'''''''''''''' +RoutineControl service allows the client to execute a defined sequence of steps to obtain any relevant result. +There is a lot of flexibility with this service, but typical usage may include functionality such as erasing memory, +resetting or learning adaptive data, running a self-test, overriding the normal server control strategy. + + +RequestDownload +''''''''''''''' +RequestDownload service allows the client to initiate a data transfer from the client to the server (download). + + +RequestUpload +''''''''''''' +RequestUpload service allows the client to initiate a data transfer from the server to the client (upload). + + +TransferData +'''''''''''' +TransferData service is used by the client to transfer data either from the client to the server (download) or +from the server to the client (upload). + + +RequestTransferExit +''''''''''''''''''' +RequestTransferExit service is used by the client to terminate a data transfer between the client and server. + + +RequestFileTransfer +''''''''''''''''''' +RequestFileTransfer service allows the client to initiate a file data transfer either from the server to +the client (upload) or from the server to the client (upload). + + +WriteMemoryByAddress +'''''''''''''''''''' +WriteMemoryByAddress service allows the client to write information into server's memory data under provided +memory address. + + +TesterPresent +''''''''''''' +TesterPresent service is used by the client to indicate to a server(s) that the client is still connected to a vehicle +and certain diagnostic services and/or communication that have been previously activated are to remain active. + + +SecuredDataTransmission +''''''''''''''''''''''' +SecuredDataTransmission service is applicable if a client intends to use diagnostic services defined +in this document in a secured mode. It may also be used to transmit external data, which conform to +some other application protocol, in a secured mode between a client and a server. A secured mode in +this context means that the data transmitted is protected by cryptographic methods. + + +ControlDTCSetting +''''''''''''''''' +ControlDTCSetting service allows the client to stop or resume the updating of DTC status bits in the server(s) memory. + + +ResponseOnEvent +''''''''''''''' +ResponseOnEvent service allows the client to request from the server to start ot stop transmission of responses on +a specified event. + + +LinkControl +''''''''''' +LinkControl service allows the client to control the communication between the client and the server(s) in order to +gain bus bandwidth for diagnostic purposes (e.g. programming). + + +Negative Response Code +`````````````````````` +Negative Response Code (NRC) is one byte value which contains information why a server is not sending +a positive response message. + +List of NRC values: + - 0x00 - positiveResponse - This NRC shall not be used in a negative response message. + This positiveResponse parameter value is reserved for server internal implementation. + - 0x00-0x0F - ISO Reserved - This range of values is reserved for future definition by ISO 14229 Standard. + - 0x10 - generalReject - This NRC indicates that the requested action has been rejected by the server. + - 0x11 - serviceNotSupported - This NRC indicates that the requested action will not be taken because the + server does not support the requested service. + - 0x12 - SubFunctionNotSupported - This NRC indicates that the requested action will not be taken because the + server does not support the service specific parameters of the request message. + - 0x13 - incorrectMessageLengthOrInvalidFormat - This NRC indicates that the requested action will not be taken + because the length of the received request message does not match the prescribed length for the specified service + or the format of the parameters do not match the prescribed format for the specified service. + - 0x14 - responseTooLong - This NRC shall be reported by the server if the response to be generated exceeds + the maximum number of bytes available by the underlying network layer. This could occur if the response message + exceeds the maximum size allowed by the underlying transport protocol or if the response message exceeds the server + buffer size allocated for that purpose. + - 0x15-0x20 - ISO Reserved - This range of values is reserved for future definition by ISO 14229 Standard. + - 0x21 - busyRepeatRequest - This NRC indicates that the server is temporarily too busy to perform the requested + operation. In this circumstance the client shall perform repetition of the "identical request message" or + "another request message". The repetition of the request shall be delayed by a time specified in the respective + implementation documents. + - 0x22 - conditionsNotCorrect - This NRC indicates that the requested action will not be taken because the server + prerequisite conditions are not met. + - 0x23 - ISO Reserved - This value is reserved for future definition by ISO 14229 Standard. + - 0x24 - requestSequenceError - This NRC indicates that the requested action will not be taken because the server + expects a different sequence of request messages or message as sent by the client. This may occur when sequence + sensitive requests are issued in the wrong order. + - 0x25 - noResponseFromSubnetComponent - This NRC indicates that the server has received the request but the requested + action could not be performed by the server as a subnet component which is necessary to supply the requested + information did not respond within the specified time. + - 0x26 - FailurePreventsExecutionOfRequestedAction - This NRC indicates that the requested action will not be taken + because a failure condition, identified by a DTC (with at least one DTC status bit for TestFailed, Pending, + Confirmed or TestFailedSinceLastClear set to 1), has occurred and that this failure condition prevents the server + from performing the requested action. + - 0x27-0x30 - ISO Reserved - This range of values is reserved for future definition by ISO 14229 Standard. + - 0x31 - requestOutOfRange - This NRC indicates that the requested action will not be taken because the server has + detected that the request message contains a parameter which attempts to substitute a value beyond its range of + authority (e.g. attempting to substitute a data byte of 111 when the data is only defined to 100), or which attempts + to access a DataIdentifier/RoutineIdentifer that is not supported or not supported in active session. + - 0x32 - ISO Reserved - This value is reserved for future definition by ISO 14229 Standard. + - 0x33 - securityAccessDenied - This NRC indicates that the requested action will not be taken because the server's + security strategy has not been satisfied by the client. + - 0x34 - authenticationRequired - This NRC indicates that the requested service will not be taken because the client + has insufficient rights based on its Authentication state. + - 0x35 - invalidKey - This NRC indicates that the server has not given security access because the key sent by + the client did not match with the key in the server's memory. This counts as an attempt to gain security. + - 0x36 - exceedNumberOfAttempts - This NRC indicates that the requested action will not be taken because the client + has unsuccessfully attempted to gain security access more times than the server's security strategy will allow. + - 0x37 - requiredTimeDelayNotExpired - This NRC indicates that the requested action will not be taken because + the client's latest attempt to gain security access was initiated before the server's required timeout period had + elapsed. + - 0x38 - secureDataTransmissionRequired - This NRC indicates that the requested service will not be taken because + the requested action is required to be sent using a secured communication channel. + - 0x39 - secureDataTransmissionNotAllowed - This NRC indicates that this message was received using the + SecuredDataTransmission (SID 0x84) service. However, the requested action is not allowed to be sent using + the SecuredDataTransmission (0x84) service. + - 0x3A - secureDataVerificationFailed - This NRC indicates that the message failed in the security sub-layer. + - 0x3B-0x4F - ISO Reserved - This range of values is reserved for future definition by ISO 14229 Standard. + - 0x50 - Certificate verification failed, Invalid Time Period - Date and time of the server does not match + the validity period of the Certificate. + - 0x51 - Certificate verification failed, Invalid Signature - Signature of the Certificate could not be verified. + - 0x52 - Certificate verification failed, Invalid Chain of Trust - Certificate could not be verified against stored + information about the issuing authority. + - 0x53 - Certificate verification failed, Invalid Type - Certificate does not match the current requested use + case. + - 0x54 - Certificate verification failed, Invalid Format - Certificate could not be evaluated because the format + requirement has not been met. + - 0x55 - Certificate verification failed, Invalid Content - Certificate could not be verified because the content + does not match. + - 0x56 - Certificate verification failed, Invalid Scope - The scope of the Certificate does not match the contents + of the server. + - 0x57 - Certificate verification failed, Invalid Certificate (revoked) - Certificate received from client is invalid, + because the server has revoked access for some reason. + - 0x58 - Ownership verification failed - Delivered Ownership does not match the provided challenge or could not + verified with the own private key. + - 0x59 - Challenge calculation failed - The challenge could not be calculated on the server side. + - 0x5A - Setting Access Rights failed - The server could not set the access rights. + - 0x5B - Session key creation/derivation failed - The server could not create or derive a session key. + - 0x5C - Configuration data usage failed - The server could not work with the provided configuration data. + - 0x5D - DeAuthentication failed - DeAuthentication was not successful, server could still be unprotected. + - 0x5E-0x6F - ISO Reserved - This range of values is reserved for future definition by ISO 14229 Standard. + - 0x70 - uploadDownloadNotAccepted - This NRC indicates that an attempt to upload/download to a server's memory + cannot be accomplished due to some fault conditions. + - 0x71 - transferDataSuspended - This NRC indicates that a data transfer operation was halted due to some fault. + The active transferData sequence shall be aborted. + - 0x72 - generalProgrammingFailure - This NRC indicates that the server detected an error when erasing or programming + a memory location in the permanent memory device (e.g. Flash Memory). + - 0x73 - wrongBlockSequenceCounter - This NRC indicates that the server detected an error in the sequence of + blockSequenceCounter values. Note that the repetition of a TransferData request message with a blockSequenceCounter + equal to the one included in the previous TransferData request message shall be accepted by the server. + - 0x74-0x77 - ISO Reserved - This range of values is reserved for future definition by ISO 14229 Standard. + - 0x78 - requestCorrectlyReceived-ResponsePending - This NRC indicates that the request message was received correctly, + and that all parameters in the request message were valid (these checks can be delayed until after sending this NRC + if executing the boot software), but the action to be performed is not yet completed and the server is not yet ready + to receive another request. As soon as the requested service has been completed, the server shall send a positive + response message or negative response message with a response code different from this. + - 0x79-0x7D - ISO Reserved - This range of values is reserved for future definition by ISO 14229 Standard. + - 0x7E - SubFunctionNotSupportedInActiveSession - This NRC indicates that the requested action will not be taken + because the server does not support the requested SubFunction in the session currently active. This NRC shall only + be used when the requested SubFunction is known to be supported in another session, otherwise response code + SubFunctionNotSupported shall be used. + - 0x7F - serviceNotSupportedInActiveSession - This NRC indicates that the requested action will not be taken because + the server does not support the requested service in the session currently active. This NRC shall only be used when + the requested service is known to be supported in another session, otherwise response code serviceNotSupported + shall be used. + - 0x80 - ISO Reserved - This value is reserved for future definition by ISO 14229 Standard. + - 0x81 - rpmTooHigh - This NRC indicates that the requested action will not be taken because the server prerequisite + condition for RPM is not met (current RPM is above a preprogrammed maximum threshold). + - 0x82 - rpmTooLow - This NRC indicates that the requested action will not be taken because the server prerequisite + condition for RPM is not met (current RPM is below a preprogrammed minimum threshold). + - 0x83 - engineIsRunning - This NRC is required for those actuator tests which cannot be actuated while the Engine + is running. This is different from RPM too high negative response, and shall be allowed. + - 0x84 - engineIsNotRunning - This NRC is required for those actuator tests which cannot be actuated unless + the Engine is running. This is different from RPM too low negative response, and shall be allowed. + - 0x85 - engineRunTimeTooLow - This NRC indicates that the requested action will not be taken because the server + prerequisite condition for engine run time is not met (current engine run time is below a preprogrammed limit). + - 0x86 - temperatureTooHigh - This NRC indicates that the requested action will not be taken because the server + prerequisite condition for temperature is not met (current temperature is above a preprogrammed maximum threshold). + - 0x87 - temperatureTooLow - This NRC indicates that the requested action will not be taken because the server + prerequisite condition for temperature is not met (current temperature is below a preprogrammed minimum threshold). + - 0x88 - vehicleSpeedTooHigh - This NRC indicates that the requested action will not be taken because the server + prerequisite condition for vehicle speed is not met (current VS is above a preprogrammed maximum threshold). + - 0x89 - vehicleSpeedTooLow - This NRC indicates that the requested action will not be taken because the server + prerequisite condition for vehicle speed is not met (current VS is below a preprogrammed minimum threshold). + - 0x8A - throttle/PedalTooHigh - This NRC indicates that the requested action will not be taken because the server + prerequisite condition for throttle/pedal position is not met (current throttle/pedal position is above + a preprogrammed maximum threshold). + - 0x8B - throttle/PedalTooLow - This NRC indicates that the requested action will not be taken because the server + prerequisite condition for throttle/pedal position is not met (current throttle/pedal position is below + a preprogrammed minimum threshold). + - 0x8C - transmissionRangeNotInNeutral - This NRC indicates that the requested action will not be taken because + the server prerequisite condition for being in neutral is not met (current transmission range is not in neutral). + - 0x8D - transmissionRangeNotInGear - This NRC indicates that the requested action will not be taken because the server + prerequisite condition for being in gear is not met (current transmission range is not in gear). + - 0x8E - ISO Reserved - This value is reserved for future definition by ISO 14229 Standard. + - 0x8F - brakeSwitch(es)NotClosed (Brake Pedal not pressed or not applied) - This NRC indicates that for safety + reasons, this is required for certain tests before it begins, and shall be maintained for the entire duration of + the test. + - 0x90 - shifterLeverNotInPark - This NRC indicates that for safety reasons, this is required for certain tests before + it begins, and shall be maintained for the entire duration of the test. + - 0x91 - torqueConverterClutchLocked - This NRC indicates that the requested action will not be taken because + the server prerequisite condition for torque converter clutch is not met (current torque converter clutch status + above a preprogrammed limit or locked). + - 0x92 - voltageTooHigh - This NRC indicates that the requested action will not be taken because the server + prerequisite condition for voltage at the primary pin of the server (ECU) is not met (current voltage is above + a preprogrammed maximum threshold). + - 0x93 - voltageTooLow - This NRC indicates that the requested action will not be taken because the server + prerequisite condition for voltage at the primary pin of the server (ECU) is not met (current voltage is below + a preprogrammed maximum threshold). + - 0x94 - ResourceTemporarilyNotAvailable - This NRC indicates that the server has received the request but + the requested action could not be performed by the server because an application which is necessary to supply + the requested 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. + - 0x95-0xEF - reservedForSpecificConditionsNotCorrect - This range of values is reserved for future definition + condition not correct scenarios by ISO 14229 Standard. + - 0xF0-0xFE - vehicleManufacturerSpecificConditionsNotCorrect - This range of values is reserved for vehicle + manufacturer specific condition not correct scenarios. + - 0xFF - ISO Reserved - This value is reserved for future definition by ISO 14229 Standard. Addressing -'''''''''' +`````````` Addressing determines model of UDS communication. We distinguish following addressing types: @@ -23,7 +559,7 @@ We distinguish following addressing types: Physical -........ +'''''''' Physical addressing is used to send a dedicated message to a certain server (ECU). When physically addressed messages are sent, the direct (point-to-point) communication between the client and the server takes place. The server shall respond to physically addressed request unless the request contains @@ -31,11 +567,11 @@ an information that response is not required (further explained in`response beha chapter). NOTE: You do not need a direct physical connection between the client and the server to have physically addressed -communication, as all messages would be routed by other servers that are part of the network and connected between -the client and the server. +communication as all messages shall be routed to a target of each message. + Response behaviour to physically addressed request -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.................................................. Expected server behaviour in case of receiving physically addressed request message with SubFunction parameter: +----------------------------------+----------------------------------------------------------------+-----------------------------------------------+-------------------------------------------------------------------------------------------------------------+ @@ -101,7 +637,7 @@ Explanation: Functional -.......... +'''''''''' Functional addressing is used to send messages to multiple servers (ECUs) in the network. When functionally addressed messages are sent, the one to many communication between the client and the servers (ECUs) takes place. The server shall only respond to certain requests (further explained in @@ -110,8 +646,9 @@ the servers (ECUs) takes place. The server shall only respond to certain request NOTE: Some types of buses (e.g. LIN) might also support broadcast communication which is very similar to functionally addressed. The only difference is that a server response is never expected by the client during broadcast communication. + Response behaviour to functionally addressed request -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.................................................... Expected server behaviour in case of receiving functionally addressed request message with SubFunction parameter: +----------------------------------+----------------------------------------------------------------+------------------------------+-------------------------------------------------------------------------------------------------------------+ @@ -172,34 +709,36 @@ Explanation: Segmentation ```````````` +TODO -Network Protocol Data Unit -'''''''''''''''''''''''''' -Network Protocol Data Unit (N_PDU) is a single packet which is transmitted during segmentation_ process of -a `diagnostic service`_. Each `diagnostic service`_ consists of at least one N_PDU. There are some N_PDUs which -does not carry any `diagnostic service`_ data as they are used to manage the flow of other N_PDUs. -Network Protocol Data Unit (N_PDU) consists of following fields: - - `Network Address Information`_ (N_AI) - - `Network Protocol Control Information`_ (N_PCI) - - `Network Data Field`_ (N_Data) +UDS Packet +`````````` +UDS packet is also called Network Protocol Data Unit (N_PDU). It is created during segmentation_ of a +`diagnostic message`_. Each `diagnostic message`_ consists of at least one N_PDU. There are some packets (N_PDUs) which +does not carry any `diagnostic message`_ data as they are used to manage the flow of other packets (N_PDUs). + +UDS packet (N_PDU) consists of following fields: + - `Network Address Information`_ (N_AI) - packet addressing + - `Network Protocol Control Information`_ (N_PCI) - packet type + - `Network Data Field`_ (N_Data) - packet date Network Address Information -........................... +''''''''''''''''''''''''''' Network Address Information (N_AI) contains address information which identifies the recipient(s) and the sender between whom data exchange takes place. It also describes communication model (e.g. whether response is required) for the message. Network Protocol Control Information -.................................... -Network Protocol Control Information (N_PCI) identifies the type of `Network Protocol Data Unit`_. +'''''''''''''''''''''''''''''''''''' +Network Protocol Control Information (N_PCI) identifies the type of `UDS packet`_ (Network Protocol Data Unit). Supported N_PCIs and theirs values interpretation are bus specific. Network Data Field -.................. -Network Data Field (N_Data) carries `diagnostic service`_ data. It might be an entire `diagnostic service`_ data (if -`diagnostic service`_ fits into one packet) or just a part (a single packet) of it (if `segmentation`_ had to be -used to divide `diagnostic service`_ into smaller parts). +'''''''''''''''''' +Network Data Field (N_Data) carries `diagnostic message`_ data. It might be an entire `diagnostic message`_ data (if +`diagnostic message`_ fits into one packet) or just a part (a single packet) of it (if `segmentation`_ had to be +used to divide `diagnostic message`_ into smaller parts). diff --git a/docs/source/pages/messages.rst b/docs/source/pages/messages.rst index dc84deb1..333f7061 100644 --- a/docs/source/pages/messages.rst +++ b/docs/source/pages/messages.rst @@ -9,116 +9,171 @@ In this chapter, you will find information about :python:`messages` subpackage i enables creation of entities that carry UDS data and helps to describe theirs transmission. In implementation we distinguish following entities that carry diagnostic data: - - `UDS Message`_ - carries application data (diagnostic service) on upper layers (layers 5-7 of UDS OSI model) - - `Network Protocol Data Unit`_ - it is a single packet that was created after a segmentation of UDS Message - (layers 3-4 of UDS OSI model) - - `Bus Frame`_ - a single frame transmitted over any bus that carries any data that is not necessarily related to - UDS communication (layers 1-2 of bus OSI model) + - `UDS Message`_ - carries application data (diagnostic service) on upper layers (layers 5-7 of UDS OSI model), + it might also be called Application Protocol Data Unit (A_PDU) + - `UDS Packet`_ - packets that are exchanged between client and server during `UDS Message`_ segmentation + (layers 3-4 of UDS OSI model), it might also be called Network Protocol Data Unit (N_PDU) + - `Bus Frame`_ - a single frame transmitted over any bus on lower layers (layers 1-2 of UDS/bus OSI model), + it carries any data that is not necessarily related to UDS communication -Additionally, you will find `Transmission Attributes`_ chapter which contains implementation details of enums that -are used to describe UDS transmission. +Additionally, you will find `Transmission Attributes`_ and `UDS Data Enums`_ chapters which contain implementation +details about enums that help to describe transmission and data of aforementioned entities. UDS Message ----------- -TODO during `UDS Message documentation task `_ +Diagnostic messages (either diagnostic requests or response messages) are called 'UDS Messages' in the implementation. +In the code, the diagnostic message features are divided into two parts: + - UdsMessage_ - storage for diagnostic message (A_PDU) attributes that could be used by a user to transmit this + UDS Message on a configured bus + - UdsMessageRecord_ - record with historic information about either received or transmitted diagnostic message -Network Protocol Data Unit --------------------------- -To efficiently handle Network Protocol Data Units (N_PDUs), the implementation is divided into two parts: -- `Network Protocol Data Unit Definition`_ - storage of N_PDU attributes that could be used to transmit N_PDU on - a dedicated bus -- `Network Protocol Data Unit Record`_ - record with historic information about either received or transmitted N_PDU +UdsMessage +`````````` +Diagnostic messages has common specification for all buses, therefore :python:`UdsMessage` class has the only one +implementation which is the same regardless of bus used by a user. :python:`UdsMessage` is a storage +for diagnostic message attributes, therefore if you want to send any diagnostic message, you should prior create +:python:`UdsMessage` object first. +.. code-block:: python + + from uds.messages import UdsMessage, AddressingType + + # example how to define a UDS Message + uds_message = UdsMessage(raw_message=[0x10, 0x03], + addressing=AddressingType.PHYSICAL) -Network Protocol Data Unit Definition -````````````````````````````````````` -Network Protocol Data Unit slightly differs for each bus, therefore abstract class (AbstractNPDU_) is separated -out in the implementation. If you want to define N_PDU (that might be sent later on), you should create an object of -any of concrete classes that inherits after :python:`AbstractNPDU` class. + # you have two attributes that you can freely change + print(uds_message.raw_message) + uds_message.raw_message = [0x3E, 0x00] + print(uds_message.raw_message) -Currently following classes are implemented to handle creation of new N_PDUs: - - AbstractNPDU_ + print(uds_message.addressing) + uds_message.addressing = AddressingType.FUNCTIONAL + print(uds_message.addressing) -AbstractNPDU -'''''''''''' -:python:`AbstractNPDU` class contains common implementation of all N_PDU types. **You should never call** -:python:`AbstractNPDU` **class directly**, therefore in the example below :python:`ConcreteNPDU` (as a concrete -implementation of N_PDU for desired bus) is used instead: + +UdsMessageRecord +```````````````` +Historic records with information about diagnostic messages that were either received or transmitted, are stored in +objects of :python:`UdsMessageRecord` class. .. code-block:: python - from uds.messages import AddressingType, ConcreteNPDU + from uds.messages import UdsMessageRecord, AddressingType + + # usually, you would not be doing this by yourself as Client and Server features are meant to create objects of this class + uds_message_records = UdsMessageRecord(raw_message=[0x10, 0x03], + packets_records=[uds_packet_record]) # at least one packet - instance of `AbstractUdsPacketRecord` class + + # you can get attributes of the UDS Message Record object + print(uds_message_records.raw_message) + print(uds_message_records.packets_records) + print(uds_message_records.addressing) + print(uds_message_records.direction) + print(uds_message_records.transmission_end) - # you can define N_PDU - pdu = ConcreteNPDU(raw_data=[0x02, 0x3E, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55], - addressing=AddressingType.PHYSICAL) - # you can get attributes of the N_PDU object - print(pdu.raw_data) - print(pdu.addressing) - print(pdu.pci) # this will only be working for concrete N_PDU implementation +UDS Packet +---------- +To efficiently handle UDS Packets (Network Protocol Data Units - N_PDUs), the implementation is divided into two parts: + - `UDS Packet Definition`_ - storage of UDS Packet (N_PDU) attributes that could be used by a user to transmit + UDS Packet on a dedicated bus + - `UDS Packet Record`_ - record with historic information about either received or transmitted UDS Packet (N_PDU) - # you can change values of N_PDU object attributes - pdu.raw_data = (0x03, 0x22, 0xF1, 0x84, 0x00, 0x00, 0x00, 0x00) - pdu.addressing = "Functional" +UDS Packet Definition +`````````````````````` +UDS Packets slightly differ for each bus, therefore abstract class (AbstractUdsPacket_) is separated +out in the implementation. If you want to define UDS Packet (that might be sent later on), you should create +an object of any of concrete classes that inherits after :python:`AbstractUdsPacket` class. + +Currently following classes are implemented to handle creation of new UDS Packets (N_PDUs): + + - AbstractUdsPacket_ + +AbstractUdsPacket +''''''''''''''''' +:python:`AbstractUdsPacket` class contains common implementation of all UDS Packet types. **You should never call** +:python:`AbstractUdsPacket` **class directly**, therefore in the example below :python:`ConcreteUdsPacket` +(as a concrete implementation of UDS Packet for desired bus) is used instead: + +.. code-block:: python -Network Protocol Data Unit Record -````````````````````````````````` -Network Protocol Data Unit Record is a record with historic data of N_PDU that was either received or transmitted. -Due to Network Protocol Data Units differences for various buses, abstract class (AbstractNPDURecord_) is separated + from uds.messages import AddressingType, ConcreteUdsPacket + + # you can define UDS Packet (N_PDU) + packet = ConcreteUdsPacket(raw_data=[0x02, 0x3E, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55], + addressing=AddressingType.PHYSICAL) + + # you can get attributes of the packet object + print(packet.raw_data) + print(packet.addressing) + print(packet.packet_type) # this will only work for concrete UDS Packet implementation + + # you can change values of UDS Packet object attributes + packet.raw_data = (0x03, 0x22, 0xF1, 0x84, 0x00, 0x00, 0x00, 0x00) + packet.addressing = "Functional" + + +UDS Packet Record +````````````````` +UDS Packet Record is a record with historic data of UDS Packet (N_PDU) that was either received or transmitted. +Due to difference in structure of UDS Packets for various buses, abstract class (AbstractUdsPacketRecord_) is separated out in the implementation. -Currently following classes are implemented to store historic data of N_PDUs: - - AbstractNPDURecord_ +Currently following classes are implemented to store historic data of UDS Packets (N_PDUs): + - AbstractUdsPacketRecord_ -AbstractNPDURecord -'''''''''''''''''' -:python:`AbstractNPDURecord` class contains common implementation of all N_PDU records for all buses. -**You should never call** :python:`AbstractNPDURecord` **class directly**, therefore in the example below -:python:`ConcreteNPDURecord` (as a concrete implementation of N_PDU record for a certain bus) is used instead: +AbstractUdsPacketRecord +''''''''''''''''''''''' +:python:`AbstractUdsPacketRecord` class contains common implementation of all UDS Packets records for all buses. +**You should never call** :python:`AbstractUdsPacketRecord` **class directly**, therefore in the example below +:python:`ConcreteUdsPacketRecord` (as a concrete implementation of UDS Packet record for a certain bus) is used instead: .. code-block:: python - from uds.messages import TransmissionDirection, ConcreteNPDURecord + from uds.messages import TransmissionDirection, ConcreteUdsPacketRecord - # usually, you would not be doing this by yourself as Transport Interface feature is meant to handle this feature - pdu_record = ConcreteNPDURecord(frame=some_frame, - direction=TransmissionDirection.RECEIVED, - ...) # ... represents additional arguments that are required by a concrete class + # usually, you would not be doing this by yourself as Transport Interface feature is meant to create objects of this class + packet_record = ConcreteUdsPacketRecord(frame=some_frame, + direction=TransmissionDirection.RECEIVED, + ...) # ... represents additional arguments that are required by a concrete class - # you can get attributes of the N_PDU Record object - print(pdu.frame) - print(pdu.direction) - print(pdu.raw_data) - print(pdu.npci) - print(pdu.addressing) - print(pdu.transmission_time) + # you can get attributes of the UDS Packet Record object + print(packet_record.frame) + print(packet_record.direction) + print(packet_record.raw_data) + print(packet_record.packet_type) + print(packet_record.addressing) + print(packet_record.transmission_time) -Network Protocol Control Information -```````````````````````````````````` -Network Protocol Control Information determines type of `Network Protocol Data Unit`_ (e.g. whether this is -the only/the first/following N_PDU). Due to Network Protocol Control Information differences for various buses, -abstract class (AbstractNPCI_) is separated out in the implementation. +UDS Packet Type +``````````````` +Network Protocol Control Information determines value of UDS Packet (N_PDU) type (e.g. whether this is +the only/the first/following UDS Packet). Due to differences in UDS specifications for various buses, +abstract class (AbstractPacketType_) is separated out in the implementation. -Currently following enums with N_PCI values are implemented: - - AbstractNPCI_ +Currently following enums with UDS Packet Type (N_PCI) values are implemented: + - AbstractPacketType_ -AbstractNPCI -'''''''''''' -An empty enum with helper methods that is parent class for all concrete N_PCI enums classes. +AbstractPacketType +'''''''''''''''''' +An empty enum with helper methods. It is meant to be parent class for all concrete UDS Packet Type enums classes. .. code-block:: python - from uds.messages import AbstractNPCI + from uds.messages import AbstractPacketType + + # you can check if value is member of AbstractPacketType enum + AbstractPacketType.is_member(value_to_check) # returns True if value is member, False otherwise + AbstractPacketType.validate_member(value_to_check) # raises an exception if value is not a member of the enum - AbstractNPCI.is_member(value_to_check) # checks whether value is enum member - returns true/false - AbstractNPCI.validate_member(value_to_check) # checks whether value is enum member - raises an exception if not a member - AbstractNPCI.add_member(name="NEW_NPCI_NAME", value=0x0) # adds a new member to enum class + # you can add a new enum member + AbstractPacketType.add_member(name="NEW_NPCI_NAME", value=0x0) Bus Frame --------- @@ -136,7 +191,7 @@ Following enums are available: TransmissionDirection ````````````````````` -:python:`TransmissionDirection` enum is used to determine whether diagnostic data entity (frame/message/PDU) was +:python:`TransmissionDirection` enum is used to determine whether diagnostic data entity (message/packet/frame) was either received or transmitted. .. code-block:: python @@ -148,7 +203,7 @@ either received or transmitted. AddressingType `````````````` -:python:`AddressingType` is used to determine type of transmission (one/many recipients and communication model). +:python:`AddressingType` is used to determine type of transmission (one/many recipient(s) and communication model). .. code-block:: python @@ -157,3 +212,59 @@ AddressingType AddressingType.PHYSICAL AddressingType.FUNCTIONAL AddressingType.BROADCAST # in fact, this is FUNCTIONAL addressing with broadcast communication used, but it was separated to distinguish this case + + +UDS Data Enums +---------------- +There are following enums that contains information related to UDS Messages data: + - RequestSID_ + - ResponseSID_ + - NRC_ + + +RequestSID +`````````` +Enum with all known Service Identifier (SID) values that might be used in a request message. + +.. code-block:: python + + from uds.messages import RequestSID + + # you can check if value is valid request sid + RequestSID.is_request_sid(value_to_check) + + # you can check whether value is enum member + RequestSID.is_member(value_to_check) # returns True if value is member, False otherwise + RequestSID.validate_member(value_to_check) # raises an exception if value is not a member of the enum + + +ResponseSID +``````````` +Enum with all known Response Service Identifier (RSID) values that might be used in a response message. + +.. code-block:: python + + from uds.messages import ResponseSID + + # you can check if value is valid request sid + ResponseSID.is_response_sid(value_to_check) + + # you can check whether value is enum member + ResponseSID.is_member(value_to_check) # returns True if value is member, False otherwise + ResponseSID.validate_member(value_to_check) # raises an exception if value is not a member of the enum + + +NRC +``` +Enum with all known Negative Response Code (NRC) values that might be used in a negative response message. + +.. code-block:: python + + from uds.messages import NRC + + # you can check whether value is NRC enum member + NRC.is_member(value_to_check) # returns True if value is member, False otherwise + NRC.validate_member(value_to_check) # raises an exception if value is not a member of the enum + + # you can add a new enum member + NRC.add_member(name="NAME_FOR_NEW_MEMBER", value=0x00) diff --git a/docs/source/tables/Negative_response_format.tgn b/docs/source/tables/Negative_response_format.tgn new file mode 100644 index 00000000..ec5d5e42 --- /dev/null +++ b/docs/source/tables/Negative_response_format.tgn @@ -0,0 +1 @@ +{"rows_views":[[{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}}],[{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}}],[{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}}],[{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}}]],"model":{"rows":[[{"value":"Byte","cspan":1,"rspan":1,"markup":[1,4]},{"value":"Description","cspan":1,"rspan":1,"markup":[1,11]},{"value":"Value","cspan":1,"rspan":1,"markup":[1,5]}],[{"value":"1","cspan":1,"rspan":1,"markup":[1,1]},{"value":"Negative Response SID","cspan":1,"rspan":1,"markup":[1,21]},{"value":"0x7F","cspan":1,"rspan":1,"markup":[1,4]}],[{"value":"2","cspan":1,"rspan":1,"markup":[1,1]},{"value":"Request SID","cspan":1,"rspan":1,"markup":[1,11]},{"value":"SID","cspan":1,"rspan":1,"markup":[1,3]}],[{"value":"3","cspan":1,"rspan":1,"markup":[1,1]},{"value":"NRC","cspan":1,"rspan":1,"markup":[1,3]},{"value":"XX","cspan":1,"rspan":1,"markup":[1,2]}]]},"theme":null,"fixed_layout":false,"markup":{"instances":[{},{"style":{"fontWeight":"","fontStyle":"","textDecoration":"","color":"","backgroundColor":""}},null]},"options":{}} \ No newline at end of file diff --git a/docs/source/tables/Positive_response_format.tgn b/docs/source/tables/Positive_response_format.tgn new file mode 100644 index 00000000..57797f50 --- /dev/null +++ b/docs/source/tables/Positive_response_format.tgn @@ -0,0 +1 @@ +{"rows_views":[[{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}}],[{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}}],[{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}}],[{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"lrtb","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}}],[{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}}]],"model":{"rows":[[{"value":"Byte","cspan":1,"rspan":1,"markup":[1,4]},{"value":"Description","cspan":1,"rspan":1,"markup":[1,11]},{"value":"Value","cspan":1,"rspan":1,"markup":[1,5]}],[{"value":"1","cspan":1,"rspan":1,"markup":[1,1]},{"value":"Response SID","cspan":1,"rspan":1,"markup":[1,12]},{"value":"SID + 0x40","cspan":1,"rspan":1,"markup":[1,10]}],[{"value":"2","cspan":1,"rspan":1,"markup":[1,1]},{"value":"data-parameter#1","cspan":1,"rspan":1,"markup":[1,16]},{"value":"XX","cspan":1,"rspan":1,"markup":[1,2]}],[{"value":"...","cspan":1,"rspan":1,"markup":[1,3]},{"value":"...","cspan":1,"rspan":1,"markup":[1,3]},{"value":"...","cspan":1,"rspan":1,"markup":[1,3]}],[{"value":"n","cspan":1,"rspan":1,"markup":[1,1]},{"value":"data-parameter#n","cspan":1,"rspan":1,"markup":[1,16]},{"value":"XX","cspan":1,"rspan":1,"markup":[1,2]}]]},"theme":null,"fixed_layout":false,"markup":{"instances":[{},{"style":{"fontWeight":"","fontStyle":"","textDecoration":"","color":"","backgroundColor":""}},null]},"options":{}} \ No newline at end of file diff --git a/tests/software_tests/messages/test_npdu.py b/tests/software_tests/messages/test_npdu.py deleted file mode 100644 index ec6e5382..00000000 --- a/tests/software_tests/messages/test_npdu.py +++ /dev/null @@ -1,158 +0,0 @@ -import pytest -from mock import Mock, patch - -from uds.messages.npdu import AbstractNPDU, AbstractNPCI, AbstractNPDURecord, \ - AddressingType, NibbleEnum, ValidatedEnum, ExtendableEnum, TransmissionDirection, ReassignmentError - - -class TestAbstractNPDUType: - """Tests for 'AbstractNPDUType' class.""" - - def test_inheritance__nibble_enum(self): - assert issubclass(AbstractNPCI, NibbleEnum) - - def test_inheritance__validated_enum(self): - assert issubclass(AbstractNPCI, ValidatedEnum) - - def test_inheritance__extendable_enum(self): - assert issubclass(AbstractNPCI, ExtendableEnum) - - -class TestAbstractNPDU: - """Tests for 'AbstractNPDU' class.""" - - SCRIPT_LOCATION = "uds.messages.npdu" - - def setup(self): - self.mock_abstract_npdu = Mock(spec=AbstractNPDU) - # patching - self._patcher_validate_raw_bytes = patch(f"{self.SCRIPT_LOCATION}.validate_raw_bytes") - self.mock_validate_raw_bytes = self._patcher_validate_raw_bytes.start() - self._patcher_validate_addressing_type = patch(f"{self.SCRIPT_LOCATION}.AddressingType.validate_member") - self.mock_validate_addressing_type = self._patcher_validate_addressing_type.start() - - def teardown(self): - self._patcher_validate_raw_bytes.stop() - self._patcher_validate_addressing_type.stop() - - # __init__ - - @pytest.mark.parametrize("raw_bytes", [None, 1, "some value", (1, 2, 3), [0x00, 0xFF]]) - @pytest.mark.parametrize("addressing_type", [None, 1, "some addressing", AddressingType.PHYSICAL]) - def test_init__valid(self, raw_bytes, addressing_type): - AbstractNPDU.__init__(self=self.mock_abstract_npdu, raw_data=raw_bytes, addressing=addressing_type) - assert self.mock_abstract_npdu.raw_data == raw_bytes - assert self.mock_abstract_npdu.addressing == addressing_type - - # raw_data - - @pytest.mark.parametrize("value_stored", [None, 0, (2, 3)]) - def test_raw_data__get(self, value_stored): - self.mock_abstract_npdu._AbstractNPDU__raw_data = value_stored - assert AbstractNPDU.raw_data.fget(self=self.mock_abstract_npdu) is value_stored - - def test_raw_data__set(self, example_raw_bytes): - AbstractNPDU.raw_data.fset(self=self.mock_abstract_npdu, value=example_raw_bytes) - self.mock_validate_raw_bytes.assert_called_once_with(example_raw_bytes) - assert self.mock_abstract_npdu._AbstractNPDU__raw_data == tuple(example_raw_bytes) - - # addressing - - @pytest.mark.parametrize("value_stored", [None, 0, False, AddressingType.PHYSICAL]) - def test_addressing__get(self, value_stored): - self.mock_abstract_npdu._AbstractNPDU__addressing = value_stored - assert AbstractNPDU.addressing.fget(self=self.mock_abstract_npdu) is value_stored - - def test_addressing__set_instance(self, example_addressing_type): - AbstractNPDU.addressing.fset(self=self.mock_abstract_npdu, value=example_addressing_type) - self.mock_validate_addressing_type.assert_called_once_with(example_addressing_type) - assert self.mock_abstract_npdu._AbstractNPDU__addressing == example_addressing_type - - def test_addressing__set_value(self, example_addressing_type): - AbstractNPDU.addressing.fset(self=self.mock_abstract_npdu, value=example_addressing_type.value) - self.mock_validate_addressing_type.assert_called_once_with(example_addressing_type.value) - assert self.mock_abstract_npdu._AbstractNPDU__addressing == example_addressing_type - - -class TestAbstractNPDURecord: - """Tests for 'AbstractNPDURecord' class.""" - - SCRIPT_LOCATION = TestAbstractNPDU.SCRIPT_LOCATION - - def setup(self): - self.mock_pdu_record = Mock(spec=AbstractNPDURecord) - # patching - self._patcher_validate_direction = patch(f"{self.SCRIPT_LOCATION}.TransmissionDirection.validate_member") - self.mock_validate_direction = self._patcher_validate_direction.start() - - def teardown(self): - self._patcher_validate_direction.stop() - - # __init__ - - @pytest.mark.parametrize("frame", [None, Mock(), 1]) - @pytest.mark.parametrize("direction", ["Some Direction"] + list(TransmissionDirection)) - def test_init(self, frame, direction): - AbstractNPDURecord.__init__(self=self.mock_pdu_record, frame=frame, direction=direction) - assert self.mock_pdu_record.frame == frame - assert self.mock_pdu_record.direction == direction - - # __get_raw_pdu_type - - @pytest.mark.parametrize("raw_data, expected_result", [ - ([0x12], 0x1), - ([0x00, 0x11, 0x22, 0x33], 0x0), - ((0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10), 0xF), - ((0xA5, 0x55, 0x33), 0xA), - ]) - def test_get_raw_pdu_type(self, raw_data, expected_result): - self.mock_pdu_record.raw_data = raw_data - assert AbstractNPDURecord._AbstractNPDURecord__get_raw_pci(self=self.mock_pdu_record) == expected_result - - # frame - - @pytest.mark.parametrize("frame", [None, 0, "some frame"]) - def test_frame__get(self, frame): - self.mock_pdu_record._AbstractNPDURecord__frame = frame - assert AbstractNPDURecord.frame.fget(self=self.mock_pdu_record) == frame - - @pytest.mark.parametrize("frame", [None, 0, "some frame"]) - def test_frame__set(self, frame): - AbstractNPDURecord.frame.fset(self=self.mock_pdu_record, value=frame) - assert self.mock_pdu_record._AbstractNPDURecord__frame == frame - self.mock_pdu_record._AbstractNPDURecord__validate_frame.assert_called_once_with(frame) - - @pytest.mark.parametrize("old_value", [None, 0, "some frame"]) - @pytest.mark.parametrize("new_value", [None, True, "some frame", "some other frame"]) - def test_frame__set__second_attempt(self, old_value, new_value): - self.mock_pdu_record._AbstractNPDURecord__frame = old_value - with pytest.raises(ReassignmentError): - AbstractNPDURecord.frame.fset(self=self.mock_pdu_record, value=new_value) - assert self.mock_pdu_record._AbstractNPDURecord__frame == old_value - self.mock_pdu_record._AbstractNPDURecord__validate_frame.assert_not_called() - - # direction - - @pytest.mark.parametrize("direction", [None, "some direction"] + list(TransmissionDirection)) - def test_direction__get(self, direction): - self.mock_pdu_record._AbstractNPDURecord__direction = direction - assert AbstractNPDURecord.direction.fget(self=self.mock_pdu_record) == direction - - def test_direction__set_instance(self, example_transmission_direction): - AbstractNPDURecord.direction.fset(self=self.mock_pdu_record, value=example_transmission_direction) - assert self.mock_pdu_record._AbstractNPDURecord__direction == example_transmission_direction - self.mock_validate_direction.assert_called_once_with(example_transmission_direction) - - def test_direction__set_value(self, example_transmission_direction): - AbstractNPDURecord.direction.fset(self=self.mock_pdu_record, value=example_transmission_direction.value) - assert self.mock_pdu_record._AbstractNPDURecord__direction == example_transmission_direction - self.mock_validate_direction.assert_called_once_with(example_transmission_direction.value) - - @pytest.mark.parametrize("old_value", [None, 0, "some direction"]) - @pytest.mark.parametrize("new_value", [None, True, "some direction", "some other direction"]) - def test_direction__set__second_attempt(self, old_value, new_value): - self.mock_pdu_record._AbstractNPDURecord__direction = old_value - with pytest.raises(ReassignmentError): - AbstractNPDURecord.direction.fset(self=self.mock_pdu_record, value=new_value) - assert self.mock_pdu_record._AbstractNPDURecord__direction == old_value - self.mock_validate_direction.assert_not_called() diff --git a/tests/software_tests/messages/test_nrc.py b/tests/software_tests/messages/test_nrc.py new file mode 100644 index 00000000..7d265e8a --- /dev/null +++ b/tests/software_tests/messages/test_nrc.py @@ -0,0 +1,15 @@ +from uds.messages.nrc import NRC, \ + ByteEnum, ValidatedEnum, ExtendableEnum + + +class TestNRC: + """Tests for 'NRC' enum""" + + def test_inheritance__byte_enum(self): + assert issubclass(NRC, ByteEnum) + + def test_inheritance__validated_enum(self): + assert issubclass(NRC, ValidatedEnum) + + def test_inheritance__extendable_enum(self): + assert issubclass(NRC, ExtendableEnum) diff --git a/tests/software_tests/messages/test_packet.py b/tests/software_tests/messages/test_packet.py new file mode 100644 index 00000000..f5c98c89 --- /dev/null +++ b/tests/software_tests/messages/test_packet.py @@ -0,0 +1,166 @@ +import pytest +from mock import Mock, patch + +from uds.messages.uds_packet import AbstractUdsPacket, AbstractPacketType, AbstractUdsPacketRecord, \ + AddressingType, NibbleEnum, ValidatedEnum, ExtendableEnum, TransmissionDirection, ReassignmentError + + +class TestAbstractPacketType: + """Tests for 'AbstractPacketType' class.""" + + def test_inheritance__nibble_enum(self): + assert issubclass(AbstractPacketType, NibbleEnum) + + def test_inheritance__validated_enum(self): + assert issubclass(AbstractPacketType, ValidatedEnum) + + def test_inheritance__extendable_enum(self): + assert issubclass(AbstractPacketType, ExtendableEnum) + + +class TestAbstractUdsPacket: + """Tests for 'AbstractUdsPacket' class.""" + + SCRIPT_LOCATION = "uds.messages.uds_packet" + + def setup(self): + self.mock_abstract_packet = Mock(spec=AbstractUdsPacket) + # patching + self._patcher_validate_raw_bytes = patch(f"{self.SCRIPT_LOCATION}.validate_raw_bytes") + self.mock_validate_raw_bytes = self._patcher_validate_raw_bytes.start() + self._patcher_validate_addressing_type = patch(f"{self.SCRIPT_LOCATION}.AddressingType.validate_member") + self.mock_validate_addressing_type = self._patcher_validate_addressing_type.start() + + def teardown(self): + self._patcher_validate_raw_bytes.stop() + self._patcher_validate_addressing_type.stop() + + # __init__ + + @pytest.mark.parametrize("raw_bytes", [None, 1, "some value", (1, 2, 3), [0x00, 0xFF]]) + @pytest.mark.parametrize("addressing_type", [None, 1, "some addressing", AddressingType.PHYSICAL]) + def test_init__valid(self, raw_bytes, addressing_type): + AbstractUdsPacket.__init__(self=self.mock_abstract_packet, raw_data=raw_bytes, addressing=addressing_type) + assert self.mock_abstract_packet.raw_data == raw_bytes + assert self.mock_abstract_packet.addressing == addressing_type + + # raw_data + + @pytest.mark.parametrize("value_stored", [None, 0, (2, 3)]) + def test_raw_data__get(self, value_stored): + self.mock_abstract_packet._AbstractUdsPacket__raw_data = value_stored + assert AbstractUdsPacket.raw_data.fget(self=self.mock_abstract_packet) is value_stored + + def test_raw_data__set(self, example_raw_bytes): + AbstractUdsPacket.raw_data.fset(self=self.mock_abstract_packet, value=example_raw_bytes) + self.mock_validate_raw_bytes.assert_called_once_with(example_raw_bytes) + assert self.mock_abstract_packet._AbstractUdsPacket__raw_data == tuple(example_raw_bytes) + + def test_raw_message__set_second_call(self, example_raw_bytes): + self.mock_abstract_packet._AbstractUdsPacket__raw_data = "some value" + self.test_raw_data__set(example_raw_bytes=example_raw_bytes) + + # addressing + + @pytest.mark.parametrize("value_stored", [None, 0, False, AddressingType.PHYSICAL]) + def test_addressing__get(self, value_stored): + self.mock_abstract_packet._AbstractUdsPacket__addressing = value_stored + assert AbstractUdsPacket.addressing.fget(self=self.mock_abstract_packet) is value_stored + + def test_addressing__set_instance(self, example_addressing_type): + AbstractUdsPacket.addressing.fset(self=self.mock_abstract_packet, value=example_addressing_type) + self.mock_validate_addressing_type.assert_called_once_with(example_addressing_type) + assert self.mock_abstract_packet._AbstractUdsPacket__addressing == example_addressing_type + + def test_addressing__set_value(self, example_addressing_type): + AbstractUdsPacket.addressing.fset(self=self.mock_abstract_packet, value=example_addressing_type.value) + self.mock_validate_addressing_type.assert_called_once_with(example_addressing_type.value) + assert self.mock_abstract_packet._AbstractUdsPacket__addressing == example_addressing_type + + def test_addressing__set_second_call(self, example_addressing_type): + self.mock_abstract_packet._AbstractUdsPacket__addressing = "some value" + self.test_addressing__set_instance(example_addressing_type=example_addressing_type) + + +class TestAbstractUdsPacketRecord: + """Tests for 'AbstractUdsPacketRecord' class.""" + + SCRIPT_LOCATION = TestAbstractUdsPacket.SCRIPT_LOCATION + + def setup(self): + self.mock_packet_record = Mock(spec=AbstractUdsPacketRecord) + # patching + self._patcher_validate_direction = patch(f"{self.SCRIPT_LOCATION}.TransmissionDirection.validate_member") + self.mock_validate_direction = self._patcher_validate_direction.start() + + def teardown(self): + self._patcher_validate_direction.stop() + + # __init__ + + @pytest.mark.parametrize("frame", [None, Mock(), 1]) + @pytest.mark.parametrize("direction", ["Some Direction"] + list(TransmissionDirection)) + def test_init(self, frame, direction): + AbstractUdsPacketRecord.__init__(self=self.mock_packet_record, frame=frame, direction=direction) + assert self.mock_packet_record.frame == frame + assert self.mock_packet_record.direction == direction + + # __get_raw_packet_type + + @pytest.mark.parametrize("raw_data, expected_result", [ + ([0x12], 0x1), + ([0x00, 0x11, 0x22, 0x33], 0x0), + ((0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10), 0xF), + ((0xA5, 0x55, 0x33), 0xA), + ]) + def test_get_raw_packet_type(self, raw_data, expected_result): + self.mock_packet_record.raw_data = raw_data + assert AbstractUdsPacketRecord._AbstractUdsPacketRecord__get_raw_packet_type(self=self.mock_packet_record) == expected_result + + # frame + + @pytest.mark.parametrize("frame", [None, 0, "some frame"]) + def test_frame__get(self, frame): + self.mock_packet_record._AbstractUdsPacketRecord__frame = frame + assert AbstractUdsPacketRecord.frame.fget(self=self.mock_packet_record) == frame + + @pytest.mark.parametrize("frame", [None, 0, "some frame"]) + def test_frame__set(self, frame): + AbstractUdsPacketRecord.frame.fset(self=self.mock_packet_record, value=frame) + assert self.mock_packet_record._AbstractUdsPacketRecord__frame == frame + self.mock_packet_record._AbstractUdsPacketRecord__validate_frame.assert_called_once_with(frame) + + @pytest.mark.parametrize("old_value", [None, 0, "some frame"]) + @pytest.mark.parametrize("new_value", [None, True, "some frame", "some other frame"]) + def test_frame__set__second_attempt(self, old_value, new_value): + self.mock_packet_record._AbstractUdsPacketRecord__frame = old_value + with pytest.raises(ReassignmentError): + AbstractUdsPacketRecord.frame.fset(self=self.mock_packet_record, value=new_value) + assert self.mock_packet_record._AbstractUdsPacketRecord__frame == old_value + self.mock_packet_record._AbstractUdsPacketRecord__validate_frame.assert_not_called() + + # direction + + @pytest.mark.parametrize("direction", [None, "some direction"] + list(TransmissionDirection)) + def test_direction__get(self, direction): + self.mock_packet_record._AbstractUdsPacketRecord__direction = direction + assert AbstractUdsPacketRecord.direction.fget(self=self.mock_packet_record) == direction + + def test_direction__set_instance(self, example_transmission_direction): + AbstractUdsPacketRecord.direction.fset(self=self.mock_packet_record, value=example_transmission_direction) + assert self.mock_packet_record._AbstractUdsPacketRecord__direction == example_transmission_direction + self.mock_validate_direction.assert_called_once_with(example_transmission_direction) + + def test_direction__set_value(self, example_transmission_direction): + AbstractUdsPacketRecord.direction.fset(self=self.mock_packet_record, value=example_transmission_direction.value) + assert self.mock_packet_record._AbstractUdsPacketRecord__direction == example_transmission_direction + self.mock_validate_direction.assert_called_once_with(example_transmission_direction.value) + + @pytest.mark.parametrize("old_value", [None, 0, "some direction"]) + @pytest.mark.parametrize("new_value", [None, True, "some direction", "some other direction"]) + def test_direction__set__second_attempt(self, old_value, new_value): + self.mock_packet_record._AbstractUdsPacketRecord__direction = old_value + with pytest.raises(ReassignmentError): + AbstractUdsPacketRecord.direction.fset(self=self.mock_packet_record, value=new_value) + assert self.mock_packet_record._AbstractUdsPacketRecord__direction == old_value + self.mock_validate_direction.assert_not_called() diff --git a/tests/software_tests/messages/test_service_identifiers.py b/tests/software_tests/messages/test_service_identifiers.py index 9aefc035..0e798a76 100644 --- a/tests/software_tests/messages/test_service_identifiers.py +++ b/tests/software_tests/messages/test_service_identifiers.py @@ -1,59 +1,87 @@ import pytest from mock import patch -from uds.messages.service_identifiers import RequestSID, ResponseSID +from uds.messages.service_identifiers import RequestSID, ResponseSID, \ + ByteEnum, ValidatedEnum, ExtendableEnum class TestRequestSID: - """Tests for RequestSID enum""" + """Tests for 'RequestSID' enum.""" SCRIPT_LOCATION = "uds.messages.service_identifiers" - EXAMPLE_REQUEST_SIDS = [0x10, 0x14, 0x22, 0x86] - EXAMPLE_RESPONSE_SIDS = [0x50, 0x54, 0x62, 0xC6, 0x7F] def setup(self): self._patcher_warn = patch(f"{self.SCRIPT_LOCATION}.warn") self.mock_warn = self._patcher_warn.start() + self._patcher_is_member = patch(f"{self.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.mock_possible_request_sids = self._patcher_possible_request_sids.start() def teardown(self): self._patcher_warn.stop() + self._patcher_is_member.stop() + self._patcher_possible_request_sids.stop() - @pytest.mark.parametrize("valid_sid", EXAMPLE_REQUEST_SIDS) - def test_is_request_sid__true(self, valid_sid): - assert RequestSID.is_request_sid(value=valid_sid) is True + def test_inheritance__byte_enum(self): + assert issubclass(RequestSID, ByteEnum) - @pytest.mark.parametrize("invalid_value", [-1, "something", 2.3] + EXAMPLE_RESPONSE_SIDS) - def test_is_request_sid__false(self, invalid_value): - assert RequestSID.is_request_sid(value=invalid_value) is False + def test_inheritance__validated_enum(self): + assert issubclass(RequestSID, ValidatedEnum) - @patch(f"{SCRIPT_LOCATION}.POSSIBLE_REQUEST_SIDS") - @pytest.mark.parametrize("invalid_value", [-1, "something", 2.3]) - def test_is_request_sid__warning(self, mock_possible_request_sids, invalid_value): - mock_possible_request_sids.__contains__.return_value = True - RequestSID.is_request_sid(value=invalid_value) + @pytest.mark.parametrize("value", [1, 0x55, 0xFF]) + def test_is_request_sid__member(self, value): + self.mock_is_member.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() + + @pytest.mark.parametrize("value", [1, 0x55, 0xFF]) + def test_is_request_sid__unsupported(self, value): + self.mock_is_member.return_value = False + self.mock_possible_request_sids.__contains__.return_value = True + assert RequestSID.is_request_sid(value=value) is True self.mock_warn.assert_called_once() - - @patch(f"{SCRIPT_LOCATION}.POSSIBLE_REQUEST_SIDS") - @pytest.mark.parametrize("invalid_value", [-1, "something", 2.3]) - def test_is_request_sid__no_warning(self, mock_possible_request_sids, invalid_value): - mock_possible_request_sids.__contains__.return_value = False - RequestSID.is_request_sid(value=invalid_value) + self.mock_is_member.assert_called_once_with(value) + self.mock_possible_request_sids.__contains__.assert_called_once_with(value) + + @pytest.mark.parametrize("value", [1, 0x55, 0xFF]) + def test_is_request_sid__invalid(self, value): + self.mock_is_member.return_value = False + 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_possible_request_sids.__contains__.assert_called_once_with(value) class TestResponseSID: - """Tests for ResponseSID Enum""" + """Tests for 'ResponseSID' enum.""" SCRIPT_LOCATION = TestRequestSID.SCRIPT_LOCATION - EXAMPLE_REQUEST_SIDS = TestRequestSID.EXAMPLE_REQUEST_SIDS - EXAMPLE_RESPONSE_SIDS = TestRequestSID.EXAMPLE_RESPONSE_SIDS def setup(self): self._patcher_warn = patch(f"{self.SCRIPT_LOCATION}.warn") self.mock_warn = self._patcher_warn.start() + self._patcher_is_member = patch(f"{self.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.mock_possible_response_sids = self._patcher_possible_response_sids.start() def teardown(self): self._patcher_warn.stop() + self._patcher_is_member.stop() + self._patcher_possible_response_sids.stop() + + def test_inheritance__byte_enum(self): + assert issubclass(ResponseSID, ByteEnum) + + def test_inheritance__validated_enum(self): + assert issubclass(ResponseSID, ValidatedEnum) + + def test_inheritance__extendable_enum(self): + assert issubclass(ResponseSID, ExtendableEnum) def test_number_of_members(self): assert len(ResponseSID) == len(RequestSID) + 1, \ @@ -64,24 +92,28 @@ def test_rsid_members(self, request_sid_member): assert ResponseSID[request_sid_member.name] == request_sid_member.value + 0x40, \ "Verify each ResponseSID member has correct value (SID + 0x40)." - @pytest.mark.parametrize("valid_rsid", EXAMPLE_RESPONSE_SIDS) - def test_is_response_sid__true(self, valid_rsid): - assert ResponseSID.is_response_sid(value=valid_rsid) is True - - @pytest.mark.parametrize("invalid_value", [-1, "something", 2.3] + EXAMPLE_REQUEST_SIDS) - def test_is_response_sid__false(self, invalid_value): - assert ResponseSID.is_response_sid(value=invalid_value) is False - - @patch(f"{SCRIPT_LOCATION}.POSSIBLE_RESPONSE_SIDS") - @pytest.mark.parametrize("invalid_value", [-1, "something", 2.3]) - def test_is_request_sid__warning(self, mock_possible_response_sids, invalid_value): - mock_possible_response_sids.__contains__.return_value = True - ResponseSID.is_response_sid(value=invalid_value) + @pytest.mark.parametrize("value", [1, 0x55, 0xFF]) + def test_is_response_sid__member(self, value): + self.mock_is_member.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() + + @pytest.mark.parametrize("value", [1, 0x55, 0xFF]) + def test_is_response_sid__unsupported(self, value): + self.mock_is_member.return_value = False + self.mock_possible_response_sids.__contains__.return_value = True + assert ResponseSID.is_response_sid(value=value) is True self.mock_warn.assert_called_once() - - @patch(f"{SCRIPT_LOCATION}.POSSIBLE_RESPONSE_SIDS") - @pytest.mark.parametrize("invalid_value", [-1, "something", 2.3]) - def test_is_request_sid__no_warning(self, mock_possible_response_sids, invalid_value): - mock_possible_response_sids.__contains__.return_value = False - ResponseSID.is_response_sid(value=invalid_value) + self.mock_is_member.assert_called_once_with(value) + self.mock_possible_response_sids.__contains__.assert_called_once_with(value) + + @pytest.mark.parametrize("value", [1, 0x55, 0xFF]) + def test_is_response_sid__invalid(self, value): + self.mock_is_member.return_value = False + 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_possible_response_sids.__contains__.assert_called_once_with(value) diff --git a/tests/software_tests/messages/test_uds_message.py b/tests/software_tests/messages/test_uds_message.py index 72cd0312..b681be0d 100644 --- a/tests/software_tests/messages/test_uds_message.py +++ b/tests/software_tests/messages/test_uds_message.py @@ -2,7 +2,7 @@ from mock import Mock, patch from uds.messages.uds_message import UdsMessage, UdsMessageRecord, \ - AddressingType, TransmissionDirection, ReassignmentError, AbstractNPDURecord + AddressingType, TransmissionDirection, ReassignmentError, AbstractUdsPacketRecord class TestUdsMessage: @@ -89,32 +89,32 @@ def teardown(self): # __init__ @pytest.mark.parametrize("raw_message", [None, [0x1, 0x02], "some message"]) - @pytest.mark.parametrize("npdu_sequence", [False, [1, 2, 3, 4], "abcdef"]) - def test_init(self, raw_message, npdu_sequence): + @pytest.mark.parametrize("packets_records", [False, [1, 2, 3, 4], "abcdef"]) + def test_init(self, raw_message, packets_records): UdsMessageRecord.__init__(self=self.mock_uds_message_record, raw_message=raw_message, - npdu_sequence=npdu_sequence) + packets_records=packets_records) assert self.mock_uds_message_record.raw_message == raw_message - assert self.mock_uds_message_record.npdu_sequence == npdu_sequence + assert self.mock_uds_message_record.packets_records == packets_records - # __validate_npdu_sequence + # __validate_packets_records @pytest.mark.parametrize("value", [ - (Mock(spec=AbstractNPDURecord),), - [Mock(spec=AbstractNPDURecord), Mock(spec=AbstractNPDURecord)], - (Mock(spec=AbstractNPDURecord), Mock(spec=AbstractNPDURecord), Mock(spec=AbstractNPDURecord)) + (Mock(spec=AbstractUdsPacketRecord),), + [Mock(spec=AbstractUdsPacketRecord), Mock(spec=AbstractUdsPacketRecord)], + (Mock(spec=AbstractUdsPacketRecord), Mock(spec=AbstractUdsPacketRecord), Mock(spec=AbstractUdsPacketRecord)) ]) - def test_validate_npdu_sequence__valid(self, value): - assert UdsMessageRecord._UdsMessageRecord__validate_npdu_sequence(npdu_sequence=value) is None + def test_validate_packets_records__valid(self, value): + assert UdsMessageRecord._UdsMessageRecord__validate_packets_records(packets_records=value) is None - @pytest.mark.parametrize("value", [None, False, 0, Mock(spec=AbstractNPDURecord)]) - def test_validate_npdu_sequence__invalid_type(self, value): + @pytest.mark.parametrize("value", [None, False, 0, Mock(spec=AbstractUdsPacketRecord)]) + def test_validate_packets_records__invalid_type(self, value): with pytest.raises(TypeError): - UdsMessageRecord._UdsMessageRecord__validate_npdu_sequence(npdu_sequence=value) + UdsMessageRecord._UdsMessageRecord__validate_packets_records(packets_records=value) - @pytest.mark.parametrize("value", [tuple(), [], ["a"], (None, ), (Mock(spec=AbstractNPDURecord), "not N_PDU")]) - def test_validate_npdu_sequence__invalid_value(self, value): + @pytest.mark.parametrize("value", [tuple(), [], ["a"], (None, ), (Mock(spec=AbstractUdsPacketRecord), "not N_PDU")]) + def test_validate_packets_records__invalid_value(self, value): with pytest.raises(ValueError): - UdsMessageRecord._UdsMessageRecord__validate_npdu_sequence(npdu_sequence=value) + UdsMessageRecord._UdsMessageRecord__validate_packets_records(packets_records=value) # raw_message @@ -137,76 +137,76 @@ def test_raw_message__set__second_call(self, old_value, new_value): assert self.mock_uds_message_record._UdsMessageRecord__raw_message == old_value self.mock_validate_raw_bytes.assert_not_called() - # npdu_sequence + # packets_records @pytest.mark.parametrize("value", [None, [Mock(), Mock()], "some sequence"]) - def test_npdu_sequence__get(self, value): - self.mock_uds_message_record._UdsMessageRecord__npdu_sequence = value - assert UdsMessageRecord.npdu_sequence.fget(self.mock_uds_message_record) is value + def test_packets_records__get(self, value): + self.mock_uds_message_record._UdsMessageRecord__packets_records = value + assert UdsMessageRecord.packets_records.fget(self.mock_uds_message_record) is value - @pytest.mark.parametrize("npdu_sequence", [ + @pytest.mark.parametrize("packets_records", [ (Mock(), Mock(), Mock()), [1, 2, 3, 4], "abcdefg" ]) - def test_npdu_sequence__set__first_call(self, npdu_sequence): - UdsMessageRecord.npdu_sequence.fset(self=self.mock_uds_message_record, value=npdu_sequence) - assert self.mock_uds_message_record._UdsMessageRecord__npdu_sequence == tuple(npdu_sequence) - self.mock_uds_message_record._UdsMessageRecord__validate_npdu_sequence.assert_called_once_with(npdu_sequence) + def test_packets_records__set__first_call(self, packets_records): + UdsMessageRecord.packets_records.fset(self=self.mock_uds_message_record, value=packets_records) + assert self.mock_uds_message_record._UdsMessageRecord__packets_records == tuple(packets_records) + self.mock_uds_message_record._UdsMessageRecord__validate_packets_records.assert_called_once_with(packets_records) @pytest.mark.parametrize("old_value", [(Mock(), Mock(), Mock()), [1, 2, 3, 4], "abcdefg"]) @pytest.mark.parametrize("new_value", [(Mock(), Mock(), Mock()), [1, 2, 3, 4], "abcdefg"]) - def test_npdu_sequence__set__second_call(self, old_value, new_value): - self.mock_uds_message_record._UdsMessageRecord__npdu_sequence = old_value + def test_packets_records__set__second_call(self, old_value, new_value): + self.mock_uds_message_record._UdsMessageRecord__packets_records = old_value with pytest.raises(ReassignmentError): - UdsMessageRecord.npdu_sequence.fset(self=self.mock_uds_message_record, value=new_value) - assert self.mock_uds_message_record._UdsMessageRecord__npdu_sequence == old_value - self.mock_uds_message_record._UdsMessageRecord__validate_npdu_sequence.assert_not_called() + UdsMessageRecord.packets_records.fset(self=self.mock_uds_message_record, value=new_value) + assert self.mock_uds_message_record._UdsMessageRecord__packets_records == old_value + self.mock_uds_message_record._UdsMessageRecord__validate_packets_records.assert_not_called() # addressing - @pytest.mark.parametrize("npdu_sequence", [ - (Mock(spec=AbstractNPDURecord, addressing=AddressingType.PHYSICAL), ), - (Mock(spec=AbstractNPDURecord, addressing=AddressingType.FUNCTIONAL), - Mock(spec=AbstractNPDURecord, addressing=AddressingType.PHYSICAL)), + @pytest.mark.parametrize("packets_records", [ + (Mock(spec=AbstractUdsPacketRecord, addressing=AddressingType.PHYSICAL),), + (Mock(spec=AbstractUdsPacketRecord, addressing=AddressingType.FUNCTIONAL), + Mock(spec=AbstractUdsPacketRecord, addressing=AddressingType.PHYSICAL)), ]) - def test_addressing__get(self, npdu_sequence): - self.mock_uds_message_record.npdu_sequence = npdu_sequence - assert UdsMessageRecord.addressing.fget(self=self.mock_uds_message_record) == npdu_sequence[0].addressing + def test_addressing__get(self, packets_records): + self.mock_uds_message_record.packets_records = packets_records + assert UdsMessageRecord.addressing.fget(self=self.mock_uds_message_record) == packets_records[0].addressing # direction - @pytest.mark.parametrize("npdu_sequence", [ - (Mock(spec=AbstractNPDURecord, direction=TransmissionDirection.RECEIVED), ), - (Mock(spec=AbstractNPDURecord, direction=TransmissionDirection.TRANSMITTED), - Mock(spec=AbstractNPDURecord, direction=TransmissionDirection.RECEIVED)), + @pytest.mark.parametrize("packets_records", [ + (Mock(spec=AbstractUdsPacketRecord, direction=TransmissionDirection.RECEIVED),), + (Mock(spec=AbstractUdsPacketRecord, direction=TransmissionDirection.TRANSMITTED), + Mock(spec=AbstractUdsPacketRecord, direction=TransmissionDirection.RECEIVED)), ]) - def test_direction__get(self, npdu_sequence): - self.mock_uds_message_record.npdu_sequence = npdu_sequence - assert UdsMessageRecord.direction.fget(self=self.mock_uds_message_record) == npdu_sequence[0].direction + def test_direction__get(self, packets_records): + self.mock_uds_message_record.packets_records = packets_records + assert UdsMessageRecord.direction.fget(self=self.mock_uds_message_record) == packets_records[0].direction # transmission_start - @pytest.mark.parametrize("npdu_sequence", [ - (Mock(spec=AbstractNPDURecord, transmission_time=0),), - (Mock(spec=AbstractNPDURecord, transmission_time=1), Mock(spec=AbstractNPDURecord, transmission_time=2)), - (Mock(spec=AbstractNPDURecord, transmission_time=9654.3), Mock(spec=AbstractNPDURecord, transmission_time=-453), - Mock(spec=AbstractNPDURecord, transmission_time=3.2),), + @pytest.mark.parametrize("packets_records", [ + (Mock(spec=AbstractUdsPacketRecord, transmission_time=0),), + (Mock(spec=AbstractUdsPacketRecord, transmission_time=1), Mock(spec=AbstractUdsPacketRecord, transmission_time=2)), + (Mock(spec=AbstractUdsPacketRecord, transmission_time=9654.3), Mock(spec=AbstractUdsPacketRecord, transmission_time=-453), + Mock(spec=AbstractUdsPacketRecord, transmission_time=3.2),), ]) - def test_transmission_start__get(self, npdu_sequence): - self.mock_uds_message_record.npdu_sequence = npdu_sequence + def test_transmission_start__get(self, packets_records): + self.mock_uds_message_record.packets_records = packets_records assert UdsMessageRecord.transmission_start.fget(self=self.mock_uds_message_record) \ - == npdu_sequence[0].transmission_time + == packets_records[0].transmission_time # transmission_end - @pytest.mark.parametrize("npdu_sequence", [ - (Mock(spec=AbstractNPDURecord, transmission_time=0),), - (Mock(spec=AbstractNPDURecord, transmission_time=1), Mock(spec=AbstractNPDURecord, transmission_time=2)), - (Mock(spec=AbstractNPDURecord, transmission_time=9654.3), Mock(spec=AbstractNPDURecord, transmission_time=-453), - Mock(spec=AbstractNPDURecord, transmission_time=3.2),), + @pytest.mark.parametrize("packets_records", [ + (Mock(spec=AbstractUdsPacketRecord, transmission_time=0),), + (Mock(spec=AbstractUdsPacketRecord, transmission_time=1), Mock(spec=AbstractUdsPacketRecord, transmission_time=2)), + (Mock(spec=AbstractUdsPacketRecord, transmission_time=9654.3), Mock(spec=AbstractUdsPacketRecord, transmission_time=-453), + Mock(spec=AbstractUdsPacketRecord, transmission_time=3.2),), ]) - def test_transmission_end__get(self, npdu_sequence): - self.mock_uds_message_record.npdu_sequence = npdu_sequence + def test_transmission_end__get(self, packets_records): + self.mock_uds_message_record.packets_records = packets_records assert UdsMessageRecord.transmission_end.fget(self=self.mock_uds_message_record) \ - == npdu_sequence[-1].transmission_time + == packets_records[-1].transmission_time diff --git a/uds/messages/__init__.py b/uds/messages/__init__.py index 6586321f..5b875973 100644 --- a/uds/messages/__init__.py +++ b/uds/messages/__init__.py @@ -1,6 +1,6 @@ """Module with basic tools to handle UDS messages.""" -from .npdu import AbstractNPCI, AbstractNPDU, AbstractNPDURecord +from .uds_packet import AbstractPacketType, AbstractUdsPacket, AbstractUdsPacketRecord from .uds_message import UdsMessage, UdsMessageRecord from .service_identifiers import RequestSID, ResponseSID, POSSIBLE_REQUEST_SIDS, POSSIBLE_RESPONSE_SIDS from .nrc import NRC diff --git a/uds/messages/nrc.py b/uds/messages/nrc.py index d8c7115d..5f8d00f1 100644 --- a/uds/messages/nrc.py +++ b/uds/messages/nrc.py @@ -4,11 +4,11 @@ from aenum import unique -from uds.utilities import ByteEnum +from uds.utilities import ByteEnum, ValidatedEnum, ExtendableEnum -@unique -class NRC(ByteEnum): +@unique # pylint: disable=too-many-ancestors +class NRC(ByteEnum, ValidatedEnum, ExtendableEnum): # pylint: disable=too-many-ancestors """ Storage for all known Negative Response Codes (NRC). diff --git a/uds/messages/service_identifiers.py b/uds/messages/service_identifiers.py index a3288399..db2d37e7 100644 --- a/uds/messages/service_identifiers.py +++ b/uds/messages/service_identifiers.py @@ -4,19 +4,19 @@ from warnings import warn -from aenum import unique, extend_enum +from aenum import unique -from uds.utilities import RawByte, ByteEnum +from uds.utilities import RawByte, ByteEnum, ValidatedEnum, ExtendableEnum # reserved SID values -_REQUEST_SIDS_DEFINED_IN_SAEJ1979 = set(range(0x01, 0x10)) -_RESPONSE_SIDS_DEFINED_IN_SAEJ1979 = set(range(0x41, 0x50)) -_REQUEST_SIDS_DEFINED_IN_ISO_14229 = set(range(0x10, 0x3F)).union(set(range(0x83, 0x89)), set(range(0xBA, 0xBF))) -_RESPONSE_SIDS_DEFINED_IN_ISO_14229 = set(range(0x50, 0x80)).union(set(range(0xC3, 0xC9)), set(range(0xFA, 0xFF))) +_REQUEST_SIDS_DEFINED_BY_SAEJ1979 = set(range(0x01, 0x10)) +_RESPONSE_SIDS_DEFINED_BY_SAEJ1979 = set(range(0x41, 0x50)) +_REQUEST_SIDS_DEFINED_BY_ISO_14229 = set(range(0x10, 0x3F)).union(set(range(0x83, 0x89)), set(range(0xBA, 0xBF))) +_RESPONSE_SIDS_DEFINED_BY_ISO_14229 = set(range(0x50, 0x80)).union(set(range(0xC3, 0xC9)), set(range(0xFA, 0xFF))) # all supported SID values according to UDS -POSSIBLE_REQUEST_SIDS = _REQUEST_SIDS_DEFINED_IN_SAEJ1979.union(_REQUEST_SIDS_DEFINED_IN_ISO_14229) -POSSIBLE_RESPONSE_SIDS = _RESPONSE_SIDS_DEFINED_IN_SAEJ1979.union(_RESPONSE_SIDS_DEFINED_IN_ISO_14229) +POSSIBLE_REQUEST_SIDS = _REQUEST_SIDS_DEFINED_BY_SAEJ1979.union(_REQUEST_SIDS_DEFINED_BY_ISO_14229) +POSSIBLE_RESPONSE_SIDS = _RESPONSE_SIDS_DEFINED_BY_SAEJ1979.union(_RESPONSE_SIDS_DEFINED_BY_ISO_14229) class UnsupportedSID(Warning): @@ -29,7 +29,7 @@ class UnsupportedSID(Warning): @unique -class RequestSID(ByteEnum): +class RequestSID(ByteEnum, ValidatedEnum): """ Storage for all known Service Identifiers (SID). @@ -45,13 +45,11 @@ def is_request_sid(cls, value: RawByte) -> bool: :return: True if value is int of known SID, else False. """ - try: - cls(value) - return True - except ValueError: - if value in POSSIBLE_REQUEST_SIDS: - warn(message=f"SID {value} is not supported by this version of the package", category=UnsupportedSID) - return False + if not cls.is_member(value): + if value not in POSSIBLE_REQUEST_SIDS: + return False + warn(message=f"SID 0x{value:X} is not supported by this version of the package", category=UnsupportedSID) + return True # Diagnostic and communication management - more information in ISO 14229-1:2020, chapter 10 DiagnosticSessionControl = 0x10 # noqa: F841 @@ -87,8 +85,8 @@ def is_request_sid(cls, value: RawByte) -> bool: SecuredDataTransmission = 0x84 # noqa: F841 -@unique -class ResponseSID(ByteEnum): +@unique # pylint: disable=too-many-ancestors +class ResponseSID(ByteEnum, ValidatedEnum, ExtendableEnum): # pylint: disable=too-many-ancestors """ Storage for all known Response Service Identifiers (RSID). @@ -104,17 +102,15 @@ def is_response_sid(cls, value: RawByte) -> bool: :return: True if value is int of known RSID, else False. """ - try: - cls(value) - return True - except ValueError: - if value in POSSIBLE_RESPONSE_SIDS: - warn(message=f"RSID {value} is not supported by this version of the package", category=UnsupportedSID) - return False + if not cls.is_member(value): + if value not in POSSIBLE_RESPONSE_SIDS: + return False + warn(message=f"RSID 0x{value:X} is not supported by this version of the package", category=UnsupportedSID) + return True NegativeResponse = 0x7F # noqa: F841 # extend 'ResponseSID' with members that were defined in RequestSID -for request_name, request_enum_member in RequestSID.__members__.items(): # TODO: make it smoother - extend_enum(ResponseSID, request_name, request_enum_member.value + 0x40) +for request_sid_member in RequestSID: # type: ignore + ResponseSID.add_member(request_sid_member.name, request_sid_member.value + 0x40) diff --git a/uds/messages/uds_message.py b/uds/messages/uds_message.py index 34929922..14f715e9 100644 --- a/uds/messages/uds_message.py +++ b/uds/messages/uds_message.py @@ -6,10 +6,11 @@ from uds.utilities import RawBytes, RawBytesTuple, validate_raw_bytes, ReassignmentError, TimeStamp from .transmission_attributes import AddressingType, AddressingMemberTyping, TransmissionDirection -from .npdu import AbstractNPDURecord +from .uds_packet import AbstractUdsPacketRecord -NPDURecordsTuple = Tuple[AbstractNPDURecord, ...] -NPDURecordsSequence = Union[NPDURecordsTuple, List[AbstractNPDURecord]] # pylint: disable=unsubscriptable-object +PacketsRecordsTuple = Tuple[AbstractUdsPacketRecord, ...] +PacketsRecordsSequence = Union[PacketsRecordsTuple, # pylint: disable=unsubscriptable-object + List[AbstractUdsPacketRecord]] class UdsMessage: @@ -59,32 +60,34 @@ def addressing(self, value: AddressingMemberTyping): class UdsMessageRecord: """Definition of a record that stores historic information about transmitted or received UDSMessage.""" - def __init__(self, raw_message: RawBytes, npdu_sequence: NPDURecordsSequence) -> None: + def __init__(self, raw_message: RawBytes, packets_records: PacketsRecordsSequence) -> None: """ Create a historic record of a diagnostic message that was either received of transmitted to a bus. :param raw_message: Raw bytes of data that this diagnostic message carried. - :param npdu_sequence: Record of N_PDUs (in transmission order) that carried this diagnostic message. + :param packets_records: Sequence (in transmission order) of UDS packets records that carried this + diagnostic message. """ self.raw_message = raw_message # type: ignore - self.npdu_sequence = npdu_sequence # type: ignore + self.packets_records = packets_records # type: ignore @staticmethod - def __validate_npdu_sequence(npdu_sequence: NPDURecordsSequence) -> None: + def __validate_packets_records(packets_records: PacketsRecordsSequence) -> None: """ - Validate N_PDUs sequence argument. + Validate UDS Packet Records sequence argument. - :param npdu_sequence: Value of N_PDUs sequence to validate. + :param packets_records: Value of UDS Packet Records sequence to validate. - :raise TypeError: N_PDUs sequence is not list or tuple type. - :raise ValueError: At least one of N_PDUs sequence elements is not an object of N_PDU. + :raise TypeError: UDS Packet Records sequence is not list or tuple type. + :raise ValueError: At least one of UDS Packet Records sequence elements is not an object of + AbstractUdsPacketRecord class. """ - if not isinstance(npdu_sequence, (tuple, list)): - raise TypeError(f"Provided value of 'npdu_sequence' is not list or tuple type. " - f"Actual type: {type(npdu_sequence)}.") - if not npdu_sequence or any([not isinstance(npdu, AbstractNPDURecord) for npdu in npdu_sequence]): - raise ValueError(f"Provided value of 'npdu_sequence' must contain only instances of AbstractNPDURecord " - f"class. Actual value: {npdu_sequence}") + if not isinstance(packets_records, (tuple, list)): + raise TypeError(f"Provided value of 'packets_records' is not list or tuple type. " + f"Actual type: {type(packets_records)}.") + if not packets_records or any([not isinstance(packet, AbstractUdsPacketRecord) for packet in packets_records]): + raise ValueError(f"Provided value of 'packets_records' must contain only instances of " + f"AbstractUdsPacketRecord class. Actual value: {packets_records}") @property def raw_message(self) -> RawBytesTuple: @@ -109,57 +112,57 @@ def raw_message(self, value: RawBytes): raise ReassignmentError("You cannot change value of 'raw_message' attribute once it is assigned.") @property - def npdu_sequence(self) -> NPDURecordsTuple: - """Sequence (in transmission order) of Network Protocol Data Units that carried this diagnostic message.""" - return self.__npdu_sequence + def packets_records(self) -> PacketsRecordsTuple: + """Sequence (in transmission order) of UDS packets records that carried this diagnostic message.""" + return self.__packets_records - @npdu_sequence.setter - def npdu_sequence(self, value: NPDURecordsSequence): + @packets_records.setter + def packets_records(self, value: PacketsRecordsSequence): """ - Assign N_PDUs which carried this diagnostic message . + Assign records value of UDS Packets that carried this diagnostic message . - :param value: N_PDUs sequence value to set. + :param value: UDS Packet Records sequence value to set. :raise ReassignmentError: There is a call to change the value after the initial assignment (in __init__). """ try: - self.__getattribute__("_UdsMessageRecord__npdu_sequence") + self.__getattribute__("_UdsMessageRecord__packets_records") except AttributeError: - self.__validate_npdu_sequence(value) - self.__npdu_sequence = tuple(value) + self.__validate_packets_records(value) + self.__packets_records = tuple(value) else: - raise ReassignmentError("You cannot change value of 'npdu_sequence' attribute once it is assigned.") + raise ReassignmentError("You cannot change value of 'packets_records' attribute once it is assigned.") @property def addressing(self) -> AddressingType: """Addressing type which was used to transmit this message.""" - return self.npdu_sequence[0].addressing + return self.packets_records[0].addressing @property def direction(self) -> TransmissionDirection: """Information whether this message was received or sent by the code.""" - return self.npdu_sequence[0].direction + return self.packets_records[0].direction @property # noqa: F841 def transmission_start(self) -> TimeStamp: """ Time stamp when transmission of this messages was initiated. - It is determined by a moment of time when the first N_PDU (that carried this message) was either published + It is determined by a moment of time when the first packet (that carried this message) was published to a bus (either received or transmitted). :return: Time stamp when transmission of this message was initiated. """ - return self.npdu_sequence[0].transmission_time + return self.packets_records[0].transmission_time @property # noqa: F841 def transmission_end(self) -> TimeStamp: """ Time stamp when transmission of this messages was completed. - It is determined by a moment of time when the last N_PDU (that carried this message) was either published + It is determined by a moment of time when the last packet (that carried this message) was published to a bus (either received or transmitted). :return: Time stamp when transmission of this message was completed. """ - return self.npdu_sequence[-1].transmission_time + return self.packets_records[-1].transmission_time diff --git a/uds/messages/npdu.py b/uds/messages/uds_packet.py similarity index 63% rename from uds/messages/npdu.py rename to uds/messages/uds_packet.py index 275a1e3c..fdeb994f 100644 --- a/uds/messages/npdu.py +++ b/uds/messages/uds_packet.py @@ -1,6 +1,6 @@ -"""Common implementation of UDS N_PDU (Network Protocol Data Unit) for all bus types.""" +"""Common implementation of UDS packets for all bus types.""" -__all__ = ["AbstractNPCI", "AbstractNPDU", "AbstractNPDURecord"] +__all__ = ["AbstractPacketType", "AbstractUdsPacket", "AbstractUdsPacketRecord"] from abc import ABC, abstractmethod from typing import Any @@ -12,31 +12,33 @@ TransmissionDirection, DirectionMemberTyping -class AbstractNPCI(NibbleEnum, ValidatedEnum, ExtendableEnum): # pylint: disable=too-many-ancestors +class AbstractPacketType(NibbleEnum, ValidatedEnum, ExtendableEnum): # pylint: disable=too-many-ancestors """ - Abstract definition of Protocol Control Information (N_PCI). + Abstract definition of UDS packet type. - Enum with N_PCI for certain buses (e.g. CAN, LIN, FlexRay) must inherit after this class. - There are some differences in available values for each bus (e.g. LIN does not use Flow Control). + Packet type information is carried by Network Protocol Control Information (N_PCI). + Enums with packet types (N_PCI) values for certain buses (e.g. CAN, LIN, FlexRay) must inherit after this class. + + Note: There are some differences in values for each bus (e.g. LIN does not use Flow Control). """ -class AbstractNPDU(ABC): - """Abstract definition of N_PDU (Network Protocol Data Unit) that is a packet of diagnostic message.""" +class AbstractUdsPacket(ABC): + """Abstract definition of UDS Packet (Network Protocol Data Unit - N_PDU ).""" def __init__(self, raw_data: RawBytes, addressing: AddressingMemberTyping) -> None: """ - Create a storage for a single UDS N_PDU. + Create a storage for a single UDS packet. - :param raw_data: Raw bytes of N_PDU data. - :param addressing: Addressing type for which this N_PDU is relevant. + :param raw_data: Raw bytes of UDS packet data. + :param addressing: Addressing type for which this packet is relevant. """ self.raw_data = raw_data # type: ignore self.addressing = addressing # type: ignore @property def raw_data(self) -> RawBytesTuple: - """Raw bytes of data that this N_PDU carries.""" + """Raw bytes of data that this packet carries.""" return self.__raw_data @raw_data.setter @@ -44,14 +46,14 @@ def raw_data(self, value: RawBytes): """ Set value of raw bytes of data. - :param value: Raw bytes of data to be carried by this N_PDU. + :param value: Raw bytes of data to be carried by this packet. """ validate_raw_bytes(value) self.__raw_data = tuple(value) @property def addressing(self) -> AddressingType: - """Addressing type for which this N_PDU is relevant.""" + """Addressing type for which this packet is relevant.""" return self.__addressing @addressing.setter @@ -66,20 +68,20 @@ def addressing(self, value: AddressingMemberTyping): @property # noqa: F841 @abstractmethod - def npci(self) -> AbstractNPCI: - """N_PCI (type of UDS N_PDU) value of this N_PDU.""" + def packet_type(self) -> AbstractPacketType: + """Type of UDS packet - N_PCI value of this N_PDU.""" -class AbstractNPDURecord(ABC): - """Abstract definition of a record that stores historic information about transmitted or received N_PDU.""" +class AbstractUdsPacketRecord(ABC): + """Abstract definition of a record that stores historic information about transmitted or received UDS packet.""" @abstractmethod def __init__(self, frame: object, direction: DirectionMemberTyping) -> None: """ - Create historic record of a N_PDU that was either received of transmitted to a bus. + Create historic record of a packet that was either received of transmitted to a bus. - :param frame: Frame that carried this N_PDU. - :param direction: Information whether this N_PDU was transmitted or received. + :param frame: Frame that carried this UDS packet. + :param direction: Information whether this packet was transmitted or received. """ self.frame = frame self.direction = direction # type: ignore @@ -95,9 +97,9 @@ def __validate_frame(self, value: Any) -> None: :raise ValueError: Some values of a frame are not """ - def __get_raw_pci(self) -> RawByte: + def __get_raw_packet_type(self) -> RawByte: """ - Get N_PCI (value that describes N_PDU type) of this N_PDU. + Get raw value of packet type (N_PCI). :return: Integer value of N_PCI. """ @@ -105,7 +107,7 @@ def __get_raw_pci(self) -> RawByte: @property def frame(self) -> object: - """Frame that carried this N_PDU.""" + """Frame that carried this packet.""" return self.__frame @frame.setter @@ -118,7 +120,7 @@ def frame(self, value: DirectionMemberTyping): :raise ReassignmentError: There is a call to change the value after the initial assignment (in __init__). """ try: - self.__getattribute__("_AbstractNPDURecord__frame") + self.__getattribute__("_AbstractUdsPacketRecord__frame") except AttributeError: self.__validate_frame(value) self.__frame = value @@ -127,7 +129,7 @@ def frame(self, value: DirectionMemberTyping): @property def direction(self) -> TransmissionDirection: - """Information whether this N_PDU was transmitted or received.""" + """Information whether this packet was transmitted or received.""" return self.__direction @direction.setter @@ -140,7 +142,7 @@ def direction(self, value: DirectionMemberTyping): :raise ReassignmentError: There is a call to change the value after the initial assignment (in __init__). """ try: - self.__getattribute__("_AbstractNPDURecord__direction") + self.__getattribute__("_AbstractUdsPacketRecord__direction") except AttributeError: TransmissionDirection.validate_member(value) self.__direction = TransmissionDirection(value) @@ -154,15 +156,15 @@ def raw_data(self) -> RawBytesTuple: @property # noqa: F841 @abstractmethod - def npci(self) -> AbstractNPCI: - """N_PCI (type of N_PDU) value carried by this N_PDU.""" + def packet_type(self) -> AbstractPacketType: + """Type of UDS packet - N_PCI value carried by this N_PDU.""" @property @abstractmethod def addressing(self) -> AddressingType: - """Addressing type over which this N_PDU was transmitted.""" + """Addressing type over which this packet was transmitted.""" @property # noqa: F841 @abstractmethod def transmission_time(self) -> TimeStamp: - """Time stamp when this N_PDU was fully transmitted on a bus.""" + """Time stamp when this packet was fully transmitted on a bus."""