From eb17ebee4ed6e7b4e63e8ebe96cabd3ee9567734 Mon Sep 17 00:00:00 2001 From: JamesJCode <13408010-JamesJCode@users.noreply.gitlab.com> Date: Mon, 10 Feb 2025 20:57:51 +0000 Subject: [PATCH] Implement time-domain length tuning - Adds time and delay units - Adds time domain tuning parameters entry and storage - Adds pad-to-die delay property - Adds time domain parameter interface for length / delay calculations - Adds unit tracking for numerical constants through LIBEVAL - Will need future work to truly propagate through binary expressions - Adds time domain tuning to meander placers - Adds time delay display to net inspector panel - Modifies DRC to handle time domain constraints --- api/proto/common/types/project_settings.proto | 3 + common/CMakeLists.txt | 5 +- common/dialogs/panel_setup_netclasses.cpp | 19 + .../dialogs/panel_setup_netclasses_base.cpp | 13 +- .../dialogs/panel_setup_netclasses_base.fbp | 4 +- common/eda_units.cpp | 153 +- common/libeval/numeric_evaluator.cpp | 105 +- common/libeval_compiler/libeval_compiler.cpp | 39 +- common/netclass.cpp | 8 + common/pcb.keywords | 1 + common/preview_items/preview_utils.cpp | 21 +- common/project/net_settings.cpp | 38 +- common/project/project_file.cpp | 15 +- common/project/project_local_settings.cpp | 2 + common/project/time_domain_parameters.cpp | 197 + common/properties/pg_editors.cpp | 4 + common/properties/pg_properties.cpp | 68 + common/settings/common_settings.cpp | 68 +- common/widgets/wx_grid.cpp | 77 +- include/base_units.h | 2 + include/dialogs/panel_setup_netclasses.h | 2 + include/eda_units.h | 31 +- include/libeval/numeric_evaluator.h | 17 +- include/libeval_compiler/libeval_compiler.h | 41 +- include/netclass.h | 9 + include/project/board_project_settings.h | 2 + include/project/net_settings.h | 1 + include/project/project_file.h | 11 + include/project/time_domain_parameters.h | 80 + include/properties/pg_properties.h | 30 + include/properties/property.h | 3 +- include/settings/common_settings.h | 1 + include/units_provider.h | 74 +- include/widgets/wx_grid.h | 16 + pcbnew/CMakeLists.txt | 2 + pcbnew/board.cpp | 23 +- pcbnew/board.h | 15 +- pcbnew/dialogs/dialog_board_setup.cpp | 113 +- pcbnew/dialogs/dialog_board_setup.h | 12 +- pcbnew/dialogs/dialog_import_settings.cpp | 13 +- .../dialogs/dialog_import_settings_base.cpp | 5 + .../dialogs/dialog_import_settings_base.fbp | 66 + pcbnew/dialogs/dialog_import_settings_base.h | 1 + pcbnew/dialogs/dialog_pad_properties.cpp | 41 +- pcbnew/dialogs/dialog_pad_properties.h | 2 + pcbnew/dialogs/dialog_pad_properties_base.cpp | 22 + pcbnew/dialogs/dialog_pad_properties_base.fbp | 272 +- pcbnew/dialogs/dialog_pad_properties_base.h | 5 + .../dialog_tuning_pattern_properties.cpp | 143 +- .../dialog_tuning_pattern_properties.h | 3 + .../dialog_tuning_pattern_properties_base.cpp | 74 +- .../dialog_tuning_pattern_properties_base.fbp | 666 ++- .../dialog_tuning_pattern_properties_base.h | 13 +- .../panel_setup_time_domain_parameters.cpp | 634 +++ .../panel_setup_time_domain_parameters.h | 150 + ...anel_setup_time_domain_parameters_base.cpp | 185 + ...anel_setup_time_domain_parameters_base.fbp | 950 ++++ .../panel_setup_time_domain_parameters_base.h | 71 + pcbnew/drc/drc_engine.cpp | 2 + pcbnew/drc/drc_length_report.h | 4 + pcbnew/drc/drc_rule.h | 15 +- pcbnew/drc/drc_rule_parser.cpp | 73 +- pcbnew/drc/drc_rule_parser.h | 2 +- pcbnew/drc/drc_test_provider.cpp | 12 +- pcbnew/drc/drc_test_provider.h | 4 +- .../drc/drc_test_provider_matched_length.cpp | 125 +- pcbnew/generators/pcb_tuning_pattern.cpp | 395 +- pcbnew/length_calculation.h | 288 -- .../length_delay_calculation.cpp} | 238 +- .../length_delay_calculation.h | 266 ++ .../length_delay_calculation_item.cpp | 55 + .../length_delay_calculation_item.h | 158 + .../time_domain_parameters_iface.h | 126 + .../time_domain_parameters_user_defined.cpp | 190 + .../time_domain_parameters_user_defined.h | 145 + pcbnew/netinfo_item.cpp | 39 +- pcbnew/pad.cpp | 8 + pcbnew/pad.h | 6 +- pcbnew/pcb_edit_frame.cpp | 2 + .../pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp | 5 + .../pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h | 3 +- .../kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp | 5 + pcbnew/pcb_track.cpp | 72 +- pcbnew/pcb_track.h | 9 +- pcbnew/pcbexpr_evaluator.cpp | 28 +- pcbnew/pcbexpr_evaluator.h | 4 + pcbnew/router/pns_dp_meander_placer.cpp | 126 +- pcbnew/router/pns_dp_meander_placer.h | 19 +- pcbnew/router/pns_kicad_iface.cpp | 133 +- pcbnew/router/pns_kicad_iface.h | 13 +- pcbnew/router/pns_meander.cpp | 75 +- pcbnew/router/pns_meander.h | 24 +- pcbnew/router/pns_meander_placer.cpp | 87 +- pcbnew/router/pns_meander_placer.h | 18 +- pcbnew/router/pns_meander_placer_base.cpp | 50 +- pcbnew/router/pns_meander_placer_base.h | 16 +- pcbnew/router/pns_meander_skew_placer.cpp | 99 +- pcbnew/router/pns_meander_skew_placer.h | 18 +- pcbnew/router/pns_node.h | 1 + pcbnew/router/pns_router.h | 9 +- pcbnew/router/pns_solid.h | 11 +- pcbnew/router/pns_topology.cpp | 2 +- pcbnew/widgets/pcb_net_inspector_panel.cpp | 82 +- pcbnew/widgets/pcb_net_inspector_panel.h | 3 + .../pcb_net_inspector_panel_data_model.h | 231 +- qa/data/config/9.99/kicad_common.json | 4 +- qa/data/pcbnew/time_calculations.kicad_dru | 36 + qa/data/pcbnew/time_calculations.kicad_pcb | 3882 +++++++++++++++++ qa/data/pcbnew/time_calculations.kicad_pro | 931 ++++ qa/data/pcbnew/time_calculations.kicad_sch | 1624 +++++++ qa/pcbnew_utils/board_test_utils.cpp | 1 + qa/tests/pcbnew/drc/test_drc_lengths.cpp | 3 +- qa/tools/pns/pns_log_viewer_frame.h | 127 +- 113 files changed, 13444 insertions(+), 1101 deletions(-) create mode 100644 common/project/time_domain_parameters.cpp create mode 100644 include/project/time_domain_parameters.h create mode 100644 pcbnew/dialogs/panel_setup_time_domain_parameters.cpp create mode 100644 pcbnew/dialogs/panel_setup_time_domain_parameters.h create mode 100644 pcbnew/dialogs/panel_setup_time_domain_parameters_base.cpp create mode 100644 pcbnew/dialogs/panel_setup_time_domain_parameters_base.fbp create mode 100644 pcbnew/dialogs/panel_setup_time_domain_parameters_base.h delete mode 100644 pcbnew/length_calculation.h rename pcbnew/{length_calculation.cpp => length_delay_calculation/length_delay_calculation.cpp} (60%) create mode 100644 pcbnew/length_delay_calculation/length_delay_calculation.h create mode 100644 pcbnew/length_delay_calculation/length_delay_calculation_item.cpp create mode 100644 pcbnew/length_delay_calculation/length_delay_calculation_item.h create mode 100644 pcbnew/length_delay_calculation/time_domain_parameters_iface.h create mode 100644 pcbnew/length_delay_calculation/time_domain_parameters_user_defined.cpp create mode 100644 pcbnew/length_delay_calculation/time_domain_parameters_user_defined.h create mode 100644 qa/data/pcbnew/time_calculations.kicad_dru create mode 100644 qa/data/pcbnew/time_calculations.kicad_pcb create mode 100644 qa/data/pcbnew/time_calculations.kicad_pro create mode 100644 qa/data/pcbnew/time_calculations.kicad_sch diff --git a/api/proto/common/types/project_settings.proto b/api/proto/common/types/project_settings.proto index 5af1320464..b96ad35ff7 100644 --- a/api/proto/common/types/project_settings.proto +++ b/api/proto/common/types/project_settings.proto @@ -49,6 +49,9 @@ message NetClassBoardSettings optional kiapi.board.types.PadStack microvia_stack = 7; optional kiapi.common.types.Color color = 8; + + // Since: 10.0.0 + optional string tuning_profile = 9; } message NetClassSchematicSettings diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 93fc778dcc..a7e63c1d96 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -118,6 +118,7 @@ set( KICOMMON_SRCS project/project_archiver.cpp project/project_file.cpp project/project_local_settings.cpp + project/time_domain_parameters.cpp # This is basically a settings object, but for the toolbar tool/ui/toolbar_configuration.cpp @@ -864,7 +865,9 @@ set( PCB_COMMON_SRCS ${CMAKE_SOURCE_DIR}/pcbnew/tools/pcb_editor_conditions.cpp ${CMAKE_SOURCE_DIR}/pcbnew/tools/pcb_viewer_tools.cpp - ${CMAKE_SOURCE_DIR}/pcbnew/length_calculation.cpp + ${CMAKE_SOURCE_DIR}/pcbnew/length_delay_calculation/length_delay_calculation.cpp + ${CMAKE_SOURCE_DIR}/pcbnew/length_delay_calculation/length_delay_calculation_item.cpp + ${CMAKE_SOURCE_DIR}/pcbnew/length_delay_calculation/time_domain_parameters_user_defined.cpp widgets/net_selector.cpp ) diff --git a/common/dialogs/panel_setup_netclasses.cpp b/common/dialogs/panel_setup_netclasses.cpp index 6ec366717e..42abae6f7e 100644 --- a/common/dialogs/panel_setup_netclasses.cpp +++ b/common/dialogs/panel_setup_netclasses.cpp @@ -61,6 +61,7 @@ enum GRID_uVIADRILL, GRID_DIFF_PAIR_WIDTH, GRID_DIFF_PAIR_GAP, + GRID_TUNING_PROFILE, GRID_PCB_COLOR, GRID_FIRST_EESCHEMA, @@ -297,6 +298,7 @@ void PANEL_SETUP_NETCLASSES::loadNetclasses() [&]( int aRow, const NETCLASS* nc ) { m_netclassGrid->SetCellValue( aRow, GRID_NAME, nc->GetName() ); + m_netclassGrid->SetCellValue( aRow, GRID_TUNING_PROFILE, nc->GetTuningProfile() ); m_netclassGrid->SetOptionalUnitValue( aRow, GRID_WIREWIDTH, nc->GetWireWidthOpt() ); @@ -502,6 +504,7 @@ bool PANEL_SETUP_NETCLASSES::TransferDataFromWindow() nc->SetPriority( aRow ); nc->SetName( m_netclassGrid->GetCellValue( aRow, GRID_NAME ) ); + nc->SetTuningProfile( m_netclassGrid->GetCellValue( aRow, GRID_TUNING_PROFILE ) ); nc->SetWireWidth( m_netclassGrid->GetOptionalUnitValue( aRow, GRID_WIREWIDTH ) ); nc->SetBusWidth( m_netclassGrid->GetOptionalUnitValue( aRow, GRID_BUSWIDTH ) ); @@ -1100,3 +1103,19 @@ void PANEL_SETUP_NETCLASSES::OnMoveNetclassDownClick( wxCommandEvent& event ) m_netclassesDirty = true; } + + +void PANEL_SETUP_NETCLASSES::UpdateTuningProfileNames( const std::vector& aNames ) const +{ + wxArrayString profileNames; + profileNames.push_back( wxEmptyString ); + std::ranges::for_each( aNames, + [&]( const wxString& aName ) + { + profileNames.push_back( aName ); + } ); + + wxGridCellAttr* attr = new wxGridCellAttr; + attr->SetEditor( new wxGridCellChoiceEditor( profileNames, false ) ); + m_netclassGrid->SetColAttr( GRID_TUNING_PROFILE, attr ); +} diff --git a/common/dialogs/panel_setup_netclasses_base.cpp b/common/dialogs/panel_setup_netclasses_base.cpp index 060161b311..cec53b63fa 100644 --- a/common/dialogs/panel_setup_netclasses_base.cpp +++ b/common/dialogs/panel_setup_netclasses_base.cpp @@ -39,7 +39,7 @@ PANEL_SETUP_NETCLASSES_BASE::PANEL_SETUP_NETCLASSES_BASE( wxWindow* parent, wxWi m_netclassGrid = new WX_GRID( m_netclassesPane, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL ); // Grid - m_netclassGrid->CreateGrid( 3, 14 ); + m_netclassGrid->CreateGrid( 3, 15 ); m_netclassGrid->EnableEditing( true ); m_netclassGrid->EnableGridLines( true ); m_netclassGrid->EnableDragGridSize( false ); @@ -57,11 +57,12 @@ PANEL_SETUP_NETCLASSES_BASE::PANEL_SETUP_NETCLASSES_BASE( wxWindow* parent, wxWi m_netclassGrid->SetColLabelValue( 6, _("uVia Hole") ); m_netclassGrid->SetColLabelValue( 7, _("DP Width") ); m_netclassGrid->SetColLabelValue( 8, _("DP Gap") ); - m_netclassGrid->SetColLabelValue( 9, _("PCB Color") ); - m_netclassGrid->SetColLabelValue( 10, _("Wire Thickness") ); - m_netclassGrid->SetColLabelValue( 11, _("Bus Thickness") ); - m_netclassGrid->SetColLabelValue( 12, _("Color") ); - m_netclassGrid->SetColLabelValue( 13, _("Line Style") ); + m_netclassGrid->SetColLabelValue( 9, _("Delay Profile") ); + m_netclassGrid->SetColLabelValue( 10, _("PCB Color") ); + m_netclassGrid->SetColLabelValue( 11, _("Wire Thickness") ); + m_netclassGrid->SetColLabelValue( 12, _("Bus Thickness") ); + m_netclassGrid->SetColLabelValue( 13, _("Color") ); + m_netclassGrid->SetColLabelValue( 14, _("Line Style") ); m_netclassGrid->SetColLabelSize( wxGRID_AUTOSIZE ); m_netclassGrid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER ); diff --git a/common/dialogs/panel_setup_netclasses_base.fbp b/common/dialogs/panel_setup_netclasses_base.fbp index 5a4f471984..dcb7572639 100644 --- a/common/dialogs/panel_setup_netclasses_base.fbp +++ b/common/dialogs/panel_setup_netclasses_base.fbp @@ -290,9 +290,9 @@ 1 wxALIGN_CENTER wxGRID_AUTOSIZE - "Name" "Clearance" "Track Width" "Via Size" "Via Hole" "uVia Size" "uVia Hole" "DP Width" "DP Gap" "PCB Color" "Wire Thickness" "Bus Thickness" "Color" "Line Style" + "Name" "Clearance" "Track Width" "Via Size" "Via Hole" "uVia Size" "uVia Hole" "DP Width" "DP Gap" "Delay Profile" "PCB Color" "Wire Thickness" "Bus Thickness" "Color" "Line Style" wxALIGN_CENTER - 14 + 15 1 diff --git a/common/eda_units.cpp b/common/eda_units.cpp index cdc61fc335..4add82e714 100644 --- a/common/eda_units.cpp +++ b/common/eda_units.cpp @@ -117,6 +117,23 @@ bool EDA_UNIT_UTILS::FetchUnitsFromString( const wxString& aTextValue, EDA_UNITS aUnits = EDA_UNITS::INCH; else if( unit == wxT( "de" ) || unit == wxT( "ra" ) ) // "deg" or "rad" aUnits = EDA_UNITS::DEGREES; + else if( unit == wxT("fs" ) ) + aUnits = EDA_UNITS::FS; + else if( unit == wxT( "ps" ) ) + { + wxString timeUnit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 5 ).Lower() ); + + if( timeUnit == wxT( "ps" ) ) + aUnits = EDA_UNITS::PS; + else if( timeUnit == wxT( "ps/in" ) ) + aUnits = EDA_UNITS::PS_PER_INCH; + else if( timeUnit == wxT( "ps/cm" ) ) + aUnits = EDA_UNITS::PS_PER_CM; + else if( timeUnit == wxT( "ps/mm" ) ) + aUnits = EDA_UNITS::PS_PER_MM; + else + return false; + } else return false; @@ -130,15 +147,20 @@ wxString EDA_UNIT_UTILS::GetText( EDA_UNITS aUnits, EDA_DATA_TYPE aType ) switch( aUnits ) { - case EDA_UNITS::UM: label = wxT( " \u00B5m" ); break; //00B5 for µ - case EDA_UNITS::MM: label = wxT( " mm" ); break; - case EDA_UNITS::CM: label = wxT( " cm" ); break; - case EDA_UNITS::DEGREES: label = wxT( "°" ); break; - case EDA_UNITS::MILS: label = wxT( " mils" ); break; - case EDA_UNITS::INCH: label = wxT( " in" ); break; - case EDA_UNITS::PERCENT: label = wxT( "%" ); break; - case EDA_UNITS::UNSCALED: break; - default: UNIMPLEMENTED_FOR( wxS( "Unknown units" ) ); break; + case EDA_UNITS::UM: label = wxT( " \u00B5m" ); break; //00B5 for µ + case EDA_UNITS::MM: label = wxT( " mm" ); break; + case EDA_UNITS::CM: label = wxT( " cm" ); break; + case EDA_UNITS::DEGREES: label = wxT( "°" ); break; + case EDA_UNITS::MILS: label = wxT( " mils" ); break; + case EDA_UNITS::INCH: label = wxT( " in" ); break; + case EDA_UNITS::PERCENT: label = wxT( "%" ); break; + case EDA_UNITS::FS: label = wxT( " fs" ); break; + case EDA_UNITS::PS: label = wxT( " ps" ); break; + case EDA_UNITS::PS_PER_INCH: label = wxT( " ps/in" ); break; + case EDA_UNITS::PS_PER_CM: label = wxT( " ps/cm"); break; + case EDA_UNITS::PS_PER_MM: label = wxT( " ps/mm"); break; + case EDA_UNITS::UNSCALED: break; + default: UNIMPLEMENTED_FOR( wxS( "Unknown units" ) ); break; } switch( aType ) @@ -146,6 +168,8 @@ wxString EDA_UNIT_UTILS::GetText( EDA_UNITS aUnits, EDA_DATA_TYPE aType ) case EDA_DATA_TYPE::VOLUME: label += wxT( "³" ); break; case EDA_DATA_TYPE::AREA: label += wxT( "²" ); break; case EDA_DATA_TYPE::DISTANCE: break; + case EDA_DATA_TYPE::TIME: break; + case EDA_DATA_TYPE::LENGTH_DELAY: break; default: UNIMPLEMENTED_FOR( wxS( "Unknown measurement" ) ); break; } @@ -253,9 +277,13 @@ bool EDA_UNIT_UTILS::ParseInternalUnits( const std::string& aInput, const EDA_IU #define IU_TO_MM( x, scale ) ( x / scale.IU_PER_MM ) #define IU_TO_IN( x, scale ) ( x / scale.IU_PER_MILS / 1000 ) #define IU_TO_MILS( x, scale ) ( x / scale.IU_PER_MILS ) +#define IU_TO_PS( x, scale ) ( x / scale.IU_PER_PS ) +#define IU_TO_PS_PER_MM( x, scale ) ( x / scale.IU_PER_PS_PER_MM ) #define MM_TO_IU( x, scale ) ( x * scale.IU_PER_MM ) #define IN_TO_IU( x, scale ) ( x * scale.IU_PER_MILS * 1000 ) #define MILS_TO_IU( x, scale ) ( x * scale.IU_PER_MILS ) +#define PS_TO_IU( x, scale ) ( x * scale.IU_PER_PS ) +#define PS_PER_MM_TO_IU( x, scale ) ( x * scale.IU_PER_PS_PER_MM ) double EDA_UNIT_UTILS::UI::ToUserUnit( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnit, @@ -263,13 +291,18 @@ double EDA_UNIT_UTILS::UI::ToUserUnit( const EDA_IU_SCALE& aIuScale, EDA_UNITS a { switch( aUnit ) { - case EDA_UNITS::UM: return IU_TO_MM( aValue, aIuScale ) * 1000; - case EDA_UNITS::MM: return IU_TO_MM( aValue, aIuScale ); - case EDA_UNITS::CM: return IU_TO_MM( aValue, aIuScale ) / 10; - case EDA_UNITS::MILS: return IU_TO_MILS( aValue, aIuScale ); - case EDA_UNITS::INCH: return IU_TO_IN( aValue, aIuScale ); - case EDA_UNITS::DEGREES: return aValue; - default: return aValue; + case EDA_UNITS::UM: return IU_TO_MM( aValue, aIuScale ) * 1000; + case EDA_UNITS::MM: return IU_TO_MM( aValue, aIuScale ); + case EDA_UNITS::CM: return IU_TO_MM( aValue, aIuScale ) / 10; + case EDA_UNITS::MILS: return IU_TO_MILS( aValue, aIuScale ); + case EDA_UNITS::INCH: return IU_TO_IN( aValue, aIuScale ); + case EDA_UNITS::DEGREES: return aValue; + case EDA_UNITS::FS: return IU_TO_PS( aValue, aIuScale ) * 1000.0; + case EDA_UNITS::PS: return IU_TO_PS( aValue, aIuScale ); + case EDA_UNITS::PS_PER_INCH: return IU_TO_PS_PER_MM( aValue, aIuScale ) * 25.4; + case EDA_UNITS::PS_PER_CM: return IU_TO_PS_PER_MM( aValue, aIuScale ) * 10; + case EDA_UNITS::PS_PER_MM: return IU_TO_PS_PER_MM( aValue, aIuScale ); + default: return aValue; } } @@ -297,6 +330,14 @@ wxString EDA_UNIT_UTILS::UI::StringFromValue( const EDA_IU_SCALE& aIuScale, EDA_ case EDA_DATA_TYPE::UNITLESS: break; + + case EDA_DATA_TYPE::TIME: + value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print ); + break; + + case EDA_DATA_TYPE::LENGTH_DELAY: + value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print ); + break; } const wxChar* format = nullptr; @@ -304,10 +345,13 @@ wxString EDA_UNIT_UTILS::UI::StringFromValue( const EDA_IU_SCALE& aIuScale, EDA_ switch( aUnits ) { - case EDA_UNITS::MILS: format = is_eeschema ? wxT( "%.3f" ) : wxT( "%.5f" ); break; - case EDA_UNITS::INCH: format = is_eeschema ? wxT( "%.6f" ) : wxT( "%.8f" ); break; - case EDA_UNITS::DEGREES: format = wxT( "%.4f" ); break; - default: format = wxT( "%.10f" ); break; + case EDA_UNITS::MILS: format = is_eeschema ? wxT( "%.3f" ) : wxT( "%.5f" ); break; + case EDA_UNITS::INCH: format = is_eeschema ? wxT( "%.6f" ) : wxT( "%.8f" ); break; + case EDA_UNITS::DEGREES: format = wxT( "%.4f" ); break; + case EDA_UNITS::PS_PER_INCH: format = wxT( "%.4f" ); break; + case EDA_UNITS::PS_PER_CM: format = wxT( "%.3f" ); break; + case EDA_UNITS::PS_PER_MM: format = wxT( "%.3f" ); break; + default: format = wxT( "%.10f" ); break; } wxString text; @@ -385,18 +429,31 @@ wxString EDA_UNIT_UTILS::UI::MessageTextFromValue( const EDA_IU_SCALE& aIuScale, case EDA_DATA_TYPE::UNITLESS: break; + + case EDA_DATA_TYPE::TIME: + value = ToUserUnit( aIuScale, aUnits, value ); + break; + + case EDA_DATA_TYPE::LENGTH_DELAY: + value = ToUserUnit( aIuScale, aUnits, value ); + break; } switch( aUnits ) { default: - case EDA_UNITS::UM: format = is_eeschema ? wxT( "%.0f" ) : wxT( "%.1f" ); break; - case EDA_UNITS::MM: format = is_eeschema ? wxT( "%.2f" ) : wxT( "%.4f" ); break; - case EDA_UNITS::CM: format = is_eeschema ? wxT( "%.3f" ) : wxT( "%.5f" ); break; - case EDA_UNITS::MILS: format = is_eeschema ? wxT( "%.0f" ) : wxT( "%.2f" ); break; - case EDA_UNITS::INCH: format = is_eeschema ? wxT( "%.3f" ) : wxT( "%.4f" ); break; - case EDA_UNITS::DEGREES: format = wxT( "%.3f" ); break; - case EDA_UNITS::UNSCALED: format = wxT( "%.0f" ); break; + case EDA_UNITS::UM: format = is_eeschema ? wxT( "%.0f" ) : wxT( "%.1f" ); break; + case EDA_UNITS::MM: format = is_eeschema ? wxT( "%.2f" ) : wxT( "%.4f" ); break; + case EDA_UNITS::CM: format = is_eeschema ? wxT( "%.3f" ) : wxT( "%.5f" ); break; + case EDA_UNITS::MILS: format = is_eeschema ? wxT( "%.0f" ) : wxT( "%.2f" ); break; + case EDA_UNITS::INCH: format = is_eeschema ? wxT( "%.3f" ) : wxT( "%.4f" ); break; + case EDA_UNITS::DEGREES: format = wxT( "%.3f" ); break; + case EDA_UNITS::UNSCALED: format = wxT( "%.0f" ); break; + case EDA_UNITS::FS: format = wxT( "%.4f" ); break; + case EDA_UNITS::PS: format = wxT( "%.2f" ); break; + case EDA_UNITS::PS_PER_INCH: format = wxT( "%.2f" ); break; + case EDA_UNITS::PS_PER_CM: format = wxT( "%.2f" ); break; + case EDA_UNITS::PS_PER_MM: format = wxT( "%.2f" ); break; } text.Printf( format, value ); @@ -444,15 +501,20 @@ double EDA_UNIT_UTILS::UI::FromUserUnit( const EDA_IU_SCALE& aIuScale, EDA_UNITS { switch( aUnits ) { - case EDA_UNITS::UM: return MM_TO_IU( aValue / 1000.0, aIuScale ); - case EDA_UNITS::MM: return MM_TO_IU( aValue, aIuScale ); - case EDA_UNITS::CM: return MM_TO_IU( aValue * 10, aIuScale ); - case EDA_UNITS::MILS: return MILS_TO_IU( aValue, aIuScale ); - case EDA_UNITS::INCH: return IN_TO_IU( aValue, aIuScale ); + case EDA_UNITS::UM: return MM_TO_IU( aValue / 1000.0, aIuScale ); + case EDA_UNITS::MM: return MM_TO_IU( aValue, aIuScale ); + case EDA_UNITS::CM: return MM_TO_IU( aValue * 10, aIuScale ); + case EDA_UNITS::MILS: return MILS_TO_IU( aValue, aIuScale ); + case EDA_UNITS::INCH: return IN_TO_IU( aValue, aIuScale ); + case EDA_UNITS::FS: return PS_TO_IU( aValue / 1000.0, aIuScale ); + case EDA_UNITS::PS: return PS_TO_IU( aValue, aIuScale ); + case EDA_UNITS::PS_PER_INCH: return PS_PER_MM_TO_IU( aValue / 25.4, aIuScale ); + case EDA_UNITS::PS_PER_CM: return PS_PER_MM_TO_IU( aValue / 10, aIuScale ); + case EDA_UNITS::PS_PER_MM: return PS_PER_MM_TO_IU( aValue, aIuScale ); default: case EDA_UNITS::DEGREES: case EDA_UNITS::UNSCALED: - case EDA_UNITS::PERCENT: return aValue; + case EDA_UNITS::PERCENT: return aValue; } } @@ -566,6 +628,23 @@ double EDA_UNIT_UTILS::UI::DoubleValueFromString( const EDA_IU_SCALE& aIuScale, if( unit == wxT( "ra" ) ) // Radians dtmp *= 180.0f / M_PI; } + else if( aUnits == EDA_UNITS::FS || aUnits == EDA_UNITS::PS || aUnits == EDA_UNITS::PS_PER_INCH + || aUnits == EDA_UNITS::PS_PER_CM || aUnits == EDA_UNITS::PS_PER_MM ) + + { + wxString timeUnit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 5 ).Lower() ); + + if( timeUnit == wxT( "fs" ) ) + aUnits = EDA_UNITS::FS; + if( timeUnit == wxT( "ps" ) ) + aUnits = EDA_UNITS::PS; + else if( timeUnit == wxT( "ps/in" ) ) + aUnits = EDA_UNITS::PS_PER_INCH; + else if( timeUnit == wxT( "ps/cm" ) ) + aUnits = EDA_UNITS::PS_PER_CM; + else if( timeUnit == wxT( "ps/mm" ) ) + aUnits = EDA_UNITS::PS_PER_MM; + } switch( aType ) { @@ -583,6 +662,14 @@ double EDA_UNIT_UTILS::UI::DoubleValueFromString( const EDA_IU_SCALE& aIuScale, case EDA_DATA_TYPE::UNITLESS: break; + + case EDA_DATA_TYPE::TIME: + dtmp = FromUserUnit( aIuScale, aUnits, dtmp ); + break; + + case EDA_DATA_TYPE::LENGTH_DELAY: + dtmp = FromUserUnit( aIuScale, aUnits, dtmp ); + break; } return dtmp; diff --git a/common/libeval/numeric_evaluator.cpp b/common/libeval/numeric_evaluator.cpp index a780d91334..34699670a4 100644 --- a/common/libeval/numeric_evaluator.cpp +++ b/common/libeval/numeric_evaluator.cpp @@ -82,12 +82,17 @@ void NUMERIC_EVALUATOR::SetDefaultUnits( EDA_UNITS aUnits ) { switch( aUnits ) { - case EDA_UNITS::MM: m_defaultUnits = Unit::MM; break; - case EDA_UNITS::MILS: m_defaultUnits = Unit::Mil; break; - case EDA_UNITS::INCH: m_defaultUnits = Unit::Inch; break; - case EDA_UNITS::DEGREES: m_defaultUnits = Unit::Degrees; break; - case EDA_UNITS::UNSCALED: m_defaultUnits = Unit::SI; break; - default: m_defaultUnits = Unit::MM; break; + case EDA_UNITS::MM: m_defaultUnits = Unit::MM; break; + case EDA_UNITS::MILS: m_defaultUnits = Unit::Mil; break; + case EDA_UNITS::INCH: m_defaultUnits = Unit::Inch; break; + case EDA_UNITS::DEGREES: m_defaultUnits = Unit::Degrees; break; + case EDA_UNITS::FS: m_defaultUnits = Unit::Femtoseconds; break; + case EDA_UNITS::PS: m_defaultUnits = Unit::Picoseconds; break; + case EDA_UNITS::PS_PER_INCH: m_defaultUnits = Unit::PsPerInch; break; + case EDA_UNITS::PS_PER_CM: m_defaultUnits = Unit::PsPerCm; break; + case EDA_UNITS::PS_PER_MM: m_defaultUnits = Unit::PsPerMm; break; + case EDA_UNITS::UNSCALED: m_defaultUnits = Unit::SI; break; + default: m_defaultUnits = Unit::MM; break; } } @@ -282,7 +287,7 @@ NUMERIC_EVALUATOR::Token NUMERIC_EVALUATOR::getToken() }; // Lamda: Get unit for current token. - // Valid units are ", in, um, cm, mm, mil and thou. Returns Unit::Invalid otherwise. + // Valid units are ", in, um, cm, mm, mil, ps and thou. Returns Unit::Invalid otherwise. auto checkUnit = [&]( double* siScaler ) -> Unit { @@ -315,6 +320,39 @@ NUMERIC_EVALUATOR::Token NUMERIC_EVALUATOR::getToken() return Unit::UM; } + if( sizeLeft >= 5 && ch == 'p' && cptr[1] == 's' && cptr[2] == '/' && cptr[3] == 'i' + && cptr[4] == 'n' && !isalnum( cptr[5] ) ) + { + m_token.pos += 5; + return Unit::PsPerInch; + } + + if( sizeLeft >= 5 && ch == 'p' && cptr[1] == 's' && cptr[2] == '/' && cptr[3] == 'c' + && cptr[4] == 'm' && !isalnum( cptr[5] ) ) + { + m_token.pos += 5; + return Unit::PsPerCm; + } + + if( sizeLeft >= 5 && ch == 'p' && cptr[1] == 's' && cptr[2] == '/' && cptr[3] == 'm' + && cptr[4] == 'm' && !isalnum( cptr[5] ) ) + { + m_token.pos += 5; + return Unit::PsPerMm; + } + + if( sizeLeft >= 2 && ch == 'f' && cptr[1] == 's' && !isalnum( cptr[2] ) ) + { + m_token.pos += 2; + return Unit::Femtoseconds; + } + + if( sizeLeft >= 2 && ch == 'p' && cptr[1] == 's' && !isalnum( cptr[2] ) ) + { + m_token.pos += 2; + return Unit::Picoseconds; + } + if( sizeLeft >= 2 && ch == 'm' && cptr[ 1 ] == 'm' && !isalnum( cptr[ 2 ] ) ) { m_token.pos += 2; @@ -443,6 +481,59 @@ NUMERIC_EVALUATOR::Token NUMERIC_EVALUATOR::getToken() { retval.value.dValue = siScaler; } + else if( m_defaultUnits == Unit::Picoseconds ) + { + switch( convertFrom ) + { + case Unit::Picoseconds: retval.value.dValue = 1.0; break; + case Unit::Femtoseconds: retval.value.dValue = 1.0 / 1000.0; break; + default: + case Unit::Invalid: break; + } + } + else if( m_defaultUnits == Unit::Femtoseconds ) + { + switch( convertFrom ) + { + case Unit::Picoseconds: retval.value.dValue = 1000.0; break; + case Unit::Femtoseconds: retval.value.dValue = 1.0; break; + default: + case Unit::Invalid: break; + } + } + else if( m_defaultUnits == Unit::PsPerInch ) + { + switch( convertFrom ) + { + case Unit::PsPerInch: retval.value.dValue = 1.0; break; + case Unit::PsPerCm: retval.value.dValue = 2.54; break; + case Unit::PsPerMm: retval.value.dValue = 25.4; break; + default: + case Unit::Invalid: break; + } + } + else if( m_defaultUnits == Unit::PsPerCm ) + { + switch( convertFrom ) + { + case Unit::PsPerInch: retval.value.dValue = 1.0 / 2.54; break; + case Unit::PsPerCm: retval.value.dValue = 1.0; break; + case Unit::PsPerMm: retval.value.dValue = 10.0; break; + default: + case Unit::Invalid: break; + } + } + else if( m_defaultUnits == Unit::PsPerMm ) + { + switch( convertFrom ) + { + case Unit::PsPerInch: retval.value.dValue = 1.0 / 25.4; break; + case Unit::PsPerCm: retval.value.dValue = 1.0 / 10.0; break; + case Unit::PsPerMm: retval.value.dValue = 1.0; break; + default: + case Unit::Invalid: break; + } + } } else if( isalpha( ch ) ) { diff --git a/common/libeval_compiler/libeval_compiler.cpp b/common/libeval_compiler/libeval_compiler.cpp index 7d6adbabbe..a6027318bd 100644 --- a/common/libeval_compiler/libeval_compiler.cpp +++ b/common/libeval_compiler/libeval_compiler.cpp @@ -719,11 +719,12 @@ void COMPILER::freeTree( LIBEVAL::TREE_NODE *tree ) } -void TREE_NODE::SetUop( int aOp, double aValue ) +void TREE_NODE::SetUop( int aOp, double aValue, EDA_UNITS aUnits ) { delete uop; std::unique_ptr val = std::make_unique( aValue ); + val->SetUnits( aUnits ); uop = new UOP( aOp, std::move( val ) ); } @@ -872,7 +873,7 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext ) node->leaf[0]->isVisited = true; node->leaf[1]->isVisited = true; - node->SetUop( TR_UOP_PUSH_VALUE, 0.0 ); + node->SetUop( TR_UOP_PUSH_VALUE, 0.0, EDA_UNITS::UNSCALED ); node->isTerminal = true; break; } @@ -1005,7 +1006,7 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext ) node->leaf[0]->isVisited = true; node->leaf[1]->isVisited = true; - node->SetUop( TR_UOP_PUSH_VALUE, 0.0 ); + node->SetUop( TR_UOP_PUSH_VALUE, 0.0, EDA_UNITS::UNSCALED ); node->isTerminal = true; break; } @@ -1017,6 +1018,7 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext ) { TREE_NODE* son = node->leaf[0]; double value; + EDA_UNITS unitsType = EDA_UNITS::UNSCALED; if( !node->value.str ) { @@ -1031,6 +1033,7 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext ) } int units = son->value.idx; + unitsType = m_unitResolver->GetSupportedUnitsTypes().at( units ); value = m_unitResolver->Convert( formatNode( node ), units ); son->isVisited = true; } @@ -1047,7 +1050,7 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext ) value = EDA_UNIT_UTILS::UI::DoubleValueFromString( formatNode( node ) ); } - node->SetUop( TR_UOP_PUSH_VALUE, value ); + node->SetUop( TR_UOP_PUSH_VALUE, value, unitsType ); node->isTerminal = true; break; } @@ -1170,19 +1173,45 @@ void UOP::Exec( CONTEXT* ctx ) } } + // TODO: This doesn't fully calculate units correctly yet. We really need to work out the dimensional analysis + // TODO: (and do this independently of unit specifics - e.g. MM + INCH needs to return one of the dimension + // TODO: types, but our units framework doesn't currently allow this. Therefore, use some heuristics to + // TODO: determine the resulting operation unit type for now + auto getOpResultUnits = []( const VALUE* aVal1, const VALUE* aVal2 ) + { + // This condition can occur in, e.g., a unary negation operation + if( aVal1->GetUnits() == EDA_UNITS::UNSCALED && aVal2->GetUnits() != EDA_UNITS::UNSCALED ) + { + return aVal2->GetUnits(); + } + + if( aVal1->GetUnits() != EDA_UNITS::UNSCALED && aVal2->GetUnits() == EDA_UNITS::UNSCALED ) + { + return aVal1->GetUnits(); + } + + return aVal2->GetUnits(); + }; + + EDA_UNITS resultUnits = EDA_UNITS::UNSCALED; + switch( m_op ) { case TR_OP_ADD: result = AS_DOUBLE( arg1 ) + AS_DOUBLE( arg2 ); + resultUnits = getOpResultUnits( arg1, arg2 ); break; case TR_OP_SUB: result = AS_DOUBLE( arg1 ) - AS_DOUBLE( arg2 ); + resultUnits = getOpResultUnits( arg1, arg2 ); break; case TR_OP_MUL: result = AS_DOUBLE( arg1 ) * AS_DOUBLE( arg2 ); + resultUnits = getOpResultUnits( arg1, arg2 ); break; case TR_OP_DIV: result = AS_DOUBLE( arg1 ) / AS_DOUBLE( arg2 ); + resultUnits = getOpResultUnits( arg1, arg2 ); break; case TR_OP_LESS_EQUAL: result = AS_DOUBLE( arg1 ) <= AS_DOUBLE( arg2 ) ? 1 : 0; @@ -1225,6 +1254,7 @@ void UOP::Exec( CONTEXT* ctx ) auto rp = ctx->AllocValue(); rp->Set( result ); + rp->SetUnits( resultUnits ); ctx->Push( rp ); return; } @@ -1246,6 +1276,7 @@ void UOP::Exec( CONTEXT* ctx ) auto rp = ctx->AllocValue(); rp->Set( result ); + rp->SetUnits( arg1->GetUnits() ); ctx->Push( rp ); return; } diff --git a/common/netclass.cpp b/common/netclass.cpp index c35a12e9c5..8ac5bef80b 100644 --- a/common/netclass.cpp +++ b/common/netclass.cpp @@ -59,6 +59,7 @@ NETCLASS::NETCLASS( const wxString& aName, bool aInitWithDefaults ) : m_isDefaul SetName( aName ); SetPriority( -1 ); + SetTuningProfile( wxEmptyString ); // Colors are a special optional case - always set, but UNSPECIFIED used in place of optional SetPcbColor( COLOR4D::UNSPECIFIED ); @@ -101,6 +102,7 @@ void NETCLASS::ResetParents() SetBusWidthParent( this ); SetSchematicColorParent( this ); SetLineStyleParent( this ); + SetTuningProfileParent( this ); } @@ -178,6 +180,9 @@ void NETCLASS::Serialize( google::protobuf::Any &aContainer ) const if( m_pcbColor != COLOR4D::UNSPECIFIED ) PackColor( *board->mutable_color(), m_pcbColor ); + if( HasTuningProfile() ) + board->set_tuning_profile( m_TuningProfile ); + project::NetClassSchematicSettings* schematic = nc.mutable_schematic(); if( m_wireWidth ) @@ -244,6 +249,9 @@ bool NETCLASS::Deserialize( const google::protobuf::Any &aContainer ) if( nc.board().has_color() ) m_pcbColor = UnpackColor( nc.board().color() ); + if( nc.board().has_tuning_profile() ) + m_TuningProfile = nc.board().tuning_profile(); + if( nc.schematic().has_wire_width() ) m_wireWidth = nc.schematic().wire_width().value_nm(); diff --git a/common/pcb.keywords b/common/pcb.keywords index 963b4a68f6..ae480c4976 100644 --- a/common/pcb.keywords +++ b/common/pcb.keywords @@ -96,6 +96,7 @@ data date defaults descr +die_delay die_length dielectric_constraints dimension diff --git a/common/preview_items/preview_utils.cpp b/common/preview_items/preview_utils.cpp index 68d32e36b4..93687264a4 100644 --- a/common/preview_items/preview_utils.cpp +++ b/common/preview_items/preview_utils.cpp @@ -45,14 +45,19 @@ wxString KIGFX::PREVIEW::DimensionLabel( const wxString& prefix, double aVal, // nanometre switch( aUnits ) { - case EDA_UNITS::UM: fmtStr = wxT( "%.0f" ); break; // 1um - case EDA_UNITS::MM: fmtStr = wxT( "%.3f" ); break; // 1um - case EDA_UNITS::CM: fmtStr = wxT( "%.4f" ); break; // 1um - case EDA_UNITS::MILS: fmtStr = wxT( "%.1f" ); break; // 0.1mil - case EDA_UNITS::INCH: fmtStr = wxT( "%.4f" ); break; // 0.1mil - case EDA_UNITS::DEGREES: fmtStr = wxT( "%.1f" ); break; // 0.1deg - case EDA_UNITS::PERCENT: fmtStr = wxT( "%.1f" ); break; // 0.1% - case EDA_UNITS::UNSCALED: fmtStr = wxT( "%f" ); break; + case EDA_UNITS::UM: fmtStr = wxT( "%.0f" ); break; // 1um + case EDA_UNITS::MM: fmtStr = wxT( "%.3f" ); break; // 1um + case EDA_UNITS::CM: fmtStr = wxT( "%.4f" ); break; // 1um + case EDA_UNITS::MILS: fmtStr = wxT( "%.1f" ); break; // 0.1mil + case EDA_UNITS::INCH: fmtStr = wxT( "%.4f" ); break; // 0.1mil + case EDA_UNITS::DEGREES: fmtStr = wxT( "%.1f" ); break; // 0.1deg + case EDA_UNITS::PERCENT: fmtStr = wxT( "%.1f" ); break; // 0.1% + case EDA_UNITS::FS: fmtStr = wxT( "%.4f" ); break; // 0.0001ps + case EDA_UNITS::PS: fmtStr = wxT( "%.3f" ); break; // 0.001ps + case EDA_UNITS::PS_PER_INCH: fmtStr = wxT( "%.3f" ); break; // 0.001ps/in + case EDA_UNITS::PS_PER_CM: fmtStr = wxT( "%.3f" ); break; // 0.001ps/cm + case EDA_UNITS::PS_PER_MM: fmtStr = wxT( "%.3f" ); break; // 0.001ps/mm + case EDA_UNITS::UNSCALED: fmtStr = wxT( "%f" ); break; } str << wxString::Format( fmtStr, EDA_UNIT_UTILS::UI::ToUserUnit( aIuScale, aUnits, aVal ) ); diff --git a/common/project/net_settings.cpp b/common/project/net_settings.cpp index 62eb771558..cc5d1966cd 100644 --- a/common/project/net_settings.cpp +++ b/common/project/net_settings.cpp @@ -35,7 +35,8 @@ // const int netSettingsSchemaVersion = 1; // new overbar syntax // const int netSettingsSchemaVersion = 2; // exclude buses from netclass members // const int netSettingsSchemaVersion = 3; // netclass assignment patterns -const int netSettingsSchemaVersion = 4; // netclass ordering +// const int netSettingsSchemaVersion = 4; // netclass ordering +const int netSettingsSchemaVersion = 5; // Tuning profile names static std::optional getInPcbUnits( const nlohmann::json& aObj, const std::string& aKey, @@ -73,7 +74,8 @@ NET_SETTINGS::NET_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) : nlohmann::json nc_json = { { "name", nc->GetName().ToUTF8() }, { "priority", nc->GetPriority() }, { "schematic_color", nc->GetSchematicColor( true ) }, - { "pcb_color", nc->GetPcbColor( true ) } }; + { "pcb_color", nc->GetPcbColor( true ) }, + { "tuning_profile", nc->GetTuningProfile() } }; auto saveInPcbUnits = []( nlohmann::json& json, const std::string& aKey, int aValue ) @@ -131,6 +133,8 @@ NET_SETTINGS::NET_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) : int priority = entry["priority"]; nc->SetPriority( priority ); + nc->SetTuningProfile( entry["tuning_profile"] ); + if( auto value = getInPcbUnits( entry, "clearance" ) ) nc->SetClearance( *value ); @@ -327,6 +331,7 @@ NET_SETTINGS::NET_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) : registerMigration( 1, 2, std::bind( &NET_SETTINGS::migrateSchema1to2, this ) ); registerMigration( 2, 3, std::bind( &NET_SETTINGS::migrateSchema2to3, this ) ); registerMigration( 3, 4, std::bind( &NET_SETTINGS::migrateSchema3to4, this ) ); + registerMigration( 4, 5, std::bind( &NET_SETTINGS::migrateSchema4to5, this ) ); } @@ -466,6 +471,21 @@ bool NET_SETTINGS::migrateSchema3to4() } +bool NET_SETTINGS::migrateSchema4to5() +{ + // Add tuning profile name field to netclasses + if( m_internals->contains( "classes" ) && m_internals->At( "classes" ).is_array() ) + { + const wxString emptyStr = ""; + + for( auto& netClass : m_internals->At( "classes" ).items() ) + netClass.value()["tuning_profile"] = emptyStr.ToUTF8(); + } + + return true; +} + + void NET_SETTINGS::SetDefaultNetclass( std::shared_ptr netclass ) { m_defaultNetClass = netclass; @@ -907,6 +927,12 @@ void NET_SETTINGS::makeEffectiveNetclass( std::shared_ptr& effectiveNe effectiveNetclass->SetSchematicColor( schColor ); effectiveNetclass->SetSchematicColorParent( nc ); } + + if( nc->HasTuningProfile() ) + { + effectiveNetclass->SetTuningProfile( nc->GetTuningProfile() ); + effectiveNetclass->SetTuningProfileParent( nc ); + } } // Fill in any required defaults @@ -997,6 +1023,14 @@ bool NET_SETTINGS::addMissingDefaults( NETCLASS* nc ) const nc->SetBusWidthParent( m_defaultNetClass.get() ); } + // The tuning profile can be empty - only fill if a default tuning profile is set + if( !nc->HasTuningProfile() && m_defaultNetClass->HasTuningProfile() ) + { + addedDefault = true; + nc->SetTuningProfile( m_defaultNetClass->GetTuningProfile() ); + nc->SetTuningProfileParent( m_defaultNetClass.get() ); + } + return addedDefault; } diff --git a/common/project/project_file.cpp b/common/project/project_file.cpp index 2a4d85adee..cc2b6dd12b 100644 --- a/common/project/project_file.cpp +++ b/common/project/project_file.cpp @@ -22,10 +22,13 @@ #include #include #include +#include #include #include +#include #include #include +#include #include #include @@ -36,8 +39,13 @@ const int projectFileSchemaVersion = 3; PROJECT_FILE::PROJECT_FILE( const wxString& aFullPath ) : JSON_SETTINGS( aFullPath, SETTINGS_LOC::PROJECT, projectFileSchemaVersion ), - m_ErcSettings( nullptr ), m_SchematicSettings( nullptr ), m_BoardSettings(), - m_project( nullptr ), m_wasMigrated( false ) + m_ErcSettings( nullptr ), + m_SchematicSettings( nullptr ), + m_BoardSettings(), + m_sheets(), + m_boards(), + m_project( nullptr ), + m_wasMigrated( false ) { // Keep old files around m_deleteLegacyAfterMigration = false; @@ -117,6 +125,9 @@ PROJECT_FILE::PROJECT_FILE( const wxString& aFullPath ) : m_ComponentClassSettings = std::make_shared( this, "component_class_settings" ); + m_timeDomainParameters = + std::make_shared( this, "time_domain_parameters" ); + m_params.emplace_back( new PARAM_LAYER_PRESET( "board.layer_presets", &m_LayerPresets ) ); m_params.emplace_back( new PARAM_VIEWPORT( "board.viewports", &m_Viewports ) ); diff --git a/common/project/project_local_settings.cpp b/common/project/project_local_settings.cpp index 985a1753bb..10ff184553 100644 --- a/common/project/project_local_settings.cpp +++ b/common/project/project_local_settings.cpp @@ -230,6 +230,8 @@ PROJECT_LOCAL_SETTINGS::PROJECT_LOCAL_SETTINGS( PROJECT* aProject, const wxStrin &m_NetInspectorPanel.show_zero_pad_nets, false ) ); m_params.emplace_back( new PARAM( "net_inspector_panel.show_unconnected_nets", &m_NetInspectorPanel.show_unconnected_nets, false ) ); + m_params.emplace_back( new PARAM( "net_inspector_panel.show_time_domain_details", + &m_NetInspectorPanel.show_time_domain_details, false ) ); m_params.emplace_back( new PARAM( "net_inspector_panel.sorting_column", &m_NetInspectorPanel.sorting_column, -1 ) ); m_params.emplace_back( new PARAM( "net_inspector_panel.sort_ascending", diff --git a/common/project/time_domain_parameters.cpp b/common/project/time_domain_parameters.cpp new file mode 100644 index 0000000000..4e981268f2 --- /dev/null +++ b/common/project/time_domain_parameters.cpp @@ -0,0 +1,197 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2020 CERN + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * @author Jon Evans + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include +#include + +#include +#include +#include +#include + + +constexpr int timeDomainParametersSchemaVersion = 0; + +TIME_DOMAIN_PARAMETERS::TIME_DOMAIN_PARAMETERS( JSON_SETTINGS* aParent, const std::string& aPath ) : + NESTED_SETTINGS( "time_domain_parameters", timeDomainParametersSchemaVersion, aParent, + aPath, false ) +{ + auto saveViaOverrideConfigurationLine = + []( nlohmann::json& json_array, const TUNING_PROFILE_VIA_OVERRIDE_ENTRY& item ) + { + const nlohmann::json item_json = { { "signal_layer_from", LSET::Name( item.m_SignalLayerFrom ) }, + { "signal_layer_to", LSET::Name( item.m_SignalLayerTo ) }, + { "via_layer_from", LSET::Name( item.m_ViaLayerFrom ) }, + { "via_layer_to", LSET::Name( item.m_ViaLayerTo ) }, + { "delay", item.m_Delay } }; + + json_array.push_back( item_json ); + }; + + auto readViaOverrideConfigurationLine = []( const nlohmann::json& entry ) + { + wxString signalLayerFromName = entry["signal_layer_from"]; + int signalLayerFromId = LSET::NameToLayer( signalLayerFromName ); + + wxString signalLayerToName = entry["signal_layer_to"]; + int signalLayerToId = LSET::NameToLayer( signalLayerToName ); + + wxString viaLayerFromName = entry["via_layer_from"]; + int viaLayerFromId = LSET::NameToLayer( viaLayerFromName ); + + wxString viaLayerToName = entry["via_layer_to"]; + int viaLayerToId = LSET::NameToLayer( viaLayerToName ); + + int delay = entry["delay"]; + + TUNING_PROFILE_VIA_OVERRIDE_ENTRY item{ static_cast( signalLayerFromId ), + static_cast( signalLayerToId ), + static_cast( viaLayerFromId ), + static_cast( viaLayerToId ), delay }; + + return item; + }; + + auto saveUserDefinedProfileConfigurationLine = + [&saveViaOverrideConfigurationLine]( nlohmann::json& json_array, const TIME_DOMAIN_TUNING_PROFILE& item ) + { + nlohmann::json layer_velocities = nlohmann::json::array(); + + for( const auto& [layerId, velocity] : item.m_LayerPropagationDelays ) + { + nlohmann::json layer_json = { { "layer", LSET::Name( layerId ) }, { "delay", velocity } }; + layer_velocities.push_back( layer_json ); + } + + nlohmann::json via_overrides = nlohmann::json::array(); + + for( const TUNING_PROFILE_VIA_OVERRIDE_ENTRY& viaOverride : item.m_ViaOverrides ) + { + saveViaOverrideConfigurationLine( via_overrides, viaOverride ); + } + + const nlohmann::json item_json = { { "profile_name", item.m_ProfileName.ToUTF8() }, + { "via_prop_delay", item.m_ViaPropagationDelay }, + { "layer_delays", layer_velocities }, + { "via_overrides", via_overrides } }; + + json_array.push_back( item_json ); + }; + + auto readUserDefinedProfileConfigurationLine = [&readViaOverrideConfigurationLine]( const nlohmann::json& entry ) + { + const wxString profileName = entry["profile_name"]; + const int viaPropDelay = entry["via_prop_delay"]; + std::map traceDelays; + + for( const nlohmann::json& layerEntry : entry["layer_delays"] ) + { + if( !layerEntry.is_object() || !layerEntry.contains( "layer" ) ) + continue; + + wxString layerName = layerEntry["layer"]; + int layerId = LSET::NameToLayer( layerName ); + const int velocity = layerEntry["delay"]; + traceDelays[static_cast( layerId )] = velocity; + } + + std::vector viaOverrides; + + for( const nlohmann::json& viaEntry : entry["via_overrides"] ) + { + if( !viaEntry.is_object() || !viaEntry.contains( "signal_layer_from" ) ) + continue; + + viaOverrides.push_back( readViaOverrideConfigurationLine( viaEntry ) ); + } + + TIME_DOMAIN_TUNING_PROFILE item{ profileName, viaPropDelay, std::move( traceDelays ), + std::move( viaOverrides ) }; + + return item; + }; + + m_params.emplace_back( new PARAM_LAMBDA( + "delay_profiles_user_defined", + [&]() -> nlohmann::json + { + nlohmann::json ret = nlohmann::json::array(); + + for( const auto& entry : m_delayProfiles ) + saveUserDefinedProfileConfigurationLine( ret, entry ); + + return ret; + }, + [&]( const nlohmann::json& aJson ) + { + if( !aJson.is_array() ) + return; + + ClearDelayProfiles(); + + for( const nlohmann::json& entry : aJson ) + { + if( !entry.is_object() || !entry.contains( "profile_name" ) ) + continue; + + m_delayProfiles.emplace_back( readUserDefinedProfileConfigurationLine( entry ) ); + } + }, + {} ) ); +} + + +TIME_DOMAIN_PARAMETERS::~TIME_DOMAIN_PARAMETERS() +{ + // Release early before destroying members + if( m_parent ) + { + m_parent->ReleaseNestedSettings( this ); + m_parent = nullptr; + } +} + + +bool TIME_DOMAIN_PARAMETERS::operator==( const TIME_DOMAIN_PARAMETERS& aOther ) const +{ + /* + if( !std::equal( std::begin( m_netClasses ), std::end( m_netClasses ), + std::begin( aOther.m_netClasses ) ) ) + return false; + + if( !std::equal( std::begin( m_netClassPatternAssignments ), + std::end( m_netClassPatternAssignments ), + std::begin( aOther.m_netClassPatternAssignments ) ) ) + return false; + + if( !std::equal( std::begin( m_netClassLabelAssignments ), + std::end( m_netClassLabelAssignments ), + std::begin( aOther.m_netClassLabelAssignments ) ) ) + return false; + + + if( !std::equal( std::begin( m_netColorAssignments ), std::end( m_netColorAssignments ), + std::begin( aOther.m_netColorAssignments ) ) ) + return false; + */ + + return true; +} diff --git a/common/properties/pg_editors.cpp b/common/properties/pg_editors.cpp index ab5568b29a..90320caac0 100644 --- a/common/properties/pg_editors.cpp +++ b/common/properties/pg_editors.cpp @@ -102,6 +102,10 @@ wxPGWindowList PG_UNIT_EDITOR::CreateControls( wxPropertyGrid* aPropGrid, wxPGPr m_unitBinder->SetCoordType( ORIGIN_TRANSFORMS::NOT_A_COORD ); m_unitBinder->SetUnits( EDA_UNITS::DEGREES ); } + else if( dynamic_cast( aProperty ) != nullptr ) + { + m_unitBinder->SetUnits( EDA_UNITS::PS ); + } UpdateControl( aProperty, win ); diff --git a/common/properties/pg_properties.cpp b/common/properties/pg_properties.cpp index a7baaa0cc3..b747ee818a 100644 --- a/common/properties/pg_properties.cpp +++ b/common/properties/pg_properties.cpp @@ -210,6 +210,11 @@ wxPGProperty* PGPropertyFactory( const PROPERTY_BASE* aProperty, EDA_DRAW_FRAME* switch( display ) { + case PROPERTY_DISPLAY::PT_TIME: + ret = new PGPROPERTY_TIME( aFrame ); + ret->SetEditor( PG_UNIT_EDITOR::BuildEditorName( aFrame ) ); + break; + case PROPERTY_DISPLAY::PT_SIZE: ret = new PGPROPERTY_SIZE( aFrame ); ret->SetEditor( PG_UNIT_EDITOR::BuildEditorName( aFrame ) ); @@ -724,3 +729,66 @@ wxString PGPROPERTY_COLOR4D::ValueToString( wxVariant& aValue, int aFlags ) cons return ret; } + + +PGPROPERTY_TIME::PGPROPERTY_TIME( EDA_DRAW_FRAME* aParentFrame ) : + wxIntProperty( wxPG_LABEL, wxPG_LABEL, 0 ), + m_parentFrame( aParentFrame ) +{ +} + + +#if wxCHECK_VERSION( 3, 3, 0 ) +bool PGPROPERTY_AREA::StringToValue( wxVariant& aVariant, const wxString& aText, + wxPGPropValFormatFlags aArgFlags ) const +#else +bool PGPROPERTY_TIME::StringToValue( wxVariant& aVariant, const wxString& aText, + int aArgFlags ) const +#endif +{ + wxCHECK_MSG( false, false, wxS( "PGPROPERTY_RATIO::StringToValue should not be used." ) ); +} + + +#if wxCHECK_VERSION( 3, 3, 0 ) +wxString PGPROPERTY_AREA::ValueToString( wxVariant& aVariant, + wxPGPropValFormatFlags aArgFlags ) const +#else +wxString PGPROPERTY_TIME::ValueToString( wxVariant& aVariant, int aArgFlags ) const +#endif +{ + int value; + + if( aVariant.GetType() == wxT( "std::optional" ) ) + { + auto* variantData = static_cast( aVariant.GetData() ); + + if( !variantData->Value().has_value() ) + return wxEmptyString; + + value = variantData->Value().value(); + } + else if( aVariant.GetType() == wxPG_VARIANT_TYPE_LONG ) + { + value = static_cast( aVariant.GetInteger() ); + } + else + { + wxFAIL_MSG( wxT( "Expected int (or std::optional) value type" ) ); + return wxEmptyString; + } + + return m_parentFrame->StringFromValue( value, true, EDA_DATA_TYPE::TIME ); +} + + +bool PGPROPERTY_TIME::ValidateValue( wxVariant& aValue, wxPGValidationInfo& aValidationInfo ) const +{ + return true; +} + + +wxValidator* PGPROPERTY_TIME::DoGetValidator() const +{ + return nullptr; +} diff --git a/common/settings/common_settings.cpp b/common/settings/common_settings.cpp index 76697ec989..73f8d3328c 100644 --- a/common/settings/common_settings.cpp +++ b/common/settings/common_settings.cpp @@ -34,13 +34,14 @@ #include #include #include +#include ///! The following environment variables will never be migrated from a previous version const wxRegEx versionedEnvVarRegex( wxS( "KICAD[0-9]+_[A-Z0-9_]+(_DIR)?" ) ); ///! Update the schema version whenever a migration is required -const int commonSchemaVersion = 3; +const int commonSchemaVersion = 4; COMMON_SETTINGS::COMMON_SETTINGS() : JSON_SETTINGS( "kicad_common", SETTINGS_LOC::USER, commonSchemaVersion ), @@ -357,10 +358,10 @@ COMMON_SETTINGS::COMMON_SETTINGS() : &m_NetclassPanel.sash_pos, 160 ) ); m_params.emplace_back( new PARAM( "netclass_panel.eeschema_shown_columns", - &m_NetclassPanel.eeschema_visible_columns, "0 10 11 12 13" ) ); + &m_NetclassPanel.eeschema_visible_columns, "0 11 12 13 14" ) ); m_params.emplace_back( new PARAM( "netclass_panel.pcbnew_shown_columns", - &m_NetclassPanel.pcbnew_visible_columns, "0 1 2 3 4 5 6 7 8 9" ) ); + &m_NetclassPanel.pcbnew_visible_columns, "0 1 2 3 4 5 6 7 8 9 10" ) ); m_params.emplace_back( new PARAM( "package_manager.sash_pos", &m_PackageManager.sash_pos, 380 ) ); @@ -434,6 +435,7 @@ COMMON_SETTINGS::COMMON_SETTINGS() : registerMigration( 0, 1, std::bind( &COMMON_SETTINGS::migrateSchema0to1, this ) ); registerMigration( 1, 2, std::bind( &COMMON_SETTINGS::migrateSchema1to2, this ) ); registerMigration( 2, 3, std::bind( &COMMON_SETTINGS::migrateSchema2to3, this ) ); + registerMigration( 3, 4, std::bind( &COMMON_SETTINGS::migrateSchema3to4, this ) ); } @@ -561,6 +563,66 @@ bool COMMON_SETTINGS::migrateSchema2to3() } +bool COMMON_SETTINGS::migrateSchema3to4() +{ + // >= 10 = add 1 + try + { + // Update netclass panel shown columns for eeschema + const nlohmann::json::json_pointer v3_pointer_eeschema( "/netclass_panel/eeschema_shown_columns"_json_pointer ); + wxString eeSchemaColumnList_old = m_internals->at( v3_pointer_eeschema ); + + wxStringTokenizer eeSchemaShownTokens( eeSchemaColumnList_old ); + wxString eeSchemaColumnList_new; + + while( eeSchemaShownTokens.HasMoreTokens() ) + { + long colNumber; + eeSchemaShownTokens.GetNextToken().ToLong( &colNumber ); + + if( colNumber >= 10 ) + ++colNumber; + + eeSchemaColumnList_new += wxString::Format( wxT( "%ld " ), colNumber ); + } + + eeSchemaColumnList_new.Trim( true ); + eeSchemaColumnList_new.Trim( false ); + + m_internals->at( v3_pointer_eeschema ) = eeSchemaColumnList_new.ToUTF8(); + + // Update netclass panel shown columns for pcbnew + const nlohmann::json::json_pointer v3_pointer_pcbnew( "/netclass_panel/pcbnew_shown_columns"_json_pointer ); + wxString pcbnewColumnList_old = m_internals->at( v3_pointer_pcbnew ); + + wxStringTokenizer pcbnewShownTokens( pcbnewColumnList_old ); + wxString pcbnewColumnList_new; + + while( pcbnewShownTokens.HasMoreTokens() ) + { + long colNumber; + pcbnewShownTokens.GetNextToken().ToLong( &colNumber ); + + if( colNumber >= 10 ) + ++colNumber; + + pcbnewColumnList_new += wxString::Format( wxT( "%ld " ), colNumber ); + } + + pcbnewColumnList_new.Trim( true ); + pcbnewColumnList_new.Trim( false ); + + m_internals->at( v3_pointer_pcbnew ) = pcbnewColumnList_new.ToUTF8(); + } + catch( ... ) + { + wxLogTrace( traceSettings, wxT( "COMMON_SETTINGS::Migrate 3->4: /netclass_panel/shown_columns not found" ) ); + } + + return true; +} + + bool COMMON_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg ) { bool ret = true; diff --git a/common/widgets/wx_grid.cpp b/common/widgets/wx_grid.cpp index 96e030ec43..0e0741b09a 100644 --- a/common/widgets/wx_grid.cpp +++ b/common/widgets/wx_grid.cpp @@ -371,17 +371,20 @@ void WX_GRID::onCellEditorShown( wxGridEvent& aEvent ) void WX_GRID::onCellEditorHidden( wxGridEvent& aEvent ) { - if( alg::contains( m_autoEvalCols, aEvent.GetCol() ) ) + const int col = aEvent.GetCol(); + + if( alg::contains( m_autoEvalCols, col ) ) { UNITS_PROVIDER* unitsProvider = m_unitsProviders[ aEvent.GetCol() ]; if( !unitsProvider ) unitsProvider = m_unitsProviders.begin()->second; - m_eval->SetDefaultUnits( unitsProvider->GetUserUnits() ); + auto [cellUnits, cellDataType] = getColumnUnits( col ); - int row = aEvent.GetRow(); - int col = aEvent.GetCol(); + m_eval->SetDefaultUnits( cellUnits ); + + const int row = aEvent.GetRow(); // Determine if this cell is marked as holding nullable values bool isNullable = false; @@ -399,7 +402,7 @@ void WX_GRID::onCellEditorHidden( wxGridEvent& aEvent ) } CallAfter( - [this, row, col, isNullable, unitsProvider]() + [this, row, col, isNullable, unitsProvider, cellDataType]() { wxString stringValue = GetCellValue( row, col ); bool processedOk = true; @@ -418,19 +421,22 @@ void WX_GRID::onCellEditorHidden( wxGridEvent& aEvent ) if( stringValue == UNITS_PROVIDER::NullUiString ) { val = unitsProvider->OptionalValueFromString( - UNITS_PROVIDER::NullUiString ); + UNITS_PROVIDER::NullUiString, cellDataType ); } else { - val = unitsProvider->OptionalValueFromString( m_eval->Result() ); + val = unitsProvider->OptionalValueFromString( m_eval->Result(), + cellDataType ); } - evalValue = unitsProvider->StringFromOptionalValue( val, true ); + evalValue = unitsProvider->StringFromOptionalValue( val, true, + cellDataType ); } else { - int val = unitsProvider->ValueFromString( m_eval->Result() ); - evalValue = unitsProvider->StringFromValue( val, true ); + int val = unitsProvider->ValueFromString( m_eval->Result(), + cellDataType ); + evalValue = unitsProvider->StringFromValue( val, true, cellDataType ); } if( stringValue != evalValue ) @@ -702,6 +708,19 @@ void WX_GRID::SetUnitsProvider( UNITS_PROVIDER* aProvider, int aCol ) } +void WX_GRID::SetAutoEvalColUnits( const int col, EDA_UNITS aUnit, EDA_DATA_TYPE aUnitType ) +{ + m_autoEvalColsUnits[col] = std::make_pair( aUnit, aUnitType ); +} + + +void WX_GRID::SetAutoEvalColUnits( const int col, EDA_UNITS aUnit ) +{ + const EDA_DATA_TYPE type = UNITS_PROVIDER::GetTypeFromUnits( aUnit ); + SetAutoEvalColUnits( col, aUnit, type ); +} + + int WX_GRID::GetUnitValue( int aRow, int aCol ) { UNITS_PROVIDER* unitsProvider = m_unitsProviders[ aCol ]; @@ -711,15 +730,17 @@ int WX_GRID::GetUnitValue( int aRow, int aCol ) wxString stringValue = GetCellValue( aRow, aCol ); + auto [cellUnits, cellDataType] = getColumnUnits( aCol ); + if( alg::contains( m_autoEvalCols, aCol ) ) { - m_eval->SetDefaultUnits( unitsProvider->GetUserUnits() ); + m_eval->SetDefaultUnits( cellUnits ); if( m_eval->Process( stringValue ) ) stringValue = m_eval->Result(); } - return unitsProvider->ValueFromString( stringValue ); + return unitsProvider->ValueFromString( stringValue, cellDataType ); } @@ -732,15 +753,17 @@ std::optional WX_GRID::GetOptionalUnitValue( int aRow, int aCol ) wxString stringValue = GetCellValue( aRow, aCol ); + auto [cellUnits, cellDataType] = getColumnUnits( aCol ); + if( alg::contains( m_autoEvalCols, aCol ) ) { - m_eval->SetDefaultUnits( unitsProvider->GetUserUnits() ); + m_eval->SetDefaultUnits( cellUnits ); if( stringValue != UNITS_PROVIDER::NullUiString && m_eval->Process( stringValue ) ) stringValue = m_eval->Result(); } - return unitsProvider->OptionalValueFromString( stringValue ); + return unitsProvider->OptionalValueFromString( stringValue, cellDataType ); } @@ -751,7 +774,14 @@ void WX_GRID::SetUnitValue( int aRow, int aCol, int aValue ) if( !unitsProvider ) unitsProvider = m_unitsProviders.begin()->second; - SetCellValue( aRow, aCol, unitsProvider->StringFromValue( aValue, true ) ); + EDA_DATA_TYPE cellDataType; + + if( m_autoEvalColsUnits.contains( aCol ) ) + cellDataType = m_autoEvalColsUnits[aCol].second; + else + cellDataType = EDA_DATA_TYPE::DISTANCE; + + SetCellValue( aRow, aCol, unitsProvider->StringFromValue( aValue, true, cellDataType ) ); } @@ -840,3 +870,20 @@ void WX_GRID::EnsureColLabelsVisible() if( initial_row_height != row_height ) SetColLabelSize( row_height ); } + + +std::pair WX_GRID::getColumnUnits( const int aCol ) const +{ + if( m_autoEvalColsUnits.contains( aCol ) ) + return { m_autoEvalColsUnits.at( aCol ).first, m_autoEvalColsUnits.at( aCol ).second }; + + UNITS_PROVIDER* unitsProvider; + + if( m_unitsProviders.contains( aCol ) ) + unitsProvider = m_unitsProviders.at( aCol ); + else + unitsProvider = m_unitsProviders.begin()->second; + + // Legacy - default always DISTANCE + return { unitsProvider->GetUserUnits(), EDA_DATA_TYPE::DISTANCE }; +} diff --git a/include/base_units.h b/include/base_units.h index da59375acd..76b8065358 100644 --- a/include/base_units.h +++ b/include/base_units.h @@ -75,6 +75,8 @@ struct EDA_IU_SCALE { const double IU_PER_MM; const double IU_PER_MILS; + const double IU_PER_PS{ 1e6 }; ///< Internal time units are attoseconds + const double IU_PER_PS_PER_MM{ 1e6 }; ///< Internal velocity units are attoseconds/mm const double MM_PER_IU; diff --git a/include/dialogs/panel_setup_netclasses.h b/include/dialogs/panel_setup_netclasses.h index cac1c77885..8ab99f940f 100644 --- a/include/dialogs/panel_setup_netclasses.h +++ b/include/dialogs/panel_setup_netclasses.h @@ -48,6 +48,8 @@ public: void ImportSettingsFrom( const std::shared_ptr& aNetSettings ); + void UpdateTuningProfileNames( const std::vector& aNames ) const; + private: void OnAddNetclassClick( wxCommandEvent& event ) override; void OnRemoveNetclassClick( wxCommandEvent& event ) override; diff --git a/include/eda_units.h b/include/eda_units.h index 0653c57ac3..d70a5e8c58 100644 --- a/include/eda_units.h +++ b/include/eda_units.h @@ -36,22 +36,29 @@ */ enum class EDA_DATA_TYPE { - DISTANCE = 0, - AREA = 1, - VOLUME = 2, - UNITLESS = 3 + DISTANCE = 0, + AREA = 1, + VOLUME = 2, + UNITLESS = 3, + TIME = 4, + LENGTH_DELAY = 5 }; enum class EDA_UNITS { - INCH = 0, // Do not use IN: it conflicts with a Windows header - MM = 1, - UNSCALED = 2, - DEGREES = 3, - PERCENT = 4, - MILS = 5, - UM = 6, - CM = 7 + INCH = 0, // Do not use IN: it conflicts with a Windows header + MM = 1, + UNSCALED = 2, + DEGREES = 3, + PERCENT = 4, + MILS = 5, + UM = 6, + CM = 7, + FS = 8, // Femtoseconds + PS = 9, // Picoseconds + PS_PER_INCH = 10, + PS_PER_CM = 11, + PS_PER_MM = 12 }; namespace EDA_UNIT_UTILS diff --git a/include/libeval/numeric_evaluator.h b/include/libeval/numeric_evaluator.h index 41084ee1d4..29839751cf 100644 --- a/include/libeval/numeric_evaluator.h +++ b/include/libeval/numeric_evaluator.h @@ -94,7 +94,22 @@ namespace numEval class KICOMMON_API NUMERIC_EVALUATOR { - enum class Unit { Invalid, UM, MM, CM, Inch, Mil, Degrees, SI }; + enum class Unit + { + Invalid, + UM, + MM, + CM, + Inch, + Mil, + Degrees, + SI, + Femtoseconds, + Picoseconds, + PsPerInch, + PsPerCm, + PsPerMm + }; public: NUMERIC_EVALUATOR( EDA_UNITS aUnits ); diff --git a/include/libeval_compiler/libeval_compiler.h b/include/libeval_compiler/libeval_compiler.h index 65e53422ed..137608c524 100644 --- a/include/libeval_compiler/libeval_compiler.h +++ b/include/libeval_compiler/libeval_compiler.h @@ -144,7 +144,7 @@ public: bool isVisited; int srcPos; - void SetUop( int aOp, double aValue ); + void SetUop( int aOp, double aValue, EDA_UNITS aUnits ); void SetUop( int aOp, const wxString& aValue, bool aStringIsWildcard ); void SetUop( int aOp, std::unique_ptr aRef = nullptr ); void SetUop( int aOp, FUNC_CALL_REF aFunc, std::unique_ptr aRef = nullptr ); @@ -172,6 +172,14 @@ public: return nullUnits; } + + virtual const std::vector& GetSupportedUnitsTypes() const + { + static const std::vector nullUnits; + + return nullUnits; + } + virtual wxString GetSupportedUnitsMessage() const { return wxEmptyString; @@ -188,29 +196,16 @@ class KICOMMON_API VALUE { public: VALUE() : - m_type( VT_UNDEFINED ), - m_valueDbl( 0 ), - m_stringIsWildcard( false ), - m_isDeferredDbl( false ), - m_isDeferredStr( false ) - {}; + m_type( VT_UNDEFINED ), m_valueDbl( 0 ), m_stringIsWildcard( false ), m_isDeferredDbl( false ), + m_isDeferredStr( false ), m_units( EDA_UNITS::UNSCALED ) {}; VALUE( const wxString& aStr, bool aIsWildcard = false ) : - m_type( VT_STRING ), - m_valueDbl( 0 ), - m_valueStr( aStr ), - m_stringIsWildcard( aIsWildcard ), - m_isDeferredDbl( false ), - m_isDeferredStr( false ) - {}; + m_type( VT_STRING ), m_valueDbl( 0 ), m_valueStr( aStr ), m_stringIsWildcard( aIsWildcard ), + m_isDeferredDbl( false ), m_isDeferredStr( false ), m_units( EDA_UNITS::UNSCALED ) {}; VALUE( const double aVal ) : - m_type( VT_NUMERIC ), - m_valueDbl( aVal ), - m_stringIsWildcard( false ), - m_isDeferredDbl( false ), - m_isDeferredStr( false ) - {}; + m_type( VT_NUMERIC ), m_valueDbl( aVal ), m_stringIsWildcard( false ), m_isDeferredDbl( false ), + m_isDeferredStr( false ), m_units( EDA_UNITS::UNSCALED ) {}; static VALUE* MakeNullValue() { @@ -286,6 +281,10 @@ public: m_valueStr = val.m_valueStr; } + void SetUnits( const EDA_UNITS aUnits ) { m_units = aUnits; } + + EDA_UNITS GetUnits() const { return m_units; } + private: VAR_TYPE_T m_type; mutable double m_valueDbl; // mutable to support deferred evaluation @@ -297,6 +296,8 @@ private: mutable bool m_isDeferredStr; std::function m_lambdaStr; + + EDA_UNITS m_units; }; class KICOMMON_API VAR_REF diff --git a/include/netclass.h b/include/netclass.h index 0a2bbed1fa..e79fb25b9c 100644 --- a/include/netclass.h +++ b/include/netclass.h @@ -238,6 +238,12 @@ public: void SetPriority( int aPriority ) { m_Priority = aPriority; } int GetPriority() const { return m_Priority; } + bool HasTuningProfile() const { return !m_TuningProfile.empty(); } + void SetTuningProfile( const wxString& aTuningProfile ) { m_TuningProfile = aTuningProfile; } + wxString GetTuningProfile() const { return m_TuningProfile; } + void SetTuningProfileParent( NETCLASS* aParent ) { m_tuningProfileParent = aParent; } + NETCLASS* GetTuningProfileParent() const { return m_tuningProfileParent; } + protected: bool m_isDefault; ///< Mark if this instance is the default netclass @@ -267,6 +273,8 @@ protected: COLOR4D m_pcbColor; ///< Optional PCB color override for this netclass + wxString m_TuningProfile; ///< The tuning profile name being used by this netclass + // The NETCLASS providing each parameter NETCLASS* m_clearanceParent; NETCLASS* m_trackWidthParent; @@ -282,6 +290,7 @@ protected: NETCLASS* m_busWidthParent; NETCLASS* m_schematicColorParent; NETCLASS* m_lineStyleParent; + NETCLASS* m_tuningProfileParent; }; #endif // CLASS_NETCLASS_H diff --git a/include/project/board_project_settings.h b/include/project/board_project_settings.h index 2aef966733..f8bee6f6e9 100644 --- a/include/project/board_project_settings.h +++ b/include/project/board_project_settings.h @@ -352,6 +352,7 @@ struct KICOMMON_API PANEL_NET_INSPECTOR_SETTINGS std::vector custom_group_rules; bool show_zero_pad_nets; bool show_unconnected_nets; + bool show_time_domain_details; int sorting_column; bool sort_order_asc; std::vector col_order; @@ -369,6 +370,7 @@ struct KICOMMON_API PANEL_NET_INSPECTOR_SETTINGS group_by_constraint = false; show_zero_pad_nets = false; show_unconnected_nets = false; + show_time_domain_details = false; sorting_column = -1; sort_order_asc = true; } diff --git a/include/project/net_settings.h b/include/project/net_settings.h index f84e37b48b..98b0c3cfcc 100644 --- a/include/project/net_settings.h +++ b/include/project/net_settings.h @@ -187,6 +187,7 @@ private: bool migrateSchema1to2(); bool migrateSchema2to3(); bool migrateSchema3to4(); + bool migrateSchema4to5(); /** * @brief Creates an effective aggregate netclass from the given constituent netclasses diff --git a/include/project/project_file.h b/include/project/project_file.h index 9ea2303ed0..f2312175eb 100644 --- a/include/project/project_file.h +++ b/include/project/project_file.h @@ -32,6 +32,7 @@ class BOARD_DESIGN_SETTINGS; class ERC_SETTINGS; class NET_SETTINGS; class COMPONENT_CLASS_SETTINGS; +class TIME_DOMAIN_PARAMETERS; class LAYER_PAIR_SETTINGS; class SCHEMATIC_SETTINGS; class TEMPLATES; @@ -111,6 +112,11 @@ public: return m_ComponentClassSettings; } + std::shared_ptr& TimeDomainParameters() + { + return m_timeDomainParameters; + } + /** * @return true if it should be safe to auto-save this file without user action */ @@ -193,6 +199,11 @@ public: */ std::shared_ptr m_ComponentClassSettings; + /** + * Time domain parameters for this project + */ + std::shared_ptr m_timeDomainParameters; + std::vector m_LayerPresets; /// List of stored layer presets std::vector m_Viewports; /// List of stored viewports (pos + zoom) std::vector m_Viewports3D; /// List of stored 3D viewports (view matrixes) diff --git a/include/project/time_domain_parameters.h b/include/project/time_domain_parameters.h new file mode 100644 index 0000000000..1a7cadf6bc --- /dev/null +++ b/include/project/time_domain_parameters.h @@ -0,0 +1,80 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2020 CERN + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * @author Jon Evans + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef KICAD_TIME_DOMAIN_PARAMETERS_H +#define KICAD_TIME_DOMAIN_PARAMETERS_H + +#include +#include + +/** + * Represents a single line in the time domain configuration via overrides configuration grid + */ +struct TUNING_PROFILE_VIA_OVERRIDE_ENTRY +{ + PCB_LAYER_ID m_SignalLayerFrom; + PCB_LAYER_ID m_SignalLayerTo; + PCB_LAYER_ID m_ViaLayerFrom; + PCB_LAYER_ID m_ViaLayerTo; + int m_Delay; +}; + + +/** + * Represents a single line in the time domain configuration net class configuration grid + */ +struct TIME_DOMAIN_TUNING_PROFILE +{ + wxString m_ProfileName; + int m_ViaPropagationDelay; + std::map m_LayerPropagationDelays; + std::vector m_ViaOverrides; +}; + + +/** + * TIME_DOMAIN_PARAMETERS stores the configuration for time-domain tuning + */ +class KICOMMON_API TIME_DOMAIN_PARAMETERS final : public NESTED_SETTINGS +{ +public: + TIME_DOMAIN_PARAMETERS( JSON_SETTINGS* aParent, const std::string& aPath ); + + virtual ~TIME_DOMAIN_PARAMETERS(); + + bool operator==( const TIME_DOMAIN_PARAMETERS& aOther ) const; + + bool operator!=( const TIME_DOMAIN_PARAMETERS& aOther ) const { return !operator==( aOther ); } + + void ClearDelayProfiles() { m_delayProfiles.clear(); } + + void AddDelayProfile( TIME_DOMAIN_TUNING_PROFILE&& aTraceEntry ) + { + m_delayProfiles.emplace_back( std::move( aTraceEntry ) ); + } + + const std::vector& GetDelayProfiles() const { return m_delayProfiles; } + +private: + std::vector m_delayProfiles; +}; + +#endif // KICAD_NET_SETTINGS_H diff --git a/include/properties/pg_properties.h b/include/properties/pg_properties.h index c0ff2744e3..a3c732cab1 100644 --- a/include/properties/pg_properties.h +++ b/include/properties/pg_properties.h @@ -336,4 +336,34 @@ public: KIGFX::COLOR4D m_backgroundColor; }; + +class PGPROPERTY_TIME : public wxIntProperty +{ +public: + PGPROPERTY_TIME( EDA_DRAW_FRAME* aParentFrame ); + + virtual ~PGPROPERTY_TIME() = default; + +protected: +#if wxCHECK_VERSION( 3, 3, 0 ) + bool StringToValue( wxVariant& aVariant, const wxString& aText, + wxPGPropValFormatFlags aFlags = wxPGPropValFormatFlags::Null ) const override; + + wxString ValueToString( wxVariant& aVariant, + wxPGPropValFormatFlags aFlags = wxPGPropValFormatFlags::Null ) const override; +#else + bool StringToValue( wxVariant& aVariant, const wxString& aText, + int aArgFlags = 0 ) const override; + + wxString ValueToString( wxVariant& aVariant, int aArgFlags = 0 ) const override; +#endif + + bool ValidateValue( wxVariant& aValue, wxPGValidationInfo& aValidationInfo ) const override; + + wxValidator* DoGetValidator() const override; + +protected: + EDA_DRAW_FRAME* m_parentFrame; +}; + #endif /* PG_PROPERTIES_H */ diff --git a/include/properties/property.h b/include/properties/property.h index 543e36a5fc..febf34069d 100644 --- a/include/properties/property.h +++ b/include/properties/property.h @@ -64,7 +64,8 @@ enum PROPERTY_DISPLAY PT_COORD, ///< Coordinate expressed in distance units (mm/inch) PT_DEGREE, ///< Angle expressed in degrees PT_DECIDEGREE, ///< Angle expressed in decidegrees - PT_RATIO + PT_RATIO, + PT_TIME, ///< Time expressed in ps }; ///< Macro to generate unique identifier for a type diff --git a/include/settings/common_settings.h b/include/settings/common_settings.h index 4c881e56a7..0b816ecf6b 100644 --- a/include/settings/common_settings.h +++ b/include/settings/common_settings.h @@ -194,6 +194,7 @@ private: bool migrateSchema0to1(); bool migrateSchema1to2(); bool migrateSchema2to3(); + bool migrateSchema3to4(); struct LEGACY_3D_SEARCH_PATH { diff --git a/include/units_provider.h b/include/units_provider.h index adac5a175c..5b2bcd4e96 100644 --- a/include/units_provider.h +++ b/include/units_provider.h @@ -79,7 +79,7 @@ public: wxString StringFromValue( double aValue, bool aAddUnitLabel = false, EDA_DATA_TYPE aType = EDA_DATA_TYPE::DISTANCE ) const { - return EDA_UNIT_UTILS::UI::StringFromValue( GetIuScale(), GetUserUnits(), aValue, + return EDA_UNIT_UTILS::UI::StringFromValue( GetIuScale(), GetUnitsFromType( aType ), aValue, aAddUnitLabel, aType ); } @@ -103,7 +103,7 @@ public: if( !aValue ) return NullUiString; else - return EDA_UNIT_UTILS::UI::StringFromValue( GetIuScale(), GetUserUnits(), + return EDA_UNIT_UTILS::UI::StringFromValue( GetIuScale(), GetUnitsFromType( aType ), aValue.value(), aAddUnitLabel, aType ); } @@ -123,8 +123,8 @@ public: wxString MessageTextFromValue( double aValue, bool aAddUnitLabel = true, EDA_DATA_TYPE aType = EDA_DATA_TYPE::DISTANCE ) const { - return EDA_UNIT_UTILS::UI::MessageTextFromValue( GetIuScale(), GetUserUnits(), aValue, - aAddUnitLabel, aType ); + return EDA_UNIT_UTILS::UI::MessageTextFromValue( GetIuScale(), GetUnitsFromType( aType ), + aValue, aAddUnitLabel, aType ); } wxString MessageTextFromValue( const EDA_ANGLE& aValue, bool aAddUnitLabel = true ) const @@ -134,9 +134,10 @@ public: EDA_DATA_TYPE::DISTANCE ); } - wxString MessageTextFromMinOptMax( const MINOPTMAX& aValue ) const + wxString MessageTextFromMinOptMax( const MINOPTMAX& aValue, + EDA_DATA_TYPE aType = EDA_DATA_TYPE::DISTANCE ) const { - return EDA_UNIT_UTILS::UI::MessageTextFromMinOptMax( GetIuScale(), GetUserUnits(), aValue ); + return EDA_UNIT_UTILS::UI::MessageTextFromMinOptMax( GetIuScale(), GetUnitsFromType( aType ), aValue ); }; /** @@ -151,8 +152,9 @@ public: int ValueFromString( const wxString& aTextValue, EDA_DATA_TYPE aType = EDA_DATA_TYPE::DISTANCE ) const { - double value = EDA_UNIT_UTILS::UI::DoubleValueFromString( GetIuScale(), GetUserUnits(), - aTextValue, aType ); + double value = EDA_UNIT_UTILS::UI::DoubleValueFromString( + GetIuScale(), GetUnitsFromType( aType ), aTextValue, aType ); + return KiROUND( value ); } @@ -175,8 +177,8 @@ public: if( aTextValue == NullUiString ) return {}; - double value = EDA_UNIT_UTILS::UI::DoubleValueFromString( GetIuScale(), GetUserUnits(), - aTextValue, aType ); + double value = EDA_UNIT_UTILS::UI::DoubleValueFromString( + GetIuScale(), GetUnitsFromType( aType ), aTextValue, aType ); return KiROUND( value ); } @@ -189,6 +191,58 @@ public: return EDA_ANGLE( angle, DEGREES_T ); } + /** + * Gets the units to use in the conversion based on the underlying user units + */ + EDA_UNITS GetUnitsFromType( EDA_DATA_TYPE aType ) const + { + // Get the unit type depending on the requested unit type and the underlying user setting + if( aType == EDA_DATA_TYPE::TIME ) + { + return EDA_UNITS::PS; + } + else if( aType == EDA_DATA_TYPE::LENGTH_DELAY ) + { + if( EDA_UNIT_UTILS::IsMetricUnit( GetUserUnits() ) ) + return EDA_UNITS::PS_PER_CM; + else + return EDA_UNITS::PS_PER_INCH; + } + + return GetUserUnits(); + } + + /** + * Gets the inferred type from the given units. Note: will always return the most simple + * type (e.g. a DISTANCE rather than AREA or VOLUME for a measurement unit). + */ + static EDA_DATA_TYPE GetTypeFromUnits( const EDA_UNITS aUnits ) + { + switch( aUnits ) + { + case EDA_UNITS::INCH: + case EDA_UNITS::MM: + case EDA_UNITS::UM: + case EDA_UNITS::CM: + case EDA_UNITS::MILS: + return EDA_DATA_TYPE::DISTANCE; + case EDA_UNITS::DEGREES: + case EDA_UNITS::PERCENT: + case EDA_UNITS::UNSCALED: + return EDA_DATA_TYPE::UNITLESS; + case EDA_UNITS::FS: + case EDA_UNITS::PS: + return EDA_DATA_TYPE::TIME; + case EDA_UNITS::PS_PER_INCH: + case EDA_UNITS::PS_PER_CM: + case EDA_UNITS::PS_PER_MM: + return EDA_DATA_TYPE::LENGTH_DELAY; + } + + wxString msg = wxString::Format( wxT( "Unhandled unit data type %d" ), static_cast( aUnits ) ); + wxCHECK_MSG( false, EDA_DATA_TYPE::UNITLESS, msg ); + } + /// @brief The string that is used in the UI to represent a null value static inline const wxString NullUiString = ""; diff --git a/include/widgets/wx_grid.h b/include/widgets/wx_grid.h index 4df72936f6..4e0b9a55da 100644 --- a/include/widgets/wx_grid.h +++ b/include/widgets/wx_grid.h @@ -127,6 +127,16 @@ public: void SetAutoEvalCols( const std::vector& aCols ) { m_autoEvalCols = aCols; } + /** + * Set the unit and unit data type to use for a given column + */ + void SetAutoEvalColUnits( int col, EDA_UNITS aUnit, EDA_DATA_TYPE aUnitType ); + + /** + * Set the unit to use for a given column. The unit data type is inferred from the unit type + */ + void SetAutoEvalColUnits( int col, EDA_UNITS aUnit ); + /** * Apply standard KiCad unit and eval services to a numeric cell. * @@ -250,12 +260,18 @@ protected: void onDPIChanged(wxDPIChangedEvent& event); + /** + * Returns the units and data type associated with a given column + */ + std::pair getColumnUnits( int aCol ) const; + protected: bool m_weOwnTable; std::map m_unitsProviders; std::unique_ptr m_eval; std::vector m_autoEvalCols; + std::unordered_map> m_autoEvalColsUnits; std::map< std::pair, std::pair > m_evalBeforeAfter; diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 11321ad412..0e3fed083a 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -201,6 +201,8 @@ set( PCBNEW_DIALOGS dialogs/panel_setup_tracks_and_vias_base.cpp dialogs/panel_setup_tuning_patterns.cpp dialogs/panel_setup_tuning_patterns_base.cpp + dialogs/panel_setup_time_domain_parameters.cpp + dialogs/panel_setup_time_domain_parameters_base.cpp footprint_wizard.cpp footprint_wizard_frame.cpp footprint_wizard_frame_functions.cpp diff --git a/pcbnew/board.cpp b/pcbnew/board.cpp index 9353a8d5e1..3e5fe6f7a4 100644 --- a/pcbnew/board.cpp +++ b/pcbnew/board.cpp @@ -79,7 +79,7 @@ BOARD::BOARD() : m_timeStamp( 1 ), m_paper( PAGE_INFO::A4 ), m_project( nullptr ), m_userUnits( EDA_UNITS::MM ), m_designSettings( new BOARD_DESIGN_SETTINGS( nullptr, "board.design_settings" ) ), m_NetInfo( this ), m_embedFonts( false ), m_componentClassManager( std::make_unique( this ) ), - m_lengthCalc( std::make_unique( this ) ) + m_lengthDelayCalc( std::make_unique( this ) ) { // A too small value do not allow connecting 2 shapes (i.e. segments) not exactly connected // A too large value do not allow safely connecting 2 shapes like very short segments. @@ -2141,6 +2141,12 @@ void BOARD::SynchronizeProperties() } +void BOARD::SynchronizeTimeDomainProperties() +{ + m_lengthDelayCalc->SynchronizeTimeDomainProperties(); +} + + void BOARD::SynchronizeNetsAndNetClasses( bool aResetTrackAndViaSizes ) { if( !m_project ) @@ -2377,26 +2383,29 @@ BOARD_STACKUP BOARD::GetStackupOrDefault() const } -std::tuple BOARD::GetTrackLength( const PCB_TRACK& aTrack ) const +std::tuple BOARD::GetTrackLength( const PCB_TRACK& aTrack ) const { auto connectivity = GetBoard()->GetConnectivity(); - std::vector items; + std::vector items; for( BOARD_CONNECTED_ITEM* boardItem : connectivity->GetConnectedItems( &aTrack, EXCLUDE_ZONES ) ) { - LENGTH_CALCULATION_ITEM item = GetLengthCalculation()->GetLengthCalculationItem( boardItem ); + LENGTH_DELAY_CALCULATION_ITEM item = GetLengthCalculation()->GetLengthCalculationItem( boardItem ); - if( item.Type() != LENGTH_CALCULATION_ITEM::TYPE::UNKNOWN ) + if( item.Type() != LENGTH_DELAY_CALCULATION_ITEM::TYPE::UNKNOWN ) items.push_back( item ); } constexpr PATH_OPTIMISATIONS opts = { .OptimiseViaLayers = true, .MergeTracks = true, .OptimiseTracesInPads = true, .InferViaInPad = false }; - LENGTH_DETAILS details = GetLengthCalculation()->CalculateLengthDetails( items, opts ); + LENGTH_DELAY_STATS details = GetLengthCalculation()->CalculateLengthDetails( + items, opts, nullptr, nullptr, LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL, + LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL ); - return std::make_tuple( items.size(), details.TrackLength + details.ViaLength, details.PadToDieLength ); + return std::make_tuple( items.size(), details.TrackLength + details.ViaLength, details.PadToDieLength, + details.TrackDelay + details.ViaDelay, details.PadToDieDelay ); } diff --git a/pcbnew/board.h b/pcbnew/board.h index f95c1cff23..b9b5a82b56 100644 --- a/pcbnew/board.h +++ b/pcbnew/board.h @@ -33,7 +33,7 @@ #include // for OUTLINE_ERROR_HANDLER #include #include -#include +#include #include #include #include @@ -1015,6 +1015,11 @@ public: */ void SynchronizeProperties(); + /** + * Ensure that all time domain properties providers are in sync with current settings + */ + void SynchronizeTimeDomainProperties(); + /** * Return the Similarity. Because we compare board to board, we just return 1.0 here */ @@ -1159,9 +1164,9 @@ public: * This uses the connectivity data for the board to calculate connections * * @param aTrack Starting track (can also be a via) to check against for connection. - * @return a tuple containing + * @return a tuple containing */ - std::tuple GetTrackLength( const PCB_TRACK& aTrack ) const; + std::tuple GetTrackLength( const PCB_TRACK& aTrack ) const; /** * Collect all the TRACKs and VIAs that are members of a net given by aNetCode. @@ -1283,7 +1288,7 @@ public: /** * Returns the track length calculator */ - LENGTH_CALCULATION* GetLengthCalculation() const { return m_lengthCalc.get(); } + LENGTH_DELAY_CALCULATION* GetLengthCalculation() const { return m_lengthDelayCalc.get(); } /** * Gets the component class manager @@ -1410,7 +1415,7 @@ private: std::unique_ptr m_componentClassManager; - std::unique_ptr m_lengthCalc; + std::unique_ptr m_lengthDelayCalc; }; diff --git a/pcbnew/dialogs/dialog_board_setup.cpp b/pcbnew/dialogs/dialog_board_setup.cpp index 5e41a12b7a..0556b20b24 100644 --- a/pcbnew/dialogs/dialog_board_setup.cpp +++ b/pcbnew/dialogs/dialog_board_setup.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ #include "dialog_board_setup.h" +#include #include @@ -60,6 +62,7 @@ DIALOG_BOARD_SETUP::DIALOG_BOARD_SETUP( PCB_EDIT_FRAME* aFrame ) : m_layers( nullptr ), m_boardFinish( nullptr ), m_physicalStackup( nullptr ), + m_timeDomainParameters( nullptr ), m_currentPage( 0 ), m_layersPage( 0 ), m_physicalStackupPage( 0 ), @@ -73,7 +76,8 @@ DIALOG_BOARD_SETUP::DIALOG_BOARD_SETUP( PCB_EDIT_FRAME* aFrame ) : m_tuningPatternsPage( 0 ), m_netclassesPage( 0 ), m_customRulesPage( 0 ), - m_severitiesPage( 0 ) + m_severitiesPage( 0 ), + m_timeDomainParametersPage( 0 ) { SetEvtHandlerEnabled( false ); @@ -199,42 +203,56 @@ DIALOG_BOARD_SETUP::DIALOG_BOARD_SETUP( PCB_EDIT_FRAME* aFrame ) : }, _( "Component Classes" ) ); - m_customRulesPage = m_treebook->GetPageCount(); - m_treebook->AddLazySubPage( - [this]( wxWindow* aParent ) -> wxWindow* - { - return new PANEL_SETUP_RULES( aParent, m_frame ); - }, _( "Custom Rules" ) ); + m_timeDomainParametersPage = m_treebook->GetPageCount(); + m_treebook->AddLazySubPage( + [this]( wxWindow* aParent ) -> wxWindow* + { + BOARD* board = m_frame->GetBoard(); + return new PANEL_SETUP_TIME_DOMAIN_PARAMETERS( + aParent, m_frame, board, m_frame->Prj().GetProjectFile().TimeDomainParameters() ); + }, + _( "Time Domain Parameters" ) ); - m_severitiesPage = m_treebook->GetPageCount(); - m_treebook->AddLazySubPage( - [this]( wxWindow* aParent ) -> wxWindow* - { - BOARD* board = m_frame->GetBoard(); - return new PANEL_SETUP_SEVERITIES( aParent, DRC_ITEM::GetItemsWithSeverities(), - board->GetDesignSettings().m_DRCSeverities ); - }, _( "Violation Severity" ) ); + m_customRulesPage = m_treebook->GetPageCount(); + m_treebook->AddLazySubPage( + [this]( wxWindow* aParent ) -> wxWindow* + { + return new PANEL_SETUP_RULES( aParent, m_frame ); + }, + _( "Custom Rules" ) ); - m_treebook->AddPage( new wxPanel( GetTreebook() ), _( "Board Data" ) ); - m_embeddedFilesPage = m_treebook->GetPageCount(); - m_treebook->AddLazySubPage( - [this]( wxWindow* aParent ) -> wxWindow* - { - return new PANEL_EMBEDDED_FILES( aParent, m_frame->GetBoard() ); - }, _( "Embedded Files" ) ); + m_severitiesPage = m_treebook->GetPageCount(); + m_treebook->AddLazySubPage( + [this]( wxWindow* aParent ) -> wxWindow* + { + BOARD* board = m_frame->GetBoard(); + return new PANEL_SETUP_SEVERITIES( aParent, DRC_ITEM::GetItemsWithSeverities(), + board->GetDesignSettings().m_DRCSeverities ); + }, + _( "Violation Severity" ) ); - for( size_t i = 0; i < m_treebook->GetPageCount(); ++i ) - m_treebook->ExpandNode( i ); + m_treebook->AddPage( new wxPanel( GetTreebook() ), _( "Board Data" ) ); + m_embeddedFilesPage = m_treebook->GetPageCount(); + m_treebook->AddLazySubPage( + [this]( wxWindow* aParent ) -> wxWindow* + { + return new PANEL_EMBEDDED_FILES( aParent, m_frame->GetBoard() ); + }, + _( "Embedded Files" ) ); - SetEvtHandlerEnabled( true ); + for( size_t i = 0; i < m_treebook->GetPageCount(); ++i ) + m_treebook->ExpandNode( i ); - finishDialogSettings(); + SetEvtHandlerEnabled( true ); - if( Prj().IsReadOnly() ) - { - m_infoBar->ShowMessage( _( "Project is missing or read-only. Some settings will not " - "be editable." ), wxICON_WARNING ); - } + finishDialogSettings(); + + if( Prj().IsReadOnly() ) + { + m_infoBar->ShowMessage( _( "Project is missing or read-only. Some settings will not " + "be editable." ), + wxICON_WARNING ); + } wxBookCtrlEvent evt( wxEVT_TREEBOOK_PAGE_CHANGED, wxID_ANY, 0 ); @@ -255,20 +273,41 @@ void DIALOG_BOARD_SETUP::onPageChanged( wxBookCtrlEvent& aEvent ) if( m_physicalStackupPage > 0 ) // Don't run this during initialization { - if( m_currentPage == m_physicalStackupPage || page == m_physicalStackupPage ) + if( m_currentPage == m_physicalStackupPage || m_currentPage == m_timeDomainParametersPage + || page == m_physicalStackupPage || page == m_timeDomainParametersPage || page == m_netclassesPage ) { m_layers = RESOLVE_PAGE( PANEL_SETUP_LAYERS, m_layersPage ); m_physicalStackup = RESOLVE_PAGE( PANEL_SETUP_BOARD_STACKUP, m_physicalStackupPage ); + m_timeDomainParameters = RESOLVE_PAGE( PANEL_SETUP_TIME_DOMAIN_PARAMETERS, m_timeDomainParametersPage ); + m_netClasses = RESOLVE_PAGE( PANEL_SETUP_NETCLASSES, m_netclassesPage ); } // Ensure layer page always gets updated even if we aren't moving towards it if( m_currentPage == m_physicalStackupPage ) + { m_layers->SyncCopperLayers( m_physicalStackup->GetCopperLayerCount() ); + // Avoid calling SyncCopperLayers twice if moving from stackup to time domain directly + m_timeDomainParameters->SyncCopperLayers( m_physicalStackup->GetCopperLayerCount() ); + } + if( page == m_physicalStackupPage ) + { m_physicalStackup->OnLayersOptionsChanged( m_layers->GetUILayerMask() ); - else if( Prj().IsReadOnly() ) + } + else if( page == m_netclassesPage || m_currentPage == m_timeDomainParametersPage ) + { + m_netClasses->UpdateTuningProfileNames( m_timeDomainParameters->GetDelayProfileNames() ); + } + else if( page == m_timeDomainParametersPage ) + { + m_timeDomainParameters->SyncCopperLayers( m_physicalStackup->GetCopperLayerCount() ); + } + + if( Prj().IsReadOnly() ) + { KIUI::Disable( m_treebook->GetPage( page ) ); + } } m_currentPage = page; @@ -437,6 +476,14 @@ void DIALOG_BOARD_SETUP::onAuxiliaryAction( wxCommandEvent& aEvent ) m_severitiesPage )->ImportSettingsFrom( otherSettings.m_DRCSeverities ); } + if( importDlg.m_TimeDomainParametersOpt->GetValue() ) + { + PROJECT_FILE& otherProjectFile = otherPrj->GetProjectFile(); + + RESOLVE_PAGE( PANEL_SETUP_TIME_DOMAIN_PARAMETERS, m_timeDomainParametersPage ) + ->ImportSettingsFrom( otherProjectFile.TimeDomainParameters() ); + } + if( otherPrj != &m_frame->Prj() ) otherBoard->ClearProject(); } diff --git a/pcbnew/dialogs/dialog_board_setup.h b/pcbnew/dialogs/dialog_board_setup.h index 182634f45d..0ab9dbebbe 100644 --- a/pcbnew/dialogs/dialog_board_setup.h +++ b/pcbnew/dialogs/dialog_board_setup.h @@ -29,6 +29,7 @@ class PANEL_SETUP_CONSTRAINTS; class PANEL_SETUP_LAYERS; class PANEL_SETUP_TEXT_AND_GRAPHICS; class PANEL_SETUP_NETCLASSES; +class PANEL_SETUP_TIME_DOMAIN_PARAMETERS; class PANEL_SETUP_RULES; class PANEL_SETUP_TRACKS_AND_VIAS; class PANEL_SETUP_MASK_AND_PASTE; @@ -49,10 +50,12 @@ protected: void onPageChanged( wxBookCtrlEvent& aEvent ) override; void onAuxiliaryAction( wxCommandEvent& aEvent ) override; - PCB_EDIT_FRAME* m_frame; - PANEL_SETUP_LAYERS* m_layers; - PANEL_SETUP_BOARD_FINISH* m_boardFinish; - PANEL_SETUP_BOARD_STACKUP* m_physicalStackup; + PCB_EDIT_FRAME* m_frame; + PANEL_SETUP_LAYERS* m_layers; + PANEL_SETUP_BOARD_FINISH* m_boardFinish; + PANEL_SETUP_BOARD_STACKUP* m_physicalStackup; + PANEL_SETUP_TIME_DOMAIN_PARAMETERS* m_timeDomainParameters; + PANEL_SETUP_NETCLASSES* m_netClasses; private: size_t m_currentPage; // the current page index @@ -71,6 +74,7 @@ private: size_t m_customRulesPage; size_t m_severitiesPage; size_t m_embeddedFilesPage; + size_t m_timeDomainParametersPage; }; diff --git a/pcbnew/dialogs/dialog_import_settings.cpp b/pcbnew/dialogs/dialog_import_settings.cpp index 6e5b9a323a..3bcbe5a2fa 100644 --- a/pcbnew/dialogs/dialog_import_settings.cpp +++ b/pcbnew/dialogs/dialog_import_settings.cpp @@ -79,12 +79,12 @@ void DIALOG_IMPORT_SETTINGS::OnCheckboxClicked( wxCommandEvent& event ) bool DIALOG_IMPORT_SETTINGS::UpdateImportSettingsButton() { // Enable "Import Settings" button if at least one import option is selected - bool buttonEnableState = ( m_LayersOpt->IsChecked() || m_MaskAndPasteOpt->IsChecked() - || m_ConstraintsOpt->IsChecked() || m_NetclassesOpt->IsChecked() - || m_SeveritiesOpt->IsChecked() || m_TextAndGraphicsOpt->IsChecked() - || m_FormattingOpt->IsChecked() || m_TracksAndViasOpt->IsChecked() - || m_TuningPatternsOpt->IsChecked() || m_CustomRulesOpt->IsChecked() - || m_ComponentClassesOpt->IsChecked() ); + bool buttonEnableState = + ( m_LayersOpt->IsChecked() || m_MaskAndPasteOpt->IsChecked() || m_ConstraintsOpt->IsChecked() + || m_NetclassesOpt->IsChecked() || m_SeveritiesOpt->IsChecked() || m_TextAndGraphicsOpt->IsChecked() + || m_FormattingOpt->IsChecked() || m_TracksAndViasOpt->IsChecked() || m_TuningPatternsOpt->IsChecked() + || m_CustomRulesOpt->IsChecked() || m_ComponentClassesOpt->IsChecked() + || m_TimeDomainParametersOpt->IsChecked() ); m_sdbSizer1OK->Enable( buttonEnableState ); @@ -150,6 +150,7 @@ void DIALOG_IMPORT_SETTINGS::OnSelectAll( wxCommandEvent& event ) m_TeardropsOpt->SetValue( m_showSelectAllOnBtn ); m_TuningPatternsOpt->SetValue( m_showSelectAllOnBtn ); m_CustomRulesOpt->SetValue( m_showSelectAllOnBtn ); + m_TimeDomainParametersOpt->SetValue( m_showSelectAllOnBtn ); // Ensure "Import Settings" button state is enabled as appropriate UpdateImportSettingsButton(); diff --git a/pcbnew/dialogs/dialog_import_settings_base.cpp b/pcbnew/dialogs/dialog_import_settings_base.cpp index b35ec938c8..d8458317a8 100644 --- a/pcbnew/dialogs/dialog_import_settings_base.cpp +++ b/pcbnew/dialogs/dialog_import_settings_base.cpp @@ -78,6 +78,9 @@ DIALOG_IMPORT_SETTINGS_BASE::DIALOG_IMPORT_SETTINGS_BASE( wxWindow* parent, wxWi m_ComponentClassesOpt = new wxCheckBox( this, wxID_ANY, _("Component classes"), wxDefaultPosition, wxDefaultSize, 0 ); bLeftCol->Add( m_ComponentClassesOpt, 0, wxBOTTOM|wxLEFT|wxRIGHT, 5 ); + m_TimeDomainParametersOpt = new wxCheckBox( this, wxID_ANY, _("Time domain parameters"), wxDefaultPosition, wxDefaultSize, 0 ); + bLeftCol->Add( m_TimeDomainParametersOpt, 0, wxBOTTOM|wxLEFT|wxRIGHT, 5 ); + m_CustomRulesOpt = new wxCheckBox( this, wxID_ANY, _("Custom rules"), wxDefaultPosition, wxDefaultSize, 0 ); bLeftCol->Add( m_CustomRulesOpt, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); @@ -124,6 +127,7 @@ DIALOG_IMPORT_SETTINGS_BASE::DIALOG_IMPORT_SETTINGS_BASE( wxWindow* parent, wxWi m_TuningPatternsOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this ); m_NetclassesOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this ); m_ComponentClassesOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this ); + m_TimeDomainParametersOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this ); m_CustomRulesOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this ); m_SeveritiesOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this ); m_selectAllButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnSelectAll ), NULL, this ); @@ -141,6 +145,7 @@ DIALOG_IMPORT_SETTINGS_BASE::~DIALOG_IMPORT_SETTINGS_BASE() m_TuningPatternsOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this ); m_NetclassesOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this ); m_ComponentClassesOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this ); + m_TimeDomainParametersOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this ); m_CustomRulesOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this ); m_SeveritiesOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnCheckboxClicked ), NULL, this ); m_selectAllButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_IMPORT_SETTINGS_BASE::OnSelectAll ), NULL, this ); diff --git a/pcbnew/dialogs/dialog_import_settings_base.fbp b/pcbnew/dialogs/dialog_import_settings_base.fbp index 3e5eb8efa7..bf1a095a7e 100644 --- a/pcbnew/dialogs/dialog_import_settings_base.fbp +++ b/pcbnew/dialogs/dialog_import_settings_base.fbp @@ -1015,6 +1015,72 @@ OnCheckboxClicked + + 5 + wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Time domain parameters + + 0 + + + 0 + + 1 + m_TimeDomainParametersOpt + 1 + + + public + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnCheckboxClicked + + 5 wxBOTTOM|wxRIGHT|wxLEFT diff --git a/pcbnew/dialogs/dialog_import_settings_base.h b/pcbnew/dialogs/dialog_import_settings_base.h index 0ca977ed7a..dcc6fa3ad3 100644 --- a/pcbnew/dialogs/dialog_import_settings_base.h +++ b/pcbnew/dialogs/dialog_import_settings_base.h @@ -65,6 +65,7 @@ class DIALOG_IMPORT_SETTINGS_BASE : public DIALOG_SHIM wxCheckBox* m_TuningPatternsOpt; wxCheckBox* m_NetclassesOpt; wxCheckBox* m_ComponentClassesOpt; + wxCheckBox* m_TimeDomainParametersOpt; wxCheckBox* m_CustomRulesOpt; wxCheckBox* m_SeveritiesOpt; diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp index a352688087..3cbae03369 100644 --- a/pcbnew/dialogs/dialog_pad_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_properties.cpp @@ -117,10 +117,7 @@ void PCB_BASE_FRAME::ShowPadPropertiesDialog( PAD* aPad ) DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, PAD* aPad ) : - DIALOG_PAD_PROPERTIES_BASE( aParent ), - m_parent( aParent ), - m_initialized( false ), - m_editLayer( F_Cu ), + DIALOG_PAD_PROPERTIES_BASE( aParent ), m_parent( aParent ), m_initialized( false ), m_editLayer( F_Cu ), m_posX( aParent, m_posXLabel, m_posXCtrl, m_posXUnits ), m_posY( aParent, m_posYLabel, m_posYCtrl, m_posYUnits ), m_sizeX( aParent, m_sizeXLabel, m_sizeXCtrl, m_sizeXUnits ), @@ -128,21 +125,19 @@ DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, PAD* aPad m_offsetX( aParent, m_offsetXLabel, m_offsetXCtrl, m_offsetXUnits ), m_offsetY( aParent, m_offsetYLabel, m_offsetYCtrl, m_offsetYUnits ), m_padToDie( aParent, m_padToDieLabel, m_padToDieCtrl, m_padToDieUnits ), + m_padToDieDelay( aParent, m_padToDieDelayLabel, m_padToDieDelayCtrl, m_padToDieDelayUnits ), m_trapDelta( aParent, m_trapDeltaLabel, m_trapDeltaCtrl, m_trapDeltaUnits ), m_cornerRadius( aParent, m_cornerRadiusLabel, m_cornerRadiusCtrl, m_cornerRadiusUnits ), m_cornerRatio( aParent, m_cornerRatioLabel, m_cornerRatioCtrl, m_cornerRatioUnits ), m_chamferRatio( aParent, m_chamferRatioLabel, m_chamferRatioCtrl, m_chamferRatioUnits ), - m_mixedCornerRatio( aParent, m_mixedCornerRatioLabel, m_mixedCornerRatioCtrl, - m_mixedCornerRatioUnits ), - m_mixedChamferRatio( aParent, m_mixedChamferRatioLabel, m_mixedChamferRatioCtrl, - m_mixedChamferRatioUnits ), + m_mixedCornerRatio( aParent, m_mixedCornerRatioLabel, m_mixedCornerRatioCtrl, m_mixedCornerRatioUnits ), + m_mixedChamferRatio( aParent, m_mixedChamferRatioLabel, m_mixedChamferRatioCtrl, m_mixedChamferRatioUnits ), m_holeX( aParent, m_holeXLabel, m_holeXCtrl, m_holeXUnits ), m_holeY( aParent, m_holeYLabel, m_holeYCtrl, m_holeYUnits ), m_clearance( aParent, m_clearanceLabel, m_clearanceCtrl, m_clearanceUnits ), m_maskMargin( aParent, m_maskMarginLabel, m_maskMarginCtrl, m_maskMarginUnits ), m_pasteMargin( aParent, m_pasteMarginLabel, m_pasteMarginCtrl, m_pasteMarginUnits ), - m_pasteMarginRatio( aParent, m_pasteMarginRatioLabel, m_pasteMarginRatioCtrl, - m_pasteMarginRatioUnits ), + m_pasteMarginRatio( aParent, m_pasteMarginRatioLabel, m_pasteMarginRatioCtrl, m_pasteMarginRatioUnits ), m_thermalGap( aParent, m_thermalGapLabel, m_thermalGapCtrl, m_thermalGapUnits ), m_spokeWidth( aParent, m_spokeWidthLabel, m_spokeWidthCtrl, m_spokeWidthUnits ), m_spokeAngle( aParent, m_spokeAngleLabel, m_spokeAngleCtrl, m_spokeAngleUnits ), @@ -230,6 +225,8 @@ DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, PAD* aPad m_pasteMarginRatio.SetUnits( EDA_UNITS::PERCENT ); m_pasteMarginRatio.SetNegativeZero(); + m_padToDieDelay.SetUnits( EDA_UNITS::PS ); + initValues(); wxFont infoFont = KIUI::GetInfoFont( this ); @@ -652,6 +649,9 @@ void DIALOG_PAD_PROPERTIES::initValues() m_padToDieOpt->SetValue( m_previewPad->GetPadToDieLength() != 0 ); m_padToDie.ChangeValue( m_previewPad->GetPadToDieLength() ); + m_padToDieDelayOpt->SetValue( m_previewPad->GetPadToDieDelay() != 0 ); + m_padToDieDelay.ChangeValue( m_previewPad->GetPadToDieDelay() ); + if( m_previewPad->GetLocalClearance().has_value() ) m_clearance.ChangeValue( m_previewPad->GetLocalClearance().value() ); else @@ -1147,6 +1147,7 @@ void DIALOG_PAD_PROPERTIES::PadTypeSelected( wxCommandEvent& event ) m_padNumCtrl->ChangeValue( wxEmptyString ); m_padNetSelector->SetSelectedNetcode( 0 ); m_padToDieOpt->SetValue( false ); + m_padToDieDelayOpt->SetValue( false ); } else if( m_padNumCtrl->GetValue().IsEmpty() && m_currentPad ) { @@ -1212,14 +1213,19 @@ void DIALOG_PAD_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event ) // Enable/disable pad length-to-die m_padToDieOpt->Enable( hasConnection ); + m_padToDieDelayOpt->Enable( hasConnection ); if( !m_padToDieOpt->IsEnabled() ) m_padToDieOpt->SetValue( false ); + if( !m_padToDieDelayOpt->IsEnabled() ) + m_padToDieDelayOpt->SetValue( false ); + // We can show/hide this here because it doesn't require the layout to be refreshed. // All the others have to be done in their event handlers because doing a layout here // causes infinite looping on MSW. m_padToDie.Show( m_padToDieOpt->GetValue() ); + m_padToDieDelay.Show( m_padToDieDelayOpt->GetValue() ); // Enable/disable Copper Layers control m_rbCopperLayersSel->Enable( m_padType->GetSelection() != APERTURE_DLG_TYPE ); @@ -1574,6 +1580,7 @@ bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow() m_currentPad->SetAttribute( m_masterPad->GetAttribute() ); m_currentPad->SetFPRelativeOrientation( m_masterPad->GetOrientation() ); m_currentPad->SetPadToDieLength( m_masterPad->GetPadToDieLength() ); + m_currentPad->SetPadToDieDelay( m_masterPad->GetPadToDieDelay() ); m_currentPad->SetLayerSet( m_masterPad->GetLayerSet() ); m_currentPad->SetNumber( m_masterPad->GetNumber() ); @@ -1839,6 +1846,11 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( PAD* aPad ) else aPad->SetPadToDieLength( 0 ); + if( m_padToDieDelayOpt->GetValue() ) + aPad->SetPadToDieDelay( m_padToDieDelay.GetIntValue() ); + else + aPad->SetPadToDieDelay( 0 ); + aPad->SetNumber( m_padNumCtrl->GetValue() ); aPad->SetNetCode( m_padNetSelector->GetSelectedNetcode() ); @@ -2068,6 +2080,15 @@ void DIALOG_PAD_PROPERTIES::OnPadToDieCheckbox( wxCommandEvent& event ) } +void DIALOG_PAD_PROPERTIES::OnPadToDieDelayCheckbox( wxCommandEvent& event ) +{ + if( m_padToDieDelayOpt->GetValue() && m_currentPad ) + m_padToDieDelay.SetValue( m_currentPad->GetPadToDieDelay() ); + + OnValuesChanged( event ); +} + + void DIALOG_PAD_PROPERTIES::onModify( wxSpinDoubleEvent& aEvent ) { if( m_initialized ) diff --git a/pcbnew/dialogs/dialog_pad_properties.h b/pcbnew/dialogs/dialog_pad_properties.h index b9f8b6449b..58a2db18e0 100644 --- a/pcbnew/dialogs/dialog_pad_properties.h +++ b/pcbnew/dialogs/dialog_pad_properties.h @@ -88,6 +88,7 @@ private: void onChangePadMode( wxCommandEvent& event ) override; void OnOffsetCheckbox( wxCommandEvent& event ) override; void OnPadToDieCheckbox( wxCommandEvent& event ) override; + void OnPadToDieDelayCheckbox( wxCommandEvent& event ) override; void PadOrientEvent( wxCommandEvent& event ) override; void PadTypeSelected( wxCommandEvent& event ) override; @@ -155,6 +156,7 @@ private: UNIT_BINDER m_sizeX, m_sizeY; UNIT_BINDER m_offsetX, m_offsetY; UNIT_BINDER m_padToDie; + UNIT_BINDER m_padToDieDelay; UNIT_BINDER m_trapDelta; UNIT_BINDER m_cornerRadius; UNIT_BINDER m_cornerRatio; diff --git a/pcbnew/dialogs/dialog_pad_properties_base.cpp b/pcbnew/dialogs/dialog_pad_properties_base.cpp index fa22d4bbe1..219e8ddd45 100644 --- a/pcbnew/dialogs/dialog_pad_properties_base.cpp +++ b/pcbnew/dialogs/dialog_pad_properties_base.cpp @@ -501,6 +501,26 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind m_padToDieUnits->Wrap( -1 ); fgSizerPadToDie->Add( m_padToDieUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRESERVE_SPACE_EVEN_IF_HIDDEN|wxRIGHT, 5 ); + wxBoxSizer* bSizer341; + bSizer341 = new wxBoxSizer( wxHORIZONTAL ); + + m_padToDieDelayOpt = new wxCheckBox( m_panelGeneral, wxID_ANY, _("Specify pad to die delay"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer341->Add( m_padToDieDelayOpt, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); + + m_padToDieDelayLabel = new wxStaticText( m_panelGeneral, wxID_ANY, _(":"), wxDefaultPosition, wxDefaultSize, 0 ); + m_padToDieDelayLabel->Wrap( -1 ); + bSizer341->Add( m_padToDieDelayLabel, 0, wxALIGN_CENTER_VERTICAL|wxRESERVE_SPACE_EVEN_IF_HIDDEN, 5 ); + + + fgSizerPadToDie->Add( bSizer341, 1, wxEXPAND, 5 ); + + m_padToDieDelayCtrl = new wxTextCtrl( m_panelGeneral, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + fgSizerPadToDie->Add( m_padToDieDelayCtrl, 0, wxEXPAND|wxLEFT|wxRESERVE_SPACE_EVEN_IF_HIDDEN|wxTOP, 5 ); + + m_padToDieDelayUnits = new wxStaticText( m_panelGeneral, wxID_ANY, _("ps"), wxDefaultPosition, wxDefaultSize, 0 ); + m_padToDieDelayUnits->Wrap( -1 ); + fgSizerPadToDie->Add( m_padToDieDelayUnits, 0, wxALL, 5 ); + m_LeftBoxSizer->Add( fgSizerPadToDie, 0, wxEXPAND, 5 ); @@ -1268,6 +1288,7 @@ DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE( wxWindow* parent, wxWind m_holeXCtrl->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this ); m_holeYCtrl->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this ); m_padToDieOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnPadToDieCheckbox ), NULL, this ); + m_padToDieDelayOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnPadToDieDelayCheckbox ), NULL, this ); m_rbCopperLayersSel->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnSetCopperLayers ), NULL, this ); m_layerFrontAdhesive->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnSetLayers ), NULL, this ); m_layerBackAdhesive->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnSetLayers ), NULL, this ); @@ -1355,6 +1376,7 @@ DIALOG_PAD_PROPERTIES_BASE::~DIALOG_PAD_PROPERTIES_BASE() m_holeXCtrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this ); m_holeYCtrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnValuesChanged ), NULL, this ); m_padToDieOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnPadToDieCheckbox ), NULL, this ); + m_padToDieDelayOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnPadToDieDelayCheckbox ), NULL, this ); m_rbCopperLayersSel->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnSetCopperLayers ), NULL, this ); m_layerFrontAdhesive->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnSetLayers ), NULL, this ); m_layerBackAdhesive->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PAD_PROPERTIES_BASE::OnSetLayers ), NULL, this ); diff --git a/pcbnew/dialogs/dialog_pad_properties_base.fbp b/pcbnew/dialogs/dialog_pad_properties_base.fbp index 74a87d9cdb..2ebc500c7c 100644 --- a/pcbnew/dialogs/dialog_pad_properties_base.fbp +++ b/pcbnew/dialogs/dialog_pad_properties_base.fbp @@ -5694,11 +5694,11 @@ - + 5 wxEXPAND 0 - + 3 wxBOTH 1 @@ -5710,7 +5710,7 @@ none 14 0 - + 5 wxEXPAND|wxRIGHT 0 @@ -5976,6 +5976,272 @@ -1 + + 5 + wxEXPAND + 1 + + + bSizer341 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxLEFT + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Specify pad to die delay + + 0 + + + 0 + + 1 + m_padToDieDelayOpt + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnPadToDieDelayCheckbox + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRESERVE_SPACE_EVEN_IF_HIDDEN + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + : + 0 + + 0 + + + 0 + + 1 + m_padToDieDelayLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + + + 5 + wxEXPAND|wxLEFT|wxRESERVE_SPACE_EVEN_IF_HIDDEN|wxTOP + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_padToDieDelayCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + ps + 0 + + 0 + + + 0 + + 1 + m_padToDieDelayUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + diff --git a/pcbnew/dialogs/dialog_pad_properties_base.h b/pcbnew/dialogs/dialog_pad_properties_base.h index b7ff06db55..3ab373cd11 100644 --- a/pcbnew/dialogs/dialog_pad_properties_base.h +++ b/pcbnew/dialogs/dialog_pad_properties_base.h @@ -147,6 +147,10 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM wxStaticText* m_padToDieLabel; wxTextCtrl* m_padToDieCtrl; wxStaticText* m_padToDieUnits; + wxCheckBox* m_padToDieDelayOpt; + wxStaticText* m_padToDieDelayLabel; + wxTextCtrl* m_padToDieDelayCtrl; + wxStaticText* m_padToDieDelayUnits; wxBoxSizer* m_middleBoxSizer; wxBoxSizer* m_FlippedWarningSizer; wxStaticBitmap* m_FlippedWarningIcon; @@ -273,6 +277,7 @@ class DIALOG_PAD_PROPERTIES_BASE : public DIALOG_SHIM virtual void OnOffsetCheckbox( wxCommandEvent& event ) { event.Skip(); } virtual void OnDrillShapeSelected( wxCommandEvent& event ) { event.Skip(); } virtual void OnPadToDieCheckbox( wxCommandEvent& event ) { event.Skip(); } + virtual void OnPadToDieDelayCheckbox( wxCommandEvent& event ) { event.Skip(); } virtual void OnSetCopperLayers( wxCommandEvent& event ) { event.Skip(); } virtual void onModify( wxCommandEvent& event ) { event.Skip(); } virtual void onTeardropsUpdateUi( wxUpdateUIEvent& event ) { event.Skip(); } diff --git a/pcbnew/dialogs/dialog_tuning_pattern_properties.cpp b/pcbnew/dialogs/dialog_tuning_pattern_properties.cpp index 4f1cdf5c9c..99547e6f96 100644 --- a/pcbnew/dialogs/dialog_tuning_pattern_properties.cpp +++ b/pcbnew/dialogs/dialog_tuning_pattern_properties.cpp @@ -18,26 +18,27 @@ */ #include "dialog_tuning_pattern_properties.h" + +#include #include #include #include #include -DIALOG_TUNING_PATTERN_PROPERTIES::DIALOG_TUNING_PATTERN_PROPERTIES( PCB_BASE_EDIT_FRAME* aFrame, +DIALOG_TUNING_PATTERN_PROPERTIES::DIALOG_TUNING_PATTERN_PROPERTIES( PCB_BASE_EDIT_FRAME* aFrame, PNS::MEANDER_SETTINGS& aSettings, - PNS::ROUTER_MODE aMeanderType, - const DRC_CONSTRAINT& aConstraint ) : - DIALOG_TUNING_PATTERN_PROPERTIES_BASE( aFrame ), - m_constraint( aConstraint ), + PNS::ROUTER_MODE aMeanderType, + const DRC_CONSTRAINT& aConstraint ) : + DIALOG_TUNING_PATTERN_PROPERTIES_BASE( aFrame ), m_constraint( aConstraint ), m_targetLength( aFrame, m_targetLengthLabel, m_targetLengthCtrl, m_targetLengthUnits ), + m_targetDelay( aFrame, m_targetDelayLabel, m_targetDelayCtrl, m_targetDelayUnits ), m_minA( aFrame, m_track_minALabel, m_minACtrl, m_minAUnits ), m_maxA( aFrame, m_maxALabel, m_maxACtrl, m_maxAUnits ), - m_spacing( aFrame, m_spacingLabel, m_spacingCtrl, m_spacingUnits ), - m_r( aFrame, m_rLabel, m_rCtrl, m_rUnits ), - m_settings( aSettings ), - m_mode( aMeanderType ) + m_spacing( aFrame, m_spacingLabel, m_spacingCtrl, m_spacingUnits ), m_r( aFrame, m_rLabel, m_rCtrl, m_rUnits ), + m_settings( aSettings ), m_mode( aMeanderType ) { + m_targetDelay.SetUnits( EDA_UNITS::PS ); m_r.SetUnits( EDA_UNITS::PERCENT ); switch( m_mode ) @@ -52,7 +53,8 @@ DIALOG_TUNING_PATTERN_PROPERTIES::DIALOG_TUNING_PATTERN_PROPERTIES( PCB_BASE_EDI case PNS::PNS_MODE_TUNE_DIFF_PAIR_SKEW: m_legend->SetBitmap( KiBitmapBundle( BITMAPS::tune_diff_pair_skew_legend ) ); - m_targetLengthLabel->SetLabel( _( "Target skew: ") ); + m_targetLengthLabel->SetLabel( _( "Target Skew: " ) ); + m_targetDelayLabel->SetLabel( _( "Target Skew Delay: " ) ); break; default: @@ -74,22 +76,54 @@ bool DIALOG_TUNING_PATTERN_PROPERTIES::TransferDataToWindow() { if( m_mode == PNS::PNS_MODE_TUNE_DIFF_PAIR_SKEW ) { - m_targetLength.SetValue( m_settings.m_targetSkew.Opt() ); - - if( m_targetLength.GetValue() == PNS::MEANDER_SETTINGS::SKEW_UNCONSTRAINED ) + if( m_settings.m_isTimeDomain ) + { m_targetLength.SetValue( wxEmptyString ); + m_targetDelay.SetValue( m_settings.m_targetSkewDelay.Opt() ); + + if( m_targetDelay.GetValue() == PNS::MEANDER_SETTINGS::SKEW_UNCONSTRAINED ) + m_targetDelay.SetValue( wxEmptyString ); + } + else + { + m_targetDelay.SetValue( wxEmptyString ); + m_targetLength.SetValue( m_settings.m_targetSkew.Opt() ); + + if( m_targetLength.GetValue() == PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED ) + m_targetLength.SetValue( wxEmptyString ); + } } else { - m_targetLength.SetValue( m_settings.m_targetLength.Opt() ); - - if( m_targetLength.GetValue() == PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED ) + if( m_settings.m_isTimeDomain ) + { m_targetLength.SetValue( wxEmptyString ); + m_targetDelay.SetValue( m_settings.m_targetLengthDelay.Opt() ); + + if( m_targetDelay.GetValue() == PNS::MEANDER_SETTINGS::DELAY_UNCONSTRAINED ) + m_targetDelay.SetValue( wxEmptyString ); + } + else + { + m_targetDelay.SetValue( wxEmptyString ); + m_targetLength.SetValue( m_settings.m_targetLength.Opt() ); + + if( m_targetLength.GetValue() == PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED ) + m_targetLength.SetValue( wxEmptyString ); + } } m_overrideCustomRules->SetValue( m_settings.m_overrideCustomRules ); - m_targetLength.Enable( m_constraint.IsNull() || m_settings.m_overrideCustomRules ); + m_targetLength.Enable( ( m_constraint.IsNull() || m_settings.m_overrideCustomRules ) + && !m_settings.m_isTimeDomain ); + m_targetDelay.Enable( ( m_constraint.IsNull() || m_settings.m_overrideCustomRules ) && m_settings.m_isTimeDomain ); + + m_radioBtnLength->Enable( m_constraint.IsNull() || m_settings.m_overrideCustomRules ); + m_radioBtnDelay->Enable( m_constraint.IsNull() || m_settings.m_overrideCustomRules ); + + m_radioBtnLength->SetValue( !m_settings.m_isTimeDomain ); + m_radioBtnDelay->SetValue( m_settings.m_isTimeDomain ); if( !m_constraint.IsNull() ) m_sourceInfo->SetLabel( wxString::Format( _( "(from %s)" ), m_constraint.GetName() ) ); @@ -122,24 +156,52 @@ bool DIALOG_TUNING_PATTERN_PROPERTIES::TransferDataFromWindow() m_settings.SetTargetSkew( lastTargetSkew ); else m_settings.m_targetSkew = m_constraint.GetValue(); + + if( m_targetDelayCtrl->GetValue().IsEmpty() ) + lastTargetSkew = PNS::MEANDER_SETTINGS::SKEW_UNCONSTRAINED; + else + lastTargetSkew = m_targetDelay.GetIntValue(); + + if( lastTargetSkew != m_constraint.GetValue().Opt() ) + m_settings.SetTargetSkewDelay( lastTargetSkew ); + else + m_settings.SetTargetSkewDelay( m_constraint.GetValue() ); } else { - long long int lastTargetLength = PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED; + long long int lastTarget = PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED; if( m_targetLengthCtrl->GetValue().IsEmpty() ) - lastTargetLength = PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED; + lastTarget = PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED; else - lastTargetLength = m_targetLength.GetIntValue(); + lastTarget = m_targetLength.GetIntValue(); - if( lastTargetLength != m_constraint.GetValue().Opt() ) - m_settings.SetTargetLength( lastTargetLength ); + if( lastTarget != m_constraint.GetValue().Opt() ) + m_settings.SetTargetLength( lastTarget ); else m_settings.SetTargetLength( m_constraint.GetValue() ); + + if( m_targetDelayCtrl->GetValue().IsEmpty() ) + lastTarget = PNS::MEANDER_SETTINGS::DELAY_UNCONSTRAINED; + else + lastTarget = m_targetDelay.GetIntValue(); + + if( lastTarget != m_constraint.GetValue().Opt() ) + m_settings.SetTargetLengthDelay( lastTarget ); + else + m_settings.SetTargetLengthDelay( m_constraint.GetValue() ); } m_settings.m_overrideCustomRules = m_overrideCustomRules->GetValue(); + if( m_radioBtnLength->IsEnabled() ) + { + if( m_radioBtnLength->GetValue() ) + m_settings.m_isTimeDomain = false; + else + m_settings.m_isTimeDomain = true; + } + m_settings.m_minAmplitude = m_minA.GetIntValue(); m_settings.m_maxAmplitude = m_maxA.GetIntValue(); m_settings.m_spacing = m_spacing.GetIntValue(); @@ -154,11 +216,24 @@ bool DIALOG_TUNING_PATTERN_PROPERTIES::TransferDataFromWindow() void DIALOG_TUNING_PATTERN_PROPERTIES::onOverrideCustomRules( wxCommandEvent& event ) { - m_targetLength.Enable( event.IsChecked() || m_constraint.IsNull() ); + m_targetLength.Enable( ( event.IsChecked() || m_constraint.IsNull() ) && !m_settings.m_isTimeDomain ); + m_targetDelay.Enable( ( event.IsChecked() || m_constraint.IsNull() ) && m_settings.m_isTimeDomain ); + m_radioBtnLength->Enable( event.IsChecked() || m_constraint.IsNull() ); + m_radioBtnDelay->Enable( event.IsChecked() || m_constraint.IsNull() ); if( !event.IsChecked() && !m_constraint.IsNull() ) { - m_targetLength.SetValue( m_constraint.GetValue().Opt() ); + if( m_constraint.GetOption( DRC_CONSTRAINT::OPTIONS::SPACE_DOMAIN ) ) + { + m_targetLength.SetValue( m_constraint.GetValue().Opt() ); + m_targetDelay.SetValue( wxEmptyString ); + } + else + { + m_targetLength.SetValue( wxEmptyString ); + m_targetDelay.SetValue( m_constraint.GetValue().Opt() ); + } + m_sourceInfo->Show( true ); } else @@ -166,3 +241,23 @@ void DIALOG_TUNING_PATTERN_PROPERTIES::onOverrideCustomRules( wxCommandEvent& ev m_sourceInfo->Show( false ); } } + + +void DIALOG_TUNING_PATTERN_PROPERTIES::onRadioBtnTargetLengthClick( wxCommandEvent& event ) +{ + if( event.IsChecked() ) + { + m_targetLength.Enable( true ); + m_targetDelay.Enable( false ); + } +} + + +void DIALOG_TUNING_PATTERN_PROPERTIES::onRadioBtnTargetDelayClick( wxCommandEvent& event ) +{ + if( event.IsChecked() ) + { + m_targetLength.Enable( false ); + m_targetDelay.Enable( true ); + } +} diff --git a/pcbnew/dialogs/dialog_tuning_pattern_properties.h b/pcbnew/dialogs/dialog_tuning_pattern_properties.h index 9db89a2ba9..d9709e1f15 100644 --- a/pcbnew/dialogs/dialog_tuning_pattern_properties.h +++ b/pcbnew/dialogs/dialog_tuning_pattern_properties.h @@ -49,11 +49,14 @@ private: bool TransferDataFromWindow() override; void onOverrideCustomRules( wxCommandEvent& event ) override; + void onRadioBtnTargetLengthClick( wxCommandEvent& event ) override; + void onRadioBtnTargetDelayClick( wxCommandEvent& event ) override; private: const DRC_CONSTRAINT& m_constraint; UNIT_BINDER m_targetLength; + UNIT_BINDER m_targetDelay; UNIT_BINDER m_minA; UNIT_BINDER m_maxA; UNIT_BINDER m_spacing; diff --git a/pcbnew/dialogs/dialog_tuning_pattern_properties_base.cpp b/pcbnew/dialogs/dialog_tuning_pattern_properties_base.cpp index feae00259d..474a9f40e2 100644 --- a/pcbnew/dialogs/dialog_tuning_pattern_properties_base.cpp +++ b/pcbnew/dialogs/dialog_tuning_pattern_properties_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf) +// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -28,9 +28,19 @@ DIALOG_TUNING_PATTERN_PROPERTIES_BASE::DIALOG_TUNING_PATTERN_PROPERTIES_BASE( wx gbSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); gbSizer1->SetEmptyCellSize( wxSize( 10,8 ) ); - m_targetLengthLabel = new wxStaticText( this, wxID_ANY, _("Target length:"), wxDefaultPosition, wxDefaultSize, 0 ); + wxBoxSizer* bSizer3; + bSizer3 = new wxBoxSizer( wxHORIZONTAL ); + + m_radioBtnLength = new wxRadioButton( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_radioBtnLength->SetValue( true ); + bSizer3->Add( m_radioBtnLength, 0, wxALL, 5 ); + + m_targetLengthLabel = new wxStaticText( this, wxID_ANY, _("Target Length:"), wxDefaultPosition, wxDefaultSize, 0 ); m_targetLengthLabel->Wrap( -1 ); - gbSizer1->Add( m_targetLengthLabel, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); + bSizer3->Add( m_targetLengthLabel, 0, wxALL, 5 ); + + + gbSizer1->Add( bSizer3, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), 0, 5 ); m_targetLengthCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); gbSizer1->Add( m_targetLengthCtrl, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 ); @@ -39,75 +49,95 @@ DIALOG_TUNING_PATTERN_PROPERTIES_BASE::DIALOG_TUNING_PATTERN_PROPERTIES_BASE( wx m_targetLengthUnits->Wrap( -1 ); gbSizer1->Add( m_targetLengthUnits, wxGBPosition( 0, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); + wxBoxSizer* bSizer31; + bSizer31 = new wxBoxSizer( wxHORIZONTAL ); + + m_radioBtnDelay = new wxRadioButton( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + bSizer31->Add( m_radioBtnDelay, 0, wxALL, 5 ); + + m_targetDelayLabel = new wxStaticText( this, wxID_ANY, _("Target Delay:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_targetDelayLabel->Wrap( -1 ); + bSizer31->Add( m_targetDelayLabel, 0, wxALL, 5 ); + + + gbSizer1->Add( bSizer31, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), 0, 5 ); + + m_targetDelayCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + gbSizer1->Add( m_targetDelayCtrl, wxGBPosition( 1, 1 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 ); + + m_targetDelayUnits = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_targetDelayUnits->Wrap( -1 ); + gbSizer1->Add( m_targetDelayUnits, wxGBPosition( 1, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); + m_overrideCustomRules = new wxCheckBox( this, wxID_ANY, _("Override custom rules"), wxDefaultPosition, wxDefaultSize, 0 ); gbSizer1->Add( m_overrideCustomRules, wxGBPosition( 0, 4 ), wxGBSpan( 1, 3 ), wxALIGN_CENTER_VERTICAL, 5 ); m_sourceInfo = new wxStaticText( this, wxID_ANY, _("(from 'rule name')"), wxDefaultPosition, wxDefaultSize, 0 ); m_sourceInfo->Wrap( -1 ); - gbSizer1->Add( m_sourceInfo, wxGBPosition( 1, 1 ), wxGBSpan( 1, 6 ), wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer1->Add( m_sourceInfo, wxGBPosition( 2, 1 ), wxGBSpan( 1, 6 ), wxALIGN_CENTER_VERTICAL, 5 ); m_track_minALabel = new wxStaticText( this, wxID_ANY, _("Minimum amplitude (A):"), wxDefaultPosition, wxDefaultSize, 0 ); m_track_minALabel->Wrap( -1 ); - gbSizer1->Add( m_track_minALabel, wxGBPosition( 4, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 1 ); + gbSizer1->Add( m_track_minALabel, wxGBPosition( 5, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 1 ); m_minACtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); - gbSizer1->Add( m_minACtrl, wxGBPosition( 4, 1 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 ); + gbSizer1->Add( m_minACtrl, wxGBPosition( 5, 1 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 ); m_minAUnits = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); m_minAUnits->Wrap( -1 ); - gbSizer1->Add( m_minAUnits, wxGBPosition( 4, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer1->Add( m_minAUnits, wxGBPosition( 5, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); m_maxALabel = new wxStaticText( this, wxID_ANY, _("Maximum amplitude (A):"), wxDefaultPosition, wxDefaultSize, 0 ); m_maxALabel->Wrap( -1 ); - gbSizer1->Add( m_maxALabel, wxGBPosition( 4, 4 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer1->Add( m_maxALabel, wxGBPosition( 5, 4 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); m_maxACtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); - gbSizer1->Add( m_maxACtrl, wxGBPosition( 4, 5 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 ); + gbSizer1->Add( m_maxACtrl, wxGBPosition( 5, 5 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 ); m_maxAUnits = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); m_maxAUnits->Wrap( -1 ); - gbSizer1->Add( m_maxAUnits, wxGBPosition( 4, 6 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer1->Add( m_maxAUnits, wxGBPosition( 5, 6 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); m_spacingLabel = new wxStaticText( this, wxID_ANY, _("Spacing (s):"), wxDefaultPosition, wxDefaultSize, 0 ); m_spacingLabel->Wrap( -1 ); - gbSizer1->Add( m_spacingLabel, wxGBPosition( 5, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 1 ); + gbSizer1->Add( m_spacingLabel, wxGBPosition( 6, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 1 ); m_spacingCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); m_spacingCtrl->SetToolTip( _("Minimum spacing between adjacent tuning segments. The resulting spacing may be greater based on design rules.") ); - gbSizer1->Add( m_spacingCtrl, wxGBPosition( 5, 1 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 ); + gbSizer1->Add( m_spacingCtrl, wxGBPosition( 6, 1 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 ); m_spacingUnits = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); m_spacingUnits->Wrap( -1 ); - gbSizer1->Add( m_spacingUnits, wxGBPosition( 5, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer1->Add( m_spacingUnits, wxGBPosition( 6, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); m_cornerLabel = new wxStaticText( this, wxID_ANY, _("Corner style:"), wxDefaultPosition, wxDefaultSize, 0 ); m_cornerLabel->Wrap( -1 ); - gbSizer1->Add( m_cornerLabel, wxGBPosition( 7, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 1 ); + gbSizer1->Add( m_cornerLabel, wxGBPosition( 8, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 1 ); wxString m_cornerCtrlChoices[] = { _("Chamfer"), _("Fillet") }; int m_cornerCtrlNChoices = sizeof( m_cornerCtrlChoices ) / sizeof( wxString ); m_cornerCtrl = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_cornerCtrlNChoices, m_cornerCtrlChoices, 0 ); m_cornerCtrl->SetSelection( 0 ); - gbSizer1->Add( m_cornerCtrl, wxGBPosition( 7, 1 ), wxGBSpan( 1, 2 ), wxEXPAND, 5 ); + gbSizer1->Add( m_cornerCtrl, wxGBPosition( 8, 1 ), wxGBSpan( 1, 2 ), wxEXPAND, 5 ); m_rLabel = new wxStaticText( this, wxID_ANY, _("Radius (r):"), wxDefaultPosition, wxDefaultSize, 0 ); m_rLabel->Wrap( -1 ); - gbSizer1->Add( m_rLabel, wxGBPosition( 7, 4 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer1->Add( m_rLabel, wxGBPosition( 8, 4 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); m_rCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); - gbSizer1->Add( m_rCtrl, wxGBPosition( 7, 5 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 ); + gbSizer1->Add( m_rCtrl, wxGBPosition( 8, 5 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 ); m_rUnits = new wxStaticText( this, wxID_ANY, _("%"), wxDefaultPosition, wxDefaultSize, 0 ); m_rUnits->Wrap( -1 ); - gbSizer1->Add( m_rUnits, wxGBPosition( 7, 6 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer1->Add( m_rUnits, wxGBPosition( 8, 6 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); m_singleSided = new wxCheckBox( this, wxID_ANY, _("Single-sided"), wxDefaultPosition, wxDefaultSize, 0 ); - gbSizer1->Add( m_singleSided, wxGBPosition( 8, 1 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL, 5 ); + gbSizer1->Add( m_singleSided, wxGBPosition( 9, 1 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL, 5 ); gbSizer1->AddGrowableCol( 1 ); - gbSizer1->AddGrowableCol( 4 ); + gbSizer1->AddGrowableCol( 5 ); singleTrackSizer->Add( gbSizer1, 1, wxEXPAND, 5 ); @@ -129,12 +159,16 @@ DIALOG_TUNING_PATTERN_PROPERTIES_BASE::DIALOG_TUNING_PATTERN_PROPERTIES_BASE( wx bMainSizer->Fit( this ); // Connect Events + m_radioBtnLength->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_TUNING_PATTERN_PROPERTIES_BASE::onRadioBtnTargetLengthClick ), NULL, this ); + m_radioBtnDelay->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_TUNING_PATTERN_PROPERTIES_BASE::onRadioBtnTargetDelayClick ), NULL, this ); m_overrideCustomRules->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_TUNING_PATTERN_PROPERTIES_BASE::onOverrideCustomRules ), NULL, this ); } DIALOG_TUNING_PATTERN_PROPERTIES_BASE::~DIALOG_TUNING_PATTERN_PROPERTIES_BASE() { // Disconnect Events + m_radioBtnLength->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_TUNING_PATTERN_PROPERTIES_BASE::onRadioBtnTargetLengthClick ), NULL, this ); + m_radioBtnDelay->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_TUNING_PATTERN_PROPERTIES_BASE::onRadioBtnTargetDelayClick ), NULL, this ); m_overrideCustomRules->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_TUNING_PATTERN_PROPERTIES_BASE::onOverrideCustomRules ), NULL, this ); } diff --git a/pcbnew/dialogs/dialog_tuning_pattern_properties_base.fbp b/pcbnew/dialogs/dialog_tuning_pattern_properties_base.fbp index 51422bc438..2aa3954c20 100644 --- a/pcbnew/dialogs/dialog_tuning_pattern_properties_base.fbp +++ b/pcbnew/dialogs/dialog_tuning_pattern_properties_base.fbp @@ -1,34 +1,36 @@ - + - C++ - 1 - source_name - 0 - 0 + + 1 + connect + none + + + 0 + 0 UTF-8 - connect dialog_tuning_pattern_properties_base 1000 - none - - 1 + 1 + UI DIALOG_TUNING_PATTERN_PROPERTIES_BASE - . - + 0 + source_name + 1 + 0 + source_name + + + 1 1 - 1 - 1 - 1 - UI - 0 - 0 0 + 0 0 wxAUI_MGR_DEFAULT @@ -80,10 +82,10 @@ 1 1 1 - + 0 - - + 0 + 0 Load From Resource; @@ -137,7 +139,7 @@ 10,8 wxBOTH - 1,4 + 1,5 4 @@ -149,65 +151,142 @@ 5 1 0 - wxALIGN_CENTER_VERTICAL + 0 1 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 0 - 1 - - 1 - - 0 - 0 - wxID_ANY - Target length: - 0 - - 0 - - - 0 + - 1 - m_targetLengthLabel - 1 - - - protected - 1 - - Resizable - 1 - - - ; ; forward_declare - 0 - - - - - -1 + bSizer3 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + + 0 + + + 0 + + 1 + m_radioBtnLength + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 1 + + + + onRadioBtnTargetLengthClick + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Target Length: + 0 + + 0 + + + 0 + + 1 + m_targetLengthLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + @@ -222,10 +301,10 @@ 1 1 1 - + 0 - - + 0 + 0 @@ -249,7 +328,7 @@ 0 - + 0 0 @@ -290,10 +369,10 @@ 1 1 1 - + 0 - - + 0 + 0 @@ -343,6 +422,281 @@ -1 + + 5 + 1 + 0 + + 1 + 1 + + + bSizer31 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + + 0 + + + 0 + + 1 + m_radioBtnDelay + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 0 + + + + onRadioBtnTargetDelayClick + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Target Delay: + 0 + + 0 + + + 0 + + 1 + m_targetDelayLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + + + 5 + 1 + 1 + wxEXPAND + 1 + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_targetDelayCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + 1 + 2 + wxALIGN_CENTER_VERTICAL + 1 + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + 0 + + 0 + + + 0 + + 1 + m_targetDelayUnits + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + 5 3 @@ -355,10 +709,10 @@ 1 1 1 - + 0 - - + 0 + 0 @@ -417,17 +771,17 @@ 6 1 wxALIGN_CENTER_VERTICAL - 1 + 2 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -482,17 +836,17 @@ 1 0 wxALIGN_CENTER_VERTICAL|wxLEFT - 4 + 5 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -547,17 +901,17 @@ 1 1 wxEXPAND - 4 + 5 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -581,7 +935,7 @@ 0 - + 0 0 @@ -615,17 +969,17 @@ 1 2 wxALIGN_CENTER_VERTICAL - 4 + 5 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -680,17 +1034,17 @@ 1 4 wxALIGN_CENTER_VERTICAL - 4 + 5 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -745,17 +1099,17 @@ 1 5 wxEXPAND - 4 + 5 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -779,7 +1133,7 @@ 0 - + 0 0 @@ -813,17 +1167,17 @@ 1 6 wxALIGN_CENTER_VERTICAL - 4 + 5 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -878,17 +1232,17 @@ 1 0 wxALIGN_CENTER_VERTICAL|wxLEFT - 5 + 6 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -943,17 +1297,17 @@ 1 1 wxEXPAND - 5 + 6 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -977,7 +1331,7 @@ 0 - + 0 0 @@ -1011,17 +1365,17 @@ 1 2 wxALIGN_CENTER_VERTICAL - 5 + 6 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -1076,17 +1430,17 @@ 1 0 wxALIGN_CENTER_VERTICAL|wxLEFT - 7 + 8 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -1141,17 +1495,17 @@ 2 1 wxEXPAND - 7 + 8 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -1209,17 +1563,17 @@ 1 4 wxALIGN_CENTER_VERTICAL - 7 + 8 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -1274,17 +1628,17 @@ 1 5 wxEXPAND - 7 + 8 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -1308,7 +1662,7 @@ 0 - + 0 0 @@ -1342,17 +1696,17 @@ 1 6 wxALIGN_CENTER_VERTICAL - 7 + 8 1 1 1 1 1 - + 0 - - + 0 + 0 @@ -1407,17 +1761,17 @@ 2 1 wxALIGN_CENTER_VERTICAL - 8 + 9 1 1 1 1 1 - + 0 - - + 0 + 0 diff --git a/pcbnew/dialogs/dialog_tuning_pattern_properties_base.h b/pcbnew/dialogs/dialog_tuning_pattern_properties_base.h index f382af2d4b..47bfa27ba7 100644 --- a/pcbnew/dialogs/dialog_tuning_pattern_properties_base.h +++ b/pcbnew/dialogs/dialog_tuning_pattern_properties_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf) +// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -20,18 +20,18 @@ #include #include #include +#include #include +#include #include #include #include #include -#include #include #include /////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// /// Class DIALOG_TUNING_PATTERN_PROPERTIES_BASE /////////////////////////////////////////////////////////////////////////////// @@ -41,9 +41,14 @@ class DIALOG_TUNING_PATTERN_PROPERTIES_BASE : public DIALOG_SHIM protected: wxStaticBitmap* m_legend; + wxRadioButton* m_radioBtnLength; wxStaticText* m_targetLengthLabel; wxTextCtrl* m_targetLengthCtrl; wxStaticText* m_targetLengthUnits; + wxRadioButton* m_radioBtnDelay; + wxStaticText* m_targetDelayLabel; + wxTextCtrl* m_targetDelayCtrl; + wxStaticText* m_targetDelayUnits; wxCheckBox* m_overrideCustomRules; wxStaticText* m_sourceInfo; wxStaticText* m_track_minALabel; @@ -66,6 +71,8 @@ class DIALOG_TUNING_PATTERN_PROPERTIES_BASE : public DIALOG_SHIM wxButton* m_stdButtonsCancel; // Virtual event handlers, override them in your derived class + virtual void onRadioBtnTargetLengthClick( wxCommandEvent& event ) { event.Skip(); } + virtual void onRadioBtnTargetDelayClick( wxCommandEvent& event ) { event.Skip(); } virtual void onOverrideCustomRules( wxCommandEvent& event ) { event.Skip(); } diff --git a/pcbnew/dialogs/panel_setup_time_domain_parameters.cpp b/pcbnew/dialogs/panel_setup_time_domain_parameters.cpp new file mode 100644 index 0000000000..5228d120e5 --- /dev/null +++ b/pcbnew/dialogs/panel_setup_time_domain_parameters.cpp @@ -0,0 +1,634 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +PANEL_SETUP_TIME_DOMAIN_PARAMETERS::PANEL_SETUP_TIME_DOMAIN_PARAMETERS( + wxWindow* aParentWindow, PCB_EDIT_FRAME* aFrame, BOARD* aBoard, + std::shared_ptr aTimeDomainParameters ) : + PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE( aParentWindow ), + m_timeDomainParameters( std::move( aTimeDomainParameters ) ), m_frame( aFrame ), m_board( aFrame->GetBoard() ) +{ + m_timeDomainParametersPane->SetBorders( true, false, false, false ); + + // Set up units + m_unitsProvider = std::make_unique( pcbIUScale, m_frame->GetUserUnits() ); + m_tracePropagationGrid->SetUnitsProvider( m_unitsProvider.get() ); + m_viaPropagationGrid->SetUnitsProvider( m_unitsProvider.get() ); + + Freeze(); + + m_splitter->SetMinimumPaneSize( FromDIP( m_splitter->GetMinimumPaneSize() ) ); + + // Set up the tuning profiles grid + m_tracePropagationGrid->BeginBatch(); + m_tracePropagationGrid->SetUseNativeColLabels(); + + m_tracePropagationGrid->EnsureColLabelsVisible(); + m_tracePropagationGrid->SetDefaultRowSize( m_tracePropagationGrid->GetDefaultRowSize() + 4 ); + m_tracePropagationGrid->PushEventHandler( new GRID_TRICKS( m_tracePropagationGrid ) ); + m_tracePropagationGrid->SetSelectionMode( wxGrid::wxGridSelectRows ); + + m_addDelayProfileButton->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) ); + m_removeDelayProfileButton->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) ); + + m_tracePropagationGrid->EndBatch(); + + m_tracePropagationGrid->Connect( + wxEVT_GRID_CELL_CHANGING, + wxGridEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnDelayProfileGridCellChanging ), nullptr, this ); + + // Set up the via override grid + m_viaPropagationGrid->BeginBatch(); + m_viaPropagationGrid->SetUseNativeColLabels(); + + m_viaPropagationGrid->EnsureColLabelsVisible(); + m_viaPropagationGrid->SetDefaultRowSize( m_viaPropagationGrid->GetDefaultRowSize() + 4 ); + m_viaPropagationGrid->PushEventHandler( new GRID_TRICKS( m_viaPropagationGrid ) ); + m_viaPropagationGrid->SetSelectionMode( wxGrid::wxGridSelectRows ); + + std::vector viaColIds; + m_viaPropagationGrid->SetAutoEvalColUnits( VIA_GRID_DELAY, + m_unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::TIME ) ); + viaColIds.push_back( VIA_GRID_DELAY ); + m_viaPropagationGrid->SetAutoEvalCols( viaColIds ); + m_viaPropagationGrid->EndBatch(); + + m_addViaOverrideButton->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) ); + m_removeViaOverrideButton->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) ); + + setColumnWidths(); + + Thaw(); +} + + +PANEL_SETUP_TIME_DOMAIN_PARAMETERS::~PANEL_SETUP_TIME_DOMAIN_PARAMETERS() +{ + // Delete the GRID_TRICKS + m_tracePropagationGrid->PopEventHandler( true ); + m_viaPropagationGrid->PopEventHandler( true ); + + m_tracePropagationGrid->Disconnect( + wxEVT_GRID_CELL_CHANGING, + wxGridEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnDelayProfileGridCellChanging ), nullptr, this ); +} + + +bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::TransferDataToWindow() +{ + m_tracePropagationGrid->ClearRows(); + m_viaPropagationGrid->ClearRows(); + + const std::vector& delayProfiles = m_timeDomainParameters->GetDelayProfiles(); + + SyncCopperLayers( m_board->GetCopperLayerCount() ); + + for( const TIME_DOMAIN_TUNING_PROFILE& profile : delayProfiles ) + { + addProfileRow( profile ); + + for( const TUNING_PROFILE_VIA_OVERRIDE_ENTRY& viaOverride : profile.m_ViaOverrides ) + addViaRow( profile.m_ProfileName, viaOverride ); + } + + updateViaProfileNamesEditor(); + + return true; +} + + +bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::TransferDataFromWindow() +{ + if( !Validate() ) + return false; + + m_timeDomainParameters->ClearDelayProfiles(); + + for( int i = 0; i < m_tracePropagationGrid->GetNumberRows(); ++i ) + { + TIME_DOMAIN_TUNING_PROFILE profile = getProfileRow( i ); + wxString profileName = profile.m_ProfileName; + + for( int j = 0; j < m_viaPropagationGrid->GetNumberRows(); ++j ) + { + if( m_viaPropagationGrid->GetCellValue( j, VIA_GRID_PROFILE_NAME ) == profileName ) + profile.m_ViaOverrides.emplace_back( getViaRow( j ) ); + } + + m_timeDomainParameters->AddDelayProfile( std::move( profile ) ); + } + + return true; +} + + +void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::addProfileRow( const TIME_DOMAIN_TUNING_PROFILE& aDelayProfile ) +{ + const int rowId = m_tracePropagationGrid->GetNumberRows(); + m_tracePropagationGrid->AppendRows(); + + m_tracePropagationGrid->SetCellValue( rowId, PROFILE_GRID_PROFILE_NAME, aDelayProfile.m_ProfileName ); + m_tracePropagationGrid->SetUnitValue( rowId, PROFILE_GRID_VIA_PROP_DELAY, aDelayProfile.m_ViaPropagationDelay ); + + for( const auto& [layerId, velocity] : aDelayProfile.m_LayerPropagationDelays ) + { + if( !m_copperLayerIdsToColumns.contains( layerId ) ) + continue; + + int col = m_copperLayerIdsToColumns[layerId]; + + if( col < m_tracePropagationGrid->GetNumberCols() ) + { + m_tracePropagationGrid->SetUnitValue( rowId, col, velocity ); + } + } +} + + +TIME_DOMAIN_TUNING_PROFILE PANEL_SETUP_TIME_DOMAIN_PARAMETERS::getProfileRow( const int aRow ) +{ + TIME_DOMAIN_TUNING_PROFILE entry; + entry.m_ProfileName = m_tracePropagationGrid->GetCellValue( aRow, PROFILE_GRID_PROFILE_NAME ); + entry.m_ViaPropagationDelay = m_tracePropagationGrid->GetUnitValue( aRow, PROFILE_GRID_VIA_PROP_DELAY ); + + std::map propDelays; + + for( const auto& [layer, col] : m_copperLayerIdsToColumns ) + propDelays[layer] = m_tracePropagationGrid->GetUnitValue( aRow, col ); + + entry.m_LayerPropagationDelays = std::move( propDelays ); + + return entry; +} + + +void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::addViaRow( const wxString& aProfileName, + const TUNING_PROFILE_VIA_OVERRIDE_ENTRY& aViaOverrideEntry ) const +{ + const int rowId = m_viaPropagationGrid->GetNumberRows(); + m_viaPropagationGrid->AppendRows(); + m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_PROFILE_NAME, aProfileName ); + m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_SIGNAL_LAYER_FROM, + m_board->GetLayerName( aViaOverrideEntry.m_SignalLayerFrom ) ); + m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_SIGNAL_LAYER_TO, + m_board->GetLayerName( aViaOverrideEntry.m_SignalLayerTo ) ); + m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_VIA_LAYER_FROM, + m_board->GetLayerName( aViaOverrideEntry.m_ViaLayerFrom ) ); + m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_VIA_LAYER_TO, + m_board->GetLayerName( aViaOverrideEntry.m_ViaLayerTo ) ); + m_viaPropagationGrid->SetUnitValue( rowId, VIA_GRID_DELAY, aViaOverrideEntry.m_Delay ); +} + + +TUNING_PROFILE_VIA_OVERRIDE_ENTRY PANEL_SETUP_TIME_DOMAIN_PARAMETERS::getViaRow( const int aRow ) +{ + // Get layer info + const wxString signalLayerFrom = m_viaPropagationGrid->GetCellValue( aRow, VIA_GRID_SIGNAL_LAYER_FROM ); + const wxString signalLayerTo = m_viaPropagationGrid->GetCellValue( aRow, VIA_GRID_SIGNAL_LAYER_TO ); + const wxString viaLayerFrom = m_viaPropagationGrid->GetCellValue( aRow, VIA_GRID_VIA_LAYER_FROM ); + const wxString viaLayerTo = m_viaPropagationGrid->GetCellValue( aRow, VIA_GRID_VIA_LAYER_TO ); + PCB_LAYER_ID signalLayerIdFrom = m_layerNamesToIDs[signalLayerFrom]; + PCB_LAYER_ID signalLayerIdTo = m_layerNamesToIDs[signalLayerTo]; + PCB_LAYER_ID viaLayerIdFrom = m_layerNamesToIDs[viaLayerFrom]; + PCB_LAYER_ID viaLayerIdTo = m_layerNamesToIDs[viaLayerTo]; + + // Order layers in stackup order (from F_Cu first) + if( signalLayerIdTo != B_Cu && ( signalLayerIdTo < signalLayerIdFrom || signalLayerIdFrom == B_Cu ) ) + std::swap( signalLayerIdFrom, signalLayerIdTo ); + + if( viaLayerIdTo != B_Cu && ( viaLayerIdTo < viaLayerIdFrom || viaLayerIdFrom == B_Cu ) ) + std::swap( viaLayerIdFrom, viaLayerIdTo ); + + const TUNING_PROFILE_VIA_OVERRIDE_ENTRY entry{ signalLayerIdFrom, signalLayerIdTo, viaLayerIdFrom, viaLayerIdTo, + m_viaPropagationGrid->GetUnitValue( aRow, VIA_GRID_DELAY ) }; + + return entry; +} + + +void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::SyncCopperLayers( int aNumCopperLayers ) +{ + m_prevLayerNamesToIDs = m_layerNamesToIDs; + m_copperLayerIdsToColumns.clear(); + m_copperColumnsToLayerId.clear(); + m_layerNames.clear(); + m_layerNamesToIDs.clear(); + + int colIdx = PROFILE_GRID_NUM_REQUIRED_COLS; + + for( const auto& layer : LSET::AllCuMask( aNumCopperLayers ).CuStack() ) + { + wxString layerName = m_board->GetLayerName( layer ); + m_layerNames.emplace_back( layerName ); + m_layerNamesToIDs[layerName] = layer; + m_copperLayerIdsToColumns[layer] = colIdx; + m_copperColumnsToLayerId[colIdx] = layer; + ++colIdx; + } + + updateProfileGridColumns(); + updateViaGridColumns(); + setColumnWidths(); +} + + +void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::setColumnWidths() +{ + const int minValueWidth = m_tracePropagationGrid->GetTextExtent( wxT( "000.00 ps/mm" ) ).x; + const int minNameWidth = m_tracePropagationGrid->GetTextExtent( wxT( "MMMMMMMMMMMM" ) ).x; + + for( int i = 0; i < m_tracePropagationGrid->GetNumberCols(); ++i ) + { + const int titleSize = m_tracePropagationGrid->GetTextExtent( m_tracePropagationGrid->GetColLabelValue( i ) ).x; + + if( i == PROFILE_GRID_PROFILE_NAME ) + m_tracePropagationGrid->SetColSize( i, std::max( titleSize, minNameWidth ) ); + else + m_tracePropagationGrid->SetColSize( i, std::max( titleSize, minValueWidth ) ); + } + + for( int i = 0; i < m_viaPropagationGrid->GetNumberCols(); ++i ) + { + const int titleSize = GetTextExtent( m_viaPropagationGrid->GetColLabelValue( i ) ).x; + if( i == VIA_GRID_PROFILE_NAME ) + m_viaPropagationGrid->SetColSize( i, std::max( titleSize, minNameWidth ) ); + else + m_viaPropagationGrid->SetColSize( i, titleSize + 30 ); + } +} + + +void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::updateProfileGridColumns() +{ + const int newCopperLayers = static_cast( m_copperLayerIdsToColumns.size() ); + const int curCopperLayers = m_tracePropagationGrid->GetNumberCols() - PROFILE_GRID_NUM_REQUIRED_COLS; + + if( newCopperLayers < curCopperLayers ) + { + // TODO: WARN OF DELETING DATA? + m_tracePropagationGrid->DeleteCols( curCopperLayers - newCopperLayers + PROFILE_GRID_NUM_REQUIRED_COLS, + curCopperLayers - newCopperLayers ); + } + else if( newCopperLayers > curCopperLayers ) + { + m_tracePropagationGrid->AppendCols( newCopperLayers - curCopperLayers ); + } + + std::vector copperColIds; + + m_tracePropagationGrid->SetAutoEvalColUnits( PROFILE_GRID_VIA_PROP_DELAY, + m_unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::LENGTH_DELAY ) ); + copperColIds.push_back( PROFILE_GRID_VIA_PROP_DELAY ); + + for( const auto& [colIdx, layerId] : m_copperColumnsToLayerId ) + { + m_tracePropagationGrid->SetColLabelValue( colIdx, m_board->GetLayerName( layerId ) ); + m_tracePropagationGrid->SetAutoEvalColUnits( colIdx, + m_unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::LENGTH_DELAY ) ); + copperColIds.push_back( colIdx ); + } + + m_tracePropagationGrid->SetAutoEvalCols( copperColIds ); + + m_tracePropagationGrid->EnsureColLabelsVisible(); + m_tracePropagationGrid->Refresh(); +} + + +void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::updateViaGridColumns() +{ + wxArrayString layerNames; + std::ranges::for_each( m_layerNames, + [&layerNames]( const wxString& aLayerName ) + { + layerNames.push_back( aLayerName ); + } ); + + // Save the current data + std::vector currentSignalLayersFrom; + std::vector currentSignalLayersTo; + std::vector currentViaLayersFrom; + std::vector currentViaLayersTo; + + for( int row = 0; row < m_viaPropagationGrid->GetNumberRows(); ++row ) + { + currentSignalLayersFrom.emplace_back( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM ) ); + currentSignalLayersTo.emplace_back( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO ) ); + currentViaLayersFrom.emplace_back( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_VIA_LAYER_FROM ) ); + currentViaLayersTo.emplace_back( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_VIA_LAYER_TO ) ); + } + + // Reset the via layers lists + wxGridCellAttr* attr = new wxGridCellAttr; + attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) ); + m_viaPropagationGrid->SetColAttr( VIA_GRID_SIGNAL_LAYER_FROM, attr ); + + attr = new wxGridCellAttr; + attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) ); + m_viaPropagationGrid->SetColAttr( VIA_GRID_SIGNAL_LAYER_TO, attr ); + + attr = new wxGridCellAttr; + attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) ); + m_viaPropagationGrid->SetColAttr( VIA_GRID_VIA_LAYER_FROM, attr ); + + attr = new wxGridCellAttr; + attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) ); + m_viaPropagationGrid->SetColAttr( VIA_GRID_VIA_LAYER_TO, attr ); + + // Restore the data, changing or resetting layer names if required + for( int row = 0; row < m_viaPropagationGrid->GetNumberRows(); ++row ) + { + const PCB_LAYER_ID lastSignalFromId = m_prevLayerNamesToIDs[currentSignalLayersFrom[row]]; + + if( m_copperLayerIdsToColumns.contains( lastSignalFromId ) ) + m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM, + m_board->GetLayerName( lastSignalFromId ) ); + else + m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM, m_layerNames.front() ); + + const PCB_LAYER_ID lastSignalToId = m_prevLayerNamesToIDs[currentSignalLayersTo[row]]; + + if( m_copperLayerIdsToColumns.contains( lastSignalToId ) ) + m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO, + m_board->GetLayerName( lastSignalToId ) ); + else + m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO, m_layerNames.back() ); + + const PCB_LAYER_ID lastViaFromId = m_prevLayerNamesToIDs[currentViaLayersFrom[row]]; + + if( m_copperLayerIdsToColumns.contains( lastViaFromId ) ) + m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, m_board->GetLayerName( lastViaFromId ) ); + else + m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, m_layerNames.front() ); + + const PCB_LAYER_ID lastViaToId = m_prevLayerNamesToIDs[currentViaLayersTo[row]]; + + if( m_copperLayerIdsToColumns.contains( lastViaToId ) ) + m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, m_board->GetLayerName( lastViaToId ) ); + else + m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, m_layerNames.back() ); + } +} + + +void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnAddDelayProfileClick( wxCommandEvent& event ) +{ + if( !m_tracePropagationGrid->CommitPendingChanges() ) + return; + + const int rowId = m_tracePropagationGrid->GetNumberRows(); + m_tracePropagationGrid->AppendRows(); + m_tracePropagationGrid->SetCellValue( rowId, PROFILE_GRID_PROFILE_NAME, "" ); + + for( int i = PROFILE_GRID_VIA_PROP_DELAY; i < m_tracePropagationGrid->GetNumberCols(); ++i ) + m_tracePropagationGrid->SetUnitValue( rowId, i, 0 ); + + const int newRow = m_tracePropagationGrid->GetNumberRows() - 1; + m_tracePropagationGrid->MakeCellVisible( newRow, PROFILE_GRID_PROFILE_NAME ); + m_tracePropagationGrid->SetGridCursor( newRow, PROFILE_GRID_PROFILE_NAME ); + m_tracePropagationGrid->EnableCellEditControl( true ); + m_tracePropagationGrid->ShowCellEditControl(); +} + + +void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnRemoveDelayProfileClick( wxCommandEvent& event ) +{ + if( !m_tracePropagationGrid->CommitPendingChanges() ) + return; + + const int curRow = m_tracePropagationGrid->GetGridCursorRow(); + + if( curRow < 0 ) + return; + + wxString profileName = m_tracePropagationGrid->GetCellValue( curRow, PROFILE_GRID_PROFILE_NAME ); + profileName.Trim( true ); + profileName.Trim( false ); + + // Delete associated via overrides + for( int viaRow = m_viaPropagationGrid->GetNumberRows() - 1; viaRow >= 0; --viaRow ) + { + if( m_viaPropagationGrid->GetCellValue( viaRow, VIA_GRID_PROFILE_NAME ) == profileName ) + m_viaPropagationGrid->DeleteRows( viaRow, 1 ); + } + + // Delete tuning profile + m_tracePropagationGrid->DeleteRows( curRow, 1 ); + + m_tracePropagationGrid->MakeCellVisible( std::max( 0, curRow - 1 ), + m_tracePropagationGrid->GetGridCursorCol() ); + m_tracePropagationGrid->SetGridCursor( std::max( 0, curRow - 1 ), + m_tracePropagationGrid->GetGridCursorCol() ); + + updateViaProfileNamesEditor(); +} + + +void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnAddViaOverrideClick( wxCommandEvent& event ) +{ + if( !m_viaPropagationGrid->CommitPendingChanges() ) + return; + + const int rowId = m_viaPropagationGrid->GetNumberRows(); + m_viaPropagationGrid->AppendRows(); + m_viaPropagationGrid->SetCellValue( rowId, PROFILE_GRID_PROFILE_NAME, "" ); + m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_SIGNAL_LAYER_FROM, m_layerNames.front() ); + m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_SIGNAL_LAYER_TO, m_layerNames.back() ); + m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_VIA_LAYER_FROM, m_layerNames.front() ); + m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_VIA_LAYER_TO, m_layerNames.back() ); + m_viaPropagationGrid->SetUnitValue( rowId, VIA_GRID_DELAY, 0 ); +} + + +void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnRemoveViaOverrideClick( wxCommandEvent& event ) +{ + if( !m_viaPropagationGrid->CommitPendingChanges() ) + return; + + int curRow = m_viaPropagationGrid->GetGridCursorRow(); + + if( curRow < 0 ) + return; + + m_viaPropagationGrid->DeleteRows( curRow, 1 ); + + m_viaPropagationGrid->MakeCellVisible( std::max( 0, curRow - 1 ), m_viaPropagationGrid->GetGridCursorCol() ); + m_viaPropagationGrid->SetGridCursor( std::max( 0, curRow - 1 ), m_viaPropagationGrid->GetGridCursorCol() ); +} + + +void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnDelayProfileGridCellChanging( wxGridEvent& event ) +{ + if( event.GetCol() == PROFILE_GRID_PROFILE_NAME ) + { + if( validateDelayProfileName( event.GetRow(), event.GetString() ) ) + { + const wxString oldName = m_tracePropagationGrid->GetCellValue( event.GetRow(), PROFILE_GRID_PROFILE_NAME ); + const wxString newName = event.GetString(); + + if( !oldName.IsEmpty() ) + { + m_viaPropagationGrid->Freeze(); + + updateViaProfileNamesEditor( oldName, newName ); + + // Update changed profile names + for( int row = 0; row < m_viaPropagationGrid->GetNumberRows(); ++row ) + { + if( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_PROFILE_NAME ) == oldName ) + m_viaPropagationGrid->SetCellValue( row, VIA_GRID_PROFILE_NAME, newName ); + } + + m_viaPropagationGrid->Thaw(); + } + else + { + updateViaProfileNamesEditor( oldName, newName ); + } + } + else + { + event.Veto(); + } + } +} + + +void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::updateViaProfileNamesEditor( const wxString& aOldName, + const wxString& aNewName ) const +{ + wxArrayString profileNames; + + for( int i = 0; i < m_tracePropagationGrid->GetNumberRows(); ++i ) + { + wxString profileName = m_tracePropagationGrid->GetCellValue( i, PROFILE_GRID_PROFILE_NAME ); + + if( profileName == aOldName ) + profileName = aNewName; + + profileNames.push_back( profileName ); + } + + std::ranges::sort( profileNames, + []( const wxString& a, const wxString& b ) + { + return a.CmpNoCase( b ) < 0; + } ); + + wxGridCellAttr* attr = new wxGridCellAttr; + attr->SetEditor( new wxGridCellChoiceEditor( profileNames, false ) ); + m_viaPropagationGrid->SetColAttr( VIA_GRID_PROFILE_NAME, attr ); +} + + +bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::validateDelayProfileName( int aRow, const wxString& aName, bool focusFirst ) +{ + wxString tmp = aName; + + tmp.Trim( true ); + tmp.Trim( false ); + + if( tmp.IsEmpty() ) + { + const wxString msg = _( "Tuning profile must have a name." ); + PAGED_DIALOG::GetDialog( this )->SetError( msg, this, m_tracePropagationGrid, aRow, PROFILE_GRID_PROFILE_NAME ); + return false; + } + + for( int ii = 0; ii < m_tracePropagationGrid->GetNumberRows(); ii++ ) + { + if( ii != aRow && m_tracePropagationGrid->GetCellValue( ii, PROFILE_GRID_PROFILE_NAME ).CmpNoCase( tmp ) == 0 ) + { + const wxString msg = _( "Tuning profile name already in use." ); + PAGED_DIALOG::GetDialog( this )->SetError( msg, this, m_tracePropagationGrid, focusFirst ? aRow : ii, + PROFILE_GRID_PROFILE_NAME ); + return false; + } + } + + return true; +} + + +bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::Validate() +{ + if( !m_tracePropagationGrid->CommitPendingChanges() || !m_viaPropagationGrid->CommitPendingChanges() ) + return false; + + // Test net class parameters. + for( int row = 0; row < m_tracePropagationGrid->GetNumberRows(); row++ ) + { + wxString profileName = m_tracePropagationGrid->GetCellValue( row, PROFILE_GRID_PROFILE_NAME ); + profileName.Trim( true ); + profileName.Trim( false ); + + if( !validateDelayProfileName( row, profileName, false ) ) + return false; + } + + return true; +} + + +std::vector PANEL_SETUP_TIME_DOMAIN_PARAMETERS::GetDelayProfileNames() const +{ + std::vector profileNames; + + for( int i = 0; i < m_tracePropagationGrid->GetNumberRows(); i++ ) + profileNames.emplace_back( m_tracePropagationGrid->GetCellValue( i, PROFILE_GRID_PROFILE_NAME ) ); + + std::ranges::sort( profileNames, + []( const wxString& a, const wxString& b ) + { + return a.CmpNoCase( b ) < 0; + } ); + + return profileNames; +} + + +void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::ImportSettingsFrom( + const std::shared_ptr& aOtherParameters ) +{ + std::shared_ptr savedParameters = m_timeDomainParameters; + + m_timeDomainParameters = aOtherParameters; + TransferDataToWindow(); + + updateViaProfileNamesEditor(); + + m_viaPropagationGrid->ForceRefresh(); + + m_timeDomainParameters = std::move( savedParameters ); +} diff --git a/pcbnew/dialogs/panel_setup_time_domain_parameters.h b/pcbnew/dialogs/panel_setup_time_domain_parameters.h new file mode 100644 index 0000000000..c2c68b1b3b --- /dev/null +++ b/pcbnew/dialogs/panel_setup_time_domain_parameters.h @@ -0,0 +1,150 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#ifndef PANEL_SETUP_TIME_DOMAIN_PARAMETERS_H +#define PANEL_SETUP_TIME_DOMAIN_PARAMETERS_H + +#include + +#include +#include +#include + +class NET_SETTINGS; + + +class PANEL_SETUP_TIME_DOMAIN_PARAMETERS : public PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE +{ +public: + PANEL_SETUP_TIME_DOMAIN_PARAMETERS( + wxWindow* aParentWindow, PCB_EDIT_FRAME* aFrame, BOARD* aBoard, + std::shared_ptr aTimeDomainParameters ); + ~PANEL_SETUP_TIME_DOMAIN_PARAMETERS() override; + + /** + * Called when switching to this tab to make sure that any changes to the copper layer count + * made on the physical stackup page are reflected here + * @param aNumCopperLayers is the number of copper layers in the board + */ + void SyncCopperLayers( int aNumCopperLayers ); + + /// Load parameter data from the settings object + bool TransferDataToWindow() override; + + /// Save parameter data to the settings object + bool TransferDataFromWindow() override; + + /// Returns all configured tuning profile names. Used by the netclass setup panel + std::vector GetDelayProfileNames() const; + + /// Load configuration from the given settings object + void ImportSettingsFrom( const std::shared_ptr& aOtherParameters ); + +private: + enum PROFILE_GRID_REQUIRED_COLS + { + PROFILE_GRID_PROFILE_NAME = 0, + PROFILE_GRID_VIA_PROP_DELAY, + PROFILE_GRID_NUM_REQUIRED_COLS + }; + + enum VIA_GRID_REQUIRED_COLS + { + VIA_GRID_PROFILE_NAME = 0, + VIA_GRID_SIGNAL_LAYER_FROM, + VIA_GRID_SIGNAL_LAYER_TO, + VIA_GRID_VIA_LAYER_FROM, + VIA_GRID_VIA_LAYER_TO, + VIA_GRID_DELAY + }; + + /// Optimise grid columns to fit titles and content + void setColumnWidths(); + + /// Updates the via override tuning profile name dropdown lists + /// Updates entries if aOldName and aNewName are passed + void updateViaProfileNamesEditor( const wxString& aOldName = wxEmptyString, + const wxString& aNewName = wxEmptyString ) const; + + /// Update the dynamic (per-layer) columns in the tuning profiles grid + void updateProfileGridColumns(); + + /// Update the dynamic (per-layer) columns in the via overrides grid + void updateViaGridColumns(); + + /// Adds a new tuning profile entry to the tuning profile grid + void OnAddDelayProfileClick( wxCommandEvent& event ) override; + + /// Removes a tuning profile entry from the tuning profile grid + void OnRemoveDelayProfileClick( wxCommandEvent& event ) override; + + /// Adds a new via override profile entry to the via overrides grid + void OnAddViaOverrideClick( wxCommandEvent& event ) override; + + /// Removes a via override profile entry from the via overrides grid + void OnRemoveViaOverrideClick( wxCommandEvent& event ) override; + + /// Validates a tuning profile row data + void OnDelayProfileGridCellChanging( wxGridEvent& event ); + + /// Validates a tuning profile name (checks for not empty and not duplicated) + bool validateDelayProfileName( int aRow, const wxString& aName, bool focusFirst = true ); + + /// Validates all data + bool Validate() override; + + /// Adds a tuning profile row with the given persisted parameters + void addProfileRow( const TIME_DOMAIN_TUNING_PROFILE& aDelayProfile ); + + /// Gets a tuning profile row as a set of persistable parameters + TIME_DOMAIN_TUNING_PROFILE getProfileRow( int aRow ); + + /// Adds a via override row with the given persisted parameters + void addViaRow( const wxString& aProfileName, const TUNING_PROFILE_VIA_OVERRIDE_ENTRY& aViaOverrideEntry ) const; + + /// Gets a via override row as a set of persistable parameters + TUNING_PROFILE_VIA_OVERRIDE_ENTRY getViaRow( int aRow ); + + /// The parameters object to load / save data from / to + std::shared_ptr m_timeDomainParameters; + + /// The active edit frame + PCB_EDIT_FRAME* m_frame; + + /// The current board + BOARD* m_board; + + std::unique_ptr m_unitsProvider; + + // Layer / column lookups + std::map m_copperLayerIdsToColumns; + std::map m_copperColumnsToLayerId; + std::vector m_layerNames; + + // We cache these in case the names change on the layers panel + std::map m_layerNamesToIDs; + std::map m_prevLayerNamesToIDs; +}; + +#endif // PANEL_SETUP_TIME_DOMAIN_PARAMETERS_H diff --git a/pcbnew/dialogs/panel_setup_time_domain_parameters_base.cpp b/pcbnew/dialogs/panel_setup_time_domain_parameters_base.cpp new file mode 100644 index 0000000000..d2e62a1152 --- /dev/null +++ b/pcbnew/dialogs/panel_setup_time_domain_parameters_base.cpp @@ -0,0 +1,185 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6) +// http://www.wxformbuilder.org/ +// +// PLEASE DO *NOT* EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "widgets/std_bitmap_button.h" +#include "widgets/wx_grid.h" +#include "widgets/wx_panel.h" + +#include "panel_setup_time_domain_parameters_base.h" + +/////////////////////////////////////////////////////////////////////////// + +PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxPanel( parent, id, pos, size, style, name ) +{ + wxBoxSizer* bpanelTomeDomainSizer; + bpanelTomeDomainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bMargins; + bMargins = new wxBoxSizer( wxVERTICAL ); + + m_splitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3DSASH|wxSP_LIVE_UPDATE|wxSP_NO_XP_THEME ); + m_splitter->SetMinimumPaneSize( 160 ); + + m_timeDomainParametersPane = new WX_PANEL( m_splitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bUpperSizer; + bUpperSizer = new wxBoxSizer( wxVERTICAL ); + + m_staticText3 = new wxStaticText( m_timeDomainParametersPane, wxID_ANY, _("Delay Profiles"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText3->Wrap( -1 ); + bUpperSizer->Add( m_staticText3, 0, wxTOP|wxLEFT|wxEXPAND, 8 ); + + + bUpperSizer->Add( 0, 3, 0, wxEXPAND, 5 ); + + m_tracePropagationGrid = new WX_GRID( m_timeDomainParametersPane, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL ); + + // Grid + m_tracePropagationGrid->CreateGrid( 0, 2 ); + m_tracePropagationGrid->EnableEditing( true ); + m_tracePropagationGrid->EnableGridLines( true ); + m_tracePropagationGrid->EnableDragGridSize( false ); + m_tracePropagationGrid->SetMargins( 0, 0 ); + + // Columns + m_tracePropagationGrid->EnableDragColMove( false ); + m_tracePropagationGrid->EnableDragColSize( true ); + m_tracePropagationGrid->SetColLabelValue( 0, _("Profile Name") ); + m_tracePropagationGrid->SetColLabelValue( 1, _("Vias") ); + m_tracePropagationGrid->SetColLabelSize( wxGRID_AUTOSIZE ); + m_tracePropagationGrid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER ); + + // Rows + m_tracePropagationGrid->EnableDragRowSize( true ); + m_tracePropagationGrid->SetRowLabelSize( 0 ); + m_tracePropagationGrid->SetRowLabelAlignment( wxALIGN_LEFT, wxALIGN_CENTER ); + + // Label Appearance + + // Cell Defaults + m_tracePropagationGrid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_CENTER ); + bUpperSizer->Add( m_tracePropagationGrid, 1, wxEXPAND|wxFIXED_MINSIZE|wxLEFT|wxRIGHT|wxTOP, 5 ); + + wxBoxSizer* buttonBoxSizer; + buttonBoxSizer = new wxBoxSizer( wxHORIZONTAL ); + + m_addDelayProfileButton = new STD_BITMAP_BUTTON( m_timeDomainParametersPane, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), wxBU_AUTODRAW|0 ); + buttonBoxSizer->Add( m_addDelayProfileButton, 0, wxLEFT, 2 ); + + + buttonBoxSizer->Add( 20, 0, 0, wxEXPAND, 5 ); + + m_removeDelayProfileButton = new STD_BITMAP_BUTTON( m_timeDomainParametersPane, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), wxBU_AUTODRAW|0 ); + buttonBoxSizer->Add( m_removeDelayProfileButton, 0, wxBOTTOM|wxLEFT, 5 ); + + + buttonBoxSizer->Add( 20, 0, 0, wxEXPAND, 5 ); + + + bUpperSizer->Add( buttonBoxSizer, 0, wxEXPAND|wxLEFT|wxTOP, 5 ); + + + m_timeDomainParametersPane->SetSizer( bUpperSizer ); + m_timeDomainParametersPane->Layout(); + bUpperSizer->Fit( m_timeDomainParametersPane ); + m_timeDomainParametersPane1 = new WX_PANEL( m_splitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bUpperSizer1; + bUpperSizer1 = new wxBoxSizer( wxVERTICAL ); + + m_staticText31 = new wxStaticText( m_timeDomainParametersPane1, wxID_ANY, _("Via Delay Overrides"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText31->Wrap( -1 ); + bUpperSizer1->Add( m_staticText31, 0, wxTOP|wxLEFT|wxEXPAND, 8 ); + + + bUpperSizer1->Add( 0, 3, 0, wxEXPAND, 5 ); + + m_viaPropagationGrid = new WX_GRID( m_timeDomainParametersPane1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL ); + + // Grid + m_viaPropagationGrid->CreateGrid( 0, 6 ); + m_viaPropagationGrid->EnableEditing( true ); + m_viaPropagationGrid->EnableGridLines( true ); + m_viaPropagationGrid->EnableDragGridSize( false ); + m_viaPropagationGrid->SetMargins( 0, 0 ); + + // Columns + m_viaPropagationGrid->EnableDragColMove( false ); + m_viaPropagationGrid->EnableDragColSize( true ); + m_viaPropagationGrid->SetColLabelValue( 0, _("Profile Name") ); + m_viaPropagationGrid->SetColLabelValue( 1, _("Signal Layer From") ); + m_viaPropagationGrid->SetColLabelValue( 2, _("Signal Layer To") ); + m_viaPropagationGrid->SetColLabelValue( 3, _("Via Layer From") ); + m_viaPropagationGrid->SetColLabelValue( 4, _("Via Layer To") ); + m_viaPropagationGrid->SetColLabelValue( 5, _("Delay") ); + m_viaPropagationGrid->SetColLabelSize( wxGRID_AUTOSIZE ); + m_viaPropagationGrid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER ); + + // Rows + m_viaPropagationGrid->EnableDragRowSize( true ); + m_viaPropagationGrid->SetRowLabelSize( 0 ); + m_viaPropagationGrid->SetRowLabelAlignment( wxALIGN_LEFT, wxALIGN_CENTER ); + + // Label Appearance + + // Cell Defaults + m_viaPropagationGrid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_CENTER ); + bUpperSizer1->Add( m_viaPropagationGrid, 1, wxEXPAND|wxFIXED_MINSIZE|wxLEFT|wxRIGHT|wxTOP, 5 ); + + wxBoxSizer* buttonBoxSizer1; + buttonBoxSizer1 = new wxBoxSizer( wxHORIZONTAL ); + + m_addViaOverrideButton = new STD_BITMAP_BUTTON( m_timeDomainParametersPane1, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), wxBU_AUTODRAW|0 ); + buttonBoxSizer1->Add( m_addViaOverrideButton, 0, wxLEFT, 2 ); + + + buttonBoxSizer1->Add( 20, 0, 0, wxEXPAND, 5 ); + + m_removeViaOverrideButton = new STD_BITMAP_BUTTON( m_timeDomainParametersPane1, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), wxBU_AUTODRAW|0 ); + buttonBoxSizer1->Add( m_removeViaOverrideButton, 0, wxBOTTOM|wxLEFT, 5 ); + + + buttonBoxSizer1->Add( 20, 0, 0, wxEXPAND, 5 ); + + + bUpperSizer1->Add( buttonBoxSizer1, 0, wxEXPAND|wxLEFT|wxTOP, 5 ); + + + m_timeDomainParametersPane1->SetSizer( bUpperSizer1 ); + m_timeDomainParametersPane1->Layout(); + bUpperSizer1->Fit( m_timeDomainParametersPane1 ); + m_splitter->SplitHorizontally( m_timeDomainParametersPane, m_timeDomainParametersPane1, -1 ); + bMargins->Add( m_splitter, 1, wxEXPAND, 10 ); + + + bpanelTomeDomainSizer->Add( bMargins, 1, wxEXPAND|wxTOP, 2 ); + + + this->SetSizer( bpanelTomeDomainSizer ); + this->Layout(); + bpanelTomeDomainSizer->Fit( this ); + + // Connect Events + this->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnUpdateUI ) ); + m_tracePropagationGrid->Connect( wxEVT_SIZE, wxSizeEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnSizeTraceParametersGrid ), NULL, this ); + m_addDelayProfileButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnAddDelayProfileClick ), NULL, this ); + m_removeDelayProfileButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnRemoveDelayProfileClick ), NULL, this ); + m_viaPropagationGrid->Connect( wxEVT_SIZE, wxSizeEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnSizeTraceParametersGrid ), NULL, this ); + m_addViaOverrideButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnAddViaOverrideClick ), NULL, this ); + m_removeViaOverrideButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnRemoveViaOverrideClick ), NULL, this ); +} + +PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::~PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnUpdateUI ) ); + m_tracePropagationGrid->Disconnect( wxEVT_SIZE, wxSizeEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnSizeTraceParametersGrid ), NULL, this ); + m_addDelayProfileButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnAddDelayProfileClick ), NULL, this ); + m_removeDelayProfileButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnRemoveDelayProfileClick ), NULL, this ); + m_viaPropagationGrid->Disconnect( wxEVT_SIZE, wxSizeEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnSizeTraceParametersGrid ), NULL, this ); + m_addViaOverrideButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnAddViaOverrideClick ), NULL, this ); + m_removeViaOverrideButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE::OnRemoveViaOverrideClick ), NULL, this ); + +} diff --git a/pcbnew/dialogs/panel_setup_time_domain_parameters_base.fbp b/pcbnew/dialogs/panel_setup_time_domain_parameters_base.fbp new file mode 100644 index 0000000000..208ed930de --- /dev/null +++ b/pcbnew/dialogs/panel_setup_time_domain_parameters_base.fbp @@ -0,0 +1,950 @@ + + + + + C++ + + 1 + connect + none + + + 0 + 1 + res + UTF-8 + panel_setup_time_domain_parameters_base + 1000 + 1 + 1 + UI + panel_setup_time_domain_parameters_base + . + 0 + source_name + 1 + 0 + source_name + + + 1 + 1 + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 0 + 1 + impl_virtual + + + 0 + wxID_ANY + + -1,-1 + PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE + + -1,-1 + ; forward_declare + + 0 + + + wxTAB_TRAVERSAL + OnUpdateUI + + + bpanelTomeDomainSizer + wxVERTICAL + none + + 2 + wxEXPAND|wxTOP + 1 + + + bMargins + wxVERTICAL + none + + 10 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 160 + + 0 + + 1 + m_splitter + 1 + + + protected + 1 + + Resizable + 0.0 + -1 + -1 + 1 + + wxSPLIT_HORIZONTAL + wxSP_3DSASH|wxSP_LIVE_UPDATE|wxSP_NO_XP_THEME + ; ; forward_declare + 0 + + + + + + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_timeDomainParametersPane + 1 + + + protected + 1 + + Resizable + 1 + + WX_PANEL; widgets/wx_panel.h; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bUpperSizer + wxVERTICAL + none + + 8 + wxTOP|wxLEFT|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Delay Profiles + 0 + + 0 + + + 0 + + 1 + m_staticText3 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 0 + + 3 + protected + 0 + + + + 5 + wxEXPAND|wxFIXED_MINSIZE|wxLEFT|wxRIGHT|wxTOP + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + 0 + + + + 1 + + + wxALIGN_LEFT + + wxALIGN_CENTER + 0 + 1 + wxALIGN_CENTER + wxGRID_AUTOSIZE + "Profile Name" "Vias" + wxALIGN_CENTER + 2 + + + 1 + 0 + Dock + 0 + Left + 0 + 0 + 1 + 0 + 1 + 1 + 1 + + 1 + + + 1 + 0 + 0 + wxID_ANY + + + + 0 + 0 + + 0 + + + 0 + -1,-1 + 1 + m_tracePropagationGrid + 1 + + + protected + 1 + + Resizable + wxALIGN_LEFT + 0 + + wxALIGN_CENTER + + 0 + 1 + + WX_GRID; widgets/wx_grid.h; forward_declare + 0 + + + + wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL + OnSizeTraceParametersGrid + + + + 5 + wxEXPAND|wxLEFT|wxTOP + 0 + + + buttonBoxSizer + wxHORIZONTAL + none + + 2 + wxLEFT + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 + wxID_ANY + Add Parameter + + 0 + + 0 + + + 0 + -1,-1 + 1 + m_addDelayProfileButton + 1 + + + protected + 1 + + + + Resizable + 1 + -1,-1 + + STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnAddDelayProfileClick + + + + 5 + wxEXPAND + 0 + + 0 + protected + 20 + + + + 5 + wxBOTTOM|wxLEFT + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 + wxID_ANY + Delete Parameter + + 0 + + 0 + + + 0 + -1,-1 + 1 + m_removeDelayProfileButton + 1 + + + protected + 1 + + + + Resizable + 1 + -1,-1 + + STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnRemoveDelayProfileClick + + + + 5 + wxEXPAND + 0 + + 0 + protected + 20 + + + + + + + + + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_timeDomainParametersPane1 + 1 + + + protected + 1 + + Resizable + 1 + + WX_PANEL; widgets/wx_panel.h; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bUpperSizer1 + wxVERTICAL + none + + 8 + wxTOP|wxLEFT|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Via Delay Overrides + 0 + + 0 + + + 0 + + 1 + m_staticText31 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 0 + + 3 + protected + 0 + + + + 5 + wxEXPAND|wxFIXED_MINSIZE|wxLEFT|wxRIGHT|wxTOP + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + 0 + + + + 1 + + + wxALIGN_LEFT + + wxALIGN_CENTER + 0 + 1 + wxALIGN_CENTER + wxGRID_AUTOSIZE + "Profile Name" "Signal Layer From" "Signal Layer To" "Via Layer From" "Via Layer To" "Delay" + wxALIGN_CENTER + 6 + + + 1 + 0 + Dock + 0 + Left + 0 + 0 + 1 + 0 + 1 + 1 + 1 + + 1 + + + 1 + 0 + 0 + wxID_ANY + + + + 0 + 0 + + 0 + + + 0 + -1,-1 + 1 + m_viaPropagationGrid + 1 + + + protected + 1 + + Resizable + wxALIGN_LEFT + 0 + + wxALIGN_CENTER + + 0 + 1 + + WX_GRID; widgets/wx_grid.h; forward_declare + 0 + + + + wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL + OnSizeTraceParametersGrid + + + + 5 + wxEXPAND|wxLEFT|wxTOP + 0 + + + buttonBoxSizer1 + wxHORIZONTAL + none + + 2 + wxLEFT + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 + wxID_ANY + Add Parameter + + 0 + + 0 + + + 0 + -1,-1 + 1 + m_addViaOverrideButton + 1 + + + protected + 1 + + + + Resizable + 1 + -1,-1 + + STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnAddViaOverrideClick + + + + 5 + wxEXPAND + 0 + + 0 + protected + 20 + + + + 5 + wxBOTTOM|wxLEFT + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 + wxID_ANY + Delete Parameter + + 0 + + 0 + + + 0 + -1,-1 + 1 + m_removeViaOverrideButton + 1 + + + protected + 1 + + + + Resizable + 1 + -1,-1 + + STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnRemoveViaOverrideClick + + + + 5 + wxEXPAND + 0 + + 0 + protected + 20 + + + + + + + + + + + + + + + diff --git a/pcbnew/dialogs/panel_setup_time_domain_parameters_base.h b/pcbnew/dialogs/panel_setup_time_domain_parameters_base.h new file mode 100644 index 0000000000..aff54d5743 --- /dev/null +++ b/pcbnew/dialogs/panel_setup_time_domain_parameters_base.h @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6) +// http://www.wxformbuilder.org/ +// +// PLEASE DO *NOT* EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include +#include +class STD_BITMAP_BUTTON; +class WX_GRID; +class WX_PANEL; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE +/////////////////////////////////////////////////////////////////////////////// +class PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE : public wxPanel +{ + private: + + protected: + wxSplitterWindow* m_splitter; + WX_PANEL* m_timeDomainParametersPane; + wxStaticText* m_staticText3; + WX_GRID* m_tracePropagationGrid; + STD_BITMAP_BUTTON* m_addDelayProfileButton; + STD_BITMAP_BUTTON* m_removeDelayProfileButton; + WX_PANEL* m_timeDomainParametersPane1; + wxStaticText* m_staticText31; + WX_GRID* m_viaPropagationGrid; + STD_BITMAP_BUTTON* m_addViaOverrideButton; + STD_BITMAP_BUTTON* m_removeViaOverrideButton; + + // Virtual event handlers, override them in your derived class + virtual void OnUpdateUI( wxUpdateUIEvent& event ) { event.Skip(); } + virtual void OnSizeTraceParametersGrid( wxSizeEvent& event ) { event.Skip(); } + virtual void OnAddDelayProfileClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnRemoveDelayProfileClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnAddViaOverrideClick( wxCommandEvent& event ) { event.Skip(); } + virtual void OnRemoveViaOverrideClick( wxCommandEvent& event ) { event.Skip(); } + + + public: + + PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString ); + + ~PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE(); + +}; + diff --git a/pcbnew/drc/drc_engine.cpp b/pcbnew/drc/drc_engine.cpp index 3c278f3824..846e54dcc7 100644 --- a/pcbnew/drc/drc_engine.cpp +++ b/pcbnew/drc/drc_engine.cpp @@ -775,6 +775,8 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO constraint.m_ZoneConnection = c->constraint.m_ZoneConnection; constraint.SetParentRule( c->constraint.GetParentRule() ); + + constraint.SetOptionsFromOther( c->constraint ); }; const FOOTPRINT* footprints[2] = {a ? a->GetParentFootprint() : nullptr, diff --git a/pcbnew/drc/drc_length_report.h b/pcbnew/drc/drc_length_report.h index afbd9a4313..a04cc76b72 100644 --- a/pcbnew/drc/drc_length_report.h +++ b/pcbnew/drc/drc_length_report.h @@ -40,9 +40,13 @@ public: std::set items; int viaCount; double totalRoute; + double totalRouteDelay; int totalVia; + int64_t totalViaDelay; int totalPadToDie; + int64_t totalPadToDieDelay; double total; + double totalDelay; }; DRC_LENGTH_REPORT() diff --git a/pcbnew/drc/drc_rule.h b/pcbnew/drc/drc_rule.h index c72ac30e2d..da08c79b9f 100644 --- a/pcbnew/drc/drc_rule.h +++ b/pcbnew/drc/drc_rule.h @@ -141,7 +141,12 @@ public: enum class OPTIONS : std::size_t { - SKEW_WITHIN_DIFF_PAIRS = 0 + SKEW_WITHIN_DIFF_PAIRS = 0, + SPACE_DOMAIN, + TIME_DOMAIN, + + // Keep this last value - used to statically size the options bitset + NUM_OPTIONS }; bool IsNull() const @@ -180,11 +185,15 @@ public: void SetOption( OPTIONS option ) { m_options.set( static_cast( option ), true ); } + void ClearOption( OPTIONS option ) { m_options.set( static_cast( option ), false ); } + bool GetOption( OPTIONS option ) const { return m_options.test( static_cast( option ) ); } + void SetOptionsFromOther( const DRC_CONSTRAINT& aOther ) { m_options = aOther.m_options; } + public: DRC_CONSTRAINT_T m_Type; MINOPTMAX m_Value; @@ -196,8 +205,8 @@ public: private: wxString m_name; // For just-in-time constraints DRC_RULE* m_parentRule; // For constraints found in rules - std::bitset<1> m_options; // Constraint-specific option bits - // (indexed from DRC_CONSTRAINT::OPTIONS) + std::bitset( OPTIONS::NUM_OPTIONS )> m_options; // Constraint-specific option bits + // (indexed from DRC_CONSTRAINT::OPTIONS) }; diff --git a/pcbnew/drc/drc_rule_parser.cpp b/pcbnew/drc/drc_rule_parser.cpp index 9fec20b0a0..f1034ef6d5 100644 --- a/pcbnew/drc/drc_rule_parser.cpp +++ b/pcbnew/drc/drc_rule_parser.cpp @@ -420,7 +420,41 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) { DRC_CONSTRAINT c; int value; + EDA_UNITS units = EDA_UNITS::UNSCALED; + EDA_DATA_TYPE unitsType = EDA_DATA_TYPE::UNITLESS; wxString msg; + bool allowsTimeDomain = false; + + auto validateAndSetValueWithUnits = + [this, &allowsTimeDomain, &unitsType, &c]( int aValue, const EDA_UNITS aUnits, auto aSetter ) + { + const EDA_DATA_TYPE unitsTypeTmp = UNITS_PROVIDER::GetTypeFromUnits( aUnits ); + + if( !allowsTimeDomain && unitsTypeTmp == EDA_DATA_TYPE::TIME ) + reportError( _( "Time based units not allowed for constraint type." ) ); + + if( ( c.m_Value.HasMin() || c.m_Value.HasMax() || c.m_Value.HasOpt() ) && unitsType != unitsTypeTmp ) + { + reportError( _( "Mixed units for constraint values." ) ); + } + + unitsType = unitsTypeTmp; + aSetter( aValue ); + + if( allowsTimeDomain ) + { + if( unitsType == EDA_DATA_TYPE::TIME ) + { + c.SetOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN ); + c.ClearOption( DRC_CONSTRAINT::OPTIONS::SPACE_DOMAIN ); + } + else + { + c.SetOption( DRC_CONSTRAINT::OPTIONS::SPACE_DOMAIN ); + c.ClearOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN ); + } + } + }; T token = NextTok(); @@ -504,6 +538,8 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) || c.m_Type == MIN_RESOLVED_SPOKES_CONSTRAINT || c.m_Type == TRACK_ANGLE_CONSTRAINT; + allowsTimeDomain = c.m_Type == LENGTH_CONSTRAINT || c.m_Type == SKEW_CONSTRAINT; + if( c.m_Type == DISALLOW_CONSTRAINT ) { for( token = NextTok(); token != T_RIGHT; token = NextTok() ) @@ -661,8 +697,12 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) break; } - parseValueWithUnits( FromUTF8(), value, unitless ); - c.m_Value.SetMin( value ); + parseValueWithUnits( FromUTF8(), value, units, unitless ); + validateAndSetValueWithUnits( value, units, + [&c]( const int aValue ) + { + c.m_Value.SetMin( aValue ); + } ); if( (int) NextTok() != DSN_RIGHT ) { @@ -681,9 +721,12 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) break; } - parseValueWithUnits( FromUTF8(), value, unitless ); - - c.m_Value.SetMax( value ); + parseValueWithUnits( FromUTF8(), value, units, unitless ); + validateAndSetValueWithUnits( value, units, + [&c]( const int aValue ) + { + c.m_Value.SetMax( aValue ); + } ); if( (int) NextTok() != DSN_RIGHT ) { @@ -702,8 +745,12 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) break; } - parseValueWithUnits( FromUTF8(), value, unitless ); - c.m_Value.SetOpt( value ); + parseValueWithUnits( FromUTF8(), value, units, unitless ); + validateAndSetValueWithUnits( value, units, + [&c]( const int aValue ) + { + c.m_Value.SetOpt( aValue ); + } ); if( (int) NextTok() != DSN_RIGHT ) { @@ -733,8 +780,11 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule ) } -void DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult, bool aUnitless ) +void DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult, EDA_UNITS& aUnits, bool aUnitless ) { + aResult = 0.0; + aUnits = EDA_UNITS::UNSCALED; + auto errorHandler = [&]( const wxString& aMessage, int aOffset ) { wxString rest; @@ -760,8 +810,11 @@ void DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult, : (LIBEVAL::UNIT_RESOLVER*) new PCBEXPR_UNIT_RESOLVER() ); evaluator.SetErrorCallback( errorHandler ); - evaluator.Evaluate( aExpr ); - aResult = evaluator.Result(); + if( evaluator.Evaluate( aExpr ) ) + { + aResult = evaluator.Result(); + aUnits = evaluator.Units(); + } } diff --git a/pcbnew/drc/drc_rule_parser.h b/pcbnew/drc/drc_rule_parser.h index 084de44fa1..fee9e05cff 100644 --- a/pcbnew/drc/drc_rule_parser.h +++ b/pcbnew/drc/drc_rule_parser.h @@ -55,7 +55,7 @@ private: std::shared_ptr parseComponentClassAssignment(); void parseConstraint( DRC_RULE* aRule ); - void parseValueWithUnits( const wxString& aExpr, int& aResult, bool aUnitless = false ); + void parseValueWithUnits( const wxString& aExpr, int& aResult, EDA_UNITS& aUnits, bool aUnitless = false ); LSET parseLayer( wxString* aSource ); SEVERITY parseSeverity(); void parseUnknown(); diff --git a/pcbnew/drc/drc_test_provider.cpp b/pcbnew/drc/drc_test_provider.cpp index 559612c303..ee7b745dc8 100644 --- a/pcbnew/drc/drc_test_provider.cpp +++ b/pcbnew/drc/drc_test_provider.cpp @@ -373,17 +373,17 @@ bool DRC_TEST_PROVIDER::isInvisibleText( const BOARD_ITEM* aItem ) const } -wxString DRC_TEST_PROVIDER::formatMsg( const wxString& aFormatString, const wxString& aSource, - double aConstraint, double aActual ) +wxString DRC_TEST_PROVIDER::formatMsg( const wxString& aFormatString, const wxString& aSource, double aConstraint, + double aActual, EDA_DATA_TYPE aType ) { - wxString constraint_str = MessageTextFromValue( aConstraint ); - wxString actual_str = MessageTextFromValue( aActual ); + wxString constraint_str = MessageTextFromValue( aConstraint, true, aType ); + wxString actual_str = MessageTextFromValue( aActual, true, aType ); if( constraint_str == actual_str ) { // Use more precise formatting if the message-text strings were equal. - constraint_str = StringFromValue( aConstraint, true ); - actual_str = StringFromValue( aActual, true ); + constraint_str = StringFromValue( aConstraint, true, aType ); + actual_str = StringFromValue( aActual, true, aType ); } return wxString::Format( aFormatString, aSource, constraint_str, actual_str ); diff --git a/pcbnew/drc/drc_test_provider.h b/pcbnew/drc/drc_test_provider.h index 22ae1c4aa7..527170886d 100644 --- a/pcbnew/drc/drc_test_provider.h +++ b/pcbnew/drc/drc_test_provider.h @@ -122,8 +122,8 @@ protected: bool isInvisibleText( const BOARD_ITEM* aItem ) const; - wxString formatMsg( const wxString& aFormatString, const wxString& aSource, double aConstraint, - double aActual ); + wxString formatMsg( const wxString& aFormatString, const wxString& aSource, double aConstraint, double aActual, + EDA_DATA_TYPE aDataType = EDA_DATA_TYPE::DISTANCE ); wxString formatMsg( const wxString& aFormatString, const wxString& aSource, const EDA_ANGLE& aConstraint, const EDA_ANGLE& aActual ); diff --git a/pcbnew/drc/drc_test_provider_matched_length.cpp b/pcbnew/drc/drc_test_provider_matched_length.cpp index f3ed3b4069..419a2724e9 100644 --- a/pcbnew/drc/drc_test_provider_matched_length.cpp +++ b/pcbnew/drc/drc_test_provider_matched_length.cpp @@ -93,15 +93,34 @@ void DRC_TEST_PROVIDER_MATCHED_LENGTH::checkLengths( const DRC_CONSTRAINT& aCons int minLen = 0; int maxLen = 0; - if( aConstraint.GetValue().HasMin() && ent.total < aConstraint.GetValue().Min() ) + const bool isTimeDomain = aConstraint.GetOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN ); + const EDA_DATA_TYPE dataType = isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE; + + if( !isTimeDomain ) { - minViolation = true; - minLen = aConstraint.GetValue().Min(); + if( aConstraint.GetValue().HasMin() && ent.total < aConstraint.GetValue().Min() ) + { + minViolation = true; + minLen = aConstraint.GetValue().Min(); + } + else if( aConstraint.GetValue().HasMax() && ent.total > aConstraint.GetValue().Max() ) + { + maxViolation = true; + maxLen = aConstraint.GetValue().Max(); + } } - else if( aConstraint.GetValue().HasMax() && ent.total > aConstraint.GetValue().Max() ) + else { - maxViolation = true; - maxLen = aConstraint.GetValue().Max(); + if( aConstraint.GetValue().HasMin() && ent.totalDelay < aConstraint.GetValue().Min() ) + { + minViolation = true; + minLen = aConstraint.GetValue().Min(); + } + else if( aConstraint.GetValue().HasMax() && ent.totalDelay > aConstraint.GetValue().Max() ) + { + maxViolation = true; + maxLen = aConstraint.GetValue().Max(); + } } if( ( minViolation || maxViolation ) ) @@ -111,17 +130,29 @@ void DRC_TEST_PROVIDER_MATCHED_LENGTH::checkLengths( const DRC_CONSTRAINT& aCons if( minViolation ) { - msg = formatMsg( _( "(%s min length %s; actual %s)" ), - aConstraint.GetName(), - minLen, - ent.total ); + if( aConstraint.GetOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN ) ) + { + msg = formatMsg( _( "(%s min length %s; actual %s)" ), aConstraint.GetName(), minLen, + ent.totalDelay, dataType ); + } + else + { + msg = formatMsg( _( "(%s min length %s; actual %s)" ), aConstraint.GetName(), minLen, ent.total, + dataType ); + } } else if( maxViolation ) { - msg = formatMsg( _( "(%s max length %s; actual %s)" ), - aConstraint.GetName(), - maxLen, - ent.total ); + if( aConstraint.GetOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN ) ) + { + msg = formatMsg( _( "(%s max length %s; actual %s)" ), aConstraint.GetName(), maxLen, + ent.totalDelay, dataType ); + } + else + { + msg = formatMsg( _( "(%s max length %s; actual %s)" ), aConstraint.GetName(), maxLen, ent.total, + dataType ); + } } drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg ); @@ -142,21 +173,44 @@ void DRC_TEST_PROVIDER_MATCHED_LENGTH::checkSkews( const DRC_CONSTRAINT& aConstr { auto checkSkewsImpl = [this, &aConstraint]( const std::vector& connections ) { + const bool isTimeDomain = aConstraint.GetOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN ); + const EDA_DATA_TYPE dataType = isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE; + double maxLength = 0; wxString maxNetname; - for( const DRC_LENGTH_REPORT::ENTRY& ent : connections ) + if( !isTimeDomain ) { - if( ent.total > maxLength ) + for( const DRC_LENGTH_REPORT::ENTRY& ent : connections ) { - maxLength = ent.total; - maxNetname = ent.netname; + if( ent.total > maxLength ) + { + maxLength = ent.total; + maxNetname = ent.netname; + } + } + } + else + { + for( const DRC_LENGTH_REPORT::ENTRY& ent : connections ) + { + if( ent.totalDelay > maxLength ) + { + maxLength = ent.totalDelay; + maxNetname = ent.netname; + } } } for( const auto& ent : connections ) { - int skew = KiROUND( ent.total - maxLength ); + int skew = 0; + + if( isTimeDomain ) + skew = KiROUND( ent.totalDelay - maxLength ); + else + skew = KiROUND( ent.total - maxLength ); + bool fail_min = false; bool fail_max = false; @@ -170,23 +224,27 @@ void DRC_TEST_PROVIDER_MATCHED_LENGTH::checkSkews( const DRC_CONSTRAINT& aConstr std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_SKEW_OUT_OF_RANGE ); wxString msg; + double reportTotal = isTimeDomain ? ent.totalDelay : ent.total; + if( fail_min ) { msg.Printf( _( "(%s min skew %s; actual %s; target net length %s (from %s); " "actual %s)" ), aConstraint.GetName(), - MessageTextFromValue( aConstraint.GetValue().Min() ), - MessageTextFromValue( skew ), MessageTextFromValue( maxLength ), - maxNetname, MessageTextFromValue( ent.total ) ); + MessageTextFromValue( aConstraint.GetValue().Min(), true, dataType ), + MessageTextFromValue( skew, true, dataType ), + MessageTextFromValue( maxLength, true, dataType ), maxNetname, + MessageTextFromValue( reportTotal, true, dataType ) ); } else { msg.Printf( _( "(%s max skew %s; actual %s; target net length %s (from %s); " "actual %s)" ), aConstraint.GetName(), - MessageTextFromValue( aConstraint.GetValue().Max() ), - MessageTextFromValue( skew ), MessageTextFromValue( maxLength ), - maxNetname, MessageTextFromValue( ent.total ) ); + MessageTextFromValue( aConstraint.GetValue().Max(), true, dataType ), + MessageTextFromValue( skew, true, dataType ), + MessageTextFromValue( maxLength, true, dataType ), maxNetname, + MessageTextFromValue( reportTotal, true, dataType ) ); } drcItem->SetErrorMessage( drcItem->GetErrorText() + " " + msg ); @@ -345,7 +403,7 @@ bool DRC_TEST_PROVIDER_MATCHED_LENGTH::runInternal( bool aDelayReportMode ) return true; } ); - LENGTH_CALCULATION* calc = m_board->GetLengthCalculation(); + LENGTH_DELAY_CALCULATION* calc = m_board->GetLengthCalculation(); std::map< DRC_RULE*, std::vector > matches; @@ -358,7 +416,7 @@ bool DRC_TEST_PROVIDER_MATCHED_LENGTH::runInternal( bool aDelayReportMode ) for( const auto& [netCode, netItems] : netMap ) { - std::vector lengthItems; + std::vector lengthItems; lengthItems.reserve( netItems.size() ); CONNECTION ent; @@ -376,21 +434,28 @@ bool DRC_TEST_PROVIDER_MATCHED_LENGTH::runInternal( bool aDelayReportMode ) for( BOARD_CONNECTED_ITEM* item : netItems ) { - LENGTH_CALCULATION_ITEM lengthItem = calc->GetLengthCalculationItem( item ); + LENGTH_DELAY_CALCULATION_ITEM lengthItem = calc->GetLengthCalculationItem( item ); - if( lengthItem.Type() != LENGTH_CALCULATION_ITEM::TYPE::UNKNOWN ) + if( lengthItem.Type() != LENGTH_DELAY_CALCULATION_ITEM::TYPE::UNKNOWN ) lengthItems.emplace_back( lengthItem ); } constexpr PATH_OPTIMISATIONS opts = { .OptimiseViaLayers = true, .MergeTracks = true, .OptimiseTracesInPads = true, .InferViaInPad = false }; - LENGTH_DETAILS details = calc->CalculateLengthDetails( lengthItems, opts ); + LENGTH_DELAY_STATS details = calc->CalculateLengthDetails( lengthItems, opts, nullptr, nullptr, + LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL, + LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL ); ent.viaCount = details.NumVias; ent.totalVia = details.ViaLength; + ent.totalViaDelay = details.ViaDelay; ent.totalRoute = static_cast( details.TrackLength ); + ent.totalRouteDelay = static_cast( details.TrackDelay ); ent.totalPadToDie = details.PadToDieLength; + ent.totalPadToDieDelay = details.PadToDieDelay; ent.total = ent.totalRoute + ent.totalVia + ent.totalPadToDie; + ent.totalDelay = ent.totalRouteDelay + static_cast( ent.totalViaDelay ) + + static_cast( ent.totalPadToDieDelay ); ent.matchingRule = rule; // fixme: doesn't seem to work ;-) diff --git a/pcbnew/generators/pcb_tuning_pattern.cpp b/pcbnew/generators/pcb_tuning_pattern.cpp index 462ab3b049..61558605ba 100644 --- a/pcbnew/generators/pcb_tuning_pattern.cpp +++ b/pcbnew/generators/pcb_tuning_pattern.cpp @@ -82,11 +82,8 @@ class TUNING_STATUS_VIEW_ITEM : public EDA_ITEM { public: TUNING_STATUS_VIEW_ITEM( PCB_BASE_EDIT_FRAME* aFrame ) : - EDA_ITEM( NOT_USED ), // Never added to anything - just a preview - m_frame( aFrame ), - m_min( 0.0 ), - m_max( 0.0 ), - m_current( 0.0 ) + EDA_ITEM( NOT_USED ), // Never added to anything - just a preview + m_frame( aFrame ), m_min( 0.0 ), m_max( 0.0 ), m_current( 0.0 ), m_isTimeDomain( false ) { } wxString GetClass() const override { return wxT( "TUNING_STATUS" ); } @@ -98,12 +95,14 @@ public: VECTOR2I GetPosition() const override { return m_pos; } void SetPosition( const VECTOR2I& aPos ) override { m_pos = aPos; }; - void SetMinMax( double aMin, double aMax ) + void SetMinMax( const double aMin, const double aMax ) { + const EDA_DATA_TYPE unitType = m_isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE; + m_min = aMin; - m_minText = m_frame->MessageTextFromValue( m_min, false ); + m_minText = m_frame->MessageTextFromValue( m_min, false, unitType ); m_max = aMax; - m_maxText = m_frame->MessageTextFromValue( m_max, false ); + m_maxText = m_frame->MessageTextFromValue( m_max, false, unitType ); } void ClearMinMax() @@ -114,13 +113,17 @@ public: m_maxText = wxT( "---" ); } - void SetCurrent( double aCurrent, const wxString& aLabel ) + void SetCurrent( const double aCurrent, const wxString& aLabel ) { + const EDA_DATA_TYPE unitType = m_isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE; + m_current = aCurrent; - m_currentText = m_frame->MessageTextFromValue( aCurrent ); + m_currentText = m_frame->MessageTextFromValue( aCurrent, true, unitType ); m_currentLabel = aLabel; } + void SetIsTimeDomain( const bool aIsTimeDomain ) { m_isTimeDomain = aIsTimeDomain; } + const BOX2I ViewBBox() const override { BOX2I tmp; @@ -237,6 +240,7 @@ protected: wxString m_currentText; wxString m_minText; wxString m_maxText; + bool m_isTimeDomain; }; @@ -450,15 +454,38 @@ public: void SetTargetLength( std::optional aValue ) { + m_settings.m_isTimeDomain = false; + if( aValue.has_value() ) m_settings.SetTargetLength( aValue.value() ); else m_settings.SetTargetLength( PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED ); } + std::optional GetTargetDelay() const + { + if( m_settings.m_targetLengthDelay.Opt() == PNS::MEANDER_SETTINGS::DELAY_UNCONSTRAINED ) + return std::optional(); + else + return m_settings.m_targetLengthDelay.Opt(); + } + + void SetTargetDelay( std::optional aValue ) + { + m_settings.m_isTimeDomain = true; + + if( aValue.has_value() ) + m_settings.SetTargetLengthDelay( aValue.value() ); + else + m_settings.SetTargetLengthDelay( PNS::MEANDER_SETTINGS::DELAY_UNCONSTRAINED ); + } + int GetTargetSkew() const { return m_settings.m_targetSkew.Opt(); } void SetTargetSkew( int aValue ) { m_settings.SetTargetSkew( aValue ); } + int GetTargetSkewDelay() const { return m_settings.m_targetSkewDelay.Opt(); } + void SetTargetSkewDelay( int aValue ) { m_settings.SetTargetSkewDelay( aValue ); } + bool GetOverrideCustomRules() const { return m_settings.m_overrideCustomRules; } void SetOverrideCustomRules( bool aOverride ) { m_settings.m_overrideCustomRules = aOverride; } @@ -745,17 +772,49 @@ PCB_TUNING_PATTERN* PCB_TUNING_PATTERN::CreateNew( GENERATOR_TOOL* aTool, case DIFF_PAIR_SKEW: pattern->m_settings = bds.m_SkewMeanderSettings; break; } - constraint = bds.m_DRCEngine->EvalRules( LENGTH_CONSTRAINT, aStartItem, nullptr, layer ); - - if( !constraint.IsNull() ) + if( aMode == SINGLE || aMode == DIFF_PAIR ) { - if( aMode == DIFF_PAIR_SKEW ) - pattern->m_settings.SetTargetSkew( constraint.GetValue() ); - else - pattern->m_settings.SetTargetLength( constraint.GetValue() ); + constraint = bds.m_DRCEngine->EvalRules( LENGTH_CONSTRAINT, aStartItem, nullptr, layer ); + + if( !constraint.IsNull() ) + { + if( constraint.GetOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN ) ) + { + pattern->m_settings.SetTargetLengthDelay( constraint.GetValue() ); + pattern->m_settings.SetTargetLength( MINOPTMAX() ); + pattern->m_settings.m_isTimeDomain = true; + } + else + { + pattern->m_settings.SetTargetLengthDelay( MINOPTMAX() ); + pattern->m_settings.SetTargetLength( constraint.GetValue() ); + pattern->m_settings.m_isTimeDomain = false; + } + } + } + else + { + constraint = bds.m_DRCEngine->EvalRules( SKEW_CONSTRAINT, aStartItem, nullptr, layer ); + + if( !constraint.IsNull() ) + { + if( constraint.GetOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN ) ) + { + pattern->m_settings.SetTargetSkew( MINOPTMAX() ); + pattern->m_settings.SetTargetLengthDelay( constraint.GetValue() ); + pattern->m_settings.m_isTimeDomain = true; + } + else + { + pattern->m_settings.SetTargetSkew( constraint.GetValue() ); + pattern->m_settings.SetTargetSkewDelay( MINOPTMAX() ); + pattern->m_settings.m_isTimeDomain = true; + } + } } pattern->SetFlags( IS_NEW ); + pattern->m_settings.m_netClass = aStartItem->GetEffectiveNetClass(); return pattern; } @@ -814,14 +873,15 @@ void PCB_TUNING_PATTERN::EditStart( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_ m_updateSideFromEnd = false; } + PCB_TRACK* track = nullptr; + m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track ); + wxCHECK( track, /* void */ ); + + m_settings.m_netClass = track->GetEffectiveNetClass(); + if( !m_settings.m_overrideCustomRules ) { - PCB_TRACK* track = nullptr; - PNS::SEGMENT pnsItem; - - m_origin = snapToNearestTrack( m_origin, aBoard, nullptr, &track ); - wxCHECK( track, /* void */ ); - + PNS::SEGMENT pnsItem; NETINFO_ITEM* net = track->GetNet(); pnsItem.SetParent( track ); @@ -832,7 +892,18 @@ void PCB_TUNING_PATTERN::EditStart( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_ if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH, &pnsItem, nullptr, layer, &constraint ) ) { - m_settings.SetTargetLength( constraint.m_Value ); + if( constraint.m_IsTimeDomain ) + { + m_settings.SetTargetLengthDelay( constraint.m_Value ); + m_settings.SetTargetLength( MINOPTMAX() ); + } + else + { + m_settings.SetTargetLengthDelay( MINOPTMAX() ); + m_settings.SetTargetLength( constraint.m_Value ); + } + + m_settings.m_isTimeDomain = constraint.m_IsTimeDomain; aTool->GetManager()->PostEvent( EVENTS::SelectedItemsModified ); } } @@ -853,7 +924,18 @@ void PCB_TUNING_PATTERN::EditStart( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_ if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_LENGTH, &pnsItem, &pnsCoupledItem, layer, &constraint ) ) { - m_settings.SetTargetLength( constraint.m_Value ); + if( constraint.m_IsTimeDomain ) + { + m_settings.SetTargetLengthDelay( constraint.m_Value ); + m_settings.SetTargetLength( MINOPTMAX() ); + } + else + { + m_settings.SetTargetLengthDelay( MINOPTMAX() ); + m_settings.SetTargetLength( constraint.m_Value ); + } + + m_settings.m_isTimeDomain = constraint.m_IsTimeDomain; aTool->GetManager()->PostEvent( EVENTS::SelectedItemsModified ); } } @@ -862,7 +944,18 @@ void PCB_TUNING_PATTERN::EditStart( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_ if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_SKEW, &pnsItem, &pnsCoupledItem, layer, &constraint ) ) { - m_settings.m_targetSkew = constraint.m_Value; + if( constraint.m_IsTimeDomain ) + { + m_settings.SetTargetSkewDelay( constraint.m_Value ); + m_settings.SetTargetSkew( MINOPTMAX() ); + } + else + { + m_settings.SetTargetSkewDelay( MINOPTMAX() ); + m_settings.SetTargetSkew( constraint.m_Value ); + } + + m_settings.m_isTimeDomain = constraint.m_IsTimeDomain; aTool->GetManager()->PostEvent( EVENTS::SelectedItemsModified ); } } @@ -1473,8 +1566,16 @@ bool PCB_TUNING_PATTERN::Update( GENERATOR_TOOL* aTool, BOARD* aBoard, BOARD_COM if( aTool->GetManager()->GetSettings() ) userUnits = static_cast( aTool->GetManager()->GetSettings()->m_System.units ); - result = EDA_UNIT_UTILS::UI::MessageTextFromValue( pcbIUScale, userUnits, - (double) placer->TuningResult() ); + if( m_settings.m_isTimeDomain ) + { + result = EDA_UNIT_UTILS::UI::MessageTextFromValue( pcbIUScale, EDA_UNITS::PS, + (double) placer->TuningLengthResult() ); + } + else + { + result = EDA_UNIT_UTILS::UI::MessageTextFromValue( pcbIUScale, userUnits, + (double) placer->TuningLengthResult() ); + } m_tuningInfo.Printf( wxS( "%s (%s)" ), result, statusMessage ); @@ -1900,6 +2001,7 @@ const STRING_ANY_MAP PCB_TUNING_PATTERN::GetProperties() const props.set( "tuning_mode", tuningToString( m_tuningMode ) ); props.set( "initial_side", sideToString( m_settings.m_initialSide ) ); props.set( "last_status", statusToString( m_tuningStatus ) ); + props.set( "is_time_domain", m_settings.m_isTimeDomain ); props.set( "end", m_end ); props.set( "corner_radius_percent", m_settings.m_cornerRadiusPercentage ); @@ -1912,6 +2014,9 @@ const STRING_ANY_MAP PCB_TUNING_PATTERN::GetProperties() const props.set_iu( "target_length_min", m_settings.m_targetLength.Min() ); props.set_iu( "target_length", m_settings.m_targetLength.Opt() ); props.set_iu( "target_length_max", m_settings.m_targetLength.Max() ); + props.set_iu( "target_delay_min", m_settings.m_targetLengthDelay.Min() ); + props.set_iu( "target_delay", m_settings.m_targetLengthDelay.Opt() ); + props.set_iu( "target_delay_max", m_settings.m_targetLengthDelay.Max() ); props.set_iu( "target_skew_min", m_settings.m_targetSkew.Min() ); props.set_iu( "target_skew", m_settings.m_targetSkew.Opt() ); props.set_iu( "target_skew_max", m_settings.m_targetSkew.Max() ); @@ -1948,6 +2053,8 @@ void PCB_TUNING_PATTERN::SetProperties( const STRING_ANY_MAP& aProps ) aProps.get_to( "last_status", status ); m_tuningStatus = statusFromString( status.utf8_string() ); + aProps.get_to( "is_time_domain", m_settings.m_isTimeDomain ); + aProps.get_to( "end", m_end ); aProps.get_to( "corner_radius_percent", m_settings.m_cornerRadiusPercentage ); aProps.get_to( "single_sided", m_settings.m_singleSided ); @@ -1968,6 +2075,15 @@ void PCB_TUNING_PATTERN::SetProperties( const STRING_ANY_MAP& aProps ) if( aProps.get_to_iu( "target_length_max", val ) ) m_settings.m_targetLength.SetMax( val ); + aProps.get_to_iu( "target_delay", val ); + m_settings.SetTargetLengthDelay( val ); + + if( aProps.get_to_iu( "target_delay_min", val ) ) + m_settings.m_targetLengthDelay.SetMin( val ); + + if( aProps.get_to_iu( "target_delay_max", val ) ) + m_settings.m_targetLengthDelay.SetMax( val ); + int int_val; aProps.get_to_iu( "target_skew", int_val ); @@ -2007,10 +2123,46 @@ void PCB_TUNING_PATTERN::ShowPropertiesDialog( PCB_BASE_EDIT_FRAME* aEditFrame ) BOARD_ITEM* startItem = static_cast( *m_items.begin() ); std::shared_ptr& drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine; - constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr, GetLayer() ); + if( m_tuningMode == DIFF_PAIR_SKEW ) + { + constraint = drcEngine->EvalRules( SKEW_CONSTRAINT, startItem, nullptr, GetLayer() ); - if( !constraint.IsNull() && !settings.m_overrideCustomRules ) - settings.SetTargetLength( constraint.GetValue() ); + if( !constraint.IsNull() && !settings.m_overrideCustomRules ) + { + if( constraint.GetOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN ) ) + { + settings.SetTargetLengthDelay( constraint.GetValue() ); + settings.SetTargetLength( MINOPTMAX() ); + settings.m_isTimeDomain = true; + } + else + { + settings.SetTargetLengthDelay( MINOPTMAX() ); + settings.SetTargetLength( constraint.GetValue() ); + settings.m_isTimeDomain = false; + } + } + } + else + { + constraint = drcEngine->EvalRules( LENGTH_CONSTRAINT, startItem, nullptr, GetLayer() ); + + if( !constraint.IsNull() && !settings.m_overrideCustomRules ) + { + if( constraint.GetOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN ) ) + { + settings.SetTargetLengthDelay( constraint.GetValue() ); + settings.SetTargetLength( MINOPTMAX() ); + settings.m_isTimeDomain = true; + } + else + { + settings.SetTargetLengthDelay( MINOPTMAX() ); + settings.SetTargetLength( constraint.GetValue() ); + settings.m_isTimeDomain = false; + } + } + } } DIALOG_TUNING_PATTERN_PROPERTIES dlg( aEditFrame, settings, GetPNSMode(), constraint ); @@ -2052,25 +2204,55 @@ std::vector PCB_TUNING_PATTERN::GetPreviewItems( GENERATOR_TOOL* aToo if( m_tuningMode == DIFF_PAIR_SKEW ) { - statusItem->SetMinMax( m_settings.m_targetSkew.Min(), m_settings.m_targetSkew.Max() ); + if( m_settings.m_isTimeDomain ) + statusItem->SetMinMax( m_settings.m_targetSkewDelay.Min(), m_settings.m_targetSkewDelay.Max() ); + else + statusItem->SetMinMax( m_settings.m_targetSkew.Min(), m_settings.m_targetSkew.Max() ); } else { - if( m_settings.m_targetLength.Opt() == PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED ) + if( m_settings.m_isTimeDomain ) { - statusItem->ClearMinMax(); + if( m_settings.m_targetLengthDelay.Opt() == PNS::MEANDER_SETTINGS::DELAY_UNCONSTRAINED ) + { + statusItem->ClearMinMax(); + } + else + { + statusItem->SetMinMax( static_cast( m_settings.m_targetLengthDelay.Min() ), + static_cast( m_settings.m_targetLengthDelay.Max() ) ); + } } else { - statusItem->SetMinMax( (double) m_settings.m_targetLength.Min(), - (double) m_settings.m_targetLength.Max() ); + if( m_settings.m_targetLengthDelay.Opt() == PNS::MEANDER_SETTINGS::LENGTH_UNCONSTRAINED ) + { + statusItem->ClearMinMax(); + } + else + { + statusItem->SetMinMax( static_cast( m_settings.m_targetLength.Min() ), + static_cast( m_settings.m_targetLength.Max() ) ); + } } } + statusItem->SetIsTimeDomain( m_settings.m_isTimeDomain ); + if( m_tuningMode == DIFF_PAIR_SKEW ) - statusItem->SetCurrent( (double) placer->TuningResult(), _( "current skew" ) ); + { + if( m_settings.m_isTimeDomain ) + statusItem->SetCurrent( static_cast( placer->TuningDelayResult() ), _( "current skew" ) ); + else + statusItem->SetCurrent( static_cast( placer->TuningLengthResult() ), _( "current skew" ) ); + } else - statusItem->SetCurrent( (double) placer->TuningResult(), _( "current length" ) ); + { + if( m_settings.m_isTimeDomain ) + statusItem->SetCurrent( static_cast( placer->TuningDelayResult() ), _( "current delay" ) ); + else + statusItem->SetCurrent( static_cast( placer->TuningLengthResult() ), _( "current length" ) ); + } statusItem->SetPosition( aFrame->GetToolManager()->GetMousePosition() ); previewItems.push_back( statusItem ); @@ -2092,6 +2274,8 @@ void PCB_TUNING_PATTERN::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, int width = 0; bool mixedWidth = false; + EDA_DATA_TYPE unitType = m_settings.m_isTimeDomain ? EDA_DATA_TYPE::TIME : EDA_DATA_TYPE::DISTANCE; + aList.emplace_back( _( "Type" ), GetFriendlyName() ); for( EDA_ITEM* member : GetItems() ) @@ -2146,27 +2330,51 @@ void PCB_TUNING_PATTERN::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, // Display full track length (in Pcbnew) if( board && primaryItem && primaryItem->GetNetCode() > 0 ) { - int count; - double trackLen; - double lenPadToDie; + int count = 0; + double trackLen = 0.0; + double lenPadToDie = 0.0; + double trackDelay = 0.0; + double delayPadToDie = 0.0; - std::tie( count, trackLen, lenPadToDie ) = board->GetTrackLength( *primaryItem ); + std::tie( count, trackLen, lenPadToDie, trackDelay, delayPadToDie ) = board->GetTrackLength( *primaryItem ); if( coupledItem && coupledItem->GetNetCode() > 0 ) { - double coupledLen; - std::tie( count, coupledLen, lenPadToDie ) = board->GetTrackLength( *coupledItem ); + double coupledLen = 0.0; + double coupledLenPadToDie = 0.0; + double coupledTrackDelay = 0.0; + double doubledDelayPadToDie = 0.0; - aList.emplace_back( _( "Routed Lengths" ), aFrame->MessageTextFromValue( trackLen ) - + wxS( ", " ) - + aFrame->MessageTextFromValue( coupledLen ) ); + std::tie( count, coupledLen, coupledLenPadToDie, coupledTrackDelay, doubledDelayPadToDie ) = + board->GetTrackLength( *coupledItem ); + + if( trackDelay == 0.0 || coupledTrackDelay == 0.0 ) + { + aList.emplace_back( _( "Routed Lengths" ), aFrame->MessageTextFromValue( trackLen ) + wxS( ", " ) + + aFrame->MessageTextFromValue( coupledLen ) ); + } + else + { + aList.emplace_back( + _( "Routed Delays" ), + aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) + wxS( ", " ) + + aFrame->MessageTextFromValue( coupledTrackDelay, true, EDA_DATA_TYPE::TIME ) ); + } } else { - aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) ); + if( trackDelay == 0.0 ) + { + aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) ); + } + else + { + aList.emplace_back( _( "Routed Delay" ), + aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) ); + } } - if( lenPadToDie != 0 ) + if( lenPadToDie != 0 && delayPadToDie == 0.0 ) { msg = aFrame->MessageTextFromValue( lenPadToDie ); aList.emplace_back( _( "Pad To Die Length" ), msg ); @@ -2174,6 +2382,14 @@ void PCB_TUNING_PATTERN::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie ); aList.emplace_back( _( "Full Length" ), msg ); } + else if( delayPadToDie > 0.0 ) + { + msg = aFrame->MessageTextFromValue( delayPadToDie, true, EDA_DATA_TYPE::TIME ); + aList.emplace_back( _( "Pad To Die Delay" ), msg ); + + msg = aFrame->MessageTextFromValue( trackDelay + delayPadToDie, true, EDA_DATA_TYPE::TIME ); + aList.emplace_back( _( "Full Delay" ), msg ); + } } if( m_tuningMode == DIFF_PAIR_SKEW ) @@ -2204,18 +2420,32 @@ void PCB_TUNING_PATTERN::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, if( constraint.IsNull() || m_settings.m_overrideCustomRules ) { - msg = aFrame->MessageTextFromValue( (double) m_settings.m_targetLength.Opt() ); + wxString caption; - aList.emplace_back( wxString::Format( _( "Target Length: %s" ), msg ), + if( m_settings.m_isTimeDomain ) + { + caption = _( "Target Delay: %s" ); + msg = aFrame->MessageTextFromValue( static_cast( m_settings.m_targetLengthDelay.Opt() ), true, + EDA_DATA_TYPE::TIME ); + } + else + { + caption = _( "Target Length: %s" ); + msg = aFrame->MessageTextFromValue( static_cast( m_settings.m_targetLength.Opt() ) ); + } + + aList.emplace_back( wxString::Format( caption, msg ), wxString::Format( _( "(from tuning pattern properties)" ) ) ); } else { - msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue() ); + msg = aFrame->MessageTextFromMinOptMax( constraint.GetValue(), unitType ); + + wxString caption = m_settings.m_isTimeDomain ? _( "Delay Constraints: %s" ) : _( "Length Constraints: %s" ); if( !msg.IsEmpty() ) { - aList.emplace_back( wxString::Format( _( "Length Constraints: %s" ), msg ), + aList.emplace_back( wxString::Format( caption, msg ), wxString::Format( _( "(from %s)" ), constraint.GetName() ) ); } } @@ -2673,28 +2903,61 @@ static struct PCB_TUNING_PATTERN_DESC return false; }; - auto notIsSkew = - [&]( INSPECTABLE* aItem ) -> bool - { - return !isSkew( aItem ); - }; + auto isTimeDomain = []( INSPECTABLE* aItem ) -> bool + { + if( PCB_TUNING_PATTERN* pattern = dynamic_cast( aItem ) ) + return pattern->GetSettings().m_isTimeDomain; + + return false; + }; + + auto isLengthIsSpaceDomain = [&]( INSPECTABLE* aItem ) -> bool + { + return !isSkew( aItem ) && !isTimeDomain( aItem ); + }; + + auto isLengthIsTimeDomain = [&]( INSPECTABLE* aItem ) -> bool + { + return !isSkew( aItem ) && isTimeDomain( aItem ); + }; + + auto isSkewIsSpaceDomain = [&]( INSPECTABLE* aItem ) -> bool + { + return isSkew( aItem ) && !isTimeDomain( aItem ); + }; + + auto isSkewIsTimeDomain = [&]( INSPECTABLE* aItem ) -> bool + { + return isSkew( aItem ) && isTimeDomain( aItem ); + }; propMgr.AddProperty( new PROPERTY>( - _HKI( "Target Length" ), - &PCB_TUNING_PATTERN::SetTargetLength, - &PCB_TUNING_PATTERN::GetTargetLength, - PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ), + _HKI( "Target Length" ), &PCB_TUNING_PATTERN::SetTargetLength, + &PCB_TUNING_PATTERN::GetTargetLength, PROPERTY_DISPLAY::PT_SIZE, + ORIGIN_TRANSFORMS::ABS_X_COORD ), groupTab ) - .SetAvailableFunc( notIsSkew ); + .SetAvailableFunc( isLengthIsSpaceDomain ); + propMgr.AddProperty( new PROPERTY>( + _HKI( "Target Delay" ), &PCB_TUNING_PATTERN::SetTargetDelay, + &PCB_TUNING_PATTERN::GetTargetDelay, PROPERTY_DISPLAY::PT_TIME, + ORIGIN_TRANSFORMS::NOT_A_COORD ), + groupTab ) + .SetAvailableFunc( isLengthIsTimeDomain ); propMgr.AddProperty( new PROPERTY( _HKI( "Target Skew" ), &PCB_TUNING_PATTERN::SetTargetSkew, - &PCB_TUNING_PATTERN::GetTargetSkew, - PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::ABS_X_COORD ), + &PCB_TUNING_PATTERN::GetTargetSkew, PROPERTY_DISPLAY::PT_SIZE, + ORIGIN_TRANSFORMS::ABS_X_COORD ), groupTab ) - .SetAvailableFunc( isSkew ); + .SetAvailableFunc( isSkewIsSpaceDomain ); + propMgr.AddProperty( new PROPERTY( + _HKI( "Target Skew Delay" ), &PCB_TUNING_PATTERN::SetTargetSkewDelay, + &PCB_TUNING_PATTERN::GetTargetSkewDelay, PROPERTY_DISPLAY::PT_TIME, + ORIGIN_TRANSFORMS::NOT_A_COORD ), + groupTab ) + .SetAvailableFunc( isSkewIsTimeDomain ); propMgr.AddProperty( new PROPERTY( _HKI( "Override Custom Rules" ), diff --git a/pcbnew/length_calculation.h b/pcbnew/length_calculation.h deleted file mode 100644 index 619e6e1498..0000000000 --- a/pcbnew/length_calculation.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright The KiCad Developers, see AUTHORS.txt for contributors. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifndef PCBNEW_LENGTH_CALCULATION_H -#define PCBNEW_LENGTH_CALCULATION_H - -#include -#include -#include -#include -#include -#include -#include - -class BOARD; - -/** - * Lightweight class which holds a pad, via, or a routed trace outline. Proxied objects passed by pointer are not - * owned by this container. - */ -class LENGTH_CALCULATION_ITEM -{ -public: - /// The type of routing object this item proxies - enum class TYPE - { - UNKNOWN, - PAD, - LINE, - VIA - }; - - /// Whether this item is UNMERGED, it has been merged and should be used (MERGED_IN_USE), or it has been merged - /// and has been retired from use (MERGED_RETIRED). MERGED_RETIRED essentially means the object has been merged - /// in to a MERGED_IN_USE item. - enum class MERGE_STATUS - { - UNMERGED, - MERGED_IN_USE, - MERGED_RETIRED - }; - - /// Gets the routing item type - TYPE Type() const { return m_type; }; - - /// Sets the parent PAD associated with this item - void SetPad( PAD* aPad ) - { - m_type = TYPE::PAD; - m_pad = aPad; - } - - /// Gets the parent PAD associated with this item - PAD* GetPad() const { return m_pad; } - - /// Sets the source SHAPE_LINE_CHAIN of this item - void SetLine( const SHAPE_LINE_CHAIN& aLine ) - { - m_type = TYPE::LINE; - m_line = aLine; - } - - /// Gets the SHAPE_LINE_CHAIN associated with this item - SHAPE_LINE_CHAIN& GetLine() const { return m_line; } - - /// Sets the VIA associated with this item - void SetVia( PCB_VIA* aVia ) - { - m_type = TYPE::VIA; - m_via = aVia; - } - - /// Gets the VIA associated with this item - PCB_VIA* GetVia() const { return m_via; } - - /// Sets the first and last layers associated with this item - void SetLayers( const PCB_LAYER_ID aStart, const PCB_LAYER_ID aEnd = PCB_LAYER_ID::UNDEFINED_LAYER ) - { - m_layerStart = aStart; - m_layerEnd = aEnd; - } - - /// Sets the MERGE_STATUS of this item. MERGED_RETIRED essentially means the object has been merged - /// in to a MERGED_IN_USE item. - void SetMergeStatus( const MERGE_STATUS aStatus ) { m_mergeStatus = aStatus; } - - /// Gets the MERGE_STATUS of this item - MERGE_STATUS GetMergeStatus() const { return m_mergeStatus; } - - /// Gets the upper and lower layers for the proxied item - std::tuple GetLayers() const { return { m_layerStart, m_layerEnd }; } - - /// Gets the start board layer for the proxied item - PCB_LAYER_ID GetStartLayer() const { return m_layerStart; } - - /// Gets the end board layer for the proxied item. - PCB_LAYER_ID GetEndLayer() const { return m_layerEnd; } - - /// Calculates active via payers for a proxied VIA object - void CalculateViaLayers( const BOARD* aBoard ); - -protected: - /// A proxied PAD object. Set to nullptr if not proxying a PAD. - PAD* m_pad{ nullptr }; - - /// A proxied SHAPE_LINE_CHAIN object. Line is empty if not proxying a SHAPE_LINE_CHAIN. - mutable SHAPE_LINE_CHAIN m_line; - - /// A proxied PVIAAD object. Set to nullptr if not proxying a VIA. - PCB_VIA* m_via{ nullptr }; - - /// The start board layer for the proxied object - PCB_LAYER_ID m_layerStart{ PCB_LAYER_ID::UNDEFINED_LAYER }; - - /// The end board layer for the proxied object - PCB_LAYER_ID m_layerEnd{ PCB_LAYER_ID::UNDEFINED_LAYER }; - - /// Flags whether this item has already been merged with another - MERGE_STATUS m_mergeStatus{ MERGE_STATUS::UNMERGED }; - - /// The routing object type of the proxied parent - TYPE m_type{ TYPE::UNKNOWN }; -}; - - -/** -* Holds length measurement result details and statistics -*/ -struct LENGTH_DETAILS -{ - int NumPads{ 0 }; - int NumVias{ 0 }; - int ViaLength{ 0 }; - int64_t TrackLength{ 0 }; - int PadToDieLength{ 0 }; - std::unique_ptr> LayerLengths; - - int64_t TotalLength() const { return ViaLength + TrackLength + PadToDieLength; } -}; - - -/** - * Struct to control which optimisations the length calculation code runs on - * the given path objects. This is required as some call sites (e.g. PNS) run - * their own path optimisation, whereas others (e.g. Net Inspector) do not. - */ -struct PATH_OPTIMISATIONS -{ - /// Optimise via layers for height calculations, ensuring only the distance - /// between routed segments is considered - bool OptimiseViaLayers = false; - - /// Merges all contiguous (end-to-end, same layer) tracks - bool MergeTracks = false; - - /// Optimises the electrical length of tracks within pads. Note that the track - /// must terminate at the trace anchor point to be considered for - /// optimisation. Will require MergeTracks if used with a non-contiguous item - /// set. - bool OptimiseTracesInPads = false; - - /// Determines if there is a via-in-pad present on the board but not in the - /// item set. This condition can arise from the PNS meander placer. - /// TODO (JJ): This can be fixed in the router - bool InferViaInPad = false; -}; - - -/** -* Class which calculates lengths (and associated routing statistics) in a BOARD context -*/ -class LENGTH_CALCULATION -{ -public: - /// Construct the calculator in the given BOARD context - explicit LENGTH_CALCULATION( BOARD* aBoard ) : m_board( aBoard ) {} - - /** - * @brief Calculates the electrical length of the given items - * @param aItems is the vector of items making up the route - * @param aPathType indicates whether this is an ordered route, or an unordered collection - * @param aOptimised indicates whether this has been optimised for electrical length (e.g. clipping within pads) - * @param aStartPad is the starting pad of the route - * @param aEndPad is the ending pad of the route - */ - int64_t CalculateLength( std::vector& aItems, PATH_OPTIMISATIONS aOptimisations, - const PAD* aStartPad = nullptr, const PAD* aEndPad = nullptr ) const; - - /** - * @brief Calculates the electrical length of the given items - * @param aItems is the vector of items making up the route - * @param aPathType indicates whether this is an ordered route, or an unordered collection - * @param aOptimised indicates whether this has been optimised for electrical length (e.g. clipping within pads) - * @param aStartPad is the starting pad of the route - * @param aEndPad is the ending pad of the route - * @param aWithLayerLengths indicates whether the layer length structure should be populated - */ - LENGTH_DETAILS CalculateLengthDetails( std::vector& aItems, - PATH_OPTIMISATIONS aOptimisations, const PAD* aStartPad = nullptr, - const PAD* aEndPad = nullptr, bool aWithLayerLengths = false ) const; - - /// Optimises the given trace / line to minimise the electrical path length within the given pad - static void OptimiseTraceInPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad, PCB_LAYER_ID aPcbLayer ); - - /// Return a LENGTH_CALCULATION_ITEM constructed from the given BOARD_CONNECTED_ITEM - LENGTH_CALCULATION_ITEM GetLengthCalculationItem( BOARD_CONNECTED_ITEM* aBoardItem ) const; - -protected: - /// The parent board for all items - BOARD* m_board; - - /// Enum to describe whether track merging is attempted from the start or end of a track segment - enum class MERGE_POINT - { - START, - END - }; - - /** - * Returns the stackup distance between the two given layers. - * - * Note: Can return 0 if the board design settings disallow stackup height calculations - */ - int stackupHeight( PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer ) const; - - /** - * Optimises the given set of items to minimise the electrical path length. At the moment - * only optimises lines attached to pads, future work could optimise paths through pads - * - * Assumes that any polylines are only connected at either end, and not at midpoints - */ - static void optimiseTracesInPads( const std::vector& aPads, - const std::vector& aLines ); - - /// Clips the given line to the minimal direct electrical length within the pad - static void clipLineToPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad, PCB_LAYER_ID aLayer, bool aForward = true ); - - /** - * Optimises the via layers. Ensures that vias that are routed through only on one layer do not count towards total - * length calculations. - */ - static void - optimiseViaLayers( const std::vector& aVias, - std::vector& aLines, - std::map>& aLinesPositionMap, - const std::map>& aPadsPositionMap ); - - /** - * Merges any lines (traces) that are contiguous, on one layer, and with no junctions - */ - static void mergeLines( std::vector& aLines, - std::map>& aLinesPositionMap ); - - /** - * Merges two SHAPE_LINE_CHAINs where there is a shared endpoing. - * - * aSecondary is merged in to aPrimary - */ - static void mergeShapeLineChains( SHAPE_LINE_CHAIN& aPrimary, const SHAPE_LINE_CHAIN& aSecondary, - MERGE_POINT aMergePoint ); - - /** - * Infers if there is a via in the given pad. Adds via details to the length details data structure if found. - */ - void inferViaInPad( const PAD* aPad, const LENGTH_CALCULATION_ITEM& aItem, LENGTH_DETAILS& aDetails ) const; -}; - -#endif //PCBNEW_LENGTH_CALCULATION_H diff --git a/pcbnew/length_calculation.cpp b/pcbnew/length_delay_calculation/length_delay_calculation.cpp similarity index 60% rename from pcbnew/length_calculation.cpp rename to pcbnew/length_delay_calculation/length_delay_calculation.cpp index 365f6e83fa..619ed47fa8 100644 --- a/pcbnew/length_calculation.cpp +++ b/pcbnew/length_delay_calculation/length_delay_calculation.cpp @@ -21,14 +21,14 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include +#include #include #include #include -void LENGTH_CALCULATION_ITEM::CalculateViaLayers( const BOARD* aBoard ) +void LENGTH_DELAY_CALCULATION_ITEM::CalculateViaLayers( const BOARD* aBoard ) { static std::initializer_list traceAndPadTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T }; @@ -53,11 +53,12 @@ void LENGTH_CALCULATION_ITEM::CalculateViaLayers( const BOARD* aBoard ) if( bottom_layer == UNDEFINED_LAYER ) bottom_layer = m_via->BottomLayer(); - SetLayers( bottom_layer, top_layer ); + SetLayers( top_layer, bottom_layer ); } -void LENGTH_CALCULATION::clipLineToPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad, PCB_LAYER_ID aLayer, bool aForward ) +void LENGTH_DELAY_CALCULATION::clipLineToPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad, PCB_LAYER_ID aLayer, + bool aForward ) { const int start = aForward ? 0 : aLine.PointCount() - 1; const int delta = aForward ? 1 : -1; @@ -106,36 +107,37 @@ void LENGTH_CALCULATION::clipLineToPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad } -LENGTH_DETAILS LENGTH_CALCULATION::CalculateLengthDetails( std::vector& aItems, - const PATH_OPTIMISATIONS aOptimisations, - const PAD* aStartPad, const PAD* aEndPad, - const bool aWithLayerLengths ) const +LENGTH_DELAY_STATS LENGTH_DELAY_CALCULATION::CalculateLengthDetails( std::vector& aItems, + const PATH_OPTIMISATIONS aOptimisations, + const PAD* aStartPad, const PAD* aEndPad, + const LENGTH_DELAY_LAYER_OPT aLayerOpt, + const LENGTH_DELAY_DOMAIN_OPT aDomain ) const { // If this set of items has not been optimised, optimise for shortest electrical path if( aOptimisations.OptimiseViaLayers || aOptimisations.MergeTracks || aOptimisations.MergeTracks ) { - std::vector pads; - std::vector lines; - std::vector vias; + std::vector pads; + std::vector lines; + std::vector vias; // Map of line endpoints to line objects - std::map> linesPositionMap; + std::map> linesPositionMap; // Map of pad positions to pad objects - std::map> padsPositionMap; + std::map> padsPositionMap; - for( LENGTH_CALCULATION_ITEM& item : aItems ) + for( LENGTH_DELAY_CALCULATION_ITEM& item : aItems ) { - if( item.Type() == LENGTH_CALCULATION_ITEM::TYPE::PAD ) + if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD ) { pads.emplace_back( &item ); padsPositionMap[item.GetPad()->GetPosition()].insert( &item ); } - else if( item.Type() == LENGTH_CALCULATION_ITEM::TYPE::VIA ) + else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA ) { vias.emplace_back( &item ); } - else if( item.Type() == LENGTH_CALCULATION_ITEM::TYPE::LINE ) + else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE ) { lines.emplace_back( &item ); linesPositionMap[item.GetLine().CPoint( 0 )].insert( &item ); @@ -153,11 +155,17 @@ LENGTH_DETAILS LENGTH_CALCULATION::CalculateLengthDetails( std::vector>(); + if( aDomain == LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL ) + details.LayerDelays = std::make_unique>(); + } + const bool useHeight = m_board->GetDesignSettings().m_UseHeightForLengthCalcs; // If this is a contiguous set of items, check if we have an inferred fanout via at either end. Note that this @@ -170,16 +178,17 @@ LENGTH_DETAILS LENGTH_CALCULATION::CalculateLengthDetails( std::vectorGetPadToDieLength(); details.NumPads += 1; } } + // Calculate the time domain statistics if required + if( aDomain == LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL ) + { + // TODO(JJ): Populate this + TIME_DOMAIN_GEOMETRY_CONTEXT ctx; + ctx.NetClass = aItems.front().GetEffectiveNetClass(); // We don't care if this is merged for net class lookup + + const std::vector itemDelays = m_timeDomainParameters->GetPropagationDelays( aItems, ctx ); + + wxASSERT( itemDelays.size() == aItems.size() ); + + for( size_t i = 0; i < aItems.size(); ++i ) + { + const LENGTH_DELAY_CALCULATION_ITEM& item = aItems[i]; + + if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE ) + { + details.TrackDelay += itemDelays[i]; + + if( details.LayerDelays ) + ( *details.LayerDelays )[item.GetStartLayer()] += itemDelays[i]; + } + else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA && useHeight ) + { + details.ViaDelay += itemDelays[i]; + } + else if( item.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD ) + { + details.PadToDieDelay += itemDelays[i]; + } + } + } + return details; } -void LENGTH_CALCULATION::inferViaInPad( const PAD* aPad, const LENGTH_CALCULATION_ITEM& aItem, - LENGTH_DETAILS& aDetails ) const +void LENGTH_DELAY_CALCULATION::inferViaInPad( const PAD* aPad, const LENGTH_DELAY_CALCULATION_ITEM& aItem, + LENGTH_DELAY_STATS& aDetails ) const { - if( aPad && aItem.Type() == LENGTH_CALCULATION_ITEM::TYPE::LINE ) + if( aPad && aItem.Type() == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE ) { const PCB_LAYER_ID startBottomLayer = aItem.GetStartLayer(); const LSET padLayers = aPad->Padstack().LayerSet(); @@ -219,21 +261,31 @@ void LENGTH_CALCULATION::inferViaInPad( const PAD* aPad, const LENGTH_CALCULATIO const PCB_LAYER_ID padLayer = padLayers.Contains( F_Cu ) ? F_Cu : B_Cu; aDetails.NumVias += 1; - aDetails.ViaLength += stackupHeight( startBottomLayer, padLayer ); + aDetails.ViaLength += StackupHeight( startBottomLayer, padLayer ); } } } -int64_t LENGTH_CALCULATION::CalculateLength( std::vector& aItems, - const PATH_OPTIMISATIONS aOptimisations, const PAD* aStartPad, - const PAD* aEndPad ) const +int64_t LENGTH_DELAY_CALCULATION::CalculateLength( std::vector& aItems, + const PATH_OPTIMISATIONS aOptimisations, const PAD* aStartPad, + const PAD* aEndPad ) const { return CalculateLengthDetails( aItems, aOptimisations, aStartPad, aEndPad ).TotalLength(); } -int LENGTH_CALCULATION::stackupHeight( const PCB_LAYER_ID aFirstLayer, const PCB_LAYER_ID aSecondLayer ) const +int64_t LENGTH_DELAY_CALCULATION::CalculateDelay( std::vector& aItems, + const PATH_OPTIMISATIONS aOptimisations, const PAD* aStartPad, + const PAD* aEndPad ) const +{ + return CalculateLengthDetails( aItems, aOptimisations, aStartPad, aEndPad, LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL, + LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL ) + .TotalDelay(); +} + + +int LENGTH_DELAY_CALCULATION::StackupHeight( const PCB_LAYER_ID aFirstLayer, const PCB_LAYER_ID aSecondLayer ) const { if( !m_board || !m_board->GetDesignSettings().m_UseHeightForLengthCalcs ) return 0; @@ -252,23 +304,23 @@ int LENGTH_CALCULATION::stackupHeight( const PCB_LAYER_ID aFirstLayer, const PCB } -void LENGTH_CALCULATION::mergeLines( - std::vector& aLines, - std::map>& aLinesPositionMap ) +void LENGTH_DELAY_CALCULATION::mergeLines( + std::vector& aLines, + std::map>& aLinesPositionMap ) { // Vector of pads, and an associated flag to indicate whether they have been visited by the clustering algorithm - std::vector pads; + std::vector pads; - auto removeFromPositionMap = [&aLinesPositionMap]( LENGTH_CALCULATION_ITEM* line ) + auto removeFromPositionMap = [&aLinesPositionMap]( LENGTH_DELAY_CALCULATION_ITEM* line ) { aLinesPositionMap[line->GetLine().CPoint( 0 )].erase( line ); aLinesPositionMap[line->GetLine().CLastPoint()].erase( line ); }; // Attempts to merge unmerged lines in to aPrimaryLine - auto tryMerge = [&removeFromPositionMap, &aLinesPositionMap]( const MERGE_POINT aMergePoint, - const VECTOR2I& aMergePos, - const LENGTH_CALCULATION_ITEM* aPrimaryItem, + auto tryMerge = [&removeFromPositionMap, &aLinesPositionMap]( const MERGE_POINT aMergePoint, + const VECTOR2I& aMergePos, + const LENGTH_DELAY_CALCULATION_ITEM* aPrimaryItem, SHAPE_LINE_CHAIN& aPrimaryLine, bool* aDidMerge ) { const auto startItr = aLinesPositionMap.find( aMergePos ); @@ -276,12 +328,12 @@ void LENGTH_CALCULATION::mergeLines( if( startItr == aLinesPositionMap.end() ) return; - std::unordered_set& startItems = startItr->second; + std::unordered_set& startItems = startItr->second; if( startItems.size() != 1 ) return; - LENGTH_CALCULATION_ITEM* lineToMerge = *startItems.begin(); + LENGTH_DELAY_CALCULATION_ITEM* lineToMerge = *startItems.begin(); // Don't merge if line is an arc if( !lineToMerge->GetLine().CArcs().empty() ) @@ -292,17 +344,17 @@ void LENGTH_CALCULATION::mergeLines( return; // Merge the lines - lineToMerge->SetMergeStatus( LENGTH_CALCULATION_ITEM::MERGE_STATUS::MERGED_RETIRED ); + lineToMerge->SetMergeStatus( LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::MERGED_RETIRED ); mergeShapeLineChains( aPrimaryLine, lineToMerge->GetLine(), aMergePoint ); removeFromPositionMap( lineToMerge ); *aDidMerge = true; }; // Cluster all lines in to contiguous entities - for( LENGTH_CALCULATION_ITEM* primaryItem : aLines ) + for( LENGTH_DELAY_CALCULATION_ITEM* primaryItem : aLines ) { // Don't start with an already merged line - if( primaryItem->GetMergeStatus() != LENGTH_CALCULATION_ITEM::MERGE_STATUS::UNMERGED ) + if( primaryItem->GetMergeStatus() != LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::UNMERGED ) continue; // Remove starting line from the position map @@ -311,7 +363,7 @@ void LENGTH_CALCULATION::mergeLines( SHAPE_LINE_CHAIN& primaryLine = primaryItem->GetLine(); // Merge all endpoints - primaryItem->SetMergeStatus( LENGTH_CALCULATION_ITEM::MERGE_STATUS::MERGED_IN_USE ); + primaryItem->SetMergeStatus( LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::MERGED_IN_USE ); bool mergeComplete = false; while( !mergeComplete ) @@ -331,8 +383,8 @@ void LENGTH_CALCULATION::mergeLines( } -void LENGTH_CALCULATION::mergeShapeLineChains( SHAPE_LINE_CHAIN& aPrimary, const SHAPE_LINE_CHAIN& aSecondary, - const MERGE_POINT aMergePoint ) +void LENGTH_DELAY_CALCULATION::mergeShapeLineChains( SHAPE_LINE_CHAIN& aPrimary, const SHAPE_LINE_CHAIN& aSecondary, + const MERGE_POINT aMergePoint ) { if( aMergePoint == MERGE_POINT::START ) { @@ -367,17 +419,17 @@ void LENGTH_CALCULATION::mergeShapeLineChains( SHAPE_LINE_CHAIN& aPrimary, const } -void LENGTH_CALCULATION::optimiseTracesInPads( const std::vector& aPads, - const std::vector& aLines ) +void LENGTH_DELAY_CALCULATION::optimiseTracesInPads( const std::vector& aPads, + const std::vector& aLines ) { - for( LENGTH_CALCULATION_ITEM* padItem : aPads ) + for( LENGTH_DELAY_CALCULATION_ITEM* padItem : aPads ) { - PAD* pad = padItem->GetPad(); + const PAD* pad = padItem->GetPad(); - for( LENGTH_CALCULATION_ITEM* lineItem : aLines ) + for( LENGTH_DELAY_CALCULATION_ITEM* lineItem : aLines ) { // Ignore merged lines - if( lineItem->GetMergeStatus() != LENGTH_CALCULATION_ITEM::MERGE_STATUS::MERGED_IN_USE ) + if( lineItem->GetMergeStatus() != LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::MERGED_IN_USE ) continue; const PCB_LAYER_ID pcbLayer = lineItem->GetStartLayer(); @@ -389,19 +441,19 @@ void LENGTH_CALCULATION::optimiseTracesInPads( const std::vector& aVias, std::vector& aLines, - std::map>& aLinesPositionMap, - const std::map>& aPadsPositionMap ) +void LENGTH_DELAY_CALCULATION::optimiseViaLayers( + const std::vector& aVias, std::vector& aLines, + std::map>& aLinesPositionMap, + const std::map>& aPadsPositionMap ) { - for( LENGTH_CALCULATION_ITEM* via : aVias ) + for( LENGTH_DELAY_CALCULATION_ITEM* via : aVias ) { auto lineItr = aLinesPositionMap.find( via->GetVia()->GetPosition() ); if( lineItr == aLinesPositionMap.end() ) continue; - std::unordered_set& connectedLines = lineItr->second; + std::unordered_set& connectedLines = lineItr->second; if( connectedLines.empty() ) { @@ -419,11 +471,11 @@ void LENGTH_CALCULATION::optimiseViaLayers( if( padItr != aPadsPositionMap.end() ) { // This could be a via-in-pad - check for overlapping pads which are not on the line layer - const std::unordered_set& pads = padItr->second; + const std::unordered_set& pads = padItr->second; if( pads.size() == 1 ) { - const LENGTH_CALCULATION_ITEM* padItem = *pads.begin(); + const LENGTH_DELAY_CALCULATION_ITEM* padItem = *pads.begin(); if( !padItem->GetPad()->Padstack().LayerSet().Contains( lineLayer ) ) { @@ -446,7 +498,7 @@ void LENGTH_CALCULATION::optimiseViaLayers( // than the overall via span) LSET layers; - for( const LENGTH_CALCULATION_ITEM* lineItem : connectedLines ) + for( const LENGTH_DELAY_CALCULATION_ITEM* lineItem : connectedLines ) layers.set( lineItem->GetStartLayer() ); LSEQ cuStack = layers.CuStack(); @@ -471,7 +523,8 @@ void LENGTH_CALCULATION::optimiseViaLayers( } -void LENGTH_CALCULATION::OptimiseTraceInPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad, const PCB_LAYER_ID aPcbLayer ) +void LENGTH_DELAY_CALCULATION::OptimiseTraceInPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad, + const PCB_LAYER_ID aPcbLayer ) { // Only consider lines which terminate in the pad if( aLine.CPoint( 0 ) != aPad->GetPosition() && aLine.CLastPoint() != aPad->GetPosition() ) @@ -489,31 +542,34 @@ void LENGTH_CALCULATION::OptimiseTraceInPad( SHAPE_LINE_CHAIN& aLine, const PAD* } -LENGTH_CALCULATION_ITEM LENGTH_CALCULATION::GetLengthCalculationItem( BOARD_CONNECTED_ITEM* aBoardItem ) const +LENGTH_DELAY_CALCULATION_ITEM +LENGTH_DELAY_CALCULATION::GetLengthCalculationItem( const BOARD_CONNECTED_ITEM* aBoardItem ) const { - if( PCB_TRACK* track = dynamic_cast( aBoardItem ) ) + if( const PCB_TRACK* track = dynamic_cast( aBoardItem ) ) { if( track->Type() == PCB_VIA_T ) { - PCB_VIA* via = static_cast( track ); + const PCB_VIA* via = static_cast( track ); - LENGTH_CALCULATION_ITEM item; + LENGTH_DELAY_CALCULATION_ITEM item; item.SetVia( via ); item.CalculateViaLayers( m_board ); + item.SetEffectiveNetClass( via->GetEffectiveNetClass() ); return item; } if( track->Type() == PCB_ARC_T ) { - PCB_ARC* arcParent = static_cast( track ); + const PCB_ARC* arcParent = static_cast( track ); SHAPE_ARC shapeArc( arcParent->GetStart(), arcParent->GetMid(), arcParent->GetEnd(), arcParent->GetWidth() ); SHAPE_LINE_CHAIN chainArc( shapeArc ); - LENGTH_CALCULATION_ITEM item; + LENGTH_DELAY_CALCULATION_ITEM item; item.SetLine( chainArc ); item.SetLayers( track->GetLayer() ); + item.SetEffectiveNetClass( arcParent->GetEffectiveNetClass() ); return item; } @@ -523,19 +579,20 @@ LENGTH_CALCULATION_ITEM LENGTH_CALCULATION::GetLengthCalculationItem( BOARD_CONN std::vector points{ track->GetStart(), track->GetEnd() }; SHAPE_LINE_CHAIN shape( points ); - LENGTH_CALCULATION_ITEM item; + LENGTH_DELAY_CALCULATION_ITEM item; item.SetLine( shape ); item.SetLayers( track->GetLayer() ); + item.SetEffectiveNetClass( track->GetEffectiveNetClass() ); return item; } } - else if( PAD* pad = dynamic_cast( aBoardItem ) ) + else if( const PAD* pad = dynamic_cast( aBoardItem ) ) { - LENGTH_CALCULATION_ITEM item; + LENGTH_DELAY_CALCULATION_ITEM item; item.SetPad( pad ); - LSET& layers = pad->Padstack().LayerSet(); + const LSET& layers = pad->Padstack().LayerSet(); PCB_LAYER_ID firstLayer = UNDEFINED_LAYER; PCB_LAYER_ID secondLayer = UNDEFINED_LAYER; @@ -548,9 +605,38 @@ LENGTH_CALCULATION_ITEM LENGTH_CALCULATION::GetLengthCalculationItem( BOARD_CONN } item.SetLayers( firstLayer, secondLayer ); + item.SetEffectiveNetClass( pad->GetEffectiveNetClass() ); return item; } return {}; } + + +void LENGTH_DELAY_CALCULATION::SetTimeDomainParametersProvider( + std::unique_ptr&& aProvider ) +{ + m_timeDomainParameters = std::move( aProvider ); +} + + +void LENGTH_DELAY_CALCULATION::SynchronizeTimeDomainProperties() const +{ + m_timeDomainParameters->OnSettingsChanged(); +} + + +int64_t LENGTH_DELAY_CALCULATION::CalculateLengthForDelay( const int64_t aDesiredDelay, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aCtx ) const +{ + return m_timeDomainParameters->GetTrackLengthForPropagationDelay( aDesiredDelay, aCtx ); +} + + +int64_t +LENGTH_DELAY_CALCULATION::CalculatePropagationDelayForShapeLineChain( const SHAPE_LINE_CHAIN& aShape, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aCtx ) const +{ + return m_timeDomainParameters->CalculatePropagationDelayForShapeLineChain( aShape, aCtx ); +} diff --git a/pcbnew/length_delay_calculation/length_delay_calculation.h b/pcbnew/length_delay_calculation/length_delay_calculation.h new file mode 100644 index 0000000000..971892402e --- /dev/null +++ b/pcbnew/length_delay_calculation/length_delay_calculation.h @@ -0,0 +1,266 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef PCBNEW_LENGTH_DELAY_CALCULATION_H +#define PCBNEW_LENGTH_DELAY_CALCULATION_H + +#include "time_domain_parameters_iface.h" +#include "time_domain_parameters_user_defined.h" + +#include +#include +#include +#include + +class BOARD; + +/** +* Holds length measurement result details and statistics +*/ +struct LENGTH_DELAY_STATS +{ + // Generic statistics + int NumPads{ 0 }; + int NumVias{ 0 }; + + // Space domain statistics + int ViaLength{ 0 }; + int64_t TrackLength{ 0 }; + int PadToDieLength{ 0 }; + std::unique_ptr> LayerLengths; + + /// Calculates the total electrical length for this set of statistics + int64_t TotalLength() const { return ViaLength + TrackLength + PadToDieLength; } + + // Time domain statistics + int64_t ViaDelay{ 0 }; + int64_t TrackDelay{ 0 }; + int64_t PadToDieDelay{ 0 }; + std::unique_ptr> LayerDelays; + + /// Calculates the total electrical propagation delay for this set of statistics + int64_t TotalDelay() const { return ViaDelay + TrackDelay + PadToDieDelay; } +}; + + +/** + * Struct to control which optimisations the length calculation code runs on + * the given path objects. This is required as some call sites (e.g. PNS) run + * their own path optimisation, whereas others (e.g. Net Inspector) do not. + */ +struct PATH_OPTIMISATIONS +{ + /// Optimise via layers for height calculations, ensuring only the distance + /// between routed segments is considered + bool OptimiseViaLayers = false; + + /// Merges all contiguous (end-to-end, same layer) tracks + bool MergeTracks = false; + + /// Optimises the electrical length of tracks within pads. Note that the track + /// must terminate at the trace anchor point to be considered for + /// optimisation. Will require MergeTracks if used with a non-contiguous item + /// set. + bool OptimiseTracesInPads = false; + + /// Determines if there is a via-in-pad present on the board but not in the + /// item set. This condition can arise from the PNS meander placer. + /// TODO (JJ): This can be fixed in the router + bool InferViaInPad = false; +}; + + +/** +* Enum which controls the level of detail returned by the length / delay calculation methods. +* +* NO_LAYER_DETAIL: Only returns totals, without populating the layer length / delay detail maps +* WITH_LAYER_DETAIL: Populates the layer lengths / delay detail maps +*/ +enum class LENGTH_DELAY_LAYER_OPT +{ + NO_LAYER_DETAIL, + WITH_LAYER_DETAIL +}; + + +/** +* Enum which controls the calculation domain of the length / delay calculation methods. +* +* NO_DELAY_DETAIL: Only calculates space domain (e.g. length) details +* WITH_DELAY_DETAIL: Calculates space and time domain (e.g. length and delay) details +*/ +enum class LENGTH_DELAY_DOMAIN_OPT +{ + NO_DELAY_DETAIL, + WITH_DELAY_DETAIL +}; + + +/** +* Class which calculates lengths (and associated routing statistics) in a BOARD context +*/ +class LENGTH_DELAY_CALCULATION +{ +public: + /** + * Construct the calculator in the given BOARD context. Also constructs a default user-defined time domain + * parameters provider + */ + explicit LENGTH_DELAY_CALCULATION( BOARD* aBoard ) : + m_board( aBoard ), + m_timeDomainParameters( std::make_unique( aBoard, this ) ) + { + } + + /** + * @brief Calculates the electrical length of the given items + * + * @param aItems is the vector of items making up the route + * @param aOptimisations details the electrical path optimisations that should be applied to the board items + * @param aStartPad is the starting pad of the route + * @param aEndPad is the ending pad of the route + */ + int64_t CalculateLength( std::vector& aItems, PATH_OPTIMISATIONS aOptimisations, + const PAD* aStartPad = nullptr, const PAD* aEndPad = nullptr ) const; + + /** + * @brief Calculates the electrical propagation delay of the given items + * + * @param aItems is the vector of items making up the route + * @param aOptimisations details the electrical path optimisations that should be applied to the board items + * @param aStartPad is the starting pad of the route + * @param aEndPad is the ending pad of the route + */ + int64_t CalculateDelay( std::vector& aItems, PATH_OPTIMISATIONS aOptimisations, + const PAD* aStartPad = nullptr, const PAD* aEndPad = nullptr ) const; + + /** + * @brief Calculates the electrical length of the given items + * + * @param aItems is the vector of items making up the route + * @param aOptimisations details the electrical path optimisations that should be applied to the board items + * @param aStartPad is the starting pad of the route + * @param aEndPad is the ending pad of the route + * @param aLayerOpt determines whether the layer details map is populated + * @param aDomain determines whether calculations include time domain (delay) details + */ + LENGTH_DELAY_STATS + CalculateLengthDetails( std::vector& aItems, PATH_OPTIMISATIONS aOptimisations, + const PAD* aStartPad = nullptr, const PAD* aEndPad = nullptr, + LENGTH_DELAY_LAYER_OPT aLayerOpt = LENGTH_DELAY_LAYER_OPT::NO_LAYER_DETAIL, + LENGTH_DELAY_DOMAIN_OPT aDomain = LENGTH_DELAY_DOMAIN_OPT::NO_DELAY_DETAIL ) const; + + /** + * Gets the propagation delay for the given shape line chain + * + * @param aShape is the shape to calculate delay for + * @param aCtx is the geometry context for which to query to propagation delay + */ + int64_t CalculatePropagationDelayForShapeLineChain( const SHAPE_LINE_CHAIN& aShape, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aCtx ) const; + + /** + * @brief Calculates the length of track required for the given delay in a specific geometry context + * + * @param aDesiredDelay is the desired track delay (in IU) + * @param aCtx is the track geometry context to calculate propagation velocitiy against + */ + int64_t CalculateLengthForDelay( int64_t aDesiredDelay, const TIME_DOMAIN_GEOMETRY_CONTEXT& aCtx ) const; + + /// Optimises the given trace / line to minimise the electrical path length within the given pad + static void OptimiseTraceInPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad, PCB_LAYER_ID aPcbLayer ); + + /// Return a LENGTH_CALCULATION_ITEM constructed from the given BOARD_CONNECTED_ITEM + LENGTH_DELAY_CALCULATION_ITEM GetLengthCalculationItem( const BOARD_CONNECTED_ITEM* aBoardItem ) const; + + /// Sets the provider for time domain parameter resolution + void SetTimeDomainParametersProvider( std::unique_ptr&& aProvider ); + + /// Ensure time domain properties provider is synced with board / project settings if required + void SynchronizeTimeDomainProperties() const; + + /** + * Returns the stackup distance between the two given layers. + * + * Note: Can return 0 if the board design settings disallow stackup height calculations + */ + int StackupHeight( PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer ) const; + +protected: + /// The parent board for all items + BOARD* m_board; + + /// The active provider of time domain parameters + std::unique_ptr m_timeDomainParameters; + + /// Enum to describe whether track merging is attempted from the start or end of a track segment + enum class MERGE_POINT + { + START, + END + }; + + /** + * Optimises the given set of items to minimise the electrical path length. At the moment + * only optimises lines attached to pads, future work could optimise paths through pads + * + * Assumes that any polylines are only connected at either end, and not at midpoints + */ + static void optimiseTracesInPads( const std::vector& aPads, + const std::vector& aLines ); + + /// Clips the given line to the minimal direct electrical length within the pad + static void clipLineToPad( SHAPE_LINE_CHAIN& aLine, const PAD* aPad, PCB_LAYER_ID aLayer, bool aForward = true ); + + /** + * Optimises the via layers. Ensures that vias that are routed through only on one layer do not count towards total + * length calculations. + */ + static void + optimiseViaLayers( const std::vector& aVias, + std::vector& aLines, + std::map>& aLinesPositionMap, + const std::map>& aPadsPositionMap ); + + /** + * Merges any lines (traces) that are contiguous, on one layer, and with no junctions + */ + static void mergeLines( std::vector& aLines, + std::map>& aLinesPositionMap ); + + /** + * Merges two SHAPE_LINE_CHAINs where there is a shared endpoing. + * + * aSecondary is merged in to aPrimary + */ + static void mergeShapeLineChains( SHAPE_LINE_CHAIN& aPrimary, const SHAPE_LINE_CHAIN& aSecondary, + MERGE_POINT aMergePoint ); + + /** + * Infers if there is a via in the given pad. Adds via details to the length details data structure if found. + */ + void inferViaInPad( const PAD* aPad, const LENGTH_DELAY_CALCULATION_ITEM& aItem, + LENGTH_DELAY_STATS& aDetails ) const; +}; + +#endif //PCBNEW_LENGTH_DELAY_CALCULATION_H diff --git a/pcbnew/length_delay_calculation/length_delay_calculation_item.cpp b/pcbnew/length_delay_calculation/length_delay_calculation_item.cpp new file mode 100644 index 0000000000..1d8797f02a --- /dev/null +++ b/pcbnew/length_delay_calculation/length_delay_calculation_item.cpp @@ -0,0 +1,55 @@ +/* +* This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include + + +void LENGTH_DELAY_CALCULATION_ITEM::CalculateViaLayers( const BOARD* aBoard ) +{ + static std::initializer_list traceAndPadTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T }; + + PCB_LAYER_ID top_layer = UNDEFINED_LAYER; + PCB_LAYER_ID bottom_layer = UNDEFINED_LAYER; + + const LSET layers = aBoard->GetDesignSettings().GetEnabledLayers(); + + for( auto layer_it = layers.copper_layers_begin(); layer_it != layers.copper_layers_end(); ++layer_it ) + { + if( aBoard->GetConnectivity()->IsConnectedOnLayer( m_via, *layer_it, traceAndPadTypes ) ) + { + if( top_layer == UNDEFINED_LAYER ) + top_layer = *layer_it; + else + bottom_layer = *layer_it; + } + } + + if( top_layer == UNDEFINED_LAYER ) + top_layer = m_via->TopLayer(); + if( bottom_layer == UNDEFINED_LAYER ) + bottom_layer = m_via->BottomLayer(); + + SetLayers( bottom_layer, top_layer ); +} diff --git a/pcbnew/length_delay_calculation/length_delay_calculation_item.h b/pcbnew/length_delay_calculation/length_delay_calculation_item.h new file mode 100644 index 0000000000..f8008c9f78 --- /dev/null +++ b/pcbnew/length_delay_calculation/length_delay_calculation_item.h @@ -0,0 +1,158 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef PCBNEW_LENGTH_DELAY_CALCULATION_ITEM_H +#define PCBNEW_LENGTH_DELAY_CALCULATION_ITEM_H + +#include +#include +#include +#include + +/** + * Lightweight class which holds a pad, via, or a routed trace outline. Proxied objects passed by pointer are not + * owned by this container. + */ +class LENGTH_DELAY_CALCULATION_ITEM +{ +public: + /// The type of routing object this item proxies + enum class TYPE + { + UNKNOWN, + PAD, + LINE, + VIA + }; + + /// Whether this item is UNMERGED, it has been merged and should be used (MERGED_IN_USE), or it has been merged + /// and has been retired from use (MERGED_RETIRED). MERGED_RETIRED essentially means the object has been merged + /// in to a MERGED_IN_USE item. + enum class MERGE_STATUS + { + UNMERGED, + MERGED_IN_USE, + MERGED_RETIRED + }; + + /// Gets the routing item type + TYPE Type() const { return m_type; }; + + /// Sets the parent PAD associated with this item + void SetPad( const PAD* aPad ) + { + m_type = TYPE::PAD; + m_pad = aPad; + } + + /// Gets the parent PAD associated with this item + const PAD* GetPad() const { return m_pad; } + + /// Sets the source SHAPE_LINE_CHAIN of this item + void SetLine( const SHAPE_LINE_CHAIN& aLine ) + { + m_type = TYPE::LINE; + m_line = aLine; + } + + /// Gets the SHAPE_LINE_CHAIN associated with this item + SHAPE_LINE_CHAIN& GetLine() const { return m_line; } + + /// Sets the VIA associated with this item + void SetVia( const PCB_VIA* aVia ) + { + m_type = TYPE::VIA; + m_via = aVia; + } + + /// Gets the VIA associated with this item + const PCB_VIA* GetVia() const { return m_via; } + + /// Sets the first and last layers associated with this item. Always stores in copper layer order + /// (F_Cu to B_Cu) + void SetLayers( const PCB_LAYER_ID aStart, const PCB_LAYER_ID aEnd = PCB_LAYER_ID::UNDEFINED_LAYER ) + { + if( aEnd != UNDEFINED_LAYER && IsCopperLayerLowerThan( aStart, aEnd ) ) + { + m_layerStart = aEnd; + m_layerEnd = aStart; + } + else + { + m_layerStart = aStart; + m_layerEnd = aEnd; + } + } + + /// Sets the MERGE_STATUS of this item. MERGED_RETIRED essentially means the object has been merged + /// in to a MERGED_IN_USE item. + void SetMergeStatus( const MERGE_STATUS aStatus ) { m_mergeStatus = aStatus; } + + /// Gets the MERGE_STATUS of this item + MERGE_STATUS GetMergeStatus() const { return m_mergeStatus; } + + /// Gets the upper and lower layers for the proxied item + std::tuple GetLayers() const { return { m_layerStart, m_layerEnd }; } + + /// Gets the start board layer for the proxied item + PCB_LAYER_ID GetStartLayer() const { return m_layerStart; } + + /// Gets the end board layer for the proxied item. + PCB_LAYER_ID GetEndLayer() const { return m_layerEnd; } + + /// Calculates active via payers for a proxied VIA object + void CalculateViaLayers( const BOARD* aBoard ); + + /// Sets the effective net class for the item + void SetEffectiveNetClass( const NETCLASS* aNetClass ) { m_netClass = aNetClass; } + + /// Returns the effective net class for the item + const NETCLASS* GetEffectiveNetClass() const { return m_netClass; } + +protected: + /// A proxied PAD object. Set to nullptr if not proxying a PAD. + const PAD* m_pad{ nullptr }; + + /// A proxied SHAPE_LINE_CHAIN object. Line is empty if not proxying a SHAPE_LINE_CHAIN. + mutable SHAPE_LINE_CHAIN m_line; + + /// A proxied PCB_VIA object. Set to nullptr if not proxying a VIA. + const PCB_VIA* m_via{ nullptr }; + + /// The start board layer for the proxied object + PCB_LAYER_ID m_layerStart{ PCB_LAYER_ID::UNDEFINED_LAYER }; + + /// The end board layer for the proxied object + PCB_LAYER_ID m_layerEnd{ PCB_LAYER_ID::UNDEFINED_LAYER }; + + /// Flags whether this item has already been merged with another + MERGE_STATUS m_mergeStatus{ MERGE_STATUS::UNMERGED }; + + /// The routing object type of the proxied parent + TYPE m_type{ TYPE::UNKNOWN }; + + /// The net class of the object + const NETCLASS* m_netClass{ nullptr }; +}; + +#endif //PCBNEW_LENGTH_DELAY_CALCULATION_ITEM_H diff --git a/pcbnew/length_delay_calculation/time_domain_parameters_iface.h b/pcbnew/length_delay_calculation/time_domain_parameters_iface.h new file mode 100644 index 0000000000..40f45c2aa2 --- /dev/null +++ b/pcbnew/length_delay_calculation/time_domain_parameters_iface.h @@ -0,0 +1,126 @@ +/* +* This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef PCBNEW_TIME_DOMAIN_PARAMETERS_INTERFACE_H +#define PCBNEW_TIME_DOMAIN_PARAMETERS_INTERFACE_H + +#include +#include + +class LENGTH_DELAY_CALCULATION; + +/** +* A data structure to contain basic geometry data which can affect signal propagation calculations. +*/ +struct TIME_DOMAIN_GEOMETRY_CONTEXT +{ + /// The net class this track belongs to + const NETCLASS* NetClass; + + /// The layer this track is on + PCB_LAYER_ID Layer; + + /// The width (in internal units) of the track + int64_t Width; + + /// Whether this track or via is a member of a coupled differential pair + bool IsDiffPairCoupled{ false }; + + /// The gap between coupled tracks + int64_t DiffPairCouplingGap{ 0 }; +}; + + +/** + * Interface for providers of time domain parameter information. This interface is consumed by the + * LENGTH_TIME_CALCULATOR object to convert space-domain physical layout informaton (e.g. track lengths) in to + * time-domain propagation information. + */ +class TIME_DOMAIN_PARAMETERS_IFACE +{ +public: + explicit TIME_DOMAIN_PARAMETERS_IFACE( BOARD* aBoard, LENGTH_DELAY_CALCULATION* aCalculation ) : + m_board{ aBoard }, m_lengthCalculation{ aCalculation } + { + } + + virtual ~TIME_DOMAIN_PARAMETERS_IFACE() = default; + + /** + * Event called by the length and time calculation architecture if the board stackup has changed. This can be used + * to invalidate any calculation / simulation caches. + */ + virtual void OnStackupChanged() {}; + + /** + * Event called by the length and time calculation architecture if netclass definitions have changed. This can be + * used to invalidate any calculation / simulation caches. + */ + virtual void OnSettingsChanged() {}; + + /** + * Gets the propagation delays (in internal units) for the given items in the given geometry context + * + * @param aItems the board items to query propagation delay for + * @param aContext the geometry context in which to query to propagation delay + */ + virtual std::vector GetPropagationDelays( const std::vector& aItems, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext ) = 0; + + /** + * Gets the propagation delay (in internal units) for the given item in the given geometry context + * + * @param aItem the board item to query propagation delay for + * @param aContext is the geometry context in which to query to propagation delay + */ + virtual int64_t GetPropagationDelay( const LENGTH_DELAY_CALCULATION_ITEM& aItem, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext ) = 0; + + /** + * Gets the track length (in internal distance units) required for the given propagation delay (in internal time + * units). The track length should be calculated with the given geometry context. + * + * @param aContext the geometry context in which to query to propagation delay + * @param aDelay the propagation delay for which a length should be calculated + */ + virtual int64_t GetTrackLengthForPropagationDelay( int64_t aDelay, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext ) = 0; + + /** + * Gets the propagation delay for the given shape line chain + * + * @param aShape is the shape to calculate delay for + * @param aContext is the geometry context for which to query to propagation delay + */ + virtual int64_t CalculatePropagationDelayForShapeLineChain( const SHAPE_LINE_CHAIN& aShape, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext ) = 0; + +protected: + /// The board all calculations are for + BOARD* m_board; + + /// The parent length / delay calculation object + LENGTH_DELAY_CALCULATION* m_lengthCalculation; +}; + +#endif //PCBNEW_TIME_DOMAIN_PARAMETERS_INTERFACE_H diff --git a/pcbnew/length_delay_calculation/time_domain_parameters_user_defined.cpp b/pcbnew/length_delay_calculation/time_domain_parameters_user_defined.cpp new file mode 100644 index 0000000000..472e675e3e --- /dev/null +++ b/pcbnew/length_delay_calculation/time_domain_parameters_user_defined.cpp @@ -0,0 +1,190 @@ +/* +* This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + + +void TIME_DOMAIN_PARAMETERS_USER_DEFINED::OnSettingsChanged() +{ + rebuildCaches(); +} + + +std::vector +TIME_DOMAIN_PARAMETERS_USER_DEFINED::GetPropagationDelays( const std::vector& aItems, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext ) +{ + if( aItems.empty() ) + return {}; + + const wxString tuningProfileName = aItems.front().GetEffectiveNetClass()->GetTuningProfile(); + const TIME_DOMAIN_TUNING_PROFILE* tuningProfile = getTuningProfile( tuningProfileName ); + + if( !tuningProfile ) + return std::vector( aItems.size(), 0 ); + + std::vector propagationDelays; + propagationDelays.reserve( aItems.size() ); + + for( const LENGTH_DELAY_CALCULATION_ITEM& item : aItems ) + propagationDelays.emplace_back( getPropagationDelay( item, aContext, tuningProfile ) ); + + return propagationDelays; +} + + +int64_t TIME_DOMAIN_PARAMETERS_USER_DEFINED::GetPropagationDelay( const LENGTH_DELAY_CALCULATION_ITEM& aItem, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext ) +{ + if( aItem.GetMergeStatus() == LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::MERGED_RETIRED ) + return 0; + + const wxString tuningProfileName = aItem.GetEffectiveNetClass()->GetTuningProfile(); + const TIME_DOMAIN_TUNING_PROFILE* tuningProfile = getTuningProfile( tuningProfileName ); + + if( !tuningProfile ) + return 0; + + return getPropagationDelay( aItem, aContext, tuningProfile ); +} + + +int64_t +TIME_DOMAIN_PARAMETERS_USER_DEFINED::getPropagationDelay( const LENGTH_DELAY_CALCULATION_ITEM& aItem, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext, + const TIME_DOMAIN_TUNING_PROFILE* aTuningProfile ) const +{ + if( aItem.GetMergeStatus() == LENGTH_DELAY_CALCULATION_ITEM::MERGE_STATUS::MERGED_RETIRED ) + return 0; + + const LENGTH_DELAY_CALCULATION_ITEM::TYPE itemType = aItem.Type(); + + if( itemType == LENGTH_DELAY_CALCULATION_ITEM::TYPE::LINE ) + { + const double delayUnit = aTuningProfile->m_LayerPropagationDelays.at( aItem.GetStartLayer() ); + return static_cast( delayUnit * ( static_cast( aItem.GetLine().Length() ) / PCB_IU_PER_MM ) ); + } + + if( itemType == LENGTH_DELAY_CALCULATION_ITEM::TYPE::VIA ) + { + const PCB_LAYER_ID signalStartLayer = aItem.GetStartLayer(); + const PCB_LAYER_ID signalEndLayer = aItem.GetEndLayer(); + const PCB_LAYER_ID viaStartLayer = aItem.GetVia()->Padstack().StartLayer(); + const PCB_LAYER_ID viaEndLayer = aItem.GetVia()->Padstack().EndLayer(); + + // First check for a layer-to-layer override - this assumes that the layers are already in CuStack() order + auto& viaOverrides = m_viaOverridesCache.at( aTuningProfile->m_ProfileName ); + + const auto viaItr = viaOverrides.find( + VIA_OVERRIDE_CACHE_KEY{ signalStartLayer, signalEndLayer, viaStartLayer, viaEndLayer } ); + + if( viaItr != viaOverrides.end() ) + return viaItr->second; + + // Otherwise, return the tuning profile default + const double distance = m_lengthCalculation->StackupHeight( signalStartLayer, signalEndLayer ); + return static_cast( aTuningProfile->m_ViaPropagationDelay * ( distance / PCB_IU_PER_MM ) ); + } + + if( itemType == LENGTH_DELAY_CALCULATION_ITEM::TYPE::PAD ) + { + return aItem.GetPad()->GetPadToDieDelay(); + } + + return 0; +} + + +const TIME_DOMAIN_TUNING_PROFILE* +TIME_DOMAIN_PARAMETERS_USER_DEFINED::getTuningProfile( const wxString& aTuningProfileName ) +{ + if( !m_cachesInitialised ) [[unlikely]] + rebuildCaches(); + + auto itr = m_tuningProfilesCache.find( aTuningProfileName ); + + if( itr != m_tuningProfilesCache.end() ) + return itr->second; + + return nullptr; +} + + +int64_t +TIME_DOMAIN_PARAMETERS_USER_DEFINED::GetTrackLengthForPropagationDelay( int64_t aDelay, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext ) +{ + const wxString tuningProfileName = aContext.NetClass->GetTuningProfile(); + const TIME_DOMAIN_TUNING_PROFILE* profile = getTuningProfile( tuningProfileName ); + + if( !profile ) + return 0; + + const double delayUnit = profile->m_LayerPropagationDelays.at( aContext.Layer ); // Time IU / MM + const double lengthInMM = static_cast( aDelay ) / delayUnit; // MM + return static_cast( lengthInMM * PCB_IU_PER_MM ); // Length IU +} + + +int64_t TIME_DOMAIN_PARAMETERS_USER_DEFINED::CalculatePropagationDelayForShapeLineChain( + const SHAPE_LINE_CHAIN& aShape, const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext ) +{ + const wxString tuningProfileName = aContext.NetClass->GetTuningProfile(); + const TIME_DOMAIN_TUNING_PROFILE* profile = getTuningProfile( tuningProfileName ); + + if( !profile ) + return 0; + + const double delayUnit = profile->m_LayerPropagationDelays.at( aContext.Layer ); + return static_cast( delayUnit * ( static_cast( aShape.Length() ) / PCB_IU_PER_MM ) ); +} + + +void TIME_DOMAIN_PARAMETERS_USER_DEFINED::rebuildCaches() +{ + m_tuningProfilesCache.clear(); + m_viaOverridesCache.clear(); + + if( const PROJECT* project = m_board->GetProject() ) + { + TIME_DOMAIN_PARAMETERS* params = project->GetProjectFile().TimeDomainParameters().get(); + + for( const TIME_DOMAIN_TUNING_PROFILE& profile : params->GetDelayProfiles() ) + { + m_tuningProfilesCache[profile.m_ProfileName] = &profile; + + std::map& viaOverrides = m_viaOverridesCache[profile.m_ProfileName]; + + for( const TUNING_PROFILE_VIA_OVERRIDE_ENTRY& viaOverride : profile.m_ViaOverrides ) + { + viaOverrides[VIA_OVERRIDE_CACHE_KEY{ viaOverride.m_SignalLayerFrom, viaOverride.m_SignalLayerTo, + viaOverride.m_ViaLayerFrom, viaOverride.m_ViaLayerTo }] = + viaOverride.m_Delay; + } + } + } + + m_cachesInitialised = true; +} diff --git a/pcbnew/length_delay_calculation/time_domain_parameters_user_defined.h b/pcbnew/length_delay_calculation/time_domain_parameters_user_defined.h new file mode 100644 index 0000000000..a595cc3472 --- /dev/null +++ b/pcbnew/length_delay_calculation/time_domain_parameters_user_defined.h @@ -0,0 +1,145 @@ +/* +* This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef PCB_NEW_TIME_DOMAIN_PARAMETERS_USER_DEFINED_H +#define PCB_NEW_TIME_DOMAIN_PARAMETERS_USER_DEFINED_H + + +#include +#include + +class TIME_DOMAIN_PARAMETERS_USER_DEFINED final : public TIME_DOMAIN_PARAMETERS_IFACE +{ +public: + explicit TIME_DOMAIN_PARAMETERS_USER_DEFINED( BOARD* aBoard, LENGTH_DELAY_CALCULATION* aCalculation ) : + TIME_DOMAIN_PARAMETERS_IFACE( aBoard, aCalculation ) + { + } + + /** + * Event called by the length and time calculation architecture if netclass definitions have changed. This can be + * used to invalidate any calculation / simulation caches. + */ + void OnSettingsChanged() override; + + /** + * Gets the propagation delays (in internal units) for the given items in the given geometry context. + * This assumes that all items are in the same netclass + * + * @param aItems the board items to query propagation delay for + * @param aContext the geometry context in which to query to propagation delay + */ + std::vector GetPropagationDelays( const std::vector& aItems, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext ) override; + + /** + * Gets the propagation delay (in internal units) for the given item in the given geometry context + * + * @param aItem the board item to query propagation delay for + * @param aContext the geometry context in which to query to propagation delay + */ + int64_t GetPropagationDelay( const LENGTH_DELAY_CALCULATION_ITEM& aItem, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext ) override; + + /** + * Gets the track length (in internal distance units) required for the given propagation delay (in internal time + * units). The track length should be calculated with the given geometry context. + * + * @param aContext the geometry context in which to query to propagation delay + * @param aDelay the propagation delay for which a length should be calculated + */ + int64_t GetTrackLengthForPropagationDelay( int64_t aDelay, const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext ) override; + + /** + * Gets the propagation delay for the given shape line chain + * + * @param aShape is the shape to calculate delay for + * @param aContext is the geometry context for which to query to propagation delay + */ + int64_t CalculatePropagationDelayForShapeLineChain( const SHAPE_LINE_CHAIN& aShape, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext ) override; + +private: + void rebuildCaches(); + + /// Cache key for use with std::map + struct VIA_OVERRIDE_CACHE_KEY + { + PCB_LAYER_ID SignalStart; + PCB_LAYER_ID SignalEnd; + PCB_LAYER_ID ViaStart; + PCB_LAYER_ID ViaEnd; + + bool operator<( const VIA_OVERRIDE_CACHE_KEY& aOther ) const + { + if( SignalStart < aOther.SignalStart ) + return true; + if( aOther.SignalStart < SignalStart ) + return false; + if( SignalEnd < aOther.SignalEnd ) + return true; + if( aOther.SignalEnd < SignalEnd ) + return false; + if( ViaStart < aOther.ViaStart ) + return true; + if( aOther.ViaStart < ViaStart ) + return false; + return ViaEnd < aOther.ViaEnd; + } + }; + + /** + * Gets the propagation delay (in internal units) for the given item in the given geometry context, + * for items in the pre-found net class. + * + * Preconditions: + * - aNetClass must not be null + * - Calculation caches must be valid + * + * @param aItem the board item to query propagation delay for + * @param aContext the geometry context in which to query to propagation delay + * @param aTuningProfile the time domain tuning profile for the given item + */ + int64_t getPropagationDelay( const LENGTH_DELAY_CALCULATION_ITEM& aItem, + const TIME_DOMAIN_GEOMETRY_CONTEXT& aContext, + const TIME_DOMAIN_TUNING_PROFILE* aTuningProfile ) const; + + /** + * Gets the tuning profile pointer for the given tuning profile name + * + * @param aTuningProfileName the tuning profile name to return + * @returns Valid pointer to a tuning profile, or nullptr if no profile found + */ + const TIME_DOMAIN_TUNING_PROFILE* getTuningProfile( const wxString& aTuningProfileName ); + + /// Cached map of tuning profile names to per-layer time domain parameters + std::map m_tuningProfilesCache; + + /// Cached per-tuning profile via overrides + std::map> m_viaOverridesCache; + + /// Used to ensure caches are valid when board first loaded + bool m_cachesInitialised{ false }; +}; + +#endif //PCB_NEW_TIME_DOMAIN_PARAMETERS_USER_DEFINED_H diff --git a/pcbnew/netinfo_item.cpp b/pcbnew/netinfo_item.cpp index 2aa583a7d7..fabe2f5e1d 100644 --- a/pcbnew/netinfo_item.cpp +++ b/pcbnew/netinfo_item.cpp @@ -125,20 +125,39 @@ void NETINFO_ITEM::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vectorGetTrackLength( *startTrack ); + std::tie( count, lengthNet, lengthPadToDie, delayNet, delayPadToDie ) = + board->GetTrackLength( *startTrack ); - // Displays the full net length (tracks on pcb + internal ICs connections ): - aList.emplace_back( _( "Net Length" ), - aFrame->MessageTextFromValue( lengthNet + lengthPadToDie ) ); + if( delayNet == 0.0 ) + { + // Displays the full net length (tracks on pcb + internal ICs connections ): + aList.emplace_back( _( "Net Length" ), aFrame->MessageTextFromValue( lengthNet + lengthPadToDie ) ); - // Displays the net length of tracks only: - aList.emplace_back( _( "On Board" ), aFrame->MessageTextFromValue( lengthNet ) ); + // Displays the net length of tracks only: + aList.emplace_back( _( "On Board" ), aFrame->MessageTextFromValue( lengthNet ) ); - // Displays the net length of internal ICs connections (wires inside ICs): - aList.emplace_back( _( "In Package" ), aFrame->MessageTextFromValue( lengthPadToDie ) ); + // Displays the net length of internal ICs connections (wires inside ICs): + aList.emplace_back( _( "In Package" ), aFrame->MessageTextFromValue( lengthPadToDie ) ); + } + else + { + // Displays the full net length (tracks on pcb + internal ICs connections ): + aList.emplace_back( _( "Net Delay" ), aFrame->MessageTextFromValue( delayNet + delayPadToDie, true, + EDA_DATA_TYPE::TIME ) ); + + // Displays the net length of tracks only: + aList.emplace_back( _( "On Board" ), + aFrame->MessageTextFromValue( delayNet, true, EDA_DATA_TYPE::TIME ) ); + + // Displays the net length of internal ICs connections (wires inside ICs): + aList.emplace_back( _( "In Package" ), + aFrame->MessageTextFromValue( delayPadToDie, true, EDA_DATA_TYPE::TIME ) ); + } } } } diff --git a/pcbnew/pad.cpp b/pcbnew/pad.cpp index c4ecdaabf3..cf884f037e 100644 --- a/pcbnew/pad.cpp +++ b/pcbnew/pad.cpp @@ -81,6 +81,7 @@ PAD::PAD( FOOTPRINT* parent ) : PADSTACK::ALL_LAYERS ); drill.x = drill.y = EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 30 ); // Default drill size 30 mils. m_lengthPadToDie = 0; + m_delayPadToDie = 0; if( m_parent && m_parent->Type() == PCB_FOOTPRINT_T ) m_pos = GetParent()->GetPosition(); @@ -130,6 +131,7 @@ PAD& PAD::operator=( const PAD &aOther ) ImportSettingsFrom( aOther ); SetPadToDieLength( aOther.GetPadToDieLength() ); + SetPadToDieDelay( aOther.GetPadToDieDelay() ); SetPosition( aOther.GetPosition() ); SetNumber( aOther.GetNumber() ); SetPinType( aOther.GetPinType() ); @@ -1887,6 +1889,7 @@ void PAD::ImportSettingsFrom( const PAD& aMasterPad ) // really specific to a given pad (JPC). #if 0 SetPadToDieLength( aMasterPad.GetPadToDieLength() ); + SetPadToDieDelay( aMasterPad.GetPadToDieDelay() ); #endif // The pad orientation, for historical reasons is the pad rotation + parent rotation. @@ -2885,6 +2888,11 @@ static struct PAD_DESC padToDie->SetAvailableFunc( isCopperPad ); propMgr.AddProperty( padToDie, groupPad ); + auto padToDieDelay = new PROPERTY( _HKI( "Pad To Die Delay" ), &PAD::SetPadToDieDelay, + &PAD::GetPadToDieDelay, PROPERTY_DISPLAY::PT_TIME ); + padToDieDelay->SetAvailableFunc( isCopperPad ); + propMgr.AddProperty( padToDieDelay, groupPad ); + const wxString groupOverrides = _HKI( "Overrides" ); propMgr.AddProperty( new PROPERTY>( diff --git a/pcbnew/pad.h b/pcbnew/pad.h index 751d7b588b..319c97fe5c 100644 --- a/pcbnew/pad.h +++ b/pcbnew/pad.h @@ -452,6 +452,9 @@ public: void SetPadToDieLength( int aLength ) { m_lengthPadToDie = aLength; } int GetPadToDieLength() const { return m_lengthPadToDie; } + void SetPadToDieDelay( int aDelay ) { m_delayPadToDie = aDelay; } + int GetPadToDieDelay() const { return m_delayPadToDie; } + std::optional GetLocalClearance() const override { return m_padStack.Clearance(); } void SetLocalClearance( std::optional aClearance ) { m_padStack.Clearance() = aClearance; } @@ -959,7 +962,8 @@ private: PAD_PROP m_property; // Property in fab files (BGA, FIDUCIAL, TESTPOINT, etc.) - int m_lengthPadToDie; // Length net from pad to die, inside the package + int m_lengthPadToDie; // Length net from pad to die, inside the package + int m_delayPadToDie; // Propagation delay from pad to die mutable std::mutex m_zoneLayerOverridesMutex; std::map m_zoneLayerOverrides; diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index e84fd47df3..771fefad18 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -1403,6 +1403,8 @@ void PCB_EDIT_FRAME::ShowBoardSetupDialog( const wxString& aInitialPage ) wxICON_WARNING, WX_INFOBAR::MESSAGE_TYPE::GENERIC ); } + GetBoard()->SynchronizeTimeDomainProperties(); + // We don't know if anything was modified, so err on the side of requiring a save OnModify(); diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp index 074ba5ce7a..db57f3686b 100644 --- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp +++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp @@ -1696,6 +1696,11 @@ void PCB_IO_KICAD_SEXPR::format( const PAD* aPad ) const formatInternalUnits( aPad->GetPadToDieLength() ).c_str() ); } + if( aPad->GetPadToDieDelay() != 0 ) + { + m_out->Print( "(die_delay %s)", formatInternalUnits( aPad->GetPadToDieDelay() ).c_str() ); + } + if( aPad->GetLocalSolderMaskMargin().has_value() ) { m_out->Print( "(solder_mask_margin %s)", diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h index a6246a6e9f..1c159fa563 100644 --- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h +++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h @@ -181,7 +181,8 @@ class PCB_IO_KICAD_SEXPR; // forward decl //#define SEXPR_BOARD_FILE_VERSION 20250228 // ipc-4761 via protection features //#define SEXPR_BOARD_FILE_VERSION 20250302 // Zone Hatching Offsets //#define SEXPR_BOARD_FILE_VERSION 20250309 // Component class dynamic assignment rules -#define SEXPR_BOARD_FILE_VERSION 20250324 // Jumper pads +//#define SEXPR_BOARD_FILE_VERSION 20250324 // Jumper pads +#define SEXPR_BOARD_FILE_VERSION 20250401 // Time domain length tuning #define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag #define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting diff --git a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp index b033344d52..36bdc35ba1 100644 --- a/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp +++ b/pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp @@ -5370,6 +5370,11 @@ PAD* PCB_IO_KICAD_SEXPR_PARSER::parsePAD( FOOTPRINT* aParent ) NeedRIGHT(); break; + case T_die_delay: + pad->SetPadToDieDelay( parseBoardUnits( T_die_delay ) ); + NeedRIGHT(); + break; + case T_solder_mask_margin: pad->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin value" ) ); NeedRIGHT(); diff --git a/pcbnew/pcb_track.cpp b/pcbnew/pcb_track.cpp index dd4cec4612..f7246b8955 100644 --- a/pcbnew/pcb_track.cpp +++ b/pcbnew/pcb_track.cpp @@ -773,6 +773,24 @@ double PCB_TRACK::GetLength() const } +double PCB_TRACK::GetDelay() const +{ + const BOARD* board = GetBoard(); + + if( !board ) + return 0.0; + + const LENGTH_DELAY_CALCULATION* calc = board->GetLengthCalculation(); + const LENGTH_DELAY_CALCULATION_ITEM calcItem = calc->GetLengthCalculationItem( this ); + std::vector items{ calcItem }; + constexpr PATH_OPTIMISATIONS opts = { + .OptimiseViaLayers = false, .MergeTracks = false, .OptimiseTracesInPads = false, .InferViaInPad = false + }; + + return calc->CalculateDelay( items, opts ); +} + + void PCB_TRACK::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) { RotatePoint( m_Start, aRotCentre, aAngle ); @@ -1761,26 +1779,56 @@ void PCB_TRACK::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vectorMessageTextFromValue( radius ) ); } - aList.emplace_back( _( "Segment Length" ), aFrame->MessageTextFromValue( GetLength() ) ); + double segmentLength = GetLength(); + double segmentDelay = GetDelay(); + + if( segmentDelay == 0.0 ) + { + aList.emplace_back( _( "Segment Length" ), aFrame->MessageTextFromValue( segmentLength ) ); + } + else + { + aList.emplace_back( _( "Segment Delay" ), + aFrame->MessageTextFromValue( segmentDelay, true, EDA_DATA_TYPE::TIME ) ); + } // Display full track length (in Pcbnew) if( board && GetNetCode() > 0 ) { - int count; - double trackLen; - double lenPadToDie; + int count = 0; + double trackLen = 0.0; + double lenPadToDie = 0.0; + double trackDelay = 0.0; + double delayPadToDie = 0.0; - std::tie( count, trackLen, lenPadToDie ) = board->GetTrackLength( *this ); + std::tie( count, trackLen, lenPadToDie, trackDelay, delayPadToDie ) = board->GetTrackLength( *this ); - aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) ); - - if( lenPadToDie != 0 ) + if( trackDelay == 0.0 ) { - msg = aFrame->MessageTextFromValue( lenPadToDie ); - aList.emplace_back( _( "Pad To Die Length" ), msg ); + aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) ); - msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie ); - aList.emplace_back( _( "Full Length" ), msg ); + if( lenPadToDie != 0 ) + { + msg = aFrame->MessageTextFromValue( lenPadToDie ); + aList.emplace_back( _( "Pad To Die Length" ), msg ); + + msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie ); + aList.emplace_back( _( "Full Length" ), msg ); + } + } + else + { + aList.emplace_back( _( "Routed Delay" ), + aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) ); + + if( delayPadToDie != 0.0 ) + { + msg = aFrame->MessageTextFromValue( delayPadToDie, true, EDA_DATA_TYPE::TIME ); + aList.emplace_back( _( "Pad To Die Delay" ), msg ); + + msg = aFrame->MessageTextFromValue( trackDelay + delayPadToDie, true, EDA_DATA_TYPE::TIME ); + aList.emplace_back( _( "Full Delay" ), msg ); + } } } diff --git a/pcbnew/pcb_track.h b/pcbnew/pcb_track.h index f3942ead0e..1007386923 100644 --- a/pcbnew/pcb_track.h +++ b/pcbnew/pcb_track.h @@ -191,10 +191,17 @@ public: /** * Get the length of the track using the hypotenuse calculation. * - * @return the length of the track. + * @return the length of the track */ virtual double GetLength() const; + /** + * Get the time delay of the track + * + * @return the delay of the track + */ + virtual double GetDelay() const; + /** * Convert the track shape to a closed polygon. * diff --git a/pcbnew/pcbexpr_evaluator.cpp b/pcbnew/pcbexpr_evaluator.cpp index 9f987c7187..a2359bc6e1 100644 --- a/pcbnew/pcbexpr_evaluator.cpp +++ b/pcbnew/pcbexpr_evaluator.cpp @@ -603,7 +603,8 @@ BOARD* PCBEXPR_CONTEXT::GetBoard() const const std::vector& PCBEXPR_UNIT_RESOLVER::GetSupportedUnits() const { static const std::vector pcbUnits = { wxT( "mil" ), wxT( "mm" ), wxT( "in" ), - wxT( "deg" ) }; + wxT( "deg" ), wxT( "fs" ), wxT( "ps" ) }; + return pcbUnits; } @@ -611,7 +612,16 @@ const std::vector& PCBEXPR_UNIT_RESOLVER::GetSupportedUnits() const wxString PCBEXPR_UNIT_RESOLVER::GetSupportedUnitsMessage() const { - return _( "must be mm, in, mil, or deg" ); + return _( "must be mm, in, mil, deg, fs, or ps" ); +} + + +const std::vector& PCBEXPR_UNIT_RESOLVER::GetSupportedUnitsTypes() const +{ + static const std::vector pcbUnits = { EDA_UNITS::MILS, EDA_UNITS::MM, EDA_UNITS::INCH, + EDA_UNITS::DEGREES, EDA_UNITS::FS, EDA_UNITS::PS }; + + return pcbUnits; } @@ -624,6 +634,9 @@ double PCBEXPR_UNIT_RESOLVER::Convert( const wxString& aString, int unitId ) con case 0: return EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::MILS, aString ); case 1: return EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::MM, aString ); case 2: return EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::INCH, aString ); + case 3: return v; + case 4: return EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::FS, aString ); + case 5: return EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::PS, aString ); default: return v; } }; @@ -637,6 +650,14 @@ const std::vector& PCBEXPR_UNITLESS_RESOLVER::GetSupportedUnits() cons } +const std::vector& PCBEXPR_UNITLESS_RESOLVER::GetSupportedUnitsTypes() const +{ + static const std::vector emptyUnits; + + return emptyUnits; +} + + double PCBEXPR_UNITLESS_RESOLVER::Convert( const wxString& aString, int unitId ) const { return wxAtof( aString ); @@ -679,7 +700,10 @@ bool PCBEXPR_EVALUATOR::Evaluate( const wxString& aExpr ) LIBEVAL::VALUE* result = ucode.Run( &evaluationContext ); if( result->GetType() == LIBEVAL::VT_NUMERIC ) + { m_result = KiROUND( result->AsDouble() ); + m_units = result->GetUnits(); + } return true; } diff --git a/pcbnew/pcbexpr_evaluator.h b/pcbnew/pcbexpr_evaluator.h index 3077d006ae..53a42a895f 100644 --- a/pcbnew/pcbexpr_evaluator.h +++ b/pcbnew/pcbexpr_evaluator.h @@ -213,6 +213,7 @@ class PCBEXPR_UNIT_RESOLVER : public LIBEVAL::UNIT_RESOLVER { public: const std::vector& GetSupportedUnits() const override; + const std::vector& GetSupportedUnitsTypes() const override; wxString GetSupportedUnitsMessage() const override; @@ -224,6 +225,7 @@ class PCBEXPR_UNITLESS_RESOLVER : public LIBEVAL::UNIT_RESOLVER { public: const std::vector& GetSupportedUnits() const override; + const std::vector& GetSupportedUnitsTypes() const override; double Convert( const wxString& aString, int unitId ) const override; }; @@ -244,6 +246,7 @@ public: bool Evaluate( const wxString& aExpr ); int Result() const { return m_result; } + EDA_UNITS Units() const { return m_units; } void SetErrorCallback( std::function aCallback ) { @@ -255,6 +258,7 @@ public: private: int m_result; + EDA_UNITS m_units; PCBEXPR_COMPILER m_compiler; PCBEXPR_UCODE m_ucode; diff --git a/pcbnew/router/pns_dp_meander_placer.cpp b/pcbnew/router/pns_dp_meander_placer.cpp index 6c95cadc0b..7a4da22bd2 100644 --- a/pcbnew/router/pns_dp_meander_placer.cpp +++ b/pcbnew/router/pns_dp_meander_placer.cpp @@ -37,13 +37,19 @@ DP_MEANDER_PLACER::DP_MEANDER_PLACER( ROUTER* aRouter ) : m_world = nullptr; m_currentNode = nullptr; - m_padToDieP = 0; - m_padToDieN = 0; + m_padToDieLengthP = 0; + m_padToDieLengthN = 0; + + m_padToDieDelayP = 0; + m_padToDieDelayN = 0; // Init temporary variables (do not leave uninitialized members) m_initialSegment = nullptr; m_lastLength = 0; + m_lastDelay = 0; m_lastStatus = TOO_SHORT; + + m_netClass = nullptr; } @@ -107,30 +113,49 @@ bool DP_MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem ) m_tunedPathP = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.PLine().GetLink( 0 ), &m_startPad_p, &m_endPad_p ); - m_padToDieP = 0; + m_padToDieLengthP = 0; + m_padToDieDelayP = 0; if( m_startPad_p ) - m_padToDieP += m_startPad_p->GetPadToDie(); + { + m_padToDieLengthP += m_startPad_p->GetPadToDie(); + m_padToDieDelayP += m_startPad_p->GetPadToDieDelay(); + } if( m_endPad_p ) - m_padToDieP += m_endPad_p->GetPadToDie(); + { + m_padToDieLengthP += m_endPad_p->GetPadToDie(); + m_padToDieDelayP += m_endPad_p->GetPadToDieDelay(); + } m_tunedPathN = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.NLine().GetLink( 0 ), &m_startPad_n, &m_endPad_n ); - m_padToDieN = 0; + m_padToDieLengthN = 0; + m_padToDieDelayN = 0; if( m_startPad_n ) - m_padToDieN += m_startPad_n->GetPadToDie(); + { + m_padToDieLengthN += m_startPad_n->GetPadToDie(); + m_padToDieDelayN += m_startPad_n->GetPadToDieDelay(); + } if( m_endPad_n ) - m_padToDieN += m_endPad_n->GetPadToDie(); + { + m_padToDieLengthN += m_endPad_n->GetPadToDie(); + m_padToDieDelayN += m_endPad_n->GetPadToDieDelay(); + } m_world->Remove( m_originPair.PLine() ); m_world->Remove( m_originPair.NLine() ); m_currentWidth = m_originPair.Width(); + const BOARD_CONNECTED_ITEM* conItem = static_cast( aStartItem->GetSourceItem() ); + m_netClass = conItem->GetEffectiveNetClass(); + + calculateTimeDomainTargets(); + return true; } @@ -142,8 +167,16 @@ void DP_MEANDER_PLACER::release() long long int DP_MEANDER_PLACER::origPathLength() const { - long long int totalP = m_padToDieP + lineLength( m_tunedPathP, m_startPad_p, m_endPad_p ); - long long int totalN = m_padToDieN + lineLength( m_tunedPathN, m_startPad_n, m_endPad_n ); + long long int totalP = m_padToDieLengthP + lineLength( m_tunedPathP, m_startPad_p, m_endPad_p ); + long long int totalN = m_padToDieLengthN + lineLength( m_tunedPathN, m_startPad_n, m_endPad_n ); + return std::max( totalP, totalN ); +} + + +int64_t DP_MEANDER_PLACER::origPathDelay() const +{ + const int64_t totalP = m_padToDieDelayP + lineDelay( m_tunedPathP, m_startPad_p, m_endPad_p ); + const int64_t totalN = m_padToDieDelayP + lineDelay( m_tunedPathN, m_startPad_n, m_endPad_n ); return std::max( totalP, totalN ); } @@ -169,6 +202,8 @@ bool DP_MEANDER_PLACER::pairOrientation( const DIFF_PAIR::COUPLED_SEGMENTS& aPai bool DP_MEANDER_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem ) { + calculateTimeDomainTargets(); + if( m_currentStart == aP ) return false; @@ -329,6 +364,7 @@ bool DP_MEANDER_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem ) m_result.AddCorner( tunedP.CPoint( -1 ), tunedN.CPoint( -1 ) ); long long int dpLen = origPathLength(); + int64_t dpDelay = origPathDelay(); m_lastStatus = TUNED; @@ -336,10 +372,24 @@ bool DP_MEANDER_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem ) { m_lastStatus = TOO_LONG; m_lastLength = dpLen; + m_lastDelay = dpDelay; } else { m_lastLength = dpLen - std::max( tunedP.Length(), tunedN.Length() ); + + if( m_settings.m_isTimeDomain ) + { + int64_t tunedPDelay = m_router->GetInterface()->CalculateDelayForShapeLineChain( + tunedP, GetOriginPair().Width(), true, GetOriginPair().Gap(), m_router->GetCurrentLayer(), + m_netClass ); + int64_t tunedNDelay = m_router->GetInterface()->CalculateDelayForShapeLineChain( + tunedN, GetOriginPair().Width(), true, GetOriginPair().Gap(), m_router->GetCurrentLayer(), + m_netClass ); + + m_lastDelay = dpDelay - std::max( tunedPDelay, tunedNDelay ); + } + tuneLineLength( m_result, m_settings.m_targetLength.Opt() - dpLen ); } @@ -358,6 +408,19 @@ bool DP_MEANDER_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem ) } m_lastLength += std::max( tunedP.Length(), tunedN.Length() ); + + if( m_settings.m_isTimeDomain ) + { + int64_t tunedPDelay = m_router->GetInterface()->CalculateDelayForShapeLineChain( + tunedP, GetOriginPair().Width(), true, GetOriginPair().Gap(), m_router->GetCurrentLayer(), + m_netClass ); + int64_t tunedNDelay = m_router->GetInterface()->CalculateDelayForShapeLineChain( + tunedN, GetOriginPair().Width(), true, GetOriginPair().Gap(), m_router->GetCurrentLayer(), + m_netClass ); + + m_lastDelay += std::max( tunedPDelay, tunedNDelay ); + } + updateStatus(); } @@ -500,7 +563,7 @@ int DP_MEANDER_PLACER::CurrentLayer() const } -long long int DP_MEANDER_PLACER::TuningResult() const +long long int DP_MEANDER_PLACER::TuningLengthResult() const { if( m_lastLength ) return m_lastLength; @@ -509,6 +572,15 @@ long long int DP_MEANDER_PLACER::TuningResult() const } +int64_t DP_MEANDER_PLACER::TuningDelayResult() const +{ + if( m_lastDelay ) + return m_lastDelay; + else + return origPathDelay(); +} + + DP_MEANDER_PLACER::TUNING_STATUS DP_MEANDER_PLACER::TuningStatus() const { return m_lastStatus; @@ -523,4 +595,36 @@ const std::vector DP_MEANDER_PLACER::CurrentNets() const return rv; } + +void DP_MEANDER_PLACER::calculateTimeDomainTargets() +{ + // If this is a time domain tuning, calculate the target length for the desired total delay + if( m_settings.m_isTimeDomain ) + { + const int64_t curDelay = origPathDelay(); + + const int64_t desiredDelayMin = m_settings.m_targetLengthDelay.Min(); + const int64_t desiredDelayOpt = m_settings.m_targetLengthDelay.Opt(); + const int64_t desiredDelayMax = m_settings.m_targetLengthDelay.Max(); + + const int64_t delayDifferenceOpt = desiredDelayOpt - curDelay; + + const int64_t curLength = origPathLength(); + const int64_t lengthDiffMin = m_router->GetInterface()->CalculateLengthForDelay( + desiredDelayOpt - desiredDelayMin, GetOriginPair().Width(), true, GetOriginPair().Gap(), + m_router->GetCurrentLayer(), m_netClass ); + int64_t lengthDiffOpt = m_router->GetInterface()->CalculateLengthForDelay( + std::abs( delayDifferenceOpt ), GetOriginPair().Width(), true, GetOriginPair().Gap(), + m_router->GetCurrentLayer(), m_netClass ); + const int64_t lengthDiffMax = m_router->GetInterface()->CalculateLengthForDelay( + desiredDelayMax - desiredDelayOpt, GetOriginPair().Width(), true, GetOriginPair().Gap(), + m_router->GetCurrentLayer(), m_netClass ); + + lengthDiffOpt = delayDifferenceOpt > 0 ? lengthDiffOpt : -lengthDiffOpt; + + m_settings.m_targetLength.SetMin( curLength + lengthDiffOpt - lengthDiffMin ); + m_settings.m_targetLength.SetOpt( curLength + lengthDiffOpt ); + m_settings.m_targetLength.SetMax( curLength + lengthDiffOpt + lengthDiffMax ); + } +} } diff --git a/pcbnew/router/pns_dp_meander_placer.h b/pcbnew/router/pns_dp_meander_placer.h index 94014b5d39..cd34d16c3b 100644 --- a/pcbnew/router/pns_dp_meander_placer.h +++ b/pcbnew/router/pns_dp_meander_placer.h @@ -108,7 +108,11 @@ public: long long int totalLength(); - long long int TuningResult() const override; + long long int TuningLengthResult() const override; + + /// @copydoc MEANDER_PLACER_BASE::TuningDelayResult() + int64_t TuningDelayResult() const override; + TUNING_STATUS TuningStatus() const override; bool CheckFit( MEANDER_SHAPE* aShape ) override; @@ -130,6 +134,10 @@ private: long long int origPathLength() const; + int64_t origPathDelay() const; + + void calculateTimeDomainTargets(); + ///< Current routing start point (end of tail, beginning of head). VECTOR2I m_currentStart; @@ -147,9 +155,14 @@ private: LINKED_ITEM* m_initialSegment; long long int m_lastLength; - int m_padToDieP; - int m_padToDieN; + int64_t m_lastDelay; + int m_padToDieLengthP; + int m_padToDieLengthN; + int64_t m_padToDieDelayP; + int64_t m_padToDieDelayN; TUNING_STATUS m_lastStatus; + + NETCLASS* m_netClass; }; } diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp index 34025875dd..5afbad257c 100644 --- a/pcbnew/router/pns_kicad_iface.cpp +++ b/pcbnew/router/pns_kicad_iface.cpp @@ -443,6 +443,7 @@ bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType, aConstraint->m_Value = hostConstraint.GetValue(); aConstraint->m_RuleName = hostConstraint.GetName(); aConstraint->m_Type = aType; + aConstraint->m_IsTimeDomain = hostConstraint.GetOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN ); return true; default: @@ -1193,6 +1194,7 @@ std::vector> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPa solid->SetNet( aPad->GetNet() ); solid->SetParent( aPad ); solid->SetPadToDie( aPad->GetPadToDieLength() ); + solid->SetPadToDieDelay( aPad->GetPadToDieDelay() ); solid->SetOrientation( aPad->GetOrientation() ); if( aPad->IsFreePad() ) @@ -2325,40 +2327,9 @@ PNS_LAYER_RANGE PNS_KICAD_IFACE_BASE::SetLayersFromPCBNew( PCB_LAYER_ID aStartLa long long int PNS_KICAD_IFACE_BASE::CalculateRoutedPathLength( const PNS::ITEM_SET& aLine, const PNS::SOLID* aStartPad, - const PNS::SOLID* aEndPad ) + const PNS::SOLID* aEndPad, const NETCLASS* aNetClass ) { - std::vector lengthItems; - - for( int idx = 0; idx < aLine.Size(); idx++ ) - { - const PNS::ITEM* lineItem = aLine[idx]; - - if( const PNS::LINE* l = dyn_cast( lineItem ) ) - { - LENGTH_CALCULATION_ITEM item; - item.SetLine( l->CLine() ); - - const PCB_LAYER_ID layer = GetBoardLayerFromPNSLayer( lineItem->Layer() ); - item.SetLayers( layer ); - - lengthItems.emplace_back( std::move( item ) ); - } - else if( lineItem->OfKind( PNS::ITEM::VIA_T ) && idx > 0 && idx < aLine.Size() - 1 ) - { - const int layerPrev = aLine[idx - 1]->Layer(); - const int layerNext = aLine[idx + 1]->Layer(); - const PCB_LAYER_ID pcbLayerPrev = GetBoardLayerFromPNSLayer( layerPrev ); - const PCB_LAYER_ID pcbLayerNext = GetBoardLayerFromPNSLayer( layerNext ); - - if( layerPrev != layerNext ) - { - LENGTH_CALCULATION_ITEM item; - item.SetVia( static_cast( lineItem->GetSourceItem() ) ); - item.SetLayers( pcbLayerPrev, pcbLayerNext ); - lengthItems.emplace_back( std::move( item ) ); - } - } - } + std::vector lengthItems = getLengthDelayCalculationItems( aLine, aNetClass ); const PAD* startPad = nullptr; const PAD* endPad = nullptr; @@ -2375,3 +2346,99 @@ long long int PNS_KICAD_IFACE_BASE::CalculateRoutedPathLength( const PNS::ITEM_S const BOARD* board = GetBoard(); return board->GetLengthCalculation()->CalculateLength( lengthItems, opts, startPad, endPad ); } + + +int64_t PNS_KICAD_IFACE_BASE::CalculateRoutedPathDelay( const PNS::ITEM_SET& aLine, const PNS::SOLID* aStartPad, + const PNS::SOLID* aEndPad, const NETCLASS* aNetClass ) +{ + std::vector lengthItems = getLengthDelayCalculationItems( aLine, aNetClass ); + + const PAD* startPad = nullptr; + const PAD* endPad = nullptr; + + if( aStartPad ) + startPad = static_cast( aStartPad->Parent() ); + + if( aEndPad ) + endPad = static_cast( aEndPad->Parent() ); + + constexpr PATH_OPTIMISATIONS opts = { + .OptimiseViaLayers = false, .MergeTracks = false, .OptimiseTracesInPads = false, .InferViaInPad = true + }; + const BOARD* board = GetBoard(); + return board->GetLengthCalculation()->CalculateDelay( lengthItems, opts, startPad, endPad ); +} + + +int64_t PNS_KICAD_IFACE_BASE::CalculateLengthForDelay( int64_t aDesiredDelay, const int aWidth, + const bool aIsDiffPairCoupled, const int aDiffPairCouplingGap, + const int aPNSLayer, const NETCLASS* aNetClass ) +{ + TIME_DOMAIN_GEOMETRY_CONTEXT ctx; + ctx.NetClass = aNetClass; + ctx.Width = aWidth; + ctx.IsDiffPairCoupled = aIsDiffPairCoupled; + ctx.DiffPairCouplingGap = aDiffPairCouplingGap; + ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer ); + + const BOARD* board = GetBoard(); + return board->GetLengthCalculation()->CalculateLengthForDelay( aDesiredDelay, ctx ); +} + + +int64_t PNS_KICAD_IFACE_BASE::CalculateDelayForShapeLineChain( const SHAPE_LINE_CHAIN& aShape, int aWidth, + bool aIsDiffPairCoupled, int aDiffPairCouplingGap, + int aPNSLayer, const NETCLASS* aNetClass ) +{ + TIME_DOMAIN_GEOMETRY_CONTEXT ctx; + ctx.NetClass = aNetClass; + ctx.Width = aWidth; + ctx.IsDiffPairCoupled = aIsDiffPairCoupled; + ctx.DiffPairCouplingGap = aDiffPairCouplingGap; + ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer ); + + const BOARD* board = GetBoard(); + return board->GetLengthCalculation()->CalculatePropagationDelayForShapeLineChain( aShape, ctx ); +} + + +std::vector +PNS_KICAD_IFACE_BASE::getLengthDelayCalculationItems( const PNS::ITEM_SET& aLine, const NETCLASS* aNetClass ) const +{ + std::vector lengthItems; + + for( int idx = 0; idx < aLine.Size(); idx++ ) + { + const PNS::ITEM* lineItem = aLine[idx]; + + if( const PNS::LINE* l = dyn_cast( lineItem ) ) + { + LENGTH_DELAY_CALCULATION_ITEM item; + item.SetLine( l->CLine() ); + + const PCB_LAYER_ID layer = GetBoardLayerFromPNSLayer( lineItem->Layer() ); + item.SetLayers( layer ); + item.SetEffectiveNetClass( aNetClass ); + + lengthItems.emplace_back( std::move( item ) ); + } + else if( lineItem->OfKind( PNS::ITEM::VIA_T ) && idx > 0 && idx < aLine.Size() - 1 ) + { + const int layerPrev = aLine[idx - 1]->Layer(); + const int layerNext = aLine[idx + 1]->Layer(); + const PCB_LAYER_ID pcbLayerPrev = GetBoardLayerFromPNSLayer( layerPrev ); + const PCB_LAYER_ID pcbLayerNext = GetBoardLayerFromPNSLayer( layerNext ); + + if( layerPrev != layerNext ) + { + LENGTH_DELAY_CALCULATION_ITEM item; + item.SetVia( static_cast( lineItem->GetSourceItem() ) ); + item.SetLayers( pcbLayerPrev, pcbLayerNext ); // TODO: BUG IS HERE!!! + item.SetEffectiveNetClass( aNetClass ); + lengthItems.emplace_back( std::move( item ) ); + } + } + } + + return lengthItems; +} diff --git a/pcbnew/router/pns_kicad_iface.h b/pcbnew/router/pns_kicad_iface.h index 4c629bb437..a32615241a 100644 --- a/pcbnew/router/pns_kicad_iface.h +++ b/pcbnew/router/pns_kicad_iface.h @@ -37,6 +37,7 @@ class PCB_TOOL_BASE; class FOOTPRINT; class PAD; class EDA_TEXT; +class LENGTH_DELAY_CALCULATION_ITEM; namespace PNS { @@ -84,7 +85,15 @@ public: void SetDebugDecorator( PNS::DEBUG_DECORATOR* aDec ); long long int CalculateRoutedPathLength( const PNS::ITEM_SET& aLine, const PNS::SOLID* aStartPad, - const PNS::SOLID* aEndPad ) override; + const PNS::SOLID* aEndPad, const NETCLASS* aNetClass ) override; + int64_t CalculateRoutedPathDelay( const PNS::ITEM_SET& aLine, const PNS::SOLID* aStartPad, + const PNS::SOLID* aEndPad, const NETCLASS* aNetClass ) override; + int64_t CalculateLengthForDelay( int64_t aDesiredDelay, int aWidth, bool aIsDiffPairCoupled, + int aDiffPairCouplingGap, int aPNSLayer, const NETCLASS* aNetClass ) override; + int64_t CalculateDelayForShapeLineChain( const SHAPE_LINE_CHAIN& aShape, int aWidth, bool aIsDiffPairCoupled, + int aDiffPairCouplingGap, int aPNSLayer, + const NETCLASS* aNetClass ) override; + PCB_LAYER_ID GetBoardLayerFromPNSLayer( int aLayer ) const override; int GetPNSLayerFromBoardLayer( PCB_LAYER_ID aLayer ) const override; @@ -114,6 +123,8 @@ protected: bool syncGraphicalItem( PNS::NODE* aWorld, PCB_SHAPE* aItem ); bool syncZone( PNS::NODE* aWorld, ZONE* aZone, SHAPE_POLY_SET* aBoardOutline ); bool inheritTrackWidth( PNS::ITEM* aItem, int* aInheritedWidth ); + std::vector getLengthDelayCalculationItems( const PNS::ITEM_SET& aLine, + const NETCLASS* aNetClass ) const; protected: PNS::NODE* m_world; diff --git a/pcbnew/router/pns_meander.cpp b/pcbnew/router/pns_meander.cpp index 0e5d58eb6d..1ddaf7124e 100644 --- a/pcbnew/router/pns_meander.cpp +++ b/pcbnew/router/pns_meander.cpp @@ -28,8 +28,12 @@ namespace PNS { -const long long int MEANDER_SETTINGS::DEFAULT_TOLERANCE( pcbIUScale.mmToIU( 0.1 ) ); +const long long int MEANDER_SETTINGS::DEFAULT_LENGTH_TOLERANCE( pcbIUScale.mmToIU( 0.1 ) ); const long long int MEANDER_SETTINGS::LENGTH_UNCONSTRAINED( 1000000 * pcbIUScale.IU_PER_MM ); + +const long long int MEANDER_SETTINGS::DEFAULT_DELAY_TOLERANCE( 0.1 * pcbIUScale.IU_PER_PS ); +const long long int MEANDER_SETTINGS::DELAY_UNCONSTRAINED( 1000000 * pcbIUScale.IU_PER_PS ); + const int MEANDER_SETTINGS::SKEW_UNCONSTRAINED( std::numeric_limits::max() ); @@ -41,7 +45,9 @@ MEANDER_SETTINGS::MEANDER_SETTINGS() m_lenPadToDie = 0; m_spacing = 600000; SetTargetLength( LENGTH_UNCONSTRAINED ); + SetTargetLengthDelay( DELAY_UNCONSTRAINED ); SetTargetSkew( 0 ); + SetTargetSkewDelay( 0 ); m_overrideCustomRules = false; m_cornerStyle = MEANDER_STYLE_ROUND; m_cornerRadiusPercentage = 80; @@ -49,6 +55,7 @@ MEANDER_SETTINGS::MEANDER_SETTINGS() m_initialSide = MEANDER_SIDE_LEFT; m_lengthTolerance = 0; m_keepEndpoints = false; + m_isTimeDomain = false; } @@ -63,8 +70,8 @@ void MEANDER_SETTINGS::SetTargetLength( long long int aOpt ) } else { - m_targetLength.SetMin( aOpt - DEFAULT_TOLERANCE ); - m_targetLength.SetMax( aOpt + DEFAULT_TOLERANCE ); + m_targetLength.SetMin( aOpt - DEFAULT_LENGTH_TOLERANCE ); + m_targetLength.SetMax( aOpt + DEFAULT_LENGTH_TOLERANCE ); } } @@ -81,6 +88,35 @@ void MEANDER_SETTINGS::SetTargetLength( const MINOPTMAX& aConstraint ) } +void MEANDER_SETTINGS::SetTargetLengthDelay( long long int aOpt ) +{ + m_targetLengthDelay.SetOpt( aOpt ); + + if( aOpt == PNS::MEANDER_SETTINGS::DELAY_UNCONSTRAINED ) + { + m_targetLengthDelay.SetMin( 0 ); + m_targetLengthDelay.SetMax( aOpt ); + } + else + { + m_targetLengthDelay.SetMin( aOpt - DEFAULT_DELAY_TOLERANCE ); + m_targetLengthDelay.SetMax( aOpt + DEFAULT_DELAY_TOLERANCE ); + } +} + + +void MEANDER_SETTINGS::SetTargetLengthDelay( const MINOPTMAX& aConstraint ) +{ + SetTargetLengthDelay( aConstraint.Opt() ); + + if( aConstraint.HasMin() ) + m_targetLengthDelay.SetMin( aConstraint.Min() ); + + if( aConstraint.HasMax() ) + m_targetLengthDelay.SetMax( aConstraint.Max() ); +} + + void MEANDER_SETTINGS::SetTargetSkew( int aOpt ) { m_targetSkew.SetOpt( aOpt ); @@ -92,8 +128,8 @@ void MEANDER_SETTINGS::SetTargetSkew( int aOpt ) } else { - m_targetSkew.SetMin( aOpt - DEFAULT_TOLERANCE ); - m_targetSkew.SetMax( aOpt + DEFAULT_TOLERANCE ); + m_targetSkew.SetMin( aOpt - DEFAULT_LENGTH_TOLERANCE ); + m_targetSkew.SetMax( aOpt + DEFAULT_LENGTH_TOLERANCE ); } } @@ -110,6 +146,35 @@ void MEANDER_SETTINGS::SetTargetSkew( const MINOPTMAX& aConstraint ) } +void MEANDER_SETTINGS::SetTargetSkewDelay( int aOpt ) +{ + m_targetSkewDelay.SetOpt( aOpt ); + + if( aOpt == PNS::MEANDER_SETTINGS::SKEW_UNCONSTRAINED ) + { + m_targetSkewDelay.SetMin( 0 ); + m_targetSkewDelay.SetMax( aOpt ); + } + else + { + m_targetSkewDelay.SetMin( aOpt - DEFAULT_LENGTH_TOLERANCE ); + m_targetSkewDelay.SetMax( aOpt + DEFAULT_LENGTH_TOLERANCE ); + } +} + + +void MEANDER_SETTINGS::SetTargetSkewDelay( const MINOPTMAX& aConstraint ) +{ + SetTargetSkewDelay( aConstraint.Opt() ); + + if( aConstraint.HasMin() ) + m_targetSkewDelay.SetMin( aConstraint.Min() ); + + if( aConstraint.HasMax() ) + m_targetSkewDelay.SetMax( aConstraint.Max() ); +} + + const MEANDER_SETTINGS& MEANDER_SHAPE::Settings() const { return m_placer->MeanderSettings(); diff --git a/pcbnew/router/pns_meander.h b/pcbnew/router/pns_meander.h index aa150bff20..52b8c8a0e6 100644 --- a/pcbnew/router/pns_meander.h +++ b/pcbnew/router/pns_meander.h @@ -67,8 +67,12 @@ enum MEANDER_SIDE class MEANDER_SETTINGS { public: - static const long long int DEFAULT_TOLERANCE; + static const long long int DEFAULT_LENGTH_TOLERANCE; static const long long int LENGTH_UNCONSTRAINED; + + static const long long int DEFAULT_DELAY_TOLERANCE; + static const long long int DELAY_UNCONSTRAINED; + static const int SKEW_UNCONSTRAINED; MEANDER_SETTINGS(); @@ -76,9 +80,15 @@ public: void SetTargetLength( long long int aOpt ); void SetTargetLength( const MINOPTMAX& aConstraint ); + void SetTargetLengthDelay( long long int aOpt ); + void SetTargetLengthDelay( const MINOPTMAX& aConstraint ); + void SetTargetSkew( int aOpt ); void SetTargetSkew( const MINOPTMAX& aConstraint ); + void SetTargetSkewDelay( int aOpt ); + void SetTargetSkewDelay( const MINOPTMAX& aConstraint ); + ///< Minimum meandering amplitude. int m_minAmplitude; @@ -97,9 +107,15 @@ public: ///< Desired length of the tuned line/diff pair (this is in nm, so allow more than board width). MINOPTMAX m_targetLength; + ///< Desired propagation delay of the tuned line + MINOPTMAX m_targetLengthDelay; + ///< Target skew value for diff pair de-skewing. MINOPTMAX m_targetSkew; + ///< Target skew value for diff pair de-skewing. + MINOPTMAX m_targetSkewDelay; + bool m_overrideCustomRules; ///< Type of corners for the meandered line. @@ -119,6 +135,12 @@ public: ///< Keep vertices between pre, tuned and post parts of the line. bool m_keepEndpoints; + + ///< Calculate tuning in the time domain + bool m_isTimeDomain; + + ///< The net class this meander pattern belongs to + NETCLASS* m_netClass; }; /** diff --git a/pcbnew/router/pns_meander_placer.cpp b/pcbnew/router/pns_meander_placer.cpp index 0d66d0c590..8c266de454 100644 --- a/pcbnew/router/pns_meander_placer.cpp +++ b/pcbnew/router/pns_meander_placer.cpp @@ -27,6 +27,8 @@ #include "pns_solid.h" #include "pns_topology.h" +#include + namespace PNS { MEANDER_PLACER::MEANDER_PLACER( ROUTER* aRouter ) : @@ -37,8 +39,11 @@ MEANDER_PLACER::MEANDER_PLACER( ROUTER* aRouter ) : // Init temporary variables (do not leave uninitialized members) m_initialSegment = nullptr; m_lastLength = 0; + m_lastDelay = 0; m_lastStatus = TOO_SHORT; m_padToDieLength = 0; + m_padToDieDelay = 0; + m_netClass = nullptr; } @@ -75,18 +80,30 @@ bool MEANDER_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem ) m_tunedPath = topo.AssembleTuningPath( Router()->GetInterface(), m_initialSegment, &m_startPad_n, &m_endPad_n ); m_padToDieLength = 0; + m_padToDieDelay = 0; if( m_startPad_n ) + { m_padToDieLength += m_startPad_n->GetPadToDie(); + m_padToDieDelay += m_startPad_n->GetPadToDieDelay(); + } if( m_endPad_n ) + { m_padToDieLength += m_endPad_n->GetPadToDie(); + m_padToDieDelay += m_endPad_n->GetPadToDieDelay(); + } m_world->Remove( m_originLine ); m_currentWidth = m_originLine.Width(); m_currentEnd = VECTOR2I( 0, 0 ); + const BOARD_CONNECTED_ITEM* conItem = static_cast( aStartItem->GetSourceItem() ); + m_netClass = conItem->GetEffectiveNetClass(); + + calculateTimeDomainTargets(); + return true; } @@ -97,8 +114,49 @@ long long int MEANDER_PLACER::origPathLength() const } +int64_t MEANDER_PLACER::origPathDelay() const +{ + return m_padToDieDelay + lineDelay( m_tunedPath, m_startPad_n, m_endPad_n ); +} + + +void MEANDER_PLACER::calculateTimeDomainTargets() +{ + // If this is a time domain tuning, calculate the target length for the desired total delay + if( m_settings.m_isTimeDomain ) + { + const int64_t curDelay = origPathDelay(); + + const int64_t desiredDelayMin = m_settings.m_targetLengthDelay.Min(); + const int64_t desiredDelayOpt = m_settings.m_targetLengthDelay.Opt(); + const int64_t desiredDelayMax = m_settings.m_targetLengthDelay.Max(); + + const int64_t delayDifferenceOpt = desiredDelayOpt - curDelay; + + const int64_t curLength = origPathLength(); + const int64_t lengthDiffMin = m_router->GetInterface()->CalculateLengthForDelay( + desiredDelayOpt - desiredDelayMin, m_currentWidth, false, m_router->Sizes().DiffPairGap(), + m_router->GetCurrentLayer(), m_netClass ); + int64_t lengthDiffOpt = m_router->GetInterface()->CalculateLengthForDelay( + std::abs( delayDifferenceOpt ), m_currentWidth, false, m_router->Sizes().DiffPairGap(), + m_router->GetCurrentLayer(), m_netClass ); + const int64_t lengthDiffMax = m_router->GetInterface()->CalculateLengthForDelay( + desiredDelayMax - desiredDelayOpt, m_currentWidth, false, m_router->Sizes().DiffPairGap(), + m_router->GetCurrentLayer(), m_netClass ); + + lengthDiffOpt = delayDifferenceOpt > 0 ? lengthDiffOpt : -lengthDiffOpt; + + m_settings.m_targetLength.SetMin( curLength + lengthDiffOpt - lengthDiffMin ); + m_settings.m_targetLength.SetOpt( curLength + lengthDiffOpt ); + m_settings.m_targetLength.SetMax( curLength + lengthDiffOpt + lengthDiffMax ); + } +} + + bool MEANDER_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem ) { + calculateTimeDomainTargets(); + return doMove( aP, aEndItem, m_settings.m_targetLength.Opt(), m_settings.m_targetLength.Min(), m_settings.m_targetLength.Max() ); } @@ -152,8 +210,10 @@ bool MEANDER_PLACER::doMove( const VECTOR2I& aP, ITEM* aEndItem, long long int a } long long int lineLen = origPathLength(); + int64_t lineDelay = origPathDelay(); m_lastLength = lineLen; + m_lastDelay = lineDelay; m_lastStatus = TUNED; if( lineLen > m_settings.m_targetLength.Max() ) @@ -163,6 +223,15 @@ bool MEANDER_PLACER::doMove( const VECTOR2I& aP, ITEM* aEndItem, long long int a else { m_lastLength = lineLen - tuned.Length(); + + if( m_settings.m_isTimeDomain ) + { + m_lastDelay = lineDelay + - m_router->GetInterface()->CalculateDelayForShapeLineChain( + tuned, m_currentWidth, false, m_router->Sizes().DiffPairGap(), + m_router->GetCurrentLayer(), m_netClass ); + } + tuneLineLength( m_result, aTargetLength - lineLen ); } @@ -190,6 +259,13 @@ bool MEANDER_PLACER::doMove( const VECTOR2I& aP, ITEM* aEndItem, long long int a m_lastLength += tuned.Length(); + if( m_settings.m_isTimeDomain ) + { + m_lastDelay += m_router->GetInterface()->CalculateDelayForShapeLineChain( + tuned, m_currentWidth, false, m_router->Sizes().DiffPairGap(), m_router->GetCurrentLayer(), + m_netClass ); + } + if( m_lastLength > aTargetMax ) m_lastStatus = TOO_LONG; else if( m_lastLength < aTargetMin ) @@ -299,7 +375,7 @@ int MEANDER_PLACER::CurrentLayer() const } -long long int MEANDER_PLACER::TuningResult() const +long long int MEANDER_PLACER::TuningLengthResult() const { if( m_lastLength ) return m_lastLength; @@ -308,6 +384,15 @@ long long int MEANDER_PLACER::TuningResult() const } +int64_t MEANDER_PLACER::TuningDelayResult() const +{ + if( m_lastDelay ) + return m_lastDelay; + else + return origPathDelay(); +} + + MEANDER_PLACER::TUNING_STATUS MEANDER_PLACER::TuningStatus() const { return m_lastStatus; diff --git a/pcbnew/router/pns_meander_placer.h b/pcbnew/router/pns_meander_placer.h index 9fe63810a2..6ec614cff5 100644 --- a/pcbnew/router/pns_meander_placer.h +++ b/pcbnew/router/pns_meander_placer.h @@ -91,8 +91,11 @@ public: /// @copydoc PLACEMENT_ALGO::CurrentLayer() int CurrentLayer() const override; - /// @copydoc MEANDER_PLACER_BASE::TuningResult() - long long int TuningResult() const override; + /// @copydoc MEANDER_PLACER_BASE::TuningLengthResult() + long long int TuningLengthResult() const override; + + /// @copydoc MEANDER_PLACER_BASE::TuningDelayResult() + int64_t TuningDelayResult() const override; /// @copydoc MEANDER_PLACER_BASE::TuningStatus() TUNING_STATUS TuningStatus() const override; @@ -106,6 +109,10 @@ protected: virtual long long int origPathLength() const; + virtual int64_t origPathDelay() const; + + virtual void calculateTimeDomainTargets(); + ///< current routing start point (end of tail, beginning of head) VECTOR2I m_currentStart; @@ -123,7 +130,14 @@ protected: ///< Total length added by pad to die size. int m_padToDieLength; + ///< Total length added by pad to die size. + int m_padToDieDelay; + + ///< The netclass for the placed segments + NETCLASS* m_netClass; + long long int m_lastLength; + int64_t m_lastDelay; TUNING_STATUS m_lastStatus; }; diff --git a/pcbnew/router/pns_meander_placer_base.cpp b/pcbnew/router/pns_meander_placer_base.cpp index 9248c58b3a..62ccbe74f8 100644 --- a/pcbnew/router/pns_meander_placer_base.cpp +++ b/pcbnew/router/pns_meander_placer_base.cpp @@ -251,44 +251,6 @@ void MEANDER_PLACER_BASE::tuneLineLength( MEANDERED_LINE& aTuned, long long int } -int MEANDER_PLACER_BASE::GetTotalPadToDieLength( const LINE& aLine ) const -{ - int length = 0; - JOINT start; - JOINT end; - - m_world->FindLineEnds( aLine, start, end ); - - // Extract the length of the pad to die for start and end pads - for( auto& link : start.LinkList() ) - { - if( const SOLID* solid = dyn_cast( link ) ) - { - // If there are overlapping pads, choose the first with a non-zero length - if( solid->GetPadToDie() > 0 ) - { - length += solid->GetPadToDie(); - break; - } - } - } - - for( auto& link : end.LinkList() ) - { - if( const SOLID* solid = dyn_cast( link ) ) - { - if( solid->GetPadToDie() > 0 ) - { - length += solid->GetPadToDie(); - break; - } - } - } - - return length; -} - - const MEANDER_SETTINGS& MEANDER_PLACER_BASE::MeanderSettings() const { return m_settings; @@ -325,6 +287,16 @@ long long int MEANDER_PLACER_BASE::lineLength( const ITEM_SET& aLine, const SOLI return 0; ROUTER_IFACE* iface = Router()->GetInterface(); - return iface->CalculateRoutedPathLength( aLine, aStartPad, aEndPad ); + return iface->CalculateRoutedPathLength( aLine, aStartPad, aEndPad, m_settings.m_netClass ); +} + + +int64_t MEANDER_PLACER_BASE::lineDelay( const ITEM_SET& aLine, const SOLID* aStartPad, const SOLID* aEndPad ) const +{ + if( aLine.Empty() ) + return 0; + + ROUTER_IFACE* iface = Router()->GetInterface(); + return iface->CalculateRoutedPathDelay( aLine, aStartPad, aEndPad, m_settings.m_netClass ); } } diff --git a/pcbnew/router/pns_meander_placer_base.h b/pcbnew/router/pns_meander_placer_base.h index 83d18bec0f..b8aef93f70 100644 --- a/pcbnew/router/pns_meander_placer_base.h +++ b/pcbnew/router/pns_meander_placer_base.h @@ -58,7 +58,12 @@ public: /** * Return the resultant length or skew of the tuned traces. */ - virtual long long int TuningResult() const = 0; + virtual long long int TuningLengthResult() const = 0; + + /** + * Return the resultant delay or skew of the tuned traces. + */ + virtual int64_t TuningDelayResult() const { return 0; }; /** * Return the tuning status (too short, too long, etc.) of the trace(s) being tuned. @@ -112,8 +117,6 @@ public: return false; } - int GetTotalPadToDieLength( const LINE& aLine ) const; - virtual const ITEM_SET TunedPath() = 0; protected: @@ -132,6 +135,13 @@ protected: */ long long int lineLength( const ITEM_SET& aLine, const SOLID* aStartPad, const SOLID* aEndPad ) const; + /** + * Calculate the total delay of the line represented by an item set (tracks and vias) + * @param aLine + * @return + */ + int64_t lineDelay( const ITEM_SET& aLine, const SOLID* aStartPad, const SOLID* aEndPad ) const; + ///< Pointer to world to search colliding items. NODE* m_world; diff --git a/pcbnew/router/pns_meander_skew_placer.cpp b/pcbnew/router/pns_meander_skew_placer.cpp index d62d598ec4..ea9dcfbc98 100644 --- a/pcbnew/router/pns_meander_skew_placer.cpp +++ b/pcbnew/router/pns_meander_skew_placer.cpp @@ -35,8 +35,11 @@ MEANDER_SKEW_PLACER::MEANDER_SKEW_PLACER ( ROUTER* aRouter ) : { // Init temporary variables (do not leave uninitialized members) m_coupledLength = 0; - m_padToDieN = 0; - m_padToDieP = 0; + m_coupledDelay = 0; + m_padToDieLengthN = 0; + m_padToDieLengthP = 0; + m_padToDieDelayN = 0; + m_padToDieDelayP = 0; } @@ -81,43 +84,71 @@ bool MEANDER_SKEW_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem ) m_tunedPathP = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.PLine().GetLink( 0 ), &m_startPad_p, &m_endPad_p ); - m_padToDieP = 0; + m_padToDieLengthP = 0; + m_padToDieDelayP = 0; if( m_startPad_p ) - m_padToDieP += m_startPad_p->GetPadToDie(); + { + m_padToDieLengthP += m_startPad_p->GetPadToDie(); + m_padToDieDelayP += m_startPad_p->GetPadToDieDelay(); + } if( m_endPad_p ) - m_padToDieP += m_endPad_p->GetPadToDie(); + { + m_padToDieLengthP += m_endPad_p->GetPadToDie(); + m_padToDieDelayP += m_endPad_p->GetPadToDieDelay(); + } m_tunedPathN = topo.AssembleTuningPath( Router()->GetInterface(), m_originPair.NLine().GetLink( 0 ), &m_startPad_n, &m_endPad_n ); - m_padToDieN = 0; + m_padToDieLengthN = 0; + m_padToDieDelayN = 0; if( m_startPad_n ) - m_padToDieN += m_startPad_n->GetPadToDie(); + { + m_padToDieLengthN += m_startPad_n->GetPadToDie(); + m_padToDieDelayN += m_startPad_n->GetPadToDieDelay(); + } if( m_endPad_n ) - m_padToDieN += m_endPad_n->GetPadToDie(); + { + m_padToDieLengthN += m_endPad_n->GetPadToDie(); + m_padToDieDelayN += m_endPad_n->GetPadToDieDelay(); + } m_world->Remove( m_originLine ); m_currentWidth = m_originLine.Width(); m_currentEnd = VECTOR2I( 0, 0 ); + const BOARD_CONNECTED_ITEM* conItem = static_cast( aStartItem->GetSourceItem() ); + m_netClass = conItem->GetEffectiveNetClass(); + m_settings.m_netClass = m_netClass; + if ( m_originPair.NetP() == m_originLine.Net() ) { - m_coupledLength = m_padToDieN + lineLength( m_tunedPathN, m_startPad_n, m_endPad_n ); - m_lastLength = m_padToDieP + lineLength( m_tunedPathP, m_startPad_p, m_endPad_p ); + m_coupledLength = m_padToDieLengthN + lineLength( m_tunedPathN, m_startPad_n, m_endPad_n ); + m_lastLength = m_padToDieLengthP + lineLength( m_tunedPathP, m_startPad_p, m_endPad_p ); + + m_coupledDelay = m_padToDieDelayN + lineDelay( m_tunedPathN, m_startPad_p, m_endPad_p ); + m_lastDelay = m_padToDieDelayP + lineDelay( m_tunedPathP, m_startPad_p, m_endPad_p ); + m_tunedPath = m_tunedPathP; } else { - m_coupledLength = m_padToDieP + lineLength( m_tunedPathP, m_startPad_p, m_endPad_p ); - m_lastLength = m_padToDieN + lineLength( m_tunedPathN, m_startPad_n, m_endPad_n ); + m_coupledLength = m_padToDieLengthP + lineLength( m_tunedPathP, m_startPad_p, m_endPad_p ); + m_lastLength = m_padToDieLengthN + lineLength( m_tunedPathN, m_startPad_n, m_endPad_n ); + + m_coupledDelay = m_padToDieDelayP + lineDelay( m_tunedPathP, m_startPad_p, m_endPad_p ); + m_lastDelay = m_padToDieDelayN + lineDelay( m_tunedPathN, m_startPad_p, m_endPad_p ); + m_tunedPath = m_tunedPathN; } + calculateTimeDomainTargets(); + return true; } @@ -125,10 +156,18 @@ bool MEANDER_SKEW_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem ) long long int MEANDER_SKEW_PLACER::origPathLength() const { if ( m_originPair.NetP() == m_originLine.Net() ) - return m_padToDieP + lineLength( m_tunedPath, m_startPad_p, m_endPad_p ); + return m_padToDieLengthP + lineLength( m_tunedPath, m_startPad_p, m_endPad_p ); - return m_padToDieN + lineLength( m_tunedPath, m_startPad_n, m_endPad_n ); + return m_padToDieLengthN + lineLength( m_tunedPath, m_startPad_n, m_endPad_n ); +} + +int64_t MEANDER_SKEW_PLACER::origPathDelay() const +{ + if( m_originPair.NetP() == m_originLine.Net() ) + return m_padToDieDelayP + lineDelay( m_tunedPath, m_startPad_p, m_endPad_p ); + + return m_padToDieDelayN + lineDelay( m_tunedPath, m_startPad_n, m_endPad_n ); } @@ -140,6 +179,8 @@ long long int MEANDER_SKEW_PLACER::CurrentSkew() const bool MEANDER_SKEW_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem ) { + calculateTimeDomainTargets(); + bool isPositive = m_originPair.NetP() == m_originLine.Net(); for( const ITEM* item : m_tunedPathP.CItems() ) @@ -168,9 +209,37 @@ bool MEANDER_SKEW_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem ) } -long long int MEANDER_SKEW_PLACER::TuningResult() const +long long int MEANDER_SKEW_PLACER::TuningLengthResult() const { return m_lastLength - m_coupledLength; } + +int64_t MEANDER_SKEW_PLACER::TuningDelayResult() const +{ + return m_lastDelay - m_coupledDelay; +} + + +void MEANDER_SKEW_PLACER::calculateTimeDomainTargets() +{ + if( m_settings.m_isTimeDomain ) + { + const int64_t minSkew = m_router->GetInterface()->CalculateLengthForDelay( + m_settings.m_targetSkewDelay.Min(), m_originPair.Width(), true, m_originPair.Gap(), + m_router->GetCurrentLayer(), m_netClass ); + + const int64_t optSkew = m_router->GetInterface()->CalculateLengthForDelay( + m_settings.m_targetSkewDelay.Opt(), m_originPair.Width(), true, m_originPair.Gap(), + m_router->GetCurrentLayer(), m_netClass ); + + const int64_t maxSkew = m_router->GetInterface()->CalculateLengthForDelay( + m_settings.m_targetSkewDelay.Max(), m_originPair.Width(), true, m_originPair.Gap(), + m_router->GetCurrentLayer(), m_netClass ); + + m_settings.m_targetSkew.SetMin( static_cast( minSkew ) ); + m_settings.m_targetSkew.SetOpt( static_cast( optSkew ) ); + m_settings.m_targetSkew.SetMax( static_cast( maxSkew ) ); + } +} } diff --git a/pcbnew/router/pns_meander_skew_placer.h b/pcbnew/router/pns_meander_skew_placer.h index d469b7c932..d292b14434 100644 --- a/pcbnew/router/pns_meander_skew_placer.h +++ b/pcbnew/router/pns_meander_skew_placer.h @@ -48,20 +48,30 @@ public: /// @copydoc PLACEMENT_ALGO::Move() bool Move( const VECTOR2I& aP, ITEM* aEndItem ) override; - /// @copydoc MEANDER_PLACER_BASE::TuningResult() - long long int TuningResult() const override; + /// @copydoc MEANDER_PLACER_BASE::TuningLengthResult() + long long int TuningLengthResult() const override; + + /// @copydoc MEANDER_PLACER_BASE::TuningDelayResult() + int64_t TuningDelayResult() const override; long long int CurrentSkew() const; private: long long int origPathLength() const override; + int64_t origPathDelay() const override; + + void calculateTimeDomainTargets() override; + DIFF_PAIR m_originPair; ITEM_SET m_tunedPathP, m_tunedPathN; long long int m_coupledLength; - int m_padToDieP; - int m_padToDieN; + int64_t m_coupledDelay; + int m_padToDieLengthP; + int m_padToDieLengthN; + int64_t m_padToDieDelayP; + int64_t m_padToDieDelayN; }; } diff --git a/pcbnew/router/pns_node.h b/pcbnew/router/pns_node.h index 377a9520b9..e3ba73107c 100644 --- a/pcbnew/router/pns_node.h +++ b/pcbnew/router/pns_node.h @@ -77,6 +77,7 @@ struct CONSTRAINT wxString m_RuleName; wxString m_FromName; wxString m_ToName; + bool m_IsTimeDomain; }; diff --git a/pcbnew/router/pns_router.h b/pcbnew/router/pns_router.h index dd30ae9a48..42c2cb4efa 100644 --- a/pcbnew/router/pns_router.h +++ b/pcbnew/router/pns_router.h @@ -118,7 +118,14 @@ enum DRAG_MODE virtual DEBUG_DECORATOR* GetDebugDecorator() = 0; virtual long long int CalculateRoutedPathLength( const ITEM_SET& aLine, const SOLID* aStartPad, - const SOLID* aEndPad ) = 0; + const SOLID* aEndPad, const NETCLASS* aNetClass ) = 0; + virtual int64_t CalculateRoutedPathDelay( const ITEM_SET& aLine, const SOLID* aStartPad, const SOLID* aEndPad, + const NETCLASS* aNetClass ) = 0; + virtual int64_t CalculateLengthForDelay( int64_t aDesiredDelay, int aWidth, bool aIsDiffPairCoupled, + int aDiffPairCouplingGap, int aPNSLayer, const NETCLASS* aNetClass ) = 0; + virtual int64_t CalculateDelayForShapeLineChain( const SHAPE_LINE_CHAIN& aShape, int aWidth, + bool aIsDiffPairCoupled, int aDiffPairCouplingGap, int aPNSLayer, + const NETCLASS* aNetClass ) = 0; virtual PCB_LAYER_ID GetBoardLayerFromPNSLayer( int aLayer ) const = 0; virtual int GetPNSLayerFromBoardLayer( PCB_LAYER_ID aLayer ) const = 0; }; diff --git a/pcbnew/router/pns_solid.h b/pcbnew/router/pns_solid.h index 67d2f6c6db..6b25d5d1af 100644 --- a/pcbnew/router/pns_solid.h +++ b/pcbnew/router/pns_solid.h @@ -39,10 +39,11 @@ public: SOLID() : ITEM( SOLID_T ), m_shape( nullptr ), + m_padToDie(0), + m_padToDieDelay(0), m_hole( nullptr ) { m_movable = false; - m_padToDie = 0; } ~SOLID() @@ -64,6 +65,7 @@ public: m_pos = aSolid.m_pos; m_padToDie = aSolid.m_padToDie; + m_padToDieDelay = aSolid.m_padToDieDelay; m_orientation = aSolid.m_orientation; m_anchorPoints = aSolid.m_anchorPoints; } @@ -81,6 +83,7 @@ public: m_pos = aB.m_pos; m_padToDie = aB.m_padToDie; + m_padToDieDelay = aB.m_padToDieDelay; m_orientation = aB.m_orientation; m_anchorPoints = aB.m_anchorPoints; @@ -115,7 +118,10 @@ public: void SetPos( const VECTOR2I& aCenter ); int GetPadToDie() const { return m_padToDie; } - void SetPadToDie( int aLen ) { m_padToDie = aLen; } + void SetPadToDie( const int aLen ) { m_padToDie = aLen; } + + int GetPadToDieDelay() const { return m_padToDieDelay; } + void SetPadToDieDelay( const int aDelay ) { m_padToDieDelay = aDelay; } virtual VECTOR2I Anchor( int aN ) const override; @@ -150,6 +156,7 @@ private: SHAPE* m_shape; VECTOR2I m_offset; int m_padToDie; + int m_padToDieDelay; EDA_ANGLE m_orientation; HOLE* m_hole; std::vector m_anchorPoints; diff --git a/pcbnew/router/pns_topology.cpp b/pcbnew/router/pns_topology.cpp index c75fa3c9fd..5bd86d206a 100644 --- a/pcbnew/router/pns_topology.cpp +++ b/pcbnew/router/pns_topology.cpp @@ -382,7 +382,7 @@ const ITEM_SET TOPOLOGY::AssembleTuningPath( ROUTER_IFACE* aRouterIface, ITEM* a SHAPE_LINE_CHAIN& slc = line->Line(); const PCB_LAYER_ID pcbLayer = aRouterIface->GetBoardLayerFromPNSLayer( line->Layer() ); - LENGTH_CALCULATION::OptimiseTraceInPad( slc, aPad, pcbLayer ); + LENGTH_DELAY_CALCULATION::OptimiseTraceInPad( slc, aPad, pcbLayer ); } }; diff --git a/pcbnew/widgets/pcb_net_inspector_panel.cpp b/pcbnew/widgets/pcb_net_inspector_panel.cpp index 2732548f54..ed0574985d 100644 --- a/pcbnew/widgets/pcb_net_inspector_panel.cpp +++ b/pcbnew/widgets/pcb_net_inspector_panel.cpp @@ -117,16 +117,40 @@ void PCB_NET_INSPECTOR_PANEL::buildColumns() CSV_COLUMN_DESC::CSV_QUOTE, false ); m_columns.emplace_back( 1u, UNDEFINED_LAYER, _( "Netclass" ), _( "Netclass" ), CSV_COLUMN_DESC::CSV_QUOTE, false ); - m_columns.emplace_back( 2u, UNDEFINED_LAYER, _( "Total Length" ), _( "Net Length" ), - CSV_COLUMN_DESC::CSV_NONE, true ); + + if( m_showTimeDomainDetails ) + { + m_columns.emplace_back( 2u, UNDEFINED_LAYER, _( "Total Delay" ), _( "Net Delay" ), CSV_COLUMN_DESC::CSV_NONE, + true ); + } + else + { + m_columns.emplace_back( 2u, UNDEFINED_LAYER, _( "Total Length" ), _( "Net Length" ), CSV_COLUMN_DESC::CSV_NONE, + true ); + } + m_columns.emplace_back( 3u, UNDEFINED_LAYER, _( "Via Count" ), _( "Via Count" ), CSV_COLUMN_DESC::CSV_NONE, false ); - m_columns.emplace_back( 4u, UNDEFINED_LAYER, _( "Via Length" ), _( "Via Length" ), - CSV_COLUMN_DESC::CSV_NONE, true ); - m_columns.emplace_back( 5u, UNDEFINED_LAYER, _( "Track Length" ), _( "Track Length" ), - CSV_COLUMN_DESC::CSV_NONE, true ); - m_columns.emplace_back( 6u, UNDEFINED_LAYER, _( "Die Length" ), _( "Die Length" ), - CSV_COLUMN_DESC::CSV_NONE, true ); + + if( m_showTimeDomainDetails ) + { + m_columns.emplace_back( 4u, UNDEFINED_LAYER, _( "Via Delay" ), _( "Via Delay" ), CSV_COLUMN_DESC::CSV_NONE, + true ); + m_columns.emplace_back( 5u, UNDEFINED_LAYER, _( "Track Delay" ), _( "Track Delay" ), CSV_COLUMN_DESC::CSV_NONE, + true ); + m_columns.emplace_back( 6u, UNDEFINED_LAYER, _( "Die Delay" ), _( "Die Delay" ), CSV_COLUMN_DESC::CSV_NONE, + true ); + } + else + { + m_columns.emplace_back( 4u, UNDEFINED_LAYER, _( "Via Length" ), _( "Via Length" ), CSV_COLUMN_DESC::CSV_NONE, + true ); + m_columns.emplace_back( 5u, UNDEFINED_LAYER, _( "Track Length" ), _( "Track Length" ), + CSV_COLUMN_DESC::CSV_NONE, true ); + m_columns.emplace_back( 6u, UNDEFINED_LAYER, _( "Die Length" ), _( "Die Length" ), CSV_COLUMN_DESC::CSV_NONE, + true ); + } + m_columns.emplace_back( 7u, UNDEFINED_LAYER, _( "Pad Count" ), _( "Pad Count" ), CSV_COLUMN_DESC::CSV_NONE, false ); const std::vector> add_col{ @@ -386,6 +410,8 @@ void PCB_NET_INSPECTOR_PANEL::buildNetsList( const bool rebuildColumns ) m_netsList->Freeze(); + m_dataModel->SetIsTimeDomain( m_showTimeDomainDetails ); + PROJECT_LOCAL_SETTINGS& localSettings = Pgm().GetSettingsManager().Prj().GetLocalSettings(); PANEL_NET_INSPECTOR_SETTINGS* cfg = &localSettings.m_NetInspectorPanel; @@ -393,6 +419,7 @@ void PCB_NET_INSPECTOR_PANEL::buildNetsList( const bool rebuildColumns ) m_filterByNetName = cfg->filter_by_net_name; m_filterByNetclass = cfg->filter_by_netclass; m_showZeroPadNets = cfg->show_zero_pad_nets; + m_showTimeDomainDetails = cfg->show_time_domain_details; m_groupByNetclass = cfg->group_by_netclass; m_groupByConstraint = cfg->group_by_constraint; @@ -612,13 +639,13 @@ PCB_NET_INSPECTOR_PANEL::calculateNets( const std::vector& aNetCo { std::vector> results; - LENGTH_CALCULATION* calc = m_board->GetLengthCalculation(); + LENGTH_DELAY_CALCULATION* calc = m_board->GetLengthCalculation(); const std::vector conItems = relevantConnectivityItems(); // First assemble the LENGTH_CALCULATION_ITEMs for board items which match the nets we need to recompute // Precondition: conItems and aNetCodes are sorted in increasing netcode value // Functionality: This extracts any items from conItems which have a netcode which is present in aNetCodes - std::unordered_map> netItemsMap; + std::unordered_map> netItemsMap; std::vector foundNets; auto itemItr = conItems.begin(); @@ -635,7 +662,7 @@ PCB_NET_INSPECTOR_PANEL::calculateNets( const std::vector& aNetCo foundNets.emplace_back( *netCodeItr ); // Take the item - LENGTH_CALCULATION_ITEM lengthItem = calc->GetLengthCalculationItem( ( *itemItr )->Parent() ); + LENGTH_DELAY_CALCULATION_ITEM lengthItem = calc->GetLengthCalculationItem( ( *itemItr )->Parent() ); netItemsMap[curItemNetCode].emplace_back( std::move( lengthItem ) ); ++itemItr; } @@ -670,8 +697,10 @@ PCB_NET_INSPECTOR_PANEL::calculateNets( const std::vector& aNetCo .MergeTracks = true, .OptimiseTracesInPads = true, .InferViaInPad = false }; - LENGTH_DETAILS lengthDetails = - calc->CalculateLengthDetails( netItemsMap[netCode], opts, nullptr, nullptr, true ); + LENGTH_DELAY_STATS lengthDetails = calc->CalculateLengthDetails( + netItemsMap[netCode], opts, nullptr, nullptr, LENGTH_DELAY_LAYER_OPT::WITH_LAYER_DETAIL, + m_showTimeDomainDetails ? LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL + : LENGTH_DELAY_DOMAIN_OPT::NO_DELAY_DETAIL ); if( aIncludeZeroPadNets || lengthDetails.NumPads > 0 ) { @@ -680,10 +709,15 @@ PCB_NET_INSPECTOR_PANEL::calculateNets( const std::vector& aNetCo new_item->SetPadCount( lengthDetails.NumPads ); new_item->SetLayerCount( m_board->GetCopperLayerCount() ); new_item->SetPadDieLength( lengthDetails.PadToDieLength ); + new_item->SetPadDieDelay( lengthDetails.PadToDieDelay ); new_item->SetViaCount( lengthDetails.NumVias ); new_item->SetViaLength( lengthDetails.ViaLength ); + new_item->SetViaDelay( lengthDetails.ViaDelay ); new_item->SetLayerWireLengths( *lengthDetails.LayerLengths ); + if( m_showTimeDomainDetails ) + new_item->SetLayerWireDelays( *lengthDetails.LayerDelays ); + std::scoped_lock lock( resultsMutex ); results.emplace_back( std::move( new_item ) ); } @@ -728,6 +762,13 @@ wxString PCB_NET_INSPECTOR_PANEL::formatLength( const int64_t aValue ) const !m_inReporting ); } +wxString PCB_NET_INSPECTOR_PANEL::formatDelay( const int64_t aValue ) const +{ + return m_frame->MessageTextFromValue( aValue, + // don't include unit label in the string when reporting + !m_inReporting, EDA_DATA_TYPE::TIME ); +} + void PCB_NET_INSPECTOR_PANEL::updateDisplayedRowValues( const std::optional& aRow ) const { @@ -887,10 +928,15 @@ void PCB_NET_INSPECTOR_PANEL::updateNets( const std::vector& aNet { curListItem->SetPadCount( newListItem->GetPadCount() ); curListItem->SetPadDieLength( newListItem->GetPadDieLength() ); + curListItem->SetPadDieDelay( newListItem->GetPadDieDelay() ); curListItem->SetViaCount( newListItem->GetViaCount() ); curListItem->SetViaLength( newListItem->GetViaLength() ); + curListItem->SetViaDelay( newListItem->GetViaDelay() ); curListItem->SetLayerWireLengths( newListItem->GetLayerWireLengths() ); + if( m_showTimeDomainDetails ) + curListItem->SetLayerWireDelays( newListItem->GetLayerWireDelays() ); + updateDisplayedRowValues( curNetRow ); } } @@ -1229,6 +1275,13 @@ void PCB_NET_INSPECTOR_PANEL::OnConfigButton( wxCommandEvent& event ) menu.AppendSeparator(); + wxMenuItem* showTimeDomainDetails = new wxMenuItem( &menu, ID_SHOW_TIME_DOMAIN_DETAILS, + _( "Show Time Domain Details" ), wxEmptyString, wxITEM_CHECK ); + menu.Append( showTimeDomainDetails ); + showTimeDomainDetails->Check( m_showTimeDomainDetails ); + + menu.AppendSeparator(); + // Report generation wxMenuItem* generateReport = new wxMenuItem( &menu, ID_GENERATE_REPORT, _( "Save Net Inspector Report..." ), @@ -1314,6 +1367,8 @@ void PCB_NET_INSPECTOR_PANEL::onContextMenuSelection( wxCommandEvent& event ) case ID_SHOW_UNCONNECTED_NETS: m_showUnconnectedNets = !m_showUnconnectedNets; break; + case ID_SHOW_TIME_DOMAIN_DETAILS: m_showTimeDomainDetails = !m_showTimeDomainDetails; break; + case ID_GENERATE_REPORT: generateReport(); saveAndRebuild = false; @@ -1766,6 +1821,7 @@ void PCB_NET_INSPECTOR_PANEL::SaveSettings() cfg.group_by_constraint = m_groupByConstraint; cfg.show_zero_pad_nets = m_showZeroPadNets; cfg.show_unconnected_nets = m_showUnconnectedNets; + cfg.show_time_domain_details = m_showTimeDomainDetails; // Grid sorting wxDataViewColumn* sortingCol = m_netsList->GetSortingColumn(); diff --git a/pcbnew/widgets/pcb_net_inspector_panel.h b/pcbnew/widgets/pcb_net_inspector_panel.h index 3fcb87100a..55a44d1fad 100644 --- a/pcbnew/widgets/pcb_net_inspector_panel.h +++ b/pcbnew/widgets/pcb_net_inspector_panel.h @@ -108,6 +108,7 @@ private: static wxString formatNetName( const NETINFO_ITEM* aNet ); static wxString formatCount( unsigned int aValue ); wxString formatLength( int64_t aValue ) const; + wxString formatDelay( int64_t aValue ) const; /// Generates a sub-menu for the show / hide columns submenu void generateShowHideColumnMenu( wxMenu* target ); @@ -255,6 +256,7 @@ private: bool m_showUnconnectedNets = false; bool m_groupByNetclass = false; bool m_groupByConstraint = false; + bool m_showTimeDomainDetails = false; /// Custom net grouping rules std::vector> m_custom_group_rules; @@ -324,6 +326,7 @@ private: ID_GENERATE_REPORT, ID_HIGHLIGHT_SELECTED_NETS, ID_CLEAR_HIGHLIGHTING, + ID_SHOW_TIME_DOMAIN_DETAILS, ID_LAST_STATIC_MENU = ID_CLEAR_HIGHLIGHTING, ID_HIDE_COLUMN, }; diff --git a/pcbnew/widgets/pcb_net_inspector_panel_data_model.h b/pcbnew/widgets/pcb_net_inspector_panel_data_model.h index 6949a38a41..55fe93bd95 100644 --- a/pcbnew/widgets/pcb_net_inspector_panel_data_model.h +++ b/pcbnew/widgets/pcb_net_inspector_panel_data_model.h @@ -183,6 +183,35 @@ public: m_via_length -= aValue; } + int64_t GetViaDelay() const { return m_via_delay; } + + void SetViaDelay( unsigned int aValue ) + { + if( m_parent ) + m_parent->SetViaDelay( m_parent->GetViaDelay() - m_via_delay + aValue ); + + m_column_changed[COLUMN_VIA_LENGTH] |= ( m_via_delay != aValue ); + m_via_delay = aValue; + } + + void AddViaDelay( unsigned int aValue ) + { + if( m_parent ) + m_parent->AddViaDelay( aValue ); + + m_column_changed[COLUMN_VIA_LENGTH] |= ( aValue != 0 ); + m_via_delay += aValue; + } + + void SubViaDelay( int64_t aValue ) + { + if( m_parent ) + m_parent->SubViaDelay( aValue ); + + m_column_changed[COLUMN_VIA_LENGTH] |= ( aValue != 0 ); + m_via_delay -= aValue; + } + int64_t GetBoardWireLength() const { int64_t retval = 0; @@ -193,12 +222,28 @@ public: return retval; } + int64_t GetBoardWireDelay() const + { + int64_t retval = 0; + + for( auto& [layer, delay] : m_layer_wire_delay ) + retval += delay; + + return retval; + } + int64_t GetLayerWireLength( PCB_LAYER_ID aLayer ) const { auto it = m_layer_wire_length.find( aLayer ); return it != m_layer_wire_length.end() ? it->second : 0; } + int64_t GetLayerWireDelay( PCB_LAYER_ID aLayer ) const + { + auto it = m_layer_wire_delay.find( aLayer ); + return it != m_layer_wire_delay.end() ? it->second : 0; + } + bool BoardWireLengthChanged() const { return m_column_changed[COLUMN_BOARD_LENGTH]; } void SetLayerWireLength( const int64_t aValue, PCB_LAYER_ID aLayer ) @@ -221,6 +266,8 @@ public: std::map GetLayerWireLengths() const { return m_layer_wire_length; } + std::map GetLayerWireDelays() const { return m_layer_wire_delay; } + void SetLayerWireLengths( const std::map& aValue ) { if( m_parent ) @@ -253,6 +300,38 @@ public: m_layer_wire_length[aLayer] -= aValue; } + void SetLayerWireDelays( const std::map& aValue ) + { + if( m_parent ) + { + for( auto& [oldLayer, oldLength] : m_layer_wire_delay ) + m_parent->SubLayerWireDelay( oldLength, oldLayer ); + + for( auto& [newLayer, newLength] : aValue ) + m_parent->AddLayerWireDelay( newLength, newLayer ); + } + + m_layer_wire_delay = aValue; + } + + void AddLayerWireDelay( const int64_t aValue, PCB_LAYER_ID aLayer ) + { + if( m_parent ) + m_parent->AddLayerWireDelay( aValue, aLayer ); + + m_column_changed[COLUMN_BOARD_LENGTH] |= ( m_layer_wire_delay[aLayer] != 0 ); + m_layer_wire_delay[aLayer] += aValue; + } + + void SubLayerWireDelay( const int64_t aValue, PCB_LAYER_ID aLayer ) + { + if( m_parent ) + m_parent->SubLayerWireDelay( aValue, aLayer ); + + m_column_changed[COLUMN_BOARD_LENGTH] |= ( m_layer_wire_delay[aLayer] != 0 ); + m_layer_wire_delay[aLayer] -= aValue; + } + int64_t GetPadDieLength() const { return m_pad_die_length; } bool PadDieLengthChanged() const { return m_column_changed[COLUMN_PAD_DIE_LENGTH]; } @@ -284,12 +363,43 @@ public: m_pad_die_length -= aValue; } + int64_t GetPadDieDelay() const { return m_pad_die_delay; } + + void SetPadDieDelay( int64_t aValue ) + { + if( m_parent ) + m_parent->SetPadDieDelay( m_parent->GetPadDieDelay() - m_pad_die_delay + aValue ); + + m_column_changed[COLUMN_PAD_DIE_LENGTH] |= ( m_pad_die_delay != aValue ); + m_pad_die_delay = aValue; + } + + void AddPadDieDelay( int64_t aValue ) + { + if( m_parent ) + m_parent->AddPadDieDelay( aValue ); + + m_column_changed[COLUMN_PAD_DIE_LENGTH] |= ( aValue != 0 ); + m_pad_die_delay += aValue; + } + + void SubPadDieDelay( int64_t aValue ) + { + if( m_parent ) + m_parent->SubPadDieDelay( aValue ); + + m_column_changed[COLUMN_PAD_DIE_LENGTH] |= ( aValue != 0 ); + m_pad_die_delay -= aValue; + } + // the total length column is always computed, never stored. unsigned long long int GetTotalLength() const { return GetBoardWireLength() + GetViaLength() + GetPadDieLength(); } + unsigned long long int GetTotalDelay() const { return GetBoardWireDelay() + GetViaDelay() + GetPadDieDelay(); } + bool TotalLengthChanged() const { return BoardWireLengthChanged() || ViaLengthChanged() || PadDieLengthChanged(); @@ -307,11 +417,16 @@ public: m_parent->SubPadCount( GetPadCount() ); m_parent->SubViaCount( GetViaCount() ); m_parent->SubViaLength( GetViaLength() ); + m_parent->SubViaDelay( GetViaDelay() ); for( auto& [layer, length] : m_layer_wire_length ) m_parent->SubLayerWireLength( length, layer ); + for( auto& [layer, delay] : m_layer_wire_delay ) + m_parent->SubLayerWireDelay( delay, layer ); + m_parent->SubPadDieLength( GetPadDieLength() ); + m_parent->SubPadDieDelay( GetPadDieDelay() ); m_parent->m_children.erase( std::find( m_parent->m_children.begin(), m_parent->m_children.end(), this ) ); @@ -324,11 +439,16 @@ public: m_parent->AddPadCount( GetPadCount() ); m_parent->AddViaCount( GetViaCount() ); m_parent->AddViaLength( GetViaLength() ); + m_parent->AddViaDelay( GetViaDelay() ); for( auto& [layer, length] : m_layer_wire_length ) m_parent->AddLayerWireLength( length, layer ); + for( auto& [layer, delay] : m_layer_wire_delay ) + m_parent->AddLayerWireDelay( delay, layer ); + m_parent->AddPadDieLength( GetPadDieLength() ); + m_parent->AddPadDieDelay( GetPadDieDelay() ); m_parent->m_children.push_back( this ); } @@ -344,9 +464,12 @@ private: unsigned int m_pad_count = 0; unsigned int m_via_count = 0; int64_t m_via_length = 0; + int64_t m_via_delay = 0; int64_t m_pad_die_length = 0; + int64_t m_pad_die_delay = 0; std::map m_layer_wire_length{}; + std::map m_layer_wire_delay{}; // Dirty bits to record when some attribute has changed, in order to avoid unnecessary sort // operations. @@ -694,6 +817,8 @@ public: return false; } + void SetIsTimeDomain( const bool aIsTimeDomain ) { m_show_time_domain_details = aIsTimeDomain; } + // implementation of wxDataViewModel interface // these are used to query the data model by the GUI view implementation. // these are not supposed to be used to modify the data model. for that @@ -740,19 +865,44 @@ protected: aOutValue = m_parent.formatCount( i->GetViaCount() ); else if( aCol == COLUMN_VIA_LENGTH ) - aOutValue = m_parent.formatLength( i->GetViaLength() ); + { + if( m_show_time_domain_details ) + aOutValue = m_parent.formatDelay( i->GetViaDelay() ); + else + aOutValue = m_parent.formatLength( i->GetViaLength() ); + } else if( aCol == COLUMN_BOARD_LENGTH ) - aOutValue = m_parent.formatLength( i->GetBoardWireLength() ); + { + if( m_show_time_domain_details ) + aOutValue = m_parent.formatDelay( i->GetBoardWireDelay() ); + else + aOutValue = m_parent.formatLength( i->GetBoardWireLength() ); + } else if( aCol == COLUMN_PAD_DIE_LENGTH ) - aOutValue = m_parent.formatLength( i->GetPadDieLength() ); + { + if( m_show_time_domain_details ) + aOutValue = m_parent.formatDelay( i->GetPadDieDelay() ); + else + aOutValue = m_parent.formatLength( i->GetPadDieLength() ); + } else if( aCol == COLUMN_TOTAL_LENGTH ) - aOutValue = m_parent.formatLength( i->GetTotalLength() ); + { + if( m_show_time_domain_details ) + aOutValue = m_parent.formatDelay( i->GetTotalDelay() ); + else + aOutValue = m_parent.formatLength( i->GetTotalLength() ); + } else if( aCol > COLUMN_LAST_STATIC_COL && aCol <= m_parent.m_columns.size() ) - aOutValue = m_parent.formatLength( i->GetLayerWireLength( m_parent.m_columns[aCol].layer ) ); + { + if( m_show_time_domain_details ) + aOutValue = m_parent.formatDelay( i->GetLayerWireDelay( m_parent.m_columns[aCol].layer ) ); + else + aOutValue = m_parent.formatLength( i->GetLayerWireLength( m_parent.m_columns[aCol].layer ) ); + } else aOutValue = ""; @@ -796,24 +946,59 @@ protected: else if( aCol == COLUMN_VIA_COUNT && i1.GetViaCount() != i2.GetViaCount() ) return compareUInt( i1.GetViaCount(), i2.GetViaCount(), aAsc ); - else if( aCol == COLUMN_VIA_LENGTH && i1.GetViaLength() != i2.GetViaLength() ) - return compareUInt( i1.GetViaLength(), i2.GetViaLength(), aAsc ); - - else if( aCol == COLUMN_BOARD_LENGTH && i1.GetBoardWireLength() != i2.GetBoardWireLength() ) - return compareUInt( i1.GetBoardWireLength(), i2.GetBoardWireLength(), aAsc ); - - else if( aCol == COLUMN_PAD_DIE_LENGTH && i1.GetPadDieLength() != i2.GetPadDieLength() ) - return compareUInt( i1.GetPadDieLength(), i2.GetPadDieLength(), aAsc ); - - else if( aCol == COLUMN_TOTAL_LENGTH && i1.GetTotalLength() != i2.GetTotalLength() ) - return compareUInt( i1.GetTotalLength(), i2.GetTotalLength(), aAsc ); - - else if( aCol > COLUMN_LAST_STATIC_COL && aCol < m_parent.m_columns.size() - && i1.GetLayerWireLength( m_parent.m_columns[aCol].layer ) - != i2.GetLayerWireLength( m_parent.m_columns[aCol].layer ) ) + else if( aCol == COLUMN_VIA_LENGTH ) { - return compareUInt( i1.GetLayerWireLength( m_parent.m_columns[aCol].layer ), - i2.GetLayerWireLength( m_parent.m_columns[aCol].layer ), aAsc ); + if( m_show_time_domain_details && i1.GetViaDelay() != i2.GetViaDelay() ) + return compareUInt( i1.GetViaDelay(), i2.GetViaDelay(), aAsc ); + + if( !m_show_time_domain_details && i1.GetViaLength() != i2.GetViaLength() ) + return compareUInt( i1.GetViaLength(), i2.GetViaLength(), aAsc ); + } + + else if( aCol == COLUMN_BOARD_LENGTH ) + { + if( m_show_time_domain_details && i1.GetBoardWireDelay() != i2.GetBoardWireDelay() ) + return compareUInt( i1.GetBoardWireDelay(), i2.GetBoardWireDelay(), aAsc ); + + if( !m_show_time_domain_details && i1.GetBoardWireLength() != i2.GetBoardWireLength() ) + return compareUInt( i1.GetBoardWireLength(), i2.GetBoardWireLength(), aAsc ); + } + + else if( aCol == COLUMN_PAD_DIE_LENGTH ) + { + if( m_show_time_domain_details && i1.GetPadDieDelay() != i2.GetPadDieDelay() ) + return compareUInt( i1.GetPadDieDelay(), i2.GetPadDieDelay(), aAsc ); + + if( !m_show_time_domain_details && i1.GetPadDieLength() != i2.GetPadDieLength() ) + return compareUInt( i1.GetPadDieLength(), i2.GetPadDieLength(), aAsc ); + } + + else if( aCol == COLUMN_TOTAL_LENGTH ) + { + if( m_show_time_domain_details && i1.GetTotalDelay() != i2.GetTotalDelay() ) + return compareUInt( i1.GetTotalDelay(), i2.GetTotalDelay(), aAsc ); + + if( !m_show_time_domain_details && i1.GetTotalLength() != i2.GetTotalLength() ) + return compareUInt( i1.GetTotalLength(), i2.GetTotalLength(), aAsc ); + } + + else if( aCol > COLUMN_LAST_STATIC_COL && aCol < m_parent.m_columns.size() ) + { + if( m_show_time_domain_details + && i1.GetLayerWireDelay( m_parent.m_columns[aCol].layer ) + != i2.GetLayerWireDelay( m_parent.m_columns[aCol].layer ) ) + { + return compareUInt( i1.GetLayerWireDelay( m_parent.m_columns[aCol].layer ), + i2.GetLayerWireDelay( m_parent.m_columns[aCol].layer ), aAsc ); + } + + if( !m_show_time_domain_details + && i1.GetLayerWireLength( m_parent.m_columns[aCol].layer ) + != i2.GetLayerWireLength( m_parent.m_columns[aCol].layer ) ) + { + return compareUInt( i1.GetLayerWireLength( m_parent.m_columns[aCol].layer ), + i2.GetLayerWireLength( m_parent.m_columns[aCol].layer ), aAsc ); + } } // when the item values compare equal resort to pointer comparison. @@ -897,6 +1082,8 @@ private: /// Map of custom group names to their representative list item std::map m_custom_group_map; + + bool m_show_time_domain_details{ false }; }; #endif diff --git a/qa/data/config/9.99/kicad_common.json b/qa/data/config/9.99/kicad_common.json index 8b18ebc5ed..72090091a5 100644 --- a/qa/data/config/9.99/kicad_common.json +++ b/qa/data/config/9.99/kicad_common.json @@ -65,10 +65,10 @@ }, "meta": { "filename": "kicad_common.json", - "version": 3 + "version": 4 }, "netclass_panel": { - "eeschema_shown_columns": "0 10 11 12 13", + "eeschema_shown_columns": "0 11 12 13 14", "pcbnew_shown_columns": "0 1 2 3 4 5 6 7 8 9", "sash_pos": 160 }, diff --git a/qa/data/pcbnew/time_calculations.kicad_dru b/qa/data/pcbnew/time_calculations.kicad_dru new file mode 100644 index 0000000000..74b4e810a0 --- /dev/null +++ b/qa/data/pcbnew/time_calculations.kicad_dru @@ -0,0 +1,36 @@ +(version 1) + +(rule CLASS1 + (condition "A.hasNetclass('CLASS1')") + (constraint length (min 29.83ps) (opt 29.84ps) (max 29.85ps)) +) + +(rule CLASS2 + (condition "A.hasNetclass('CLASS2')") + (constraint length (min 59.83ps) (opt 59.84ps) (max 59.85ps)) +) + +(rule CLASS3 + (condition "A.hasNetclass('CLASS3')") + (constraint length (min 59.68ps) (opt 59.69ps) (max 59.70ps)) +) + +(rule CLASS4 + (condition "A.hasNetclass('CLASS4')") + (constraint length (min 31.38ps) (opt 31.39ps) (max 31.40ps)) +) + +(rule CLASS5 + (condition "A.hasNetclass('CLASS5')") + (constraint length (min 49.83ps) (opt 49.84ps) (max 49.85ps)) +) + +(rule CLASS6 + (condition "A.hasNetclass('CLASS6')") + (constraint length (min 75.71ps) (opt 75.72ps) (max 75.73ps)) +) + +(rule CLASS7 + (condition "A.hasNetclass('CLASS7')") + (constraint skew (min 4.44ps) (opt 4.45ps) (max 4.46ps)) +) diff --git a/qa/data/pcbnew/time_calculations.kicad_pcb b/qa/data/pcbnew/time_calculations.kicad_pcb new file mode 100644 index 0000000000..c2ef88bca4 --- /dev/null +++ b/qa/data/pcbnew/time_calculations.kicad_pcb @@ -0,0 +1,3882 @@ +(kicad_pcb + (version 20250401) + (generator "pcbnew") + (generator_version "9.99") + (general + (thickness 1.6) + (legacy_teardrops no) + ) + (paper "A4") + (layers + (0 "F.Cu" signal) + (4 "In1.Cu" signal) + (6 "In2.Cu" signal) + (2 "B.Cu" signal) + (9 "F.Adhes" user "F.Adhesive") + (11 "B.Adhes" user "B.Adhesive") + (13 "F.Paste" user) + (15 "B.Paste" user) + (5 "F.SilkS" user "F.Silkscreen") + (7 "B.SilkS" user "B.Silkscreen") + (1 "F.Mask" user) + (3 "B.Mask" user) + (17 "Dwgs.User" user "User.Drawings") + (19 "Cmts.User" user "User.Comments") + (21 "Eco1.User" user "User.Eco1") + (23 "Eco2.User" user "User.Eco2") + (25 "Edge.Cuts" user) + (27 "Margin" user) + (31 "F.CrtYd" user "F.Courtyard") + (29 "B.CrtYd" user "B.Courtyard") + (35 "F.Fab" user) + (33 "B.Fab" user) + (39 "User.1" user) + (41 "User.2" user) + (43 "User.3" user) + (45 "User.4" user) + ) + (setup + (stackup + (layer "F.SilkS" + (type "Top Silk Screen") + ) + (layer "F.Paste" + (type "Top Solder Paste") + ) + (layer "F.Mask" + (type "Top Solder Mask") + (thickness 0.01) + ) + (layer "F.Cu" + (type "copper") + (thickness 0.035) + ) + (layer "dielectric 1" + (type "prepreg") + (thickness 0.1) + (material "FR4") + (epsilon_r 4.5) + (loss_tangent 0.02) + ) + (layer "In1.Cu" + (type "copper") + (thickness 0.035) + ) + (layer "dielectric 2" + (type "core") + (thickness 1.24) + (material "FR4") + (epsilon_r 4.5) + (loss_tangent 0.02) + ) + (layer "In2.Cu" + (type "copper") + (thickness 0.035) + ) + (layer "dielectric 3" + (type "prepreg") + (thickness 0.1) + (material "FR4") + (epsilon_r 4.5) + (loss_tangent 0.02) + ) + (layer "B.Cu" + (type "copper") + (thickness 0.035) + ) + (layer "B.Mask" + (type "Bottom Solder Mask") + (thickness 0.01) + ) + (layer "B.Paste" + (type "Bottom Solder Paste") + ) + (layer "B.SilkS" + (type "Bottom Silk Screen") + ) + (copper_finish "None") + (dielectric_constraints no) + ) + (pad_to_mask_clearance 0) + (allow_soldermask_bridges_in_footprints no) + (tenting + (front yes) + (back yes) + ) + (covering + (front no) + (back no) + ) + (plugging + (front no) + (back no) + ) + (capping no) + (filling no) + (pcbplotparams + (layerselection 0x00000000_00000000_55555555_5755f5ff) + (plot_on_all_layers_selection 0x00000000_00000000_00000000_00000000) + (disableapertmacros no) + (usegerberextensions no) + (usegerberattributes yes) + (usegerberadvancedattributes yes) + (creategerberjobfile yes) + (dashed_line_dash_ratio 12.000000) + (dashed_line_gap_ratio 3.000000) + (svgprecision 4) + (plotframeref no) + (mode 1) + (useauxorigin no) + (hpglpennumber 1) + (hpglpenspeed 20) + (hpglpendiameter 15.000000) + (pdf_front_fp_property_popups yes) + (pdf_back_fp_property_popups yes) + (pdf_metadata yes) + (pdf_single_document no) + (dxfpolygonmode yes) + (dxfimperialunits yes) + (dxfusepcbnewfont yes) + (psnegative no) + (psa4output no) + (plot_black_and_white yes) + (sketchpadsonfab no) + (plotpadnumbers no) + (hidednponfab no) + (sketchdnponfab yes) + (crossoutdnponfab yes) + (subtractmaskfromsilk no) + (outputformat 1) + (mirror no) + (drillshape 1) + (scaleselection 1) + (outputdirectory "") + ) + ) + (net 0 "") + (net 1 "Net-(R1-Pad2)") + (net 2 "unconnected-(R1-Pad1)") + (net 3 "unconnected-(R2-Pad2)") + (net 4 "unconnected-(R3-Pad1)") + (net 5 "Net-(R3-Pad2)") + (net 6 "unconnected-(R4-Pad2)") + (net 7 "unconnected-(R5-Pad1)") + (net 8 "Net-(R5-Pad2)") + (net 9 "unconnected-(R6-Pad2)") + (net 10 "Net-(R7-Pad2)") + (net 11 "unconnected-(R7-Pad1)") + (net 12 "unconnected-(R8-Pad2)") + (net 13 "Net-(R10-Pad1)") + (net 14 "unconnected-(R9-Pad1)") + (net 15 "unconnected-(R10-Pad2)") + (net 16 "unconnected-(R11-Pad1)") + (net 17 "Net-(R11-Pad2)") + (net 18 "unconnected-(R12-Pad2)") + (net 19 "/NET_P") + (net 20 "unconnected-(R13-Pad1)") + (net 21 "unconnected-(R14-Pad2)") + (net 22 "unconnected-(R15-Pad1)") + (net 23 "/NET_N") + (net 24 "unconnected-(R16-Pad2)") + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "07a65da0-841b-4ca6-b31f-c05ba846e5f6") + (at 125.4525 38.735) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R2" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "64ed7328-67c3-46d4-bd0a-822451148257") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "2516a519-81d4-417b-8c34-4e845bf6c8d0") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "fc51b18a-4f9d-42d2-bb58-e17ae5845716") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "44873712-fdc9-408d-ba08-d8ef2bf367c8") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/6fbf107e-be60-47e6-b3af-13ccfc680d26") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "cdc4c49a-508b-4b2d-ac6e-8194fefa8e9d") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "f6273013-dc9c-438f-ab08-3780fce4e95d") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "dd9bc2b9-f6a7-46a6-b29f-dadc080ab752") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "9a4542b9-58d9-4763-bf9b-34660cdf19ea") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "172c9798-3e52-48b3-b7e4-fa43e842a52b") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "90e59640-cf2b-4d8f-879d-ab998fc9788b") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "b9051426-13cd-45c1-b819-2f922b9c92d8") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "07b50eae-4831-443e-9f70-7a9ebd60ec70") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "204cf6a1-78c0-4c33-9ef5-cffe28b2d7eb") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "a3e2e130-a7e1-4358-9f84-eb4c22d24f3a") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "1738a30d-dc48-4744-b02a-f07e110bbc6c") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 1 "Net-(R1-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "e73d4e75-1020-4293-8436-5f5290c049e3") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 3 "unconnected-(R2-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "231f216b-d86f-4565-b823-20847cfaa6c0") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "2bb4b78b-fd4a-4232-833e-f0bd01a1b68c") + (at 125.3725 50.8) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R4" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "1bf80261-702b-4fde-a710-2a49043f0842") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "1cf5d6f0-6b42-4160-93a0-55775cb7f085") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "890f1a9c-7572-4b81-a5db-2033a897dd48") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "3deef047-311d-4b85-8de5-dec29f592239") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/11f32aaf-4471-4688-b819-7a6001f94544") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "1be63f31-c1a6-48d3-bd86-4e30f94c00e1") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "a915e7a3-ab68-4ced-ae67-e1bf7ff0efd8") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "580d6649-b2fc-4d58-8a8c-c1864ed7f964") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "7130c72b-5350-4aff-9a81-4793c4f413f5") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "895b123c-333a-4782-9966-8a899994a770") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "a52b25b1-f083-4d12-b225-639be9753dff") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "c59f71f7-9c26-4964-be2b-b5c43adb1d98") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "4afe4e2e-ceec-44ef-aa54-8c9a4563c115") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "f9e706b0-85bf-4103-89da-22f0c9a3fb1b") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "4b258bd3-c910-4542-b5ee-94303eb665d1") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "84e0effb-31d9-45fb-8e53-42ad040114ec") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 5 "Net-(R3-Pad2)") + (pintype "passive") + (die_delay 20) + (tenting + (front none) + (back none) + ) + (uuid "b5d52e92-100b-491c-b429-b3c8e546b0e2") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 6 "unconnected-(R4-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "949dd946-0a32-417f-96f0-5771c4225710") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "46a18f23-82e4-481c-98c4-e13577069ffc") + (at 125.3725 94.615) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R14" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "878b7f40-1d34-4912-9c85-70f9e152cb6f") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "94cdc971-1a5b-4a1c-b0c9-f26e45db5f4c") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "3a22a233-5b29-4d92-b404-5a50eb9f778d") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "92ae1638-b86e-410d-8c3d-ffc8b199e629") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/84a7f85b-ceaf-4a2a-936e-23c469bd67b5") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "cf8b33ec-4a04-4333-8757-90ef9735fc85") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "1dcf82c5-7c0c-4404-b479-a24cabe38ffa") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "d77fffde-4d81-454e-89b7-4ae5943c4f4e") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "62e2056f-4b4a-475c-bf2f-892a11edff95") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "7697394e-cbcf-402d-8baf-a9c3002658ea") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "d7c8b404-860e-4e4d-bdda-47fe7acc5a88") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "4f0e83cb-f9f4-40e8-9274-82baa998687f") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "2cb44147-9961-44b2-9b01-c4bd8cda24a6") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "02671bd3-1c17-466c-8762-f3d5383635f7") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "f24997c1-67a9-445d-b40d-3d3d57072905") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "e3d22579-3106-413d-8f20-5b8174c672e2") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 19 "/NET_P") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "32ab06f4-853d-42bc-a84e-2ed2ac31ae79") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 21 "unconnected-(R14-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "11a828e0-f58f-4299-9e74-c36cf604e06d") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "5e172951-7655-4e84-85f1-b584ecff7923") + (at 93.7025 69.85) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R7" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "a8562d8e-77f9-4631-84b0-a8ebc9282eb1") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "7076c673-f6e3-4120-addc-adce815b3c94") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "348d975a-52a8-4246-bb04-e01c010f5d0d") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "c66005f1-be24-4fb6-bf17-f07f17391a39") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/168987aa-5d0f-457d-a473-1c6864d7e9ca") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "9d6d755e-068f-4086-9b87-668be2bee45e") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "a08b2d6b-738f-4352-ab2a-988016dc2e4a") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "5688f46d-c472-4875-bec0-20040886ee6a") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "95477e75-943e-433a-93bd-b780008c2c7c") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "0ca0ce81-708b-4ca3-8656-0f044c674d78") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "7fd33198-73f3-4770-a47f-2b95d7f2f8fa") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "a37d9453-90c0-4adb-aee5-232557fd47fd") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "58945fb8-40fa-46ff-a85a-3f6b1cf847dd") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "ef09b2a1-8865-4bec-b3cb-cd9e81ad43c4") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "a5606bcc-3200-402d-8378-57b4107ac6b6") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "3cb2686a-3702-4a37-85cf-3688cffb7586") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 11 "unconnected-(R7-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "f07f84ce-0793-45c5-85d5-798cbd696299") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 10 "Net-(R7-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "4191ed4c-578a-4ba1-a95f-99f6e9a55490") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "76d418ff-1997-4594-af73-1bad9484964c") + (at 93.7025 99.06) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R15" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "86472a70-b3e1-4ffa-b160-f796d0f29475") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "5364a128-6cd0-40f7-ba1b-4dd0ef1f41e5") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "0dd7e4e7-aebe-4751-b9a9-93b0ef89dbf1") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "ab1f946e-069a-4fa0-8fe8-df5499d1d764") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/894b92c4-9393-47f8-9936-c23b4fded612") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "a3e1c58e-c00a-4909-b857-09b8f478c3da") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "4f7ea41c-9443-4709-a267-a4f762e063e5") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "8d3b7443-e643-4744-871a-97818ee7410a") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "73717e47-a70c-4807-9b85-dafb532fe7e4") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "7f0d24d0-3042-4847-bab4-8d23aeac77a3") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "917d6bba-7ed2-4d20-a1f0-0d8b8627b9e5") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "b0acdfea-353e-4517-94fb-8295da6a17c5") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "ad0b8f3a-e38c-4fe1-92a2-695de06e3174") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "2ec8e6da-fbd2-44d4-bfa6-4270bf198677") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "ddf06bf7-5b16-486b-94ba-922dfc81848c") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "6487c66c-3c54-4a45-95bc-560c6f26d996") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 22 "unconnected-(R15-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "c47f5d0b-0774-4e29-ab66-d2c86c6cd7a7") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 23 "/NET_N") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "f9c89945-522d-4198-b29a-74fb5591217a") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "8770d458-7a54-4e75-af5c-db16d1858ace") + (at 121.0075 99.06) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R16" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "47ac3ae1-2c9d-4867-a1f8-8a61d4e8d8f4") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "83e01a00-f3c6-49ca-8cfb-f28422842e9a") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "279206b4-1a01-47f3-b580-62a38460634a") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "4942a2a8-309f-44a0-b88a-06f6864a4f68") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/b72e4e4c-09df-4511-92a1-90d7e7d528c9") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "440b1828-73a6-488c-8503-1124da37a4bc") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "9660f378-a3ef-4195-a41e-a0062ac8c85e") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "bc654f1b-83ec-466e-882c-28174af78b3f") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "fb146768-a630-44b6-a74d-26d887630a20") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "54f4f49b-147c-4fc5-8337-5b9669c29a4c") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "f6f59603-fde5-4b0b-8b8b-6f94eaefae77") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "384a4ad8-b67c-4cf6-9ef6-52319d666bf2") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "6818d36d-cf55-4153-82db-94ba5e784c6c") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "916d92b1-7d3e-45e2-8f30-f4ed318b2705") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "8429fe99-7b84-4eac-8e5e-8ea397ddd529") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "9b8554b8-77b0-4b13-ba6c-f2f129c63e74") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 23 "/NET_N") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "5b4e78d8-43e7-409f-b548-e64ac1f21183") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 24 "unconnected-(R16-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "75b6372c-2575-466a-9d24-249a0b51ec3e") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "90a88b68-e68c-42ab-849a-754ed85edb12") + (at 125.3725 89.535) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R12" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "7a544f2f-ae89-47cf-898f-e5ccf12ffa8b") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "6052612d-ccab-402e-ad75-391a22530f2b") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "d8f80294-fad2-4772-a572-7ebc3dee370a") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "b3983b10-0a45-485c-9fa3-27fc6b302cb6") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/f166b6a8-fae7-4ec1-a997-d85f78ee8409") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "cb440079-169c-4c23-abae-5c26be4c72c9") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "2761ea02-2dd7-49b8-9e9e-86dd9a5a438e") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "e7a5e93a-b799-4a16-a8ec-60870369f5a0") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "02faebdc-314e-4009-b92a-9769967acfc8") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "4e4fd2ca-ba73-4506-b2d7-e2ea17ff75b1") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "df61ba0b-7594-4a70-8bab-f307ea578afb") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "58a886c6-103e-42f9-a201-7837857a107d") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "eabdcaaf-b3fb-466b-ab7d-6838b53bf08f") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "38d152d0-7661-4659-b464-abb8ad39c847") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "7e99e9ad-b6a7-4aab-a8a0-6c1c9f5a2e9c") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "b1002e08-f00a-4c9c-869b-e831089c5049") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 17 "Net-(R11-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "2ba1f667-e94a-4887-bd17-d622e7827ffc") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 18 "unconnected-(R12-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "5d9dfeac-a249-4a55-a97b-b1f07c728b4a") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "9eea77ca-0d16-4444-aa6a-f69e53dc11f2") + (at 93.7025 94.615) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R13" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "5996a7dc-8e59-46b4-9512-3c3cf1f259cb") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "5f4a852b-d26c-4727-b0ee-8f7484b0df47") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "45ba9fe8-738c-45bb-ba38-e63c2b94394f") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "a1b761bf-52c9-4586-923d-86a57d9dfd9d") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/8060d6fb-9102-4c21-b7d3-dd6202aae313") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "3c94e3d5-771c-47d2-a753-92540e1d0443") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "c9361c5d-ff12-4d0a-84ef-caf28afbe58f") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "15f29ad4-347f-4517-a3eb-d0183813df05") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "d5d2b768-6186-4ded-a8c5-0e95f185fdab") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "0d9b478b-faca-48c1-b8a6-29cf324fa6f8") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "bccc358c-fac8-4060-8a9c-69410c9281db") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "5e5aa8ba-184e-403e-b0da-d515a526e3b9") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "c2f754b7-5b9b-424b-9eb0-646cc72bdd32") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "b9264379-4d78-43d4-9563-a741a3ee5568") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "0d561c65-01f5-4ac2-a73d-f204017f411e") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "dc4c5554-08ca-44f9-b132-c611ed0b4ec7") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 20 "unconnected-(R13-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "f1ba1cb3-5d05-4a20-b05c-1492d0d73796") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 19 "/NET_P") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "2fcf5f6c-3ad6-4049-adaf-ec8e11868604") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "a13a2b16-dcbe-45f1-accf-38c3fb687c6a") + (at 93.7825 38.735) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R1" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "5ebbfd78-eade-4eef-9518-8186f025389e") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "382a6923-268a-4fe9-9be4-c88665b15c93") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "b552621c-b1f4-4b0a-ac20-21f5a589cfcf") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "425a7307-8ea9-4eca-ac18-6a9bab64992d") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/74b5797b-ca1a-4357-aad5-352d7c3455c9") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "8eb0ffa8-71e1-488a-9152-b624d08f7b2b") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "1c66919c-8bdb-4f53-8843-b40d4541abc8") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "cdb479ee-02e6-4b40-b9e6-42f3a2011497") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "7bada3b6-b59a-4fed-a748-f6858b823022") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "350e870f-3308-41ad-a3ea-9887ea2d2057") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "9409b882-ac1b-40d0-935e-38c0bbc407c8") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "33f4d62f-80ff-49a2-929f-281d9d9078ed") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "23201bef-2b04-40cc-8f2e-301c2735ab3a") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "0617b5bd-f088-4571-97c1-1533ed3be4d7") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "abb3c22f-f6fd-4825-962c-c08ac38bfbda") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "81be0bcd-31ba-43f9-89eb-4b42b0b879af") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 2 "unconnected-(R1-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "f2a4917f-793a-431e-a8c8-be8dd38ff5a7") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 1 "Net-(R1-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "e24f2823-680d-4186-afd6-054ce690be7f") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "b88c289f-b379-4a3c-af34-99e4a502180d") + (at 93.7025 50.8) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R3" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "4d945606-38e1-41f4-9016-e16ca3d878f2") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "7a9332ef-852a-4d0f-b146-e1438d0cac47") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "a7869d88-be6a-4cdd-8252-f5a1f5065f9e") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "d4806857-4613-453e-b03d-ec5dc4d560ff") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/fa889142-62ae-4e55-99fe-de19adfd6f6a") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "72182018-1db2-4c5d-b02a-ee169f4a68b1") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "582ec2f7-1bf8-4d02-838c-cf36400b1ff5") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "b50648fd-495c-4c20-a643-b954fc5f9bc3") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "73533b41-8284-48bd-aba5-3d7c7ca4c9d1") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "fdefa027-915e-42f7-9dec-67046502e387") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "5842e4d5-e986-4ae9-afe3-00c59332dc96") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "7bfde94d-ad2e-4db0-8236-5bb7c2e7ee02") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "aa8a9ff7-e0fb-4742-b55f-5139d405752b") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "35cc51ff-b0b4-47a0-850e-0cef877b76c4") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "659e69ac-3339-4cdf-8b15-b12f8700b3bb") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "5b5bf587-2f7a-4b30-86c2-b6bb2250d8d4") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 4 "unconnected-(R3-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "1f4b107d-ea00-449e-907c-5977fd012b0a") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 5 "Net-(R3-Pad2)") + (pintype "passive") + (die_delay 10) + (tenting + (front none) + (back none) + ) + (uuid "caaf5508-eea7-447e-9e58-bc0f75b8d259") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "f07a3057-4b2c-4c58-87bd-d0334bac6b53") + (at 93.7025 80.01) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R9" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "02ebc12b-94ac-4066-bd8d-0ad8830fef30") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "ead0ef2b-bc21-4760-8052-8784d881eadf") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "fab69c63-5f1d-464e-8947-fb8f9adee86d") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "8e8adfa6-e543-4786-8135-63d7e8307c90") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/6e1874b7-85b2-449a-8f06-c2f8c3e2df6f") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "97b6fdae-cadb-4df0-8903-474e1dff6782") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "3b91fd02-5d47-4777-a02c-d96bdc0c764d") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "c0df2ebc-248d-406f-9aef-92df9a87a41f") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "1e00603b-49bf-4316-a383-8f374a3b94fb") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "1e1641d5-8386-4159-a2ab-d3c012e3021a") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "a4be29e8-5b9a-40b8-800b-6445fb27bd4e") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "105c2803-cd43-4392-bf1e-e5b54e3e7894") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "8f66f046-a8d0-4e0e-b800-c2c47e13dfca") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "35362978-4644-483b-ab27-443fc6411b1a") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "07d3874d-31e6-4c3a-9ec1-470a64ed2ae1") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "7e97037c-231c-48d3-994e-139046796ddb") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 14 "unconnected-(R9-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "f932077a-c0cd-4c79-b344-efbc321401ee") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 13 "Net-(R10-Pad1)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "6900cc01-7a49-4135-a675-b0b7c0ae18b3") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "F.Cu") + (uuid "f613fe6f-ecfc-45d3-b725-f9981652142c") + (at 93.7025 89.535) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R11" + (at 0 -1.65 0) + (layer "F.SilkS") + (uuid "d88fdfed-a4b5-4a31-981b-c2c18a22ded3") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Value" "R" + (at 0 1.65 0) + (layer "F.Fab") + (uuid "34144c6d-08b6-43c2-b348-dbf08e5e9814") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "3bd5730b-7a6b-4cf4-9bb7-f136f253fd73") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "F.Fab") + (hide yes) + (uuid "f28ef42c-57bd-476c-96b0-0a9f118ffef7") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + ) + ) + (property ki_fp_filters "R_*") + (path "/990dfaf0-bb9f-4ae9-bddb-3fef171bf3b0") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "d8967461-4fa1-4741-bd13-46c13703d482") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "F.SilkS") + (uuid "bd6c0022-85e3-4eca-adec-be65ad5e7517") + ) + (fp_line + (start -1.68 -0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "3c33e7df-56e1-4a43-a97c-4823e7120dd2") + ) + (fp_line + (start -1.68 0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "8f3b6eea-abbd-49ac-a909-2618b0fc4561") + ) + (fp_line + (start 1.68 -0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "37f576db-119e-41c9-878e-8dc7d6b43f37") + ) + (fp_line + (start 1.68 0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "F.CrtYd") + (uuid "7f2e15cf-c993-4fd0-83d9-ec6a8f0f71d4") + ) + (fp_line + (start -1 -0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "cb31a0bc-473a-48f4-8f2a-8b5671798e5b") + ) + (fp_line + (start -1 0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "1a0dc971-e366-4bda-9b22-f32c94b7baef") + ) + (fp_line + (start 1 -0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "39f330d9-6c73-4249-b98d-575bd1bc0fae") + ) + (fp_line + (start 1 0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "F.Fab") + (uuid "fca2f5e5-e331-48aa-bdc4-e76841e6bf13") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "F.Fab") + (uuid "c166877c-1e2f-4f7e-971a-ee90e6b45640") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 16 "unconnected-(R11-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "6d2036b3-81f4-4718-ace3-bc82005ff9e7") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "F.Cu" "F.Mask" "F.Paste") + (roundrect_rratio 0.243902) + (net 17 "Net-(R11-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "6e2bdc4c-07dd-4403-bcc1-5bfaa70f36e2") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "B.Cu") + (uuid "25ebac99-c694-46b0-bda6-6c69817633a3") + (at 125.3725 62.23 180) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R5" + (at 0 1.65 0) + (layer "B.SilkS") + (uuid "5ccb4642-58fc-450e-af9a-be443bea7a25") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Value" "R" + (at 0 -1.65 0) + (layer "B.Fab") + (uuid "aa33bf69-01ae-421c-8f38-af6ac0bcd580") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "B.Fab") + (hide yes) + (uuid "2571c191-de03-4923-a01a-6ac500f605df") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "B.Fab") + (hide yes) + (uuid "55529023-af7a-450a-8a87-9c62a2fcdddc") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property ki_fp_filters "R_*") + (path "/0015c052-25a6-474f-8dee-c00a6ecfdabf") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "B.SilkS") + (uuid "57919d0e-a132-4077-83f5-46c8d359661f") + ) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "B.SilkS") + (uuid "5bd4c527-ebf5-4d5b-8ba2-f4a9d353de2c") + ) + (fp_line + (start 1.68 0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "4108d9ca-c2f6-460e-8531-22ee22e8256b") + ) + (fp_line + (start 1.68 -0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "89bd2be2-eec3-4d5e-b5d5-bc0e51fd0e0f") + ) + (fp_line + (start -1.68 0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "11717003-f7c7-4ab2-8937-76ab0eab7ec6") + ) + (fp_line + (start -1.68 -0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "cb96975e-43b5-4cb4-938b-0a0a442a75bd") + ) + (fp_line + (start 1 0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "df38df4d-2ee9-4558-9168-a1ca989ead79") + ) + (fp_line + (start 1 -0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "e2bb0451-93e8-48c3-8d6d-cfa29fd4c248") + ) + (fp_line + (start -1 0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "3c7c4fa7-44fd-4f19-a851-5958179c6b97") + ) + (fp_line + (start -1 -0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "f4ba9c03-6a97-4b9f-8b25-c5972dc8b4a1") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "B.Fab") + (uuid "d383ec45-8c4c-494a-9d26-f68079e2a6cd") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + (justify mirror) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0 180) + (size 1.025 1.4) + (layers "B.Cu" "B.Mask" "B.Paste") + (roundrect_rratio 0.243902) + (net 7 "unconnected-(R5-Pad1)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "2355ab5b-8cca-4eb9-8cb3-74af3ef670d4") + ) + (pad "2" smd roundrect + (at 0.9125 0 180) + (size 1.025 1.4) + (layers "B.Cu" "B.Mask" "B.Paste") + (roundrect_rratio 0.243902) + (net 8 "Net-(R5-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "cf6b59b1-a43f-4078-9a9e-decc8fad41d5") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "B.Cu") + (uuid "40df7022-3926-4ba2-9ad1-f97ceb0072e9") + (at 93.7025 62.23 180) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R6" + (at 0 1.65 0) + (layer "B.SilkS") + (uuid "4ecea55b-98e3-451b-8eaf-89610f515fa4") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Value" "R" + (at 0 -1.65 0) + (layer "B.Fab") + (uuid "0324ab46-e863-46ca-b05f-073f9be35086") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "B.Fab") + (hide yes) + (uuid "52405afc-aa12-4a17-9116-6d07b8aef6ec") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "B.Fab") + (hide yes) + (uuid "03405811-50e1-4d2d-bf98-fb3dd4e95b90") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property ki_fp_filters "R_*") + (path "/e64fc1c9-1692-4c47-a21c-463ae8673dad") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "B.SilkS") + (uuid "bc31fd3e-4bc2-416a-b110-59f7c83f4c74") + ) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "B.SilkS") + (uuid "02d9ea0b-01b1-418c-8398-61a837849a99") + ) + (fp_line + (start 1.68 0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "8f524738-96ef-47c4-93fb-2b14e1ca8d9c") + ) + (fp_line + (start 1.68 -0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "3ba57a09-5f6b-44d2-8646-2aa4ff425d72") + ) + (fp_line + (start -1.68 0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "3b8329a7-e9a3-4b4d-941b-0ea9fbd7f1ea") + ) + (fp_line + (start -1.68 -0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "25ba1411-58a3-4c25-8618-61104eeecac5") + ) + (fp_line + (start 1 0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "e96fa334-cfab-460e-99f2-6960882f400d") + ) + (fp_line + (start 1 -0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "78edfef1-a31b-4ea8-bddd-b582ba52d47a") + ) + (fp_line + (start -1 0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "2c5d765e-066a-4b4b-beed-b77d592bffe2") + ) + (fp_line + (start -1 -0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "bd6f5ce7-c9ab-4a0e-be40-5d009cba1d68") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "B.Fab") + (uuid "59cf290b-db5b-471e-8fec-fbbd3a3bc579") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + (justify mirror) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0 180) + (size 1.025 1.4) + (layers "B.Cu" "B.Mask" "B.Paste") + (roundrect_rratio 0.243902) + (net 8 "Net-(R5-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "d27051d8-75bd-4f11-898c-86edfee22533") + ) + (pad "2" smd roundrect + (at 0.9125 0 180) + (size 1.025 1.4) + (layers "B.Cu" "B.Mask" "B.Paste") + (roundrect_rratio 0.243902) + (net 9 "unconnected-(R6-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "f4c81575-56d4-4e2b-a2d6-9382b28c7c3d") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "B.Cu") + (uuid "dbbb8cf7-015a-45f8-8aac-b7c64e43f23c") + (at 125.3725 80.01) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R10" + (at 0 1.65 0) + (layer "B.SilkS") + (uuid "27d5c831-6460-43f3-956b-2b20a7aa3814") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Value" "R" + (at 0 -1.65 0) + (layer "B.Fab") + (uuid "159072c6-36b1-493e-b3c3-079c20223dde") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "B.Fab") + (hide yes) + (uuid "8aedb47c-17f0-4a0c-86cc-14d923ac06a4") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "B.Fab") + (hide yes) + (uuid "ec0e21ba-da83-4b37-8dc5-7d0a7e328275") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property ki_fp_filters "R_*") + (path "/62d70245-08ec-4619-afe3-9bcfe9345a0b") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "B.SilkS") + (uuid "8d789c2b-aed7-4cb5-8d78-bc572e43f279") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "B.SilkS") + (uuid "b0bca64b-d43a-4d8f-85e8-bb0aef08a0c6") + ) + (fp_line + (start -1.68 -0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "523a4da3-7332-4b6b-9f5b-a79f62bddab0") + ) + (fp_line + (start -1.68 0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "ec499ca6-a4d2-4cfa-afbd-0edc81c2ce71") + ) + (fp_line + (start 1.68 -0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "82654578-e030-4a69-a4d6-8f60f1346970") + ) + (fp_line + (start 1.68 0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "26a47fc7-5914-446b-b49e-af61d9d10a85") + ) + (fp_line + (start -1 -0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "5341178d-4bde-4843-9f6c-7905d10d0b97") + ) + (fp_line + (start -1 0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "209aea26-2956-4e26-86c9-4cea398cda89") + ) + (fp_line + (start 1 -0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "e7060ba1-db94-4172-9db9-42835ac8d3bd") + ) + (fp_line + (start 1 0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "cb7886bb-8653-4652-8366-796d9d068968") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "B.Fab") + (uuid "3f8b4f8e-a4d6-4458-8e52-f94a98426221") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + (justify mirror) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "B.Cu" "B.Mask" "B.Paste") + (roundrect_rratio 0.243902) + (net 13 "Net-(R10-Pad1)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "695c473e-13d7-44b8-bc3e-0b0493465cf1") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "B.Cu" "B.Mask" "B.Paste") + (roundrect_rratio 0.243902) + (net 15 "unconnected-(R10-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "f84e789b-848d-4756-9b51-a854abec11b3") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (footprint "Resistor_SMD:R_0805_2012Metric" + (layer "B.Cu") + (uuid "eda4b152-7cbe-42aa-bc00-689c3ccdc9f1") + (at 125.3725 69.85) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC-7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags "resistor") + (property "Reference" "R8" + (at 0 1.65 0) + (layer "B.SilkS") + (uuid "89c0ff94-f703-4d37-9362-6ba8c11e5219") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Value" "R" + (at 0 -1.65 0) + (layer "B.Fab") + (uuid "37d6ea59-25b7-4ca8-9a08-3929b195e2a9") + (effects + (font + (size 1 1) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (layer "B.Fab") + (hide yes) + (uuid "d1acdf12-d829-4ba1-a5b7-7e32c75ab0d1") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (layer "B.Fab") + (hide yes) + (uuid "8704185b-442f-4a96-9dea-b5ba66ba71ff") + (effects + (font + (size 1.27 1.27) + (thickness 0.15) + ) + (justify mirror) + ) + ) + (property ki_fp_filters "R_*") + (path "/627a2ba8-c0b3-49e0-809e-90174b458fee") + (sheetname "/") + (sheetfile "time_calculations.kicad_sch") + (attr smd) + (duplicate_pad_numbers_are_jumpers no) + (fp_line + (start -0.227064 -0.735) + (end 0.227064 -0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "B.SilkS") + (uuid "46e48734-0ceb-46d9-a05c-8b55bd648757") + ) + (fp_line + (start -0.227064 0.735) + (end 0.227064 0.735) + (stroke + (width 0.12) + (type solid) + ) + (layer "B.SilkS") + (uuid "4c40f6ab-b774-43f9-82d0-2d0855114227") + ) + (fp_line + (start -1.68 -0.95) + (end -1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "2cb95543-89d1-4dc1-9be0-c65d1b5e6939") + ) + (fp_line + (start -1.68 0.95) + (end 1.68 0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "fce30c2e-4631-40cb-9c21-286d851c8f5d") + ) + (fp_line + (start 1.68 -0.95) + (end -1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "2bd46d82-8890-42ec-827a-f6273f510f21") + ) + (fp_line + (start 1.68 0.95) + (end 1.68 -0.95) + (stroke + (width 0.05) + (type solid) + ) + (layer "B.CrtYd") + (uuid "a6cf7571-beae-43f6-a0d2-c6eaf3eb94dd") + ) + (fp_line + (start -1 -0.625) + (end -1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "77bbbfd6-3044-40cc-97d7-d137de1d83d5") + ) + (fp_line + (start -1 0.625) + (end 1 0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "a3eb91e5-5552-45d3-8f07-40235b431275") + ) + (fp_line + (start 1 -0.625) + (end -1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "6132ca81-9955-4197-aaf3-aab30b94bcbd") + ) + (fp_line + (start 1 0.625) + (end 1 -0.625) + (stroke + (width 0.1) + (type solid) + ) + (layer "B.Fab") + (uuid "189a97e3-1054-4c95-94b7-d359d87c5d6c") + ) + (fp_text user "${REFERENCE}" + (at 0 0 0) + (layer "B.Fab") + (uuid "a1bbec8f-c5ff-4a98-8cae-df1e88080aa1") + (effects + (font + (size 0.5 0.5) + (thickness 0.08) + ) + (justify mirror) + ) + ) + (pad "1" smd roundrect + (at -0.9125 0) + (size 1.025 1.4) + (layers "B.Cu" "B.Mask" "B.Paste") + (roundrect_rratio 0.243902) + (net 10 "Net-(R7-Pad2)") + (pintype "passive") + (tenting + (front none) + (back none) + ) + (uuid "9e4bcee5-a714-417b-a3fc-e27223f15409") + ) + (pad "2" smd roundrect + (at 0.9125 0) + (size 1.025 1.4) + (layers "B.Cu" "B.Mask" "B.Paste") + (roundrect_rratio 0.243902) + (net 12 "unconnected-(R8-Pad2)") + (pintype "passive+no_connect") + (tenting + (front none) + (back none) + ) + (uuid "ee1e42d5-c1da-4ee8-9981-3741c9c486ae") + ) + (embedded_fonts no) + (model "${KICAD9_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl" + (offset + (xyz 0 0 0) + ) + (scale + (xyz 1 1 1) + ) + (rotate + (xyz 0 0 0) + ) + ) + ) + (gr_rect + (start 83.82 27.305) + (end 165.735 112.395) + (stroke + (width 0.05) + (type default) + ) + (fill no) + (layer "Edge.Cuts") + (uuid "5cdd295f-9add-4b28-b341-54a71605c461") + ) + (gr_text "Simple track, no pad-to-die delay\nT = 59.69ps" + (at 128.905 63.5 0) + (layer "User.1") + (uuid "172824b2-7c57-4538-81d1-13862455918b") + (effects + (font + (size 1 1) + (thickness 0.2) + (bold yes) + ) + (justify left bottom) + ) + ) + (gr_text "Two layer track + via\nT = 31.39ps" + (at 128.905 71.12 0) + (layer "User.1") + (uuid "2942d426-2cfc-4054-86e6-b3cc0ace1bbc") + (effects + (font + (size 1 1) + (thickness 0.2) + (bold yes) + ) + (justify left bottom) + ) + ) + (gr_text "Simple track\nT_P = 31.50ps\nT_N = 27.05ps\nSkew = 4.45ps" + (at 128.905 99.695 0) + (layer "User.1") + (uuid "683d84ce-bf0f-4eef-8b51-75bb3f39bd82") + (effects + (font + (size 1 1) + (thickness 0.2) + (bold yes) + ) + (justify left bottom) + ) + ) + (gr_text "Simple track, with pad-to-die delay\nT = 59.84ps" + (at 128.905 52.07 0) + (layer "User.1") + (uuid "a3614c8a-990b-4c54-a82d-d54907d9ef67") + (effects + (font + (size 1 1) + (thickness 0.2) + (bold yes) + ) + (justify left bottom) + ) + ) + (gr_text "Two layer track + micro-via overrides\nT = 75.72ps" + (at 128.905 90.805 0) + (layer "User.1") + (uuid "bd39c7e5-1a0d-4c9d-9c8f-398927319889") + (effects + (font + (size 1 1) + (thickness 0.2) + (bold yes) + ) + (justify left bottom) + ) + ) + (gr_text "Two layer track + via override\nT = 49.84ps" + (at 128.905 81.28 0) + (layer "User.1") + (uuid "d474afc2-1efd-4e5b-bc96-4927bdfed1ae") + (effects + (font + (size 1 1) + (thickness 0.2) + (bold yes) + ) + (justify left bottom) + ) + ) + (gr_text "Simple track, no pad-to-die delay\nT = 29.84ps" + (at 128.905 40.005 0) + (layer "User.1") + (uuid "dd06e931-0109-4a49-858c-578a8196e7e9") + (effects + (font + (size 1 1) + (thickness 0.2) + (bold yes) + ) + (justify left bottom) + ) + ) + (segment + (start 94.695 38.735) + (end 124.54 38.735) + (width 0.2) + (layer "F.Cu") + (net 1) + (uuid "fe7d2a54-ac71-4691-9e81-702df896b756") + ) + (segment + (start 94.615 50.8) + (end 124.46 50.8) + (width 0.2) + (layer "F.Cu") + (net 5) + (uuid "e911a5fa-1186-4edc-b140-f1947feb68f3") + ) + (segment + (start 124.46 62.23) + (end 94.615 62.23) + (width 0.2) + (layer "B.Cu") + (net 8) + (uuid "25625c65-64c7-4d24-b0e2-b536ed1c0e27") + ) + (segment + (start 94.615 69.85) + (end 107.95 69.85) + (width 0.2) + (layer "F.Cu") + (net 10) + (uuid "18471454-8aba-4c16-9a80-82a2da0b2e6f") + ) + (via + (at 107.95 69.85) + (size 0.6) + (drill 0.3) + (layers "F.Cu" "B.Cu") + (tenting + (front none) + (back none) + ) + (capping none) + (covering + (front none) + (back none) + ) + (plugging + (front none) + (back none) + ) + (filling none) + (net 10) + (uuid "a6edf592-8787-4875-aae3-3facd70b6d5e") + ) + (segment + (start 107.95 69.85) + (end 124.46 69.85) + (width 0.2) + (layer "B.Cu") + (net 10) + (uuid "1cc8d7d5-7124-4961-be70-cbd1d8931bdf") + ) + (segment + (start 94.615 80.01) + (end 107.95 80.01) + (width 0.2) + (layer "F.Cu") + (net 13) + (uuid "021819c4-1dad-4480-a9b6-51a5b9044c8c") + ) + (via + (at 107.95 80.01) + (size 0.6) + (drill 0.3) + (layers "F.Cu" "B.Cu") + (tenting + (front none) + (back none) + ) + (capping none) + (covering + (front none) + (back none) + ) + (plugging + (front none) + (back none) + ) + (filling none) + (net 13) + (uuid "7077c1cd-9477-49df-8489-ee8b4d622f08") + ) + (segment + (start 107.95 80.01) + (end 124.46 80.01) + (width 0.2) + (layer "B.Cu") + (net 13) + (uuid "67ed6837-01de-4805-9d43-6a9c5cc6c4fb") + ) + (segment + (start 94.615 89.535) + (end 101.6 89.535) + (width 0.2) + (layer "F.Cu") + (net 17) + (uuid "d4a26612-9d59-475e-9b93-c0ce887e733c") + ) + (segment + (start 117.475 89.535) + (end 124.46 89.535) + (width 0.2) + (layer "F.Cu") + (net 17) + (uuid "d8b5c676-0705-49c4-8203-73f26f6ee636") + ) + (via micro + (at 101.6 89.535) + (size 0.6) + (drill 0.3) + (layers "F.Cu" "In1.Cu") + (tenting + (front none) + (back none) + ) + (capping none) + (covering + (front none) + (back none) + ) + (plugging + (front none) + (back none) + ) + (filling none) + (net 17) + (uuid "0707a21a-52b5-43cf-ae60-9302a91ec8bb") + ) + (via micro + (at 117.475 89.535) + (size 0.6) + (drill 0.3) + (layers "F.Cu" "In2.Cu") + (tenting + (front none) + (back none) + ) + (capping none) + (covering + (front none) + (back none) + ) + (plugging + (front none) + (back none) + ) + (filling none) + (net 17) + (uuid "49c84dbe-3364-4e42-8aba-ab4d7678673f") + ) + (segment + (start 101.6 89.535) + (end 117.475 89.535) + (width 0.2) + (layer "In1.Cu") + (net 17) + (uuid "ac409195-5ab3-4123-9dae-39f1971d8777") + ) + (segment + (start 94.615 94.615) + (end 95.665001 94.615) + (width 0.2) + (layer "F.Cu") + (net 19) + (uuid "499e9b0d-972e-4ebd-90a0-faa024ee966e") + ) + (segment + (start 95.665001 94.615) + (end 97.662501 96.6125) + (width 0.2) + (layer "F.Cu") + (net 19) + (uuid "4eb1eaaf-25bb-4a9b-aca9-f67aee914114") + ) + (segment + (start 120.65 94.615) + (end 124.46 94.615) + (width 0.2) + (layer "F.Cu") + (net 19) + (uuid "822c55c6-eaea-4d1d-8f67-b0e9e32993e7") + ) + (segment + (start 97.662501 96.6125) + (end 118.6525 96.6125) + (width 0.2) + (layer "F.Cu") + (net 19) + (uuid "859b2dec-3989-4f94-acbe-cf8835de01ba") + ) + (segment + (start 118.6525 96.6125) + (end 120.65 94.615) + (width 0.2) + (layer "F.Cu") + (net 19) + (uuid "a7e39f74-99aa-43c8-b7d0-d68d9e421e28") + ) + (segment + (start 95.665001 99.06) + (end 97.662501 97.0625) + (width 0.2) + (layer "F.Cu") + (net 23) + (uuid "542b75e5-f0fe-480d-bd9c-0061f32327e2") + ) + (segment + (start 120.015 99.06) + (end 117.978198 99.06) + (width 0.2) + (layer "F.Cu") + (net 23) + (uuid "73f23862-9a4e-48e7-af8b-3c26a0413d97") + ) + (segment + (start 94.615 99.06) + (end 95.665001 99.06) + (width 0.2) + (layer "F.Cu") + (net 23) + (uuid "c16bf28b-2cc1-4182-abcd-8c04369864e8") + ) + (segment + (start 97.662501 97.0625) + (end 115.980698 97.0625) + (width 0.2) + (layer "F.Cu") + (net 23) + (uuid "db1070d2-40b4-4f2a-9b2e-58b59b754bb6") + ) + (segment + (start 117.978198 99.06) + (end 115.980698 97.0625) + (width 0.2) + (layer "F.Cu") + (net 23) + (uuid "f294e0cd-51e9-4263-83a0-65ee6d65b842") + ) + (embedded_fonts no) +) diff --git a/qa/data/pcbnew/time_calculations.kicad_pro b/qa/data/pcbnew/time_calculations.kicad_pro new file mode 100644 index 0000000000..97b8ee9485 --- /dev/null +++ b/qa/data/pcbnew/time_calculations.kicad_pro @@ -0,0 +1,931 @@ +{ + "board": { + "3dviewports": [], + "design_settings": { + "defaults": { + "apply_defaults_to_fp_fields": false, + "apply_defaults_to_fp_shapes": false, + "apply_defaults_to_fp_text": false, + "board_outline_line_width": 0.05, + "copper_line_width": 0.2, + "copper_text_italic": false, + "copper_text_size_h": 1.5, + "copper_text_size_v": 1.5, + "copper_text_thickness": 0.3, + "copper_text_upright": false, + "courtyard_line_width": 0.05, + "dimension_precision": 4, + "dimension_units": 3, + "dimensions": { + "arrow_length": 1270000, + "extension_offset": 500000, + "keep_text_aligned": true, + "suppress_zeroes": true, + "text_position": 0, + "units_format": 0 + }, + "fab_line_width": 0.1, + "fab_text_italic": false, + "fab_text_size_h": 1.0, + "fab_text_size_v": 1.0, + "fab_text_thickness": 0.15, + "fab_text_upright": false, + "other_line_width": 0.1, + "other_text_italic": false, + "other_text_size_h": 1.0, + "other_text_size_v": 1.0, + "other_text_thickness": 0.15, + "other_text_upright": false, + "pads": { + "drill": 0.8, + "height": 1.27, + "width": 2.54 + }, + "silk_line_width": 0.1, + "silk_text_italic": false, + "silk_text_size_h": 1.0, + "silk_text_size_v": 1.0, + "silk_text_thickness": 0.1, + "silk_text_upright": false, + "zones": { + "min_clearance": 0.5 + } + }, + "diff_pair_dimensions": [], + "drc_exclusions": [], + "meta": { + "version": 2 + }, + "rule_severities": { + "annular_width": "error", + "clearance": "error", + "connection_width": "warning", + "copper_edge_clearance": "error", + "copper_sliver": "warning", + "courtyards_overlap": "error", + "creepage": "error", + "diff_pair_gap_out_of_range": "error", + "diff_pair_uncoupled_length_too_long": "error", + "drill_out_of_range": "error", + "duplicate_footprints": "warning", + "extra_footprint": "warning", + "footprint": "error", + "footprint_filters_mismatch": "ignore", + "footprint_symbol_mismatch": "warning", + "footprint_type_mismatch": "ignore", + "hole_clearance": "error", + "hole_to_hole": "warning", + "holes_co_located": "warning", + "invalid_outline": "error", + "isolated_copper": "warning", + "item_on_disabled_layer": "error", + "items_not_allowed": "error", + "length_out_of_range": "error", + "lib_footprint_issues": "warning", + "lib_footprint_mismatch": "warning", + "malformed_courtyard": "error", + "microvia_drill_out_of_range": "error", + "mirrored_text_on_front_layer": "warning", + "missing_courtyard": "ignore", + "missing_footprint": "warning", + "net_conflict": "warning", + "nonmirrored_text_on_back_layer": "warning", + "npth_inside_courtyard": "ignore", + "padstack": "warning", + "pth_inside_courtyard": "ignore", + "shorting_items": "error", + "silk_edge_clearance": "warning", + "silk_over_copper": "warning", + "silk_overlap": "warning", + "skew_out_of_range": "error", + "solder_mask_bridge": "error", + "starved_thermal": "error", + "text_height": "warning", + "text_on_edge_cuts": "error", + "text_thickness": "warning", + "through_hole_pad_without_hole": "error", + "too_many_vias": "error", + "track_angle": "error", + "track_dangling": "warning", + "track_segment_length": "error", + "track_width": "error", + "tracks_crossing": "error", + "unconnected_items": "error", + "unresolved_variable": "error", + "via_dangling": "warning", + "zones_intersect": "error" + }, + "rules": { + "max_error": 0.005, + "min_clearance": 0.0, + "min_connection": 0.0, + "min_copper_edge_clearance": 0.5, + "min_groove_width": 0.0, + "min_hole_clearance": 0.25, + "min_hole_to_hole": 0.25, + "min_microvia_diameter": 0.2, + "min_microvia_drill": 0.1, + "min_resolved_spokes": 2, + "min_silk_clearance": 0.0, + "min_text_height": 0.8, + "min_text_thickness": 0.08, + "min_through_hole_diameter": 0.3, + "min_track_width": 0.0, + "min_via_annular_width": 0.1, + "min_via_diameter": 0.5, + "solder_mask_to_copper_clearance": 0.0, + "use_height_for_length_calcs": true + }, + "teardrop_options": [ + { + "td_onpthpad": true, + "td_onroundshapesonly": false, + "td_onsmdpad": true, + "td_ontrackend": false, + "td_onvia": true + } + ], + "teardrop_parameters": [ + { + "td_allow_use_two_tracks": true, + "td_curve_segcount": 0, + "td_height_ratio": 1.0, + "td_length_ratio": 0.5, + "td_maxheight": 2.0, + "td_maxlen": 1.0, + "td_on_pad_in_zone": false, + "td_target_name": "td_round_shape", + "td_width_to_size_filter_ratio": 0.9 + }, + { + "td_allow_use_two_tracks": true, + "td_curve_segcount": 0, + "td_height_ratio": 1.0, + "td_length_ratio": 0.5, + "td_maxheight": 2.0, + "td_maxlen": 1.0, + "td_on_pad_in_zone": false, + "td_target_name": "td_rect_shape", + "td_width_to_size_filter_ratio": 0.9 + }, + { + "td_allow_use_two_tracks": true, + "td_curve_segcount": 0, + "td_height_ratio": 1.0, + "td_length_ratio": 0.5, + "td_maxheight": 2.0, + "td_maxlen": 1.0, + "td_on_pad_in_zone": false, + "td_target_name": "td_track_end", + "td_width_to_size_filter_ratio": 0.9 + } + ], + "track_widths": [], + "tuning_pattern_settings": { + "diff_pair_defaults": { + "corner_radius_percentage": 80, + "corner_style": 1, + "max_amplitude": 1.0, + "min_amplitude": 0.2, + "single_sided": false, + "spacing": 1.0 + }, + "diff_pair_skew_defaults": { + "corner_radius_percentage": 80, + "corner_style": 1, + "max_amplitude": 1.0, + "min_amplitude": 0.2, + "single_sided": false, + "spacing": 0.6 + }, + "single_track_defaults": { + "corner_radius_percentage": 80, + "corner_style": 1, + "max_amplitude": 1.0, + "min_amplitude": 0.2, + "single_sided": false, + "spacing": 0.6 + } + }, + "via_dimensions": [], + "zones_allow_external_fillets": false + }, + "ipc2581": { + "dist": "", + "distpn": "", + "internal_id": "", + "mfg": "", + "mpn": "" + }, + "layer_pairs": [], + "layer_presets": [], + "viewports": [] + }, + "boards": [], + "component_class_settings": { + "assignments": [], + "meta": { + "version": 0 + }, + "sheet_component_classes": { + "enabled": false + } + }, + "cvpcb": { + "equivalence_files": [] + }, + "erc": { + "erc_exclusions": [], + "meta": { + "version": 0 + }, + "pin_map": [ + [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2 + ], + [ + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 2 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2 + ], + [ + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 2 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2 + ], + [ + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2 + ], + [ + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2 + ], + [ + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 2 + ], + [ + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2 + ], + [ + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2 + ], + [ + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2 + ] + ], + "rule_severities": { + "bus_definition_conflict": "error", + "bus_entry_needed": "error", + "bus_to_bus_conflict": "error", + "bus_to_net_conflict": "error", + "different_unit_footprint": "error", + "different_unit_net": "error", + "duplicate_reference": "error", + "duplicate_sheet_names": "error", + "endpoint_off_grid": "warning", + "extra_units": "error", + "footprint_filter": "ignore", + "footprint_link_issues": "warning", + "four_way_junction": "ignore", + "global_label_dangling": "warning", + "hier_label_mismatch": "error", + "label_dangling": "error", + "label_multiple_wires": "warning", + "lib_symbol_issues": "warning", + "lib_symbol_mismatch": "warning", + "missing_bidi_pin": "warning", + "missing_input_pin": "warning", + "missing_power_pin": "error", + "missing_unit": "warning", + "multiple_net_names": "warning", + "net_not_bus_member": "warning", + "no_connect_connected": "warning", + "no_connect_dangling": "warning", + "pin_not_connected": "error", + "pin_not_driven": "error", + "pin_to_pin": "warning", + "power_pin_not_driven": "error", + "same_local_global_label": "warning", + "similar_label_and_power": "warning", + "similar_labels": "warning", + "similar_power": "warning", + "simulation_model_issue": "ignore", + "single_global_label": "ignore", + "unannotated": "error", + "unconnected_wire_endpoint": "warning", + "unit_value_mismatch": "error", + "unresolved_variable": "error", + "wire_dangling": "error" + } + }, + "libraries": { + "pinned_footprint_libs": [], + "pinned_symbol_libs": [] + }, + "meta": { + "filename": "time_calculations.kicad_pro", + "version": 3 + }, + "net_settings": { + "classes": [ + { + "bus_width": 12, + "clearance": 0.2, + "diff_pair_gap": 0.25, + "diff_pair_via_gap": 0.25, + "diff_pair_width": 0.2, + "line_style": 0, + "microvia_diameter": 0.3, + "microvia_drill": 0.1, + "name": "Default", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "priority": 2147483647, + "schematic_color": "rgba(0, 0, 0, 0.000)", + "track_width": 0.2, + "tuning_profile": "", + "via_diameter": 0.6, + "via_drill": 0.3, + "wire_width": 6 + }, + { + "name": "CLASS1", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "priority": 6, + "schematic_color": "rgba(0, 0, 0, 0.000)", + "tuning_profile": "CLASS1" + }, + { + "name": "CLASS2", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "priority": 5, + "schematic_color": "rgba(0, 0, 0, 0.000)", + "tuning_profile": "CLASS2" + }, + { + "name": "CLASS3", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "priority": 4, + "schematic_color": "rgba(0, 0, 0, 0.000)", + "tuning_profile": "CLASS3" + }, + { + "name": "CLASS4", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "priority": 3, + "schematic_color": "rgba(0, 0, 0, 0.000)", + "tuning_profile": "CLASS4" + }, + { + "name": "CLASS5", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "priority": 2, + "schematic_color": "rgba(0, 0, 0, 0.000)", + "tuning_profile": "CLASS5" + }, + { + "name": "CLASS6", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "priority": 1, + "schematic_color": "rgba(0, 0, 0, 0.000)", + "tuning_profile": "CLASS6" + }, + { + "name": "CLASS7", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "priority": 0, + "schematic_color": "rgba(0, 0, 0, 0.000)", + "tuning_profile": "CLASS7" + } + ], + "meta": { + "version": 5 + }, + "net_colors": null, + "netclass_assignments": { + "/NET_N": [ + "CLASS7" + ], + "/NET_P": [ + "CLASS7" + ], + "Net-(R1-Pad2)": [ + "CLASS1" + ], + "Net-(R10-Pad1)": [ + "CLASS5" + ], + "Net-(R11-Pad2)": [ + "CLASS6" + ], + "Net-(R3-Pad2)": [ + "CLASS2" + ], + "Net-(R5-Pad2)": [ + "CLASS3" + ], + "Net-(R7-Pad2)": [ + "CLASS4" + ] + }, + "netclass_patterns": [] + }, + "pcbnew": { + "last_paths": { + "gencad": "", + "idf": "", + "netlist": "", + "plot": "", + "pos_files": "", + "specctra_dsn": "", + "step": "", + "svg": "", + "vrml": "" + }, + "page_layout_descr_file": "" + }, + "schematic": { + "annotate_start_num": 0, + "bom_export_filename": "${PROJECTNAME}.csv", + "bom_fmt_presets": [], + "bom_fmt_settings": { + "field_delimiter": ",", + "keep_line_breaks": false, + "keep_tabs": false, + "name": "CSV", + "ref_delimiter": ",", + "ref_range_delimiter": "", + "string_delimiter": "\"" + }, + "bom_presets": [], + "bom_settings": { + "exclude_dnp": false, + "fields_ordered": [ + { + "group_by": false, + "label": "Reference", + "name": "Reference", + "show": true + }, + { + "group_by": true, + "label": "Value", + "name": "Value", + "show": true + }, + { + "group_by": true, + "label": "Footprint", + "name": "Footprint", + "show": true + }, + { + "group_by": false, + "label": "Datasheet", + "name": "Datasheet", + "show": true + }, + { + "group_by": false, + "label": "Description", + "name": "Description", + "show": false + }, + { + "group_by": false, + "label": "Qty", + "name": "${QUANTITY}", + "show": true + }, + { + "group_by": false, + "label": "#", + "name": "${ITEM_NUMBER}", + "show": false + }, + { + "group_by": true, + "label": "DNP", + "name": "${DNP}", + "show": true + }, + { + "group_by": true, + "label": "Exclude from BOM", + "name": "${EXCLUDE_FROM_BOM}", + "show": true + }, + { + "group_by": true, + "label": "Exclude from Board", + "name": "${EXCLUDE_FROM_BOARD}", + "show": true + } + ], + "filter_string": "", + "group_symbols": true, + "include_excluded_from_bom": true, + "name": "", + "sort_asc": true, + "sort_field": "Reference" + }, + "connection_grid_size": 50.0, + "drawing": { + "dashed_lines_dash_length_ratio": 12.0, + "dashed_lines_gap_length_ratio": 3.0, + "default_line_thickness": 6.0, + "default_text_size": 50.0, + "field_names": [], + "intersheets_ref_own_page": false, + "intersheets_ref_prefix": "", + "intersheets_ref_short": false, + "intersheets_ref_show": false, + "intersheets_ref_suffix": "", + "junction_size_choice": 3, + "label_size_ratio": 0.375, + "operating_point_overlay_i_precision": 3, + "operating_point_overlay_i_range": "~A", + "operating_point_overlay_v_precision": 3, + "operating_point_overlay_v_range": "~V", + "overbar_offset_ratio": 1.23, + "pin_symbol_size": 25.0, + "text_offset_ratio": 0.15 + }, + "legacy_lib_dir": "", + "legacy_lib_list": [], + "meta": { + "version": 1 + }, + "net_format_name": "", + "page_layout_descr_file": "", + "plot_directory": "", + "space_save_all_events": true, + "spice_current_sheet_as_root": false, + "spice_external_command": "spice \"%I\"", + "spice_model_current_sheet_as_root": true, + "spice_save_all_currents": false, + "spice_save_all_dissipations": false, + "spice_save_all_voltages": false, + "subpart_first_id": 65, + "subpart_id_separator": 0 + }, + "sheets": [ + [ + "50623816-1a9e-4253-a8ae-1dd555a2ddbe", + "Root" + ] + ], + "text_variables": {}, + "time_domain_parameters": { + "delay_profiles_user_defined": [ + { + "layer_delays": [ + { + "delay": 1000000, + "layer": "F.Cu" + }, + { + "delay": 0, + "layer": "B.Cu" + }, + { + "delay": 0, + "layer": "In1.Cu" + }, + { + "delay": 0, + "layer": "In2.Cu" + } + ], + "profile_name": "CLASS1", + "via_overrides": [], + "via_prop_delay": 0 + }, + { + "layer_delays": [ + { + "delay": 1000000, + "layer": "F.Cu" + }, + { + "delay": 0, + "layer": "B.Cu" + }, + { + "delay": 0, + "layer": "In1.Cu" + }, + { + "delay": 0, + "layer": "In2.Cu" + } + ], + "profile_name": "CLASS2", + "via_overrides": [], + "via_prop_delay": 0 + }, + { + "layer_delays": [ + { + "delay": 1000000, + "layer": "F.Cu" + }, + { + "delay": 2000000, + "layer": "B.Cu" + }, + { + "delay": 1000000, + "layer": "In1.Cu" + }, + { + "delay": 1000000, + "layer": "In2.Cu" + } + ], + "profile_name": "CLASS3", + "via_overrides": [], + "via_prop_delay": 0 + }, + { + "layer_delays": [ + { + "delay": 1000000, + "layer": "F.Cu" + }, + { + "delay": 1000000, + "layer": "B.Cu" + }, + { + "delay": 0, + "layer": "In1.Cu" + }, + { + "delay": 0, + "layer": "In2.Cu" + } + ], + "profile_name": "CLASS4", + "via_overrides": [], + "via_prop_delay": 1000000 + }, + { + "layer_delays": [ + { + "delay": 1000000, + "layer": "F.Cu" + }, + { + "delay": 1000000, + "layer": "B.Cu" + }, + { + "delay": 0, + "layer": "In1.Cu" + }, + { + "delay": 0, + "layer": "In2.Cu" + } + ], + "profile_name": "CLASS5", + "via_overrides": [ + { + "delay": 20000000, + "signal_layer_from": "F.Cu", + "signal_layer_to": "B.Cu", + "via_layer_from": "F.Cu", + "via_layer_to": "B.Cu" + } + ], + "via_prop_delay": 0 + }, + { + "layer_delays": [ + { + "delay": 1000000, + "layer": "F.Cu" + }, + { + "delay": 0, + "layer": "B.Cu" + }, + { + "delay": 2000000, + "layer": "In1.Cu" + }, + { + "delay": 0, + "layer": "In2.Cu" + } + ], + "profile_name": "CLASS6", + "via_overrides": [ + { + "delay": 10000000, + "signal_layer_from": "F.Cu", + "signal_layer_to": "In1.Cu", + "via_layer_from": "F.Cu", + "via_layer_to": "In1.Cu" + }, + { + "delay": 20000000, + "signal_layer_from": "F.Cu", + "signal_layer_to": "In1.Cu", + "via_layer_from": "F.Cu", + "via_layer_to": "In2.Cu" + } + ], + "via_prop_delay": 0 + }, + { + "layer_delays": [ + { + "delay": 1000000, + "layer": "F.Cu" + }, + { + "delay": 0, + "layer": "B.Cu" + }, + { + "delay": 0, + "layer": "In1.Cu" + }, + { + "delay": 0, + "layer": "In2.Cu" + } + ], + "profile_name": "CLASS7", + "via_overrides": [], + "via_prop_delay": 0 + } + ], + "meta": { + "version": 0 + }, + "via_override_parameters": [ + { + "delay": 20000000, + "net_class": "CLASS5", + "signal_layer_from": "F.Cu", + "signal_layer_to": "B.Cu", + "via_layer_from": "F.Cu", + "via_layer_to": "B.Cu" + }, + { + "delay": 10000000, + "net_class": "CLASS6", + "signal_layer_from": "F.Cu", + "signal_layer_to": "In1.Cu", + "via_layer_from": "F.Cu", + "via_layer_to": "In1.Cu" + }, + { + "delay": 20000000, + "net_class": "CLASS6", + "signal_layer_from": "F.Cu", + "signal_layer_to": "In1.Cu", + "via_layer_from": "F.Cu", + "via_layer_to": "In2.Cu" + } + ] + } +} diff --git a/qa/data/pcbnew/time_calculations.kicad_sch b/qa/data/pcbnew/time_calculations.kicad_sch new file mode 100644 index 0000000000..d7b4b7985c --- /dev/null +++ b/qa/data/pcbnew/time_calculations.kicad_sch @@ -0,0 +1,1624 @@ +(kicad_sch + (version 20250318) + (generator "eeschema") + (generator_version "9.99") + (uuid "50623816-1a9e-4253-a8ae-1dd555a2ddbe") + (paper "A4") + (lib_symbols + (symbol "Device:R" + (pin_numbers + (hide yes) + ) + (pin_names + (offset 0) + ) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (duplicate_pin_numbers_are_jumpers no) + (property "Reference" "R" + (at 2.032 0 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 0 0 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "" + (at -1.778 0 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 0 0 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "ki_keywords" "R res resistor" + (at 0 0 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "ki_fp_filters" "R_*" + (at 0 0 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (symbol "R_0_1" + (rectangle + (start -1.016 -2.54) + (end 1.016 2.54) + (stroke + (width 0.254) + (type default) + ) + (fill + (type none) + ) + ) + ) + (symbol "R_1_1" + (pin passive line + (at 0 3.81 270) + (length 1.27) + (name "" + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (number "1" + (effects + (font + (size 1.27 1.27) + ) + ) + ) + ) + (pin passive line + (at 0 -3.81 90) + (length 1.27) + (name "" + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (number "2" + (effects + (font + (size 1.27 1.27) + ) + ) + ) + ) + ) + (embedded_fonts no) + ) + ) + (no_connect + (at 54.61 121.92) + (uuid "008511c7-ca99-4209-839f-4308773f6124") + ) + (no_connect + (at 54.61 91.44) + (uuid "14b6f1c9-afd2-46f0-ba09-a632ef134016") + ) + (no_connect + (at 95.25 91.44) + (uuid "1cb11b31-d89c-4121-8dec-fd8eca058ebd") + ) + (no_connect + (at 54.61 45.72) + (uuid "2a270350-1049-4240-8620-7e5d2d7c59b5") + ) + (no_connect + (at 95.25 45.72) + (uuid "329ca1e8-df46-4bf1-8bd6-e7a8ccf52313") + ) + (no_connect + (at 54.61 80.01) + (uuid "3a9f2065-49d6-4011-86e4-4a313f37a368") + ) + (no_connect + (at 54.61 57.15) + (uuid "5d12824a-b3c2-4c93-ae5c-5cd75f674da2") + ) + (no_connect + (at 54.61 132.08) + (uuid "649a64a3-7f11-4e24-bb40-687193cde965") + ) + (no_connect + (at 95.25 121.92) + (uuid "64d9c20b-ec9f-4cbc-8e45-ade71fa0fe91") + ) + (no_connect + (at 54.61 102.87) + (uuid "7567a152-a46b-4ff1-a12a-d9f4da0dd4e8") + ) + (no_connect + (at 95.25 102.87) + (uuid "77e93b6c-d1c5-480f-bb62-48a181b9d333") + ) + (no_connect + (at 95.25 80.01) + (uuid "7d0c8445-07f2-4449-bd33-3acf9a409cc1") + ) + (no_connect + (at 95.25 57.15) + (uuid "dd1265c0-327e-4841-8fd8-bccc5cadbcd4") + ) + (no_connect + (at 95.25 132.08) + (uuid "e3356337-f94e-4415-abba-2e6ef72acc05") + ) + (no_connect + (at 54.61 68.58) + (uuid "e8c74145-06cd-4c1f-ab7c-25b195012845") + ) + (no_connect + (at 95.25 68.58) + (uuid "fc70ea9e-ad7a-48b9-bed8-f37166f7492e") + ) + (wire + (pts + (xy 62.23 121.92) (xy 87.63 121.92) + ) + (stroke + (width 0) + (type default) + ) + (uuid "07850248-1db1-42b3-ac61-985c00e32cea") + ) + (wire + (pts + (xy 62.23 102.87) (xy 87.63 102.87) + ) + (stroke + (width 0) + (type default) + ) + (uuid "79c452a7-ed7d-4197-ab2a-c0729fc60653") + ) + (wire + (pts + (xy 62.23 91.44) (xy 87.63 91.44) + ) + (stroke + (width 0) + (type default) + ) + (uuid "7a0b695a-32ce-4bb9-9a60-aa0ba9622102") + ) + (wire + (pts + (xy 62.23 132.08) (xy 87.63 132.08) + ) + (stroke + (width 0) + (type default) + ) + (uuid "82c09111-28af-4e98-946d-b59aea115446") + ) + (wire + (pts + (xy 62.23 80.01) (xy 87.63 80.01) + ) + (stroke + (width 0) + (type default) + ) + (uuid "ab97fd54-b677-474b-8aa6-ab12dd9537ca") + ) + (wire + (pts + (xy 62.23 68.58) (xy 87.63 68.58) + ) + (stroke + (width 0) + (type default) + ) + (uuid "c7520602-8710-4d14-9744-77feadffdcf6") + ) + (wire + (pts + (xy 62.23 57.15) (xy 87.63 57.15) + ) + (stroke + (width 0) + (type default) + ) + (uuid "d1682299-3791-4537-a836-fd9f280a0e73") + ) + (wire + (pts + (xy 62.23 45.72) (xy 87.63 45.72) + ) + (stroke + (width 0) + (type default) + ) + (uuid "fc570dce-1f14-4603-b61c-ef9663e2955f") + ) + (label "NET_N" + (at 72.39 132.08 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "54fe963d-0f2f-45bd-b103-fa21cb65373f") + ) + (label "NET_P" + (at 72.39 121.92 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "75059fb5-53af-4c03-a2db-8d8f45e958fd") + ) + (rule_area + (polyline + (pts + (xy 64.77 113.03) (xy 85.09 113.03) (xy 85.09 135.89) (xy 64.77 135.89) + ) + (stroke + (width 0) + (type dash) + ) + (fill + (type none) + ) + (uuid 76e7c2bc-3965-4f57-bcb6-68cf3865c268) + ) + ) + (netclass_flag "" + (length 2.54) + (shape round) + (at 66.04 68.58 0) + (fields_autoplaced yes) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "1885a1f6-f3ec-4c09-97c1-552532f86c66") + (property "Net Class" "CLASS3" + (at 66.7385 66.04 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Component Class" "" + (at -241.3 12.7 0) + (effects + (font + (size 1.27 1.27) + (italic yes) + ) + ) + ) + ) + (netclass_flag "" + (length 2.54) + (shape round) + (at 66.04 57.15 0) + (fields_autoplaced yes) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "2d919403-9f71-4147-a927-ff8b9376ba30") + (property "Net Class" "CLASS2" + (at 66.7385 54.61 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Component Class" "" + (at -241.3 1.27 0) + (effects + (font + (size 1.27 1.27) + (italic yes) + ) + ) + ) + ) + (netclass_flag "" + (length 2.54) + (shape round) + (at 66.04 102.87 0) + (fields_autoplaced yes) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "3e0657e2-b1d1-40aa-bb08-d56aef89373d") + (property "Net Class" "CLASS6" + (at 66.7385 100.33 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Component Class" "" + (at -241.3 46.99 0) + (effects + (font + (size 1.27 1.27) + (italic yes) + ) + ) + ) + ) + (netclass_flag "" + (length 2.54) + (shape round) + (at 66.04 80.01 0) + (fields_autoplaced yes) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "4f34b735-646f-47b1-9b17-a71b3d149725") + (property "Net Class" "CLASS4" + (at 66.7385 77.47 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Component Class" "" + (at -241.3 24.13 0) + (effects + (font + (size 1.27 1.27) + (italic yes) + ) + ) + ) + ) + (netclass_flag "" + (length 2.54) + (shape round) + (at 66.04 45.72 0) + (fields_autoplaced yes) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "b5a0c7f4-2a19-40c8-a8d2-67b0e9fb146e") + (property "Net Class" "CLASS1" + (at 66.7385 43.18 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Component Class" "" + (at -241.3 -10.16 0) + (effects + (font + (size 1.27 1.27) + (italic yes) + ) + ) + ) + ) + (netclass_flag "" + (length 2.54) + (shape round) + (at 66.04 113.03 0) + (fields_autoplaced yes) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "bb031b48-90b6-4634-b947-510dee585b0e") + (property "Net Class" "CLASS7" + (at 66.7385 110.49 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Component Class" "" + (at -241.3 57.15 0) + (effects + (font + (size 1.27 1.27) + (italic yes) + ) + ) + ) + ) + (netclass_flag "" + (length 2.54) + (shape round) + (at 66.04 91.44 0) + (fields_autoplaced yes) + (effects + (font + (size 1.27 1.27) + ) + (justify left bottom) + ) + (uuid "c3758464-3eb4-4d39-9559-dea89fd341c6") + (property "Net Class" "CLASS5" + (at 66.7385 88.9 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Component Class" "" + (at -241.3 35.56 0) + (effects + (font + (size 1.27 1.27) + (italic yes) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 58.42 68.58 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "0015c052-25a6-474f-8dee-c00a6ecfdabf") + (property "Reference" "R5" + (at 58.42 62.23 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 58.42 64.77 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 58.42 70.358 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 58.42 68.58 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 58.42 68.58 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "2a326472-72ab-44da-9c22-aa4760903800") + ) + (pin "2" + (uuid "fdb69585-150d-4a92-be11-b0829a5c4a3c") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R5") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 91.44 57.15 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "11f32aaf-4471-4688-b819-7a6001f94544") + (property "Reference" "R4" + (at 91.44 50.8 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 91.44 53.34 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 91.44 58.928 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 91.44 57.15 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 91.44 57.15 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "433c7131-9fc6-4807-9cd4-1a7b345a2682") + ) + (pin "2" + (uuid "6054be8c-4f8a-40e3-9d6e-b5fb4570b55b") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R4") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 58.42 80.01 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "168987aa-5d0f-457d-a473-1c6864d7e9ca") + (property "Reference" "R7" + (at 58.42 73.66 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 58.42 76.2 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 58.42 81.788 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 58.42 80.01 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 58.42 80.01 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "2138d35f-7506-4294-b0b9-c88163dd36f0") + ) + (pin "2" + (uuid "99e5b4f6-8d5a-4aad-b5df-302d8eaa5c2e") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R7") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 91.44 80.01 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "627a2ba8-c0b3-49e0-809e-90174b458fee") + (property "Reference" "R8" + (at 91.44 73.66 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 91.44 76.2 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 91.44 81.788 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 91.44 80.01 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 91.44 80.01 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "1ca74a1c-0744-426b-bb2d-7a0c290f24e8") + ) + (pin "2" + (uuid "878d3f3b-6621-4ebc-8108-538043fc4cc8") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R8") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 91.44 91.44 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "62d70245-08ec-4619-afe3-9bcfe9345a0b") + (property "Reference" "R10" + (at 91.44 85.09 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 91.44 87.63 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 91.44 93.218 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 91.44 91.44 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 91.44 91.44 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "c94d1558-23ae-4017-934d-d098ee5d2851") + ) + (pin "2" + (uuid "66be3c04-e47d-4191-998c-907181780fce") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R10") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 58.42 91.44 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "6e1874b7-85b2-449a-8f06-c2f8c3e2df6f") + (property "Reference" "R9" + (at 58.42 85.09 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 58.42 87.63 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 58.42 93.218 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 58.42 91.44 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 58.42 91.44 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "ec8c390b-2bc1-48d0-8be5-ea97f4875ed1") + ) + (pin "2" + (uuid "a1d389ed-92d5-482b-ba4b-ac2071d2e478") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R9") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 91.44 45.72 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "6fbf107e-be60-47e6-b3af-13ccfc680d26") + (property "Reference" "R2" + (at 91.44 39.37 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 91.44 41.91 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 91.44 47.498 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 91.44 45.72 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 91.44 45.72 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "d44a5f80-1a68-4536-8263-643f7e6f1d98") + ) + (pin "2" + (uuid "3ea25ec3-7d25-4987-be3d-9cfdade5eb77") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R2") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 58.42 45.72 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "74b5797b-ca1a-4357-aad5-352d7c3455c9") + (property "Reference" "R1" + (at 58.42 39.37 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 58.42 41.91 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 58.42 47.498 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 58.42 45.72 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 58.42 45.72 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "c2f86a0f-6fe8-4aff-9991-4a225f6eb4fc") + ) + (pin "2" + (uuid "735a7592-3553-456a-b64e-182f4f864172") + ) + (instances + (project "" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R1") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 58.42 121.92 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "8060d6fb-9102-4c21-b7d3-dd6202aae313") + (property "Reference" "R13" + (at 58.42 115.57 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 58.42 118.11 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 58.42 123.698 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 58.42 121.92 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 58.42 121.92 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "796da595-e803-41a7-b728-cd8bb4cd32e8") + ) + (pin "2" + (uuid "4f8c4577-a094-4826-986b-aac3400d1e89") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R13") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 91.44 121.92 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "84a7f85b-ceaf-4a2a-936e-23c469bd67b5") + (property "Reference" "R14" + (at 91.44 115.57 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 91.44 118.11 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 91.44 123.698 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 91.44 121.92 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 91.44 121.92 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "35bdcba1-f67a-42f8-8a5d-b13393084a95") + ) + (pin "2" + (uuid "20de4f5a-c515-467c-982c-2cc6999cd0d7") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R14") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 58.42 132.08 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "894b92c4-9393-47f8-9936-c23b4fded612") + (property "Reference" "R15" + (at 58.42 125.73 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 58.42 128.27 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 58.42 133.858 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 58.42 132.08 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 58.42 132.08 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "638f385a-05e1-4512-93fb-99925300843e") + ) + (pin "2" + (uuid "fdb8d47f-096c-4d35-853e-cfbd429da155") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R15") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 58.42 102.87 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "990dfaf0-bb9f-4ae9-bddb-3fef171bf3b0") + (property "Reference" "R11" + (at 58.42 96.52 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 58.42 99.06 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 58.42 104.648 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 58.42 102.87 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 58.42 102.87 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "f1e27bee-b2fe-485a-b971-7ba22f3c8f92") + ) + (pin "2" + (uuid "ed7ae5e5-6d47-4176-a422-ece7dcd2de20") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R11") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 91.44 132.08 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "b72e4e4c-09df-4511-92a1-90d7e7d528c9") + (property "Reference" "R16" + (at 91.44 125.73 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 91.44 128.27 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 91.44 133.858 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 91.44 132.08 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 91.44 132.08 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "19ed804c-3f25-4ec6-81f8-eaffe24238f9") + ) + (pin "2" + (uuid "fe7f3177-3b16-46ce-b6ff-bac709ebda1b") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R16") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 91.44 68.58 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "e64fc1c9-1692-4c47-a21c-463ae8673dad") + (property "Reference" "R6" + (at 91.44 62.23 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 91.44 64.77 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 91.44 70.358 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 91.44 68.58 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 91.44 68.58 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "bef96d7f-e666-4496-8dae-56b41aeb239e") + ) + (pin "2" + (uuid "19b4a828-f2b6-44bb-bbaa-99720b2e03a9") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R6") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 91.44 102.87 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "f166b6a8-fae7-4ec1-a997-d85f78ee8409") + (property "Reference" "R12" + (at 91.44 96.52 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 91.44 99.06 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 91.44 104.648 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 91.44 102.87 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 91.44 102.87 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "cfdb79fa-e6a5-4bd3-bab8-13f26546726e") + ) + (pin "2" + (uuid "28f1a9ad-9a86-4168-aac0-a6d9154189ed") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R12") + (unit 1) + ) + ) + ) + ) + (symbol + (lib_id "Device:R") + (at 58.42 57.15 90) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "fa889142-62ae-4e55-99fe-de19adfd6f6a") + (property "Reference" "R3" + (at 58.42 50.8 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 58.42 53.34 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" + (at 58.42 58.928 90) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Datasheet" "" + (at 58.42 57.15 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Description" "Resistor" + (at 58.42 57.15 0) + (hide yes) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (pin "1" + (uuid "ce2246e4-0f9d-4afd-bfc4-5a8621563c1c") + ) + (pin "2" + (uuid "dee934a3-bbfd-4b34-96bf-173ec267e130") + ) + (instances + (project "time_calculations" + (path "/50623816-1a9e-4253-a8ae-1dd555a2ddbe" + (reference "R3") + (unit 1) + ) + ) + ) + ) + (sheet_instances + (path "/" + (page "1") + ) + ) + (embedded_fonts no) +) diff --git a/qa/pcbnew_utils/board_test_utils.cpp b/qa/pcbnew_utils/board_test_utils.cpp index 531c0f07ec..55af5ac3d0 100644 --- a/qa/pcbnew_utils/board_test_utils.cpp +++ b/qa/pcbnew_utils/board_test_utils.cpp @@ -463,6 +463,7 @@ void CheckFpPad( const PAD* expected, const PAD* pad ) BOOST_CHECK_EQUAL( expected->GetPinFunction(), pad->GetPinFunction() ); BOOST_CHECK_EQUAL( expected->GetPinType(), pad->GetPinType() ); BOOST_CHECK_EQUAL( expected->GetPadToDieLength(), pad->GetPadToDieLength() ); + BOOST_CHECK_EQUAL( expected->GetPadToDieDelay(), pad->GetPadToDieDelay() ); BOOST_CHECK_EQUAL( expected->GetLocalSolderMaskMargin().value_or( 0 ), pad->GetLocalSolderMaskMargin().value_or( 0 ) ); BOOST_CHECK_EQUAL( expected->GetLocalSolderPasteMargin().value_or( 0 ), diff --git a/qa/tests/pcbnew/drc/test_drc_lengths.cpp b/qa/tests/pcbnew/drc/test_drc_lengths.cpp index d6a4335b19..736f06ddd9 100644 --- a/qa/tests/pcbnew/drc/test_drc_lengths.cpp +++ b/qa/tests/pcbnew/drc/test_drc_lengths.cpp @@ -47,7 +47,8 @@ BOOST_FIXTURE_TEST_CASE( DRCLengths, DRC_REGRESSION_TEST_FIXTURE ) // Check for minimum copper connection errors std::vector> tests = { - { "length_calculations", 0 } // Exclude warnings on unconnected pads + { "length_calculations", 0 }, + { "time_calculations", 1 } // Expect one skew DRC error from NET_P }; for( const std::pair& test : tests ) diff --git a/qa/tools/pns/pns_log_viewer_frame.h b/qa/tools/pns/pns_log_viewer_frame.h index a869e825dd..46f0776588 100644 --- a/qa/tools/pns/pns_log_viewer_frame.h +++ b/qa/tools/pns/pns_log_viewer_frame.h @@ -28,7 +28,7 @@ #ifndef __PNS_LOG_VIEWER_FRAME_H #define __PNS_LOG_VIEWER_FRAME_H -#include +#include #include #include #include @@ -108,40 +108,9 @@ public: } long long int CalculateRoutedPathLength( const PNS::ITEM_SET& aLine, const PNS::SOLID* aStartPad, - const PNS::SOLID* aEndPad ) override + const PNS::SOLID* aEndPad, const NETCLASS* aNetClass ) override { - std::vector lengthItems; - - for( int idx = 0; idx < aLine.Size(); idx++ ) - { - const PNS::ITEM* lineItem = aLine[idx]; - - if( const PNS::LINE* l = dyn_cast( lineItem ) ) - { - LENGTH_CALCULATION_ITEM item; - item.SetLine( l->CLine() ); - - const PCB_LAYER_ID layer = GetBoardLayerFromPNSLayer( lineItem->Layer() ); - item.SetLayers( layer ); - - lengthItems.emplace_back( std::move( item ) ); - } - else if( lineItem->OfKind( PNS::ITEM::VIA_T ) && idx > 0 && idx < aLine.Size() - 1 ) - { - const int layerPrev = aLine[idx - 1]->Layer(); - const int layerNext = aLine[idx + 1]->Layer(); - const PCB_LAYER_ID pcbLayerPrev = GetBoardLayerFromPNSLayer( layerPrev ); - const PCB_LAYER_ID pcbLayerNext = GetBoardLayerFromPNSLayer( layerNext ); - - if( layerPrev != layerNext ) - { - LENGTH_CALCULATION_ITEM item; - item.SetVia( static_cast( lineItem->GetSourceItem() ) ); - item.SetLayers( pcbLayerPrev, pcbLayerNext ); - lengthItems.emplace_back( std::move( item ) ); - } - } - } + std::vector lengthItems = getLengthDelayCalculationItems( aLine, aNetClass ); const PAD* startPad = nullptr; const PAD* endPad = nullptr; @@ -159,6 +128,96 @@ public: return m_board->GetLengthCalculation()->CalculateLength( lengthItems, opts, startPad, endPad ); } + int64_t CalculateRoutedPathDelay( const PNS::ITEM_SET& aLine, const PNS::SOLID* aStartPad, + const PNS::SOLID* aEndPad, const NETCLASS* aNetClass ) override + { + std::vector lengthItems = getLengthDelayCalculationItems( aLine, aNetClass ); + + const PAD* startPad = nullptr; + const PAD* endPad = nullptr; + + if( aStartPad ) + startPad = static_cast( aStartPad->Parent() ); + + if( aEndPad ) + endPad = static_cast( aEndPad->Parent() ); + + constexpr PATH_OPTIMISATIONS opts = { + .OptimiseViaLayers = false, .MergeTracks = false, .OptimiseTracesInPads = false, .InferViaInPad = true + }; + + return m_board->GetLengthCalculation()->CalculateDelay( lengthItems, opts, startPad, endPad ); + } + + std::vector getLengthDelayCalculationItems( const PNS::ITEM_SET& aLine, + const NETCLASS* aNetClass ) const + { + std::vector lengthItems; + + for( int idx = 0; idx < aLine.Size(); idx++ ) + { + const PNS::ITEM* lineItem = aLine[idx]; + + if( const PNS::LINE* l = dyn_cast( lineItem ) ) + { + LENGTH_DELAY_CALCULATION_ITEM item; + item.SetLine( l->CLine() ); + + const PCB_LAYER_ID layer = GetBoardLayerFromPNSLayer( lineItem->Layer() ); + item.SetLayers( layer ); + item.SetEffectiveNetClass( aNetClass ); + + lengthItems.emplace_back( std::move( item ) ); + } + else if( lineItem->OfKind( PNS::ITEM::VIA_T ) && idx > 0 && idx < aLine.Size() - 1 ) + { + const int layerPrev = aLine[idx - 1]->Layer(); + const int layerNext = aLine[idx + 1]->Layer(); + const PCB_LAYER_ID pcbLayerPrev = GetBoardLayerFromPNSLayer( layerPrev ); + const PCB_LAYER_ID pcbLayerNext = GetBoardLayerFromPNSLayer( layerNext ); + + if( layerPrev != layerNext ) + { + LENGTH_DELAY_CALCULATION_ITEM item; + item.SetVia( static_cast( lineItem->GetSourceItem() ) ); + item.SetLayers( pcbLayerPrev, pcbLayerNext ); + item.SetEffectiveNetClass( aNetClass ); + lengthItems.emplace_back( std::move( item ) ); + } + } + } + + return lengthItems; + } + + int64_t CalculateLengthForDelay( int64_t aDesiredDelay, const int aWidth, const bool aIsDiffPairCoupled, + const int aDiffPairCouplingGap, const int aPNSLayer, + const NETCLASS* aNetClass ) override + { + TIME_DOMAIN_GEOMETRY_CONTEXT ctx; + ctx.NetClass = aNetClass; + ctx.Width = aWidth; + ctx.IsDiffPairCoupled = aIsDiffPairCoupled; + ctx.DiffPairCouplingGap = aDiffPairCouplingGap; + ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer ); + + return m_board->GetLengthCalculation()->CalculateLengthForDelay( aDesiredDelay, ctx ); + } + + int64_t CalculateDelayForShapeLineChain( const SHAPE_LINE_CHAIN& aShape, int aWidth, bool aIsDiffPairCoupled, + int aDiffPairCouplingGap, int aPNSLayer, + const NETCLASS* aNetClass ) override + { + TIME_DOMAIN_GEOMETRY_CONTEXT ctx; + ctx.NetClass = aNetClass; + ctx.Width = aWidth; + ctx.IsDiffPairCoupled = aIsDiffPairCoupled; + ctx.DiffPairCouplingGap = aDiffPairCouplingGap; + ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer ); + + return m_board->GetLengthCalculation()->CalculatePropagationDelayForShapeLineChain( aShape, ctx ); + } + private: std::shared_ptr m_board; };