view pads2gpcb/decals.c @ 139:bf188727e606

donl-rename-parts reader: no tEDAx-style escapes
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 07 Sep 2020 04:25:11 +0000
parents f673b6ad2a78
children
line wrap: on
line source

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include "globals.h"
#include "struct.h"

extern long convert_input_dim();

static struct part_decal *current_decal;
static struct footprint_body fpbody;
static struct footprint_pad *pins_array;

#define	MAX_SILK_LINES	64
static struct element_line silk_lines[MAX_SILK_LINES];
static struct element_arc silk_arcs[MAX_SILK_LINES];
static int num_silk_lines;
static int num_silk_arcs;

static void
enter_decal()
{
	struct part_decal *p, **pp;
	char *name = input_line_fields[0];

	for (pp = &part_decal_list; p = *pp; pp = &p->next)
		if (!strcmp(p->name, name)) {
			fprintf(stderr,
			"%s line %d: decal name \"%s\" already defined\n",
				input_filename, input_lineno, name);
			exit(1);
		}
	p = malloc(sizeof(struct part_decal) + strlen(name) + 1);
	if (!p) {
		perror("malloc of struct part_decal");
		exit(1);
	}
	p->name = (char *)(p + 1);
	strcpy(p->name, name);
	p->body = 0;
	p->next = 0;
	*pp = p;
	current_decal = p;
}

static void
get_line_internal()
{
	if (!get_input_line()) {
		fprintf(stderr,
		      "error: EOF in the middle of a part decal definition\n");
		exit(1);
	}
}

static
drawpiece_silk_candidate()
{
	int level;

	if (input_line_nfields != 5)
		return(0);
	level = atoi(input_line_fields[4]);
	return is_drawlevel_selected(level);
}

static
try_silk_open_closed()
{
	int ncoord, i, bad;
	struct coord_pair coord[MAX_SILK_LINES+1];
	long thickness;

	if (strcmp(input_line_fields[0], "OPEN") &&
	    strcmp(input_line_fields[0], "CLOSED"))
		return(0);
	ncoord = atoi(input_line_fields[1]);
	if (ncoord < 2) {
		printf("line %d: silk %s piece ncoord < 2\n", input_lineno,
			input_line_fields[0]);
		return(0);
	}
	if (ncoord > MAX_SILK_LINES + 1) {
		printf("line %d: silk %s piece ncoord too big\n", input_lineno,
			input_line_fields[0]);
		return(0);
	}
	thickness = convert_input_dim(input_line_fields[2]);

	bad = 0;
	for (i = 0; i < ncoord; i++) {
		get_line_internal();
		parse_input_line_fields();
		if (input_line_nfields != 2) {
			printf("line %d: silk line coord not 2 numbers\n",
				input_lineno);
			bad = 1;
			continue;
		}
		coord[i].x = convert_input_dim(input_line_fields[0]);
		coord[i].y = convert_input_dim(input_line_fields[1]);
	}
	if (bad)
		return(1);

	for (i = 0; i < ncoord - 1; i++) {
		if (num_silk_lines >= MAX_SILK_LINES) {
			printf("Too many silk lines!\n");
			return(1);
		}
		silk_lines[num_silk_lines].end1 = coord[i];
		silk_lines[num_silk_lines].end2 = coord[i+1];
		silk_lines[num_silk_lines].thickness = thickness;
		num_silk_lines++;
	}
	return(1);
}

