Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
rumpelsepp committed Jun 15, 2022
1 parent 9d5c6c2 commit 7c2e19a
Show file tree
Hide file tree
Showing 35 changed files with 307 additions and 192 deletions.
42 changes: 21 additions & 21 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,47 +64,47 @@ jobs:
- name: Spawn vECU
run: |
poetry run gallia vecu "tcp-lines://127.0.0.1:20162" rng --seed 3 --mandatory_sessions "[1, 2, 3]" --mandatory_services "[DiagnosticSessionControl, EcuReset, ReadDataByIdentifier, WriteDataByIdentifier, RoutineControl, SecurityAccess, ReadMemoryByAddress, WriteMemoryByAddress, RequestDownload, RequestUpload, TesterPresent, ReadDTCInformation, ClearDiagnosticInformation, InputOutputControlByIdentifier]" &
poetry run gallia serve vecu "tcp-lines://127.0.0.1:20162" rng --seed 3 --mandatory_sessions "[1, 2, 3]" --mandatory_services "[DiagnosticSessionControl, EcuReset, ReadDataByIdentifier, WriteDataByIdentifier, RoutineControl, SecurityAccess, ReadMemoryByAddress, WriteMemoryByAddress, RequestDownload, RequestUpload, TesterPresent, ReadDTCInformation, ClearDiagnosticInformation, InputOutputControlByIdentifier]" &
- name: Test scan-services
run: |
poetry run gallia scan-services --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --sessions 1 2 --check-session
poetry run gallia scan uds services --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --sessions 1 2 --check-session
- name: Test scan-sessions
run: |
poetry run gallia scan-sessions --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --depth 2
poetry run gallia scan uds sessions --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --depth 2
- name: Test scan-identifiers
run: |
poetry run gallia scan-identifiers --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --start 0 --end 100 --sid 0x22
poetry run gallia scan-identifiers --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --start 0 --end 100 --sid 0x2e
poetry run gallia scan-identifiers --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --start 0 --end 100 --sid 0x31
poetry run gallia scan uds identifiers --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --start 0 --end 100 --sid 0x22
poetry run gallia scan uds identifiers --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --start 0 --end 100 --sid 0x2e
poetry run gallia scan uds identifiers --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --start 0 --end 100 --sid 0x31
- name: Test scan-reset
run: |
poetry run gallia scan-reset --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia scan uds reset --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
- name: Test scan-dump-seeds
run: |
poetry run gallia scan-dump-seeds --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --duration 0.01 --level 0x2f
poetry run gallia scan uds dump-seeds --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --duration 0.01 --level 0x2f
- name: Test scan-memory-functions
run: |
for sid in 0x23 0x34 0x35 0x3d; do
poetry run gallia scan-memory-functions --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --sid "$sid"
poetry run gallia scan uds memory --target "tcp-lines://127.0.0.1:20162" --no-dumpcap --sid "$sid"
done
- name: Test UDS primitives
run: |
poetry run gallia simple-ecu-reset --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia simple-read-error-log --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia simple-get-vin --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia simple-ping --count 2 --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia simple-read-by-identifier --data-id 0x108d --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia simple-send-pdu 1001 --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia simple-write-by-identifier --data-id 0x2266 --data 00 --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia simple-dtc --target "tcp-lines://127.0.0.1:20162" --no-dumpcap read
poetry run gallia simple-dtc --target "tcp-lines://127.0.0.1:20162" --no-dumpcap clear
poetry run gallia simple-dtc --target "tcp-lines://127.0.0.1:20162" --no-dumpcap control --stop
poetry run gallia simple-dtc --target "tcp-lines://127.0.0.1:20162" --no-dumpcap control --resume
poetry run gallia simple-iocbi --target "tcp-lines://127.0.0.1:20162" --no-dumpcap 0x1000 reset-to-default
poetry run gallia prims uds ecu-reset --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia prims uds error-log --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia prims uds vin --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia prims uds ping --count 2 --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia prims uds rdbid --data-id 0x108d --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia prims uds send-pdu 1001 --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia prims uds rdbid --data-id 0x2266 --data 00 --target "tcp-lines://127.0.0.1:20162" --no-dumpcap
poetry run gallia prims uds dtc --target "tcp-lines://127.0.0.1:20162" --no-dumpcap read
poetry run gallia prims uds dtc --target "tcp-lines://127.0.0.1:20162" --no-dumpcap clear
poetry run gallia prims uds dtc --target "tcp-lines://127.0.0.1:20162" --no-dumpcap control --stop
poetry run gallia prims uds dtc --target "tcp-lines://127.0.0.1:20162" --no-dumpcap control --resume
poetry run gallia prims uds IOCBI --target "tcp-lines://127.0.0.1:20162" --no-dumpcap 0x1000 reset-to-default
185 changes: 115 additions & 70 deletions src/gallia/cli.py
Original file line number Diff line number Diff line change
@@ -1,49 +1,44 @@
# type: ignore

