#usage "Data generation for mounting machines\n"
"
"
"Generates files for smds on the top and bottom layers "
"wich can be used with mounting machines. "
"The x and y coordinates (units: mm) of the SMD elements are calculated "
"as mean of maximum and mimimum value of the smds origin points. "
"The calculated value does not necessarily fit with the origin "
"point of the part in the layout."
"All SMD elements populated in currently set assembly variant are considered."
"
"
"The syntax of the output data looks like this:"
"
"
"name x-coord y-coord rotation value package"
"
"
"Author: support@cadsoft.de"
// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
// 2019-09-20: Modified by D. Roosendaal to output a JLCPCB compatible CSV and BOM!
// UNVERIFIED as of yet. Use at your own risk.
//
// *** YOU CAN POPULATE THIS LIST TO CORRECT ROTATION, AND TO [option] ADD SMT ORDER CODE
//
// Value, package, additional rotation (pos or neg), optional JLC SMT order code to populate the BOM
string Modify[] = { "BC847B;SOT23-BEC;-90",
"BC857B;SOT23-BEC;-90",
"12.288MHz;ABM3B;-90",
"BAV99;SOT-23;90",
"1117-3.3;SOT223;-90",
"BS170;SOT-23;90",
"BSS84;SOT23;-90",
"8V2;SOT23;-90",
"S9012;SOT23-BEC;-90",
"47uF;CT3216;180",
"100uF;CT3528;180" };
//,
//"SS14;DO214AC;-180" };
// At this moment, JLCPCB seems to have a bug which stops properly reading of parts if one or more components have the optional order code.
// This may or may not be useful to you in the future.... your decision.
//"ADAU1701;LQFP-48;;C26394"};
if (board) board(B) {
int NumParts=0;
int i, j;
string PartName[], PartValue[], PartPackage[];
int PartSorted[];
string List;
string Code;
// Get filename
string fileName = dlgFileSave("Save File", filesetext(B.name, "CPL.csv"), "*.csv");
if (fileName == "") exit(0);
output(fileName) {
printf("Designator,Mid X,Mid Y,Layer,Rotation\n");
B.elements(E) if (E.populate) {
int wasSmd,
xmax =-2147483648,
xmin = 2147483647,
ymax = xmax,
ymin = xmin;
wasSmd = 0;
E.package.contacts(C) {
if (C.smd && C.smd.layer == 1) {
wasSmd = 1;
if (C.x > xmax) xmax = C.x;
if (C.y > ymax) ymax = C.y;
if (C.x < xmin) xmin = C.x;
if (C.y < ymin) ymin = C.y;
// If MOUNT attribute is NO, don't mount it...
if ((E.attribute["MOUNT"]=="NO")) wasSmd=0;
}
}
if (wasSmd) {
i=0;
// Look for the part&package in the Modify list, and apply rotation if applicable
if (E.package.name==lookup(Modify, E.value, 1, ';')) {
i=strtol(lookup(Modify, E.value, 2, ';'));
}
//Designator,Mid X,Mid Y,Layer,Rotation
printf("%s,%5.3fmm,%5.3fmm,Top,%1.0f\n",E.name, u2mm((xmin + xmax)/2), u2mm((ymin + ymax)/2),E.angle+i);
// Get part details to create the BOM, only populate parts that have a value.
if(E.value) {
PartSorted[NumParts]=0;
PartName[NumParts]=E.name;
PartValue[NumParts]=E.value;
PartPackage[NumParts++]=E.package.name;
}
}
}
B.elements(E) if (E.populate) {
int wasSmd,
xmax =-2147483648,
xmin = 2147483647,
ymax = xmax,
ymin = xmin;
wasSmd = 0;
E.package.contacts(C) {
if (C.smd && C.smd.layer == 16) {
wasSmd = 1;
if (C.x > xmax) xmax = C.x;
if (C.y > ymax) ymax = C.y;
if (C.x < xmin) xmin = C.x;
if (C.y < ymin) ymin = C.y;
// If MOUNT attribute is NO, don't mount it...
if ((E.attribute["MOUNT"]=="NO")) wasSmd=0;
}
}
if (wasSmd) {
i=0;
// Look for the part&package in the Modify list, and apply rotation if applicable
if (E.package.name==lookup(Modify, E.value, 1, ';')) {
i=strtol(lookup(Modify, E.value, 2, ';'));
}
//Designator,Mid X,Mid Y,Layer,Rotation
printf("%s,%5.3fmm,%5.3fmm,Bot,%1.0f\n",E.name, u2mm((xmin + xmax)/2), u2mm((ymin + ymax)/2),E.angle+i);
// Get part details to create the BOM, only populate parts that have a value.
if(E.value) {
PartSorted[NumParts]=0;
PartName[NumParts]=E.name;
PartValue[NumParts]=E.value;
PartPackage[NumParts++]=E.package.name;
}
}
}
}
// Get filename for the BOM
string fileNameBOM = dlgFileSave("Save File", filesetext(B.name, "BOM.csv"), "*.csv");
if (fileNameBOM == "") exit(0);
output(fileNameBOM) {
// Comment,Designator,Footprint - Comment being the value
List+="Comment,Designator,Footprint\n";
for(i=0; i