static
try_silk_circle()
{
	int i, bad;
	struct coord_pair coord[2], centre;
	long diameter, thickness;

	if (strcmp(input_line_fields[0], "CIRCLE"))
		return(0);
	if (strcmp(input_line_fields[1], "2")) {
		printf("line %d: silk CIRCLE piece ncoord != 2\n",
			input_lineno);
		return(0);
	}
	thickness = convert_input_dim(input_line_fields[2]);

	bad = 0;
	for (i = 0; i < 2; i++) {
		get_line_internal();
		parse_input_line_fields();
		if (input_line_nfields != 2) {
			printf("line %d: silk CIRCLE coord not 2 numbers\n",
				input_lineno);
			bad = 1;
			continue;
		}
		coord[i].x = convert_input_dim(input_line_fields[0]);
		coord[i].y = convert_input_dim(input_line_fields[1]);
	}
	if (bad)
		return(1);

	/* find the centre and diameter */
	if (coord[0].x == coord[1].x) {
		centre.x = coord[0].x;
		if (coord[0].y < coord[1].y) {
			diameter = coord[1].y - coord[0].y;
			centre.y = coord[0].y + diameter / 2;
		} else if (coord[1].y < coord[0].y) {
			diameter = coord[0].y - coord[1].y;
			centre.y = coord[1].y + diameter / 2;
		} else
			goto centre_diam_fail;
	} else if (coord[0].y == coord[1].y) {
		centre.y = coord[0].y;
		if (coord[0].x < coord[1].x) {
			diameter = coord[1].x - coord[0].x;
			centre.x = coord[0].x + diameter / 2;
		} else if (coord[1].x < coord[0].x) {
			diameter = coord[0].x - coord[1].x;
			centre.x = coord[1].x + diameter / 2;
		} else
			goto centre_diam_fail;
	} else {
centre_diam_fail:
		printf("line %d: unable to find circle centre and diameter\n",
			input_lineno);
		return(1);
	}
	if (diameter % 2)
		printf("warning: line %d: circle diameter in nm is odd!\n",
			input_lineno);

	if (num_silk_arcs >= MAX_SILK_LINES) {
		printf("Too many silk arcs!\n");
		return(1);
	}
	silk_arcs[num_silk_arcs].centre = centre;
	silk_arcs[num_silk_arcs].width = diameter / 2;
	silk_arcs[num_silk_arcs].height = diameter / 2;
	silk_arcs[num_silk_arcs].start_angle = 0;
	silk_arcs[num_silk_arcs].delta_angle = 360;
	silk_arcs[num_silk_arcs].thickness = thickness;
	num_silk_arcs++;
	return(1);
}

static void
one_drawing_piece()
{
	int ncoord, i;

	/* extract silk lines and arcs if enabled, otherwise skip */
	get_line_internal();
	parse_input_line_fields();
	if (input_line_nfields < 2) {
		fprintf(stderr,
		"%s line %d: expected piece header line giving # of coords\n",
			input_filename, input_lineno);
		exit(1);
	}
	if (do_footprint_silk && drawpiece_silk_candidate()) {
		if (try_silk_open_closed())
			return;
		if (try_silk_circle())
			return;
	}
	ncoord = atoi(input_line_fields[1]);
	for (i = 0; i < ncoord; i++)
		get_line_internal();
}

static void
one_text_item()
{
	/* just skip it for now */
	get_line_internal();
	get_line_internal();
	get_line_internal();
}

static void
one_attr_label()
{
	/* just skip it for now */
	get_line_internal();
	get_line_internal();
	get_line_internal();
}

static void
read_pindef_line(idx)
{
	get_line_internal();
	if (input_line_buf[0] != 'T') {
		fprintf(stderr, "%s line %d: 'T' line expected\n",
			input_filename, input_lineno);
		exit(1);
	}
	parse_input_line_fields();
	if (input_line_nfields != 5) {
		fprintf(stderr, "%s line %d: expected 5 fields in 'T' line\n",
			input_filename, input_lineno);
		exit(1);
	}
	input_line_fields[0]++;

	if (atoi(input_line_fields[4]) != idx + 1) {
		fprintf(stderr,
			"%s line %d: expected %d in the pin number field\n",
			input_filename, input_lineno);
		exit(1);
	}
	pins_array[idx].end1.x = convert_input_dim(input_line_fields[0]);
	pins_array[idx].end1.y = convert_input_dim(input_line_fields[1]);
}

static void
process_pad_shape(padptr)
	struct pad_shape_info *padptr;
{
	padptr->short_dim = convert_input_dim(input_line_fields[1]);
	if (padptr->short_dim <= 0) {
		printf("line %d: pad short dim <= 0\n", input_lineno);
		return;
	}
	if (!strcmp(input_line_fields[2], "R")) {
		padptr->rounded = 1;
		padptr->elongated = 0;
	} else if (!strcmp(input_line_fields[2], "S")) {
		padptr->rounded = 0;
		padptr->elongated = 0;
	} else if (!strcmp(input_line_fields[2], "OF")) {
		padptr->rounded = 1;
		padptr->elongated = 1;
	} else if (!strcmp(input_line_fields[2], "RF")) {
		padptr->rounded = 0;
		padptr->elongated = 1;
	} else {
		printf("line %d: unsupported pad shape %s\n", input_lineno,
			input_line_fields[2]);
		return;
	}
	if (padptr->elongated) {
		if (input_line_nfields < 6) {
			fprintf(stderr,
			"%s line %d: too few fields in OF/RF pad stack line\n",
				input_filename, input_lineno);
			exit(1);
		}
		padptr->angle = parse_input_angle_90s(input_line_fields[3]);
		if (padptr->angle != 0 && padptr->angle != 90) {
			printf("line %d: unsupported OF/RF angle\n",
				input_lineno);
			return;
		}
		padptr->long_dim = convert_input_dim(input_line_fields[4]);
		if (strcmp(input_line_fields[5], "0")) {
			printf("line %d: unsupported nonzero finoffset\n",
				input_lineno);
			return;
		}
		if (padptr->long_dim <= padptr->short_dim) {
			printf("line %d: OF/RF long dim <= short dim\n",
				input_lineno);
			return;
		}
	}
	padptr->valid = 1;
}