import argparse
import os
import sys
from argparse import ArgumentDefaultsHelpFormatter
from importlib.metadata import entry_points
from typing import Any

import argcomplete

from gallia.udscan.scanner.find_can_ids import FindCanIDsScanner
from gallia.udscan.scanner.find_endpoints import FindEndpoints
from gallia.udscan.scanner.find_iso_tp_addr import FindISOTPAddr
from gallia.udscan.scanner.scan_identifiers import ScanIdentifiers
from gallia.udscan.scanner.scan_memory_functions import ScanMemoryFunctions
from gallia.udscan.scanner.scan_reset import ScanReset
from gallia.udscan.scanner.scan_sa_dump_seeds import SaDumpSeeds
from gallia.udscan.scanner.scan_services import ScanServices
from gallia.udscan.scanner.scan_sessions import ScanSessions
from gallia.udscan.scanner.simple_dtc import SimpleDTC
from gallia.udscan.scanner.simple_ecu_reset import SimpleECUReset
from gallia.udscan.scanner.simple_get_vin import SimpleGetVin
from gallia.udscan.scanner.simple_iocbi import SimpleIOCBI
from gallia.udscan.scanner.simple_ping import SimplePing
from gallia.udscan.scanner.simple_read_by_identifier import ReadByIdentifier
from gallia.udscan.scanner.simple_read_error_log import SimpleReadErrorLog
from gallia.udscan.scanner.simple_rmba import SimpleRMBA
from gallia.udscan.scanner.simple_rtcl import SimpleRTCL
from gallia.udscan.scanner.simple_send_pdu import SimpleSendPDU
from gallia.udscan.scanner.simple_test_xcp import SimpleTestXCP
from gallia.udscan.scanner.simple_wmba import SimpleWMBA
from gallia.udscan.scanner.simple_write_by_identifier import WriteByIdentifier
from gallia.utils import camel_to_dash

