콘텐츠로 이동

IPC-2581 예제와 읽는 코드

아래는 실제 문서의 발췌다. 이름이 뜻을 말하므로 형식을 몰라도 절반은 읽힌다.

<?xml version="1.0" encoding="UTF-8"?>
<IPC-2581 revision="C" xmlns="http://webstds.ipc.org/2581">
<Content roleRef="Owner">
<FunctionMode mode="ASSEMBLY"/>
<StepRef name="test-3_r2.-17_4"/>
<LayerRef name="TOP"/>
<LayerRef name="BOTTOM"/>
<LayerRef name="DRILL_1-6"/>
<BomRef name="BOM_test-3_r2.-17_4"/>
<DictionaryLineDesc units="MILLIMETER"/>
</Content>
요소
revision="C"표준의 판
FunctionMode이 문서의 용도 — 조립용인가 제조용인가
StepRef · LayerRef문서가 담은 스텝(step)과 층의 목록
BomRef어느 BOM 을 가리키는가
DictionaryLineDesc units사전과 그 단위

용도 표시를 먼저 본다. 조립용 문서에는 층 형상이 없을 수 있고, 제조용 문서에는 BOM 이 얇을 수 있다. 받은 문서가 무엇을 위한 것인지가 첫 줄에서 정해진다.

<Ecad name="Design">
<CadHeader units="INCH"/>
<CadData>
<Layer name="TOP" layerFunction="CONDUCTOR" side="TOP" polarity="POSITIVE"/>
<Layer name="BOTTOM" layerFunction="CONDUCTOR" side="BOTTOM" polarity="POSITIVE"/>
<Layer name="DRILL_1-6" layerFunction="DRILL" side="ALL" polarity="POSITIVE"/>
속성
units이 문서의 좌표 단위
layerFunction그 층이 도체인가 · 드릴인가 · 마스크인가
side앞면 · 뒷면 · 전체
polarity양화 · 음화

층이 바뀌어 제조되는 사고가 여기서 사라진다. 파일 이름이 아니라 이 선언이 층을 정한다.

<Step name="board">
<Profile>
<Polygon>
<PolyBegin x="0" y="0"/>
<PolyStepSegment x="100" y="0"/>
<PolyStepSegment x="100" y="80"/>
<PolyStepSegment x="0" y="80"/>
<PolyStepSegment x="0" y="0"/>
</Polygon>
</Profile>
<Package name="R_0402" type="OTHER">
<Outline>
<Polygon>
<PolyBegin x="-0.5" y="-0.3"/>
<PolyStepSegment x="0.5" y="-0.3"/>
<PolyStepSegment x="0.5" y="0.3"/>
<PolyStepSegment x="-0.5" y="0.3"/>
<PolyStepSegment x="-0.5" y="-0.3"/>
</Polygon>
</Outline>
</Package>
<Package name="HDR_1x02" type="OTHER">
<Pin number="1">
<Hole diameter="1.0"/>
</Pin>
</Package>
요소
Profile보드 외곽(board outline)
Polygon · PolyBegin · PolyStepSegment다각형 — 시작점과 이어지는 점
Package패키지 정의 — 부품마다 되풀이하지 않는다
Pin · Hole패키지의 단자와 홀

다각형은 시작점으로 돌아와 닫는다. 마지막 점이 시작점과 같은 것이 그것이다.

<Component refDes="R1" packageRef="R_0402" layerRef="TOP"
part="10k" mountType="SMT">
<Location x="20" y="20"/>
<Xform rotation="0"/>
</Component>
<Component refDes="C2" packageRef="C_0402" layerRef="BOTTOM"
part="1nF" mountType="SMT">
<Location x="45" y="30"/>
<Xform rotation="0" mirror="true"/>
</Component>
속성
refDes참조 지정자(reference designator)
packageRef어느 패키지 정의를 쓰는가
layerRef어느 면에 있는가
mountType표면 실장인가 삽입인가
Location · Xform위치와 회전 · 뒷면은 뒤집힌다
<Bom name="bom">
<BomItem OEMDesignNumberRef="10k">
<RefDes name="R1"/>
<RefDes name="R2"/>
</BomItem>
<BomItem OEMDesignNumberRef="10k">
<RefDes name="R3" populate="false"/>
</BomItem>
</Bom>