static void
one_padstack_def()
{
	int pinno, stacklines, i;
	struct pad_shape_info *padptr;

	get_line_internal();
	parse_input_line_fields();
	if (input_line_nfields != 3 || strcmp(input_line_fields[0], "PAD")) {
		fprintf(stderr, "%s line %d: expected PAD header line\n",
			input_filename, input_lineno);
		exit(1);
	}
	pinno = atoi(input_line_fields[1]);
	stacklines = atoi(input_line_fields[2]);

	if (pinno < 0 || pinno > fpbody.npins) {
		fprintf(stderr, "%s line %d: PAD pinno field invalid\n",
			input_filename, input_lineno);
		exit(1);
	}
	if (pinno)
		padptr = &pins_array[pinno-1].shape;
	else
		padptr = &fpbody.default_pad;
	padptr->defined = 1;

	for (i = 0; i < stacklines; i++) {
		get_line_internal();
		parse_input_line_fields();
		if (input_line_nfields < 3) {
			fprintf(stderr,
			"%s line %d: too few fields in pad stack line\n",
				input_filename, input_lineno);
			exit(1);
		}
		if (!strcmp(input_line_fields[0], "-2"))
			process_pad_shape(padptr);
	}
}

static void
apply_default_padstack()
{
	int i;

	if (!fpbody.default_pad.valid)
		return;
	for (i = 0; i < fpbody.npins; i++)
		if (!pins_array[i].shape.defined)
			pins_array[i].shape = fpbody.default_pad;
}

static
convert_pad_to_gpcb(pinidx)
{
	struct footprint_pad *pin = pins_array + pinidx;
	long long_minus_short, delta;

	if (!pin->shape.valid) {
		printf("error: no pad shape for pin #%d\n", pinidx + 1);
		return(-1);
	}
	pin->thickness = pin->shape.short_dim;
	pin->clearance = clearance_setting;
	pin->mask = pin->thickness + soldermask_delta;
	pin->end2 = pin->end1;
	if (!pin->shape.elongated)
		return(0);
	long_minus_short = pin->shape.long_dim - pin->shape.short_dim;
	delta = long_minus_short / 2;
	switch (pin->shape.angle) {
	case 0:
		pin->end1.x -= delta;
		pin->end2.x += delta;
		return(0);
	case 90:
		pin->end1.y -= delta;
		pin->end2.y += delta;
		return(0);
	}
	return(-1);
}

static void
write_decal_as_element()
{
	char *filename, *cp, *dp;
	int c;
	FILE *outf;

	filename = malloc(strlen(current_decal->name) * 3 + 8);
	if (!filename) {
		perror("malloc for output file name");
		exit(1);
	}
	strcpy(filename, "decals/");
	dp = filename + 7;
	for (cp = current_decal->name; *cp; ) {
		c = *cp++;
		if (isalnum(c) || c == '-' || c == '.' || c == '_')
			*dp++ = c;
		else {
			sprintf(dp, "%%%02X", c);
			dp += 3;
		}
	}
	*dp = '\0';
	outf = fopen(filename, "w");
	if (!outf) {
		perror(filename);
		exit(1);
	}
	write_gpcb_element(outf, current_decal->body, 0, "", "", "", 0);
	fclose(outf);
	printf("Written to %s\n", filename);
	free(filename);
}

