# Copyright (C) 2015..2022 Tibor 'Igor2' Palinkas # License: GNU LGPL 2.1 or later # (Output generated using this script is not affected by the license of the script) #@@param:pin_ringdia pin's copper ring (annulus) outer diameter (in mil by default, mm suffix can be used) #@@optional:pin_ringdia #@@dim:pin_ringdia #@@param:pin_clearance pin's copper clearance diameter (in mil by default, mm suffix can be used) #@@optional:pin_clearance #@@dim:pin_clearance #@@param:pin_mask pin's solder mask diameter (in mil by default, mm suffix can be used) #@@optional:pin_mask #@@dim:pin_mask #@@param:pin_mask_offs how much bigger (+) or smaller (-) the mask opening should be compared to copper (in mil by default, mm suffix can be used); pin_mask must be set to 0 #@@optional:pin_mask_offs #@@dim:pin_mask_offs #@@param:pin_mask_ratio pin mask opening should be copper size * this ratio (numbers larger than 1 mean opening with a gap, 1.00 means exactly as big as the copper shape) - doesn't work in GUI #@@optional:pin_mask_ratio #@@dim:pin_mask_ratio #@@param:pin_drill copper pin's drill diameter (in mil by default, mm suffix can be used) #@@optional:pin_drill #@@dim:pin_drill #@@param:pad_thickness width of pads (in mil by default, mm suffix can be used) #@@optional:pad_thickness #@@dim:pad_thickness #@@param:pad_clearance copper clearance around the pad (in mil by default, mm suffix can be used) #@@optional:pad_clearance #@@dim:pad_clearance #@@param:pad_mask pin's solder mask (in mil by default, mm suffix can be used) #@@optional:pad_mask #@@dim:pad_mask #@@param:pad_mask_offs how much bigger (+) or smaller (-) the mask opening should be compared to copper (in mil by default, mm suffix can be used); pad_mask must be set to 0 #@@optional:pad_mask_offs #@@dim:pad_mask_offs #@@param:pad_mask_ratio pad mask opening should be copper size * this ratio (numbers larger than 1 mean opening with a gap, 1.00 means exactly as big as the copper shape) - doesn't work in GUI #@@optional:pad_mask_ratio #@@dim:pad_mask_ratio #@@param:pad_paste pad's paste line thickness (in mil by default, mm suffix can be used) #@@optional:pad_paste #@@dim:pad_paste #@@param:pad_paste_offs how much bigger (+) or smaller (-) the paste should be compared to copper (in mil by default, mm suffix can be used); pad_paste must be set to 0 #@@optional:pad_paste_offs #@@dim:pad_paste_offs #@@param:pad_paste_ratio pad paste should be copper size * this ratio (numbers smaller than 1 mean smaller paste, 1.00 means exactly as big as the copper shape) - doesn't work in GUI #@@optional:pad_paste_ratio #@@dim:pad_paste_ratio #@@param:line_thickness silk line thickness (in mil by default, mm suffix can be used) #@@optional:line_thickness #@@dim:line_thickness BEGIN { q="\"" DEFAULT["pin_ringdia"] = mil(80) DEFAULT["pin_ringdia", "dim"] = 1 DEFAULT["pin_clearance"] = mil(50) DEFAULT["pin_clearance", "dim"] = 1 DEFAULT["pin_mask"] = mil(86) DEFAULT["pin_mask", "dim"] = 1 DEFAULT["pin_mask_offs"] = "" # use copper size DEFAULT["pin_mask_offs", "dim"] = 1 DEFAULT["pin_mask_ratio"] = "" # use copper size DEFAULT["pin_drill"] = mm(1) DEFAULT["pin_drill", "dim"] = 1 DEFAULT["line_thickness"] = mil(10) DEFAULT["line_thickness", "dim"] = 1 DEFAULT["pad_thickness"] = mil(20) DEFAULT["pad_thickness", "dim"] = 1 DEFAULT["pad_clearance"] = mil(10) DEFAULT["pad_clearance", "dim"] = 1 DEFAULT["pad_mask"] = mil(30) DEFAULT["pad_mask", "dim"] = 1 DEFAULT["pad_mask_offs"] = "" # use copper size DEFAULT["pad_mask_offs", "dim"] = 1 DEFAULT["pad_mask_ratio"] = "" # use copper size DEFAULT["pad_paste"] = "" # use copper size DEFAULT["pad_paste", "dim"] = 1 DEFAULT["pad_paste_offs"] = "" # use copper size DEFAULT["pad_paste_offs", "dim"] = 1 DEFAULT["pad_paste_ratio"] = "" # use copper size DEFAULT["pin_flags"] = "__auto" s_default=1 s_weak=2 s_explicit=3 offs_x = 0 offs_y = 0 objid = 1 proto_next_id = 0 pi=3.141592654 NL = "\n" # minuid for(n = 32; n < 127; n++) ORD[sprintf("%c", n)] = n BASE64 = "ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz0123456789+/" } function minuid_add(SUM, s ,n,v,c1,c2) { v = length(s) for(n = 1; n <= v; n++) SUM[(n-1) % 20] += ORD[substr(s, n, 1)]-32 } function minuid_str(SUM, s ,n) { s = "Prm/" for(n = 0; n < 20; n++) s = s substr(BASE64, SUM[n] % 64, 1) return s } # Throw an error and exit function error(msg) { print "Error: " msg > "/dev/stderr" exit 1 } # return a if it is not empty, else return b function either(a, b) { return a != "" ? a : b } # strip leading/trailing whitespaces function strip(s) { sub("^[ \t\r\n]*", "", s) sub("[ \t\r\n]*$", "", s) return s } function lht_str(s) { if (s ~ "[^A-Za-z0-9 _-]") { gsub("}", "\\}", s) return "{" s "}" } return s } function unit(coord) { if (coord == "") coord = 0 if (base_unit_mm) return coord "mm" return coord "mil" } function subc_text(layer, x, y, str, scale, rot, flags, attributes ,s) { s = s " ha:text." (++objid) "{" NL s = s " scale = " either(scale, 100) NL if (attributes != "") s = s " ha:attributes {" attributes "}" NL s = s " x = " unit(x) NL s = s " y = " unit(y) NL s = s " rot = " either(rot, 0) NL if (str == "") str = "%a.parent.refdes%" s = s " string = " str NL s = s " fid = 0" NL s = s " ha:flags {" flags "}" NL s = s " }" NL LAYER[layer] = LAYER[layer] NL s } function subc_line(layer, x1, y1, x2, y2, thick, clr, flags, attributes ,s) { s = s " ha:line." (++objid) " {" NL s = s " x1 = " unit(x1) NL s = s " y1 = " unit(y1) NL s = s " x2 = " unit(x2) NL s = s " y2 = " unit(y2) NL s = s " thickness = " unit(either(thick, DEFAULT["line_thickness"])) NL s = s " clearance = " unit(either(clr, 0)) NL if (attributes != "") s = s " ha:attributes {" attributes "}" NL s = s " ha:flags {" flags "}" NL s = s " }" NL LAYER[layer] = LAYER[layer] NL s } function subc_arc(layer, cx, cy, r, a_start, a_delta, thick, clr, flags, attributes ,s) { s = s " ha:arc." (++objid) " {" NL s = s " x = " unit(cx) NL s = s " y = " unit(cy) NL s = s " astart = " a_start NL s = s " adelta = " a_delta NL s = s " thickness = " unit(either(thick, DEFAULT["line_thickness"])) NL s = s " clearance = " unit(either(clr, 0)) NL s = s " width = " unit(r) NL s = s " height = " unit(r) NL if (attributes != "") s = s " ha:attributes {" attributes "}" NL s = s " ha:flags {" flags "}" NL s = s " }" NL LAYER[layer] = LAYER[layer] NL s } function subc_rect(layer, x1, y1, x2, y2, clearance, flags, attributes ,s) { w = w/2 h = h/2 s = s " ha:polygon." (++objid) " {" NL s = s " clearance=" unit(clearance) NL s = s " li:geometry {" NL s = s " ta:contour {" NL s = s " { " unit(x1) "; " unit(y1) " }" NL s = s " { " unit(x2) "; " unit(y1) " }" NL s = s " { " unit(x2) "; " unit(y2) " }" NL s = s " { " unit(x1) "; " unit(y2) " }" NL s = s " }" NL s = s " }" NL s = s " ha:attributes {" attributes "}" NL s = s " ha:flags {" flags "}" NL s = s " }" NL LAYER[layer] = LAYER[layer] NL s } # POLY[] is an array indexed between 0 to 2*N-1 for a polygon of N # vertices, packed as x0;y0;x1;y1;x2;y2 ... xN;yN. The usual pcb-rnd # polygon rules apply: at least 3 vertices, no self-intersection. This # call does not make any attempt on cheking polygon validity. function subc_poly(layer, POLY, clearance, flags, attributes ,s,n) { w = w/2 h = h/2 s = s " ha:polygon." (++objid) " {" NL s = s " clearance=" unit(clearance) NL s = s " li:geometry {" NL s = s " ta:contour {" NL for(n = 0; (n in POLY); n += 2) s = s " { " unit(POLY[n]) "; " unit(POLY[n+1]) " }" NL s = s " }" NL s = s " }" NL s = s " ha:attributes {" attributes "}" NL s = s " ha:flags {" flags "}" NL s = s " }" NL LAYER[layer] = LAYER[layer] NL s } # reset a polygon so it has no vertices function poly_reset(POLY ,n) { for(n = 0; (n in POLY); n += 2) delete POLY[n] POLY["len"] = 0 } # append x;y to the end of a polygon's vertex list function poly_append(POLY, x, y) { POLY[POLY["len"]++] = x; POLY[POLY["len"]++] = y; } # start generating a subcircuit function subc_begin(footprint, refdes, refdes_x, refdes_y, refdes_dir, ATTR ,a) { print "li:pcb-rnd-subcircuit-v6 {" print " ha:subc." (++objid) "{" print " ha:attributes {" print " footprint = " lht_str(footprint) if (refdes != "") print " refdes = " lht_str(refdes) for(a in ATTR) print " " a " = " lht_str(ATTR[a]); print " }" subc_text("top-silk", refdes_x, refdes_y, "%a.parent.refdes%", 100, text_dir, "dyntext = 1;floater=1;") LAYER_TYPE["subc-aux"] = "top-misc-virtual" subc_line("subc-aux", -offs_x, -offs_y, -offs_x + mm(1), -offs_y, mm(0.1), 0, "", "subc-role = x"); subc_line("subc-aux", -offs_x, -offs_y, -offs_x, -offs_y + mm(1), mm(0.1), 0, "", "subc-role = y"); subc_line("subc-aux", -offs_x, -offs_y, -offs_x, -offs_y, mm(0.1), 0, "", "subc-role = origin"); } # generate subcircuit footers function subc_end( layer,n,v,L,lt,UID,lc) { minuid_add(UID, tolower(gen)) for(n in P) { minuid_add(UID, tolower(n)) minuid_add(UID, " " P[n]) } print " ha:data {" print " li:padstack_prototypes {" for(n = 0; n < proto_next_id; n++) { if (PROTO_COMMENT[n] != "") print PROTO_COMMENT[n] print " ha:ps_proto_v6." n " {" print PROTO[n] print " }" } print " }" # global objects (padstack refs) print " li:objects {" print globals print " }" # layers and layer objects print " li:layers {" for(layer in LAYER) { lt = either(LAYER_TYPE[layer], layer) v = split(lt, L, "-") print " ha:" layer " {" print " lid = 0" print " ha:type {" for(n = 1; n <= v; n++) if (L[n] != "") print " " L[n] " = 1" print " }" print " li:objects {" print LAYER[layer] print " }" print " ha:combining {" lc = LAYER_COMBINING[layer] if (lc != "") { v = split(lc, L, "-") for(n = 1; n <= v; n++) if (L[n] != "") print " " L[n] " = 1" } print " }" print " }" } print " }" print " }" print " uid = " minuid_str(UID) print " }" print "}" } # [pcb-rnd >= 3.1.2] # Optional helper function; call this to set up a layer. For the most usual # layers this is not required, simply naming them "top-coppe" or "bottom-silk" # would automatically create them. Setting up the layer is required if it has # a non-standard name or the combining flags (neg, auto) are non-zero. # Arguments: # - name: arbitrary but may contribute to binding score # - type is group type ("mask", "paste", "copper", "silk") # - loc is "top", "bottom" or "intern" # - neg is 0 or 1 (1 for sub (negatively drawn layers), e.g. mask; contributes to the combining field) # - auto is 0 or 1 (1 for setting the auto bit in the combining field) function layer_setup(name, loc, type, neg, auto) { if (!(name in LAYER)) LAYER[name] = "" LAYER_TYPE[name] = loc "-" type if (auto) LAYER_COMBINING[name] = "auto" if (neg) { if (LAYER_COMBINING[name] != "") LAYER_COMBINING[name] = LAYER_COMBINING[name] "-sub" else LAYER_COMBINING[name] = "sub" } } function subc_proto_alloc() { return proto_next_id++ } function subc_pstk_add_hole(proto, dia, plated, htop, hbottom ,s) { s = s " hdia = " unit(dia) NL s = s " hplated = " int(plated) NL s = s " htop = " int(htop) NL s = s " hbottom = " int(hbottom) NL PROTO[proto] = PROTO[proto] s PROTO_HOLE[proto] = dia } function subc_pstk_no_hole(proto ,s) { s = s " hdia = 0; hplated = 0; htop = 0; hbottom = 0" NL PROTO[proto] = PROTO[proto] s } function subc_pstk_shape_layer(layer ,s,L,v,n) { v = split(layer, L, "-") s = s " ha:layer_mask {" NL for(n = 1; n <= v; n++) s = s " " L[n] " = 1" NL s = s " }" NL s = s " ha:combining {" NL if (layer ~ "mask") s = s " sub = 1" NL if ((layer ~ "mask") || (layer ~ "paste")) s = s " auto = 1" NL s = s " }" NL return s } function subc_pstk_add_shape_circ(proto, layer, x, y, dia ,s) { s = s " ha:ps_shape_v4 {" NL s = s " clearance = 0" NL s = s " ha:ps_circ {" NL s = s " x = " unit(x) NL s = s " y = " unit(y) NL s = s " dia = " unit(dia) NL s = s " }" NL s = s subc_pstk_shape_layer(layer) s = s " }" NL PROTO[proto] = PROTO[proto] s } function subc_pstk_add_shape_square(proto, layer, x, y, sx, sy ,s) { # clamp at minimum to avoid broken polygons (can't do squares smaller than 4 nanometer) if (sx < 4) sx = 4; if (sy < 4) sy = 4; sx = sx / 2 sy = sy / 2 s = s " ha:ps_shape_v4 {" NL s = s " clearance = 0" NL s = s " li:ps_poly {" NL s = s " " unit(x - sx) ";" unit(y - sy) "; " unit(x + sx) ";" unit(y - sy) ";" NL s = s " " unit(x + sx) ";" unit(y + sy) "; " unit(x - sx) ";" unit(y + sy) ";" NL s = s " }" NL s = s subc_pstk_shape_layer(layer) s = s " }" NL PROTO[proto] = PROTO[proto] s } function subc_pstk_add_shape_square_corners(proto, layer, x1, y1, x2, y2 ,s) { sx = sx / 2 sy = sy / 2 s = s " ha:ps_shape_v4 {" NL s = s " clearance = 0" NL s = s " li:ps_poly {" NL s = s " " unit(x1) ";" unit(y1) "; " unit(x2) ";" unit(y1) ";" NL s = s " " unit(x2) ";" unit(y2) "; " unit(x1) ";" unit(y2) ";" NL s = s " }" NL s = s subc_pstk_shape_layer(layer) s = s " }" NL PROTO[proto] = PROTO[proto] s } function subc_pstk_add_shape_line(proto, layer, x1, y1, x2, y2, thick ,s) { s = s " ha:ps_shape_v4 {" NL s = s " clearance = 0" NL s = s " ha:ps_line {" NL s = s " x1=" unit(x1) "; y1=" unit(y1) "; x2=" unit(x2) "; y2=" unit(y2) ";" NL s = s " thickness=" unit(thick) "; square=0" NL s = s " }" NL s = s subc_pstk_shape_layer(layer) s = s " }" NL PROTO[proto] = PROTO[proto] s } # POLY[] is an array indexed between 0 to 2*N-1 for a polygon of N # vertices, packed as x0;y0;x1;y1;x2;y2 ... xN;yN. The usual pcb-rnd # polygon rules apply: at least 3 vertices, no self-intersection. This # call does not make any attempt on cheking polygon validity. function subc_pstk_add_shape_poly(proto, layer, POLY ,s,n) { s = s " ha:ps_shape_v4 {" NL s = s " clearance = 0" NL s = s " li:ps_poly {" NL for(n = 0; (n in POLY); n += 2) s = s " { " unit(POLY[n]) "; " unit(POLY[n+1]) " }" NL s = s " }" NL s = s subc_pstk_shape_layer(layer) s = s " }" NL PROTO[proto] = PROTO[proto] s } function subc_pstk_add_shape_hshadow(proto, layer ,s) { s = s " ha:ps_shape_v4 {" NL s = s " clearance = 0" NL s = s " ps_hshadow = {}" NL s = s subc_pstk_shape_layer(layer) s = s " }" NL PROTO[proto] = PROTO[proto] s } function subc_proto_create_pin_round(drill_dia, ring_dia, mask_dia ,proto) { proto = subc_proto_alloc() subc_pstk_add_hole(proto, either(drill_dia, DEFAULT["pin_drill"]), 1) PROTO_COMMENT[proto] = "# Round plated through hole " unit(ring_dia) "/" unit(drill_dia) PROTO[proto] = PROTO[proto] " li:shape {" NL ring_dia = either(ring_dia, DEFAULT["pin_ringdia"]) subc_pstk_add_shape_circ(proto, "top-copper", x, y, ring_dia) subc_pstk_add_shape_circ(proto, "intern-copper", x, y, ring_dia) subc_pstk_add_shape_circ(proto, "bottom-copper", x, y, ring_dia) mask_dia = pin_mask(ring_dia, mask_dia) subc_pstk_add_shape_circ(proto, "top-mask", x, y, mask_dia) subc_pstk_add_shape_circ(proto, "bottom-mask", x, y, mask_dia) PROTO[proto] = PROTO[proto] " }" NL return proto } function subc_proto_create_pin_square(drill_dia, ring_span, mask_span ,proto) { proto = subc_proto_alloc() subc_pstk_add_hole(proto, either(drill_dia, DEFAULT["pin_drill"]), 1) PROTO_COMMENT[proto] = "# Square plated through hole " unit(ring_dia) "/" unit(drill_dia) PROTO[proto] = PROTO[proto] " li:shape {" NL ring_span = either(ring_span, DEFAULT["pin_ringdia"]) subc_pstk_add_shape_square(proto, "top-copper", x, y, ring_span, ring_span) subc_pstk_add_shape_square(proto, "intern-copper", x, y, ring_span, ring_span) subc_pstk_add_shape_square(proto, "bottom-copper", x, y, ring_span, ring_span) mask_span = pin_mask(ring_span, mask_dia) subc_pstk_add_shape_square(proto, "top-mask", x, y, mask_span, mask_span) subc_pstk_add_shape_square(proto, "bottom-mask", x, y, mask_span, mask_span) PROTO[proto] = PROTO[proto] " }" NL return proto } function paste_or_mask_abs(copper, absval, offsval, ratio, prefix) { if (absval != "") return absval if (offsval != 0) return copper+offsval if ((ratio != 0) && (ratio != "")) return copper*ratio if ((DEFAULT[prefix] != "") && (DEFAULT[prefix] != "-") && (DEFAULT[prefix]+0 > 0)) return DEFAULT[prefix] if ((DEFAULT[prefix "_offs"] != "") && (DEFAULT[prefix "_offs"] != "-")) return copper+DEFAULT[prefix "_offs"]*2 if ((DEFAULT[prefix "_ratio"] != "") && (DEFAULT[prefix "_ratio"] != "-")) return copper*DEFAULT[prefix "_ratio"] return copper } function pad_paste(copper, absval, offsval, ratio) { return paste_or_mask_abs(copper, absval, offsval, ratio, "pad_paste") } function pad_mask(copper, absval, offsval, ratio) { return paste_or_mask_abs(copper, absval, offsval, ratio, "pad_mask") } function pin_mask(copper, absval, offsval, ratio) { return paste_or_mask_abs(copper, absval, offsval, ratio, "pin_mask") } function pad_paste_offs(offsval ,copper) { copper = DEFAULT["pad_thickness"] return paste_or_mask_abs(copper, "", offsval, "", "pad_paste") - copper } function pad_mask_offs(offsval ,copper) { copper = DEFAULT["pad_thickness"] return paste_or_mask_abs(copper, "", offsval, "", "pad_mask") - copper } function subc_proto_create_pad_sqline(x1, x2, thick, mask, paste ,proto,m,p) { proto = subc_proto_alloc() thick = either(thick, DEFAULT["pad_thickness"]) if (thick < 0.01) thick = 0.01; subc_pstk_no_hole(proto) PROTO_COMMENT[proto] = "# Square smd pad " x2-x1 " * " thick PROTO[proto] = PROTO[proto] " li:shape {" NL subc_pstk_add_shape_square_corners(proto, "top-copper", x1-thick/2, -thick/2, x2+thick/2, thick/2) m = (pad_mask(thick, mask)-thick)/2 if (+thick/2+m > 0) subc_pstk_add_shape_square_corners(proto, "top-mask", x1-thick/2-m, -thick/2-m, x2+thick/2+m, thick/2+m) p = (pad_paste(thick, paste)-thick)/2 if (+thick/2+p > 0) subc_pstk_add_shape_square_corners(proto, "top-paste", x1-thick/2-p, -thick/2-p, x2+thick/2+p, thick/2+p) PROTO[proto] = PROTO[proto] " }" NL return proto } function subc_proto_create_pad_line(x1, x2, thick, mask, paste ,proto,m,p) { proto = subc_proto_alloc() thick = either(thick, parse_dim(DEFAULT["pad_thickness"])) if (thick < 0.01) thick = 0.01; subc_pstk_no_hole(proto) PROTO_COMMENT[proto] = "# Square smd pad " x2-x1 " * " thick PROTO[proto] = PROTO[proto] " li:shape {" NL subc_pstk_add_shape_line(proto, "top-copper", x1, 0, x2, 0, thick) subc_pstk_add_shape_line(proto, "top-mask", x1, 0, x2, 0, pad_mask(thick, mask)) subc_pstk_add_shape_line(proto, "top-paste", x1, 0, x2, 0, pad_paste(thick, paste)) PROTO[proto] = PROTO[proto] " }" NL return proto } function subc_proto_create_pad_rect(w, h, mask_offs, paste_offs ,proto,m,p) { proto = subc_proto_alloc() subc_pstk_no_hole(proto) PROTO_COMMENT[proto] = "# Square smd pad " w " * " h PROTO[proto] = PROTO[proto] " li:shape {" NL w = w/2 h = h/2 subc_pstk_add_shape_square_corners(proto, "top-copper", -w, -h, +w, +h) if (mask_offs != "none") { m = pad_mask_offs(mask_offs) / 2 subc_pstk_add_shape_square_corners(proto, "top-mask", -w-m, -h-m, +w+m, +h+m) } if (paste_offs != "none") { p = pad_paste_offs(paste_offs) / 2 subc_pstk_add_shape_square_corners(proto, "top-paste", -w-p, -h-p, +w+p, +h+p) } PROTO[proto] = PROTO[proto] " }" NL return proto } function subc_proto_create_pad_circle(dia, mask_dia, paste_dia ,proto) { proto = subc_proto_alloc() subc_pstk_no_hole(proto) dia = either(dia, DEFAULT["pad_dia"]) PROTO_COMMENT[proto] = "# Circular smd pad " unit(dia) PROTO[proto] = PROTO[proto] " li:shape {" NL subc_pstk_add_shape_circ(proto, "top-copper", 0, 0, dia) mask_dia = either(mask_dia, DEFAULT["pad_mask_dia"]) subc_pstk_add_shape_circ(proto, "top-mask", 0, 0, mask_dia) paste_dia = either(paste_dia, DEFAULT["pad_paste_dia"]) subc_pstk_add_shape_circ(proto, "top-paste", 0, 0, paste_dia) PROTO[proto] = PROTO[proto] " }" NL return proto } # generate a padstack reference function subc_pstk(proto, x, y, rot, termid, name, clearance, s) { if (termid == "") termid = ++pin_number s = s " ha:padstack_ref." (++objid) " {" NL s = s " proto = " proto NL s = s " x = " unit(x) NL s = s " y = " unit(y) NL s = s " rot = " rot+0 NL s = s " smirror = 0; xmirror = 0" NL s = s " clearance = " unit(either(clearance, (PROTO_HOLE[proto] > 0 ? DEFAULT["pin_clearance"] : DEFAULT["pad_clearance"]))/2) NL s = s " ha:attributes {" NL s = s " term = " termid NL if (name != "") s = s " name = " name NL s = s " }" NL s = s " li:thermal { }" NL s = s " ha:flags { clearline = 1; }" NL s = s " }" NL globals = globals NL s } # draw element pad function subc_pad(x1, y1, x2, y2, thickness, number, flags, clearance, mask, name) { print " Pad[", x1, y1, x2, y2, int(either(thickness, DEFAULT["pad_thickness"])), int(either(clearance, DEFAULT["pad_clearance"])), int(either(mask, DEFAULT["pad_mask"])), q name q, q number q, q flags q "]" } # draw element pad - no thickness, but exact corner coordinates given function subc_pad_rectangle(x1, y1, x2, y2, number, flags, clearance, mask, name, th,dx,dy,cx,cy) { if (x2 < x1) { th = x2 x2 = x1 x1 = th } if (y2 < y1) { th = y2 y2 = y1 y1 = th } dx = x2-x1 dy = y2-y1 if (dx >= dy) { th = dy cy = (y1+y2)/2 print " Pad[", x1+th/2, cy, x2-th/2, cy, th, int(either(clearance, DEFAULT["pad_clearance"])), int(either(mask, DEFAULT["pad_mask"])), q name q, q number q, q flags q "]" } else { th = dx cx = (x1+x2)/2 print " Pad[", cx, y1+th/2, cx, y2-th/2, th, int(either(clearance, DEFAULT["pad_clearance"])), int(either(mask, DEFAULT["pad_mask"])), q name q, q number q, q flags q "]" } } # draw element pad circle function subc_pad_circle(x1, y1, radius, number, clearance, mask, name) { print " Pad[", x1, y1, x1, y1, int(either(radius, DEFAULT["pad_thickness"])), int(either(clearance, DEFAULT["pad_clearance"])), int(either(mask, DEFAULT["pad_mask"])), q name q, q number q, q "" q "]" } function subc_arrow(layer, x1, y1, x2, y2, asize, thickness ,vx,vy,nx,ny,len,xb,yb) { subc_line(layer, x1, y1, x2,y2, thickness) if (asize == 0) asize = mil(20) vx = x2-x1 vy = y2-y1 len = sqrt(vx*vx+vy*vy) if (len != 0) { vx /= len vy /= len nx = vy ny = -vx xb = x2 - vx*asize yb = y2 - vy*asize # subc_line(layer, x2, y2, xb + 1000, yb + 1000) subc_line(layer, x2, y2, xb + nx*asize/2, yb + ny*asize/2) subc_line(layer, x2, y2, xb - nx*asize/2, yb - ny*asize/2) subc_line(layer, xb - nx*asize/2, yb - ny*asize/2, xb + nx*asize/2, yb + ny*asize/2) } } # draw a rectangle of silk lines # omit sides as requested in omit # if r is non-zero, round corners - omit applies as NW, NW, SW, SE # if omit includes "arc", corners are "rounded" with lines function subc_rectangle(layer, x1, y1, x2, y2, omit, r, thickness ,tmp,r1,r2) { # order coords for round corners if (x1 > x2) { tmp = x1 x1 = x2 x2 = tmp } if (y1 > y2) { tmp = y1 y1 = y2 y2 = tmp } if (!(omit ~ "left")) { r1 = (omit ~ "NW") ? 0 : r r2 = (omit ~ "SW") ? 0 : r subc_line(layer, x1, y1+r1, x1, y2-r2, thickness) } if (!(omit ~ "top")) { r1 = (omit ~ "NW") ? 0 : r r2 = (omit ~ "NE") ? 0 : r subc_line(layer, x1+r1, y1, x2-r2, y1, thickness) } if (!(omit ~ "bottom")) { r1 = (omit ~ "SE") ? 0 : r r2 = (omit ~ "SW") ? 0 : r subc_line(layer, x2-r1, y2, x1+r2, y2, thickness) } if (!(omit ~ "right")) { r1 = (omit ~ "SE") ? 0 : r r2 = (omit ~ "NE") ? 0 : r subc_line(layer, x2, y2-r1, x2, y1+r2, thickness) } if (r > 0) { if (omit ~ "arc") { if (!(omit ~ "NW")) subc_line(layer, x1, y1+r, x1+r, y1) if (!(omit ~ "SW")) subc_line(layer, x1, y2-r, x1+r, y2) if (!(omit ~ "NE")) subc_line(layer, x2, y1+r, x2-r, y1) if (!(omit ~ "SE")) subc_line(layer, x2, y2-r, x2-r, y2) } else { if (!(omit ~ "NW")) subc_arc(layer, x1+r, y1+r, r, 270, 90) if (!(omit ~ "SW")) subc_arc(layer, x1+r, y2-r, r, 0, 90) if (!(omit ~ "NE")) subc_arc(layer, x2-r, y1+r, r, 180, 90) if (!(omit ~ "SE")) subc_arc(layer, x2-r, y2-r, r, 90, 90) } } } # draw a rectangle corners of silk lines, wx and wy long in x and y directions # omit sides as requested in omit: NW, NW, SW, SE # corners are always sharp function subc_rectangle_corners(layer, x1, y1, x2, y2, wx, wy, omit, thickness ,tmp) { if (!(omit ~ "NW")) { subc_line(layer, x1, y1, x1+wx, y1, thickness) subc_line(layer, x1, y1, x1, y1+wy, thickness) } if (!(omit ~ "NE")) { subc_line(layer, x2-wx, y1, x2, y1, thickness) subc_line(layer, x2, y1, x2, y1+wy, thickness) } if (!(omit ~ "SW")) { subc_line(layer, x1, y2, x1+wx, y2, thickness) subc_line(layer, x1, y2-wy, x1, y2, thickness) } if (!(omit ~ "SE")) { subc_line(layer, x2-wx, y2, x2, y2, thickness) subc_line(layer, x2, y2-wy, x2, y2, thickness) } } # convert coord given in mils to footprint units function mil(coord) { if (base_unit_mm) return coord / 39.3701 else return coord } # reverse mil(): converts footprint units back to mil function rev_mil(coord) { if (base_unit_mm) return coord * 39.3701 else return coord } # convert coord given in mm to footprint units function mm(coord) { if (base_unit_mm) return coord else return coord * 39.3701 } # reverse mm(): converts footprint units back to mm function rev_mm(coord) { if (base_unit_mm) return coord else return coord / 39.3701 } function set_arg_(OUT, key, value, strength) { if (OUT[key, "strength"] > strength) return OUT[key] = value OUT[key, "strength"] = strength } # set parameter key=value with optioal strength (s_* consts) in array OUT[] # set only if current strength is stronger than the original value # if key starts with a "?", use s_weak # if key is in DEFAULT[], use DEFAULT[] instead of OUT[] function set_arg(OUT, key, value ,strength) { if (strength == "") strength = s_explicit if (key ~ "^[?]") { sub("^[?]", "", key) strength = s_weak } if (key in DEFAULT) { if (DEFAULT[key, "dim"]) value = parse_dim_(value, 0) set_arg_(DEFAULT, key, value, strength) } else set_arg_(OUT, key, value, strength) } # Process a generator argument list from arg_names. Save the result in # array OUT. If mandatory is specified, check whether all mandatory # parameters are specified # Both arg_names and mandatory are comma separated list of argument names function proc_args(OUT, arg_names, mandatory, N,A,M,v,n,key,val,pos) { gsub(" ", "", arg_names) gsub(" ", "", mandatory) split(arg_names, N, ",") v = split(args, A, ",") # fill in all named and positional arguments pos = 1 for(n = 1; n <= v; n++) { A[n] = strip(A[n]) if (A[n] == "") continue if (A[n] ~ "=") { # named key=A[n] val=A[n] sub("=.*", "", key) sub("^[^=]*=", "", val) set_arg(OUT, key, val, s_explicit) } else { # positional if (N[pos] == "") { error("too many positional arguments at " A[n]) } while((N[pos] in OUT) && (N[pos, "strength"] == s_explicit)) pos++ set_arg(OUT, N[pos], A[n], s_explicit) pos++ } } # check whether all mandatory arguments are specified v = split(mandatory, M, ",") for(n = 1; n <= v; n++) { if (!(M[n] in OUT)) { error("missing argument " M[n] " (or positional " n ")") exit 1 } } } function parse_dim_(h, fallback_mil) { if (h == "") return "" if (h ~ "mm$") { sub("mm", "", h) return mm(h) } if (h ~ "um$") { sub("um", "", h) return mm(h)/1000 } if (h ~ "nm$") { sub("nm", "", h) return mm(h)/1000000 } if (h ~ "cm$") { sub("cm", "", h) return mm(h)*10 } if (h ~ "m$") { sub("m", "", h) return mm(h)*1000 } if (h ~ "km$") { sub("km", "", h) return mm(h)*1000000 } if (h ~ "in$") { sub("in", "", h) return mil(h)*1000 } if (h ~ "dmil$") { sub("dmil", "", h) return mil(h)/10 } if (h ~ "cmil$") { sub("cmil", "", h) return mil(h)/100 } if (h ~ "mil$") { sub("mil", "", h) return mil(h) } if (fallback_mil) return mil(h) else return h } # Assume h is a dimension and convert it function parse_dim(h) { return parse_dim_(h, 1) } # Draw a DIP outline: useful for any rectangular package with a little # half circle centered on the top line # arcr: radius of the half circle # xhalf: optional coordinate where the circle should be put function dip_outline(layer, x1, y1, x2, y2, arcr ,xhalf) { if (xhalf == "") xhalf=(x1+x2)/2 subc_rectangle(layer, x1, y1, x2, y2, "top") subc_line(layer, x1, y1, xhalf-arcr, y1) subc_line(layer, xhalf+arcr, y1, x2, y1) subc_arc(layer, xhalf, y1, arcr, 0, 180) } # decide whether x is true or false # returns 1 if true # returns 0 if false function tobool(x) { if (x == int(x)) return (int(x) != 0) x = tolower(x) return (x == "true") || (x == "yes") || (x == "on") } # default pin1 mark on a box # style: mark style, ":" separated list # x,y: the coordinates of the origin corner (top-left) # half: half the stepping of the pin grid - the size of the mark # step: optional size of the external arrow or square (defaults to 2*half) function silkmark(style, x, y, half, step, S,n,v,r) { if (step == "") step = half*2 r = step if (r < 5) r = 5; v = split(style, S, ":") for(n = 1; n <= v; n++) { if (S[n] == "angled") { subc_line("top-silk", x+half, y, x, y+half) } else if (S[n] == "square") { subc_line("top-silk", x, y+step, x+2*half, y+step) subc_line("top-silk", x+step, y, x+2*half, y+step) } else if ((S[n] == "external") || (S[n] == "externalx")) { subc_line("top-silk", x, y+half, x-step+half, y+half/2) subc_line("top-silk", x, y+half, x-step+half, y+half*1.5) subc_line("top-silk", x-step+half, y+half/2, x-step+half, y+half*1.5) } else if (S[n] == "externaly") { subc_line("top-silk", x+half, y, x-half/2+half, y-step+half) subc_line("top-silk", x+half, y, x+half/2+half, y-step+half) subc_line("top-silk", x-half/2+half, y-step+half, x+half/2+half, y-step+half) } else if (S[n] == "external45") { subc_line("top-silk", x, y, x-half, y-half/3) subc_line("top-silk", x, y, x-half/3, y-half) subc_line("top-silk", x-half, y-half/3, x-half/3, y-half) } else if (S[n] == "arc") { subc_arc("top-silk", x, y, r/2, 180, 270) } else if (S[n] == "circle") { subc_arc("top-silk", x, y, r/2, 0, 360) } else if (S[n] == "dot") { subc_arc("top-silk", x-step/2, y-step/2, r/4, 0, 360) } else if ((S[n] != "none") && (S[n] != "")) { error("invalid silkmark parameter: " S[n]) } } } function center_pad_init() { cpm_width = parse_dim(P["cpm_width"]) cpm_height = parse_dim(P["cpm_height"]) cpm_nx = int(P["cpm_nx"]) cpm_ny = int(P["cpm_ny"]) } # draw a matrix of paste rectangles; top-left corner is x1;y1, there are nx*ny # rectangles of w*h size. rows/cols of pads are drawn with ox and oy offset function paste_matrix(x1, y1, nx, ny, w, h, ox, oy, flags, attrbiutes, clearance, ix,iy) { for(iy = 0; iy < ny; iy++) for(ix = 0; ix < nx; ix++) subc_rect("top-paste", x1+ix*ox, y1+iy*oy, x1+ix*ox+w, y1+iy*oy+h, clearance, flags, attributes) } function center_pad(cpadid, cpx, cpy) { if ((cpad_width != "") && (cpad_height != "")) { # center pad paste matrix if ((cpm_nx > 0) && (cpm_ny > 0)) { ox = (cpad_width - (cpm_nx*cpm_width)) / (cpm_nx - 1) oy = (cpad_height - (cpm_ny*cpm_height)) / (cpm_ny - 1) paste_matrix(cpx-cpad_width/2, xpy-cpad_height/2, cpm_nx,cpm_ny, cpm_width,cpm_height, ox+cpm_width,oy+cpm_height, "", "termid=" cpadid ";", 0) } # center pad cpad_proto = subc_proto_create_pad_rect(cpad_width, cpad_height, cpad_mask == "" ? 0 : cpad_mask, "none") subc_pstk(cpad_proto, cpx, cpy, 0, cpadid) dimension(cpx-cpad_width/2, cpy-cpad_height/2, cpx+cpad_width/2, cpy-cpad_height/2, "@0;" (height * -0.6-ext_bloat), "cpad_width") dimension(cpx+cpad_width/2, cpy-cpad_height/2, cpx+cpad_width/2, cpy+cpad_height/2, "@" (width * 0.8+ext_bloat) ";0", "cpad_height") } } # output a dimension specification between x1;y1 and x2;y2, text distance at dist # for a name,value pair # if name is empty, only value is printed # if value is empty, it's calculated # if only name should be printed, value should be "!" # if dist starts with a "@", it's the absolute coordinate of the center of the dim line (text base), else it's relative distance from the measured line function dimension(x1, y1, x2, y2, dist, name, value, vx,vy) { print "#dimension", x1, y1, x2, y2, dist, name, value } function help_extract(SEEN, fn, dirn, OVER, IGN, WANT,tmp,key,val,i,skip) { if (fn in SEEN) return SEEN[fn]++ print "#@@info-gen-extract " fn close(fn) while((getline line < fn) > 0) { if (line ~ "^#@@include") { sub("^#@@include[ \t]*", "", line) tmp = dirn "/" line WANT[tmp]++ } else if (line ~ "^#@@over@ignore") { key = line sub("^#@@over@ignore:", "", key) sub(" .*", "", key) IGN[key] = 1 } else if (line ~ "^#@@over@") { key = line sub("^#@@over@", "", key) val = "#@@" key sub(" .*", "", key) OVER[key] = val } else if (line ~ "^#@@") { key = line sub("^#@@", "", key) sub(" .*", "", key) skip = 0 for(i in IGN) { if (key ~ i) skip = 1 } if (skip) continue if (key in OVER) { print OVER[key] OVER[key "::PRINTED"] = 1 } else print line } } close(fn) for(tmp in WANT) help_extract(SEEN, tmp, dirn, OVER, IGN) } function help_print( SEEN, OVER, dirn, k) { print "#@@info-generator pcb-rnd common_subc.awk" dirn = genfull sub("/[^/]*$", "", dirn) help_extract(SEEN, genfull, dirn, OVER) for(k in OVER) { if (!(k ~ "::PRINTED$") && !((k "::PRINTED") in OVER)) print OVER[k] } } function help_auto() { if ((args ~ "^--help") || (args ~ ",[ \t]*--help")) { help_print() exit(0) } }