From 4902886baaa7a5c3e9330fa80a684935e87dae1c Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Fri, 30 Mar 2012 18:53:51 -0300 Subject: [PATCH] genex/: generate expanded component view (WIP) --- genex/Makefile | 40 ++++++++++++++ genex/comp.c | 125 +++++++++++++++++++++++++++++++++++++++++++ genex/comp.h | 34 ++++++++++++ genex/expand-pintype | 85 +++++++++++++++++++++++++++++ genex/genex.c | 61 +++++++++++++++++++++ genex/libs.c | 119 ++++++++++++++++++++++++++++++++++++++++ genex/libs.h | 19 +++++++ genex/pdf.c | 96 +++++++++++++++++++++++++++++++++ genex/pdf.h | 17 ++++++ genex/run | 8 +++ genex/sym2xps | 75 ++++++++++++++++++++++++++ genex/util.h | 39 ++++++++++++++ 12 files changed, 718 insertions(+) create mode 100644 genex/Makefile create mode 100644 genex/comp.c create mode 100644 genex/comp.h create mode 100755 genex/expand-pintype create mode 100644 genex/genex.c create mode 100644 genex/libs.c create mode 100644 genex/libs.h create mode 100644 genex/pdf.c create mode 100644 genex/pdf.h create mode 100755 genex/run create mode 100755 genex/sym2xps create mode 100644 genex/util.h diff --git a/genex/Makefile b/genex/Makefile new file mode 100644 index 0000000..a694189 --- /dev/null +++ b/genex/Makefile @@ -0,0 +1,40 @@ +# +# Makefile - Expanded component view generator +# +# Copyright 2012 by Werner Almesberger +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# + +CFLAGS = -Wall -g +OBJS = genex.o comp.o libs.o pdf.o + +CC_normal := $(CC) +DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG + +CC_quiet = @echo " CC " $@ && $(CC_normal) +GEN_quiet = @echo " GENERATE " $@ && +DEPEND_quiet = @$(DEPEND_normal) + +ifeq ($(V),1) + CC = $(CC_normal) + GEN = + DEPEND = $(DEPEND_normal) +else + CC = $(CC_quiet) + GEN = $(GEN_quiet) + DEPEND = $(DEPEND_quiet) +endif + +.PHONY: all clean + +all: genex + +genex: $(OBJS) + $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDLIBS) + +clean: + rm -f $(OBJS) diff --git a/genex/comp.c b/genex/comp.c new file mode 100644 index 0000000..8f317b6 --- /dev/null +++ b/genex/comp.c @@ -0,0 +1,125 @@ +/* + * comp.c - Component hierarchy + * + * Copyright 2012 by Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include + +#include "util.h" +#include "comp.h" + + +struct node *tree = NULL; + + +void read_tree(FILE *file) +{ + char buf[1100]; /* more than enough */ + struct node *last = NULL, *node; + int depth = -1; + const char *s, *p, *e; + char *name; + int n; + +next: + while (fgets(buf, sizeof(buf), file)) { + n = 0; + s = buf; + while (1) { + switch (*s++) { + case ' ': + n++; + continue; + case '\t': + n = (n+8) & ~7; + continue; + case 0: + case '#': + goto next; + default: + break; + } + break; + } + for (p = e = s--; *p && *p != '#' && *p != '\n'; p++) + if (*p != ' ' && *p != '\t') + e = p; + if (!last && n) { + fprintf(stderr, "first entry must not be intended\n"); + exit(1); + } + name = malloc(e-s+2); + if (!name) { + perror("malloc"); + exit(1); + } + memcpy(name, s, e-s+1); + name[e-s+1] = 0; + node = alloc_type(struct node); + node->name = name; + node->lib = NULL; + node->indent = n; + node->child = node->next = NULL; + if (n > depth) { + if (last) + last->child = node; + else + tree = node; + node->parent = last; + } else { + while (last && last->indent != n) + last = last->parent; + if (!last && n) { + fprintf(stderr, "indentation error\n"); + exit(1); + } + last->next = node; + node->parent = last->parent; + } + last = node; + depth = n; + } +} + + +void set_libs(struct node *node, + const char *(*find_lib)(const char *sym, const char **canon)) +{ + while (node) { + if (!node->child) { + node->lib = find_lib(node->name, &node->canon); + if (!node->lib) { + fprintf(stderr, "symbol %s not found\n", + node->name); + exit(1); + } + } + set_libs(node->child, find_lib); + node = node->next; + } +} + + +static void dump_level(const struct node *tree, int level) +{ + const struct node *n; + + for (n = tree; n; n = n->next) { + printf("%*s%s\n", 4*level, "", n->name); + dump_level(n->child, level+1); + } +} + + +void dump_tree(void) +{ + dump_level(tree, 0); +} diff --git a/genex/comp.h b/genex/comp.h new file mode 100644 index 0000000..b4a245c --- /dev/null +++ b/genex/comp.h @@ -0,0 +1,34 @@ +/* + * comp.h - Component hierarchy + * + * Copyright 2012 by Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef COMP_H +#define COMP_H + +struct node { + const char *name; + const char *lib; /* NULL if not intermediate node */ + const char *canon; /* canonical name of component */ + int indent; /* level of indentation (characters) */ + struct node *parent; + struct node *child; + struct node *next; +}; + + +extern struct node *tree; + + +void read_tree(FILE *file); +void set_libs(struct node *node, + const char *(*find_lib)(const char *sym, const char **canon)); +void dump_tree(void); + +#endif /* !COMP_H */ diff --git a/genex/expand-pintype b/genex/expand-pintype new file mode 100755 index 0000000..84557a8 --- /dev/null +++ b/genex/expand-pintype @@ -0,0 +1,85 @@ +#!/usr/bin/perl +# +# expand-pintype - Expand pin types of symbols in a Kicad library +# +# Copyright 2010, 2012 by Werner Almesberger +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# + +# +# usage: +# +# expand-pintype input.lib +# expand-pintype input.lib output.lib +# + + +$GAP = 50; # gap between pin and type, in mil +$CHAR_WIDTH = 66; # default character width, in mil +$NAME_WIDTH = 15; # name field width in ASCII mode, in characters + + +%map = ( + "I" => "Input", + "O" => "Output", + "B" => "BiDi", + "T" => "3-state", + "P" => "Passive", + "U" => "Unspec", + "W" => "Pwr In", + "w" => "Pwr Out", + "C" => "OC", + "E" => "OE", +); + +if (@ARGV < 2) { + $out = 0; +} elsif (@ARGV == 2) { + $file = pop @ARGV; + $out = 1; + open(FILE, ">$file") || die "$file: $!"; +} else { + print STDERR "usage: expand-pintype input.lib [output.lib]\n"; + exit(1); +} + +while (<>) { + if ($out) { + # make name differ so that KiCad's cache doesn't get confused + s/^DEF\s+/$&X/; + s/^F1\s+"+/$&X/; + print FILE || die; + } + next unless /^X/; + @a = split(/\s+/); + ($name, $pin, $x, $y, $dir, $unit, $pt) = @a[1, 2, 3, 4, 6, 9, 11]; + $type = $map{$pt}; + $type = "???" unless defined $type; + if ($out) { + $off = $GAP+(length $type)*$CHAR_WIDTH/2; + if ($dir eq "U") { + ($a, $y) = (90, $y-$off); + } elsif ($dir eq "D") { + ($a, $y) = (90, $y+$off); + } elsif ($dir eq "R") { + ($a, $x) = (0, $x-$off); + } else { + ($a, $x) = (0, $x+$off); + } + $type =~ y/ /~/; + print FILE sprintf("T %d %d %d 60 0 %d 0 %s Normal 0\n", + $a*10, $x, $y, $unit, $type); + } else { + $s = "$name ($pin)"; + $f = $NAME_WIDTH-length $s; + $f = "-" x ($f > 0 ? $f : 0); + print "$s $f $type\n"; + } +} +if ($out) { + close FILE || die; +} diff --git a/genex/genex.c b/genex/genex.c new file mode 100644 index 0000000..9c8ffaf --- /dev/null +++ b/genex/genex.c @@ -0,0 +1,61 @@ +/* + * genex.c - Generate expanded component view + * + * Copyright 2012 by Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + + +#include +#include +#include + +#include "comp.h" +#include "libs.h" + + +static void usage(const char *name) +{ + fprintf(stderr, "usage: %s [-L libdir ...] [-l lib ...] hierarchy\n", + name); + exit(1); +} + + +int main(int argc, char **argv) +{ + FILE *file; + int c; + + while ((c = getopt(argc, argv, "L:l:")) != EOF) + switch (c) { + case 'L': + add_libdir(optarg); + break; + case 'l': + add_lib(optarg); + break; + default: + usage(*argv); + } + + + if (argc-optind != 1) + usage(*argv); + + file = fopen(argv[optind], "r"); + if (!file) { + perror(argv[optind]); + exit(1); + } + read_tree(file); + set_libs(tree, lookup_sym); + fclose(file); +// dump_tree(); + make_pdf(); + return 0; +} diff --git a/genex/libs.c b/genex/libs.c new file mode 100644 index 0000000..2a22d84 --- /dev/null +++ b/genex/libs.c @@ -0,0 +1,119 @@ +/* + * libs.c - Component libraries + * + * Copyright 2012 by Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "util.h" +#include "libs.h" + + +struct entry { + const char *name; + struct entry *next; +}; + +static struct lib { + const char *path; + struct entry *comps; + struct lib *next; +} *libs = NULL; + + +const char *lookup_sym(const char *name, const char **canon) +{ + const struct lib *lib; + const struct entry *e; + + for (lib = libs; lib; lib = lib->next) + for (e = lib->comps; e; e = e->next) + if (!strcasecmp(e->name, name)) { + if (canon) + *canon = e->name; + return lib->path; + } + return NULL; +} + + +void add_lib(const char *path) +{ + FILE *file; + struct lib *lib; + struct entry *e; + char buf[1024]; /* @@@ */ + char *spc; + + + file = fopen(path, "r"); + if (!file) { + perror(path); + exit(1); + } + + lib = alloc_type(struct lib); + lib->path = stralloc(path); + lib->comps = NULL; + lib->next = libs; + libs = lib; + + while (fgets(buf, sizeof(buf), file)) { + if (strncmp(buf, "DEF ", 4)) + continue; + spc = strchr(buf+4, ' '); + if (!spc) { + fprintf(stderr, "invalid DEF line in %s\n", path); + exit(1); + } + *spc = 0; + e = alloc_type(struct entry); + e->name = stralloc(buf+4); + e->next = lib->comps; + lib->comps = e; + } + + fclose(file); +} + + +void add_libdir(const char *path) +{ + DIR *dir; + const struct dirent *de; + size_t len; + char *tmp; + + dir = opendir(path); + if (!dir) { + perror(path); + exit(1); + } + while (1) { + de = readdir(dir); + if (!de) + break; + len = strlen(de->d_name); + if (len < 4) + continue; + if (strcmp(de->d_name+len-4, ".lib")) + continue; + if (asprintf(&tmp, "%s/%s", path, de->d_name) < 0) { + perror("asprintf"); + exit(1); + } + add_lib(tmp); + } + closedir(dir); +} diff --git a/genex/libs.h b/genex/libs.h new file mode 100644 index 0000000..cb88ecd --- /dev/null +++ b/genex/libs.h @@ -0,0 +1,19 @@ +/* + * libs.h - Component libraries + * + * Copyright 2012 by Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef LIBS_H +#define LIBS_H + +const char *lookup_sym(const char *name, const char **canon); +void add_lib(const char *path); +void add_libdir(const char *path); + +#endif /* !LIBS_H */ diff --git a/genex/pdf.c b/genex/pdf.c new file mode 100644 index 0000000..5c4fbf7 --- /dev/null +++ b/genex/pdf.c @@ -0,0 +1,96 @@ +/* + * pdf.c - Generate PDF + * + * Copyright 2012 by Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#define _GNU_SOURCE +#include +#include + +#include "comp.h" +#include "pdf.h" + + +static int children(const struct node *node) +{ + int n = 0; + + while (node) { + n++; + node = node->next; + } + return n; +} + + +static void convert_comp(const struct node *node, FILE *out) +{ + char *tmp; + int res; + + if (asprintf(&tmp, "./sym2xps '%s' '%s' '%s' '%s'", + node->lib, node->canon, "tmp", "tmp.ps") < 0) { + perror("asprintf"); + exit(1); + } + res = system(tmp); + if (res < 0) { + perror("system"); + exit(1); + } + if (res) { + fprintf(stderr, "sym2xps returned %d\n", res); + exit(1); + } + fflush(out); + system("cat tmp.ps"); +} + + +static void convert_tree(const struct node *node, FILE *out) +{ + while (node) { + fprintf(out, "[ /Title (%s) /Count %d /OUT pdfmark\n", + node->name, -children(node->child)); + if (node->child) + convert_tree(node->child, out); + else + convert_comp(node, out); + node = node->next; + } +} + + +void make_pdf(void) +{ + FILE *out; + int res; + +#if 0 + out = popen( + "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=- -f -", + "w"); +#else + out = popen("cat", "w"); +#endif + if (!out) { + perror("gs"); + exit(1); + } + convert_tree(tree, out); + res = pclose(out); + if (res < 0) { + perror("pclose"); + exit(1); + } + if (res) { + fprintf(stderr, "exit status %d\n", res); + exit(1); + } +} diff --git a/genex/pdf.h b/genex/pdf.h new file mode 100644 index 0000000..7ab058e --- /dev/null +++ b/genex/pdf.h @@ -0,0 +1,17 @@ +/* + * pdf.h - Generate PDF + * + * Copyright 2012 by Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef PDF_H +#define PDF_H + +void make_pdf(void); + +#endif /* !PDF_H */ diff --git a/genex/run b/genex/run new file mode 100755 index 0000000..46dfe9d --- /dev/null +++ b/genex/run @@ -0,0 +1,8 @@ +#!/bin/sh +# Hack: ps2pdf is happy with the PS generate, but if we invoke gs diretctly, +# isn't. Some voodoo is still missing ... +PATH=$PATH:. ./genex \ + -L /home/qi/kicad-libs/components \ + /home/qi/kicad-libs/components/EXPAND >out.ps +ps2pdf out.ps out.pdf +rm -f out.ps diff --git a/genex/sym2xps b/genex/sym2xps new file mode 100755 index 0000000..7e36972 --- /dev/null +++ b/genex/sym2xps @@ -0,0 +1,75 @@ +#!/bin/sh -e +# +# sym2xps - Convert a symbol from a Kicad library to Postscript with expanded +# pin types +# +# Copyright 2012 by Werner Almesberger +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# + + +usage() +{ + echo "usage: $0 library symbol tmpdir outfile" 1>&2 + exit 1 +} + + +lib=$1 +sym=$2 +tmp=$3 +out=$4 + +[ "$lib" ] && [ "$sym" ] && [ "$tmp" ] && [ "$out" ] || usage + +[ -r "$lib" ] || { + echo "$lib: not found" 1>&2 + exit 1 +} + +grep "^DEF $sym " "$lib" >/dev/null || { + echo "\"$sym\" not found in $lib" 1>&2 + exit 1 +} + +[ "${tmp#/}" = "$tmp" ] && tmp=`pwd`/$tmp +[ "${out#/}" = "$out" ] && out=`pwd`/$out + +mkdir "$tmp" + +trap "rm -rf '$tmp'" 0 + +expand-pintype "$lib" "$tmp"/tmp.lib + +cat <"$tmp"/tmp.pro +[eeschema] +version=1 +[eeschema/libraries] +LibName1=./tmp +EOF + +X=6000 +Y=4000 + +cat <"$tmp"/tmp.sch +EESchema Schematic File Version 2 date Mon Mar 26 09:29:33 2012 +LIBS:dummy +EELAYER 43 0 +EELAYER END +\$Comp +L X$sym ?? +U 1 1 00000000 +P $X $Y + 1 $X $Y + 1 0 0 -1 +\$EndComp +\$EndSCHEMATC +EOF + +cd "$tmp" +eeschema --plot=ps "$tmp/tmp.sch" +mv tmp.ps "$out" diff --git a/genex/util.h b/genex/util.h new file mode 100644 index 0000000..e6f0514 --- /dev/null +++ b/genex/util.h @@ -0,0 +1,39 @@ +/* + * util.h - Utility functions + * + * Copyright 2012 by Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef UTIL_H +#define UTIL_H + +#include +#include + + +#define alloc_size(s) \ + ({ void *alloc_size_tmp = malloc(s); \ + if (!alloc_size_tmp) \ + abort(); \ + alloc_size_tmp; }) + +#define alloc_type(t) ((t *) alloc_size(sizeof(t))) + + +static inline char *stralloc(const char *s) +{ + char *t; + + t = strdup(s); + if (t) + return t; + perror("strdup"); + exit(1); +} + +#endif /* !UTIL_H */