static void
process_one_decal()
{
	int num_drawing_pieces, num_padstack_defs;
	int num_text_items, num_attr_labels;
	int i, valid;

	if (input_line_nfields < 7 || input_line_nfields > 9) {
		fprintf(stderr,
"%s line %d: expected beginning of part decal definition, wrong # of fields\n",
			input_filename, input_lineno);
		exit(1);
	}
	enter_decal();
	printf("Processing decal %s\n", current_decal->name);
	bzero(&fpbody, sizeof fpbody);
	if (input_line_fields[1][0] != 'I' && input_line_fields[1][0] != 'M'
	    || input_line_fields[1][1]) {
		fprintf(stderr, "%s line %d: expected 'I' or 'M' in field 1\n",
			input_filename, input_lineno);
		exit(1);
	}
	fpbody.src_units = input_line_fields[1][0];
	if (input_units_global == 'B')
		input_units_current = 'B';
	else
		input_units_current = fpbody.src_units;
	fpbody.mark_x = convert_input_dim(input_line_fields[2]);
	fpbody.mark_y = convert_input_dim(input_line_fields[3]);
	num_drawing_pieces = atoi(input_line_fields[4]);
	fpbody.npins = atoi(input_line_fields[5]);
	num_padstack_defs = atoi(input_line_fields[6]);
	if (input_line_nfields > 7)
		num_text_items = atoi(input_line_fields[7]);
	else
		num_text_items = 0;
	if (input_line_nfields > 8)
		num_attr_labels = atoi(input_line_fields[8]);
	else
		num_attr_labels = 0;

	/* done parsing the header line, initialize some misc */
	fpbody.refdes_scale = 100;
	num_silk_lines = 0;
	num_silk_arcs = 0;

	/* read and process the miscellany */
	for (i = 0; i < num_drawing_pieces; i++)
		one_drawing_piece();
	for (i = 0; i < num_text_items; i++)
		one_text_item();
	for (i = 0; i < num_attr_labels; i++)
		one_attr_label();

	/* deal with dummies */
	if (fpbody.npins == 0 && num_padstack_defs == 0) {
		printf("Dummy decal with no pins, skipping\n");
		return;
	}
	if (fpbody.npins < 1) {
		fprintf(stderr, "Error in decal %s: # of terminals %d < 1\n",
			current_decal->name, fpbody.npins);
		exit(1);
	}
	if (num_padstack_defs < 1) {
		fprintf(stderr,
			"Error in decal %s: # of pad stack defs %d < 1\n",
			current_decal->name, num_padstack_defs);
		exit(1);
	}

	/* the meat: allocate and fill the pins array */
	pins_array = malloc(sizeof(struct footprint_pad) * fpbody.npins);
	if (!pins_array) {
		perror("malloc of the pins array");
		exit(1);
	}
	fpbody.pins = pins_array;
	bzero(pins_array, sizeof(struct footprint_pad) * fpbody.npins);
	for (i = 0; i < fpbody.npins; i++)
		read_pindef_line(i);
	/* read and process the pad stack definitions */
	for (i = 0; i < num_padstack_defs; i++)
		one_padstack_def();

	/* post-processing */
	apply_default_padstack();
	valid = 1;
	for (i = 0; i < fpbody.npins; i++)
		if (convert_pad_to_gpcb(i) < 0)
			valid = 0;
	if (valid) {
		/* good, save it */
		if (num_silk_lines) {
			fpbody.silk_lines =
			  malloc(sizeof(struct element_line) * num_silk_lines);
			if (!fpbody.silk_lines) {
				perror("malloc to save silk lines");
				exit(1);
			}
			bcopy(silk_lines, fpbody.silk_lines,
				sizeof(struct element_line) * num_silk_lines);
			fpbody.num_silk_lines = num_silk_lines;
		}
		if (num_silk_arcs) {
			fpbody.silk_arcs =
			    malloc(sizeof(struct element_arc) * num_silk_arcs);
			if (!fpbody.silk_arcs) {
				perror("malloc to save silk arcs");
				exit(1);
			}
			bcopy(silk_arcs, fpbody.silk_arcs,
				sizeof(struct element_arc) * num_silk_arcs);
			fpbody.num_silk_arcs = num_silk_arcs;
		}
		current_decal->body = malloc(sizeof(struct footprint_body));
		if (!current_decal->body) {
			perror("malloc to save footprint body");
			exit(1);
		}
		*current_decal->body = fpbody;
		if (write_footprint_files)
			write_decal_as_element();
	} else {
		printf("decal to gpcb fp conversion FAILED\n");
		free(pins_array);
	}
}

process_partdecal_section()
{
	for (;;) {
		if (!get_input_line()) {
			fprintf(stderr, "error: EOF in PARTDECAL section\n");
			exit(1);
		}
		if (input_line_buf[0] == '*') {
			parse_starline();
			if (strcmp(input_line_starkw, "REMARK"))
				break;
			else
				continue;
		}
		parse_input_line_fields();
		if (input_line_nfields)
			process_one_decal();
	}
}

struct part_decal *
find_decal_by_name(name)
	char *name;
{
	struct part_decal *p;

	for (p = part_decal_list; p; p = p->next)
		if (!strcmp(p->name, name))
			break;
	return(p);
}