populate="false"실장 제외다. 별도 문서로 알리던 사실이 자료로 들어와 있다 — 조립 쪽이 사람의 메모를 읽지 않아도 된다.

문서 전체를 자료 구조로 올리면 큰 보드에서 메모리가 늘어난다. 필요한 요소만 골라 훑는 방식이 실무에서 쓸모 있다.

#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
namespace codename7
{
/// IPC-2581 문서에서 필요한 요소만 골라 받는 처리기.
/// XML 파서는 SAX 계열(요소를 만나는 대로 알려 주는 방식)을 쓴다.
class c_ipc2581_reader
{
public:
struct s_layer
{
std::string name;
std::string function; ///< CONDUCTOR · DRILL · SOLDERMASK …
std::string side; ///< TOP · BOTTOM · ALL
};
struct s_component
{
std::string refDes;
std::string packageRef;
std::string layerRef;
double x = 0.0, y = 0.0, rotation = 0.0;
bool mirror = false;
};
/// 요소를 만날 때마다 호출된다. 관심 없는 요소는 그냥 지나간다.
void OnElement(std::string_view aName,
const std::unordered_map<std::string, std::string> &aAttr)
{
if (aName == "CadHeader") { m_units = attr(aAttr, "units"); }
else if (aName == "Layer") { m_layers.push_back(makeLayer(aAttr)); }
else if (aName == "Component") { m_components.push_back(makeComponent(aAttr)); }
else if (aName == "Location") { setLocation(aAttr); }
else if (aName == "Xform") { setXform(aAttr); }
}
const std::string &Units() const { return m_units; }
const std::vector<s_layer> &Layers() const { return m_layers; }
const std::vector<s_component> &Components() const { return m_components; }
private:
using t_attr = std::unordered_map<std::string, std::string>;
static std::string attr(const t_attr &a, const char *k)
{
const auto it = a.find(k);
return it == a.end() ? std::string() : it->second;
}
static double num(const t_attr &a, const char *k)
{
const std::string v = attr(a, k);
return v.empty() ? 0.0 : std::stod(v);
}
static s_layer makeLayer(const t_attr &a)
{
return {attr(a, "name"), attr(a, "layerFunction"), attr(a, "side")};
}
static s_component makeComponent(const t_attr &a)
{
s_component c;
c.refDes = attr(a, "refDes");
c.packageRef = attr(a, "packageRef");
c.layerRef = attr(a, "layerRef");
return c;
}
/// Location 과 Xform 은 바로 앞의 Component 에 붙는다.
void setLocation(const t_attr &a)
{
if (m_components.empty()) return;
m_components.back().x = num(a, "x");
m_components.back().y = num(a, "y");
}
void setXform(const t_attr &a)
{
if (m_components.empty()) return;
m_components.back().rotation = num(a, "rotation");
m_components.back().mirror = (attr(a, "mirror") == "true");
}
std::string m_units;
std::vector<s_layer> m_layers;
std::vector<s_component> m_components;
};
}
순서하는 일
1용도 표시와 단위를 확인한다
2층 선언 수와 기능이 스택업(stackup)과 맞는지 본다
3부품 수와 면 배분을 설계와 대조한다
4넷 수를 대조한다
5실장 제외 부품이 BOM 에 바르게 표시되었는지 본다
6다시 읽어 보드로 복원해 화면에서 확인한다

6 번이 요령이다. 낸 문서를 그대로 읽어 원래 설계와 같은 그림이 나오면, 그 문서는 최소한 자기 자신과 일관된다.