Skip to content

Commit

Permalink
split find command into 'find' and 'decode' and restore service name …
Browse files Browse the repository at this point in the history
…search functionality without data for find
  • Loading branch information
floroks committed Oct 22, 2023
1 parent e453456 commit 8f70b3f
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 124 deletions.
104 changes: 66 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ send to/received from ECUs in an pythonic manner.
- [The `browse` subcommand](#the-browse-subcommand)
- [The `snoop` subcommand](#the-snoop-subcommand)
- [The `find` subcommand](#the-find-subcommand)
- [The `decode` subcommand](#the-decode-subcommand)
- [Testing](#testing)
- [Contributing](#contributing)
- [Code of Conduct](#code-of-conduct)
Expand Down Expand Up @@ -292,7 +293,8 @@ positional arguments:
list Print a summary of automotive diagnostic files.
browse Interactively browse the content of automotive diagnostic files.
snoop Live decoding of a diagnostic session.
find Find & display services by hex-data, or name, can also decodes requests.
find Find & display services by their name
decode Decode hex-data to service-name & optionally its parameters

optional arguments:
-h, --help show this help message and exit
Expand Down Expand Up @@ -495,67 +497,54 @@ Tester: do_forward_flips(forward_soberness_check=18, num_flips=50)
### The `find` subcommand
The `find` subcommand can be used to find a service and its associated
information by either a hex request, or partial name via cli.
In addition, it can also decode a hex request and display its parameters
mapped to a service.
information by a partial name via cli.
```bash
$ odxtools find -h
usage: odxtools find [-h] [-v VARIANT [VARIANT ...]] [-d [DATA ...]] [-D [DECODE ...]] [-s [SERVICES ...]] [-nd]
[-ro]
PDX_FILE
usage: odxtools find [-h] [-v VARIANT] -s [SERVICES ...] [-nd] [-ro] PDX_FILE
Find & print services by hex-data, or name, can also decodes requests
Find & print services by name
Examples:
For displaying the service associated with the request 10 01:
odxtools find ./path/to/database.pdx -d 10 01
For displaying the service associated with the request 10 01, and decoding it:
odxtools find ./path/to/database.pdx -D 10 01
For displaying the services associated with the partial name 'Reset' without details:
odxtools find ./path/to/database.pdx -s "Reset" --no-details
For more information use:
odxtools find -h
positional arguments:
PDX_FILE path to the .pdx file
PDX_FILE Location of the .pdx file
options:
-h, --help show this help message and exit
-v VARIANT [VARIANT ...], --variants VARIANT [VARIANT ...]
-v VARIANT, --variants VARIANT
Specifies which ecu variants should be included.
-d [DATA ...], --data [DATA ...]
Print a list of diagnostic services associated with the hex request.
-D [DECODE ...], --decode [DECODE ...]
Print a list of diagnostic services associated with the hex request and decode the request.
-s [SERVICES ...], --service-names [SERVICES ...]
Print a list of diagnostic services partially matching given service names
-nd, --no-details Don't show all service details
-ro, --relaxed-output
Relax output formatting rules (allow unknown bitlengths for ascii representation)
```
Example: Find diagnostic services associated with the hex request `10 00`
```bash
$ odxtools find $BASE_DIR/odxtools/examples/somersault.pdx -D 10 00
Example: Find diagnostic services with the name `session_start`
```bash
$ odxtools find examples/somersault.pdx -s session_start
=====================================
somersault_lazy, somersault_assiduous
=====================================
session_start <ID: somersault.service.session_start>
session_start <ID: OdxLinkId('somersault.service.session_start')>
Message format of a request:
7 6 5 4 3 2 1 0
+-----+-----+-----+-----+-----+-----+-----+-----+
0 | sid (8 bits) |
+-----+-----+-----+-----+-----+-----+-----+-----+
1 | id (8 bits) |
+-----+-----+-----+-----+-----+-----+-----+-----+
Parameter(short_name='sid', type='CODED-CONST', semantic=None, byte_position=0, bit_length=8, coded_value='0x10')
Parameter(short_name='id', type='CODED-CONST', semantic=None, byte_position=1, bit_length=8, coded_value='0x0')
CodedConstParameter(short_name='sid', long_name=None, description=None, byte_position=0, bit_position=None, semantic=None, sdgs=[], diag_coded_type=StandardLengthType(base_data_type=<DataType.A_UINT32: 'A_UINT32'>, base_type_encoding=None, is_highlow_byte_order_raw=None, bit_length=8, bit_mask=None, is_condensed_raw=None), coded_value=16)
CodedConstParameter(short_name='id', long_name=None, description=None, byte_position=1, bit_position=None, semantic=None, sdgs=[], diag_coded_type=StandardLengthType(base_data_type=<DataType.A_UINT32: 'A_UINT32'>, base_type_encoding=None, is_highlow_byte_order_raw=None, bit_length=8, bit_mask=None, is_condensed_raw=None), coded_value=0)
Number of positive responses: 1
Message format of a positive response:
7 6 5 4 3 2 1 0
Expand All @@ -564,9 +553,8 @@ somersault_lazy, somersault_assiduous
+-----+-----+-----+-----+-----+-----+-----+-----+
1 | can_do_backward_flips (8 bits) |
+-----+-----+-----+-----+-----+-----+-----+-----+
Parameter(short_name='sid', type='CODED-CONST', semantic=None, byte_position=0, bit_length=8, coded_value='0x50')
Parameter(short_name='can_do_backward_flips', type='VALUE', semantic=None, byte_position=1, bit_length=8, dop_ref='somersault.DOP.boolean')
DataObjectProperty('boolean', category='TEXTTABLE', internal_type='A_UINT32', physical_type='A_UNICODE2STRING')
CodedConstParameter(short_name='sid', long_name=None, description=None, byte_position=0, bit_position=None, semantic=None, sdgs=[], diag_coded_type=StandardLengthType(base_data_type=<DataType.A_UINT32: 'A_UINT32'>, base_type_encoding=None, is_highlow_byte_order_raw=None, bit_length=8, bit_mask=None, is_condensed_raw=None), coded_value=80)
ValueParameter(short_name='can_do_backward_flips', long_name=None, description=None, byte_position=1, bit_position=None, semantic=None, sdgs=[], dop_ref=OdxLinkRef(ref_id='somersault.DOP.boolean', ref_docs=[OdxDocFragment(doc_name='somersault', doc_type='CONTAINER'), OdxDocFragment(doc_name='somersault', doc_type='LAYER')]), dop_snref=None, physical_default_value_raw=None)
Number of negative responses: 1
Message format of a negative response:
7 6 5 4 3 2 1 0
Expand All @@ -577,19 +565,59 @@ somersault_lazy, somersault_assiduous
+-----+-----+-----+-----+-----+-----+-----+-----+
2 | response_code (8 bits) |
+-----+-----+-----+-----+-----+-----+-----+-----+
Parameter(short_name='sid', type='CODED-CONST', semantic=None, byte_position=0, bit_length=8, coded_value='0x7f')
Parameter(short_name='rq_sid', type='MATCHING-REQUEST-PARAM', semantic=None, byte_position=1)
Request byte position = 0, byte length = 1
Parameter(short_name='response_code', type='VALUE', semantic=None, byte_position=2, bit_length=8, dop_ref='somersault.DOP.error_code')
DataObjectProperty('error_code', category='IDENTICAL', internal_type='A_UINT32', physical_type='A_UINT32')
CodedConstParameter(short_name='sid', long_name=None, description=None, byte_position=0, bit_position=None, semantic=None, sdgs=[], diag_coded_type=StandardLengthType(base_data_type=<DataType.A_UINT32: 'A_UINT32'>, base_type_encoding=None, is_highlow_byte_order_raw=None, bit_length=8, bit_mask=None, is_condensed_raw=None), coded_value=127)
MatchingRequestParameter(short_name='rq_sid', long_name=None, description=None, byte_position=1, bit_position=None, semantic=None, sdgs=[], request_byte_position=0, byte_length=1)
ValueParameter(short_name='response_code', long_name=None, description=None, byte_position=2, bit_position=None, semantic=None, sdgs=[], dop_ref=OdxLinkRef(ref_id='somersault.DOP.error_code', ref_docs=[OdxDocFragment(doc_name='somersault', doc_type='CONTAINER'), OdxDocFragment(doc_name='somersault', doc_type='LAYER')]), dop_snref=None, physical_default_value_raw=None)
```
### The `decode` subcommand
Decoded Request('start_session'):
sid: 16
id: 0
The `decode` subcommand can be used to decode hex-data a service and its associated
parameters.
```bash
$ odxtools decode -h
usage: odxtools decode [-h] [-v VARIANT] -d DATA [-D] PDX_FILE
Decode request by hex-data
Examples:
For displaying the service associated with the request 10 01 & decoding it:
odxtools decode ./path/to/database.pdx -D -d '10 01'
For displaying the service associated with the request 10 01, without decoding it:
odxtools decode ./path/to/database.pdx -d '10 01'
For more information use:
odxtools decode -h
positional arguments:
PDX_FILE Location of the .pdx file
options:
-h, --help show this help message and exit
-v VARIANT, --variants VARIANT
Specifies which ecu variants should be included.
-d DATA, --data DATA Specify data of hex request
-D, --decode Decode the given hex data
```
`odxtools find $BASE_DIR/odxtools/examples/somersault.pdx -d 10 00` would display the same information,
without the decoded request, and `-s <name>` can be used to find a service by partial name.
Example: Decode diagnostic services with the request `10 00`
```bash
$ odxtools decode examples/somersault.pdx -d '10 00'
Binary data: 10 00
Decoded by service 'session_start' (decoding ECUs: somersault_lazy, somersault_assiduous)
```
Example: Decode diagnostic services with the request `10 00` and parameters
```bash
$ odxtools decode examples/somersault.pdx -d '10 00' -D
Binary data: 10 00
Decoded by service 'session_start' (decoding ECUs: somersault_lazy, somersault_assiduous)
Decoded data:
sid=16 (0x10)
id=0 (0x0)
```
## Testing
Expand Down
128 changes: 128 additions & 0 deletions odxtools/cli/decode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# SPDX-License-Identifier: MIT
import argparse
from typing import Dict, List, Optional

from ..database import Database
from ..diagservice import DiagService
from ..exceptions import odxraise
from ..odxtypes import ParameterValue
from ..singleecujob import SingleEcuJob
from . import _parser_utils

# name of the tool
_odxtools_tool_name_ = "decode"


def get_display_value(v: ParameterValue) -> str:
if isinstance(v, bytes):
return v.hex(" ")
elif isinstance(v, int):
return f"{v} (0x{v:x})"
else:
return str(v)


def print_summary(
odxdb: Database,
ecu_variants: Optional[List[str]] = None,
data: bytes = b'',
decode: bool = False,
) -> None:
ecu_names = ecu_variants if ecu_variants else [ecu.short_name for ecu in odxdb.ecus]
services: Dict[DiagService, List[str]] = {}
for ecu_name in ecu_names:
ecu = odxdb.ecus[ecu_name]
if not ecu:
print(f"The ecu variant '{ecu_name}' could not be found!")
continue
if data:
found_services = ecu._find_services_for_uds(data)
for found_service in found_services:
ecu_names = services.get(found_service, [])
ecu_names.append(ecu_name)
services[found_service] = ecu_names

print(f"Binary data: {data.hex(' ')}")
for service, ecu_names in services.items():
if isinstance(service, DiagService):
print(
f"Decoded by service '{service.short_name}' (decoding ECUs: {', '.join(ecu_names)})"
)
elif isinstance(service, SingleEcuJob):
print(
f"Decoded by single ecu job '{service.short_name}' (decoding ECUs: {', '.join(ecu_names)})"
)
else:
print(f"Decoded by unknown diagnostic communication: '{service.short_name}' "
f"(decoding ECUs: {', '.join(ecu_names)})")

if decode:
if data is None:
odxraise("Data is required for decoding")

decoded = service.decode_message(data)
print(f"Decoded data:")
for param_name, param_value in decoded.param_dict.items():
print(f" {param_name}={get_display_value(param_value)}")


def add_subparser(subparsers: "argparse._SubParsersAction") -> None:
parser = subparsers.add_parser(
"decode",
description="\n".join([
"Decode request by hex-data",
"",
"Examples:",
" For displaying the service associated with the request 10 01 & decoding it:",
" odxtools decode ./path/to/database.pdx -D -d '10 01'",
" For displaying the service associated with the request 10 01, without decoding it:",
" odxtools decode ./path/to/database.pdx -d '10 01'",
" For more information use:",
" odxtools decode -h",
]),
help="Find & print service by hex-data. Can also decode the hex-data to into their named parameters.",
formatter_class=argparse.RawTextHelpFormatter,
)
_parser_utils.add_pdx_argument(parser)

parser.add_argument(
"-v",
"--variants",
nargs=1,
metavar="VARIANT",
required=False,
help="Specifies which ecu variants should be included.",
default="all",
)

parser.add_argument(
"-d",
"--data",
metavar="DATA",
required=True,
help="Specify data of hex request",
)

parser.add_argument(
"-D",
"--decode",
action="store_true",
required=False,
help="Decode the given hex data",
)


def hex_to_binary(data_str: str) -> bytes:
return bytes.fromhex(data_str)


def run(args: argparse.Namespace) -> None:
odxdb = _parser_utils.load_file(args)
variants = args.variants

print_summary(
odxdb,
ecu_variants=None if variants == "all" else variants,
data=bytes.fromhex(args.data),
decode=args.decode,
)
Loading

0 comments on commit 8f70b3f

Please sign in to comment.