KiCad PCB EDA Suite
Loading...
Searching...
No Matches
ipc2581_function_mode.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <array>
23#include <utility>
24
25#include <wx/translation.h>
26
27namespace IPC2581
28{
29
30namespace
31{
32
33// Each layerFunction value that KiCad writes with its Table 4 schema section
34constexpr std::array<std::pair<const char*, SECTION>, 27> LAYER_FUNCTION_SECTIONS = { {
35 // EDGE_CHAMFER is in section 4.1.1.10 and in section 4.1.1.15
36 // Table 4 makes R necessary for FABRICATION but F is optional
37 { "DRILL", SECTION::DRILL_ROUT },
38 { "ROUT", SECTION::DRILL_ROUT },
39 { "V_CUT", SECTION::DRILL_ROUT },
40 { "EDGE_CHAMFER", SECTION::DRILL_ROUT },
41 { "SOLDERMASK", SECTION::SOLDERMASK },
42 { "SOLDERPASTE", SECTION::SOLDERPASTE },
43 { "SILKSCREEN", SECTION::SILKSCREEN },
44 { "LEGEND", SECTION::SILKSCREEN },
45 { "DOCUMENT", SECTION::DOCUMENTATION },
46 { "GRAPHIC", SECTION::DOCUMENTATION },
47 { "BOARD_OUTLINE", SECTION::DOCUMENTATION },
48 { "REWORK", SECTION::DOCUMENTATION },
49 { "FIXTURE", SECTION::DOCUMENTATION },
50 { "PROBE", SECTION::DOCUMENTATION },
51 { "COURTYARD", SECTION::DOCUMENTATION },
52 { "ASSEMBLY", SECTION::COMPONENTS },
53 { "COATINGCOND", SECTION::MISC_FAB },
54 { "COATINGNONCOND", SECTION::MISC_FAB },
55 { "CONDUCTIVE_ADHESIVE", SECTION::MISC_FAB },
56 { "GLUE", SECTION::MISC_FAB },
57 { "HOLEFILL", SECTION::MISC_FAB },
58 { "SOLDERBUMP", SECTION::MISC_FAB },
59 { "THIEVING_KEEP_INOUT", SECTION::MISC_FAB },
60 { "EDGE_PLATING", SECTION::MISC_FAB },
61 { "STIFFENER", SECTION::MISC_FAB },
62 { "CAPACITIVE", SECTION::MISC_FAB },
63 { "RESISTIVE", SECTION::MISC_FAB },
64} };
65
66
67} // namespace
68
69
71{
72 // Revision B has no DFX function mode and KiCad writes no Dfx element
73 return aMode != MODE::DFX;
74}
75
76
77std::optional<SECTION> SectionForBoardLayer( PCB_LAYER_ID aLayer )
78{
79 if( IsCopperLayer( aLayer ) )
80 return IsExternalCopperLayer( aLayer ) ? SECTION::OUTER_COPPER : SECTION::INNER_COPPER;
81
82 switch( aLayer )
83 {
84 case F_Adhes:
85 case B_Adhes:
86 return SECTION::MISC_FAB;
87
88 case F_Paste:
89 case B_Paste:
90 return SECTION::SOLDERPASTE;
91
92 case F_SilkS:
93 case B_SilkS:
94 return SECTION::SILKSCREEN;
95
96 case F_Mask:
97 case B_Mask:
98 return SECTION::SOLDERMASK;
99
100 case Edge_Cuts:
101 return SECTION::PROFILE;
102
103 case F_CrtYd:
104 case B_CrtYd:
105 case Margin:
106 return SECTION::DOCUMENTATION;
107
108 // Section 4.1.1.4 puts layerFunction ASSEMBLY in Component Assembly Data
109 case F_Fab:
110 case B_Fab:
111 return SECTION::COMPONENTS;
112
113 default:
114 if( IsUserLayer( aLayer ) )
115 return SECTION::DOCUMENTATION;
116
117 return std::nullopt;
118 }
119}
120
121
122std::optional<SECTION> SectionForLayerFunction( const wxString& aLayerFunction,
123 const wxString& aSide )
124{
125 for( const auto& entry : LAYER_FUNCTION_SECTIONS )
126 {
127 if( aLayerFunction == wxString::FromAscii( entry.first ) )
128 return entry.second;
129 }
130
131 if( aLayerFunction.StartsWith( wxT( "DIEL" ) ) )
132 return SECTION::DIELECTRIC;
133
134 // Revision B writes EMBEDDED_COMPONENT and revision C writes COMPONENT_EMBEDDED
135 // because why not?
136 if( aLayerFunction.StartsWith( wxT( "COMPONENT" ) )
137 || aLayerFunction == wxT( "EMBEDDED_COMPONENT" ) )
138 {
139 return SECTION::COMPONENTS;
140 }
141
142 // Sections 4.1.1.12 and 4.1.1.13 divide the conductor functions by side
143 static const std::array<const char*, 6> conductors = { "CONDUCTOR", "CONDFILM", "CONDFOIL",
144 "PLANE", "SIGNAL", "MIXED" };
145
146 for( const char* function : conductors )
147 {
148 if( aLayerFunction == wxString::FromAscii( function ) )
149 {
150 if( aSide == wxT( "INTERNAL" ) )
151 return SECTION::INNER_COPPER;
152
153 return aSide.IsEmpty() ? std::nullopt
154 : std::optional<SECTION>( SECTION::OUTER_COPPER );
155 }
156 }
157
158 return std::nullopt;
159}
160
161
162RESOLVE_RESULT ResolveSections( REVISION aRevision, MODE aMode, const SECTION_SET& aRequested )
163{
165
166 if( !ModeSupported( aMode, aRevision ) )
167 {
168 result.m_conflicts.push_back( { std::nullopt, std::nullopt, _( "Cannot produce this IPC-2581 data set." ) } );
169 return result;
170 }
171
172 // A requested section stays only if the function mode makes it optional
173 result.m_included = ( ( aRequested & OptionalSections( aMode ) ) | RequiredSections( aMode ) )
175
176 if( result.m_included.none() )
177 {
178 result.m_conflicts.push_back( { std::nullopt, std::nullopt, _( "No IPC-2581 content selected." ) } );
179 return result;
180 }
181
182 const bool haveBom = result.m_included.Contains( SECTION::BOM_AVL );
183 const bool havePackages = result.m_included.Contains( SECTION::PACKAGES );
184 const bool haveComponents = result.m_included.Contains( SECTION::COMPONENTS );
185 const bool havePadstacks = result.m_included.Contains( SECTION::PADSTACKS );
186 const bool haveOuterCopper = result.m_included.Contains( SECTION::OUTER_COPPER );
187
188 // Component@layerRef is mandatory and names the copper layer of the footprint
189 // You cannot remove it and it must not dangle
190 if( haveComponents && !haveOuterCopper )
191 {
192 result.m_conflicts.push_back(
193 { SECTION::COMPONENTS, SECTION::OUTER_COPPER,
194 _( "Cannot export assembly data without outer copper layers." ) } );
195 }
196
197 // Each physical net point names an outer copper layer
198 if( result.m_included.Contains( SECTION::PHYSICAL_NET ) && !haveOuterCopper )
199 {
200 result.m_conflicts.push_back(
201 { SECTION::PHYSICAL_NET, SECTION::OUTER_COPPER,
202 _( "Cannot export physical netlist without outer copper layers." ) } );
203 }
204
205 if( !havePadstacks )
206 result.m_suppressions.Set( SUPPRESS::PAD_PADSTACKDEFREF );
207
208 // No keyref selects RefDes@packageRef in the two revisions
209 // Remove it to prevent a dangling name
210 if( haveBom && !havePackages )
211 result.m_suppressions.Set( SUPPRESS::BOM_REFDES_PACKAGEREF );
212
213 // RefDes@layerRef names an outer copper layer and revision C puts it in layerKeyRef
214 if( haveBom && !haveOuterCopper )
215 result.m_suppressions.Set( SUPPRESS::BOM_REFDES_LAYERREF );
216
217 if( aRevision == REVISION::C )
218 {
219 if( !haveBom )
220 {
221 result.m_suppressions.Set( SUPPRESS::COMPONENT_REFDES );
222 result.m_suppressions.Set( SUPPRESS::PINREF_COMPONENTREF );
223 }
224
225 if( !havePackages )
226 result.m_suppressions.Set( SUPPRESS::COMPONENT_PACKAGEREF );
227 }
228 else
229 {
230 // Can't remove Component@packageRef in RevB
231 if( haveComponents && !havePackages )
232 {
233 result.m_conflicts.push_back(
234 { SECTION::COMPONENTS, SECTION::PACKAGES,
235 _( "Component assembly data cannot be exported without component "
236 "packages in IPC-2581B." ) } );
237 }
238
239 // We need component for RefDes and we store this in PinRef
240 if( !haveComponents )
241 {
242 result.m_suppressions.Set( SUPPRESS::PINREF_COMPONENTREF );
243
244 if( haveBom )
245 result.m_suppressions.Set( SUPPRESS::BOM_REFDES );
246 }
247 }
248
249 if( !NeedsCadData( result.m_included ) )
250 result.m_suppressions.Set( SUPPRESS::BOM_HEADER_STEPREF );
251
252 return result;
253}
254
255} // namespace IPC2581
Set of schema sections.
#define _(s)
bool IsUserLayer(PCB_LAYER_ID aLayerId)
Test whether a layer is a non copper and a non tech layer.
Definition layer_ids.h:785
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:703
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition layer_ids.h:714
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ F_CrtYd
Definition layer_ids.h:112
@ B_Adhes
Definition layer_ids.h:99
@ Edge_Cuts
Definition layer_ids.h:108
@ F_Paste
Definition layer_ids.h:100
@ F_Adhes
Definition layer_ids.h:98
@ B_Mask
Definition layer_ids.h:94
@ F_Mask
Definition layer_ids.h:93
@ B_Paste
Definition layer_ids.h:101
@ F_Fab
Definition layer_ids.h:115
@ Margin
Definition layer_ids.h:109
@ F_SilkS
Definition layer_ids.h:96
@ B_CrtYd
Definition layer_ids.h:111
@ B_SilkS
Definition layer_ids.h:97
@ B_Fab
Definition layer_ids.h:114
JOB_EXPORT_PCB_FAB::DATA_SET MODE
Columns of Table 4 The job owns the enum so that every layer shares one type.
SECTION_SET RequiredSections(MODE aMode)
Schema sections that Table 4 marks Y for aMode.
SECTION_SET OptionalSections(MODE aMode)
Schema sections that Table 4 marks O for aMode.
SECTION_SET UnsupportedSections()
Schema sections that no KiCad board supplies.
bool NeedsCadData(const SECTION_SET &aSet)
True if an included schema section needs an Ecad/CadData element.
RESOLVE_RESULT ResolveSections(REVISION aRevision, MODE aMode, const SECTION_SET &aRequested)
Compare aRequested with Table 4 and give the attributes to remove and the conflicts.
REVISION
Schema revision The two revisions declare different identity constraints.
std::optional< SECTION > SectionForLayerFunction(const wxString &aLayerFunction, const wxString &aSide)
Schema section that holds the layers with aLayerFunction.
bool ModeSupported(MODE aMode, REVISION)
True if KiCad can write aMode for aRevision.
@ PINREF_COMPONENTREF
Pad/PinRef@componentRef and LogicalNet/PinRef@componentRef.
@ BOM_HEADER_STEPREF
Bom/BomHeader/StepRef.
@ COMPONENT_REFDES
Component\refDes.
@ PAD_PADSTACKDEFREF
Pad@padstackDefRef, and the PadStackDef elements themselves.
@ COMPONENT_PACKAGEREF
Component@packageRef.
@ BOM_REFDES_PACKAGEREF
Bom/BomItem/RefDes@packageRef.
@ BOM_REFDES
Bom/BomItem/RefDes and all its attributes.
@ BOM_REFDES_LAYERREF
Bom/BomItem/RefDes@layerRef.
std::optional< SECTION > SectionForBoardLayer(PCB_LAYER_ID aLayer)
Schema section that holds the artwork of aLayer.
wxString result
Test unit parsing edge cases and error handling.