# TODO: Rename classes: SimpleFoo…
# TODO: Create groups: simple, scanner, discover
# TODO: Entry points
registry = [
from gallia.command import GalliaBase
from gallia.commands.discover.uds.find_can_ids import FindCanIDsScanner
from gallia.commands.prims.uds.simple_dtc import SimpleDTC
from gallia.commands.prims.uds.simple_ecu_reset import SimpleECUReset
from gallia.commands.prims.uds.simple_get_vin import SimpleGetVin
from gallia.commands.prims.uds.simple_iocbi import SimpleIOCBI
from gallia.commands.prims.uds.simple_ping import SimplePing
from gallia.commands.prims.uds.simple_read_by_identifier import ReadByIdentifier
from gallia.commands.prims.uds.simple_read_error_log import SimpleReadErrorLog
from gallia.commands.prims.uds.simple_rmba import SimpleRMBA
from gallia.commands.prims.uds.simple_rtcl import SimpleRTCL
from gallia.commands.prims.uds.simple_send_pdu import SimpleSendPDU
from gallia.commands.prims.uds.simple_wmba import SimpleWMBA
from gallia.commands.prims.uds.simple_write_by_identifier import WriteByIdentifier
from gallia.commands.scan.uds.scan_identifiers import ScanIdentifiers
from gallia.commands.scan.uds.scan_memory_functions import MemoryFunctionsScanner
from gallia.commands.scan.uds.scan_reset import ResetScanner
from gallia.commands.scan.uds.scan_sa_dump_seeds import SaDumpSeeds
from gallia.commands.scan.uds.scan_services import ServicesScanner
from gallia.commands.scan.uds.scan_sessions import ScanSessions
from gallia.commands.serve.virtual_ecu import VirtualECU

# from gallia.commands.prims.uds.simple_test_xcp import SimpleTestXCP

registry: list[type[GalliaBase]] = [
FindCanIDsScanner,
FindEndpoints,
FindISOTPAddr,
ReadByIdentifier,
SaDumpSeeds,
ScanIdentifiers,
ScanMemoryFunctions,
ScanReset,
ScanServices,
MemoryFunctionsScanner,
ResetScanner,
ServicesScanner,
ScanSessions,
SimpleDTC,
SimpleECUReset,
Expand All @@ -54,59 +49,109 @@
SimpleRTCL,
SimpleReadErrorLog,
SimpleSendPDU,
SimpleTestXCP,
# SimpleTestXCP,
SimpleWMBA,
WriteByIdentifier,
VirtualECU,
]


class Formatter(ArgumentDefaultsHelpFormatter):
def __init__(self, *args: Any, **kwargs: Any) -> None:
if (w := os.getenv("GALLIA_HELP_WIDTH")) is not None:
kwargs["width"] = int(w)
super().__init__(*args, **kwargs)


def get_id(cls: type) -> str:
return cls.ID if hasattr(cls, "ID") else camel_to_dash(cls.__name__) # type: ignore


def get_short_help(cls: type) -> str:
return cls.SHORT_HELP if hasattr(cls, "SHORT_HELP") else cls.__doc__ # type: ignore


def get_help(cls: type) -> str:
return cls.HELP if hasattr(cls, "HELP") else get_short_help(cls) # type: ignore


def load_plugins() -> None:
global registry

eps = entry_points()
if "gallia_commands" in eps:
for entry in eps["gallia_commands"]:
registry.append(entry.load())


parser_structure = {
"discover": {
"help": "find hosts and endpoints",
"subcategories": {
"uds": {
"help": "Universal Diagnostic Services",
},
"xcp": {
"help": "Universal Measurement and Calibration Protocol",
},
},
},
"prims": {
"help": "various primitives for network protocols",
"subcategories": {
"uds": {
"help": "Universal Diagnostic Services",
},
},
},
"scan": {
"help": "scan parameters of various network protocols",
"subcategories": {
"uds": {
"help": "Universal Diagnostic Services",
},
},
},
"serve": {
"help": "utilities to spawn services",
},
}


def build_parsers() -> dict:
parser = argparse.ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
subparsers = parser.add_subparsers(metavar="COMMAND")
parsers = {"parser": parser, "subparsers": subparsers}

for category in parser_structure: # pylint: disable=consider-using-dict-items
p = subparsers.add_parser(category, help=parser_structure[category]["help"])
sp = p.add_subparsers(metavar="COMMAND")
parsers[category] = {"parser": p, "subparsers": sp}

if "subcategories" not in parser_structure[category]:
continue

for subcategory in parser_structure[category]["subcategories"].keys():
pp = sp.add_parser(
subcategory,
help=parser_structure[category]["subcategories"][subcategory]["help"],
)
spp = pp.add_subparsers(metavar="COMMAND")
parsers[category][subcategory] = {"parser": pp, "subparsers": spp}

return parsers


def main() -> None:
load_plugins()

parser = argparse.ArgumentParser(formatter_class=Formatter)
subparsers = parser.add_subparsers(metavar="SCANNER")

for cls in sorted(registry, key=lambda x: get_id(x)):
subparser = subparsers.add_parser(
get_id(cls),
description=get_help(cls),
help=get_short_help(cls),
parsers = build_parsers()

for cls in registry:
if cls.CATEGORY is not None:
if cls.SUBCATEGORY is not None:
cat_subparsers = parsers[cls.CATEGORY][cls.SUBCATEGORY]["subparsers"]
else:
cat_subparsers = parsers[cls.CATEGORY]["subparsers"]
else:
cat_subparsers = parsers["subparsers"]

subparser = cat_subparsers.add_parser(
cls.COMMAND,
description=cls.__doc__,
help=cls.SHORT_HELP,
)
scanner = cls(subparser) # type: ignore
scanner = cls(subparser)
subparser.set_defaults(func=scanner.run)

parser = parsers["parser"]
argcomplete.autocomplete(parser)
args = parser.parse_args()
if not hasattr(args, "func"):
parser.print_help()
parser.exit()

sys.exit(args.func())
if len(sys.argv) >= 2 and (cat := sys.argv[1]) in parser_structure:
if len(sys.argv) >= 3 and (subcat := sys.argv[2]) in parser_structure[cat]:
parsers[cat][subcat]["parser"].print_usage()
else:
parsers[cat]["parser"].print_usage()
parser.exit(1)

sys.exit(args.func(args))
Loading

0 comments on commit 7c2e19a

Please sign in to comment.