콘텐츠로 이동

Gerber 예제와 읽는 코드

형식은 실제 파일을 한 줄씩 읽어 볼 때 가장 빨리 이해된다. 아래는 실제 도구가 낸 파일의 발췌다.

G04 (created by PCB tool) date 11/9/2013 7:35:54 PM*
%MOIN*%
G04 Gerber Fmt 3.4, Leading zero omitted, Abs format*
%FSLAX34Y34*%
G01*
G70*
G90*
G04 APERTURE LIST*
%ADD10C,0.006*%
%ADD13R,0.0393701X0.153543*%
%ADD15R,0.0275591X0.0275591*%
G04 APERTURE END LIST*
G54D15*
X15425Y19750D03*
X9450Y18125D03*
G54D10*
X40375Y4875D02*
X40600Y4875D01*
X40600Y4500D01*
M02*
G04 …*주석이다. 도구 이름과 서식을 사람이 읽으라고 적어 둔 것이며 기계는 쓰지 않는다
%MOIN*%단위는 인치다
%FSLAX34Y34*%좌표 서식 — 앞의 0 을 생략하고, 정수 3 자리 · 소수 4 자리로 읽는다
G01*직선 보간
G70* G90*인치 · 절대 좌표
%ADD10C,0.006*%10 번 구경(aperture)은 지름 0.006 인치의
%ADD13R,0.0393701X0.153543*%13 번 구경은 그 크기의 사각
G54D15*15 번 구경을 고른다
X15425Y19750D03*그 자리에 구경을 찍는다 — 패드(pad) 하나
X40375Y4875D02*그리지 않고 옮긴다
X40600Y4875D01*거기까지 그린다 — 트랙(track) 한 구간
M02*파일 끝

X15425 를 실제 치수로 바꾸면 1.5425 인치다 — 서식이 정수 3 · 소수 4 라고 말했기 때문이다. 이 한 줄이 틀리면 모든 좌표가 같은 배율로 어긋난다.

같은 파일에 속성이 붙으면 자료가 스스로 뜻을 말한다.

%TF.FileFunction,Copper,Bot,L4*%
%TF.FilePolarity,Positive*%
%TF.Part,Single*%
%TA.AperFunction,Conductor*%
%ADD10C,0.150*%
%TA.AperFunction,ViaPad*%
%ADD11C,0.600*%
%TA.AperFunction,ComponentPad*%
%ADD12R,0.800X1.200*%
%TF.FileFunction,Copper,Bot,L4*%이 파일은 4 층 보드의 뒷면 구리
%TF.FilePolarity,Positive*%양화 — 그린 것이 구리다
%TF.Part,Single*%낱장 보드다(패널이 아니다)
%TA.AperFunction,Conductor*%다음에 정의할 구경은 트랙용이다
%TA.AperFunction,ViaPad*%다음 구경은 비아(via) 패드
%TA.AperFunction,ComponentPad*%다음 구경은 부품 패드

파일 이름이 아니라 파일 내용이 층을 말한다. 이름 규칙이 어긋나 층이 바뀌어 제조되는 사고를 막는 것이 이 속성의 목적이다.

M48
METRIC,TZ
T1C0.300
T2C1.016
T3C3.401
%
G90
G05
T1
X41.7Y-51.7
X42.11Y-50.62
T2
X50.33Y-52.51
T0
M30
M48머리 시작
METRIC,TZ밀리미터 · 뒤의 0 을 유지한다
T1C0.3001 번 공구는 지름 0.3 mm
%머리 끝
G90 G05절대 좌표 · 드릴 모드
T11 번 공구를 고른다
X41.7Y-51.7그 자리에 홀 하나
T0공구 해제
M30파일 끝

Y 좌표가 음수인 것에 주의한다. 형상 파일과 원점(origin)·부호 규약이 같아야 홀이 패드 가운데에 온다.

Gerber 는 두 종류의 명령으로 이루어진다 — % 로 감싼 확장 명령* 로 끝나는 일반 명령. 읽는 쪽의 첫 단계는 그 둘을 가르는 일이다.

#include <string>
#include <string_view>
#include <vector>
namespace codename7
{
/// Gerber 스트림을 명령 단위로 가른다.
/// 확장 명령은 `%…%`, 일반 명령은 `…*` 로 끝난다.
class c_gerber_lexer
{
public:
struct s_command
{
bool extended = false; ///< `%` 로 감싼 명령인가
std::string body; ///< 구분자를 뺀 본문
};
explicit c_gerber_lexer(std::string_view aText) : m_text(aText) {}
std::vector<s_command> Tokenize()
{
std::vector<s_command> out;
size_t i = 0;
while (i < m_text.size())
{
const char c = m_text[i];
if (c == '%') { i = readExtended(i + 1, out); }
else if (isSpace(c)) { ++i; }
else { i = readPlain(i, out); }
}
return out;
}
private:
static bool isSpace(char c) { return c == '\n' || c == '\r' || c == ' ' || c == '\t'; }
/// `%` 다음부터 닫는 `%` 까지. 안에 `*` 로 끝나는 조각이 여럿 올 수 있다.
size_t readExtended(size_t aFrom, std::vector<s_command> &aOut)
{
const size_t end = m_text.find('%', aFrom);
if (end == std::string_view::npos) return m_text.size(); // 닫히지 않았다
std::string_view span = m_text.substr(aFrom, end - aFrom);
size_t start = 0;
while (start < span.size())
{
const size_t star = span.find('*', start);
if (star == std::string_view::npos) break;
aOut.push_back({true, std::string(span.substr(start, star - start))});
start = star + 1;
}
return end + 1;
}
/// `*` 까지가 한 명령이다.
size_t readPlain(size_t aFrom, std::vector<s_command> &aOut)
{
const size_t star = m_text.find('*', aFrom);
if (star == std::string_view::npos) return m_text.size();
aOut.push_back({false, std::string(m_text.substr(aFrom, star - aFrom))});
return star + 1;
}
std::string_view m_text;
};
}

이 단계까지 오면 남은 일은 본문의 머리 글자로 갈래를 나누는 것이다.

본문이 시작하는 글자갈래
MO · FS단위 · 좌표 서식
AD구경 정의
AM구경 매크로
LP극성(polarity)
TF · TA · TO · TD속성
G보간 모드 · 영역 시작과 끝
X · Y · D좌표와 동작
순서하는 일
1낸 묶음을 다시 읽어 층마다 화면에 띄운다
2형상과 드릴을 겹쳐 홀이 패드 가운데에 오는지 본다
3외곽(board outline)과 구리의 간격을 본다
4마스크 개구가 패드와 맞는지 본다
5층 순서를 지시서와 대조한다

낸 사람이 확인한다. 제조사가 발견해 주기를 기대하면 그 발견은 일정이 급할 때 오지 않는다.