From: Keith Packard Date: Wed, 12 Feb 2025 05:29:18 +0000 (-0800) Subject: Add jlcpcb BOM generation X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=146d37c4f77eb40adbcace54efdbd106b3c9db78;p=hw%2Faltusmetrum Add jlcpcb BOM generation Signed-off-by: Keith Packard --- diff --git a/bin/partslist-vendor b/bin/partslist-vendor index 6ac4217..19f4d55 100755 --- a/bin/partslist-vendor +++ b/bin/partslist-vendor @@ -13,8 +13,10 @@ string not_vendor_list; string input_name; string output_name; string program; +file output = stdout; int argi; int lineno = 0; +bool saw_error = false; void fatal(string format, poly args ...) { @@ -22,6 +24,12 @@ void fatal(string format, poly args ...) exit(1); } +void error(string format, poly args ...) +{ + File::fprintf(stderr, format, args...); + saw_error = true; +} + string[*] read_line(file f) { lineno++; string line = fgets(f); @@ -126,21 +134,21 @@ void process_seeed(string[string] entry) static bool start = true; if (start) { - printf("Part/Designator,Manufacturer Part Number/Seeed SKU, Quantity\n"); + File::fprintf (output, "Part/Designator,Manufacturer Part Number/Seeed SKU, Quantity\n"); start = false; } string[*] refdes = String::wordsplit(entry["refdes"], " \t"); if (dim(refdes) > 1) - printf ("\""); + File::fprintf (output, "\""); for (int i = 0; i < dim(refdes); i++) { - printf("%s", refdes[i]); + File::fprintf (output, "%s", refdes[i]); if (i < dim(refdes) - 1) - printf (","); + File::fprintf (output, ","); } if (dim(refdes) > 1) - printf ("\""); - printf(",%s,%s\n", quoted(part_number), entry["quantity"]); + File::fprintf (output, "\""); + File::fprintf (output, ",%s,%s\n", quoted(part_number), entry["quantity"]); } void process_goldphoenix(string[string] entry) @@ -153,31 +161,31 @@ void process_goldphoenix(string[string] entry) static int item = 1; static bool start = true; if (start) { - printf("#Item,Description,Designator,Package,Manufacturer,Manufacturer Part Number#,Supplier,Supplier Part #,QTY/BOARD,Order QTY,Unit Price, Subtotal \n"); + File::fprintf (output, "#Item,Description,Designator,Package,Manufacturer,Manufacturer Part Number#,Supplier,Supplier Part #,QTY/BOARD,Order QTY,Unit Price, Subtotal \n"); start = false; } string[*] refdes = String::wordsplit(entry["refdes"], " \t"); - printf("%d,", item); + File::fprintf (output, "%d,", item); /* description */ - printf("%s %s,", + File::fprintf (output, "%s %s,", quoted(entry["device"]), quoted(entry["value"])); /* designators */ if (dim(refdes) > 1) - printf ("\""); + File::fprintf (output, "\""); for (int i = 0; i < dim(refdes); i++) { - printf("%s", refdes[i]); + File::fprintf (output, "%s", refdes[i]); if (i < dim(refdes) - 1) - printf (","); + File::fprintf (output, ","); } if (dim(refdes) > 1) - printf ("\""); + File::fprintf (output, "\""); /* rest */ - printf(",%s,%s,%s,%s,%s,%s,%d\n", + File::fprintf (output, ",%s,%s,%s,%s,%s,%s,%d\n", quoted(entry["footprint"]), quoted(entry["mfg"]), quoted(entry["mfg_part_number"]), @@ -188,11 +196,42 @@ void process_goldphoenix(string[string] entry) item++; } +void process_jlcpcb(string[string] entry) +{ + if (entry["loadstatus"] == "noload") { + File::fprintf(stderr, "skipping part %v\n", entry); + return; + } + string part_number; + if (hash_test(entry, "jlcpcb_part_number")) { + part_number = entry["jlcpcb_part_number"]; + } else { + error("Component (%s, %s, %s) has no JLCPCB Part #\n", + entry["device"], entry["value"], entry["footprint"]); + part_number = "unknown"; + } + + static bool start = true; + if (start) { + File::fprintf (output, "Comment,Designator,Footprint,JLCPCB Part #\n"); + start = false; + } + + File::fprintf (output, "%s,", quoted(entry["value"])); + string[*] refdes = String::wordsplit(entry["refdes"], " \t"); + for (int i = 0; i < dim(refdes); i++) { + File::fprintf (output, "%s", quoted(refdes[i])); + if (i < dim(refdes) - 1) + File::fprintf (output, " "); + } + File::fprintf (output, "%s,%s\n", quoted(entry["footprint"]), quoted(part_number)); +} + void process_digikey(string[string] entry) { if (entry["loadstatus"] == "noload") return; - printf("%s,%s,%s %s\n", + File::fprintf (output, "%s,%s,%s %s\n", entry["quantity"], quoted(part_number(entry)), quoted(entry["device"]), @@ -203,16 +242,16 @@ void process_mouser(string[string] entry) { if (entry["loadstatus"] == "noload") return; -/* printf("%s|%s\n", part_number(entry), entry["quantity"]); */ +/* File::fprintf (output, "%s|%s\n", part_number(entry), entry["quantity"]); */ static bool start = true; if (start) { - printf("Mouser Part Number,Manufacturer Part Number,Quantity\n"); + File::fprintf (output, "Mouser Part Number,Manufacturer Part Number,Quantity\n"); start = false; } - printf("%s,%s,%s\n", + File::fprintf (output, "%s,%s,%s\n", quoted(entry["vendor_part_number"]), quoted(entry["mfg_part_number"]), entry["quantity"]); @@ -221,7 +260,7 @@ void process_mouser(string[string] entry) void process_other(string[string] entry) { if (entry["loadstatus"] == "noload") return; - printf("%s,%s,%s,%s %s\n", + File::fprintf (output, "%s,%s,%s,%s %s\n", entry["vendor"], entry["quantity"], quoted(part_number(entry)), @@ -238,6 +277,8 @@ void process_file(file f) { process_seeed(entry); } else if (!is_uninit(&vendors) && has_vendor(vendors, "goldphoenix")) { process_goldphoenix(entry); + } else if (!is_uninit(&vendors) && has_vendor(vendors, "jlcpcb")) { + process_jlcpcb(entry); } else if ((!is_uninit(&vendors) && has_vendor(vendors, vendor)) || (!is_uninit(¬_vendors) && !has_vendor(not_vendors, vendor))) { switch (entry["vendor"]) { @@ -271,11 +312,22 @@ ParseArgs::argdesc argd = { .name = "not-vendor", .expr_name = "not-vendor", .desc = "Vendors to exclude"}, + { .var = { .arg_string = &output_name }, + .abbr = 'o', + .name = "output", + .expr_name = "output", + .desc = "Output file name"}, }, .unknown = &argi, }; +void cleanup(int status) { + if (status != 0 && !is_uninit(&output_name)) + File::unlink(output_name); +} + void main() { + int status = 1; ParseArgs::parseargs(&argd, &argv); if (!is_uninit(&vendor_list)) vendors = String::parse_csv(vendor_list); @@ -283,12 +335,20 @@ void main() { if (!is_uninit(¬_vendor_list)) not_vendors = String::parse_csv(not_vendor_list); - if (!is_uninit(&argi)) { - for (int i = argi; i < dim(argv); i++) - twixt(file f = File::open(argv[i], "r"); File::close(f)) - process_file(f); - } else - process_file(stdin); + if (!is_uninit(&output_name)) + output = File::open(output_name, "w"); + + twixt(; cleanup(status)) { + if (!is_uninit(&argi)) { + for (int i = argi; i < dim(argv); i++) + twixt(file f = File::open(argv[i], "r"); File::close(f)) + process_file(f); + } else + process_file(stdin); + if (!saw_error) + status = 0; + } + exit(status); } main(); diff --git a/pcb-rnd.mk b/pcb-rnd.mk index 2de9604..e61aa46 100644 --- a/pcb-rnd.mk +++ b/pcb-rnd.mk @@ -31,22 +31,25 @@ partslist.csv: $(PROJECT)-parts.csv preferred-parts.csv $(CONFIG) $(AM)/bin/fillpartscsv.py $(PROJECT)-parts.csv --output $@ --preferred preferred-parts.csv partslist-dk.csv: partslist.csv - $(AM)/bin/partslist-vendor --vendor digikey partslist.csv > $@ + $(AM)/bin/partslist-vendor --vendor digikey -o $@ partslist.csv partslist-check.dk: partslist.csv - $(AM)/bin/partslist-vendor --vendor digikey --mfg partslist.csv > $@ + $(AM)/bin/partslist-vendor --vendor digikey -o $@ --mfg partslist.csv partslist-mouser.csv: partslist.csv - $(AM)/bin/partslist-vendor --vendor mouser partslist.csv > $@ + $(AM)/bin/partslist-vendor --vendor mouser -o $@ partslist.csv partslist-other.csv: partslist.csv - $(AM)/bin/partslist-vendor --not-vendor digikey,mouser partslist.csv > $@ + $(AM)/bin/partslist-vendor --not-vendor digikey,mouser -o $@ partslist.csv $(PROJECT)-seeed.csv: partslist.csv - $(AM)/bin/partslist-vendor --vendor seeed partslist.csv > $@ + $(AM)/bin/partslist-vendor --vendor seeed -o $@ partslist.csv $(PROJECT)-goldphoenix.csv: partslist.csv - $(AM)/bin/partslist-vendor --vendor goldphoenix partslist.csv > $@ + $(AM)/bin/partslist-vendor --vendor goldphoenix -o $@ partslist.csv + +$(PROJECT)-jlcpcb.csv: partslist.csv + $(AM)/bin/partslist-vendor --vendor jlcpcb -o $@ partslist.csv $(PROJECT)-parts.tab: $(SCHEMATICS) Makefile lepton-netlist -g bom -o $@ $(SCHEMATICS) @@ -95,10 +98,10 @@ $(PROJECT)-seeed.zip: $(PROJECT).lht $(CONFIG) $(PROJECT)-sch.pdf $(SEEED_EXTRA) jlcpcb: $(PROJECT)-jlcpcb.zip -$(PROJECT)-jlcpcb.zip: $(PROJECT).lht $(CONFIG) +$(PROJECT)-jlcpcb.zip: $(PROJECT).lht $(CONFIG) $(PROJECT)-jlcpcb.csv pcb-rnd -x cam gerber:JLC_PCB --outfile out/$(PROJECT) $(PROJECT).lht $(call emit_xyrs) - rm -f $@ && zip -j $@ out/* $(PROJECT).xy + rm -f $@ && zip -j $@ out/* $(PROJECT).xy $(PROJECT)-jlcpcb.csv stencilsunlimited: $(BOTTOMCOPPER) $(PROJECT).toppaste.gbr $(OUTLINE) rm -f $(PROJECT)-stencil.zip && zip $(PROJECT)-stencil.zip $(PROJECT).toppaste.gbr $(OUTLINE) @@ -123,7 +126,7 @@ clean: rm -f $(PROJECT).txt $(PROJECT).gl2 $(PROJECT).gl3 rm -f $(PROJECT).drd $(PROJECT).g2l $(PROJECT).g3l $(PROJECT).gko rm -f $(PROJECT)-seeed.zip $(PROJECT)-seeed.csv - rm -f $(PROJECT)-goldphoenix.zip $(PROJECT)-goldphoenix.csv + rm -f $(PROJECT)-goldphoenix.zip $(PROJECT)-goldphoenix.csv $(PROJECT)-jlcpcb.csv rm -f $(PROJECT)*.ps $(PROJECT)*.pdf $(PROJECT)-bom.csv rm -f $(PROJECT)-parts.csv $(PROJECT)-parts.tab preferred-parts.csv rm -f *.scad diff --git a/pcb.mk b/pcb.mk index b6fe2ea..ecddd7f 100644 --- a/pcb.mk +++ b/pcb.mk @@ -31,22 +31,25 @@ partslist.csv: $(PROJECT)-parts.csv preferred-parts.csv $(AM)/bin/fillpartscsv.py $(PROJECT)-parts.csv --output $@ --preferred preferred-parts.csv partslist-dk.csv: partslist.csv - $(AM)/bin/partslist-vendor --vendor digikey partslist.csv > $@ + $(AM)/bin/partslist-vendor --vendor digikey -o $@ partslist.csv partslist-check.dk: partslist.csv - $(AM)/bin/partslist-vendor --vendor digikey --mfg partslist.csv > $@ + $(AM)/bin/partslist-vendor --vendor digikey -o $@ --mfg partslist.csv partslist-mouser.csv: partslist.csv - $(AM)/bin/partslist-vendor --vendor mouser partslist.csv > $@ + $(AM)/bin/partslist-vendor --vendor mouser -o $@ partslist.csv partslist-other.csv: partslist.csv - $(AM)/bin/partslist-vendor --not-vendor digikey,mouser partslist.csv > $@ + $(AM)/bin/partslist-vendor --not-vendor digikey,mouser -o $@ partslist.csv $(PROJECT)-seeed.csv: partslist.csv - $(AM)/bin/partslist-vendor --vendor seeed partslist.csv > $@ + $(AM)/bin/partslist-vendor --vendor seeed -o $@ partslist.csv $(PROJECT)-goldphoenix.csv: partslist.csv - $(AM)/bin/partslist-vendor --vendor goldphoenix partslist.csv > $@ + $(AM)/bin/partslist-vendor --vendor goldphoenix -o $@ partslist.csv + +$(PROJECT)-jlcpcb.csv: partslist.csv + $(AM)/bin/partslist-vendor --vendor jlcpcb -o $@ partslist.csv pcb: $(SCHEMATICS) Makefile $(CONFIG) lepton-sch2pcb project