#!/usr/bin/env bash set -u if [ "$#" -ne 1 ]; then printf "Uso: %s \n" "$0" >&2 exit 2 fi INPUT_PATH="$1" if [ -d "$INPUT_PATH" ]; then RUN_DIR="$(cd "$INPUT_PATH" >/dev/null 2>&1 && pwd)" RUN_LOG="$RUN_DIR/run.log" elif [ -f "$INPUT_PATH" ]; then RUN_LOG="$(cd "$(dirname "$INPUT_PATH")" >/dev/null 2>&1 && pwd)/$(basename "$INPUT_PATH")" RUN_DIR="$(dirname "$RUN_LOG")" else printf "[NON DIMOSTRATO] Percorso di validazione non trovato: %s\n" "$INPUT_PATH" >&2 exit 21 fi RUN_CONFIG="$RUN_DIR/configuration.marte" OUTPUT_FILE="$RUN_DIR/s02_output.bin" RUNNER_SUMMARY="$RUN_DIR/runner_summary.txt" for required_file in "$RUN_LOG" "$RUN_CONFIG" "$OUTPUT_FILE"; do if [ ! -f "$required_file" ]; then printf "[NON DIMOSTRATO] File richiesto assente: %s\n" "$required_file" >&2 exit 21 fi done count_lines() { pattern="$1" file="$2" grep -Ec "$pattern" "$file" 2>/dev/null || true } START_LINES="$(count_lines '^\[Information - RealTimeLoader\.cpp:[0-9]+\]: Started application in state State1[[:space:]]*$' "$RUN_LOG")" APPLICATION_START_LINES="$(count_lines '^\[Information - MARTeApp\.cpp:[0-9]+\]: Application starting[[:space:]]*$' "$RUN_LOG")" FILE_OPEN_LINES="$(count_lines '^\[Information - FileWriter\.cpp:[0-9]+\]: Going to open file with name ' "$RUN_LOG")" SIGINT_LINES="$(count_lines '^\[Information - Bootstrap\.cpp:[0-9]+\]: Application recieved SIGINT\.[[:space:]]*$' "$RUN_LOG")" STOP_OK_LINES="$(count_lines '^\[Information - Bootstrap\.cpp:[0-9]+\]: Application successfully stopped\.[[:space:]]*$' "$RUN_LOG")" TERMINATED_LINES="$(count_lines '^\[NoError - MARTeApp\.cpp:[0-9]+\]: Application terminated[[:space:]]*$' "$RUN_LOG")" STARTUP_ERROR_LINES="$(count_lines 'Failed dlopen|Failed CreateByName|Failed to Initialise object|Failed to initialise the ObjectRegistryDatabase|Could not Initialise the loader' "$RUN_LOG")" FATAL_ERROR_LINES="$(count_lines '^\[FatalError ' "$RUN_LOG")" OS_ERROR_LINES="$(count_lines '^\[OSError ' "$RUN_LOG")" ERROR_LINES="$(count_lines '^\[Error ' "$RUN_LOG")" INITIALISATION_ERROR_LINES="$(count_lines '^\[InitialisationEr ' "$RUN_LOG")" NO_ERROR_LINES="$(count_lines '^\[NoError ' "$RUN_LOG")" WARNING_LINES="$(count_lines '^\[Warning ' "$RUN_LOG")" PRIORITY_CLIP_LINES="$(count_lines '^\[Warning - Threads\.cpp:[0-9]+\]: Requested a thread priority that is higher than ' "$RUN_LOG")" PRIORITY_FAIL_LINES="$(count_lines '^\[Warning - Threads\.cpp:[0-9]+\]: Failed to change the thread priority' "$RUN_LOG")" UNCLASSIFIED_WARNING_LINES=$((WARNING_LINES - PRIORITY_CLIP_LINES - PRIORITY_FAIL_LINES)) if [ "$UNCLASSIFIED_WARNING_LINES" -lt 0 ]; then UNCLASSIFIED_WARNING_LINES=0 fi DOUBLE_STOP_LINES="$(count_lines '^\[FatalError - RealTimeApplication\.cpp:[0-9]+\]: Could not stop the RealTimeApplication\. Was it ever started\?[[:space:]]*$' "$RUN_LOG")" ASYNC_EVENTSEM_CLOSE_LINES="$(count_lines '^\[FatalError - MemoryMapAsyncOutputBroker\.cpp:[0-9]+\]: Could not Close the EventSem\.[[:space:]]*$' "$RUN_LOG")" PTHREAD_MUTEX_DESTROY_LINES="$(count_lines '^\[OSError - EventSem\.cpp:[0-9]+\]: Error: pthread_mutex_destroy\(\)[[:space:]]*$' "$RUN_LOG")" UNCLASSIFIED_FATAL_LINES=$((FATAL_ERROR_LINES - DOUBLE_STOP_LINES - ASYNC_EVENTSEM_CLOSE_LINES)) UNCLASSIFIED_OS_ERROR_LINES=$((OS_ERROR_LINES - PTHREAD_MUTEX_DESTROY_LINES)) if [ "$UNCLASSIFIED_FATAL_LINES" -lt 0 ]; then UNCLASSIFIED_FATAL_LINES=0 fi if [ "$UNCLASSIFIED_OS_ERROR_LINES" -lt 0 ]; then UNCLASSIFIED_OS_ERROR_LINES=0 fi PLACEHOLDER_COUNT="$(grep -o '__MARTE_RUN_DIR__' "$RUN_CONFIG" 2>/dev/null | wc -l)" NAMESPACED_CLASS_COUNT="$(count_lines '^[[:space:]]*Class = FileDataSource::FileWriter[[:space:]]*$' "$RUN_CONFIG")" PLAIN_CLASS_COUNT="$(count_lines '^[[:space:]]*Class = FileWriter[[:space:]]*$' "$RUN_CONFIG")" EXPECTED_FILENAME="$RUN_DIR/s02_output.bin" FILENAME_MATCH_LINES="$( python3 - "$RUN_CONFIG" "$EXPECTED_FILENAME" <<'PYCONFIG' import sys from pathlib import Path config_path = Path(sys.argv[1]) expected = f'Filename = "{sys.argv[2]}"' count = sum( 1 for line in config_path.read_text(encoding="utf-8").splitlines() if line.strip() == expected ) print(count) PYCONFIG )" MARTE_EXIT_CODE="NOT_AVAILABLE" TEE_EXIT_CODE="NOT_AVAILABLE" if [ -f "$RUNNER_SUMMARY" ]; then value="$(sed -n 's/^Exit code MARTe:[[:space:]]*//p' "$RUNNER_SUMMARY" | tail -n 1)" if [ -n "$value" ]; then MARTE_EXIT_CODE="$value" fi value="$(sed -n 's/^Exit code tee:[[:space:]]*//p' "$RUNNER_SUMMARY" | tail -n 1)" if [ -n "$value" ]; then TEE_EXIT_CODE="$value" fi fi case "$MARTE_EXIT_CODE" in 124) MARTE_EXIT_CLASS="TIMEOUT_EXIT_124" ;; 137) MARTE_EXIT_CLASS="EXIT_137_SIGKILL" ;; 0) MARTE_EXIT_CLASS="EXIT_0" ;; NOT_AVAILABLE) MARTE_EXIT_CLASS="NOT_AVAILABLE" ;; *) MARTE_EXIT_CLASS="OTHER_EXIT_CODE" ;; esac CONFIG_REPORT="$(mktemp "${TMPDIR:-/tmp}/s02_validator_config_XXXXXX.log")" BINARY_REPORT="$(mktemp "${TMPDIR:-/tmp}/s02_validator_binary_XXXXXX.log")" trap 'rm -f -- "$CONFIG_REPORT" "$BINARY_REPORT"' EXIT python3 - "$RUN_CONFIG" >"$CONFIG_REPORT" 2>&1 <<'PYCONFIGOBS' import re import sys from decimal import Decimal, InvalidOperation from pathlib import Path class Node: def __init__(self, name): self.name = name.lstrip("+$") self.properties = {} def sanitise(text): """Remove comments while preserving strings, braces and line boundaries.""" output = [] index = 0 quote = None block_comment = False while index < len(text): char = text[index] next_char = text[index + 1] if index + 1 < len(text) else "" if block_comment: if char == "*" and next_char == "/": block_comment = False output.extend(" ") index += 2 else: output.append("\n" if char == "\n" else " ") index += 1 continue if quote: output.append(char) if char == "\\" and index + 1 < len(text): output.append(text[index + 1]) index += 2 continue if char == quote: quote = None index += 1 continue if char in {'"', "'"}: quote = char output.append(char) index += 1 continue if char == "/" and next_char == "*": block_comment = True output.extend(" ") index += 2 continue if char == "/" and next_char == "/": while index < len(text) and text[index] != "\n": output.append(" ") index += 1 continue if char == "#": while index < len(text) and text[index] != "\n": output.append(" ") index += 1 continue output.append(char) index += 1 return "".join(output) def braces_outside_strings(line): result = [] quote = None index = 0 while index < len(line): char = line[index] if quote: if char == "\\" and index + 1 < len(line): index += 2 continue if char == quote: quote = None elif char in {'"', "'"}: quote = char elif char in "{}": result.append(char) index += 1 return result text = Path(sys.argv[1]).read_text(encoding="utf-8") clean = sanitise(text) nodes = [] stack = [] object_open = re.compile(r"^\s*([+$]?[A-Za-z_][A-Za-z0-9_.:-]*)\s*=\s*\{") assignment = re.compile(r"^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$") for line in clean.splitlines(): match = object_open.match(line) if match: node = Node(match.group(1)) nodes.append(node) stack.append(node) elif stack: match = assignment.match(line) if match and not match.group(2).startswith("{"): stack[-1].properties[match.group(1)] = match.group(2).strip() opens_and_closes = braces_outside_strings(line) opening_already_consumed = bool(match and object_open.match(line)) if opening_already_consumed: removed = False adjusted = [] for brace in opens_and_closes: if brace == "{" and not removed: removed = True continue adjusted.append(brace) opens_and_closes = adjusted for brace in opens_and_closes: if brace == "{": stack.append(Node("")) elif stack: stack.pop() def report_objects(prefix, classes, property_name): matches = [node for node in nodes if node.properties.get("Class") in classes] names = ",".join(node.name for node in matches) or "NOT_AVAILABLE_OBJECT_NOT_FOUND" affinities = [] for node in matches: value = node.properties.get(property_name, "NOT_EXPLICITLY_CONFIGURED") affinities.append(f"{node.name}={value}") affinity = ",".join(affinities) or "NOT_AVAILABLE_OBJECT_NOT_FOUND" print(f"{prefix}_OBJECT_COUNT={len(matches)}") print(f"{prefix}_OBJECT_NAMES={names}") print(f"{prefix}_AFFINITY={affinity}") report_objects("REALTIME_THREAD", {"RealTimeThread"}, "CPUs") report_objects("FILE_WRITER", {"FileDataSource::FileWriter", "FileWriter"}, "CPUMask") report_objects("LINUX_TIMER", {"LinuxTimer"}, "CPUMask") frequency_values = [] for node in nodes: raw = node.properties.get("Frequency") if raw is None: continue raw = raw.strip().strip('"').strip("'") try: value = Decimal(raw) except InvalidOperation: continue if value > 0: frequency_values.append(value) unique_frequencies = sorted(set(frequency_values)) if len(unique_frequencies) == 1: frequency = unique_frequencies[0] period = Decimal(1_000_000) / frequency period_text = str(int(period)) if period == period.to_integral_value() else format(period, ".6f").rstrip("0").rstrip(".") frequency_text = format(frequency, "f").rstrip("0").rstrip(".") if "." in format(frequency, "f") else format(frequency, "f") print(f"DT_NOMINAL_PERIOD_US={period_text}") print(f"DT_NOMINAL_SOURCE=CONFIG_FREQUENCY_{frequency_text}_HZ") elif not unique_frequencies: print("DT_NOMINAL_PERIOD_US=NOT_AVAILABLE") print("DT_NOMINAL_SOURCE=NOT_AVAILABLE_NO_POSITIVE_FREQUENCY") else: print("DT_NOMINAL_PERIOD_US=NOT_AVAILABLE") print("DT_NOMINAL_SOURCE=NOT_AVAILABLE_MULTIPLE_FREQUENCIES") print("CONFIG_OBSERVABILITY_STATUS=PASS") PYCONFIGOBS CONFIG_RC=$? config_value() { key="$1" sed -n "s/^${key}=//p" "$CONFIG_REPORT" | tail -n 1 } CONFIG_OBSERVABILITY_STATUS="$(config_value CONFIG_OBSERVABILITY_STATUS)" REALTIME_THREAD_OBJECT_COUNT="$(config_value REALTIME_THREAD_OBJECT_COUNT)" REALTIME_THREAD_OBJECT_NAMES="$(config_value REALTIME_THREAD_OBJECT_NAMES)" REALTIME_THREAD_AFFINITY="$(config_value REALTIME_THREAD_AFFINITY)" FILE_WRITER_OBJECT_COUNT="$(config_value FILE_WRITER_OBJECT_COUNT)" FILE_WRITER_OBJECT_NAMES="$(config_value FILE_WRITER_OBJECT_NAMES)" FILE_WRITER_AFFINITY="$(config_value FILE_WRITER_AFFINITY)" LINUX_TIMER_OBJECT_COUNT="$(config_value LINUX_TIMER_OBJECT_COUNT)" LINUX_TIMER_OBJECT_NAMES="$(config_value LINUX_TIMER_OBJECT_NAMES)" LINUX_TIMER_AFFINITY="$(config_value LINUX_TIMER_AFFINITY)" DT_NOMINAL_PERIOD_US="$(config_value DT_NOMINAL_PERIOD_US)" DT_NOMINAL_SOURCE="$(config_value DT_NOMINAL_SOURCE)" python3 - "$OUTPUT_FILE" "${DT_NOMINAL_PERIOD_US:-NOT_AVAILABLE}" >"$BINARY_REPORT" 2>&1 <<'PY' from collections import Counter from decimal import Decimal, InvalidOperation import struct import sys from pathlib import Path path = Path(sys.argv[1]) nominal_period_raw = sys.argv[2] data = path.read_bytes() expected_names = [ "Counter", "Time", "State1_Thread1_CycleTime", ] expected_type_hex = "0408" expected_signals = len(expected_names) signal_header_bytes = 2 + 32 + 4 print(f"FILE_SIZE_BYTES={len(data)}") if len(data) < 4: print("BINARY_STATUS=FAIL_HEADER_TOO_SMALL") sys.exit(31) number_of_signals = struct.unpack_from(" len(data): print(f"TRUNCATED_SIGNAL_HEADER_INDEX={index}") print("BINARY_STATUS=FAIL_TRUNCATED_SIGNAL_HEADER") sys.exit(33) type_bytes = data[offset:offset + 2] offset += 2 raw_name = data[offset:offset + 32] offset += 32 number_of_elements = struct.unpack_from(" 0] print(f"COUNTER_FIRST={counters[0]}") print(f"COUNTER_LAST={counters[-1]}") print(f"COUNTER_GAP_COUNT={counter_gap_count}") print(f"TIME_FIRST={times[0]}") print(f"TIME_LAST={times[-1]}") print(f"TIME_DECREASE_COUNT={time_decrease_count}") print(f"NONZERO_CYCLE_TIME_SAMPLES={len(nonzero_cycle_times)}") if nonzero_cycle_times: print(f"CYCLE_TIME_MIN={min(nonzero_cycle_times)}") print(f"CYCLE_TIME_MAX={max(nonzero_cycle_times)}") print(f"CYCLE_TIME_MEAN={sum(nonzero_cycle_times) / len(nonzero_cycle_times):.3f}") else: print("CYCLE_TIME_MIN=NOT_AVAILABLE") print("CYCLE_TIME_MAX=NOT_AVAILABLE") print("CYCLE_TIME_MEAN=NOT_AVAILABLE") if counters[0] != 1 or counter_gap_count != 0: print("BINARY_STATUS=FAIL_COUNTER_SEQUENCE") sys.exit(39) if time_decrease_count != 0: print("BINARY_STATUS=FAIL_TIME_MONOTONICITY") sys.exit(40) if len(nonzero_cycle_times) == 0: print("BINARY_STATUS=FAIL_NO_CYCLE_TIME") sys.exit(41) print("BINARY_STATUS=PASS") PY BINARY_RC=$? binary_value() { key="$1" sed -n "s/^${key}=//p" "$BINARY_REPORT" | tail -n 1 } BINARY_STATUS="$(binary_value BINARY_STATUS)" FILE_SIZE_BYTES="$(binary_value FILE_SIZE_BYTES)" NUMBER_OF_SIGNALS="$(binary_value NUMBER_OF_SIGNALS)" SIGNAL_NAMES="$(binary_value SIGNAL_NAMES)" HEADER_BYTES="$(binary_value HEADER_BYTES)" SAMPLE_BYTES="$(binary_value SAMPLE_BYTES)" PAYLOAD_BYTES="$(binary_value PAYLOAD_BYTES)" PAYLOAD_REMAINDER_BYTES="$(binary_value PAYLOAD_REMAINDER_BYTES)" COMPLETE_SAMPLE_COUNT="$(binary_value COMPLETE_SAMPLE_COUNT)" COUNTER_FIRST="$(binary_value COUNTER_FIRST)" COUNTER_LAST="$(binary_value COUNTER_LAST)" COUNTER_GAP_COUNT="$(binary_value COUNTER_GAP_COUNT)" TIME_FIRST="$(binary_value TIME_FIRST)" TIME_LAST="$(binary_value TIME_LAST)" TIME_DECREASE_COUNT="$(binary_value TIME_DECREASE_COUNT)" NONZERO_CYCLE_TIME_SAMPLES="$(binary_value NONZERO_CYCLE_TIME_SAMPLES)" CYCLE_TIME_MIN="$(binary_value CYCLE_TIME_MIN)" CYCLE_TIME_MAX="$(binary_value CYCLE_TIME_MAX)" CYCLE_TIME_MEAN="$(binary_value CYCLE_TIME_MEAN)" DT_INTERVAL_COUNT="$(binary_value DT_INTERVAL_COUNT)" DT_DISTINCT_VALUES="$(binary_value DT_DISTINCT_VALUES)" DT_HISTOGRAM="$(binary_value DT_HISTOGRAM)" DT_MIN="$(binary_value DT_MIN)" DT_MAX="$(binary_value DT_MAX)" DT_ANOMALY_COUNT="$(binary_value DT_ANOMALY_COUNT)" DT_ANOMALY_INDICES="$(binary_value DT_ANOMALY_INDICES)" DT_FIRST_ANOMALY_BETWEEN_RECORDS="$(binary_value DT_FIRST_ANOMALY_BETWEEN_RECORDS)" DT_FIRST_ANOMALY_COUNTER_PAIR="$(binary_value DT_FIRST_ANOMALY_COUNTER_PAIR)" DT_FIRST_ANOMALY_VALUE="$(binary_value DT_FIRST_ANOMALY_VALUE)" LEADING_ZERO_CYCLE_TIME_SAMPLES="$(binary_value LEADING_ZERO_CYCLE_TIME_SAMPLES)" affinity_display() { object_count="$1" affinity_mapping="$2" if [ "$object_count" = "1" ]; then printf "%s" "${affinity_mapping#*=}" else printf "%s" "$affinity_mapping" fi } REALTIME_THREAD_AFFINITY_DISPLAY="$(affinity_display "${REALTIME_THREAD_OBJECT_COUNT:-0}" "${REALTIME_THREAD_AFFINITY:-NOT_AVAILABLE}")" FILE_WRITER_AFFINITY_DISPLAY="$(affinity_display "${FILE_WRITER_OBJECT_COUNT:-0}" "${FILE_WRITER_AFFINITY:-NOT_AVAILABLE}")" LINUX_TIMER_AFFINITY_DISPLAY="$(affinity_display "${LINUX_TIMER_OBJECT_COUNT:-0}" "${LINUX_TIMER_AFFINITY:-NOT_AVAILABLE}")" printf "============================================================\n" printf "VALIDAZIONE PRECISA S02\n" printf "============================================================\n" printf "Run directory: %s\n" "$RUN_DIR" printf "Log: %s\n" "$RUN_LOG" printf "Configurazione: %s\n" "$RUN_CONFIG" printf "File binario: %s\n" "$OUTPUT_FILE" printf "Avvii State1: %s\n" "$START_LINES" printf "Application starting: %s\n" "$APPLICATION_START_LINES" printf "Aperture FileWriter: %s\n" "$FILE_OPEN_LINES" printf "Placeholder residui: %s\n" "$PLACEHOLDER_COUNT" printf "Classe qualificata FileWriter: %s\n" "$NAMESPACED_CLASS_COUNT" printf "Classe semplice FileWriter: %s\n" "$PLAIN_CLASS_COUNT" printf "Filename corretti: %s\n" "$FILENAME_MATCH_LINES" printf "Dimensione file: %s byte\n" "${FILE_SIZE_BYTES:-NOT_AVAILABLE}" printf "Segnali binari: %s\n" "${NUMBER_OF_SIGNALS:-NOT_AVAILABLE}" printf "Nomi segnali: %s\n" "${SIGNAL_NAMES:-NOT_AVAILABLE}" printf "Header: %s byte\n" "${HEADER_BYTES:-NOT_AVAILABLE}" printf "Record: %s byte\n" "${SAMPLE_BYTES:-NOT_AVAILABLE}" printf "Payload: %s byte\n" "${PAYLOAD_BYTES:-NOT_AVAILABLE}" printf "Residuo payload: %s byte\n" "${PAYLOAD_REMAINDER_BYTES:-NOT_AVAILABLE}" printf "Campioni completi: %s\n" "${COMPLETE_SAMPLE_COUNT:-NOT_AVAILABLE}" printf "Counter iniziale: %s\n" "${COUNTER_FIRST:-NOT_AVAILABLE}" printf "Counter finale: %s\n" "${COUNTER_LAST:-NOT_AVAILABLE}" printf "Salti Counter: %s\n" "${COUNTER_GAP_COUNT:-NOT_AVAILABLE}" printf "Time iniziale: %s\n" "${TIME_FIRST:-NOT_AVAILABLE}" printf "Time finale: %s\n" "${TIME_LAST:-NOT_AVAILABLE}" printf "Regressioni Time: %s\n" "${TIME_DECREASE_COUNT:-NOT_AVAILABLE}" printf "CycleTime non nulli: %s\n" "${NONZERO_CYCLE_TIME_SAMPLES:-NOT_AVAILABLE}" printf "CycleTime minimo: %s\n" "${CYCLE_TIME_MIN:-NOT_AVAILABLE}" printf "CycleTime massimo: %s\n" "${CYCLE_TIME_MAX:-NOT_AVAILABLE}" printf "CycleTime medio: %s\n" "${CYCLE_TIME_MEAN:-NOT_AVAILABLE}" printf "Stato parser binario: %s\n" "${BINARY_STATUS:-NOT_AVAILABLE}" printf "Exit code MARTe: %s\n" "$MARTE_EXIT_CODE" printf "Exit code tee: %s\n" "$TEE_EXIT_CODE" printf "SIGINT ricevuti: %s\n" "$SIGINT_LINES" printf "Stop riusciti: %s\n" "$STOP_OK_LINES" printf "Application terminated: %s\n" "$TERMINATED_LINES" printf "Errori startup: %s\n" "$STARTUP_ERROR_LINES" printf "FatalError reali: %s\n" "$FATAL_ERROR_LINES" printf "OSError reali: %s\n" "$OS_ERROR_LINES" printf "Error reali: %s\n" "$ERROR_LINES" printf "InitialisationError reali: %s\n" "$INITIALISATION_ERROR_LINES" printf "NoError: %s\n" "$NO_ERROR_LINES" printf "Doppio arresto: %s\n" "$DOUBLE_STOP_LINES" printf "Close EventSem asincrono: %s\n" "$ASYNC_EVENTSEM_CLOSE_LINES" printf "pthread_mutex_destroy: %s\n" "$PTHREAD_MUTEX_DESTROY_LINES" printf "FatalError non classificati: %s\n" "$UNCLASSIFIED_FATAL_LINES" printf "OSError non classificati: %s\n" "$UNCLASSIFIED_OS_ERROR_LINES" printf "\n--- INTERVALLI TEMPORALI (osservativo) ---\n" printf "Periodo nominale: %s us\n" "${DT_NOMINAL_PERIOD_US:-NOT_AVAILABLE}" printf "Fonte periodo nominale: %s\n" "${DT_NOMINAL_SOURCE:-NOT_AVAILABLE}" printf "Intervalli dt: %s\n" "${DT_INTERVAL_COUNT:-NOT_AVAILABLE}" printf "Valori dt distinti: %s\n" "${DT_DISTINCT_VALUES:-NOT_AVAILABLE}" printf "Istogramma dt: %s\n" "${DT_HISTOGRAM:-NOT_AVAILABLE}" printf "dt minimo: %s\n" "${DT_MIN:-NOT_AVAILABLE}" printf "dt massimo: %s\n" "${DT_MAX:-NOT_AVAILABLE}" printf "Intervalli dt anomali: %s\n" "${DT_ANOMALY_COUNT:-NOT_AVAILABLE}" printf "Indici dt anomali: %s\n" "${DT_ANOMALY_INDICES:-NOT_AVAILABLE}" printf "Primo dt anomalo tra record: %s\n" "${DT_FIRST_ANOMALY_BETWEEN_RECORDS:-NOT_AVAILABLE}" printf "Primo dt anomalo Counter: %s\n" "${DT_FIRST_ANOMALY_COUNTER_PAIR:-NOT_AVAILABLE}" printf "Primo dt anomalo valore: %s\n" "${DT_FIRST_ANOMALY_VALUE:-NOT_AVAILABLE}" printf "CycleTime nulli iniziali: %s\n" "${LEADING_ZERO_CYCLE_TIME_SAMPLES:-NOT_AVAILABLE}" printf "\n--- AFFINITA' DICHIARATE IN CONFIGURAZIONE ---\n" REALTIME_THREAD_LABEL="RealTimeThread (${REALTIME_THREAD_OBJECT_NAMES:-NOT_AVAILABLE}) CPUs:" FILE_WRITER_LABEL="FileWriter (${FILE_WRITER_OBJECT_NAMES:-NOT_AVAILABLE}) CPUMask:" LINUX_TIMER_LABEL="LinuxTimer (${LINUX_TIMER_OBJECT_NAMES:-NOT_AVAILABLE}) CPUMask:" printf "%-40s %s (rc=%s)\n" "Stato parser configurazione:" "${CONFIG_OBSERVABILITY_STATUS:-NOT_AVAILABLE}" "$CONFIG_RC" printf "%-40s %s\n" "$REALTIME_THREAD_LABEL" "${REALTIME_THREAD_AFFINITY_DISPLAY:-NOT_AVAILABLE}" printf "%-40s %s\n" "$FILE_WRITER_LABEL" "${FILE_WRITER_AFFINITY_DISPLAY:-NOT_AVAILABLE}" printf "%-40s %s\n" "$LINUX_TIMER_LABEL" "${LINUX_TIMER_AFFINITY_DISPLAY:-NOT_AVAILABLE}" printf "\n--- PRIORITA' E TERMINAZIONE ---\n" printf "Warning totali: %s\n" "$WARNING_LINES" printf "Warning clipping priorita': %s\n" "$PRIORITY_CLIP_LINES" printf "Warning priorita' non applic.: %s\n" "$PRIORITY_FAIL_LINES" printf "Warning non classificati: %s\n" "$UNCLASSIFIED_WARNING_LINES" printf "Classe exit code: %s\n" "$MARTE_EXIT_CLASS" FUNCTIONAL_OK=0 if [ "$START_LINES" -ge 1 ] && [ "$APPLICATION_START_LINES" -ge 1 ] && [ "$FILE_OPEN_LINES" -ge 1 ] && [ "$STARTUP_ERROR_LINES" -eq 0 ] && [ "$PLACEHOLDER_COUNT" -eq 0 ] && [ "$NAMESPACED_CLASS_COUNT" -eq 1 ] && [ "$PLAIN_CLASS_COUNT" -eq 0 ] && [ "$FILENAME_MATCH_LINES" -eq 1 ] && [ "$BINARY_RC" -eq 0 ]; then FUNCTIONAL_OK=1 fi if [ "$FUNCTIONAL_OK" -eq 1 ]; then FUNCTIONAL_STATUS="PASS" else FUNCTIONAL_STATUS="NOT_DEMONSTRATED" fi if [ "$MARTE_EXIT_CLASS" = "EXIT_137_SIGKILL" ]; then TIMING_STATUS="NOT_VALID_EXIT_137_SIGKILL" elif [ "$PRIORITY_FAIL_LINES" -ge 1 ]; then TIMING_STATUS="NOT_VALID_PRIORITY_NOT_APPLIED" else TIMING_STATUS="UNASSESSED_DT_SEMANTICS" fi printf "\nFUNCTIONAL_STATUS=%s\n" "$FUNCTIONAL_STATUS" printf "TIMING_STATUS=%s\n" "$TIMING_STATUS" case "$FUNCTIONAL_STATUS:$TIMING_STATUS" in PASS:NOT_VALID_*) printf "FUNCTIONAL_PASS_TIMING_NOT_VALID\n" ;; esac printf "\n============================================================\n" printf "CLASSIFICAZIONE\n" printf "============================================================\n" if [ "$FUNCTIONAL_OK" -ne 1 ]; then printf "[NON DIMOSTRATO] Funzionamento S02 e registrazione binaria non sufficientemente provati.\n" printf "[DA VERIFICARE] Dettaglio parser binario:\n" cat -- "$BINARY_REPORT" exit 20 fi printf "[VERIFICATO] Funzionamento S02 e registrazione binaria dimostrati.\n" if [ "$SIGINT_LINES" -ge 1 ] && [ "$STOP_OK_LINES" -ge 1 ] && [ "$TERMINATED_LINES" -ge 1 ] && [ "$FATAL_ERROR_LINES" -eq 0 ] && [ "$OS_ERROR_LINES" -eq 0 ] && [ "$ERROR_LINES" -eq 0 ] && [ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then printf "[VERIFICATO] Shutdown privo di Error, OSError e FatalError.\n" exit 0 fi KNOWN_SHUTDOWN_TOTAL=$((DOUBLE_STOP_LINES + ASYNC_EVENTSEM_CLOSE_LINES + PTHREAD_MUTEX_DESTROY_LINES)) if [ "$SIGINT_LINES" -ge 1 ] && [ "$STOP_OK_LINES" -ge 1 ] && [ "$TERMINATED_LINES" -ge 1 ] && [ "$KNOWN_SHUTDOWN_TOTAL" -ge 1 ] && [ "$UNCLASSIFIED_FATAL_LINES" -eq 0 ] && [ "$UNCLASSIFIED_OS_ERROR_LINES" -eq 0 ] && [ "$ERROR_LINES" -eq 0 ] && [ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then printf "[DA VERIFICARE] Funzionalità riuscita con sole anomalie di shutdown già classificate.\n" exit 10 fi printf "[DA VERIFICARE] Funzionalità riuscita, ma sono presenti anomalie di shutdown non classificate.\n" exit 11