""" GRIFO_M_PBIT.py - Automated Power-On BIT Test for GRIFO-F/TH Radar This script performs comprehensive Built-In Test (BIT) verification with power cycling: - Executes configurable number of test repetitions (default: 10) - Power cycles radar between runs to simulate cold-start conditions - Monitors B6 LRU (Line Replaceable Unit) status fields - Performs detailed B8 diagnostic drill-down on real failures - Generates comprehensive statistics report with timing analysis Test Flow: 1. Power on radar and wait for initialization 2. Execute BIT and wait for completion (timeout: 180s) 3. Verify all 12 B6 LRU status fields 4. If real failures detected, drill-down into 185 B8 diagnostic fields 5. Track statistics (timing, pass/fail counts, failure details) 6. Power off and repeat 7. Generate final comprehensive report with aggregate statistics Author: Test Automation Team Date: 2026-01-29 """ import __init__ import signal import time,sys,os import logging from leo_grifo_common import * from test_common_function import * from leo_grifo_test_report import testReport from leo_grifo_1553 import theGrifo1553 #import leo_grifo_serial_maintnance from logger import logger_setup import leo_grifo_terminal import pdb import traceback NUMBER_OF_REPETITIONS = 10 # Total test cycles to execute PBIT_SEC_TIME = 180 # BIT completion timeout in seconds # ==================== # KNOWN FAILURES CONFIGURATION # ==================== # List of field names that are expected to fail due to HW test setup limitations. # These failures are tracked but do not trigger B8 drill-down or test failure. # # Use case: When test HW setup lacks physical components (e.g., pedestal unit), # certain status checks will always fail. Adding them here prevents false negatives. # # Format: Full field name from bit_fields tuple # Note: Known failures are reported separately in statistics but don't affect test verdict KNOWN_FAILURES = [ "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_pedestal_status", # Add more known HW setup limitations here as needed ] interruptRequest = False # Global flag for graceful Ctrl-C handling # ==================== # TEST STATISTICS TRACKING # ==================== # Global dictionary to track statistics across all test repetitions. # Populated during test execution and used to generate final comprehensive report. # # Structure: # repetitions: List of dicts, one per run, containing: # - repetition: Run number (1-based) # - pbit_time: BIT completion time in seconds # - bit_available: Boolean, True if BIT completed # - success: Boolean, overall run result (pass/fail) # - b6_total/pass/fail/known_fail: B6 LRU status check counts # - b8_checked/pass/fail: B8 diagnostic check counts # - failures: List of (field_name, value) tuples for real failures # - known_failures: List of (field_name, value) tuples for expected failures # total_runs: Counter for completed test runs # successful_runs: Counter for runs with no real failures # failed_runs: Counter for runs with real failures detected test_statistics = { 'repetitions': [], # List of per-run statistics dictionaries 'total_runs': 0, # Total number of completed runs 'successful_runs': 0, # Number of runs that passed (only known failures allowed) 'failed_runs': 0, # Number of runs with real failures detected } def signal_handler(sig, frame): """Handle Ctrl-C signal for graceful test termination.""" global interruptRequest logging.info("Ctrl-C detected, exiting gracefully...") interruptRequest = True def generate_final_statistics_report(report, stats): """ Generate comprehensive final statistics report with 8-section analysis. Produces professional test summary suitable for formal documentation and presentations. Includes aggregate statistics, timing analysis, failure categorization, and test verdict. Args: report: testReport object for PDF generation (supports add_comment method) stats: test_statistics dictionary containing all run data Report Sections: 1. Overall Test Summary: Total runs, success/fail rates with percentages 2. Detailed Per-Run Results: Compact table showing status, timing, B6/B8 metrics per run 3. Aggregate Statistics: Combined B6/B8 checks from all runs with pass rates 4. PBIT Timing Analysis: Average, min, max, std dev, utilization vs target timeout 5. Known Failures Tracking: HW setup limitations with consistency flags 6. Real Failures Analysis: Top 15 failures by frequency with priority levels 7. Failure Distribution: Subsystem breakdown with visual bar charts 8. Test Conclusion: Automated verdict (EXCELLENT/GOOD/ACCEPTABLE/CRITICAL) Returns: None (outputs to report object) """ report.add_comment("\n" + "="*90) report.add_comment(" FINAL TEST STATISTICS REPORT") report.add_comment("="*90) # ========== SECTION 1: OVERALL SUMMARY ========== # High-level pass/fail metrics across all test runs total = stats['total_runs'] success = stats['successful_runs'] failed = stats['failed_runs'] success_rate = (success / total * 100) if total > 0 else 0 report.add_comment("\n┌─── OVERALL TEST SUMMARY ───────────────────────────────────────────────────────┐") report.add_comment(f"│ Total Runs: {total:3d} │") report.add_comment(f"│ Successful Runs: {success:3d} ({success_rate:5.1f}%) │") report.add_comment(f"│ Failed Runs: {failed:3d} ({100-success_rate:5.1f}%) │") report.add_comment("└────────────────────────────────────────────────────────────────────────────────┘") # ========== SECTION 2: DETAILED PER-RUN TABLE ========== # Compact tabular view of each test run with key metrics + serial statistics report.add_comment("\n┌─── DETAILED PER-RUN RESULTS ───────────────────────────────────────────────────────────────────────┐") # Table columns: Run# | Status | PBIT time | B6 counts | B8 counts | Serial stats | Result table_header = ( "│ │\n" "│ Run │ Status │ PBIT │ B6 Status (P/F/K) │ B8 Checked │ Serial (E/F/R) │ B8 Fail │ Result │\n" "│─────┼────────┼────────┼───────────────────┼────────────┼────────────────┼─────────┼─────────│\n" ) report.add_comment(table_header) for run in stats['repetitions']: # Format run result with pass/fail indicators status_symbol = "✓" if run['success'] else "✗" status_text = "PASS" if run['success'] else "FAIL" pbit_time = run['pbit_time'] if run['bit_available'] else 0 # B6 status: compact Pass/Fail/Known format for quick scanning b6_status = f"{run['b6_pass']:2d}/{run['b6_fail']}/{run['b6_known_fail']}" # Serial statistics: compact Error/Fatal/Recycle format serial_stats_display = f"{run.get('serial_errors', 0)}/{run.get('serial_fatal', 0)}/{run.get('serial_recycles', 0)}" # B8 failures: show count or '-' if not checked (no real B6 failures) b8_fail_count = run['b8_fail'] b8_fail_display = f"{b8_fail_count:3d}" if b8_fail_count > 0 else " -" # Result with symbol result = f"{status_symbol} {status_text}" row = ( f"│ {run['repetition']:3d} │ {status_text:6s} │ {pbit_time:5.1f}s │ " f"{b6_status:^17s} │ {run['b8_checked']:10d} │ {serial_stats_display:^14s} │ {b8_fail_display:^7s} │ {result:7s} │\n" ) report.add_comment(row) report.add_comment("└────────────────────────────────────────────────────────────────────────────────────────────────┘") report.add_comment(" Legend: B6 Status = Pass/Fail/Known | Serial = Errors/Fatal/Recycles | '-' = Not checked") # ========== SECTION 3: AGGREGATE STATISTICS ========== # Sum all B6/B8 checks across runs for overall health assessment report.add_comment("\n┌─── AGGREGATE STATISTICS (All Runs Combined) ──────────────────────────────────┐") # Calculate total checks and outcomes across all repetitions total_b6_checks = sum(r['b6_total'] for r in stats['repetitions']) total_b6_pass = sum(r['b6_pass'] for r in stats['repetitions']) total_b6_fail = sum(r['b6_fail'] for r in stats['repetitions']) total_b6_known = sum(r['b6_known_fail'] for r in stats['repetitions']) total_b8_checks = sum(r['b8_checked'] for r in stats['repetitions']) total_b8_pass = sum(r['b8_pass'] for r in stats['repetitions']) total_b8_fail = sum(r['b8_fail'] for r in stats['repetitions']) b6_pass_rate = (total_b6_pass / total_b6_checks * 100) if total_b6_checks > 0 else 0 b8_pass_rate = (total_b8_pass / total_b8_checks * 100) if total_b8_checks > 0 else 0 report.add_comment(f"│ │") report.add_comment(f"│ B6 LRU Status Checks: │") report.add_comment(f"│ Total Checks: {total_b6_checks:5d} │") report.add_comment(f"│ Pass: {total_b6_pass:5d} ({b6_pass_rate:5.1f}%) │") report.add_comment(f"│ Fail (Real): {total_b6_fail:5d} ({total_b6_fail/total_b6_checks*100 if total_b6_checks>0 else 0:5.1f}%) │") report.add_comment(f"│ Known Failures: {total_b6_known:5d} ({total_b6_known/total_b6_checks*100 if total_b6_checks>0 else 0:5.1f}%) [HW setup - ignored] │") report.add_comment(f"│ │") if total_b8_checks > 0: report.add_comment(f"│ B8 Diagnostic Checks: │") report.add_comment(f"│ Total Checks: {total_b8_checks:5d} │") report.add_comment(f"│ Pass: {total_b8_pass:5d} ({b8_pass_rate:5.1f}%) │") report.add_comment(f"│ Fail: {total_b8_fail:5d} ({total_b8_fail/total_b8_checks*100:5.1f}%) │") report.add_comment(f"│ │") # Serial communication aggregate statistics total_serial_msgs = sum(r.get('serial_total', 0) for r in stats['repetitions']) total_serial_errors = sum(r.get('serial_errors', 0) for r in stats['repetitions']) total_serial_fatal = sum(r.get('serial_fatal', 0) for r in stats['repetitions']) total_serial_recycles = sum(r.get('serial_recycles', 0) for r in stats['repetitions']) report.add_comment(f"│ Serial Communication: │") report.add_comment(f"│ Total Messages: {total_serial_msgs:5d} │") report.add_comment(f"│ Error (%%E): {total_serial_errors:5d} │") report.add_comment(f"│ Fatal (%%F): {total_serial_fatal:5d} │") report.add_comment(f"│ System Recycles: {total_serial_recycles:5d} [Power cycles + unexpected resets] │") report.add_comment(f"│ │") report.add_comment("└────────────────────────────────────────────────────────────────────────────────┘") # ========== SECTION 4: TIMING ANALYSIS ========== # Statistical analysis of BIT completion times to assess performance consistency pbit_times = [r['pbit_time'] for r in stats['repetitions'] if r['bit_available']] if pbit_times: avg_pbit = sum(pbit_times) / len(pbit_times) min_pbit = min(pbit_times) max_pbit = max(pbit_times) # Calculate standard deviation for timing consistency assessment variance = sum((t - avg_pbit) ** 2 for t in pbit_times) / len(pbit_times) std_dev = variance ** 0.5 report.add_comment("\n┌─── PBIT TIMING ANALYSIS ───────────────────────────────────────────────────────┐") report.add_comment(f"│ │") report.add_comment(f"│ Samples: {len(pbit_times):3d} runs │") report.add_comment(f"│ Average: {avg_pbit:6.2f}s │") report.add_comment(f"│ Minimum: {min_pbit:6.2f}s │") report.add_comment(f"│ Maximum: {max_pbit:6.2f}s │") report.add_comment(f"│ Std Deviation: {std_dev:6.2f}s │") report.add_comment(f"│ Target Timeout: {PBIT_SEC_TIME:6.2f}s │") # Performance indicator based on timeout utilization percentage # <30% = EXCELLENT, <50% = GOOD, else ACCEPTABLE avg_utilization = (avg_pbit / PBIT_SEC_TIME * 100) if PBIT_SEC_TIME > 0 else 0 perf_indicator = "EXCELLENT" if avg_utilization < 30 else "GOOD" if avg_utilization < 50 else "ACCEPTABLE" report.add_comment(f"│ Avg Utilization: {avg_utilization:5.1f}% ({perf_indicator}) │") report.add_comment(f"│ │") report.add_comment("└────────────────────────────────────────────────────────────────────────────────┘") # ========== SECTION 5: KNOWN FAILURES TRACKING ========== # Track expected failures due to HW test setup limitations (from KNOWN_FAILURES list) all_known = [f for r in stats['repetitions'] for f in r['known_failures']] if all_known: # Count occurrence frequency to identify consistent vs intermittent known issues known_counts = {} for field, _ in all_known: field_name = field.split('_')[-1] # Short name known_counts[field_name] = known_counts.get(field_name, 0) + 1 report.add_comment("\n┌─── KNOWN FAILURES (HW Setup - Ignored for Analysis) ──────────────────────────┐") report.add_comment(f"│ │") for field, count in sorted(known_counts.items(), key=lambda x: x[1], reverse=True): occurrence_rate = count / total * 100 # Flag as CONSISTENT if appears in all runs, else INTERMITTENT consistency = "CONSISTENT" if count == total else "INTERMITTENT" report.add_comment(f"│ • {field:25s} {count:2d}/{total} runs ({occurrence_rate:5.1f}%) {consistency:12s} │") report.add_comment(f"│ │") report.add_comment("└────────────────────────────────────────────────────────────────────────────────┘") # ========== SECTION 5.1: SERIAL RECYCLE ANALYSIS ========== # Track system recycles detected via serial communication (RECYCLE keyword) all_recycles = [] for run in stats['repetitions']: run_recycles = run.get('serial_recycles', 0) if run_recycles > 0: all_recycles.append((run['repetition'], run_recycles, run.get('serial_details', []))) if total_serial_recycles > 0: report.add_comment("\n┌─── SYSTEM RECYCLE ANALYSIS (Serial Communication) ────────────────────────────┐") report.add_comment(f"│ │") report.add_comment(f"│ Total Recycles Detected: {total_serial_recycles:2d} │") report.add_comment(f"│ Runs with Recycles: {len(all_recycles):2d}/{total} │") report.add_comment(f"│ │") # Determine recycle frequency pattern expected_recycles_per_run = 1 # Power cycle at start unexpected_recycles = total_serial_recycles - (total * expected_recycles_per_run) if unexpected_recycles > 0: report.add_comment(f"│ ⚠ WARNING: {unexpected_recycles} unexpected recycles detected! │") report.add_comment(f"│ Expected: {expected_recycles_per_run} per run (planned power cycle) │") report.add_comment(f"│ Additional recycles may indicate system instability │") else: report.add_comment(f"│ ✓ All recycles expected (planned power cycles only) │") report.add_comment(f"│ │") report.add_comment("│ Per-Run Recycle Details: │") for run_num, recycle_count, details in all_recycles: recycle_details_for_run = [d for d in details if d['type'] == 'RECYCLE'] report.add_comment(f"│ Run {run_num:2d}: {recycle_count} recycle(s) │") for detail in recycle_details_for_run[:3]: # Show first 3 timestamp = detail.get('timestamp', 'N/A') report.add_comment(f"│ [{timestamp}] Recycle detected │") report.add_comment(f"│ │") report.add_comment("└────────────────────────────────────────────────────────────────────────────────┘") # ========== SECTION 6: REAL FAILURES ANALYSIS ========== # Analyze actual failures requiring investigation (not in KNOWN_FAILURES) all_failures = [f for r in stats['repetitions'] for f in r['failures']] if all_failures: # Count failure frequency by field and assign priority levels fail_counts = {} for field, value in all_failures: # Abbreviate field names for readability while preserving key information parts = field.split('_') if 'test_' in field: # Test fields: extract test type and SRU location field_short = '_'.join([p for p in parts if p.startswith('test_') or p.startswith('sru')]) else: # Status fields: use last 2-3 parts (e.g., processor_status, transmitter_test) field_short = '_'.join(parts[-3:]) if len(parts) > 3 else field fail_counts[field_short] = fail_counts.get(field_short, 0) + 1 report.add_comment("\n┌─── REAL FAILURES DETECTED (Require Investigation) ────────────────────────────┐") report.add_comment(f"│ │") report.add_comment(f"│ Total Unique Failures: {len(fail_counts)} │") report.add_comment(f"│ Total Occurrences: {len(all_failures)} │") report.add_comment(f"│ │") report.add_comment("│ Most Frequent Failures: │") # Show top 15 most frequent failures with priority assignment # Priority: HIGH (≥50% of runs), MEDIUM (≥25%), LOW (<25%) for idx, (field, count) in enumerate(sorted(fail_counts.items(), key=lambda x: x[1], reverse=True)[:15], 1): occurrence_rate = count / total * 100 priority = "HIGH" if count >= total/2 else "MEDIUM" if count >= total/4 else "LOW" report.add_comment(f"│ {idx:2d}. {field:35s} {count:2d} occ ({occurrence_rate:5.1f}%) [{priority:6s}] │") if len(fail_counts) > 15: report.add_comment(f"│ ... and {len(fail_counts)-15} more unique failures │") report.add_comment(f"│ │") report.add_comment("└────────────────────────────────────────────────────────────────────────────────┘") # Subsystem-level failure distribution for root cause analysis report.add_comment("\n┌─── FAILURE DISTRIBUTION BY SUBSYSTEM ──────────────────────────────────────────┐") category_failures = {} for field, _ in all_failures: # Categorize failures by subsystem using field name pattern matching if 'failure_location_processor' in field: cat = 'Processor SRU' elif 'failure_location_transmitter' in field: cat = 'Transmitter SRU' elif 'failure_location_receiver' in field: cat = 'Receiver SRU' elif 'failure_location_servoloop' in field: cat = 'Servoloop SRU' elif 'failure_location_pedestal' in field: cat = 'Pedestal SRU' elif 'failure_location_rx_frontend' in field: cat = 'RX Frontend SRU' elif 'processor_test_results' in field or 'signal_processor' in field or 'data_processor' in field: cat = 'Processor Tests' elif 'transmitter_test_results' in field: cat = 'Transmitter Tests' elif 'receiver_and_rx' in field or 'rx_module' in field: cat = 'Receiver Tests' elif 'servoloop_test' in field: cat = 'Servoloop Tests' elif 'degradation_conditions' in field: cat = 'Degradation' elif 'radar_health_status' in field: cat = 'B6 LRU Status' else: cat = 'Other' category_failures[cat] = category_failures.get(cat, 0) + 1 report.add_comment(f"│ │") for cat, count in sorted(category_failures.items(), key=lambda x: x[1], reverse=True): cat_rate = count / len(all_failures) * 100 bar_length = int(cat_rate / 5) # Visual bar: 1 block per 5%, max 20 chars bar = "█" * bar_length report.add_comment(f"│ {cat:25s} {count:3d} ({cat_rate:5.1f}%) {bar:20s} │") report.add_comment(f"│ │") report.add_comment("└────────────────────────────────────────────────────────────────────────────────┘") else: report.add_comment("\n┌─── REAL FAILURES DETECTED ─────────────────────────────────────────────────────┐") report.add_comment(f"│ │") report.add_comment(f"│ ✓ NO REAL FAILURES DETECTED │") report.add_comment(f"│ │") report.add_comment(f"│ All runs completed successfully with only known HW setup limitations. │") report.add_comment(f"│ │") report.add_comment("└────────────────────────────────────────────────────────────────────────────────┘") # ========== SECTION 8: TEST CONCLUSION ========== # Automated verdict based on success rate with actionable recommendations report.add_comment("\n┌─── TEST CONCLUSION ────────────────────────────────────────────────────────────┐") report.add_comment(f"│ │") # Assign verdict: EXCELLENT (100%), GOOD (≥80%), ACCEPTABLE (≥50%), CRITICAL (<50%) if success == total: report.add_comment(f"│ ✓✓✓ ALL RUNS PASSED ({total}/{total}) │") report.add_comment(f"│ │") report.add_comment(f"│ Radar BIT system is operating within expected parameters. │") verdict = "EXCELLENT" elif success >= total * 0.8: report.add_comment(f"│ ✓ MOSTLY SUCCESSFUL ({success}/{total} runs passed, {success_rate:.1f}%) │") report.add_comment(f"│ │") report.add_comment(f"│ Radar BIT system shows good performance with minor issues. │") verdict = "GOOD" elif success >= total * 0.5: report.add_comment(f"│ ⚠ PARTIAL SUCCESS ({success}/{total} runs passed, {success_rate:.1f}%) │") report.add_comment(f"│ │") report.add_comment(f"│ Radar BIT system requires attention. Investigation recommended. │") verdict = "ACCEPTABLE" else: report.add_comment(f"│ ✗ CRITICAL ISSUES ({success}/{total} runs passed, {success_rate:.1f}%) │") report.add_comment(f"│ │") report.add_comment(f"│ Radar BIT system has significant problems. Immediate action required. │") verdict = "CRITICAL" report.add_comment(f"│ │") report.add_comment(f"│ Overall Assessment: {verdict:20s} │") report.add_comment(f"│ │") report.add_comment("└────────────────────────────────────────────────────────────────────────────────┘") report.add_comment("\n" + "="*90) report.add_comment(" END OF REPORT") report.add_comment("="*90 + "\n") def tgt_gen(interface): logging.info('tgt_gen()') #time.sleep(5) period=10 #ms expeced_range=1000 pcnt=0 for i in range(500): time.sleep(0.010) cnt = interface.getSingleMessageReceivedSz("B9") t_num=interface.getMessageFieldValue("B9", "b9_t_num") t_rng=interface.getMessageFieldValue("B9", "b9_t1_rng") if (i % 10)==0: dcnt=cnt-pcnt pcnt=cnt logging.info(f'TgtMsg: {cnt} {dcnt}') if t_num>0: logging.info(f'Tgt: {t_num} @ {t_rng}') ret_proc_sts, err= check(theGrifo1553,(1,2), "B9", "b9_t_num") check(theGrifo1553,(1179, 1186), "B9", "b9_t1_rng") break if interruptRequest is True: break def tgt_gen_alone(interface): interface.logStart(3,os.path.dirname(sys.argv[0])) for n in range(10*1000): logging.info(f'tgt_gen_alone(): {n}') tgt_gen(interface) if interruptRequest is True: break interface.logStop() return True def test_proc(): global report, test_statistics # Complete bit_fields: All B6 LRU status + All B8 degradation/SRU/test fields # Total: 185 fields (12 B6 status + 12 B8 degradation + 43 B8 SRU + 118 B8 tests) bit_fields = ( # ===== B6: LRU Status Fields ===== "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_array_status", "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_pedestal_status", "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_pressurization_status", "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_processor_over_temperature_alarm", "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_processor_status", "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_radar_fail_status", "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_receiver_status", "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_rx_front_end_status", "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_servoloop_over_temperature_alarm", "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_servoloop_status", "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_trasmitter_over_temperature_alarm", "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_trasmitter_status", # ===== B8: Degradation Conditions ===== "degradation_conditions_w1_DegradationConditionsW1_bcn_fail", "degradation_conditions_w1_DegradationConditionsW1_gm_rbm_sea1_ta_wa_fail", "degradation_conditions_w1_DegradationConditionsW1_group1_fail", "degradation_conditions_w1_DegradationConditionsW1_group2_fail", "degradation_conditions_w1_DegradationConditionsW1_group3_fail", "degradation_conditions_w1_DegradationConditionsW1_group4_fail", "degradation_conditions_w1_DegradationConditionsW1_group5_fail", "degradation_conditions_w1_DegradationConditionsW1_hr_modes_and_gm_dbs_fail", "degradation_conditions_w1_DegradationConditionsW1_no_rdr_symbology", "degradation_conditions_w1_DegradationConditionsW1_not_identified_rdr_fail", "degradation_conditions_w1_DegradationConditionsW1_selected_channel_fail", "degradation_conditions_w1_DegradationConditionsW1_total_rdr_fail", # ===== B8: SRU Failure Locations ===== "failure_location_pedestal_FailureLocationPedestal_sru1_gimbal", "failure_location_pedestal_FailureLocationPedestal_sru2_waveguide", "failure_location_pedestal_FailureLocationPedestal_sru3_waveguide", "failure_location_pedestal_FailureLocationPedestal_sru4_delta_guard_lna_switch", "failure_location_pedestal_FailureLocationPedestal_sru5_waveguide_switch", "failure_location_processor_FailureLocationProcessor_sru10_main_computer", "failure_location_processor_FailureLocationProcessor_sru11_graphic_computer", "failure_location_processor_FailureLocationProcessor_sru12_power_supply", "failure_location_processor_FailureLocationProcessor_sru13_det_exp", "failure_location_processor_FailureLocationProcessor_sru14_rx_module", "failure_location_processor_FailureLocationProcessor_sru1_motherboard_chassis", "failure_location_processor_FailureLocationProcessor_sru2_mti_fft", "failure_location_processor_FailureLocationProcessor_sru3_dsp0", "failure_location_processor_FailureLocationProcessor_sru4_dsp1", "failure_location_processor_FailureLocationProcessor_sru5_cfar_px_ctrl", "failure_location_processor_FailureLocationProcessor_sru6_timer", "failure_location_processor_FailureLocationProcessor_sru7_post_processor", "failure_location_processor_FailureLocationProcessor_sru8_agc", "failure_location_processor_FailureLocationProcessor_sru9_esa_if", "failure_location_receiver_FailureLocationReceiver_sru1_chassis", "failure_location_receiver_FailureLocationReceiver_sru2_uhf_assy", "failure_location_receiver_FailureLocationReceiver_sru3_synthesizer", "failure_location_receiver_FailureLocationReceiver_sru4_delta_guard_down_converter", "failure_location_receiver_FailureLocationReceiver_sru5_sum_down_converter", "failure_location_receiver_FailureLocationReceiver_sru6_lo_distributor", "failure_location_receiver_FailureLocationReceiver_sru7_up_converter", "failure_location_rx_frontend_FailureLocationRxFrontEnd_sru1_chassis", "failure_location_rx_frontend_FailureLocationRxFrontEnd_sru2_delta_guard_lna", "failure_location_rx_frontend_FailureLocationRxFrontEnd_sru3_sum_act_prot_lna", "failure_location_rx_frontend_FailureLocationRxFrontEnd_sru4_4port_circulator", "failure_location_rx_frontend_FailureLocationRxFrontEnd_sru5_stc_delta_guard", "failure_location_rx_frontend_FailureLocationRxFrontEnd_sru5_stc_sum", "failure_location_servoloop_FailureLocationServoloop_sru1_chassis", "failure_location_servoloop_FailureLocationServoloop_sru2_power_supply", "failure_location_servoloop_FailureLocationServoloop_sru3_digital_controller", "failure_location_transmitter_FailureLocationTransmitter_sru1_chassis", "failure_location_transmitter_FailureLocationTransmitter_sru2_rex_f_tx", "failure_location_transmitter_FailureLocationTransmitter_sru3_power_supply", "failure_location_transmitter_FailureLocationTransmitter_sru4_valve_el_twt_tx", "failure_location_transmitter_FailureLocationTransmitter_sru5_rf_driver", "failure_location_transmitter_FailureLocationTransmitter_sru6_controller_tx", "failure_location_transmitter_FailureLocationTransmitter_sru7_hv_power_supply", "failure_location_transmitter_FailureLocationTransmitter_sru8_eht_power_supply", # ===== B8: All Test Results ===== "agc_test_results_AGCTestResults_test_agc10_pulse_compressor_interface", "agc_test_results_AGCTestResults_test_agc11_dp_interface", "agc_test_results_AGCTestResults_test_agc13_taxi_running", "agc_test_results_AGCTestResults_test_agc14_external_xyp_ram", "agc_test_results_AGCTestResults_test_agc15_servoloop_interface", "agc_test_results_AGCTestResults_test_agc1_internal_xyp_ram", "agc_test_results_AGCTestResults_test_agc2_external_xyp_ram", "agc_test_results_AGCTestResults_test_agc5_dual_port_ram", "agc_test_results_AGCTestResults_test_agc6_agc_machine", "agc_test_results_AGCTestResults_test_agc7_sat_machine", "agc_test_results_AGCTestResults_test_agc9_c_ram_xy_checksum", "data_processor_test_results_DataProcessorTestResults_test_dp10_video_memory", "data_processor_test_results_DataProcessorTestResults_test_dp11_video_unit", "data_processor_test_results_DataProcessorTestResults_test_dp12_transputer_unit", "data_processor_test_results_DataProcessorTestResults_test_dp13_scan_converter_polar_memory", "data_processor_test_results_DataProcessorTestResults_test_dp14_scan_converter_format_converter", "data_processor_test_results_DataProcessorTestResults_test_dp1_486_cpu_tests", "data_processor_test_results_DataProcessorTestResults_test_dp2_486_interfaces_with_r3000_gc", "data_processor_test_results_DataProcessorTestResults_test_dp3_486_interface_with_slc", "data_processor_test_results_DataProcessorTestResults_test_dp4_slc_communications", "data_processor_test_results_DataProcessorTestResults_test_dp5_r3000_cpu_tests", "data_processor_test_results_DataProcessorTestResults_test_dp6_r3000_interfaces", "data_processor_test_results_DataProcessorTestResults_test_dp7_1553_and_discretes", "data_processor_test_results_DataProcessorTestResults_test_dp8_graphic_cpu", "data_processor_test_results_DataProcessorTestResults_test_dp9_graphic_processors", "integrated_system_test_results_IntegratedSystemTestResults_array_status", "integrated_system_test_results_IntegratedSystemTestResults_cal_delta_channel_fail", "integrated_system_test_results_IntegratedSystemTestResults_cal_injection_fail", "integrated_system_test_results_IntegratedSystemTestResults_cal_noise_fail", "integrated_system_test_results_IntegratedSystemTestResults_pedestal_status", "integrated_system_test_results_IntegratedSystemTestResults_processor_status", "integrated_system_test_results_IntegratedSystemTestResults_receiver_status", "integrated_system_test_results_IntegratedSystemTestResults_rx_frontend_status", "integrated_system_test_results_IntegratedSystemTestResults_servoloop_status", "integrated_system_test_results_IntegratedSystemTestResults_test_is1_upconverter_chain_levels", "integrated_system_test_results_IntegratedSystemTestResults_test_is2_downconverter_chain_levels", "integrated_system_test_results_IntegratedSystemTestResults_test_is3_antenna_status_inconsistent", "integrated_system_test_results_IntegratedSystemTestResults_test_is4_tx_status_inconsistent", "integrated_system_test_results_IntegratedSystemTestResults_test_is5_tx_power_level", "integrated_system_test_results_IntegratedSystemTestResults_transmitter_status", "post_processor_test_results_PostProcessorTestResults_test_pp1_master_dsp", "post_processor_test_results_PostProcessorTestResults_test_pp2_interface_card", "post_processor_test_results_PostProcessorTestResults_test_pp3_cpu_cards", "post_processor_test_results_PostProcessorTestResults_test_pp4_dma_bus", "post_processor_test_results_PostProcessorTestResults_test_pp5_sp_interface", "post_processor_test_results_PostProcessorTestResults_test_pp6_dp_interface", "post_processor_test_results_PostProcessorTestResults_test_pp7_scan_converter_interface", "post_processor_test_results_PostProcessorTestResults_test_pp8_agc_interface", "power_supply_test_results_PowerSupplyTestResults_test_ps1_power_supply", "power_supply_test_results_PowerSupplyTestResults_test_ps2_over_temperature", "receiver_and_rx_frontend_test_results_ReceiverAndRxTestResults_test_fe1_lna", "receiver_and_rx_frontend_test_results_ReceiverAndRxTestResults_test_fe2_agc_attenuators", "receiver_and_rx_frontend_test_results_ReceiverAndRxTestResults_test_rx1_synthesizer_commands", "receiver_and_rx_frontend_test_results_ReceiverAndRxTestResults_test_rx2_synthesizer_internal_tests", "receiver_and_rx_frontend_test_results_ReceiverAndRxTestResults_test_rx3_uhf_oscillator_level", "receiver_and_rx_frontend_test_results_ReceiverAndRxTestResults_test_rx4_downconverter_lo_level", "receiver_and_rx_frontend_test_results_ReceiverAndRxTestResults_test_rx5_upconverter_lo_level", "rx_module_test_results_RxModuleTestResults_test_rm16_calibration_sum_channel_fail", "rx_module_test_results_RxModuleTestResults_test_rm1_master_clock_level", "rx_module_test_results_RxModuleTestResults_test_rm2_expander_level", "rx_module_test_results_RxModuleTestResults_test_rm3_sum_channel_down_converter", "rx_module_test_results_RxModuleTestResults_test_rm4_dg_channel_down_converter", "rx_module_test_results_RxModuleTestResults_test_rm5_noise_attenuators", "servoloop_test_results_ServoloopTestResults_test_sl10_agc_control", "servoloop_test_results_ServoloopTestResults_test_sl11_ad", "servoloop_test_results_ServoloopTestResults_test_sl12_das", "servoloop_test_results_ServoloopTestResults_test_sl13_serial_communications", "servoloop_test_results_ServoloopTestResults_test_sl14_taxi_interface", "servoloop_test_results_ServoloopTestResults_test_sl15_pedestal_centre_scan_location", "servoloop_test_results_ServoloopTestResults_test_sl1_low_voltage_power_supply", "servoloop_test_results_ServoloopTestResults_test_sl2_high_voltage_power_supply", "servoloop_test_results_ServoloopTestResults_test_sl3_motor_drivers", "servoloop_test_results_ServoloopTestResults_test_sl4_resolvers_power_supply", "servoloop_test_results_ServoloopTestResults_test_sl5_waveguide_switch", "servoloop_test_results_ServoloopTestResults_test_sl6_over_temperature", "servoloop_test_results_ServoloopTestResults_test_sl7_resolver_to_digital_conv", "servoloop_test_results_ServoloopTestResults_test_sl8_position_loop_error", "servoloop_test_results_ServoloopTestResults_test_sl9_microprocessor", "signal_processor_test_results_SignalProcessorTestResults_test_sp10_board_overall", "signal_processor_test_results_SignalProcessorTestResults_test_sp11_attenuatori_antenna", "signal_processor_test_results_SignalProcessorTestResults_test_sp14_external_sp_if", "signal_processor_test_results_SignalProcessorTestResults_test_sp16_bcn", "signal_processor_test_results_SignalProcessorTestResults_test_sp1_timer1_up", "signal_processor_test_results_SignalProcessorTestResults_test_sp2_timer_dma_pxc_if", "signal_processor_test_results_SignalProcessorTestResults_test_sp3_timer_internal", "signal_processor_test_results_SignalProcessorTestResults_test_sp4_px_ctrl_comm", "signal_processor_test_results_SignalProcessorTestResults_test_sp5_video1_without_ad", "signal_processor_test_results_SignalProcessorTestResults_test_sp6_video1_with_ad", "signal_processor_test_results_SignalProcessorTestResults_test_sp7_video2_ad_sync", "signal_processor_test_results_SignalProcessorTestResults_test_sp8_video2_timer_sync", "signal_processor_test_results_SignalProcessorTestResults_test_sp9_ad_da", "signal_processor_test_results_SignalProcessorTestResults_test_sp9b_wideband_expander", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx10_hv_ps_over_temperature_warning", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx11_twt_helix_over_current", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx12_cathode_to_helix_arc", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx13_twt_over_temperature_hazard", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx14_twt_over_temperature_warning", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx15_cathode_under_voltage", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx16_cathode_over_voltage", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx1_microprocessors", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx2_tx_rf_input", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx3_twt_rf_input", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx4_twt_rf_output", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx5_tx_rf_output_level", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx6_vswr", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx7_three_phase_input_power", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx8_low_voltage_power_supplies", "transmitter_test_results_w1_TransmitterTestResultsW1_test_tx9_hv_ps_over_temperature_hazard", "transmitter_test_results_w2_TransmitterTestResultsW2_test_tx17_collector_under_voltage", "transmitter_test_results_w2_TransmitterTestResultsW2_test_tx18_collector_over_voltage", "transmitter_test_results_w2_TransmitterTestResultsW2_test_tx19_rectified_voltage", "transmitter_test_results_w2_TransmitterTestResultsW2_test_tx20_cathode_inv_current_fail", "transmitter_test_results_w2_TransmitterTestResultsW2_test_tx21_collector_inv_current_fail", "transmitter_test_results_w2_TransmitterTestResultsW2_test_tx22_waveguide_pressurization", "transmitter_test_results_w2_TransmitterTestResultsW2_test_tx23_grid_window_over_duty_alt", "transmitter_test_results_w2_TransmitterTestResultsW2_test_tx24_floating_deck_fail", "transmitter_test_results_w2_TransmitterTestResultsW2_test_tx25_floating_deck_ps_fail", "transmitter_test_results_w2_TransmitterTestResultsW2_test_tx26_grid_window_over_duty", ) # ==================== # BIT FIELDS CATEGORIZATION # ==================== # Dictionary mapping category names to field indices in bit_fields tuple. # Used for organized drill-down reporting when B6 failures trigger B8 verification. # # Categories: # B6_LRU_Status: 12 Line Replaceable Unit status fields (always checked) # B8_Degradation: 12 system degradation condition flags # B8_SRU_*: 43 Shop Replaceable Unit failure location flags (6 subsystems) # B8_Test_*: 118 detailed test result fields (10 test types) # # Total: 185 diagnostic fields providing complete radar health visibility bit_fields_categories = { 'B6_LRU_Status': bit_fields[0:12], 'B8_Degradation': bit_fields[12:24], 'B8_SRU_Pedestal': bit_fields[24:29], 'B8_SRU_Processor': bit_fields[29:43], 'B8_SRU_Receiver': bit_fields[43:50], 'B8_SRU_RxFrontend': bit_fields[50:56], 'B8_SRU_Servoloop': bit_fields[56:59], 'B8_SRU_Transmitter': bit_fields[59:67], 'B8_Test_AGC': bit_fields[67:78], 'B8_Test_DataProcessor': bit_fields[78:92], 'B8_Test_IntegratedSystem': bit_fields[92:107], 'B8_Test_PostProcessor': bit_fields[107:115], 'B8_Test_PowerSupply': bit_fields[115:117], 'B8_Test_Receiver': bit_fields[117:124], 'B8_Test_RxModule': bit_fields[124:130], 'B8_Test_Servoloop': bit_fields[130:145], 'B8_Test_SignalProcessor': bit_fields[145:159], 'B8_Test_Transmitter': bit_fields[159:185], } logger_setup('GRIFO_M_PBIT.log') report = testReport(sys.argv[0]) interface = theGrifo1553.getInterface() terminal = leo_grifo_terminal.GrifoSerialTerminal() terminal.connect() test_return = True try: #report.open_session('Pre Conditions') #power_grifo_off() #report.close_session() ############ Test Execution ############ #report.open_session('Test Execution') report.add_comment("The Test Operator check if the failure BIT in B6_MsgRdrSettingsAndParametersTellback changes ...") if tgt_gen_alone(interface) is False: return for repetition in range(NUMBER_OF_REPETITIONS): info = f'Repetition {1 + repetition} of {NUMBER_OF_REPETITIONS}' logging.info(info) report.open_session(info) # Statistics for this run run_stats = { 'repetition': repetition + 1, 'pbit_time': 0, 'bit_available': False, 'b6_total': 0, 'b6_pass': 0, 'b6_fail': 0, 'b6_known_fail': 0, 'b8_checked': 0, 'b8_pass': 0, 'b8_fail': 0, 'failures': [], 'known_failures': [], 'success': True, # Serial statistics 'serial_total': 0, 'serial_errors': 0, 'serial_fatal': 0, 'serial_recycles': 0, 'serial_details': [], # List of notable serial events } test_statistics['total_runs'] += 1 # Reset serial statistics for this run terminal.reset_serial_statistics() report.add_comment("The test operator is required to switch off the target and wait 3 seconds.") power_grifo_off(3) report.add_comment("The test operator is required to switch on the target.") power_grifo_on() remaining_time = PBIT_SEC_TIME pbit_start_time = time.perf_counter() max_counter_1553_msg = 20 while remaining_time > 0: start = time.perf_counter() ret_rep_is_avail = False msg_cnt = 0 mil1553_error_flag = max_counter_1553_msg for i in range(100): cnt = interface.getSingleMessageReceivedSz("B6_MsgRdrSettingsAndParametersTellback") value = interface.getMessageFieldValue("B6_MsgRdrSettingsAndParametersTellback", "radar_health_status_and_bit_report_valid_RdrHealthStatusAndBitReport_bit_report_available") ret_rep_is_avail = value == "true" if ret_rep_is_avail is True: break time.sleep(0.05) #logging.critical(f"1553 messag count {cnt} {mil1553_error_flag}") if cnt > msg_cnt: mil1553_error_flag = max_counter_1553_msg else : mil1553_error_flag -=1 msg_cnt = cnt if mil1553_error_flag == 0: logging.critical("1553 communication lost") return False if ret_rep_is_avail is True: time.sleep(0.02) run_stats['bit_available'] = True run_stats['pbit_time'] = time.perf_counter() - pbit_start_time report.add_comment(f"BIT report available after {run_stats['pbit_time']:.1f}s") # ===== PHASE 1: Verify ALL B6 LRU Status Fields ===== b6_lru_fields = bit_fields_categories['B6_LRU_Status'] b6_failures = [] b6_known_failures = [] for f in b6_lru_fields: run_stats['b6_total'] += 1 ret, err = check(theGrifo1553, "false", "B6_MsgRdrSettingsAndParametersTellback", f) if ret: run_stats['b6_pass'] += 1 else: if f in KNOWN_FAILURES: # Known failure: annotate but don't trigger drill-down run_stats['b6_known_fail'] += 1 b6_known_failures.append((f, err)) logging.warning(f"Known failure (ignored): {f}") else: # Real failure: needs investigation run_stats['b6_fail'] += 1 b6_failures.append((f, err)) test_return = False run_stats['success'] = False # Log B6 summary b6_summary = ( f"\n{'='*70}\n" f"B6 LRU Status Summary:\n" f" Total: {run_stats['b6_total']}\n" f" Pass: {run_stats['b6_pass']}\n" f" Fail: {run_stats['b6_fail']}\n" f" Known Fail: {run_stats['b6_known_fail']} (ignored for drill-down)\n" f"{'='*70}" ) logging.info(b6_summary) report.add_comment(b6_summary) if b6_known_failures: known_fail_list = "\n".join([f" - {f.split('_')[-1]}: {v}" for f, v in b6_known_failures]) report.add_comment(f"Known Failures (HW setup):\n{known_fail_list}") run_stats['known_failures'].extend(b6_known_failures) if b6_failures: fail_list = "\n".join([f" - {f.split('_')[-1]}: {v}" for f, v in b6_failures]) report.add_comment(f"Real Failures detected:\n{fail_list}") run_stats['failures'].extend(b6_failures) # ===== PHASE 2: Drill-down B8 only if REAL failures in B6 ===== if b6_failures: report.add_comment(f"\nDrill-down: Verifying all {len(bit_fields) - 12} B8 diagnostic fields...") b8_fields = bit_fields[12:] # All B8 fields b8_failures = [] for category, fields in list(bit_fields_categories.items())[1:]: # Skip B6 category_fail = 0 category_pass = 0 for f in fields: run_stats['b8_checked'] += 1 ret, err = check(theGrifo1553, "false", "B8_MsgBitReport", f) if ret: category_pass += 1 run_stats['b8_pass'] += 1 else: category_fail += 1 run_stats['b8_fail'] += 1 b8_failures.append((category, f, err)) test_return = False if category_fail > 0: logging.warning(f"{category}: {category_fail}/{len(fields)} failures") # B8 summary b8_summary = ( f"\n{'='*70}\n" f"B8 Diagnostic Fields Summary:\n" f" Checked: {run_stats['b8_checked']}\n" f" Pass: {run_stats['b8_pass']}\n" f" Fail: {run_stats['b8_fail']}\n" f"{'='*70}" ) logging.info(b8_summary) report.add_comment(b8_summary) if b8_failures: # Group by category for clarity fail_by_cat = {} for cat, field, err in b8_failures: if cat not in fail_by_cat: fail_by_cat[cat] = [] fail_by_cat[cat].append((field.split('_')[-1], err)) fail_detail = "\nB8 Failures by Category:\n" for cat, fails in fail_by_cat.items(): fail_detail += f"\n {cat} ({len(fails)} failures):\n" for fname, val in fails[:5]: # Max 5 per category fail_detail += f" - {fname}: {val}\n" if len(fails) > 5: fail_detail += f" ... and {len(fails)-5} more\n" report.add_comment(fail_detail) run_stats['failures'].extend([(f, v) for _, f, v in b8_failures]) else: report.add_comment("\n✓ All B6 LRU Status PASS (no B8 drill-down needed)") # Run statistics test_statistics['repetitions'].append(run_stats) if run_stats['success']: test_statistics['successful_runs'] += 1 else: test_statistics['failed_runs'] += 1 time_passed = time.perf_counter() - start remaining_time -= time_passed if ret_rep_is_avail is True: remaining_time = 0 logging.info(f'{remaining_time:.1f}s remaining ...') # Collect serial statistics for this run before closing session serial_stats = terminal.get_serial_statistics() run_stats['serial_total'] = serial_stats['total_messages'] run_stats['serial_errors'] = serial_stats['error_messages'] run_stats['serial_fatal'] = serial_stats['fatal_messages'] run_stats['serial_recycles'] = serial_stats['recycle_count'] # Add serial details to run report report.add_comment("\n--- Serial Communication Summary ---") report.add_comment(f"Total serial messages: {serial_stats['total_messages']}") report.add_comment(f"Error messages (%%E): {serial_stats['error_messages']}") report.add_comment(f"Fatal messages (%%F): {serial_stats['fatal_messages']}") report.add_comment(f"System recycles: {serial_stats['recycle_count']}") # Show recycle details if any if serial_stats['recycle_count'] > 0: report.add_comment("\nRecycle Events Detected:") for timestamp, message in serial_stats['recycle_details']: report.add_comment(f" [{timestamp}] {message}") run_stats['serial_details'].append({'type': 'RECYCLE', 'timestamp': timestamp, 'message': message}) # Show error details if any (limit to first 5 to avoid clutter) if serial_stats['error_messages'] > 0: report.add_comment(f"\nError Messages (%%E) - showing first 5 of {serial_stats['error_messages']}:") for timestamp, message in serial_stats['error_details'][:5]: report.add_comment(f" [{timestamp}] {message}") run_stats['serial_details'].append({'type': 'ERROR', 'timestamp': timestamp, 'message': message}) # Show fatal details if any (limit to first 5) if serial_stats['fatal_messages'] > 0: report.add_comment(f"\nFatal Messages (%%F) - showing first 5 of {serial_stats['fatal_messages']}:") for timestamp, message in serial_stats['fatal_details'][:5]: report.add_comment(f" [{timestamp}] {message}") run_stats['serial_details'].append({'type': 'FATAL', 'timestamp': timestamp, 'message': message}) report.close_session() if interruptRequest is True: report.add_comment("Test interrupted by user (Ctrl-C)") break tgt_gen(interface) report.add_comment("Repetitions terminated.") # ===== FINAL STATISTICS REPORT ===== generate_final_statistics_report(report, test_statistics) ############ END STEPS ############ #report.open_session('Post Conditions') power_grifo_off() #report.close_session() if terminal is not None: terminal.disconnect() return test_return except Exception as e: report.add_comment(f"Test terminated unexpectedly :{e}") return False finally: report.generate_pdf() #-- --------------------------------------------------------------- if __name__ == '__main__': signal.signal(signal.SIGINT, signal_handler) test_proc()